-
Notifications
You must be signed in to change notification settings - Fork 49
/
embeddedtool.go
159 lines (147 loc) · 5.39 KB
/
embeddedtool.go
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
// Package tool in this file provides functions that can be embedded into a go binary
// such that the binary now supports the various operations the remotetool
// supports (e.g., show_action, upload_blob, etc).
// A canonical usage of this library is the remotetool binary.
package tool
import (
"context"
"encoding/json"
"flag"
"fmt"
"os"
"github.com/bazelbuild/remote-apis-sdks/go/pkg/outerr"
log "github.com/golang/glog"
)
var (
inputDigest string
pathPrefix string
overwrite bool
actionRoot string
execAttempts int
jsonOutput string
)
// RegisterFlags registers the flags necessary for the embedded tool to work.
func RegisterFlags() {
flag.StringVar(&inputDigest, "digest", "", "Digest in <digest/size_bytes> format.")
flag.StringVar(&pathPrefix, "path", "", "Path to which outputs should be downloaded to.")
flag.BoolVar(&overwrite, "overwrite", false, "Overwrite the output path if it already exist.")
flag.StringVar(&actionRoot, "action_root", "", "For execute_action: the root of the action spec, containing ac.textproto (Action proto), cmd.textproto (Command proto), and input/ (root of the input tree).")
flag.IntVar(&execAttempts, "exec_attempts", 10, "For check_determinism: the number of times to remotely execute the action and check for mismatches.")
flag.StringVar(&jsonOutput, "json", "", "Path to output operation result as JSON. Currently supported for \"upload_dir\", and includes various upload metadata (see UploadStats).")
}
// OpType denotes the type of operation to perform.
type OpType string
const (
downloadActionResult OpType = "download_action_result"
showAction OpType = "show_action"
downloadAction OpType = "download_action"
downloadBlob OpType = "download_blob"
downloadDir OpType = "download_dir"
executeAction OpType = "execute_action"
checkDeterminism OpType = "check_determinism"
uploadBlob OpType = "upload_blob"
uploadBlobV2 OpType = "upload_blob_v2"
uploadDir OpType = "upload_dir"
)
// SupportedOps denote the list of operations supported by this remotetool.
var SupportedOps = []OpType{
downloadActionResult,
showAction,
downloadAction,
downloadBlob,
downloadDir,
executeAction,
checkDeterminism,
uploadBlob,
uploadDir,
}
// RemoteToolOperations maps each supported operation to a function that performs
// the operation.
var RemoteToolOperations = map[OpType]func(ctx context.Context, c *Client){
downloadActionResult: func(ctx context.Context, c *Client) {
if err := c.DownloadActionResult(ctx, getDigestFlag(), getPathFlag()); err != nil {
log.Exitf("error downloading action result for digest %v: %v", getDigestFlag(), err)
}
},
downloadBlob: func(ctx context.Context, c *Client) {
res, err := c.DownloadBlob(ctx, getDigestFlag(), getPathFlag())
if err != nil {
log.Exitf("error downloading blob for digest %v: %v", getDigestFlag(), err)
}
os.Stdout.Write([]byte(res))
},
downloadDir: func(ctx context.Context, c *Client) {
if err := c.DownloadDirectory(ctx, getDigestFlag(), getPathFlag()); err != nil {
log.Exitf("error downloading directory for digest %v: %v", getDigestFlag(), err)
}
},
showAction: func(ctx context.Context, c *Client) {
res, err := c.ShowAction(ctx, getDigestFlag())
if err != nil {
log.Exitf("error fetching action %v: %v", getDigestFlag(), err)
}
os.Stdout.Write([]byte(res))
},
downloadAction: func(ctx context.Context, c *Client) {
err := c.DownloadAction(ctx, getDigestFlag(), getPathFlag(), overwrite)
if err != nil {
log.Exitf("error fetching action %v: %v", getDigestFlag(), err)
}
fmt.Printf("Action downloaded to %v\n", getPathFlag())
},
executeAction: func(ctx context.Context, c *Client) {
if _, err := c.ExecuteAction(ctx, getDigestFlag(), actionRoot, getPathFlag(), outerr.SystemOutErr); err != nil {
log.Exitf("error executing action: %v", err)
}
},
checkDeterminism: func(ctx context.Context, c *Client) {
if err := c.CheckDeterminism(ctx, getDigestFlag(), actionRoot, execAttempts); err != nil {
log.Exitf("error checking determinism: %v", err)
}
},
uploadBlob: func(ctx context.Context, c *Client) {
if err := c.UploadBlob(ctx, getPathFlag()); err != nil {
log.Exitf("error uploading blob for digest %v: %v", getDigestFlag(), err)
}
},
uploadBlobV2: func(ctx context.Context, c *Client) {
if err := c.UploadBlobV2(ctx, getPathFlag()); err != nil {
log.Exitf("error uploading blob for digest %v: %v", getDigestFlag(), err)
}
},
uploadDir: func(ctx context.Context, c *Client) {
us, err := c.UploadDirectory(ctx, getPathFlag())
if jsonOutput != "" {
js, _ := json.MarshalIndent(us, "", " ")
if jsonOutput == "-" {
fmt.Printf("%s\n", js)
} else {
log.Infof("Outputting JSON results to %s", jsonOutput)
if err := os.WriteFile(jsonOutput, []byte(js), 0o666); err != nil {
log.Exitf("Error writing JSON output to file: %v", err)
}
}
}
if err != nil {
log.Exitf("error uploading directory for path %s: %v", getPathFlag(), err)
}
},
}
// ValidateFlags validates the command line flags associated with this embedded remote tool.
func ValidateFlags() {
if execAttempts <= 0 {
log.Exitf("--exec_attempts must be >= 1.")
}
}
func getDigestFlag() string {
if inputDigest == "" {
log.Exitf("--digest must be specified.")
}
return inputDigest
}
func getPathFlag() string {
if pathPrefix == "" {
log.Exitf("--path must be specified.")
}
return pathPrefix
}