Write a Command-line application with Go
Golang is an open source programming language built by Google in 2007. During its short lifetime as compared to other progamming languages in its era, Go has made a huge impact in the programming world. I have just picked up Go as a recommendation from a friend and I think its awesome. In this tutorial we will be building a console based application that takes users input from the console and outputs list of post stored in a slice(our data structure), so let's get started.
Why we love Go
- It is a compiled, statically typed language, A pragmatic version of C
- Functions are first class objects, meaning they can be passed as arguments to other functions
- It has Garbage collection
- It supports Concurrency out of the box. All Go standard libraries are built with Concurrrency in mind
- Go is not object oriented
- Go has an active community (Just incase you get into trouble)
- Easy deployment
Setting Up Go
In this tutorial we will be using Cloud9 as our coding environment. If you don't already have Go installed on your local machine, head over to c9.io to follow along. The Cloud9 platform has a Blank template(Ubuntu obviously) that comes with Go installed, add the needed details and create your Workspace. All you have to do afterwards is create a new file calle main.go(this can be anything you want, but the community uses a lot of main.go as the entry point to a go app)
If everything went well, you should have something like this on your browser.
Getting Started
If you have ever written a C or Java program, you will come across a main function as the starting point in those programming languages; Go is no different. Go applications are organized in system directories called packages, they enable code reusability.
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello World")
}
This is a simple Go program that prints "Hello World" to standard output. It imports the fmt package from the standard library, using its Println function to output the text to the console.
In this tutorial we will be focusing on the flag package. The flag package implements command-line flag parsing. Normally, in console based applications we use flags to direct the flow of program execution
For example
$ myapp --version will give me the version of myapp
$ myapp --help will show me list of commands to perform
$ myapp --port 3000 will run the server at port 3000
flag package
The flag package comes with a lot of interesting functions and constants. You can define a flag using flag.Int(), flag.String(), flag.Bool(), flag.Duration() etc.
Defining flags
var integerPointer = flag.Int("age", 24, "Enter your age here")
Here we are defining an Integer flag and storing it into a pointer integerPointer, with type *int.
Another way of defining flag is by binding the flag to a variable using the Var() functions like so
var intflagvar int
var stringflagvar string
var boolvar bool
...
func main() {
flag.IntVar(&intflagvar, "integer flag", 9090, "help message for this flag")
flag.StringVar(&stringflagvar, "name of flag", "default value", "help message for this flag")
flag.StringVar(&boolvar, "name of flag", true, "help message")
flag.Parse()
}
Note
-
Defining a flag of a particular type returns a pointer to that type : meaning flag.Int() returns *int etc.
-
When you done defining all the flags your application is going to use, only then should you call flag.Parse()
-
If you are binding flags to variables using the Var() functions, the variable will contain the value of that flag.
Get Post from a console
In our application, we define a struct called options to hold the possible flags the application can work with. Users of our application can either give us a post count to retrieve a certain number of post from our slice or can ask for the version of our app. We using a bool to represent our version options, so we can check if thats the given argument.
import (
"flag"
"fmt"
"os"
"strings"
)
var options struct {
postCount int
version bool
}
The main() function initializes a slice of strings(ie posts titles), define a Usage function that explains how the app works, defines all of our flags and Parse() the flags afterwards.
var posts = []string{"Using Docker and Docker Compose for Local Development and Small Deployments", "Trying Clean Architecture on Golang", "Understanding Depenedency Management and Package Management in Golang", "Dancing with Go's Mutexes", "Selenium: easy as pie", "Go Best Practises - Testing"}
var Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s[post_count]\n", os.Args[0])
flag.PrintDefaults()
}
flag.IntVar(&options.postCount, "count", 1, "Enter the number of post you would love to see")
flag.BoolVar(&options.version, "version", false, "View the version of this application")
flag.Parse()
In other to get the post count entered by the user, we create intPtr which references the value bound to options.PostCount. If this variable is nil, it means this was not the argument passed to our application else we check if the number of post we want is not greater than the length of post titles we have in our slice. While there are many ways we can go about getting data like from a database, i've chosen to just hard-code it into a slice. We loop over the post based on the users count calling the getPostByCount() function and printing each post title to the console
var intPtr *int
intPtr = &options.postCount
if intPtr != nil {
if *intPtr > len(posts) {
fmt.Printf("%s\n", "Number of post specified is greater than what we currently have...")
os.Exit(0)
}
buildPost := getPostByCount(posts, *intPtr)
for post := range buildPost {
fmt.Printf("%s\n", buildPost[post])
}
os.Exit(0)
}
To show the user which version of the console they are using is pretty simple, we check if the options.version is true because that would mean a -version flag was passed to the application and we echo the version and exit the program. The program makes sure that if no argument was passed to the application, it just gracefully echoes the first post title
if options.version {
fmt.Printf("%s", "goCmd installed version 0.0.1\n")
os.Exit(0)
}
if len(flag.Args()) == 0 {
Usage()
os.Exit(1)
}
The getPostByCount() function takes the number of post to retrieve, loops through the posts slice and appends each post to a buildPost variable of type []string( slice of strings) and returns buildPost to the calling application.
func getPostByCount(posts []string, count int) []string {
buildPost := []string{}
for post := 0; post < count; post++ {
buildPost = append(buildPost, posts[post])
}
return buildPost
}
Conclusion
In this post i have highlighted my journey through the flag package. Hopefully, u have got a hang of how a commandline application is written in Go.
You can look at the code for this tutorial on Cloud9 or on My Github. Comments and reprove are welcome.
Happy Coding