Go Modules
The purpose of this post is to give a very simple example and instructions on how to
create a Go package with the Go Modules.
Create a new package
Let’s start by creating a new repository (e.g. go-modules
) and apply the following
folder/file structure to it:
go-modules
|-- bar
| `-- bar.go
|-- foo
| `-- foo.go
`-- main.go
Now run
$ go mod init gomodules
This will create go.mod
file with the following structure:
module gomodules
go 1.13
Now let’s add an external dependency to our project:
$ go get rsc.io/quote
This will add require rsc.io/quote v1.5.2 // indirect
to go.mod
and it will also
create go.sum
file with pinned packages.
Now let’s add some code.
Add this to main.go
:
package main
import (
"gomodules/foo"
"gomodules/bar"
)
func main() {
foo.Hello()
bar.Hello()
}
Add this to foo/foo.go
:
package foo
import (
"fmt"
"rsc.io/quote"
)
func main() {
fmt.Println(quote.Hello())
}
Add this to bar/bar.go
:
package bar
import (
"fmt"
"gomodules/foo"
)
func Hello() {
fmt.Println("Hello from Bar.")
foo.Hello()
}
Now run go build .
. This will produce a file executable file named gomodules
. If we run
it this is what the output should be:
$ ./gomodules
Hello, world.
Hello from Bar.
Hello, world.
The first Hello, world.
is from calling foo.Hello()
in main.go then we call bar.Hello()
which produces Hello from Bar.
and Hello, world.
because bar.Hello also calls
foo.Hello()
.
NOTE: Do not forget to name the public functions with a
capital letter
otherwise they won’t be available in main.go (because they won’t be exported).
Pin a package
Now let’s add another package but this time let’s pin it to a specific version:
$ go get github.com/liderman/text-generator@v0.1.0
If we would already have added text-generator we would need to use the -u
(upgrade)
flag to apply the changes.
$ go get -u github.com/liderman/text-generator@v0.1.0
This will add github.com/liderman/text-generator v0.1.0
to go.mod
file. The v0.1.0
refers to the github tag. You can see all tags/releases here: https://github.com/liderman/text-generator/releases
(for liderman/text-generator package).
Now let’s modify main.go file a bit to use our new package:
package main
import (
"fmt"
"github.com/liderman/text-generator"
"gomodules/bar"
"gomodules/foo"
)
func main() {
foo.Hello()
bar.Hello()
tg := text_generator.New()
template := "Good {morning|day}!"
fmt.Println(tg.Generate(template))
}
Now we need to build the package again and run it:
$ go build
$ ./gomodules
Hello, world.
Hello from Bar.
Hello, world.
Good day!
Tidy your go.mod
To make sure that go.mod matches the source code in the module run go tidy:
$ go mod tidy
It adds any missing modules necessary to build the current module’s
packages and dependencies, and it removes unused modules that
don’t provide any relevant packages. It also adds any missing entries
to go.sum and removes any unnecessary ones.
See this article
using go list
, go mod why
and go mod graph
.
What is the difference between package versions?
Using apidiff
to determine API compatibility.
Ref:
- https://github.com/karantan/go-modules
- https://github.com/golang/go/wiki/Modules#quick-start
- https://blog.callr.tech/migrating-from-dep-to-go-1.11-modules/
- https://stackoverflow.com/questions/52026284/accessing-local-packages-within-a-go-module-go-1-11
- https://ukiahsmith.com/blog/a-gentle-introduction-to-golang-modules/