summaryrefslogtreecommitdiff
path: root/src/cmd/export/assets.go
blob: 2e62cbd810bd860312d2a847282b797519d3b4b6 (plain)
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
}