Golang Notes

This will encompass things that I find useful and end up looking up later when I haven't written go in a while.

Concepts

A slice is essentially an array in Golang.

functionName vs FunctionName

A function that starts with a lowercase letter is only available within the package in which it's defined.

A function that start with an uppercase letter is available to any packages in your program.

Resource:
https://stackoverflow.com/questions/38616687/which-way-to-name-a-function-in-go-camelcase-or-semi-camelcase

Compile binary

go build

String Interpolation

var a string = "Hello"
var b string = "World"
c := fmt.Sprintf("%s %s!", a, b)
fmt.Println(c)

Debugging

Start debugger:
dlv debug

Set breakpoint on line 36 in main.go:
break main.go:36

Set breakpoint on line 8 in anotherGoFile.go:
break anotherGoFile.go:8

Debug program with command line arguments (after compiling)
dlv debug -- -a argument -b another_argument

Print contents of the b variable
print b

Restart the debugging process
r

Resources:
https://github.com/derekparker/delve/issues/178
https://www.youtube.com/watch?v=zgLjVD5ZSOc

Useful Functions

Read an input file from a specified path

func readLines(filePath string) ([]string, error) {
  b, err := ioutil.ReadFile(filePath)
  if err != nil {
    return nil, err
  }

  return RemoveTrailingEmptyStringsInStringArray(strings.Split(string(b), "\n")), nil
}

Remove empty strings trailing in a slice

func RemoveTrailingEmptyStringsInStringArray(sa []string) []string {
  lastNonEmptyStringIndex := len(sa) - 1
  for i := lastNonEmptyStringIndex; i >= 0; i-- {
    if sa[i] == "" {
      lastNonEmptyStringIndex--
    } else {
      break
    }
  }
  return sa[0 : lastNonEmptyStringIndex+1]
}

Compiling binaries

OSX 64-bit:

env GOOS=darwin GOARCH=amd64 go build -o osx

Linux 64-bit:

env GOOS=linux GOARCH=amd64 go build -o linux

Resources:
https://www.digitalocean.com/community/tutorials/how-to-build-go-executables-for-multiple-platforms-on-ubuntu-16-04
https://stackoverflow.com/questions/42706246/how-to-build-executable-with-name-other-than-golang-package

Return multiple values from function

You can natively return multiple values in go. Here's a basic function example (specifcally the declaration and return):

