Getting started with Golang on Mac OS X
December 06, 2015
Installation
Installation through homebrew
To install go through homebrew (or to update it to the latest version), run:
brew update
brew install go # if go is not yet installed - and/or -
brew upgrade go # update an existing go installationCheck that you have the latest version:
go versionSetting up the environment
You'll need to create a local directory that will be used as the 'Go Workspace'. This workspace will be shared between all of your projects, so generally you'll need only one.
For example:
mkdir ~/goThen setup these environment variables, ideally in your ~/.bashrc file.
export GOPATH=$HOME/go
export GOROOT=/usr/local/opt/go/libexec
export PATH=$PATH:$GOPATH/bin
export PATH=$PATH:$GOROOT/binSetup atom plugin
Install the go-plus plugin. On startup, it will do some sanity checks to make sure everything is set up correctly. In case of errors, double check that you've set up your environment variables correctly in the current (atom) session. To make sure, start a new bash session, and run atom from there.
This plugin will:
- Auto format using go fmt on save
- Build your app on save (and show any errors in atom, with line highlights, etc)
- and more... (see plugin page for details)
Creating your first project
Go is pretty opinionated about where it wants your code to be located.
Your code is expected to be stored in
$GOPATH/src/github.com/your-username/your-projectname.
The idea is that any project/package you write is easily shareable.
Instead of the github.com format, there are a few others like bitbucket, mercurial, etc (Read more about Package Publishing)
mkdir -p $GOPATH/src/github.com/your-username
mkdir $GOPATH/src/github.com/your-username/your-projectnameSimple console application with flags
Start with a simple file, for example:
package main
import (
"flag"
"fmt"
)
var greetingFlag string
func init() {
flag.StringVar(&greetingFlag, "greeting", "Hello", "Type of greeting")
}
func main() {
flag.Parse()
fmt.Println(fmt.Sprintf("%s, go!", greetingFlag))
}Build your application like this:
go buildYou can now run your built executable:
./go-test -greeting="What's up"Web-enabling your app
With some small updates, you can turn your console application into a web application:
package main
import (
"flag"
"fmt"
"net/http"
)
var greetingFlag string
func init() {
flag.StringVar(&greetingFlag, "greeting", "Hello", "Type of greeting")
}
func main() {
flag.Parse()
fmt.Println(fmt.Sprintf("%s, go!!", greetingFlag))
http.HandleFunc("/", hello)
http.ListenAndServe(":8080", nil)
}
func hello(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(fmt.Sprintf("%s, go!!", greetingFlag)))
}Package management / vendor
The $GOPATH design is a bit weird when coming from package managed languages like php/composer, nodejs/npm, etc. In Go 1.5 there is a development experiment to support a vendor/ directory, like these other package managers.
Read more about it here. It is based on Glide
To use it, you'll need to set the environment variable GO15VENDOREXPERIMENT to 1 and install glide:
export GO15VENDOREXPERIMENT=1
brew install glideIn your project directory, use glide like this:
glide create # creates your glide.yaml if it does not existNow edit your newly created glide.yaml file to list your dependencies, for example:
package: main
# Declare your project's dependencies.
import:
- package: github.com/Masterminds/cookoo
repo: git@github.com:Masterminds/cookoo.git
ref: 1.1.0
vcs: gitNote how you can specify repository locations, and most importantly: explicit versions.
Now install these dependencies in vendor/ with the following command:
glide installyou can build your package as usual:
go buildBecause of the environment flag, it will try to locate your dependencies in the vendor/ directory.
Debugging
Printf
Most recommendations so far suggest to simply output data using fmt.Printf. As Go is making heavy usage of struct, you'll often want to output all fields of a struct. A simple way to do this:
fmt.Printf("%+v\n", someData)Logrus
You could use a nice logger like logrus for logging messages, augmented with custom fields.
Import it like this:
import log "github.com/Sirupsen/logrus"Then log a message like this:
log.WithFields(log.Fields{
"animal": "walrus",
}).Info("A walrus appears")You can tweak the logrus settings in init:
func init() {
// Log as JSON instead of the default ASCII formatter.
log.SetFormatter(&log.JSONFormatter{})
// Output to stderr instead of stdout, could also be a file.
log.SetOutput(os.Stderr)
// Only log the warning severity or above.
log.SetLevel(log.WarnLevel)
}godebug
For lower level debugging you can use Mailgun's godebug
Install godebug:
go get github.com/mailgun/godebugThen add breakpoints to your code like this:
_ = "breakpoint"To run your app, simply:
godebug run hello.goYour app will run normally, until it hits the breakpoint. There you can use a few basic commands to list context, and print variables (including structs) in their current state.
Spew
Think of this as Go's equivelant of var_dump. Add it to your imports like this:
import spew "github.com/davecgh/go-spew/spew"Then whatever variable (including structs) you want to output, simply use:
spew.Dump(v) // output to console directly
fmt.Printf(spew.Sdump(v)) // create a stringReloading
When working on web-apps and servers, you generally don't want to manually recompile and restart your app every time you change a line of code. This is where reloading comes in.
On Mac OS X you will get a popup from the firewall, asking if your newly built app is allowed to open incoming connections. It does this every time your app changes (new binary file content hash). This is obviously very annoying during development. To solve it, always make sure that your web app is listening to the local host ip (127.0.0.1) only, and not any public or catch-all addresses.
Gin
The gin app is a simple proxy server that rebuilds your app when .go files changes, and restarts a server.
Install it using go get github.com/codegangsta/gin, and use gin -h to read about the options. In general, this is all you need to get started:
gin -a "8080" runNow you can simply open up this url in your browser to view your app: http://127.0.0.1:3000 (note: not the port specified with -a!)
Gin will monitor the current directory for changes. If a .go file is changed, a go run is executed, and the app is stopped/started. The proxy is forwarding requests to port 3001 by default, which you can override with -a.
Note that this is a very ungraceful restart only suitable for development. In production you'll need to work with loadbalancers.
Gulp
Here's a blog post about reloading code through gulp. That would require mixing node in the project, so gin would be a cleaner solution.