In this article, we are going to create a simple module in Go.
What is a Go Module?
A module is a collection of Go packages stored in a file tree. It has several Go code files implementing the functionality of a package, but it also has two specific and important files in the root: the go.mod file and the go.sum
file. These files contain information the go tool uses to keep track of your module’s configuration and are commonly maintained by the tool so you don’t need to. The go.sum
file is autogenerated dependencies lock file.
Modules allow us to define precise dependency requirements and design reproducible builds for multiple environments.
Go has a very flexible module system that enables third-party modules to be downloaded from respective repositories into a cache which is located by default in the go subdirectory of the home directory. All Golang versions from 1.11 support the use of modules.
Go module Commands
The go tool provides several commands that are related to modules.
go mod init
- initializes new module in the current directorygo mod tidy
- adds missing and removes unused modulesgo mod download
- downloads modules to the local cachego mod vendor
- makes vendored copy of dependenciesgo mod graph
- prints module requirement graphgo mod verify
- verifies dependencies have expected contentgo mod why
- explains why packages or modules are neededgo list -m
- list all available modules.go get -u
- used to install dependencies and update the go.mod file.go build
- command to compile the code into an executable binary file.- go test - command executes test functions (whose names begin with Test) in test files (whose names end with _test.go). You can add the -v flag to get verbose output that lists all of the tests and their results
Creating a custom Go Module
Now, we will create an example Go module. We will call it GoLinuxCloud. First, we need to create a folder inside the GOPATH src
directory. Now, we need to have a go.mod
file in that directory that will allow us to manage dependency for this module.
Step-1: Define GOPATH Environment Variable
The Go path is used to resolve import statements. The GOPATH environment variable lists places to look for Go code. On Unix, the value is a colon-separated string. On Windows, the value is a semicolon-separated string.
GOPATH is a variable that defines the root of your workspace. By default, the workspace directory is a directory that is named go within your user home directory (~/go
for Linux and MacOS, %USERPROFILE%/go
for Windows). GOPATH stores your code base and all the files that are necessary for your development. Learn more about GOPATH Configuration
Execute "go env GOPATH
" to see the current GOPATH. In most cases, GOPATH is the root of your workspace and contains the following folders:-
src/
:- location of Go source code (for example, .go, .c, .g, .s).pkg/
:- location of compiled package code (for example, .a).bin/
:- location of compiled executable programs built by Go.
Step-2: Configuring GOPATH for different scopes
You can configure GOPATH for the following scopes:
Global GOPATH
:-settings apply to all projects of a specific installation of GoLang.Project GOPATH
:-settings apply only to the current project.Module GOPATH
:-settings apply only to one module. A module can have an SDK that is different from those configured for a project. They can also carry a specific technology or a framework.
Step-3: Create directory structure for custom module
Create a directory called golinuxcloud
for our Go module source code. This is where we all our code will be held and called and create a directory for greeting
this will be inside the main directory golinuxcloud
$ mkdir golinuxcloud $ cd golinuxcloud $ mkdir greeting
Following is our directory structure
/
|-- golinuxcloud/
|--|-- greeting/
Create all files required for our module
$ cd golinuxcloud $ mkdir greeting && touch main.go $ cd greeting && touch greeting.go && touch greeting_test.go
Here, we have created all required files and folders, our structure looks like
Step-4: Initializing our custom go module
To do it, run this command.
go mod init golinuxcloud
After running this command we will get a go.mod
file. Now, currently, we don’t have dependencies. But in any case, if we add it the mod file will get updated.
This is how modules simplify the package and dependency management in Go. Now, to get all the dependencies my package has, we run the following command:-
go list -m all
The output is for my case as follows:
$ go list -m all
golinuxcloud
Whenever we update its dependencies and run the test it will automatically fetch those packages without anything from our side. This is what makes modularization a very powerful tool in GoLang.
Get go.mod
file content
$ cat go.mod
module golinuxcloud
go 1.18
These are the contents of the go.mod
file. We have the module path for the Go version.
Step-5: Create some sample Go module code
Then for simplicity’s sake add two files in the greeting
folder namely greeting.go
file and greating_test.go
. One is general go code and the other is a testing file. main.go
file is located at the root of the project golinuxcloud
folder
Example at the greeting folder
// greeting.go
package greeting
import (
"errors"
"fmt"
)
// Greeting returns a greeting for the named person/organisation.
func Greeting(name string) (string, error) {
// If no name was given, return an error with a message.
if name == "" {
return name, errors.New("The name is Empty ")
}
msg := fmt.Sprintf("Hello world from %s.", name)
return msg, nil
}
Now, we run go main to see the result with a string input value
$ go run main.go "GoLinuxCloud"
Hello world from GoLinuxCloud.
Without an input string value/empty string
$ go run main.go "" The name is Empty
Explanation:-
Greeting():-
It accepts string input value and return two outputs of type string and error. It checks if the input value is empty, then returns an error stating the name should not be empty, otherwise its returns a string containing a message of hello world from %name_passed.
Main():-
We are using os package to pass a value without hardcoding value into our main function. The value is passed into Greeting()
function and response stored in a res variable which is later printed on the screen using fmt
package using println
function.
// greeting_test.go
package greeting
import (
"regexp"
"testing"
)
// TestGreeting calls Greeting() with a name, checking for a valid return value.
func TestGreeting(t *testing.T) {
name := "GoLinuxCloud"
want := regexp.MustCompile(`\b` + name + `\b`)
msg, err := Greeting("GoLinuxCloud")
if !want.MatchString(msg) || err != nil {
t.Fatalf(`Greeting("GoLinuxCloud") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
// TestGreetingEmpty calls Greeting() with an empty string,checking for an error.
func TestGreetingEmpty(t *testing.T) {
msg, err := Greeting("")
if msg != "" || err == nil {
t.Fatalf(`Greeting("") = %q, %v, want "", error`, msg, err)
}
}
In this code above:-
- Implement test functions in the same package as the code you're testing.
- Create two test functions to test the Greeting function. Test function names have the form
TestName
, where the Name says something about the specific test. Also, test functions take a pointer to the testing package's testing.T
type as a parameter. You use this parameter's methods for reporting and logging from your test.
Implement two tests:
TestGreeting
calls the Greeting function, passing a name-value with which the function should be able to return a valid response message. If the call returns an error or an unexpected response message (one that doesn't include the name you passed in), you use the t parameter'sFatalf
method to print a message to the console and end execution.TestGreetingEmpty
calls the Greeting function with an empty string. This test is designed to confirm that your error handling works. If the call returns a non-empty string or no error, you use the t parameter's Fatalf method to print a message to the console and end execution.
At the terminal in the golinuxcloud directory, run the go test command to execute the test.
- The go test command executes test functions (whose names begin with Test) in test files (whose names end with
_test.go
). You can add the-v
flag to get verbose output that lists all of the tests and their results. - The tests should pass.
$ go test PASS ok golinuxcloud 0.005s $ go test -v === RUN TestGreeting --- PASS: TestGreeting (0.00s) === RUN TestGreetingEmpty --- PASS: TestGreetingEmpty (0.00s) PASS ok golinuxcloud 0.005s
main()
function code
// main.go
package main
import (
"golinuxcloud/greeting"
"log"
"os"
)
func main() {
value := os.Args[1]
res, err := greeting.Greeting(value)
if err != nil {
log.Println(err)
os.Exit(0)
}
log.Println(res)
}
Explanation:-
- Declare the main package. In Go, code executed as an application must be in the main package.
- Import three packages:
golinuxcloud/greeting
,os
and thelog
package. This gives your code access to functions in those packages. Importinggolinuxcloud/greeting
this package gives us access to theGreeting()
function. We have imported log package, with functions for handling input and output text, i.e printing function to display either error message or results of the function being executed. - Get a greeting by calling the greetings package’s
Greeting()
function. - The os package enables us to exit from program once an error is encountered and reading of users inputs like the string being passed as argument into
Greeting()
function, we useos.Args[]
function andos.Exit()
function
Step-6: Compile code into executable binary file
At the root of the project, run go build command
$ go build
The above command will create an executable binary file same as the module name golinuxcloud. We execute the binary file by running as ./name_module
go run main.go "Golang study"
For Example
$./golinuxcloud ""
2022/06/22 14:41:32 The name is Empty
With string inputs, For Example
$./golinuxcloud "Golang study"
2022/06/22 14:42:05 Hello world from Golang study.
Summary
In this article, you’ve learned how to create a Go module, create tests and execute various go commands from version control systems, as well as build and cross-compile executables for different platforms.
References
How to create Go modules
modules in Go