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
go
whenGooFile
is absent. Includes allgo
commands. - Be able to read, compile and run
GooFile
on the fly. - Uses public functions implemented in
GooFile
to hook upgo
any command - just likerake
. - Gets/Installs golang packages in local directory - just like
npm
. - A set of APIs helping developers to work with shell and
go
output 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.