Skip to content

Commit 6cdd5ab

Browse files
authored
CLI: Register commands in a different place from where the command list is instantiated (#9635)
The parser needs to have access to the full list of CLI commands, and many packages use or may need to use the parser. To avoid dependency cycles, we declare the list in one package and populate using the `Register` function in a sub-package. We call `register.Register` as one of our first calls upon beginning execution.
1 parent 32d84a9 commit 6cdd5ab

File tree

6 files changed

+209
-147
lines changed

6 files changed

+209
-147
lines changed

cli/cli_command/BUILD

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,6 @@ go_library(
44
name = "cli_command",
55
srcs = ["cli_command.go"],
66
importpath = "github.com/buildbuddy-io/buildbuddy/cli/cli_command",
7-
deps = [
8-
"//cli/add",
9-
"//cli/analyze",
10-
"//cli/ask",
11-
"//cli/download",
12-
"//cli/execute",
13-
"//cli/explain",
14-
"//cli/fix",
15-
"//cli/index",
16-
"//cli/login",
17-
"//cli/plugin",
18-
"//cli/printlog",
19-
"//cli/remote_download",
20-
"//cli/remotebazel",
21-
"//cli/search",
22-
"//cli/update",
23-
"//cli/upload",
24-
"//cli/versioncmd",
25-
],
267
)
278

289
package(default_visibility = ["//cli:__subpackages__"])

cli/cli_command/cli_command.go

Lines changed: 28 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,38 @@
11
package cli_command
22

3-
import (
4-
"github.com/buildbuddy-io/buildbuddy/cli/add"
5-
"github.com/buildbuddy-io/buildbuddy/cli/analyze"
6-
"github.com/buildbuddy-io/buildbuddy/cli/ask"
7-
"github.com/buildbuddy-io/buildbuddy/cli/download"
8-
"github.com/buildbuddy-io/buildbuddy/cli/execute"
9-
"github.com/buildbuddy-io/buildbuddy/cli/explain"
10-
"github.com/buildbuddy-io/buildbuddy/cli/fix"
11-
"github.com/buildbuddy-io/buildbuddy/cli/index"
12-
"github.com/buildbuddy-io/buildbuddy/cli/login"
13-
"github.com/buildbuddy-io/buildbuddy/cli/plugin"
14-
"github.com/buildbuddy-io/buildbuddy/cli/printlog"
15-
"github.com/buildbuddy-io/buildbuddy/cli/remote_download"
16-
"github.com/buildbuddy-io/buildbuddy/cli/remotebazel"
17-
"github.com/buildbuddy-io/buildbuddy/cli/search"
18-
"github.com/buildbuddy-io/buildbuddy/cli/update"
19-
"github.com/buildbuddy-io/buildbuddy/cli/upload"
20-
"github.com/buildbuddy-io/buildbuddy/cli/versioncmd"
21-
)
22-
233
type Command struct {
244
Name string
255
Help string
266
Handler func(args []string) (exitCode int, err error)
277
Aliases []string
288
}
299

30-
var Commands = []Command{
31-
{
32-
Name: "add",
33-
Help: "Adds a dependency to your WORKSPACE file.",
34-
Handler: add.HandleAdd,
35-
},
36-
{
37-
Name: "analyze",
38-
Help: "Analyzes the dependency graph.",
39-
Handler: analyze.HandleAnalyze,
40-
},
41-
{
42-
Name: "ask",
43-
Help: "Asks for suggestions about your last invocation.",
44-
Handler: ask.HandleAsk,
45-
Aliases: []string{"wtf", "huh"},
46-
},
47-
{
48-
Name: "download",
49-
Help: "Downloads artifacts from a remote cache.",
50-
Handler: download.HandleDownload,
51-
},
52-
{
53-
Name: "execute",
54-
Help: "Executes arbitrary commands using remote execution.",
55-
Handler: execute.HandleExecute,
56-
},
57-
{
58-
Name: "fix",
59-
Help: "Applies fixes to WORKSPACE and BUILD files.",
60-
Handler: fix.HandleFix,
61-
},
62-
// Handle 'help' command separately to avoid circular dependency with `cli_command`
63-
// package
64-
{
65-
Name: "install",
66-
Help: "Installs a bb plugin (https://buildbuddy.io/plugins).",
67-
Handler: plugin.HandleInstall,
68-
},
69-
{
70-
Name: "login",
71-
Help: "Configures bb commands to use your BuildBuddy API key.",
72-
Handler: login.HandleLogin,
73-
},
74-
{
75-
Name: "logout",
76-
Help: "Configures bb commands to no longer use your saved API key.",
77-
Handler: login.HandleLogout,
78-
},
79-
{
80-
Name: "print",
81-
Help: "Displays various log file types written by bazel.",
82-
Handler: printlog.HandlePrint,
83-
},
84-
{
85-
Name: "remote",
86-
Help: "Runs a bazel command in the cloud with BuildBuddy's hosted bazel service.",
87-
Handler: remotebazel.HandleRemoteBazel,
88-
},
89-
{
90-
Name: "remote-download",
91-
Help: "Fetches a remote asset via an intermediate cache.",
92-
Handler: remote_download.HandleRemoteDownload,
93-
},
94-
{
95-
Name: "search",
96-
Help: "Searches for code in the remote codesearch index.",
97-
Handler: search.HandleSearch,
98-
},
99-
{
100-
Name: "index",
101-
Help: "Sends updates to the remote codesearch index.",
102-
Handler: index.HandleIndex,
103-
},
104-
{
105-
Name: "update",
106-
Help: "Updates the bb CLI to the latest version.",
107-
Handler: update.HandleUpdate,
108-
},
109-
{
110-
Name: "upload",
111-
Help: "Uploads files to the remote cache.",
112-
Handler: upload.HandleUpload,
113-
},
114-
{
115-
Name: "version",
116-
Help: "Prints bb cli version info.",
117-
Handler: versioncmd.HandleVersion,
118-
},
119-
{
120-
Name: "explain",
121-
Help: "Explains the difference between two compact execution logs.",
122-
Handler: explain.HandleExplain,
123-
},
10+
var (
11+
// Commands is a slice of all known CLI commands, sorted by their Name fields.
12+
//
13+
// It is nil until Register in cli_command/register is called.
14+
Commands []*Command
15+
16+
// CommandsByName is a map of every known CLI command, each indexed by its
17+
// Name field.
18+
//
19+
// It is nil until Register in cli_command/register is called.
20+
CommandsByName map[string]*Command
21+
22+
// Aliases maps every known alias to its corresponding CLI command.
23+
//
24+
// It is nil until Register in cli_command/register is called.
25+
Aliases map[string]*Command
26+
)
27+
28+
// GetCommand returns the Command corresponding to the provided command name or
29+
// alias, or nil if no such Command exists.
30+
func GetCommand(commandName string) *Command {
31+
if command, ok := CommandsByName[commandName]; ok {
32+
return command
33+
}
34+
if command, ok := Aliases[commandName]; ok {
35+
return command
36+
}
37+
return nil
12438
}

cli/cli_command/register/BUILD

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library")
2+
3+
go_library(
4+
name = "register",
5+
srcs = ["register.go"],
6+
importpath = "github.com/buildbuddy-io/buildbuddy/cli/cli_command/register",
7+
visibility = ["//visibility:public"],
8+
deps = [
9+
"//cli/add",
10+
"//cli/analyze",
11+
"//cli/ask",
12+
"//cli/cli_command",
13+
"//cli/download",
14+
"//cli/execute",
15+
"//cli/explain",
16+
"//cli/fix",
17+
"//cli/index",
18+
"//cli/login",
19+
"//cli/plugin",
20+
"//cli/printlog",
21+
"//cli/remote_download",
22+
"//cli/remotebazel",
23+
"//cli/search",
24+
"//cli/update",
25+
"//cli/upload",
26+
"//cli/versioncmd",
27+
],
28+
)
29+
30+
package(default_visibility = ["//cli:__subpackages__"])

cli/cli_command/register/register.go

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package register
2+
3+
import (
4+
"sync"
5+
6+
"github.com/buildbuddy-io/buildbuddy/cli/add"
7+
"github.com/buildbuddy-io/buildbuddy/cli/analyze"
8+
"github.com/buildbuddy-io/buildbuddy/cli/ask"
9+
"github.com/buildbuddy-io/buildbuddy/cli/cli_command"
10+
"github.com/buildbuddy-io/buildbuddy/cli/download"
11+
"github.com/buildbuddy-io/buildbuddy/cli/execute"
12+
"github.com/buildbuddy-io/buildbuddy/cli/explain"
13+
"github.com/buildbuddy-io/buildbuddy/cli/fix"
14+
"github.com/buildbuddy-io/buildbuddy/cli/index"
15+
"github.com/buildbuddy-io/buildbuddy/cli/login"
16+
"github.com/buildbuddy-io/buildbuddy/cli/plugin"
17+
"github.com/buildbuddy-io/buildbuddy/cli/printlog"
18+
"github.com/buildbuddy-io/buildbuddy/cli/remote_download"
19+
"github.com/buildbuddy-io/buildbuddy/cli/remotebazel"
20+
"github.com/buildbuddy-io/buildbuddy/cli/search"
21+
"github.com/buildbuddy-io/buildbuddy/cli/update"
22+
"github.com/buildbuddy-io/buildbuddy/cli/upload"
23+
"github.com/buildbuddy-io/buildbuddy/cli/versioncmd"
24+
)
25+
26+
// Register registers all known cli commands in the structures laid out in
27+
// cli/cli_command. It is meant to be called immediately on CLI
28+
// startup.
29+
//
30+
// This indirection prevents dependency cycles from occurring when, for example,
31+
// an imported package tries to use the parser, which itself needs to know all
32+
// of the cli commands.
33+
var Register = sync.OnceFunc(register)
34+
35+
func register() {
36+
cli_command.Commands = []*cli_command.Command{
37+
{
38+
Name: "add",
39+
Help: "Adds a dependency to your WORKSPACE file.",
40+
Handler: add.HandleAdd,
41+
},
42+
{
43+
Name: "analyze",
44+
Help: "Analyzes the dependency graph.",
45+
Handler: analyze.HandleAnalyze,
46+
},
47+
{
48+
Name: "ask",
49+
Help: "Asks for suggestions about your last invocation.",
50+
Handler: ask.HandleAsk,
51+
Aliases: []string{"wtf", "huh"},
52+
},
53+
{
54+
Name: "download",
55+
Help: "Downloads artifacts from a remote cache.",
56+
Handler: download.HandleDownload,
57+
},
58+
{
59+
Name: "execute",
60+
Help: "Executes arbitrary commands using remote execution.",
61+
Handler: execute.HandleExecute,
62+
},
63+
{
64+
Name: "fix",
65+
Help: "Applies fixes to WORKSPACE and BUILD files.",
66+
Handler: fix.HandleFix,
67+
},
68+
// Handle 'help' command separately to avoid circular dependency with `cli_command`
69+
// package
70+
{
71+
Name: "install",
72+
Help: "Installs a bb plugin (https://buildbuddy.io/plugins).",
73+
Handler: plugin.HandleInstall,
74+
},
75+
{
76+
Name: "login",
77+
Help: "Configures bb commands to use your BuildBuddy API key.",
78+
Handler: login.HandleLogin,
79+
},
80+
{
81+
Name: "logout",
82+
Help: "Configures bb commands to no longer use your saved API key.",
83+
Handler: login.HandleLogout,
84+
},
85+
{
86+
Name: "print",
87+
Help: "Displays various log file types written by bazel.",
88+
Handler: printlog.HandlePrint,
89+
},
90+
{
91+
Name: "remote",
92+
Help: "Runs a bazel command in the cloud with BuildBuddy's hosted bazel service.",
93+
Handler: remotebazel.HandleRemoteBazel,
94+
},
95+
{
96+
Name: "remote-download",
97+
Help: "Fetches a remote asset via an intermediate cache.",
98+
Handler: remote_download.HandleRemoteDownload,
99+
},
100+
{
101+
Name: "search",
102+
Help: "Searches for code in the remote codesearch index.",
103+
Handler: search.HandleSearch,
104+
},
105+
{
106+
Name: "index",
107+
Help: "Sends updates to the remote codesearch index.",
108+
Handler: index.HandleIndex,
109+
},
110+
{
111+
Name: "update",
112+
Help: "Updates the bb CLI to the latest version.",
113+
Handler: update.HandleUpdate,
114+
},
115+
{
116+
Name: "upload",
117+
Help: "Uploads files to the remote cache.",
118+
Handler: upload.HandleUpload,
119+
},
120+
{
121+
Name: "version",
122+
Help: "Prints bb cli version info.",
123+
Handler: versioncmd.HandleVersion,
124+
},
125+
{
126+
Name: "explain",
127+
Help: "Explains the difference between two compact execution logs.",
128+
Handler: explain.HandleExplain,
129+
},
130+
}
131+
cli_command.CommandsByName = make(
132+
map[string]*cli_command.Command,
133+
len(cli_command.Commands),
134+
)
135+
cli_command.Aliases = make(map[string]*cli_command.Command)
136+
for _, command := range cli_command.Commands {
137+
cli_command.CommandsByName[command.Name] = command
138+
for _, alias := range command.Aliases {
139+
cli_command.Aliases[alias] = command
140+
}
141+
}
142+
}

cli/cmd/bb/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ go_library(
1212
"//cli/arg",
1313
"//cli/bazelisk",
1414
"//cli/cli_command",
15+
"//cli/cli_command/register",
1516
"//cli/cmd/sidecar",
1617
"//cli/help",
1718
"//cli/log",

0 commit comments

Comments
 (0)