build/fietsje: split into monogon-specific library and cli tool

This is a first pass at sightly modularizing fietsje. This allows
fietsje-for-Monogon to be used as a Go library, and moves all the
toolbase startup logic into its own executable package. This allows us
to call fietsje from some multi-purpose CI/check tool that I'm slowly
implementing on the side.

Fietsje should still be split up further, allowing a generic fietsje
library to be used for more than just the Monogon repository - but that
will come at a later point.

Change-Id: Ic59c0bb954c5416fda95d3604d5aa94553dc1030
Reviewed-on: https://review.monogon.dev/c/monogon/+/331
Reviewed-by: Mateusz Zalega <mateusz@monogon.tech>
diff --git a/build/fietsje/BUILD.bazel b/build/fietsje/BUILD.bazel
index 733a832..5fe5f5e 100644
--- a/build/fietsje/BUILD.bazel
+++ b/build/fietsje/BUILD.bazel
@@ -1,4 +1,4 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
 
 go_library(
     name = "go_default_library",
@@ -8,30 +8,22 @@
         "deps_delve.go",
         "deps_gvisor.go",
         "deps_kubernetes.go",
-        "main.go",
+        "deps_monogon.go",
         "planner.go",
         "render.go",
         "shelf.go",
         "transitive.go",
     ],
     importpath = "source.monogon.dev/build/fietsje",
-    visibility = ["//visibility:private"],
+    visibility = ["//build:__subpackages__"],
     deps = [
         "//build/fietsje/proto:go_default_library",
-        "//build/toolbase:go_default_library",
-        "//build/toolbase/gotoolchain:go_default_library",
         "@bazel_gazelle//label:go_default_library",
         "@com_github_golang_protobuf//proto:go_default_library",
         "@org_golang_x_mod//modfile:go_default_library",
     ],
 )
 