func greatFunc(param1 string, param2 string, param3 string) (bool, string) {
// body omitted
return true, returnString

Resource:
https://gobyexample.com/multiple-return-values

Multiline string

    var payload = `  include myfile
}`

Resource:
https://play.golang.org/p/kcupXFwzgrZ

Comments

Normal

// comment

Block

/*
comment
*/

Convert byte array to string

s := string(byteArray)

Resource:
https://stackoverflow.com/questions/14230145/what-is-the-best-way-to-convert-byte-array-to-string

Nested directory creation

err := os.MkdirAll("/tmp/foo/bar", os.ModePerm)

Resource:
https://stackoverflow.com/questions/28448543/how-to-create-nested-directories-using-mkdir-in-golang

Convert int to str

import "strconv"
strconv.Itoa(123) // "123"

Resource: https://stackoverflow.com/questions/10105935/how-to-convert-an-int-value-to-string-in-go

Check if string contains another string

import (
    "strings"
)

var var2 string = "bla"
output := strings.Contains("blablabla", var2) 
fmt.Println(output) // true

Resource: https://stackoverflow.com/questions/45266784/go-test-string-contains-substring

Filepath operations

import "fmt"
import "path/filepath"

func main() {
	t := "/etc/init.d/somefile"
	fmt.Printf("base is %q dir is %q is it absolute? %v\n",
		filepath.Base(t),
		filepath.Dir(t),
		filepath.IsAbs(t))
	d, f := filepath.Split(t)

	fmt.Printf("split returns file %q dir %q\n", f, d)
        fmt.Printf("clean it up %q", filepath.Clean("a/b/c/../d//////../../f"))
}

If you need to return a filepath:

d := "/etc/bla/bla2/bla3/"
filepath.Clean(filepath.Join(d, "../")) // /etc/bla/bla2

Read template file

The person that put this together is a hero (Gustavo Bittencourt).

package main

import (
  "log"
  "os"
  "path"
  "text/template"
)

type Command struct {
  ClassName string
  CmdName   string
  Cmd       string
}

func main() {
  command := Command{
    ClassName: "my_cmd",
    CmdName:   "cmd",
    Cmd:       "curl target.com:8001/asdf",
  }

  t := template.New("puppetModule.tmpl")

  t, err := t.ParseFiles(path.Join("templates", "puppetModule.tmpl"))

  if err != nil {
    log.Fatal("Parse: ", err)
  }

  err = t.Execute(os.Stdout, command)
  if err != nil {
    log.Fatal("Execute: ", err)
  }
}

puppetModule.tmpl

class {{.ClassName}} {
  exec { '{{.CmdName}}':
    path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
    command => '{{.Cmd}}'
  }
}

Resource:
https://stackoverflow.com/questions/32388777/error-when-creating-a-template-and-then-parsing-from-files

Go get cert errors fix

Obviously, this is not ideal (observe the -insecure flag):

go get -u -v -insecure <target project>

From go help get:
-u: Look for updates to existing packages
-v: Verbose progress and debug output

Resource:
https://github.com/golang/go/issues/18519

Generate random int in a range

import (
  "fmt"
  "math/rand"
  "time"
)

func randInt(min int, max int) int {
  return min + rand.Intn(max-min)
}

func main() {
  start := 1
  finish := 6
  rand.Seed(time.Now().UTC().UnixNano())
  fmt.Printf("%v", rand.Intn(finish-start)+start)
}

Resources:
https://stackoverflow.com/questions/44659343/how-to-choose-a-random-number-from-the-range
https://golang.cafe/blog/golang-random-number-generator.html

Get lowercase version of string

import "strings"
strings.ToLower("Gopher")

Resource:
https://stackoverflow.com/questions/10411538/how-do-i-convert-a-string-to-a-lower-case-representation

Copy file

import (
  "io/ioutil"
  "log"
)

 func CpFile(src string, dst string) {
   input, err := ioutil.ReadFile(src)
   if err != nil {
     log.Println(err)
     return
   }

   err = ioutil.WriteFile(dst, input, 0644)
   if err != nil {
     log.Println("Error creating", dst)
     log.Println(err)
     return
   }
 }

Resource:
https://opensource.com/article/18/6/copying-files-go

Determine OS being used

package main

import (
	"fmt"
	"runtime"
)

func main() {
	if runtime.GOOS == "linux" {
		fmt.Println("You are running on Linux")
	} else if runtime.GOOS == "darwin" {
		fmt.Println("You are running on OSX")
	} else if runtime.GOOS == "windows" {
		fmt.Println("You are running on Windows")
	} else {
		fmt.Println("Unsupported OS detected")
	}
}

Playground:
https://play.golang.org/p/ULd8sMpy0dt
Resources:
https://golangcode.com/detect-if-code-is-running-on-windows-at-runtime/

Go get private repo

git config --global url."git@github.com:".insteadOf "https://github.com/"

Resource:
https://bialon.net/post/how-to-go-get-private-repos/

Get Working Directory

func Gwd() string {
	dir, err := os.Getwd()
	if err != nil {
		log.Fatalln(err)
	}
	return dir
}

Resource:
https://gist.github.com/arxdsilva/4f73d6b89c9eac93d4ac887521121120

String to String Array

cmd := "puppetserver ca list --all"
strArr := strings.Fields(cmd)
fmt.Println(strArr[0])
// Will print: puppetserver

Resource:
https://stackoverflow.com/questions/13737745/split-a-string-on-whitespace-in-go

Get everything but first element of array

range Arr[1:]

Resource:
https://stackoverflow.com/questions/37429248/skip-first-element-of-an-array-in-golang

Convert string array to string

strings.Join(arr []string, seperator string) string

Resource:
https://stackoverflow.com/questions/41756412/golang-convert-type-string-to-string