Skip to content

Commit

Permalink
Split the remotetool into its a separate binary
Browse files Browse the repository at this point in the history
In this CL, I'm creating an embeddedtool binary so that I can
subsequently use it in reproxytool binary in re-client to implement the
log file filtering functionalities. There's no behavior change
associated with this CL.

Tested: Ran show_action and show_action_2 (error'ed out) on the new
remotetool.
  • Loading branch information
gkousik committed May 13, 2024
1 parent 369e1ca commit 9600fa7
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 127 deletions.
2 changes: 1 addition & 1 deletion go/cmd/remotetool/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ go_library(
visibility = ["//visibility:private"],
deps = [
"//go/pkg/flags",
"//go/pkg/outerr",
"//go/pkg/tool",
"//go/cmd/remotetool/embeddedtool",
"@com_github_golang_glog//:go_default_library",
],
)
Expand Down
13 changes: 13 additions & 0 deletions go/cmd/remotetool/embeddedtool/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "embeddedtool",
srcs = ["embeddedtool.go"],
importpath = "github.com/bazelbuild/remote-apis-sdks/go/cmd/remotetool/embeddedtool",
visibility = ["//visibility:public"],
deps = [
"//go/pkg/outerr",
"//go/pkg/tool",
"@com_github_golang_glog//:glog",
],
)
154 changes: 154 additions & 0 deletions go/cmd/remotetool/embeddedtool/embeddedtool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Package embeddedtool is a library 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 outer remotetool binary.
package embeddedtool

import (
"context"
"encoding/json"
"flag"
"fmt"
"os"

"github.com/bazelbuild/remote-apis-sdks/go/pkg/outerr"
"github.com/bazelbuild/remote-apis-sdks/go/pkg/tool"

log "github.com/golang/glog"
)

var (
digest = flag.String("digest", "", "Digest in <digest/size_bytes> format.")
pathPrefix = flag.String("path", "", "Path to which outputs should be downloaded to.")
overwrite = flag.Bool("overwrite", false, "Overwrite the output path if it already exist.")
actionRoot = flag.String("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).")
execAttempts = flag.Int("exec_attempts", 10, "For check_determinism: the number of times to remotely execute the action and check for mismatches.")
jsonOutput = flag.String("json", "", "Path to output operation result as JSON. Currently supported for \"upload_dir\", and includes various upload metadata (see UploadStats).")
_ = flag.String("input_root", "", "Deprecated. Use action root instead.")
)

// 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 *tool.Client){
downloadActionResult: func(ctx context.Context, c *tool.Client) {
if err := c.DownloadActionResult(ctx, getDigestFlag(), getPathFlag()); err != nil {
log.Exitf("error downloading action result for digest %v: %v", digest, err)
}
},
downloadBlob: func(ctx context.Context, c *tool.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 *tool.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 *tool.Client) {
res, err := c.ShowAction(ctx, getDigestFlag())
if err != nil {
log.Exitf("error fetching action %v: %v", digest, err)
}
os.Stdout.Write([]byte(res))
},
downloadAction: func(ctx context.Context, c *tool.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 *tool.Client) {
if _, err := c.ExecuteAction(ctx, *digest, *actionRoot, getPathFlag(), outerr.SystemOutErr); err != nil {
log.Exitf("error executing action: %v", err)
}
},
checkDeterminism: func(ctx context.Context, c *tool.Client) {
if err := c.CheckDeterminism(ctx, *digest, *actionRoot, *execAttempts); err != nil {
log.Exitf("error checking determinism: %v", err)
}
},
uploadBlob: func(ctx context.Context, c *tool.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 *tool.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 *tool.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 !flag.Parsed() {
flag.Parse()
}
if *execAttempts <= 0 {
log.Exitf("--exec_attempts must be >= 1.")
}
}

func getDigestFlag() string {
if *digest == "" {
log.Exitf("--digest must be specified.")
}
return *digest
}

func getPathFlag() string {
if *pathPrefix == "" {
log.Exitf("--path must be specified.")
}
return *pathPrefix
}
133 changes: 7 additions & 126 deletions go/cmd/remotetool/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,56 +21,20 @@ package main

