~bigbes/ci-cacher

ref: 63e1653aea40a9dca690f49bd8017e72c867d61b ci-cacher/cmd/dir.go -rw-r--r-- 2.4 KiB
63e1653a — Eugene Blikh Add builds.sr.ht CI: unit, e2e, and tag-only publish 2 days ago
                                                                                
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
package cmd

import (
	"context"
	"fmt"
	"io"
	"os"

	"github.com/spf13/cobra"

	"go.bigb.es/cacher/internal/archive"
)

var dirCmd = &cobra.Command{
	Use:   "dir",
	Short: "Directory cache (tar+zstd of a tree)",
	Long: `Cache resolved trees keyed by content hash (e.g. ~/go/pkg/mod
keyed by go.sum, or .rocks/ keyed by rockspec hash). Closes the biggest
gap left by the single-file shell helper this binary replaces.`,
}

var dirDownloadCmd = &cobra.Command{
	Use:   "download <key> <local-dir>",
	Short: "Extract a cached directory into <local-dir>",
	Args:  cobra.ExactArgs(2),
	RunE: func(cmd *cobra.Command, args []string) error {
		cli, cfg, err := client()
		if err != nil {
			return err
		}
		key, err := resolveKey(args[0], cfg)
		if err != nil {
			return err
		}
		dest := args[1]
		ctx := context.Background()

		ok, err := cli.Exists(ctx, key)
		if err != nil {
			return err
		}
		if !ok {
			return fmt.Errorf("%w: %s", ErrNotFound, key)
		}
		if err := os.MkdirAll(dest, 0o755); err != nil {
			return err
		}
		fmt.Fprintf(cmd.ErrOrStderr(), "Cache HIT  — %s → extract %s\n", key, dest)
		body, err := cli.Get(ctx, key)
		if err != nil {
			return err
		}
		defer body.Close()
		return archive.DecodeDir(body, dest)
	},
}

var dirUploadCmd = &cobra.Command{
	Use:   "upload <key> <local-dir>",
	Short: "Pack a local directory (tar+zstd) and upload",
	Args:  cobra.ExactArgs(2),
	RunE: func(cmd *cobra.Command, args []string) error {
		cli, cfg, err := client()
		if err != nil {
			return err
		}
		key, err := resolveKey(args[0], cfg)
		if err != nil {
			return err
		}
		src := args[1]
		ctx := context.Background()

		if !flagForce {
			ok, err := cli.Exists(ctx, key)
			if err != nil {
				return err
			}
			if ok {
				fmt.Fprintf(cmd.ErrOrStderr(), "Skipped — %s already present (use --force)\n", key)
				return nil
			}
		}
		st, err := os.Stat(src)
		if err != nil {
			return err
		}
		if !st.IsDir() {
			return fmt.Errorf("%s is not a directory", src)
		}
		fmt.Fprintf(cmd.ErrOrStderr(), "Packing %s → %s\n", src, key)

		pr, pw := io.Pipe()
		go func() {
			err := archive.EncodeDir(pw, src)
			pw.CloseWithError(err)
		}()
		return cli.Put(ctx, key, pr)
	},
}

func init() {
	for _, c := range []*cobra.Command{dirDownloadCmd, dirUploadCmd} {
		addS3Flags(c)
		addKeyFlags(c)
	}
	dirUploadCmd.Flags().BoolVar(&flagForce, "force", false, "overwrite if key already exists")
	dirCmd.AddCommand(dirDownloadCmd, dirUploadCmd)
	rootCmd.AddCommand(dirCmd)
}