This is only a conceptual document. Every detail may change in my real implementation.
Golang is a great language with a powerful built-in command line tool go. Unlike other language's compiler tool, go can do much more than just compiling code: go get or go install can download or install external packages; go test is for testing; and more...
As a developer, I always have needs to do something before or after go command to do my own customization.
For example, I'm writing several golang projects. I want to keep all external packages in local directory like what npm does. If I do this, I have to set GOPATH before executing any of go get and go run and go build, and reset GOPATH to default after that. It's annoying to do it manually.
Another example is that I want to do some preparation work before go run, e.g. cleaning up files generated by last run.
I can write small scripts for all requirements I have. However, I'm a lazy develop and don't want to repeat myself. So I write goo.
goo is a facade or proxy of go command line. It provides ways to run code before/after any go command line. Instead of writing small scripts, write one GooFile to do anything we want.
First of all, we need to install goo.
sudo bash -c "$(curl https://raw.githubusercontent.com/huandu/goo/master/install.sh)"
If everything goes well, we'll have goo command now.
goo wraps all go commands. We can use goo to replace go under any circumstance. For instance, goo build works exactly the same as go build. You may want to add alias go=goo in your shell rc file.
goo shows its special ability only if there is a GooFile in current directory. GooFile is a simplified golang source file. The only difference between a golang source file and GooFile is that there is no package statement at beginning.
Here is a valid GooFile says Hello, goo! before any goo run.
func Run() {
G.Console.Println("Hello, goo!")
}goo will build and run GooFile in every goo command. Thanks to go blazing building speed. It won't add too much overhead.
If there is a GooFile file in a directory, goo behavior will become a bit different.
A big change is that goo will add $PWD/goo_packages at the beginning of GOPATH. This change forces go downloads and uses packages in local directory first. Just like npm and bundler, we need to manually run goo get to download all packages. goo won't do it for us automatically.
A minor change is that goo can handle more commands than go.
If we call goo hello world, goo will check whether there is a Hello function in GooFile. If find one, call it.
// we can import any package in GooFile.
import "flag"
func Hello() {
args := flag.Args()
// prints "goo-hello: hello, world"
G.Console.Printf("%v: %v, %v", args[0], G.Verb, args[1])
}If we want to do something after a goo command, just write code after calling G.Start().
func Run() {
// do some preparation work...
// kick off real go command.
// G.Start() is basically a call to os.Process.Wait().
processState, err := G.Start()
// do something after go command...
}goo should have similar feature sets like npm or rake. And goo should provide useful tool function to work with shell.
In scope:
- Works exactly the same as
gowhenGooFileis absent. Includes allgocommands. - Be able to read, compile and run
GooFileon the fly. - Uses public functions implemented in
GooFileto hook upgoany command - just likerake. - Gets/Installs golang packages in local directory - just like
npm. - A set of APIs helping developers to work with shell and
gooutput easier.
All features not related to go command line are out of scope. For instance, adding goo foo to do bar while there is no go foo. I tend to provide easy-to-use APIs to developers. goo should be extended by GooFile only.