-go_binary(
-    name = "fietsje",
-    embed = [":go_default_library"],
-    visibility = ["//visibility:public"],
-)
-
 exports_files(
     [
         "fietsje.bash.in",
diff --git a/build/fietsje/cmd/BUILD.bazel b/build/fietsje/cmd/BUILD.bazel
new file mode 100644
index 0000000..00ab0f0
--- /dev/null
+++ b/build/fietsje/cmd/BUILD.bazel
@@ -0,0 +1,19 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+
+go_library(
+    name = "go_default_library",
+    srcs = ["main.go"],
+    importpath = "source.monogon.dev/build/fietsje/cmd",
+    visibility = ["//visibility:private"],
+    deps = [
+        "//build/fietsje:go_default_library",
+        "//build/toolbase:go_default_library",
+        "//build/toolbase/gotoolchain:go_default_library",
+    ],
+)
+
+go_binary(
+    name = "cmd",
+    embed = [":go_default_library"],
+    visibility = ["//visibility:public"],
+)
diff --git a/build/fietsje/cmd/main.go b/build/fietsje/cmd/main.go
new file mode 100644
index 0000000..b9e1553
--- /dev/null
+++ b/build/fietsje/cmd/main.go
@@ -0,0 +1,49 @@
+// Copyright 2020 The Monogon Project Authors.
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// fietsje is the standalone command line tool which calls into the Fietsje
+// library (//build/fietsje) to perform actual work. The split between cli and
+// main library is used so that Fietsje can be called from other Go tooling
+// without having to shell out to a binary.
+package main
+
+import (
+	"log"
+	"os"
+	"path"
+
+	"source.monogon.dev/build/fietsje"
+	"source.monogon.dev/build/toolbase"
+	"source.monogon.dev/build/toolbase/gotoolchain"
+)
+
+func main() {
+	// Get absolute path of Monogon workspace directory currently operating on
+	// (either via bazel run or by running it directly in the root of a checkout),
+	// use it to build paths to shelf.pb.txt and repositories.bzl.
+	wd, err := toolbase.WorkspaceDirectory()
+	if err != nil {
+		log.Fatalf("%v", err)
+	}
+	shelfPath := path.Join(wd, "third_party/go/shelf.pb.text")
+	repositoriesBzlPath := path.Join(wd, "third_party/go/repositories.bzl")
+	// Set GOROOT as required by fietsje/go-the-tool.
+	os.Setenv("GOROOT", gotoolchain.Root)
+
+	if err := fietsje.Monogon(shelfPath, repositoriesBzlPath); err != nil {
+		log.Fatal(err)
+	}
+}
diff --git a/build/fietsje/dependency.go b/build/fietsje/dependency.go
index 709b457..e3520a4 100644
--- a/build/fietsje/dependency.go
+++ b/build/fietsje/dependency.go
@@ -14,7 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package fietsje
 
 import (
 	"encoding/json"
diff --git a/build/fietsje/deps_containerd.go b/build/fietsje/deps_containerd.go
index 99d36f6..37c71c5 100644
--- a/build/fietsje/deps_containerd.go
+++ b/build/fietsje/deps_containerd.go
@@ -14,7 +14,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package fietsje
+
+// deps_containerd.go contains all dependencies required by containerd/runc.
 
 func depsContainerd(p *planner) {
 	p.collectOverride(
diff --git a/build/fietsje/deps_delve.go b/build/fietsje/deps_delve.go
index 747f3e2..69258a8 100644
--- a/build/fietsje/deps_delve.go
+++ b/build/fietsje/deps_delve.go
@@ -14,7 +14,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package fietsje
+
+// deps_delve.go contains all dependencies required by the Delve debugger.
 
 func depsDelve(p *planner) {
 	p.collect("github.com/go-delve/delve", "v1.4.1").use(
diff --git a/build/fietsje/deps_gvisor.go b/build/fietsje/deps_gvisor.go
index 3414e4c..c4e7ca0 100644
--- a/build/fietsje/deps_gvisor.go
+++ b/build/fietsje/deps_gvisor.go
@@ -14,7 +14,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package fietsje
+
+// deps_gvisor.go contains all dependencies required by gVisor/runsc.
 
 func depsGVisor(p *planner) {
 	p.collect(
diff --git a/build/fietsje/deps_kubernetes.go b/build/fietsje/deps_kubernetes.go
index ffd650e..bea586e 100644
--- a/build/fietsje/deps_kubernetes.go
+++ b/build/fietsje/deps_kubernetes.go
@@ -14,7 +14,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package fietsje
+
+// deps_kubernetes.go contains all dependencies required by Kubernetes.
 
 func depsKubernetes(p *planner) {
 	// containerd and its deps
diff --git a/build/fietsje/main.go b/build/fietsje/deps_monogon.go
similarity index 76%
rename from build/fietsje/main.go
rename to build/fietsje/deps_monogon.go
index 6fb66e1..fc81bf5 100644
--- a/build/fietsje/main.go
+++ b/build/fietsje/deps_monogon.go
@@ -1,49 +1,20 @@
-// Copyright 2020 The Monogon Project Authors.
-//
-// SPDX-License-Identifier: Apache-2.0
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+package fietsje
 
-package main
+// deps_monogon.go contains the main entrypoint for Monogon-specific
+// dependencies to be handled by fietsje, and calls out to all other functions
+// in deps_*.go.
 
 import (
 	"bytes"
-	"flag"
+	"fmt"
 	"io/ioutil"
-	"log"
-	"os"
-	"path"
-
-	"source.monogon.dev/build/toolbase"
-	"source.monogon.dev/build/toolbase/gotoolchain"
 )
 
-func main() {
-	flag.Parse()
-
-	// TODO(q3k): factor out fietsje as a library, make it independent from
-	// monogon workspace assumptions.
-	wd, err := toolbase.WorkspaceDirectory()
-	if err != nil {
-		log.Fatalf("%v", err)
-	}
-	shelfPath := path.Join(wd, "third_party/go/shelf.pb.text")
-	repositoriesBzlPath := path.Join(wd, "third_party/go/repositories.bzl")
-	os.Setenv("GOROOT", gotoolchain.Root)
-
+// Monogon runs fietsje for all Monogon transitive dependencies.
+func Monogon(shelfPath, repositoriesBzlPath string) error {
 	shelf, err := shelfLoad(shelfPath)
 	if err != nil {
-		log.Fatalf("could not load shelf: %v", err)
+		return fmt.Errorf("could not load shelf: %w", err)
 	}
 
 	p := &planner{
@@ -160,11 +131,12 @@
 	buf := bytes.NewBuffer(nil)
 	err = p.render(buf)
 	if err != nil {
-		log.Fatalf("could not render deps: %v", err)
+		return fmt.Errorf("could not render deps: %w", err)
 	}
 
 	err = ioutil.WriteFile(repositoriesBzlPath, buf.Bytes(), 0666)
 	if err != nil {
-		log.Fatalf("could not write deps: %v", err)
+		return fmt.Errorf("could not write deps: %w", err)
 	}
+	return nil
 }
diff --git a/build/fietsje/planner.go b/build/fietsje/planner.go
index be955cf..0be1b8a 100644
--- a/build/fietsje/planner.go
+++ b/build/fietsje/planner.go
@@ -14,7 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package fietsje
 
 import (
 	"fmt"
@@ -25,7 +25,7 @@
 
 // planner is a builder for a single world of Go package dependencies, and what is
 // then emitted into a Starlark file containing gazelle go_repository rules. The
-// planner's builder system covers three increasingly specific contextx:
+// planner's builder system covers three increasingly specific contexts:
 //  - planner (this structure, allows for 'collecting' in high-level dependencies. ie. collections)
 //  - collection (represents what has been pulled in by a high-level dependency, and allows for 'using' transitive
 //    dependencies from a collection)
diff --git a/build/fietsje/render.go b/build/fietsje/render.go
index 03e2857..5890411 100644
--- a/build/fietsje/render.go
+++ b/build/fietsje/render.go
@@ -14,7 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package fietsje
 
 import (
 	"fmt"
diff --git a/build/fietsje/shelf.go b/build/fietsje/shelf.go
index 963c139..807ee44 100644
--- a/build/fietsje/shelf.go
+++ b/build/fietsje/shelf.go
@@ -14,7 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package fietsje
 
 import (
 	"bytes"
diff --git a/build/fietsje/transitive.go b/build/fietsje/transitive.go
index e42199b..2e2a9f7 100644
--- a/build/fietsje/transitive.go
+++ b/build/fietsje/transitive.go
@@ -14,7 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package fietsje
 
 import (
 	"fmt"