blang

Collection of my experiences with golang and other programming languages.

© 2014. Benedikt Lang All rights reserved.

Travis-ci Golang Binary Github Release

If you're working on a golang project which results in an usable binary, you might want to let travis-ci do the work for you. Travis will test and build your project and create a github release with the binary attached.


.travis.yml

language: go
go:
  - 1.3
install:
  - "go get -d -v ./..."
  - "go build -v ./..."
deploy:
  provider: releases
  api_key:
    secure: [YOUR ENCRYPTED OAUTH TOKEN]
  file: "[NAME OF YOUR PRODUCED BINARY]"
  skip_cleanup: true
  on:
    repo: [YOUR REPO e.g. blang/expenv]
    tags: true
    all_branches: true

The best way to create this file is by using the travis command-line tool:

$ travis init
$ travis setup releases

This will create nearly everything for you including the encrypted oauth token. Afterwards you want to add the missing lines from above.

To create a release, simply tag the commit with e.g. v1.0.0 and push the tag: git push origin v1.0.0

Note: Travis does not build your project by default, which will not produce a binary, because of that we changed the install instructions.

Golang Exporting

While i'm learning golang and searching the web for every possible talk and docs about it, i experienced that i can't find a good doc about the exporting features. By export i'm refering to the mechanism to export types, method and properties to the world outside the package.


Exporting

You already might know that you can export types by starting its name with an upcase letter. But there are many edge cases like a public struct with private fields which i will talk about in this post.

Everying public

Let's begin with a public struct with public fields.

package north
type Record struct {
    Firstname string
    Lastname string
}

It's quite clear that outside the 'north' package you can access the type and all properties:

package south
import "north"

// Init empty and set properties
i:=&north.Record{}
i.Firstname = "Foo"
i.Lastname = "Bar"

// Init with literal
i:=&north.Record{"Foo","Bar"}

It's also clear that if the type and the properties are private you can't instantiate the struct or access the properties directly, later more.

Private properties

But what if the struct is public and the members are private?

package north
type Record struct {
    firstname string
    lastname string
}

Now you can create a new instance of Record but can't use the literal to init the fields. Also there's no read or write access to those fields

package south
import "north"

// The empty literal is ok
i:=&north.Record{}

//Compile time error if accessing private fields
i.firstname = "Foo"
i.lastname = "Bar"

// Nope! Init with literal
// Compile time error
i:=&north.Record{"Foo","Bar"}

Private type, public properties

But what if the type is private and the members are public?

package north
type record struct {
    Firstname string
    Lastname string
}

func MakeRecord() record {
    return &record{}
}

Now you can't create a new instance outside the north package but you can access the properties of an existing instance!

package south
import "north"

// Compile time error, private struct
i:=north.record{}

// Ok if instance is made inside the north pkg
i:=north.MakeRecord()
i.Firstname = "Foo"
i.Lastname = "Bar"

That's very useful if you need to initialize every new struct with non-default values like pointers.

Everything private, but getter/setter

If the struct and its properties are private you can still provide access functions like getter and setter to better control the manipulation of the object.

package north
type record struct {
    firstname string
    fastname string
}

func MakeRecord() record {
    return &record{}
}

func (r *record) SetFirstname(n string) {
    r.firstname = n
}

func (r *record) Firstname() string {
    return r.firstname
}

Now you can restrict and control the access via methods:

package south
import "north"

i:=north.MakeRecord()
i.SetFirstname("Foo")
i.Firstname() // "Foo"

// Compile time error
i.firstname

Well and that's it. I really like go's exporting feature because it gives you quite a good feeling in the robustness of the system if entry-points of your api are secured by proper guards of object instantiation and manipulation.