1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
package main
import (
"bytes"
"compress/gzip"
"context"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"strings"
"dev.mediocregopher.com/mediocre-blog.git/src/post/asset"
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
"github.com/nlepage/go-tarfs"
)
func writeArchiveAsset(
assetStore asset.Store,
assetsDirPath string,
id string,
) error {
buf := new(bytes.Buffer)
if err := assetStore.Get(id, buf); err != nil {
return fmt.Errorf("loading into buffer: %w", err)
}
gzipR, err := gzip.NewReader(buf)
if err != nil {
return fmt.Errorf("decompressing as gzip: %w", err)
}
tarFS, err := tarfs.New(gzipR)
if err != nil {
return fmt.Errorf("parsing as tar: %w", err)
}
return fs.WalkDir(tarFS, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return fmt.Errorf("walking path %q: %w", path, err)
} else if d.IsDir() {
return nil
}
var (
dirPath = filepath.Join(assetsDirPath, id, filepath.Dir(path))
dstPath = filepath.Join(dirPath, d.Name())
srcPath = path
)
if err := os.MkdirAll(dirPath, 0755); err != nil {
return fmt.Errorf("creating directory %q: %w", dirPath, err)
}
dstF, err := os.Create(dstPath)
if err != nil {
return fmt.Errorf("opening dst path %q: %w", dstPath, err)
}
defer dstF.Close()
srcF, err := tarFS.Open(srcPath)
if err != nil {
return fmt.Errorf("opening path %q within the tar: %w", srcPath, err)
}
defer srcF.Close()
if _, err = io.Copy(dstF, srcF); err != nil {
return fmt.Errorf("copying %q into %q: %w", srcPath, dstPath, err)
}
return nil
})
}
func writeAsset(
assetStore asset.Store,
assetsDirPath string,
id string,
) error {
if strings.HasSuffix(id, ".tgz") {
return writeArchiveAsset(assetStore, assetsDirPath, id)
}
assetPath := filepath.Join(assetsDirPath, id)
f, err := os.Create(assetPath)
if err != nil {
return fmt.Errorf("creating file %q: %w", assetPath, err)
}
defer func() { _ = f.Close() }()
if err := assetStore.Get(id, f); err != nil {
return fmt.Errorf("writing asset to %q: %w", assetPath, err)
}
return nil
}
func exportAssets(
ctx context.Context,
logger *mlog.Logger,
assetStore asset.Store,
exportDirPath string,
) error {
var (
assetsDirPath = filepath.Join(exportDirPath, "assets")
)
if err := os.MkdirAll(assetsDirPath, 0755); err != nil {
return fmt.Errorf("creating asset dir %q: %w", assetsDirPath, err)
}
logger.Info(ctx, "Listing assets")
assets, err := assetStore.List()
if err != nil {
return fmt.Errorf("listing assets: %w", err)
}
for _, id := range assets {
logger.Info(mctx.Annotate(ctx, "assetID", id), "Writing asset")
if err := writeAsset(assetStore, assetsDirPath, id); err != nil {
return fmt.Errorf("writing asset %q: %w", id, err)
}
}
return nil
}
|