build/toolbase: init

In an effort to better the developer/CI experience, I'm moving some of
our presubmit checks into a Go tool. This is a helper library that will
be used to interact with a Monogon workspace checkout from Go, both in
the new presubmit tool but also any other future tools that would like
to operate on source code.

Change-Id: Ie5f1b1d0153a1c853c241e167d2d3a469c636c94
Reviewed-on: https://review.monogon.dev/c/monogon/+/328
Reviewed-by: Mateusz Zalega <mateusz@monogon.tech>
diff --git a/build/toolbase/workspace.go b/build/toolbase/workspace.go
new file mode 100644
index 0000000..0994ac5
--- /dev/null
+++ b/build/toolbase/workspace.go
@@ -0,0 +1,38 @@
+package toolbase
+
+import (
+	"fmt"
+	"os"
+	"path"
+)
+
+// 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
+}
+
+// WorkspaceDirectory 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 directly in a workspace directory (but
+//    not a subdirectory).
+//
+// If the workspace directory path cannot be inferred based on the above
+// assumptions, an error is returned.
+func WorkspaceDirectory() (string, error) {
+	if p := os.Getenv("BUILD_WORKSPACE_DIRECTORY"); p != "" && isWorkspace(p) {
+		return p, nil
+	}
+
+	if p, err := os.Getwd(); err != nil && isWorkspace(p) {
+		return p, nil
+	}
+
+	return "", fmt.Errorf("not invoked from `bazel run` and not running in workspace directory")
+}