Skip to content

Instantly share code, notes, and snippets.

@huandu
Last active August 29, 2015 14:02
Show Gist options
  • Save huandu/d471f6219a766b507299 to your computer and use it in GitHub Desktop.
Save huandu/d471f6219a766b507299 to your computer and use it in GitHub Desktop.
Design doc for `goo`: Supercharging `go` command line

This is only a conceptual document. Every detail may change in my real implementation.

goo: Supercharging go command line

Motivation

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.

How to use goo

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...
}

What's in scope of goo

goo should have similar feature sets like npm or rake. And goo should provide useful tool function to work with shell.

In scope:

  1. Works exactly the same as go when GooFile is absent. Includes all go commands.
  2. Be able to read, compile and run GooFile on the fly.
  3. Uses public functions implemented in GooFile to hook up go any command - just like rake.
  4. Gets/Installs golang packages in local directory - just like npm.
  5. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment