Cobra is a library for creating CLI applications in Go. It provides a simple interface for defining commands, flags, and subcommands.
I’ve utilized Cobra to create a CLI tool and organized the code into multiple packages.
Find the related source code here:
https://github.com/m7kvqbe1/advent-of-code-2023
Init
First we initialize the project as a new module:
go mod init github.com/m7kvqbe1/advent-of-code-2023
This creates a go.mod
file (there is also go.sum
file which is essentially a lockfile). As we import packages the Go tooling automatically updates these files.
It specifies direct and indirect deps:
module github.com/m7kvqbe1/advent-of-code-2023
go 1.22.1
require github.com/spf13/cobra v1.8.1
require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
)
Organizing Code into Packages
The code has then been divided into multiple packages within the pkg
directory (this is an established Go convention).
Each package corresponds to a specific day of the ‘Advent of Code’ challenge and contains the logic for each part of that day’s challenge in seperate files.
The package namespace is declared at the top of each file:
package day01
We can import one of our local packages like so:
import (
"github.com/m7kvqbe1/advent-of-code-2023/pkg/day01"
// ...
)
Using Cobra for CLI
The main.go
file in the root of the codebase contains a root command and subcommands for each of the challenges:
rootCmd := &cobra.Command{Use: "advent-of-code-2023"}
rootCmd.AddCommand(&cobra.Command{
Use: "day01part1",
Short: "Run Day 01 Part 1",
Run: func(cmd *cobra.Command, args []string) {
day01.Part1()
},
})
// ...
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
}
Each subcommand is associated with a public function from the respective package.
Public functions in Go are always declared with PascalCase. Private functions use camelCase.
I’ve explicitly referenced the package namespace (day01
) as there are numerous Part01
functions declared across my packages.