Automating your routine with Golang and a CLI

Automating your routine with Golang and a CLI

I had this idea after reading the article of Chris Bongers about automating morning routine

I read that article and loved the idea to automate some tasks that we do everyday.

So i decided to take a step further and create a CLI who is gonna be my "assistant" to make all kind of small tasks.

In this tutorial, we are going to make a CLI in Golang to do two things :

  • Open tabs on my browser (like Chris Bongers did with a script but we are gonna do it with Golang)
  • Create and saves txt notes from the CLI.

Requirements

You must have a little knowledge about Golang to follow this tutorial.

To create the CLI, we are going to use Cobra

Cobra is a library for creating CLI in golang.

Create the project

Now we can start.

We are going to create a new project on our computer

mkdir mycli
cd mycli
go mod init mycli
go get -u github.com/spf13/cobra/cobra

init the CLI

Now that we have cobra installed, we can start creating our cli

The pkg-name here is important because it's going to be the name you invoke when calling your CLI. I'm gonna call mine Homer

cobra init --pkg-name homer

After executing that command , you can see that your project-folder looks like this

▾ mycli/
  ▾ cmd/
     root.go
   main.go

Create our first command

Now let's add our first command to our cli

cobra add <commandName>

Our first command is to open tabs in the morning, so i am gonna type

cobra add morning

If you look at your files structure, a new file called morning.go has been created. Every time you are gonna add a command, a new file with the name of your command is gonna be created in the cmd folder.

▾ mycli/
  ▾ cmd/
     root.go
     morning.go
   main.go

Implement the morning command

Now, open the file called morning.go

package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

// morningCmd represents the morning command
var morningCmd = &cobra.Command{
    Use:   "morning",
    Short: "A brief description of your command",
    Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("morning called")
    },
}

func init() {
    rootCmd.AddCommand(morningCmd)

    // Here you will define your flags and configuration settings.

    // Cobra supports Persistent Flags which will work for this command
    // and all subcommands, e.g.:
    // morningCmd.PersistentFlags().String("foo", "", "A help for foo")

    // Cobra supports local flags which will only run when this command
    // is called directly, e.g.:
    // morningCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

We are going to work inside the var morningCmd that represents our command.

First, complete the use and the descriptions (long and short) of your command.

Then, inside the Run , we are going to implement the actual code that we want to run when we are going to call the command : homer morning

package cmd

import (
    "bufio"
    "fmt"
    "os"

    "github.com/spf13/cobra"
    "github.com/pkg/browser"
)

// morningCmd represents the morning command
var morningCmd = &cobra.Command{
    Use:   "morning",
    Short: "Open a list of urls",
    Long: `Url opens a list of urls defined in a txt file`,
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Good morning ! Homer is opening your tabs")
        // Open the file.
        f, _ := os.Open("/path/to/your/tabs.txt")
        // Create a new Scanner for the file.
        scanner := bufio.NewScanner(f)
        // Loop over all lines in the file and print them.
        for scanner.Scan() {
          line := scanner.Text()
          // use browser to Open the url
          browser.OpenURL(line)
        }
    },
}

Great ! Now let's build our app

go install homer

And try our command

homer morning
Good morning ! Homer is opening your tabs

Tadaaaaaam !

Let's add another command

Well, now let's go further and add another command.

Let's add a command to take quick notes.

cobra add notes

A new file called notes.go is now available.

Let's implement the code

package cmd

import (
    "fmt"
    "os"
    "os/exec"

    "github.com/spf13/cobra"
)

// notesCmd represents the notes command
var notesCmd = &cobra.Command{
    Use:   "notes",
    Short: "A command to take quick notes",
    Long: `This command helps you take quick notes by opening a file .txt`,
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Homer is opening a new note")
        // create a folder for the notes if doesn't exists
        _ = os.Mkdir("./notes", 0755)
        // open the editor of your choice => nano for me
        // the name of the file will be your argument
        // homer notes myfile will open a file called myfile.txt 
        editorCmd := exec.Command("nano", fmt.Sprintf("./notes/%v.txt", args[0]))
        editorCmd.Stdin = os.Stdin
        editorCmd.Stdout = os.Stdout
        editorCmd.Stderr = os.Stderr

        err := editorCmd.Run()
        if (err != nil) {
            fmt.Println(err)
        }
    },
}

func init() {
    rootCmd.AddCommand(notesCmd)
}

Now, build the app : go install homer

And run the command

homer notes mynote

Capture d'écran 2020-11-29 13:21:46.png

Just write your note and save it.

All your notes will be saved inside the folder notes.
I chose to put it inside the project (./notes) but you can choose to create it wherever you want on your computer.

And now ?

Now you have a new assistant called homer that can do multiple tasks for you.
So just think about a new task you want to automate, and make a new command with cobra.

For example, you can add subcommands to list all your notes, to find a particular note, to delete a note ...

Have fun with your new assistant :)

Did you find this article valuable?

Support Sonia Manoubi by becoming a sponsor. Any amount is appreciated!