The goal of the Go rewrite is to improve the usability and maintainability of Blackbox, meanwhile make it easier to implement new
The system is built in distinct layers: view, controller, model.
Suppose there is a subcommand "foo
". blackbox.go
parses the
user's command line args and calls cmdFoo()
, which is given
everything it needs to do the operation. For example, it is given the
filenames the user specified exactly; even if an empty list means "all
files", at this layer the empty list is passed to the function.
cmdFoo()
contains the business logic of how the operation should be
done: usually iterating over filenames and calling verb(s) for each
one. For example if an empty file list means "all files", this is the
layer that enumerates the files.
cmdFoo()
is implemented in the file cmd_foo.go
. The caller of
cmdFoo()
should provide all data it needs to get the job done.
cmdFoo()
doesn't refer to global flags, they are passed to the
function as parameters. Therefore the function has zero side-effects
(except possibly logging) and can be called as library functions by
other systems. This is the external (binary) API which should be
relatively stable.
cmdFoo()
calls verbs that are in bbutil/
. Some of those verbs are
actually interfaces. For example, any VCS-related verbs are actually a
Go interface which might be implemented one of many ways (Git,
Subversion, Mercurial), GPG-functions may be implemented by shelling
out to gpg.exe
or by using Go's gpg library.
They layers look like this:
| View | blackbox.go
| Parses User Commands, calls controller |
| Controller | cmd_*.go
| The business logic. Iterates and calls verbs |
| Model | pkg/bbutil
| Verbs |
| Interfaces | pkg/*
| Interfaces and their implementations |
At least that's the goal. We'll see how well we can achieve this.
Software architecture.
We try to keep the command-line parsing separate from the business logic and all plug-ins. This keeps things clean and easy to refactor. In fact layer 2 could be used as a stand-alone module for projects that want to embed blackbox actions.
Layer 1: The command itself
- cmd/blackbox/blackbox.go -- main() not much more
- cmd/blackbox/cli.go -- Set up and call the ufave/cli flag parser
- cmd/blackbox/drive.go -- Check # of arguments, conflicting flags, and then call the businss logic layer
Layer 2: The business logic
- pkg/box/box.go -- The interface to accessing .blackbox (admins, files, etc.)
- pkg/box/verbs.go -- Verbs called by Layer 1. Just the verbs
- pkg/box/boxutils.go -- Functions needed by the verbs
Layer 3: The plug-ins
- pkg/vcs/... -- Plug-ins for Git, (Mercurial, Subversion, Perforce,) and None
- pkg/crypters/... -- Plug-ins for PGP access: GnuPG, (go-openpgp, others in the future)
Layer 4: Support functions for use by Layer 3
- pkg/bbutil/filestats.go -- File manipulations
- pkg/bbutil/runbash.go -- Safely run external Linux commands