-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathmain.go
More file actions
182 lines (150 loc) · 3.64 KB
/
main.go
File metadata and controls
182 lines (150 loc) · 3.64 KB
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package main
import (
"bytes"
"context"
"errors"
"flag"
"fmt"
"os"
"strings"
"text/template"
"github.com/sethvargo/gcs-cacher/cacher"
"github.com/sethvargo/go-signalcontext"
"google.golang.org/api/googleapi"
)
var (
stdout = os.Stdout
stderr = os.Stderr
// bucket is the Cloud Storage bucket.
bucket string
// cache is the key to use to cache.
cache string
// restore is the list of restore keys to use to restore.
restore stringSliceFlag
// allowFailure allows a command to fail.
allowFailure bool
// dir is the directory on disk to cache or the destination in which to
// restore.
dir string
// hash is the glob pattern to hash.
hash string
// debug enables debug logging.
debug bool
)
func init() {
flag.StringVar(&bucket, "bucket", "", "Bucket name without gs:// prefix.")
flag.StringVar(&dir, "dir", "", "Directory to cache or restore.")
flag.StringVar(&cache, "cache", "", "Key with which to cache.")
flag.Var(&restore, "restore", "Keys to search to restore (can use multiple times).")
flag.BoolVar(&allowFailure, "allow-failure", false, "Allow the command to fail.")
flag.StringVar(&hash, "hash", "", "Glob pattern to hash.")
flag.BoolVar(&debug, "debug", false, "Print verbose debug logs.")
}
func main() {
ctx, done := signalcontext.OnInterrupt()
err := realMain(ctx)
done()
if err != nil {
fmt.Fprintf(stderr, "%s\n", err)
// Check if the error is a Google API error and print extra information.
var gerr *googleapi.Error
if errors.As(err, &gerr) {
fmt.Fprintf(stderr, "Error is a googleapi error:\n%s\n", err.Error())
}
if !allowFailure {
os.Exit(1)
}
}
}
func realMain(ctx context.Context) error {
args := os.Args
for _, arg := range args {
if arg == "-h" || arg == "--help" || arg == "help" {
flag.PrintDefaults()
return nil
}
}
flag.Parse()
if len(flag.Args()) > 0 {
return fmt.Errorf("no arguments expected")
}
c, err := cacher.New(ctx)
if err != nil {
return err
}
c.Debug(debug)
switch {
case cache != "":
parsed, err := parseTemplate(c, cache)
if err != nil {
return err
}
if err := c.Save(ctx, &cacher.SaveRequest{
Bucket: bucket,
Dir: dir,
Key: parsed,
}); err != nil {
return err
}
fmt.Fprintf(stdout, "finished saving cache\n")
return nil
case restore != nil:
keys := make([]string, len(restore))
for i, key := range restore {
parsed, err := parseTemplate(c, key)
if err != nil {
return err
}
keys[i] = parsed
}
if err := c.Restore(ctx, &cacher.RestoreRequest{
Bucket: bucket,
Dir: dir,
Keys: keys,
}); err != nil {
return err
}
fmt.Fprintf(stdout, "finished restoring cache\n")
return nil
default:
return fmt.Errorf("missing command operation")
}
}
func parseTemplate(c *cacher.Cacher, key string) (string, error) {
tmpl, err := template.New("").
Option("missingkey=error").
Funcs(templateFuncs(c)).
Parse(key)
if err != nil {
return "", fmt.Errorf("failed to parse template: %w", err)
}
var b bytes.Buffer
if err := tmpl.Execute(&b, nil); err != nil {
return "", fmt.Errorf("failed to process template: %w", err)
}
return b.String(), nil
}
func templateFuncs(c *cacher.Cacher) template.FuncMap {
return template.FuncMap{
"hashGlob": func(key string) (string, error) {
return c.HashGlob(key)
},
}
}
type stringSliceFlag []string
func (s *stringSliceFlag) String() string {
if s == nil {
return ""
}
return strings.Join(*s, ",")
}
func (s *stringSliceFlag) Set(value string) error {
var vals []string
for _, val := range strings.Split(value, ",") {
if k := strings.TrimSpace(val); k != "" {
vals = append(vals, k)
}
}
*s = append(*s, vals...)
return nil
}