going all-in with go for cli apps

35
Going all-in with Go for CLI apps

Upload: tom-elliott

Post on 24-Jan-2017

161 views

Category:

Software


0 download

TRANSCRIPT

Going all-in with Go

for CLI apps

About Me» Tom Elliott

» Engineer @ Yext

» https://telliott.io

» @theotherelliott

About Yext» Location data management

» 90 engineers

» 200+ microservices in Java & Go

» http://www.yext.com

» http://github.com/yext

» http://engblog.yext.com/

Agenda» Who Uses Go For CLI?

» Why Go for CLI?

» Tools at Yext

» Standard Library

» 3rd Party Packages

» Distribution

» Update Notification

Who Uses Go for CLI?

Who Uses Go for CLI?

Why Gofor CLI?

Why Go for CLI?» Familiarity

» Code Reuse

» Cross-platform

» Distribution Flexibility

Tools AtYext

srvInternal tool for building, testing and deploying Yext services

$ srv build Pages$ srv test Pages unit$ srv publish Pages all release

» Wrapper around build, test and deployment tools

» Simplifies CI configuration

» Reproducible

sites-cfgInternal configuration tool for sites managed by Pages

$ sites-cfg listsites$ sites-cfg validate stores.enterpriseclient.com

» Query configuration of sites in system

» Validate site repo without pushing

» Uses existing client code to interact with RPC services

Edwardhttps://github.com/yext/edward

Open source tool to manage local instances of service

$ edward start pages$ edward stop pages$ edward tail sites-admin

» Simplifies dev workflow with many microservices

» Build & launch services individually or as a group

» Auto-generate configuration for go & Docker services

StandardLibrary

Flagsimport "flag"

Define and parse command-line flags

var port = flag.Int("port", 8080, "Port number for service")flag.Parse()

» Supports all primitive types

» Get remaining arguments with flag.Args()

» Output usage with -help

Directory tree walkingimport "path/filepath"

Call filepath.Walk with a starting dir and a visitor function.

To find all .c files:

func main() { _ = filepath.Walk(os.Args[1], visit)}

func visit(path string, f os.FileInfo, err error) error { if filepath.Ext(path) == ".c" { fmt.Println(path) } return nil}

Process Executionimport "os/exec"

Run other command-line processes:

cmd := exec.Command("echo", "hello")err := cmd.Run()

» Redirect stdin/stdout

» Wait for completion, or run in the background

Environment Variablesimport "os"

Getenv / Setenv:

os.Setenv("MYKEY", "VALUE")value := os.Getenv("MYKEY")

ExpandEnv:

expanded := os.ExpandEnv("$GOPATH/github.com/user/repo")

Platform-Specific CodeBuild tags:

// +build !linux,!darwin

package main func init() { macOS_or_Linux_only() }

File names:

dns_windows.go

3rd PartyPackages

CLI$ go get github.com/urfave/cli

import "urfave/cli"

» Framework for command-line applications

» Familiar command, args and flags form

myapp -flag1 value command1 arg1 arg2

» Auto-generated help text

» Hidden commands

gopsutil$ go get github.com/shirou/gopsutil

import "shirou/gopsutil"

» go port of Python's psutil

» Helps retrieve information on running processes and system resource usage

» At Yext, is used to monitor forked processes and check for local open ports

Distribution

Distribution» go get

» Build from source

» Pre-built binary

go getUse go get to download and build as with any package

$ go get <package>

Updates:

$ go get -u <package>

Example:

» Edward

go getPros:

» No overhead, just push to a repo

» Handles dependencies and installation

» Cross-platform by default

Cons:

» Always pulls the latest commit

» Limits build complexity (by design)

» Difficult to use for closed-source

Build from source» Download source

» Provide instructions

» Build with Makefile or similar

Example:* sites-cfg* Hugo

Build from sourcePros:

» Allows a more complicated build process

» Easy to support private repos

» Can tailor to a familar workflow

Cons:

» Requires more detailed instruction

» More build tools complicates cross-platform distribution

» Additional build dependencies

Pre-built binary» Cross-compile and distribute directly

» Can use package managers like homebrew for quick install

» Or distribute binary via download page

Examples:* srv* Docker* Hugo

Pre-built binaryPros:

» No dependency on go

» Greater choice of distribution channels

» Simpler version management

Cons:

» Overhead

» Building binaries

» Setting up distribution channels

» Must decide on supported platforms

UpdateNotification

Update NotificationAlerting users who installed using go get

» Tag commits in Git with a version number: x.y.z

» Marked as releases in GitHub

» Compare current version to tags on Git remote, alert if a newer version is available

Checking for Updatesimport "github.com/hashicorp/go-version"

func UpdateAvailable(repo, currentVersion) (bool, string, error) { output, _ := exec.Command( "git", "ls-remote", "-t", "git://"+repo ).CombinedOutput() // Parse tag from output in the form [0-9]+\.[0-9]+\.[0-9]+ latestVersion, _ = findLatestVersionTag(output) remote, _ := version.NewVersion(latestVersion) local, _ := version.NewVersion(currentVersion) return local.LessThan(remote), remote, nil}

What Could

You Do?

Thank You» http://www.yext.com

» https://telliott.io

» @theotherelliott