Table of Contents
- Introduction
- Prerequisites
- Setup
- Creating the CLI Tool
- Adding Time Tracking Commands
- Saving and Loading Data
- Conclusion
Introduction
In this tutorial, we will learn how to create a command-line interface (CLI) tool in Go for time tracking. We will build a tool that allows users to track their time and manage tasks using simple commands. By the end of this tutorial, you will be able to create your own CLI tool using Go and perform time tracking operations.
Prerequisites
To follow this tutorial, you should have a basic understanding of the Go programming language and have Go installed on your machine. If you don’t have Go installed, you can download it from the official Go website (https://golang.org/) and follow the installation instructions for your specific operating system.
Setup
Before we start building our CLI tool, let’s set up a new Go project. Open your terminal and create a new directory for your project:
mkdir go-time-tracking
cd go-time-tracking
Next, initialize a new Go module using the following command:
go mod init github.com/your-username/go-time-tracking
This will create a go.mod
file that tracks the dependencies for your project.
Creating the CLI Tool
To create the CLI tool, we will be using the Cobra library, which provides a simple and elegant way to build CLI applications in Go. Cobra takes care of parsing command-line arguments, generating help documentation, and managing subcommands.
First, let’s add Cobra as a dependency to our project by running the following command:
go get -u github.com/spf13/cobra/cobra
Once the dependency is installed, let’s create a new Go file named main.go
in the root of our project directory. Open the file in your favorite text editor and add the following code:
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "time-tracker",
Short: "A CLI tool for time tracking",
Long: `time-tracker is a command-line interface tool
designed to help you track and manage your time.`,
Run: func(cmd *cobra.Command, args []string) {
// Default command action
},
}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
This sets up our basic CLI tool structure using Cobra. It initializes a new Cobra root command and defines its name, short description, long description, and default action. The main
function executes the root command and handles any errors that may occur.
To test our CLI tool, run the following command:
go run main.go
You should see the following output:
A CLI tool for time tracking
Usage:
time-tracker [command]
Available Commands:
help Help about any command
Flags:
--config string config file (default is $HOME/.time-tracker.yaml)
-h, --help help for time-tracker
-t, --toggle Help message for toggle
Use "time-tracker [command] --help" for more information about a command.
Congratulations! We have successfully set up the foundation of our CLI tool.
Adding Time Tracking Commands
Now that we have our basic CLI tool structure in place, let’s add some commands for time tracking. For this tutorial, we will focus on two main commands: start
and stop
.
Modify the main.go
file with the following code to add the start
and stop
commands:
package main
import (
"fmt"
"os"
"time"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "time-tracker",
Short: "A CLI tool for time tracking",
Long: `time-tracker is a command-line interface tool
designed to help you track and manage your time.`,
Run: func(cmd *cobra.Command, args []string) {
// Default command action
},
}
var startCmd = &cobra.Command{
Use: "start",
Short: "Start tracking time for a task",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Time tracking started...")
startTime := time.Now()
fmt.Println("Start Time:", startTime)
},
}
var stopCmd = &cobra.Command{
Use: "stop",
Short: "Stop tracking time for the current task",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Time tracking stopped...")
},
}
func main() {
rootCmd.AddCommand(startCmd)
rootCmd.AddCommand(stopCmd)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
We added startCmd
and stopCmd
as subcommands to the root command using the AddCommand
function. Each command has its own short description and action function. The start
command prints the current time as the start time, and the stop
command simply prints a message indicating the time tracking has stopped.
To test the new commands, run the following commands:
go run main.go start
Output:
Time tracking started...
Start Time: 2022-01-01 12:34:56.789
go run main.go stop
Output:
Time tracking stopped...
Great! We now have the basic functionality of starting and stopping time tracking.
Saving and Loading Data
To make our time tracking tool more useful, let’s implement saving and loading of tracked time data. We will use a simple text file to store the start and stop times of each task.
Create a new directory named data
at the root of your project. This directory will be used to store our time tracking data. Inside the data
directory, create a new file named tasks.txt
.
Modify the main.go
file with the following code to add file I/O functionality:
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"time"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "time-tracker",
Short: "A CLI tool for time tracking",
Long: `time-tracker is a command-line interface tool
designed to help you track and manage your time.`,
Run: func(cmd *cobra.Command, args []string) {
// Default command action
},
}
var startCmd = &cobra.Command{
Use: "start",
Short: "Start tracking time for a task",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Time tracking started...")
startTime := time.Now()
fmt.Println("Start Time:", startTime)
// Append start time to tasks.txt
task := "Start Time: " + startTime.Format(time.RFC3339) + "\n"
writeToTasksFile(task)
},
}
var stopCmd = &cobra.Command{
Use: "stop",
Short: "Stop tracking time for the current task",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Time tracking stopped...")
// Retrieve last start time from tasks.txt
startTime, err := getLastStartTime()
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Start Time:", startTime)
// Calculate and print elapsed time
stopTime := time.Now()
elapsedTime := stopTime.Sub(startTime)
fmt.Println("Elapsed Time:", elapsedTime.String())
// Append stop time to tasks.txt
task := "Stop Time: " + stopTime.Format(time.RFC3339) + "\n"
writeToTasksFile(task)
},
}
func writeToTasksFile(task string) {
dataDir := getDataDir()
filePath := filepath.Join(dataDir, "tasks.txt")
err := ioutil.WriteFile(filePath, []byte(task), os.FileMode(0644))
if err != nil {
fmt.Println("Error:", err)
}
}
func getLastStartTime() (time.Time, error) {
dataDir := getDataDir()
filePath := filepath.Join(dataDir, "tasks.txt")
fileData, err := ioutil.ReadFile(filePath)
if err != nil {
return time.Time{}, err
}
lines := strings.Split(string(fileData), "\n")
for i := len(lines) - 1; i >= 0; i-- {
if strings.HasPrefix(lines[i], "Start Time: ") {
startTimeStr := strings.TrimPrefix(lines[i], "Start Time: ")
startTime, err := time.Parse(time.RFC3339, startTimeStr)
if err != nil {
return time.Time{}, err
}
return startTime, nil
}
}
return time.Time{}, fmt.Errorf("no start time found")
}
func getDataDir() string {
homeDir, _ := os.UserHomeDir()
dataDir := filepath.Join(homeDir, ".time-tracker")
if _, err := os.Stat(dataDir); os.IsNotExist(err) {
os.Mkdir(dataDir, os.FileMode(0755))
}
return dataDir
}
func main() {
rootCmd.AddCommand(startCmd)
rootCmd.AddCommand(stopCmd)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
We added functions to write to the tasks.txt
file and retrieve the last start time from the file. The writeToTasksFile
function appends the task data to the file, and the getLastStartTime
function reads the file and retrieves the last recorded start time.
Let’s test the new functionality by running the following commands:
go run main.go start
go run main.go stop
You should see the start and stop times printed, and the tasks.txt file will contain the recorded start and stop times.
Conclusion
In this tutorial, we have learned how to create a CLI tool for time tracking using Go. We started by setting up the project structure and adding the Cobra library as a dependency. We then added commands for starting and stopping time tracking and implemented saving and loading of data using a text file.
By following this tutorial, you should now have a basic understanding of how to create a CLI tool in Go and perform time tracking operations. You can further enhance the tool by adding more commands, implementing additional features, or integrating with other services.
Take what you have learned and start building your own CLI tools using Go. Have fun exploring the possibilities and experimenting with new ideas!