Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Going all-inwith Go
for CLIapps
AboutMe
» Tom Elliott
» Engineer @ Yext
» https://telliott.io
» @theotherelliott
AboutYext
» Location data management
» 90 engineers
» 200+ microservices in Java
& Go
» http://www.yext.com
» http://githu...
Agenda
» Who Uses Go For CLI?
» Why Go for CLI?
» Tools at Yext
» Standard Library
» 3rd Party Packages
» Distribution
» U...
Who Uses Go for CLI?
Who Uses Go for CLI?
Why Go
for CLI?
WhyGo for CLI?
» Familiarity
» Code Reuse
» Cross-platform
» Distribution Flexibility
ToolsAt
Yext
srv
Internal tool for building, testing and deploying
Yext services
$ srv build Pages
$ srv test Pages unit
$ srv publish ...
sites-cfg
Internal configuration tool for sites managed by
Pages
$ sites-cfg listsites
$ sites-cfg validate stores.enterpri...
Edward
https://github.com/yext/edward
Open source tool to manage local instances of service
$ edward start pages
$ edward ...
Standard
Library
Flags
import "flag"
Define and parse command-line flags
var port = flag.Int("port", 8080, "Port number for service")
flag.Parse...
Directorytreewalking
import "path/filepath"
Call filepath.Walk with a starting dir and a visitor function.
To find all .c file...
Process Execution
import "os/exec"
Run other command-line processes:
cmd := exec.Command("echo", "hello")
err := cmd.Run()...
EnvironmentVariables
import "os"
Getenv / Setenv:
os.Setenv("MYKEY", "VALUE")
value := os.Getenv("MYKEY")
ExpandEnv:
expan...
Platform-Specific Code
Build tags:
// +build !linux,!darwin
package main
func init() { macOS_or_Linux_only() }
File names:
...
3rd Party
Packages
CLI
$ go get github.com/urfave/cli
import "urfave/cli"
» Framework for command-line applications
» Familiar command, args ...
gopsutil
$ go get github.com/shirou/gopsutil
import "shirou/gopsutil"
» go port of Python's psutil
» Helps retrieve inform...
Distribution
Distribution
» go get
» Build from source
» Pre-built binary
go get
Use go get to download and build as with any package
$ go get <package>
Updates:
$ go get -u <package>
Example:
» E...
go get
Pros:
» No overhead, just push to a repo
» Handles dependencies and installation
» Cross-platform by default
Cons:
...
Build from source
» Download source
» Provide instructions
» Build with Makefile or similar
Example:
* sites-cfg
* Hugo
Build from source
Pros:
» Allows a more complicated build process
» Easy to support private repos
» Can tailor to a famila...
Pre-builtbinary
» Cross-compile and distribute directly
» Can use package managers like homebrew for quick
install
» Or di...
Pre-builtbinary
Pros:
» No dependency on go
» Greater choice of distribution channels
» Simpler version management
Cons:
»...
UpdateNotification
Update Notification
Alerting users who installed using go get
» Tag commits in Git with a version number: x.y.z
» Marked as...
Checking for Updates
import "github.com/hashicorp/go-version"
func UpdateAvailable(repo, currentVersion) (bool, string, er...
WhatCould
You Do?
ThankYou» http://www.yext.com
» https://telliott.io
» @theotherelliott
Going All-In With Go For CLI Apps
Upcoming SlideShare
Loading in …5
×

Going All-In With Go For CLI Apps

3,039 views

Published on

An exploration of how Yext adopted Go for building command line tools, the language features and third-party packages that helped along the way, and how we manage distribution to an 90-strong team.

Published in: Software
  • Be the first to comment

Going All-In With Go For CLI Apps

  1. 1. Going all-inwith Go for CLIapps
  2. 2. AboutMe » Tom Elliott » Engineer @ Yext » https://telliott.io » @theotherelliott
  3. 3. AboutYext » Location data management » 90 engineers » 200+ microservices in Java & Go » http://www.yext.com » http://github.com/yext » http://engblog.yext.com/
  4. 4. Agenda » Who Uses Go For CLI? » Why Go for CLI? » Tools at Yext » Standard Library » 3rd Party Packages » Distribution » Update Notification
  5. 5. Who Uses Go for CLI?
  6. 6. Who Uses Go for CLI?
  7. 7. Why Go for CLI?
  8. 8. WhyGo for CLI? » Familiarity » Code Reuse » Cross-platform » Distribution Flexibility
  9. 9. ToolsAt Yext
  10. 10. srv Internal 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
  11. 11. sites-cfg Internal 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
  12. 12. Edward https://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
  13. 13. Standard Library
  14. 14. Flags import "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
  15. 15. Directorytreewalking import "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 }
  16. 16. Process Execution import "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
  17. 17. EnvironmentVariables import "os" Getenv / Setenv: os.Setenv("MYKEY", "VALUE") value := os.Getenv("MYKEY") ExpandEnv: expanded := os.ExpandEnv("$GOPATH/github.com/user/repo")
  18. 18. Platform-Specific Code Build tags: // +build !linux,!darwin package main func init() { macOS_or_Linux_only() } File names: dns_windows.go
  19. 19. 3rd Party Packages
  20. 20. 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
  21. 21. 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
  22. 22. Distribution
  23. 23. Distribution » go get » Build from source » Pre-built binary
  24. 24. go get Use go get to download and build as with any package $ go get <package> Updates: $ go get -u <package> Example: » Edward
  25. 25. go get Pros: » 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
  26. 26. Build from source » Download source » Provide instructions » Build with Makefile or similar Example: * sites-cfg * Hugo
  27. 27. Build from source Pros: » 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
  28. 28. Pre-builtbinary » Cross-compile and distribute directly » Can use package managers like homebrew for quick install » Or distribute binary via download page Examples: * srv * Docker * Hugo
  29. 29. Pre-builtbinary Pros: » 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
  30. 30. UpdateNotification
  31. 31. Update Notification Alerting 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
  32. 32. Checking for Updates import "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 }
  33. 33. WhatCould You Do?
  34. 34. ThankYou» http://www.yext.com » https://telliott.io » @theotherelliott

×