package main import ( "crypto/md5" //nolint:gosec // not used for security "encoding/base64" "flag" "fmt" "log" "os" "runtime" "strings" "github.com/peterbourgon/ff/v3" "edge-infra.dev/pkg/lib/cli/sh" ) var ( storageURL = "https://storage.googleapis.com" ciBucket = "edge-bzl-cache" credsPath string enableCache bool uploadResults bool bucket string shell *sh.Shell flags *flag.FlagSet ) func init() { shell = sh.New() flags = flag.NewFlagSet("bzl-cache-rc-gen", flag.ExitOnError) flags.StringVar( &bucket, "bucket", ciBucket, "bucket name to use for cache", ) flags.StringVar( &credsPath, "google-creds-path", "", "path to google creds file, if not using google default credentials", ) flags.BoolVar( &enableCache, "enable-cache", false, "whether or not cache usage should be applied to every Bazel command by default", ) flags.BoolVar( &uploadResults, "upload-results", false, "whether or not results should be uploaded to the cache (R/W) or not (RO)", ) if err := ff.Parse(flags, os.Args[1:], ff.WithEnvVarNoPrefix()); err != nil { log.Fatal("failed to parse config") } } func main() { bazelrc := "" // if no creds path is provided, use default credentials if credsPath == "" { bazelrc += "build:cache --google_default_credentials\n" } else { bazelrc += fmt.Sprintf("build:cache --google_credentials=%s\n", credsPath) } if uploadResults { bazelrc += "build:cache --remote_upload_local_results=true\n" } // determine full remote cache URL by hasing the environment we are // creating the bazelrc file for host := fmt.Sprintf("%s/%s", storageURL, bucket) // add unique workstation hash to end host = fmt.Sprintf("%s/%s", host, hashEnvironment()) bazelrc += fmt.Sprintf("build:cache --remote_cache=%s\n", host) if enableCache { bazelrc += "build --config=cache\n" } fmt.Println(bazelrc) } func hashEnvironment() string { // $CC and Bazel interactions // https://github.com/kubernetes/test-infra/blob/master/images/bootstrap/create_bazel_cache_rcs.sh#L46 // > if $CC is set bazel will use this to detect c/c++ toolchains, otherwise gcc // > https://blog.bazel.build/2016/03/31/autoconfiguration.html cc := os.Getenv("CC") if cc == "" { out, err := shell.Run("gcc -dumpversion") if err != nil { log.Fatal("failed to determine gcc version", out, err) } cc = strings.TrimSpace(out) } // some bazel rules still indirectly depend on host python // dont bother checking for python like we do for gcc because // it should be installed every python, err := shell.Run("python3 --version") if err == nil { python = strings.TrimSpace(python) } else { python = "none" } // add operationg system to hash to split osx + linux //nolint:gosec // not used for security md5Hash := md5.Sum([]byte(fmt.Sprintf("%s,%s,%s", cc, python, runtime.GOOS))) return base64.StdEncoding.EncodeToString(md5Hash[:]) }