import (
"context"
"encoding/json"
"flag"
"fmt"
"os"
"path"

"github.com/bazelbuild/remote-apis-sdks/go/pkg/outerr"
"github.com/bazelbuild/remote-apis-sdks/go/cmd/remotetool/embeddedtool"
"github.com/bazelbuild/remote-apis-sdks/go/pkg/tool"

rflags "github.com/bazelbuild/remote-apis-sdks/go/pkg/flags"
log "github.com/golang/glog"
)

// 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"
)

var supportedOps = []OpType{
downloadActionResult,
showAction,
downloadAction,
downloadBlob,
downloadDir,
executeAction,
checkDeterminism,
uploadBlob,
uploadDir,
}

var (
operation = flag.String("operation", "", fmt.Sprintf("Specifies the operation to perform. Supported values: %v", supportedOps))
digest = flag.String("digest", "", "Digest in <digest/size_bytes> format.")
pathPrefix = flag.String("path", "", "Path to which outputs should be downloaded to.")
overwrite = flag.Bool("overwrite", false, "Overwrite the output path if it already exist.")
actionRoot = flag.String("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).")
execAttempts = flag.Int("exec_attempts", 10, "For check_determinism: the number of times to remotely execute the action and check for mismatches.")
jsonOutput = flag.String("json", "", "Path to output operation result as JSON. Currently supported for \"upload_dir\", and includes various upload metadata (see UploadStats).")
_ = flag.String("input_root", "", "Deprecated. Use action root instead.")
operation = flag.String("operation", "", fmt.Sprintf("Specifies the operation to perform. Supported values: %v", embeddedtool.SupportedOps))
)

func main() {
Expand All @@ -82,9 +46,7 @@ func main() {
if *operation == "" {
log.Exitf("--operation must be specified.")
}
if *execAttempts <= 0 {
log.Exitf("--exec_attempts must be >= 1.")
}
embeddedtool.ValidateFlags()

ctx := context.Background()
grpcClient, err := rflags.NewClientFromFlags(ctx)
Expand All @@ -94,90 +56,9 @@ func main() {
defer grpcClient.Close()
c := &tool.Client{GrpcClient: grpcClient}

switch OpType(*operation) {
case downloadActionResult:
if err := c.DownloadActionResult(ctx, getDigestFlag(), getPathFlag()); err != nil {
log.Exitf("error downloading action result for digest %v: %v", getDigestFlag(), err)
}

case downloadBlob:
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))

case downloadDir:
if err := c.DownloadDirectory(ctx, getDigestFlag(), getPathFlag()); err != nil {
log.Exitf("error downloading directory for digest %v: %v", getDigestFlag(), err)
}

case showAction:
res, err := c.ShowAction(ctx, getDigestFlag())
if err != nil {
log.Exitf("error fetching action %v: %v", getDigestFlag(), err)
}
os.Stdout.Write([]byte(res))

case downloadAction:
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())

case executeAction:
if _, err := c.ExecuteAction(ctx, *digest, *actionRoot, getPathFlag(), outerr.SystemOutErr); err != nil {
log.Exitf("error executing action: %v", err)
}

case checkDeterminism:
if err := c.CheckDeterminism(ctx, *digest, *actionRoot, *execAttempts); err != nil {
log.Exitf("error checking determinism: %v", err)
}

case uploadBlob:
if err := c.UploadBlob(ctx, getPathFlag()); err != nil {
log.Exitf("error uploading blob for digest %v: %v", getDigestFlag(), err)
}

case uploadBlobV2:
if err := c.UploadBlobV2(ctx, getPathFlag()); err != nil {
log.Exitf("error uploading blob for digest %v: %v", getDigestFlag(), err)
}

case uploadDir:
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)
}

default:
log.Exitf("unsupported operation %v. Supported operations:\n%v", *operation, supportedOps)
}
}

func getDigestFlag() string {
if *digest == "" {
log.Exitf("--digest must be specified.")
}
return *digest
}

func getPathFlag() string {
if *pathPrefix == "" {
log.Exitf("--path must be specified.")
fn, ok := embeddedtool.RemoteToolOperations[embeddedtool.OpType(*operation)]
if !ok {
log.Exitf("unsupported operation %v. Supported operations:\n%v", *operation, embeddedtool.SupportedOps)
}
return *pathPrefix
fn(ctx, c)
}

0 comments on commit 9600fa7

Please sign in to comment.