diff --git a/BUILD b/BUILD index 394ed858..05e91728 100644 --- a/BUILD +++ b/BUILD @@ -45,6 +45,7 @@ go_library( visibility = ["//visibility:private"], deps = [ "//core:go_default_library", + "//core/configs:go_default_library", "//repositories:go_default_library", ], ) @@ -196,8 +197,8 @@ pkg_npm( srcs = [ "LICENSE", "README.md", - "bazelisk.js", "bazelisk.d.ts", + "bazelisk.js", "package.json", ], deps = [ diff --git a/bazelisk.go b/bazelisk.go index 5cdee070..b76393c1 100644 --- a/bazelisk.go +++ b/bazelisk.go @@ -20,12 +20,13 @@ import ( "os" "github.com/bazelbuild/bazelisk/core" + "github.com/bazelbuild/bazelisk/core/configs" "github.com/bazelbuild/bazelisk/repositories" ) func main() { gcs := &repositories.GCSRepo{} - gitHub := repositories.CreateGitHubRepo(core.GetEnvOrConfig("BAZELISK_GITHUB_TOKEN")) + gitHub := repositories.CreateGitHubRepo(configs.GetEnvOrConfig("BAZELISK_GITHUB_TOKEN")) // Fetch LTS releases, release candidates, rolling releases and Bazel-at-commits from GCS, forks from GitHub. repos := core.CreateRepositories(gcs, gcs, gitHub, gcs, gcs, true) diff --git a/core/BUILD b/core/BUILD index fee6d3a0..36257e9e 100644 --- a/core/BUILD +++ b/core/BUILD @@ -10,6 +10,8 @@ go_library( visibility = ["//visibility:public"], x_defs = {"BazeliskVersion": "{STABLE_VERSION}"}, deps = [ + "//core/configs:go_default_library", + "//core/path:go_default_library", "//httputil:go_default_library", "//platforms:go_default_library", "//versions:go_default_library", diff --git a/core/configs/BUILD.bazel b/core/configs/BUILD.bazel new file mode 100644 index 00000000..165f9549 --- /dev/null +++ b/core/configs/BUILD.bazel @@ -0,0 +1,9 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["configs.go"], + importpath = "github.com/bazelbuild/bazelisk/core/configs", + visibility = ["//visibility:public"], + deps = ["//core/path:go_default_library"], +) diff --git a/core/configs/configs.go b/core/configs/configs.go new file mode 100644 index 00000000..1570691b --- /dev/null +++ b/core/configs/configs.go @@ -0,0 +1,60 @@ +// Package core.configs contains the core.configs Bazelisk logic, as well as abstractions for Bazel repositories. +package configs + +import ( + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" + "sync" + + "github.com/bazelbuild/bazelisk/core/path" +) + +var ( + fileConfig map[string]string + fileConfigOnce sync.Once +) + +// GetEnvOrConfig reads a configuration value from the environment, but fall back to reading it from .bazeliskrc in the workspace root. +func GetEnvOrConfig(name string) string { + if val := os.Getenv(name); val != "" { + return val + } + + // Parse .bazeliskrc in the workspace root, once, if it can be found. + fileConfigOnce.Do(func() { + workingDirectory, err := os.Getwd() + if err != nil { + return + } + workspaceRoot := path.FindWorkspaceRoot(workingDirectory) + if workspaceRoot == "" { + return + } + rcFilePath := filepath.Join(workspaceRoot, ".bazeliskrc") + contents, err := ioutil.ReadFile(rcFilePath) + if err != nil { + if os.IsNotExist(err) { + return + } + log.Fatal(err) + } + fileConfig = make(map[string]string) + for _, line := range strings.Split(string(contents), "\n") { + if strings.HasPrefix(line, "#") { + // comments + continue + } + parts := strings.SplitN(line, "=", 2) + if len(parts) < 2 { + continue + } + key := strings.TrimSpace(parts[0]) + fileConfig[key] = strings.TrimSpace(parts[1]) + } + }) + + return fileConfig[name] +} diff --git a/core/core.go b/core/core.go index 1e6c6f70..69cc3528 100644 --- a/core/core.go +++ b/core/core.go @@ -7,7 +7,6 @@ import ( "bufio" "fmt" "io" - "io/ioutil" "log" "os" "os/exec" @@ -19,6 +18,8 @@ import ( "sync" "syscall" + "github.com/bazelbuild/bazelisk/core/configs" + "github.com/bazelbuild/bazelisk/core/path" "github.com/bazelbuild/bazelisk/httputil" "github.com/bazelbuild/bazelisk/platforms" "github.com/bazelbuild/bazelisk/versions" @@ -43,7 +44,7 @@ var ( func RunBazelisk(args []string, repos *Repositories) (int, error) { httputil.UserAgent = getUserAgent() - bazeliskHome := GetEnvOrConfig("BAZELISK_HOME") + bazeliskHome := configs.GetEnvOrConfig("BAZELISK_HOME") if len(bazeliskHome) == 0 { userCacheDir, err := os.UserCacheDir() if err != nil { @@ -86,7 +87,7 @@ func RunBazelisk(args []string, repos *Repositories) (int, error) { return -1, fmt.Errorf("could not resolve the version '%s' to an actual version number: %v", bazelVersion, err) } - bazelForkOrURL := dirForURL(GetEnvOrConfig(BaseURLEnv)) + bazelForkOrURL := dirForURL(configs.GetEnvOrConfig(BaseURLEnv)) if len(bazelForkOrURL) == 0 { bazelForkOrURL = bazelFork } @@ -171,84 +172,13 @@ func getBazelCommand(args []string) (string, error) { } func getUserAgent() string { - agent := GetEnvOrConfig("BAZELISK_USER_AGENT") + agent := configs.GetEnvOrConfig("BAZELISK_USER_AGENT") if len(agent) > 0 { return agent } return fmt.Sprintf("Bazelisk/%s", BazeliskVersion) } -// GetEnvOrConfig reads a configuration value from the environment, but fall back to reading it from .bazeliskrc in the workspace root. -func GetEnvOrConfig(name string) string { - if val := os.Getenv(name); val != "" { - return val - } - - // Parse .bazeliskrc in the workspace root, once, if it can be found. - fileConfigOnce.Do(func() { - workingDirectory, err := os.Getwd() - if err != nil { - return - } - workspaceRoot := findWorkspaceRoot(workingDirectory) - if workspaceRoot == "" { - return - } - rcFilePath := filepath.Join(workspaceRoot, ".bazeliskrc") - contents, err := ioutil.ReadFile(rcFilePath) - if err != nil { - if os.IsNotExist(err) { - return - } - log.Fatal(err) - } - fileConfig = make(map[string]string) - for _, line := range strings.Split(string(contents), "\n") { - if strings.HasPrefix(line, "#") { - // comments - continue - } - parts := strings.SplitN(line, "=", 2) - if len(parts) < 2 { - continue - } - key := strings.TrimSpace(parts[0]) - fileConfig[key] = strings.TrimSpace(parts[1]) - } - }) - - return fileConfig[name] -} - -// isValidWorkspace returns true iff the supplied path is the workspace root, defined by the presence of -// a file named WORKSPACE or WORKSPACE.bazel -// see https://github.com/bazelbuild/bazel/blob/8346ea4cfdd9fbd170d51a528fee26f912dad2d5/src/main/cpp/workspace_layout.cc#L37 -func isValidWorkspace(path string) bool { - info, err := os.Stat(path) - if err != nil { - return false - } - - return !info.IsDir() -} - -func findWorkspaceRoot(root string) string { - if isValidWorkspace(filepath.Join(root, "WORKSPACE")) { - return root - } - - if isValidWorkspace(filepath.Join(root, "WORKSPACE.bazel")) { - return root - } - - parentDirectory := filepath.Dir(root) - if parentDirectory == root { - return "" - } - - return findWorkspaceRoot(parentDirectory) -} - func getBazelVersion() (string, error) { // Check in this order: // - env var "USE_BAZEL_VERSION" is set to a specific version. @@ -262,7 +192,7 @@ func getBazelVersion() (string, error) { // - workspace_root/.bazelversion exists -> read contents, that version. // - workspace_root/WORKSPACE contains a version -> that version. (TODO) // - fallback: latest release - bazelVersion := GetEnvOrConfig("USE_BAZEL_VERSION") + bazelVersion := configs.GetEnvOrConfig("USE_BAZEL_VERSION") if len(bazelVersion) != 0 { return bazelVersion, nil } @@ -272,7 +202,7 @@ func getBazelVersion() (string, error) { return "", fmt.Errorf("could not get working directory: %v", err) } - workspaceRoot := findWorkspaceRoot(workingDirectory) + workspaceRoot := path.FindWorkspaceRoot(workingDirectory) if len(workspaceRoot) != 0 { bazelVersionPath := filepath.Join(workspaceRoot, ".bazelversion") if _, err := os.Stat(bazelVersionPath); err == nil { @@ -323,7 +253,7 @@ func downloadBazel(fork string, version string, baseDirectory string, repos *Rep destFile := "bazel" + platforms.DetermineExecutableFilenameSuffix() destinationDir := filepath.Join(baseDirectory, pathSegment, "bin") - if url := GetEnvOrConfig(BaseURLEnv); url != "" { + if url := configs.GetEnvOrConfig(BaseURLEnv); url != "" { return repos.DownloadFromBaseURL(url, version, destinationDir, destFile) } @@ -370,7 +300,7 @@ func linkLocalBazel(baseDirectory string, bazelPath string) (string, error) { } func maybeDelegateToWrapper(bazel string) string { - if GetEnvOrConfig(skipWrapperEnv) != "" { + if configs.GetEnvOrConfig(skipWrapperEnv) != "" { return bazel } @@ -379,7 +309,7 @@ func maybeDelegateToWrapper(bazel string) string { return bazel } - root := findWorkspaceRoot(wd) + root := path.FindWorkspaceRoot(wd) wrapper := filepath.Join(root, wrapperPath) if stat, err := os.Stat(wrapper); err != nil || stat.IsDir() || stat.Mode().Perm()&0001 == 0 { return bazel @@ -492,7 +422,7 @@ func insertArgs(baseArgs []string, newArgs []string) []string { } func shutdownIfNeeded(bazelPath string) { - bazeliskClean := GetEnvOrConfig("BAZELISK_SHUTDOWN") + bazeliskClean := configs.GetEnvOrConfig("BAZELISK_SHUTDOWN") if len(bazeliskClean) == 0 { return } @@ -510,7 +440,7 @@ func shutdownIfNeeded(bazelPath string) { } func cleanIfNeeded(bazelPath string) { - bazeliskClean := GetEnvOrConfig("BAZELISK_CLEAN") + bazeliskClean := configs.GetEnvOrConfig("BAZELISK_CLEAN") if len(bazeliskClean) == 0 { return } diff --git a/core/path/BUILD.bazel b/core/path/BUILD.bazel new file mode 100644 index 00000000..72e24197 --- /dev/null +++ b/core/path/BUILD.bazel @@ -0,0 +1,8 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["path.go"], + importpath = "github.com/bazelbuild/bazelisk/core/path", + visibility = ["//visibility:public"], +) diff --git a/core/path/path.go b/core/path/path.go new file mode 100644 index 00000000..4e00c16d --- /dev/null +++ b/core/path/path.go @@ -0,0 +1,37 @@ +// Package core.configs contains the core.configs Bazelisk logic, as well as abstractions for Bazel repositories. +package path + +import ( + "os" + "path/filepath" +) + +// isValidWorkspace returns true iff the supplied path is the workspace root, defined by the presence of +// a file named WORKSPACE or WORKSPACE.bazel +// see https://github.com/bazelbuild/bazel/blob/8346ea4cfdd9fbd170d51a528fee26f912dad2d5/src/main/cpp/workspace_layout.cc#L37 +func isValidWorkspace(path string) bool { + info, err := os.Stat(path) + if err != nil { + return false + } + + return !info.IsDir() +} + +// FindWorkspaceRoot find the WORKSPACE root path. +func FindWorkspaceRoot(root string) string { + if isValidWorkspace(filepath.Join(root, "WORKSPACE")) { + return root + } + + if isValidWorkspace(filepath.Join(root, "WORKSPACE.bazel")) { + return root + } + + parentDirectory := filepath.Dir(root) + if parentDirectory == root { + return "" + } + + return FindWorkspaceRoot(parentDirectory) +} diff --git a/httputil/BUILD b/httputil/BUILD index 89113cad..49bb5430 100644 --- a/httputil/BUILD +++ b/httputil/BUILD @@ -10,12 +10,12 @@ go_library( "fake.go", "httputil.go", ], + importpath = "github.com/bazelbuild/bazelisk/httputil", + visibility = ["//visibility:public"], deps = [ + "@com_github_jdxcode_netrc//:go_default_library", "@com_github_mitchellh_go_homedir//:go_default_library", - "@com_github_jdxcode_netrc//:go_default_library" ], - importpath = "github.com/bazelbuild/bazelisk/httputil", - visibility = ["//visibility:public"], ) go_test( diff --git a/platforms/BUILD b/platforms/BUILD index 6b8f9257..2cdaaf90 100644 --- a/platforms/BUILD +++ b/platforms/BUILD @@ -6,6 +6,7 @@ go_library( importpath = "github.com/bazelbuild/bazelisk/platforms", visibility = ["//visibility:public"], deps = [ + "//core/configs:go_default_library", "@com_github_hashicorp_go_version//:go_default_library", ], ) @@ -15,3 +16,9 @@ go_test( srcs = ["platforms_test.go"], embed = [":go_default_library"], ) + +go_test( + name = "go_default_test", + srcs = ["platforms_test.go"], + embed = [":go_default_library"], +) diff --git a/platforms/platforms.go b/platforms/platforms.go index a779db3f..8e6f6228 100644 --- a/platforms/platforms.go +++ b/platforms/platforms.go @@ -4,9 +4,10 @@ package platforms import ( "fmt" "log" - "os" "runtime" + "github.com/bazelbuild/bazelisk/core/configs" + semver "github.com/hashicorp/go-version" ) @@ -62,7 +63,7 @@ func DetermineBazelFilename(version string, includeSuffix bool) (string, error) } bazelFlavor := "bazel" - if val, ok := os.LookupEnv("BAZELISK_NOJDK"); ok && (val != "0") { + if configs.GetEnvOrConfig("BAZELISK_NOJDK") != "0" && configs.GetEnvOrConfig("BAZELISK_NOJDK") != "" { bazelFlavor = "bazel_nojdk" } return fmt.Sprintf("%s-%s-%s-%s%s", bazelFlavor, version, osName, machineName, filenameSuffix), nil