Go Environment

This article builds a reusable environment for Go Jupyter runtimes, based on the Minimal Python 3 environment.

Learn more about environments on Nextjournal.

Nextjournal's Go environment has two Jupyter kernels available:

  • lgo, a standalone kernel currently running on v1.9.7 of the official Go compiler, because of regressions in more recent versions.
  • gophernotes, which comes with its own unofficial Go interpreter, compiled with the official Go v1.12.8 compiler.

The default is lgo, for speed and somewhat richer Jupyter support. To use lgo with the official Go compiler version 1.9.7, simply remix the Nextjournal Go template. To switch to the gophernotes kernel after remixing the template (see image below):

  • Scroll to the bottom of the notebook.
  • Expand the Runtime Languages section.
  • Access the ··· menu, then Configure...
  • In the expanded panel, re-select Go in the top menu.
  • Once loaded, select the Go (gnotes) kernel in the lower menu.
  • Click the Save & Add button to insert a cell with the new gophernotes runtime.

Showcase

Go-Chart

21.8s
Go lgo/1.9 Test (Go (lgo))
Go
// This sample is copied from https://github.com/wcharczuk/go-chart/tree/master/_examples/stacked_bar

import (
    "bytes"
    "fmt"

    "github.com/wcharczuk/go-chart"
)

sbc := chart.StackedBarChart{
    Title:      "Test Stacked Bar Chart",
    TitleStyle: chart.StyleShow(),
    Background: chart.Style{
        Padding: chart.Box{
            Top: 40,
        },
    },
    Height: 512,
    XAxis: chart.Style{
        Show: true,
    },
    YAxis: chart.Style{
        Show: true,
    },
    Bars: []chart.StackedBar{
        {
            Name: "This is a very long string to test word break wrapping.",
            Values: []chart.Value{
                {Value: 5, Label: "Blue"},
                {Value: 5, Label: "Green"},
                {Value: 4, Label: "Gray"},
                {Value: 3, Label: "Orange"},
                {Value: 3, Label: "Test"},
                {Value: 2, Label: "??"},
                {Value: 1, Label: "!!"},
            },
        }, {
            Name: "Test",
            Values: []chart.Value{
                {Value: 10, Label: "Blue"},
                {Value: 5, Label: "Green"},
                {Value: 1, Label: "Gray"},
            },
        },
        {
            Name: "Test 2",
            Values: []chart.Value{
                {Value: 10, Label: "Blue"},
                {Value: 6, Label: "Green"},
                {Value: 4, Label: "Gray"},
            },
        },
    },
}
var buf bytes.Buffer
err := sbc.Render(chart.PNG, &buf)
if err != nil {
    fmt.Printf("Error rendering chart: %v\n", err)
    return
}
_ctx.Display.PNG(buf.Bytes(), nil)

Setup

Build the Go Environment

Install some dependencies.

apt-get -qq update
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends \
  build-essential gfortran cmake automake libtool libltdl-dev pkg-config \
  libzmq3-dev
apt-get clean
rm -r /var/lib/apt/lists/* # Clear package list so it isn't stale

Install Jupyter.

pip install --upgrade jupyter jupyter_client

Download Go binaries.

for ver in $GO_VERSION $GO_EX_VERSIONS; do
  FILENAME="go${ver}.linux-amd64.tar.gz"
  FILEURL="https://dl.google.com/go/${FILENAME}"
  
  wget --progress=dot:giga ${FILEURL} ${FILEURL}.sha256
  echo " ${FILENAME}" >> ${FILENAME}.sha256
  sha256sum -c ${FILENAME}.sha256
done

tar -cf /results/goses.tar go*.tar.gz
goses.tar

Install Go(s).

mkdir -p /opt/go/packages
cd /opt/go
tar -xf 
goses.tar
for ver in $GO_VERSION $GO_EX_VERSIONS; do tar -zxf go${ver}.linux-amd64.tar.gz mv go ${ver} rm go${ver}.linux-amd64.tar.gz done ln -s ${GO_VERSION} default

lgo needs 1.9 because of bugs in Go.

mkdir -p /opt/go/lgo
go get github.com/yunabe/lgo/cmd/lgo
go get -d github.com/yunabe/lgo/cmd/lgo-internal
lgo install
python $GOPATH/src/github.com/yunabe/lgo/bin/install_kernel

gophernotes is fine with 1.12.

/opt/go/1.12.8/bin/go get -u github.com/gopherdata/gophernotes
mkdir -p /usr/local/share/jupyter/kernels/gophernotes
cp $GOPATH/src/github.com/gopherdata/gophernotes/kernel/* \
  /usr/local/share/jupyter/kernels/gophernotes/

Make the display name descriptive.

sed -i 's/"display_name": "Go"/"display_name": "Go (gnotes)"/' \
  /usr/local/share/jupyter/kernels/*/kernel.json

Install some libraries.

go get -u github.com/wcharczuk/go-chart
/opt/go/1.12.8/bin/go get -u github.com/wcharczuk/go-chart
/opt/go/1.12.8/bin/go get -u -t gonum.org/v1/gonum/...
/opt/go/1.12.8/bin/go get -u -t gonum.org/v1/plot/...

Check everything.

du -hsx /
go version
jupyter kernelspec list

Test

// naiveFib calculates the n-th fibonacci number
func naiveFib(n int) int {
    if n > 1 {
        return naiveFib(n - 1) + naiveFib(n - 2)
    }
    return 1
}
naiveFib(20)

Go, go, Golang Gopher...

import (
    "fmt"
    "io/ioutil"
    "net/http"    
)

var gopherPNG []byte
{
    res, err := http.Get("https://golang.org/doc/gopher/frontpage.png")
    if err != nil {
        fmt.Printf("Failed to get: %v\n", err)
        return
    }
    defer res.Body.Close()
    gopherPNG, err = ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Printf("Failed to read: %v\n", err)
        return
    }
    _ctx.Display.Text("PNG Gopher", nil)
    _ctx.Display.PNG(gopherPNG, nil)
}