*: do not require env.sh
This removes the need to source env.{sh,fish} when working with hscloud.
This is done by:
1. Implementing a Go library to reliably detect the location of the
active hscloud checkout. That in turn is enabled by
BUILD_WORKSPACE_DIRECTORY being now a thing in Bazel.
2. Creating a tool `hscloud`, with a command `hscloud workspace` that
returns the workspace path.
3. Wrapping this tool to be accessible from Python and Bash.
4. Bumping all users of hscloud_root to use either the Go library or
one of the two implemented wrappers.
We also drive-by replace tools/install.sh to be a proper sh_binary, and
make it yell at people if it isn't being ran as `bazel run
//tools:install`.
Finally, we also drive-by delete cluster/tools/nixops.sh which was never used.
Change-Id: I7873714319bfc38bbb930b05baa605c5aa36470a
Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1169
Reviewed-by: informatic <informatic@hackerspace.pl>
diff --git a/cluster/clustercfg/BUILD b/cluster/clustercfg/BUILD
index 433f79c..e08a2e3 100644
--- a/cluster/clustercfg/BUILD
+++ b/cluster/clustercfg/BUILD
@@ -15,5 +15,6 @@
requirement("idna"),
requirement("six"),
"//tools:secretstore_lib",
+ "//tools/hscloud:python",
],
)
diff --git a/cluster/clustercfg/clustercfg.py b/cluster/clustercfg/clustercfg.py
index d852d6a..ea15df8 100644
--- a/cluster/clustercfg/clustercfg.py
+++ b/cluster/clustercfg/clustercfg.py
@@ -16,13 +16,12 @@
import fabric
from tools import secretstore
+from tools.hscloud import lib as hscloud
import ca
-local_root = os.getenv('hscloud_root')
-if local_root is None:
- raise Exception("Please source env.sh")
+local_root = hscloud.workspace_location()
cluster = 'k0.hswaw.net'
diff --git a/cluster/doc/user.md b/cluster/doc/user.md
index f04e7db..11ea959 100644
--- a/cluster/doc/user.md
+++ b/cluster/doc/user.md
@@ -19,7 +19,10 @@
Enter SSO/LDAP password for q3k@hackerspace.pl:
Good evening professor. I see you have driven here in your Ferrari.
-If `prodaccess` is not on your $PATH, ensure you have sourced `env.sh` from the root of hscloud and ran `tools/install.sh`.
+If `prodaccess` is not on your $PATH:
+
+ $ bazel run //tools:install
+ $ . env.sh
By default, `prodaccess` will use your local user name to authenticate as `<user>@hackerspce.pl`. If your Hackerspace SSO name is different, specify it using the `-u` flag to prodaccess, eg. `prodaccess -u informatic`.
diff --git a/cluster/prodaccess/BUILD.bazel b/cluster/prodaccess/BUILD.bazel
index 6c72082..4db48dd 100644
--- a/cluster/prodaccess/BUILD.bazel
+++ b/cluster/prodaccess/BUILD.bazel
@@ -13,6 +13,7 @@
"//cluster/certs:go_default_library",
"//cluster/prodvider/proto:go_default_library",
"//go/pki:go_default_library",
+ "//go/workspace:go_default_library",
"@com_github_golang_glog//:go_default_library",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_google_grpc//credentials:go_default_library",
diff --git a/cluster/prodaccess/kubernetes.go b/cluster/prodaccess/kubernetes.go
index 7226423..c50cd07 100644
--- a/cluster/prodaccess/kubernetes.go
+++ b/cluster/prodaccess/kubernetes.go
@@ -14,17 +14,18 @@
"github.com/golang/glog"
pb "code.hackerspace.pl/hscloud/cluster/prodvider/proto"
+ "code.hackerspace.pl/hscloud/go/workspace"
)
func kubernetesPaths() (string, string, string) {
- localRoot := os.Getenv("hscloud_root")
- if localRoot == "" {
- glog.Exitf("Please source env.sh")
+ ws, err := workspace.Get()
+ if err != nil {
+ glog.Exitf("%v", err)
}
- localKey := path.Join(localRoot, ".kubectl", fmt.Sprintf("%s.key", flagUsername))
- localCert := path.Join(localRoot, ".kubectl", fmt.Sprintf("%s.crt", flagUsername))
- localCA := path.Join(localRoot, ".kubectl", fmt.Sprintf("ca.crt"))
+ localKey := path.Join(ws, ".kubectl", fmt.Sprintf("%s.key", flagUsername))
+ localCert := path.Join(ws, ".kubectl", fmt.Sprintf("%s.crt", flagUsername))
+ localCA := path.Join(ws, ".kubectl", fmt.Sprintf("ca.crt"))
return localKey, localCert, localCA
}
diff --git a/cluster/tools/BUILD b/cluster/tools/BUILD
index 2526fd7..a63245e 100644
--- a/cluster/tools/BUILD
+++ b/cluster/tools/BUILD
@@ -22,7 +22,14 @@
sh_binary(
name = "calicoctl",
srcs = ["calicoctl.sh"],
- data = [":calicoctl.bin", "//tools:secretstore"],
+ data = [
+ ":calicoctl.bin",
+ "//tools:secretstore",
+ "//tools/hscloud",
+ ],
+ deps = [
+ "//tools/hscloud:shell",
+ ],
)
copy_go_binary(
diff --git a/cluster/tools/calicoctl.sh b/cluster/tools/calicoctl.sh
index 30fe652..86e1097 100755
--- a/cluster/tools/calicoctl.sh
+++ b/cluster/tools/calicoctl.sh
@@ -1,23 +1,22 @@
#!/usr/bin/env bash
-# A wrapper around the real calicoctl to configure etcd access...
+# A wrapper around the real calicoctl to configure etcd access.
-if [ -z "$hscloud_root" ]; then
- echo 2>&1 "Please source env.sh"
- exit 1
-fi
+source tools/hscloud/lib.sh || exit 1
-ETCD_ENDPOINTS="https://bc01n01.hswaw.net:2379,https://bc01n01.hswaw.net:2379,https://bc01n01.hswaw.net:2379"
-ETCD_KEY_FILE="$hscloud_root/cluster/secrets/plain/etcd-calico.key"
-ETCD_CERT_FILE="$hscloud_root/cluster/certs/etcd-calico.cert"
-ETCD_CA_CERT_FILE="$hscloud_root/cluster/certs/ca-etcd.crt"
+function main() {
+ local ws=$(hscloud::workspace_location)
-if [ ! -f "$ETCD_KEY_FILE" ] ; then
- secretstore decrypt "$hscloud_root/cluster/secrets/cipher/etcd-calico.key" > "$ETCD_KEY_FILE"
-fi
+ export ETCD_ENDPOINTS="https://bc01n01.hswaw.net:2379,https://bc01n01.hswaw.net:2379,https://bc01n01.hswaw.net:2379"
+ export ETCD_KEY_FILE="$ws/cluster/secrets/plain/etcd-calico.key"
+ export ETCD_CERT_FILE="$ws/cluster/certs/etcd-calico.cert"
+ export ETCD_CA_CERT_FILE="$ws/cluster/certs/ca-etcd.crt"
-export ETCD_ENDPOINTS
-export ETCD_KEY_FILE
-export ETCD_CERT_FILE
-export ETCD_CA_CERT_FILE
-calicoctl.bin "$@"
+ if [ ! -f "$ETCD_KEY_FILE" ] ; then
+ $(hscloud::must_rlocation hscloud/tools/secretstore) decrypt "$ws/cluster/secrets/cipher/etcd-calico.key" "$ETCD_KEY_FILE"
+ fi
+
+ "$(hscloud::must_rlocation hscloud/cluster/tools/calicoctl.bin)" "$@"
+}
+
+main "$@"
diff --git a/cluster/tools/install.sh b/cluster/tools/install.sh
deleted file mode 100755
index 6f32fbb..0000000
--- a/cluster/tools/install.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-
-set -e -o pipefail
-
-if [ -z "$hscloud_root" ]; then
- echo 2>&1 "Please first source env.sh"
- exit 1
-fi
-
-cd "${hscloud_root}"
-
-bazel build \
- //cluster/tools:kubectl \
- //cluster/tools:kubecfg \
- //cluster/tools:calicoctl \
- //cluster/tools:cfssl
-
diff --git a/cluster/tools/nixops.sh b/cluster/tools/nixops.sh
deleted file mode 100755
index e810972..0000000
--- a/cluster/tools/nixops.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-# A wrapper around real nixops to decrypt GCP secret.
-
-if [ -z "$hscloud_root" ]; then
- echo 2>&1 "Please source env.sh"
- exit 1
-fi
-
-for f in sa.json sa.pem; do
- plain="$hscloud_root/gcp/secrets/plain/$f"
- cipher="$hscloud_root/gcp/secrets/cipher/$f"
- if [ ! -f "$plain" ]; then
- secretstore decrypt "$cipher" > "$plain"
- fi
-done
-
-export GCE_PROJECT="hscloud"
-export GCE_SERVICE_ACCOUNT="nixops@hscloud.iam.gserviceaccount.com"
-export ACCESS_KEYPATH="$hscloud_root/gcp/secrets/plain/sa.pem"
-
-./external/nixops/bin/nixops "$@"
diff --git a/env.fish b/env.fish
index 428c5df..02cfa77 100644
--- a/env.fish
+++ b/env.fish
@@ -11,6 +11,8 @@
set -x PATH $hscloud_path $PATH
end
+# Leftover junk. This should be removed, as env.fish is now optional.
+# Do _not_ add more aliases!
function gpg-unlock
echo "test" | gpg2 --sign --batch --no-tty -o /dev/null
end
diff --git a/env.sh b/env.sh
index e9cfd22..0723030 100644
--- a/env.sh
+++ b/env.sh
@@ -1,23 +1,24 @@
-# source me to have all the nice things
+# Source this file to have hscloud tools available in your PATH after running
+# `bazel run //tools:install`.
if [ "$0" == "$BASH_SOURCE" ]; then
echo "You should be sourcing this."
exit 1
fi
-export hscloud_root="$( cd "$(dirname "$BASH_SOURCE")"; pwd -P )"
-
+hscloud_root="$( cd "$(dirname "$BASH_SOURCE")"; pwd -P )"
if [ ! -f "$hscloud_root/WORKSPACE" ]; then
echo "Could not find WORKSPACE"
exit 1
fi
-
hscloud_path="$hscloud_root/bazel-bin/tools:$hscloud_root/bazel-bin/cluster/tools"
-
[[ ":$PATH:" != *":$hscloud_path:"* ]] && PATH="$hscloud_path:${PATH}"
+unset -f hscloud_root
+unset -f hscloud_path
+# Leftover junk. This should be removed, as env.sh is now optional.
+# Do _not_ add more aliases!
alias bajzel=bazel
-
gpg-unlock() {
echo "test" | gpg2 --sign --batch --no-tty -o /dev/null
}
diff --git a/go/workspace/BUILD.bazel b/go/workspace/BUILD.bazel
new file mode 100644
index 0000000..34f8acc
--- /dev/null
+++ b/go/workspace/BUILD.bazel
@@ -0,0 +1,8 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["workspace.go"],
+ importpath = "code.hackerspace.pl/hscloud/go/workspace",
+ visibility = ["//visibility:public"],
+)
diff --git a/go/workspace/workspace.go b/go/workspace/workspace.go
new file mode 100644
index 0000000..f8f2ef9
--- /dev/null
+++ b/go/workspace/workspace.go
@@ -0,0 +1,101 @@
+package workspace
+
+import (
+ "fmt"
+ "os"
+ "path"
+ "sync"
+ "syscall"
+)
+
+// isWorkspace returns whether a given string is a valid path pointing to a
+// Bazel workspace directory.
+func isWorkspace(dir string) bool {
+ w := path.Join(dir, "WORKSPACE")
+ if _, err := os.Stat(w); err == nil {
+ return true
+ }
+ return false
+}
+
+// getPathFSID returns an opaque filesystem identifier for a given path.
+func getPathFSID(dir string) (uint64, error) {
+ st, err := os.Stat(dir)
+ if err != nil {
+ // No need to wrap err, as stat errors are already quite explicit
+ // (they also include the stat'd path).
+ return 0, err
+ }
+ switch x := st.Sys().(type) {
+ case *syscall.Stat_t:
+ return x.Dev, nil
+ default:
+ return 0, fmt.Errorf("unsupported operating system (got stat type %+v)", st.Sys())
+ }
+}
+
+// lookForWorkspace recurses up a directory until it finds a WORKSPACE, the
+// root, or crosses a filesystem boundary.
+func lookForWorkspace(dir string) (string, error) {
+ fsid, err := getPathFSID(dir)
+ if err != nil {
+ return "", fmt.Errorf("could not get initial FSID: %w", err)
+ }
+ for {
+ if dir == "." || dir == "/" || dir == "" {
+ return "", fmt.Errorf("got up to root before finding workspace")
+ }
+
+ fsid2, err := getPathFSID(dir)
+ if err != nil {
+ return "", fmt.Errorf("could not get parent FWID: %w", err)
+ }
+ if fsid2 != fsid {
+ return "", fmt.Errorf("crossed filesystem boundaries before finding workspace")
+ }
+
+ if isWorkspace(dir) {
+ return dir, nil
+ }
+ dir = path.Dir(dir)
+ }
+}
+
+// Get returns the workspace directory from which a given
+// command line tool is running. This handles the following
+// cases:
+//
+// 1. The command line tool was invoked via `bazel run`.
+// 2. The command line tool was started in the workspace directory or a
+// subdirectory.
+//
+// If the workspace directory path cannot be inferred based on the above
+// assumptions, an error is returned.
+func Get() (string, error) {
+ workspaceOnce.Do(func() {
+ workspace, workspaceErr = get()
+ })
+ return workspace, workspaceErr
+}
+
+var (
+ workspace string
+ workspaceErr error
+ workspaceOnce sync.Once
+)
+
+func get() (string, error) {
+ if p := os.Getenv("BUILD_WORKSPACE_DIRECTORY"); p != "" && isWorkspace(p) {
+ return p, nil
+ }
+
+ wd, err := os.Getwd()
+ if err != nil {
+ return "", err
+ }
+ p, err := lookForWorkspace(wd)
+ if err != nil {
+ return "", fmt.Errorf("not invoked from `bazel run` and could not find workspace root by traversing upwards: %w", err)
+ }
+ return p, nil
+}
diff --git a/shell.nix b/shell.nix
index 080aca0..e295a36 100644
--- a/shell.nix
+++ b/shell.nix
@@ -10,7 +10,7 @@
''
source /etc/profile
source ${toString ./.}/env.sh
- ${toString ./.}/tools/install.sh
+ bazel run //tools:install
# Fancy colorful PS1 to make people notice easily they're in hscloud.
PS1='\[\033]0;\u/hscloud:\w\007\]'
diff --git a/tools/BUILD b/tools/BUILD
index 64faf53..daf6c12 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -1,6 +1,17 @@
load("@bazel_tools//tools/build_defs/pkg:pkg.bzl", "pkg_tar", "pkg_deb")
load("//bzl:rules.bzl", "copy_go_binary")
+sh_binary(
+ name = "install",
+ srcs = [
+ "install.sh",
+ ],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//tools/hscloud:shell",
+ ],
+)
+
py_library(
name = "secretstore_lib",
srcs = ["secretstore.py"],
diff --git a/tools/hscloud/BUILD.bazel b/tools/hscloud/BUILD.bazel
new file mode 100644
index 0000000..ac455b3
--- /dev/null
+++ b/tools/hscloud/BUILD.bazel
@@ -0,0 +1,46 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+
+go_library(
+ name = "hscloud_lib",
+ srcs = ["main.go"],
+ importpath = "code.hackerspace.pl/hscloud/tools/hscloud",
+ visibility = ["//visibility:private"],
+ deps = [
+ "//go/workspace:go_default_library",
+ "@com_github_spf13_cobra//:go_default_library",
+ ],
+)
+
+go_binary(
+ name = "hscloud",
+ embed = [":hscloud_lib"],
+ visibility = ["//visibility:public"],
+)
+
+sh_library(
+ name = "shell",
+ srcs = [
+ "lib.sh",
+ ],
+ deps = [
+ "@bazel_tools//tools/bash/runfiles",
+ ],
+ data = [
+ ":hscloud",
+ ],
+ visibility = ["//visibility:public"],
+)
+
+py_library(
+ name = "python",
+ srcs = [
+ "lib.py",
+ ],
+ deps = [
+ "@rules_python//python/runfiles",
+ ],
+ data = [
+ ":hscloud",
+ ],
+ visibility = ["//visibility:public"],
+)
diff --git a/tools/hscloud/lib.py b/tools/hscloud/lib.py
new file mode 100644
index 0000000..1ef2b33
--- /dev/null
+++ b/tools/hscloud/lib.py
@@ -0,0 +1,45 @@
+# Library to interact with the active hscloud checkout. This supersedes the
+# hscloud_root environment variable once used in hscloud.
+#
+# Some of this could be implemented in Python instead of shelling out to a Go
+# binary - but that way we have a single source of truth, even if it's janky.
+#
+# To use:
+#
+# from tools.hscloud import lib as hscloud
+#
+# And specify deps = [ "//tools/hscloud:python" ] in py_binary.
+
+import subprocess
+
+from rules_python.python.runfiles import runfiles
+
+
+r = runfiles.Create()
+
+
+def tool_location():
+ """
+ Return an absolute path to a built //tools/hscloud binary, ready to run.
+ """
+ rloc = r.Rlocation("hscloud/tools/hscloud/hscloud_/hscloud")
+ if rloc is None:
+ raise Exception("Could not find location of hscloud - are you in a valid checkout?")
+ return rloc
+
+
+def workspace_location():
+ """Return an absolute path to the hscloud checkout."""
+ return subprocess.check_output([tool_location(), "workspace"]).decode()
+
+
+def must_rlocation(runfile):
+ """Return an absolute path to a runfile, eg. a data depndency in sh_binary."""
+ rloc = r.Rlocation(runfile)
+ if rloc is None:
+ msg = f"Could not find runfile {runfile}"
+ manifest = os.environ.get("RUNFILES_MANIFEST_FILE", "")
+ if manifest != "":
+ msg += f"; manifest file: {manifest}"
+ raise Exception(msg)
+ return rloc
diff --git a/tools/hscloud/lib.sh b/tools/hscloud/lib.sh
new file mode 100644
index 0000000..c45b050
--- /dev/null
+++ b/tools/hscloud/lib.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+
+# Top-level 'universal' shell library for hscloud. All sh_binary targets should
+# depend on this and import it as follows:
+#
+# #!/usr/bin/env bash
+# source tools/hscloud/lib.sh || exit 1
+#
+# And by specifying deps = [ "//tools/hscloud:shell" ] in sh_binary.
+
+set -e -u -o pipefail
+
+function hscloud::_prepare_runfiles() {
+ if [[ $(type -t rlocation) == function ]]; then
+ return
+ fi
+ # --- begin runfiles.bash initialization v2 ---
+ # Mostly copy-pasted from the Bazel Bash runfiles library v2.
+ local f=bazel_tools/tools/bash/runfiles/runfiles.bash
+ source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
+ source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
+ source "$0.runfiles/$f" 2>/dev/null || \
+ source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
+ source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
+ { echo>&2 "ERROR: cannot find $f - are you in a valid checkout and running the script via bazel?"; exit 1; }
+ # --- end runfiles.bash initialization v2 ---
+}
+
+# Return an absolute path to a built //tools/hscloud binary, ready to run.
+#
+# This will fail if we're not in a hscloud checkout.
+function hscloud::tool_location() {
+ rloc="$(hscloud::rlocation "hscloud/tools/hscloud/hscloud_/hscloud")"
+ if [ -z "$rloc" ]; then
+ echo "Could not find location of hscloud - are you in a valid checkout and running the script via bazel?" >&2
+ exit 1
+ fi
+ echo "$rloc"
+}
+
+# Return an absolute path to the hscloud checkout.
+function hscloud::workspace_location() {
+ $(hscloud::tool_location) workspace
+}
+
+# Return an absolute path to a runfile, eg. a data dependency in sh_binary.
+function hscloud::rlocation() {
+ hscloud::_prepare_runfiles
+ echo "$(rlocation "$1")"
+}
+
+# Return an absolute path to a runfile, eg. a data dependency in sh_binary.
+#
+# This will fail if the runfile is not found.
+function hscloud::must_rlocation() {
+ rloc="$(hscloud::rlocation $1)"
+ if [ -z "$rloc" ]; then
+ echo "Could not find runfile $1" >&2
+ if [ ! -z "${RUNFILES_MANIFEST_FILE:-}" ]; then
+ echo "Manifest file: $RUNFILES_MANIFEST_FILE" >&2
+ fi
+ exit 1
+ fi
+ echo "$rloc"
+}
diff --git a/tools/hscloud/main.go b/tools/hscloud/main.go
new file mode 100644
index 0000000..35f00f3
--- /dev/null
+++ b/tools/hscloud/main.go
@@ -0,0 +1,37 @@
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "code.hackerspace.pl/hscloud/go/workspace"
+ "github.com/spf13/cobra"
+)
+
+var rootCmd = &cobra.Command{
+ Use: "hscloud",
+ Short: "hscloud kitchesink tool",
+ Long: `A single entrypoint tool to interact with a hscloud git checkout.`,
+}
+
+var workspaceCmd = &cobra.Command{
+ Use: "workspace",
+ Short: "Print root path of hscloud checkuot",
+ Long: `This returns the directory path containing WORKSPACE. It works both from 'bazel run', when invoked as a tool in bazel or when called manually. Feel free to use this in your sh_binary scripts.`,
+ Run: func(cmd *cobra.Command, args []string) {
+ wd, err := workspace.Get()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%v", err)
+ os.Exit(1)
+ }
+ fmt.Println(wd)
+ },
+}
+
+func main() {
+ rootCmd.AddCommand(workspaceCmd)
+ if err := rootCmd.Execute(); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+}
diff --git a/tools/install.sh b/tools/install.sh
index 6151a38..04b4f79 100755
--- a/tools/install.sh
+++ b/tools/install.sh
@@ -1,14 +1,52 @@
#!/usr/bin/env bash
+source tools/hscloud/lib.sh || exit 1
-set -e -o pipefail
+function main() {
+ # If we're not running from `bazel run/buld`, complain and re-execute
+ # ourselves.
+ #
+ # We do the check fairly low level, as //tools/hscloud:lib.sh will just
+ # fail in this case. We want to be nice.
+ #
+ # This is all mostly copied from the runfiles.bash snippet in
+ # tools/hscloud/lib.sh.
+ f=bazel_tools/tools/bash/runfiles/runfiles.bash
+ if [ ! -e "${RUNFILES_DIR:-/dev/null}/$f" ] && \
+ [ ! -e "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" ] && \
+ [ ! -e "$0.runfiles/$f" ] && \
+ [ ! -e "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" ] && \
+ [ ! -e "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" ]; then
+ echo "Uh-oh, looks like you didn't run this as 'bazel run //tools:install'.">&2
+ echo "Let me fix that for you in a few seconds - but work on your muscle memory, as we'll stop supporting this by some point.">&2
+ sleep 2
+ bazel run //tools:install -- "$@"
+ exit $?
+ fi
-if [ -z "$hscloud_root" ]; then
- echo 2>&1 "Please first source env.sh"
- exit 1
-fi
+ cd $(hscloud::workspace_location)
+ echo "Building hscloud tools and cluster tools..."
+ bazel build //tools/... //cluster/tools/...
-cd "${hscloud_root}"
+ local path_missing=""
+ local path="$(hscloud::workspace_location)/bazel-bin/tools"
+ if [[ ":$PATH:" == *":$path:"* ]]; then
+ path_missing="$path"
+ fi
+ local path="$(hscloud::workspace_location)/bazel-bin/cluster/tools"
+ if [[ ":$PATH:" == *":$path:"* ]]; then
+ if [ -z "$path_missing" ]; then
+ path_missing="$path"
+ else
+ path_missing="$path_missing:$path"
+ fi
+ fi
+ if [ -z "$path_missing" ]; then
+ echo "Tools built correctly, but your PATH should be updated to access them:">&2
+ echo ' PATH="$PATH:'$path_missing'"'
+ echo 'Add the above line to your shell profile, or source env.sh from the root of hscloud.'
+ else
+ echo "Tools built correctly and in PATH. Happy hsclouding!"
+ fi
+}
-bazel build //tools/...
-
-cluster/tools/install.sh
+main "$@"