Refactoring the Command-Line interface
We'll refactor the command-line interface of multi-git into its proper place in our directory structure in this lesson.
We'll cover the following
In this lesson, we will not make changes to the functionality. We’ll just move files around. This measured approach of separating refactoring from functional changes helps us eliminate many problems and if something does go wrong, it is easier to identify the root cause and fix it.
Planning the refactoring
In the previous lesson, we refactored the core logic into a set of packages under the pkg
top-level directory. Now, we will do something similar for the command-line interface. We will move into a new subdirectory called mg
, which is short for multi-git under the cmd
top-level directory. This follows established conventions in the Go community. It will allow adding additional commands later if necessary.
The plan is as follows:
- Create the multi-git command
- Move the code from the main() function into the new command
- Verify that everything still works
Let’s get to it!
Creating the command
Creating the command is as simple as creating the top-level directory, cmd
, and a sub-directory called, mg
:
$ mkdir -p cmd/mg
Here is our new directory structure:
$ tree -L 2
.
├── LICENSE
├── README.md
├── cmd
│ └── mg
├── go.mod
├── go.sum
└── pkg
├── helpers
└── repo_manager
The pkg
directory contains two packages: repo_manager
and helpers
. The new cmd
directory contains the mg
directory.
Moving the code from the main() function
Moving the code from the main()
function is trivial. All we have to do is move the entire main.go file, as is, to the cmd/mg
directory.
$ mv main.go cmd/mg
To build the mg
command we need to run the following commands:
$ cd cmd/mg
$ go build
The result is the mg
binary.
$ ls -laHG
total 4888
drwxr-xr-x 4 gigi.sayfan staff 128 Nov 3 09:45 .
drwxr-xr-x 3 gigi.sayfan staff 96 Nov 3 09:22 ..
-rw-r--r-- 1 gigi.sayfan staff 786 Nov 3 09:28 main.go
-rwxr-xr-x 1 gigi.sayfan staff 2498264 Nov 3 09:45 mg
The reason it works with no changes is that the code in the main() function imports the repo_manager
package by its fully qualified path and not as a relative path. The location of the main package itself is not important.
package main
import (
"flag"
"fmt"
"log"
"os"
"path"
"strings"
"github.com/the-gigi/multi-git/pkg/repo_manager"
.
.
.
)
Verifying everything works
This version of multi-git is tagged as v0.3 and is available here: https://github.com/the-gigi/multi-git/releases/tag/v0.3
Let’s have some fun with the interactive terminal. Now, that you’re in the driver’s seat, play around with multi-git. In the terminal below git
and go
are already installed. You will fetch the code for multi-git, build it, create a few directories and git repos, and let mg
run git commands against the repositories.
First, to get multi-git type the following commands:
mkdir test-mg
cd test-mg
git clone --branch v0.3 https://github.com/the-gigi/multi-git
Then, to build the mg
, executable type the following commands:
cd multi-git/cmd/mg
go build
mv mg /usr/local/bin
Feel free along the way to type ls
to see what files exist in each directory. In particular, there should be the mg
executable in the current directory (/test-mg/multi-git/cmd/mg
) after the go build
command. The mg
executable is then moved to the /usr/loca/bin
directory.
The next step is to create a couple of directories that will contain the repositories multi-git will operate on. If you want to follow my footsteps, use:
mkdir -p /test-mg/repos/repo-1
mkdir -p /test-mg/repos/repo-2
Now would be a good time to set MG_ROOT and MG_REPOS:
export MG_ROOT=/test-mg/repos
export MG_REPOS=repo-1,repo-2
And… that’s it. You’re ready to test multi-git interactively. Your first command should be
mg --command init
This will initialize git in the target repositories. Then, you can freestyle, check that mg
indeed created a .git subdirectory in repo-1
and repo-2
, add files and directories, and issue more mg
commands.
Note that if you want to commit files, you’ll have to configure git with your username and email
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
Get hands-on with 1400+ tech skills courses.