Go.mod: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(49 intermediate revisions by the same user not shown)
Line 6: Line 6:


=Overview=
=Overview=
<code>go.mod</code> declares the [[Go_Modules#Module_Path|module path]], which is the [[Go_Packages#Import_Path|import path]] prefix for all [[Go_Packages#Overview|packages]] within the module. It also tracks the modules that provide dependencies to this module. <code>go.mod</code> is located in the root of the module, which is also the root of the source tree for the module.
<code>go.mod</code> declares the [[Go_Modules#Module_Path|module path]], which is the [[Go_Packages#Import_Path|import path]] prefix for all [[Go_Packages#Overview|packages]] within the module. It also tracks the modules that provide dependencies to this module. <code>go.mod</code> is located in the root of the module, which is also the root of the source tree for the module. The most common way to create a <code>go.mod</code> is with <code>[[#Initialize_go.mod|go mod init <module-path>]]</code>. The file can also be created manually with a text editor, and then edited with the same text editor, but Go documentation recommends to make changes to the file via <code>go</code> commands.
 
One way to create it is with <code>[[Go_Tool#mod|go mod init]]</code>:
<syntaxhighlight lang='bash'>
go mod init <module-path>
</syntaxhighlight>
 
The file can also be created manually with a text editor, but Go documentation recommends to make changes to the file via <code>go</code> commands.


<code>go.mod</code> stays with the code, including in the source repository.
<code>go.mod</code> stays with the code, including in the source repository.
Line 19: Line 12:
A typical <code>go.mod</code> file usually assumes that your project is hosted in GitHub, but this is not a requirement. The [[Go_Modules#Module_Path|module path]] can be anything.
A typical <code>go.mod</code> file usually assumes that your project is hosted in GitHub, but this is not a requirement. The [[Go_Modules#Module_Path|module path]] can be anything.


As <code>go</code> tools are used to manage dependencies, the tools update the <code>go.mod</code> file so that it maintains the current list of dependencies.  
As <code>go</code> tools are used to manage dependencies, the tools update the <code>go.mod</code> file so that it maintains the current list of dependencies.
 
=<tt>go.sum</tt>=
=<tt>go.sum</tt>=
{{External|https://golang.org/ref/mod#go-sum-files}}
When a dependency is added, <code>go</code> creates a <code>go.sum</code> file that contains checksums, in form of cryptographic hashes, of dependency modules. This is used to verify the integrity of the downloaded module files. This file should not edited manually.
When a dependency is added, <code>go</code> creates a <code>go.sum</code> file that contains checksums, in form of cryptographic hashes, of dependency modules. This is used to verify the integrity of the downloaded module files. This file should not edited manually.


=Example=
=<span id='Example'></span><tt>go.mod</tt> Example=
<syntaxhighlight lang='go'>
<syntaxhighlight lang='go'>
module example.com/hello
module example.com/hello
Line 44: Line 39:
<syntaxhighlight lang='bash'>
<syntaxhighlight lang='bash'>
go mod init example.com/generic
go mod init example.com/generic
</syntaxhighlight>
=<tt>go.mod</tt> Editing Commands=
Do not modify <code>go.mod</code> manually, always use <code>go mod</code> editing commands to ensure that requirements described by the file remain consistent.
==<tt>edit</tt>==
===<tt>-require</tt>===
<syntaxhighlight lang='bash'>
go mod edit -require=...
</syntaxhighlight>
Examples [[#go_mod_edit|below]].
===<tt>-droprequire</tt>===
<syntaxhighlight lang='bash'>
go mod edit -droprequire=github.com/apache/yunikorn-scheduler-interface
</syntaxhighlight>
===<tt>-replace</tt>===
<syntaxhighlight lang='bash'>
go mod edit -replace=...
</syntaxhighlight>
Examples [[#go_mod_edit_replace|below]].
=Go Version=
<syntaxhighlight lang='go'>
module example.com/hello
go 1.22.4
</syntaxhighlight>
</syntaxhighlight>


=<span id='get'></span>Adding a Dependency to a Module=
=<span id='get'></span>Adding a Dependency to a Module=


Dependencies are added with the <code>go get</code> command. The command updates <code>go.mod</code> by adding the <code>require</code> directive for dependencies. The <code>require</code> directive tracks the minimum version of a module that the module depends on. The command also updates the module source code and places in the [[Go_Modules#Module_Cache|module cache]] and authenticate each module it downloads. This ensures that it's unchanged ged from when the module was published.  
Dependencies are added with the <code>go get</code> command. The command updates <code>go.mod</code> by adding the <code>require</code> directive for dependencies. The <code>require</code> directive tracks the minimum version of a module that the module depends on. The command also updates the module source code and places in the [[Go_Modules#Module_Cache|module cache]] and authenticate each module it downloads. This ensures that it's unchanged from when the module was published.  


<syntaxhighlight lang='bash'>
<syntaxhighlight lang='bash'>
go get [-u] github.com/apache/yunikorn-core@v1.4.0
go get [-u] github.com/apache/yunikorn-core@v1.4.0
</syntaxhighlight>
For a post v1 module, postfix <code>/vx</code> to the module path:
<syntaxhighlight lang='bash'>
go get github.com/labstack/echo/v4@v4.11.4
</syntaxhighlight>
</syntaxhighlight>


Note that you are adding the dependency in advance without actually referring it from the module source code, <code>go get</code> will add an "// indirect" comment for that specific dependency in <code>go.mod</code>.
Note that you are adding the dependency in advance without actually referring it from the module source code, <code>go get</code> will add an "// indirect" comment for that specific dependency in <code>go.mod</code>.
If the exact latest version is unknown, use the following syntax to let <code>go get</code> determine it:
<syntaxhighlight lang='bash'>
go get google.golang.org/protobuf/reflect/protoreflect
</syntaxhighlight>


<font color=darkkhaki>TODO: https://pkg.go.dev/cmd/go#hdr-Add_dependencies_to_current_module_and_install_them</font>
<font color=darkkhaki>TODO: https://pkg.go.dev/cmd/go#hdr-Add_dependencies_to_current_module_and_install_them</font>
==Variations of <tt>go get</tt>==
==Variations of <tt>go get</tt>==
{{Internal|Go_Tool#get|<tt>go get</tt>}}
{{Internal|Go_get#Overview|<tt>go get</tt>}}
 
=Removing a Dependency from a Module=
 
See <code>[[#-droprequire|go mod edit -droprequire]]</code> above.


=Update Module's Dependencies=
=Update Module's Dependencies=
Line 69: Line 104:
=Using Unpublished Module Code=
=Using Unpublished Module Code=
{{External|https://go.dev/doc/modules/managing-dependencies#unpublished}}
{{External|https://go.dev/doc/modules/managing-dependencies#unpublished}}
Normally, <code>go get</code> is used with published, versioned releases of a project's dependencies. However, there are situations that require experimentally modifying a dependency to use it with the current project. The Go documentation refers to this situation as "developing and testing against unpublished module code". There are two ways to access a modified dependency: in a local directory on the development machine and in a forked repository.
Normally, <code>go get</code> is used with published, versioned releases of a project's dependencies. However, there are situations that require experimentally modifying a dependency to use it with the current project. The Go documentation refers to this situation as "developing and testing against unpublished module code". There are two ways to access a modified dependency: in a [[#Using_Local_Module_Code|local directory]] on the development machine and in a [[#Using_an_Arbitrary_Fork_Module_Code|forked repository]].
==Using Local Module Code==
==Using Local Module Code==
<font color=darkkhaki>TODO: https://go.dev/doc/modules/managing-dependencies#local_directory</font>
A very common situation when experimenting with the source of a dependency is to clone the dependency repository locally, and modify the code. It is convenient, and possible, to express the <code>go.mod</code> dependency to point to the local directory. The <code>go.mod</code> syntax to express this situation is:
<syntaxhighlight lang='py'>
...
require example.com/somemodule v0.0.0-unpublished
replace example.com/somemodule v0.0.0-unpublished => ../somemodule
</syntaxhighlight>
 
The configuration expresses the fact the dependency version we intend do use is not published anywhere (<code>v0.0.0-unpublished</code>), and the tool chain must reach out to the local directory <code>../somemodule</code> to get it. The <code>replace</code> directive specifies the location. An absolute path can be used, but that might introduce problems if <code>go.mod</code> is shared within a team, and the path is not consistent across developers' machines.
 
<span id='go_mod_edit'></span><span id='go_mod_edit_replace'></span>Avoid modifying <code>go.mod</code> manually. Use the following command to generate the configuration:
<syntaxhighlight lang='bash'>
go mod edit -require=example.com/somemodule@v0.0.0-unpublished
# Careful when using copy-and-paste, the first command uses "-require", the second "-replace"
go mod edit -replace=example.com/somemodule@v0.0.0-unpublished=../somemodule
</syntaxhighlight>
Example:
<syntaxhighlight lang='bash'>
go mod edit -require=github.com/apache/yunikorn-core@v0.0.0-unpublished
go mod edit -replace=github.com/apache/yunikorn-core@v0.0.0-unpublished=/Users/ovidiu/projects/yunikorn/github-ovidiuf-forks/yunikorn-core
</syntaxhighlight>
Use <code>go get</code> to pull the source code in the [[Go_Modules#Module_Cache|module cache]]:
<syntaxhighlight lang='bash'>
go get example.com/somemodule@v0.0.0-unpublished
</syntaxhighlight>
 
==Using an Arbitrary Fork Module Code==
==Using an Arbitrary Fork Module Code==
<font color=darkkhaki>TODO: https://go.dev/doc/modules/managing-dependencies#external_fork</font>
{{External|https://go.dev/doc/modules/managing-dependencies#external_fork}}
The same pattern as in [[#Using_Local_Module_Code|Using Local Module Code]] applies, but this time the <code>replace</code> statement refers to an actual repository.
 
The <code>go.mod</code> should look like:
<syntaxhighlight lang='go'>
...
require github.com/apache/yunikorn-core v0.0.0-unpublished
replace github.com/apache/yunikorn-core v0.0.0-unpublished => example.com/myfork/yunikorn-core v1.2.3-fixed
</syntaxhighlight>
The edit commands are:
<syntaxhighlight lang='bash'>
go mod edit -require=github.com/apache/yunikorn-core@v0.0.0-unpublished
go mod edit -replace=github.com/apache/yunikorn-core@v0.0.0-unpublished=example.com/myfork/yunikorn-core@v1.2.3-fixed
</syntaxhighlight>
 
Instead of a specific version, a commit hash or a branch name can be used instead, as show below in the [[Go.mod#Getting_a_Specific_Commit|Getting a Specific Commit]] section.
 
=Getting a Specific Commit=
=Getting a Specific Commit=
<font color=darkkhaki>TODO: https://go.dev/doc/modules/managing-dependencies#repo_identifier</font>
{{External|https://go.dev/doc/modules/managing-dependencies#repo_identifier}}
 
To get a specific commit, use the commit hash or a branch name:
<syntaxhighlight lang='bash'>
go get example.com/theirmodule@4cf76c2
go get example.com/theirmodule@of/some-branch
</syntaxhighlight>
 
This command will modify <code>go.mod</code> as follows:
<syntaxhighlight lang='go'>
require example.com/theirmodule v0.0.0-20240109203350-28b9035e2013
</syntaxhighlight>
 
If the dependency on a dot version is already declared in the <code>go.mod</code>:
<syntaxhighlight lang='bash'>
require official.com/somemodule v1.0.0
</syntaxhighlight>
and we want to (temporarily) replace it with the dependency defined by a specific commit or branch name in a different repository, use <code>go mod edit -replace</code> as follows:
<syntaxhighlight lang='bash'>
go mod edit -replace=official.com/somemodule@v1.0.0=experimental.com/somemodule@4cf76c2
go mod edit -replace=official.com/somemodule@v1.0.0=experimental.com/somemodule@of/somebranch
</syntaxhighlight>
This command will modify <code>go.mod</code> as follows:
<syntaxhighlight lang='go'>
replace official.com/somemodule v1.0.0 => experimental.com/somemodule v0.0.0-20240109203350-28b9035e2013
</syntaxhighlight>
 
The version label eventually stored in the <code>go.mod</code> file has a timestamp "...-20240117154324-..." and a commit hash "...-4323f643fa79", that contains the first 12 most significant digits of the GitHub commit.
=<tt>go.mod</tt> and Bazel=
{{Internal|Gazelle#Relationship_between_WORKSPACE_and_go.mod|Relationship between <tt>WORKSPACE</tt> and <tt>go.mod</tt>}}

Latest revision as of 08:16, 23 November 2024

External

Internal

Overview

go.mod declares the module path, which is the import path prefix for all packages within the module. It also tracks the modules that provide dependencies to this module. go.mod is located in the root of the module, which is also the root of the source tree for the module. The most common way to create a go.mod is with go mod init <module-path>. The file can also be created manually with a text editor, and then edited with the same text editor, but Go documentation recommends to make changes to the file via go commands.

go.mod stays with the code, including in the source repository.

A typical go.mod file usually assumes that your project is hosted in GitHub, but this is not a requirement. The module path can be anything.

As go tools are used to manage dependencies, the tools update the go.mod file so that it maintains the current list of dependencies.

go.sum

https://golang.org/ref/mod#go-sum-files

When a dependency is added, go creates a go.sum file that contains checksums, in form of cryptographic hashes, of dependency modules. This is used to verify the integrity of the downloaded module files. This file should not edited manually.

go.mod Example

module example.com/hello

go 1.21.0

require rsc.io/quote v1.5.2

require (
	golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
	rsc.io/sampler v1.3.0 // indirect
)

Initialize go.mod

In the module root directory, initialize the go.mod file.

go mod init <module-path>
go mod init example.com/generic

go.mod Editing Commands

Do not modify go.mod manually, always use go mod editing commands to ensure that requirements described by the file remain consistent.

edit

-require

go mod edit -require=...

Examples below.

-droprequire

go mod edit -droprequire=github.com/apache/yunikorn-scheduler-interface

-replace

go mod edit -replace=...

Examples below.

Go Version

module example.com/hello

go 1.22.4

Adding a Dependency to a Module

Dependencies are added with the go get command. The command updates go.mod by adding the require directive for dependencies. The require directive tracks the minimum version of a module that the module depends on. The command also updates the module source code and places in the module cache and authenticate each module it downloads. This ensures that it's unchanged from when the module was published.

go get [-u] github.com/apache/yunikorn-core@v1.4.0

For a post v1 module, postfix /vx to the module path:

go get github.com/labstack/echo/v4@v4.11.4

Note that you are adding the dependency in advance without actually referring it from the module source code, go get will add an "// indirect" comment for that specific dependency in go.mod.

If the exact latest version is unknown, use the following syntax to let go get determine it:

go get google.golang.org/protobuf/reflect/protoreflect


TODO: https://pkg.go.dev/cmd/go#hdr-Add_dependencies_to_current_module_and_install_them

Variations of go get

go get

Removing a Dependency from a Module

See go mod edit -droprequire above.

Update Module's Dependencies

Use go list to check if there are newer versions of dependencies. If there are available useful upgrades, use go get command again to add the particular newer version.

Synchronize Dependencies

TODO: https://go.dev/doc/modules/managing-dependencies#synchronizing

Using Unpublished Module Code

https://go.dev/doc/modules/managing-dependencies#unpublished

Normally, go get is used with published, versioned releases of a project's dependencies. However, there are situations that require experimentally modifying a dependency to use it with the current project. The Go documentation refers to this situation as "developing and testing against unpublished module code". There are two ways to access a modified dependency: in a local directory on the development machine and in a forked repository.

Using Local Module Code

A very common situation when experimenting with the source of a dependency is to clone the dependency repository locally, and modify the code. It is convenient, and possible, to express the go.mod dependency to point to the local directory. The go.mod syntax to express this situation is:

...
require example.com/somemodule v0.0.0-unpublished
replace example.com/somemodule v0.0.0-unpublished => ../somemodule

The configuration expresses the fact the dependency version we intend do use is not published anywhere (v0.0.0-unpublished), and the tool chain must reach out to the local directory ../somemodule to get it. The replace directive specifies the location. An absolute path can be used, but that might introduce problems if go.mod is shared within a team, and the path is not consistent across developers' machines.

Avoid modifying go.mod manually. Use the following command to generate the configuration:

go mod edit -require=example.com/somemodule@v0.0.0-unpublished
# Careful when using copy-and-paste, the first command uses "-require", the second "-replace"
go mod edit -replace=example.com/somemodule@v0.0.0-unpublished=../somemodule

Example:

go mod edit -require=github.com/apache/yunikorn-core@v0.0.0-unpublished
go mod edit -replace=github.com/apache/yunikorn-core@v0.0.0-unpublished=/Users/ovidiu/projects/yunikorn/github-ovidiuf-forks/yunikorn-core

Use go get to pull the source code in the module cache:

go get example.com/somemodule@v0.0.0-unpublished

Using an Arbitrary Fork Module Code

https://go.dev/doc/modules/managing-dependencies#external_fork

The same pattern as in Using Local Module Code applies, but this time the replace statement refers to an actual repository.

The go.mod should look like:

...
require github.com/apache/yunikorn-core v0.0.0-unpublished
replace github.com/apache/yunikorn-core v0.0.0-unpublished => example.com/myfork/yunikorn-core v1.2.3-fixed

The edit commands are:

go mod edit -require=github.com/apache/yunikorn-core@v0.0.0-unpublished
go mod edit -replace=github.com/apache/yunikorn-core@v0.0.0-unpublished=example.com/myfork/yunikorn-core@v1.2.3-fixed

Instead of a specific version, a commit hash or a branch name can be used instead, as show below in the Getting a Specific Commit section.

Getting a Specific Commit

https://go.dev/doc/modules/managing-dependencies#repo_identifier

To get a specific commit, use the commit hash or a branch name:

go get example.com/theirmodule@4cf76c2
go get example.com/theirmodule@of/some-branch

This command will modify go.mod as follows:

require example.com/theirmodule v0.0.0-20240109203350-28b9035e2013

If the dependency on a dot version is already declared in the go.mod:

require official.com/somemodule v1.0.0

and we want to (temporarily) replace it with the dependency defined by a specific commit or branch name in a different repository, use go mod edit -replace as follows:

go mod edit -replace=official.com/somemodule@v1.0.0=experimental.com/somemodule@4cf76c2
go mod edit -replace=official.com/somemodule@v1.0.0=experimental.com/somemodule@of/somebranch

This command will modify go.mod as follows:

replace official.com/somemodule v1.0.0 => experimental.com/somemodule v0.0.0-20240109203350-28b9035e2013

The version label eventually stored in the go.mod file has a timestamp "...-20240117154324-..." and a commit hash "...-4323f643fa79", that contains the first 12 most significant digits of the GitHub commit.

go.mod and Bazel

Relationship between WORKSPACE and go.mod