[depot tools] Add generator package for creating deps_gen.go

This is just the former contents of go/depot_tools/deps/generate.go but
wrapped up so that it can be used elsewhere. My plan is to use it in
Skia so that we can pin task drivers in DEPS, update them using a normal
autoroller, and directly use them from gen_tasks.

Bug: b/256860862
Change-Id: Ia63db5685f3f55f3ca081f0ebbcee48458d50649
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/892332
Commit-Queue: Kaylee Lubick <kjlubick@google.com>
Reviewed-by: Kaylee Lubick <kjlubick@google.com>
Auto-Submit: Eric Boren <borenet@google.com>
diff --git a/go/depot_tools/deps/generate.go b/go/depot_tools/deps/generate.go
index 64ef2ae..9c7e589 100644
--- a/go/depot_tools/deps/generate.go
+++ b/go/depot_tools/deps/generate.go
@@ -4,65 +4,9 @@
 package main
 
 import (
-	"fmt"
-	"os"
-	"path/filepath"
-	"sort"
-	"strings"
-
-	"go.skia.org/infra/go/depot_tools/deps_parser"
-	"go.skia.org/infra/go/sklog"
-)
-
-const (
-	targetFile = "deps_gen.go"
-	header     = `// Code generated by "go run generate.go"; DO NOT EDIT
-
-package deps
-
-import (
-	"go.skia.org/infra/go/depot_tools/deps_parser"
-)
-
-var deps = deps_parser.DepsEntries{`
-
-	entryTmpl = `	"%s": {
-		Id:      "%s",
-		Version: "%s",
-		Path:    "%s",
-	},`
-	footer = `}
-`
+	"go.skia.org/infra/go/depot_tools/generator"
 )
 
 func main() {
-	cwd, err := os.Getwd()
-	if err != nil {
-		sklog.Fatal(err)
-	}
-	depsContents, err := os.ReadFile(filepath.Join(cwd, "..", "..", "..", "DEPS"))
-	if err != nil {
-		sklog.Fatal(err)
-	}
-	entries, err := deps_parser.ParseDeps(string(depsContents))
-	if err != nil {
-		sklog.Fatal(err)
-	}
-	ids := make([]string, 0, len(entries))
-	for id := range entries {
-		ids = append(ids, id)
-	}
-	sort.Strings(ids)
-
-	parts := []string{header}
-	for _, id := range ids {
-		entry := entries[id]
-		parts = append(parts, fmt.Sprintf(entryTmpl, entry.Id, entry.Id, entry.Version, entry.Path))
-	}
-	parts = append(parts, footer)
-
-	targetContents := strings.Join(parts, "\n")
-	if err := os.WriteFile(targetFile, []byte(targetContents), os.ModePerm); err != nil {
-		sklog.Fatal(err)
-	}
+	generator.MustGenerate("../../../DEPS")
 }
diff --git a/go/depot_tools/generator/BUILD.bazel b/go/depot_tools/generator/BUILD.bazel
new file mode 100644
index 0000000..8c4376c
--- /dev/null
+++ b/go/depot_tools/generator/BUILD.bazel
@@ -0,0 +1,13 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+    name = "generator",
+    srcs = ["generator.go"],
+    importpath = "go.skia.org/infra/go/depot_tools/generator",
+    visibility = ["//visibility:public"],
+    deps = [
+        "//go/depot_tools/deps_parser",
+        "//go/skerr",
+        "//go/sklog",
+    ],
+)
diff --git a/go/depot_tools/generator/generator.go b/go/depot_tools/generator/generator.go
new file mode 100644
index 0000000..224f07f
--- /dev/null
+++ b/go/depot_tools/generator/generator.go
@@ -0,0 +1,90 @@
+package generator
+
+/*
+Package generator provides functionality for generating a source file containing
+DEPS entries. It is designed to require the absolute minimum of boilerplate from
+the caller so that they just need to call MustGenerate, along with the necessary
+go:build / +build comments:
+
+```
+	generator.MustGenerate("../../../DEPS")
+```
+*/
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+
+	"go.skia.org/infra/go/depot_tools/deps_parser"
+	"go.skia.org/infra/go/skerr"
+	"go.skia.org/infra/go/sklog"
+)
+
+const (
+	targetFile = "deps_gen.go"
+	header     = `// Code generated by "go run generate.go"; DO NOT EDIT
+
+package deps
+
+import (
+	"go.skia.org/infra/go/depot_tools/deps_parser"
+)
+
+var deps = deps_parser.DepsEntries{`
+
+	entryTmpl = `	"%s": {
+		Id:      "%s",
+		Version: "%s",
+		Path:    "%s",
+	},`
+	footer = `}
+`
+)
+
+// Generate creates a deps_gen.go file with the contents of the DEPS file.
+// It assumes that it's being run via "go generate" and therefore the output
+// file is to be written to the current working directory. relPathToDeps is the
+// relative path to the DEPS file from the current working directory.
+func Generate(relPathToDeps string) error {
+	cwd, err := os.Getwd()
+	if err != nil {
+		return skerr.Wrap(err)
+	}
+	depsPath := filepath.Join(cwd, filepath.FromSlash(relPathToDeps))
+	depsContents, err := os.ReadFile(depsPath)
+	if err != nil {
+		return skerr.Wrap(err)
+	}
+	entries, err := deps_parser.ParseDeps(string(depsContents))
+	if err != nil {
+		return skerr.Wrap(err)
+	}
+	ids := make([]string, 0, len(entries))
+	for id := range entries {
+		ids = append(ids, id)
+	}
+	sort.Strings(ids)
+
+	parts := []string{header}
+	for _, id := range ids {
+		entry := entries[id]
+		parts = append(parts, fmt.Sprintf(entryTmpl, entry.Id, entry.Id, entry.Version, entry.Path))
+	}
+	parts = append(parts, footer)
+
+	targetContents := strings.Join(parts, "\n")
+	if err := os.WriteFile(targetFile, []byte(targetContents), os.ModePerm); err != nil {
+		return skerr.Wrap(err)
+	}
+	return nil
+}
+
+// MustGenerate runs Generate and panics if it fails.
+func MustGenerate(relPathToDeps string) {
+	if err := Generate(relPathToDeps); err != nil {
+		sklog.Fatal(err)
+	}
+}