Dependency Management Before Go Modules
GOPATH Workspace
Before the introduction of Go modules, Go dependency management was primarily handled using the GOPATH workspace. The GOPATH environment variable defined the root of the workspace where all Go code and dependencies were stored. This approach centralized all dependencies in a single workspace, which sometimes led to conflicts and difficulties in managing different versions of the same dependency across multiple projects.
Setting Up GOPATH
To set up the GOPATH workspace, you need to define the GOPATH environment variable. Here’s an example:
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
The structure of the GOPATH workspace typically looked like this:
GOPATH/
├── bin/
├── pkg/
└── src/
├── github.com/
├── golang.org/
└── example/
└── myproject/
├── main.go
├── go.mod (if modules are being used in hybrid mode)
└── somepackage/
└── somefile.go
- bin: Compiled binaries are stored here.
- pkg: Compiled package objects are stored here.
- src: Source files for Go projects and their dependencies are stored here.
Dependency Management in GOPATH
Dependencies were typically managed by directly placing them in the src
directory within the GOPATH. When you ran go get
to fetch a dependency, it was placed in the appropriate path under $GOPATH/src
.
For example:
go get github.com/some/dependency
This command would download the dependency and place it in:
$GOPATH/src/github.com/some/dependency
Project Example Using GOPATH
Let’s create a simple Go project to demonstrate how dependencies were managed in GOPATH.
-
Setting Up the Project First, set up the GOPATH and create the project directory:
export GOPATH=$HOME/go export PATH=$PATH:$GOPATH/bin mkdir -p $GOPATH/src/example.com/myproject cd $GOPATH/src/example.com/myproject
-
Writing the Code Create a simple Go program that uses an external dependency.
// main.go package main import ( "fmt" "github.com/sirupsen/logrus" ) func main() { logrus.Info("Hello, World!") fmt.Println("Hello, World!") }
-
Fetching the Dependency Use the go get command to fetch the logrus dependency:
go get github.com/sirupsen/logrus
This command downloads the
logrus
package and places it in$GOPATH/src/github.com/sirupsen/logrus
. -
Running the Project Run the project using the go run command:
go run main.go
This should output:
INFO[0000] Hello, World! Hello, World!
Vendor Directory
The vendor directory allowed projects to include copies of their dependencies within the project directory itself. This ensured that each project could use specific versions of dependencies without conflict.
Using the Vendor Directory
-
Create a Vendor Directory: In the root of your project, create a
vendor
directory:mkdir -p myproject/vendor
-
Add Dependencies to Vendor: You can manually copy dependencies to the
vendor
directory, but it’s more common to use a tool to automate this process. -
Example Structure:
myproject/ ├── main.go └── vendor/ └── github.com/ └── some/ └── dependency/
Dependencies are placed in the
vendor
directory, ensuring that the project uses the exact versions specified.
Dependency Management Tools
Several tools were developed to help manage dependencies and the vendor directory before Go modules:
-
Godep: Godep was one of the early tools for managing dependencies. It could save the state of dependencies and restore them when needed.
go get -u github.com/tools/godep cd myproject godep save ./...
This created a
Godeps
directory with aGodeps.json
file, storing the versions of the dependencies. -
Glide: Glide provided more features and flexibility. It used a
glide.yaml
file to specify dependencies and their versions.curl https://glide.sh/get | sh cd myproject glide init glide install
The
glide.yaml
file contained the list of dependencies, andglide.lock
stored the exact versions. -
Govendor: Govendor offered similar functionality, allowing developers to manage dependencies and their versions.
go get -u github.com/kardianos/govendor cd myproject govendor init govendor add +external
Govendor used a
vendor.json
file to keep track of dependencies.
Project Example Using GOPATH and Vendor
-
Set Up Project Directory:
export GOPATH=$HOME/go export PATH=$PATH:$GOPATH/bin mkdir -p $GOPATH/src/example.com/myproject cd $GOPATH/src/example.com/myproject
-
Create
main.go
and Add Dependency:// main.go package main import ( "github.com/sirupsen/logrus" ) func main() { logrus.Info("Hello, Vendor!") }
-
Fetch Dependency:
go get github.com/sirupsen/logrus
-
Create Vendor Directory and Copy Dependency:
mkdir -p vendor/github.com/sirupsen/ cp -r $GOPATH/src/github.com/sirupsen/logrus vendor/github.com/sirupsen/
-
Update Import Paths (if needed): Update import paths to ensure the project uses the vendor directory first:
// main.go package main import ( "example.com/myproject/vendor/github.com/sirupsen/logrus" ) func main() { logrus.Info("Hello, Vendor!") }
-
Run the Project:
go run main.go