Click a button to subscribe to “Yunjian Da Jia” column, access to the official recommended boutique content, learn technology not lost!

Now that you know about module paths, version numbers and compatibility principles, and pseudo-version numbers, what else is worth looking at about the core concepts of Go Modules? Let’s move on to the next exciting content!

In the previous part, we introduced the three concepts of module path, version number and compatibility principle, and pseudo version number. In the next part, we will continue to introduce the core concept of Go Modules.

Four: major version number suffix


Starting with major version 2, a suffix like /v2 that matches the major version number must be added to the module path. For example, if a module has a path of example.com/test at v1.0.0, its path at v2.0.0 will be example.com/test/v2.

The main version suffix follows the import compatibility rules:

If a new package has the same import path as the old package, the new package must guarantee backward compatibility with the old package.

  • By definition, packages in the new major version of a module are not backward compatible with their counterparts in the previous major version. Therefore, starting with V2, the package needs a new import path. This is done by adding a major version suffix to the module path. Because the module path is the prefix to the import path for each package within the module, adding the major version suffix to the module path provides a different import path for each incompatible version.
  • The major version suffix v0 or v1 is not allowed. The module path between v0 and v1 does not need to be changed because the V0 version is unstable and has no compatibility guarantee. In addition, for most modules, V1 is backward compatible with the latest V0 version, which only began as a commitment to compatibility.
  • A special case here is that module paths starting with gopkg.in/ must always have a major version suffix, even for v0 and V1 versions. Suffixes must begin with a dot rather than a slash (for example, gopkg.in/yaml.v2). Since gopkg.in followed this rule before Go Modules came out, Go did some compatibility work to make it possible to import and compile code from the gopkg.in package.
  • The major version suffix allows multiple major versions of a module to coexist in the same build. Diamond dependency conflict jlbp.dev/what-is-a-d… Typically, if a module is required in two different versions of the passing dependency, the later version will be used. However, if two versions are incompatible, neither version will satisfy all callers. Since incompatible versions must have different major version numbers, the major version suffix has different module paths, so there is no conflict: modules with different suffixes are treated as separate modules, and their packages have different import paths.
  • Because many Go projects release version V2 or later before migrating to the Go module, the main version suffix is not used. For these versions, Go is annotated using the +incompatible construction flag (for example, V2.0.0 +incompatible).

Five: the process of resolving package path to module path


Usually “go get” is used to specify a package path rather than a module path. How does go find the module path?

The go command searches the build list of the main module (the current module) for module paths that match the prefix of the package path. For example, if the imported package path is example.com/a/b and example.com/a is found to be a module path, then example.com/a is checked to see if it contains the package in directory B, To be considered a valid package, at least one GO source file must exist in this directory. Build Constraints are not applied during this process. If a module containing the package is indeed found in the build list, the module will be used. The go command prompts an error if no module is found that provides the package or if two or more modules provide the package. But you can specify -mod=mod to make go try to download packages that can’t be found locally, and update go.mod and go.sum. The go get and Go Mod Tidy commands will do this automatically.

When the go command tries to download a new code package, it goes back and checks the GOPROXY environment variable, which is a comma-separated list of urls with support for keywords like direct and off, of course. The proxy URL indicates that GO will use the GOPROXY protocol to pull modules. Direct indicates that GO needs to interact directly with the version control system, while OFF does not need to interact with the outside world. In addition, GOPRIVATE and GONOPROXY environment variables fine-tune go’s strategy for downloading code packages.

For each item in the GOPROXY list, the go command goes back and requests each prefix of the module path. For modules with successful requests, the go command goes back to download the latest module and checks whether this particular block contains the requested package. If multiple modules contain the requested package, the one with the longest path will be selected. An error is reported if a module is found that does not contain this package. If no modules are found, the go command will try the next configuration item in the GOPROXY list, or an error will be reported if both modules are eventually tried and not found. For example, assume that the user wants to get golang.org/x/net/html this package, configuration before GOPROXY for corp.example.com, https://goproxy.io… Commands follow the following request order:

Initiate the request (parallel) to https://corp.example.com/ : Request for latest version of golang.org/x/net/html Request for latest version of golang.org/x/net Request for latest version of golang.org/x Request for latest version of golang.orgCopy the code

If corp.example.com/ fails, return 410 or 404 and make a proxy.golang.org/ request:

Request for latest version of golang.org/x/net/html
Request for latest version of golang.org/x/net
Request for latest version of golang.org/x
Request for latest version of golang.org
Copy the code

When a desired module is found, the go command adds the path and version of the dependent module to the main module’s go.mod file. This ensures that the same module version will be used when the module is compiled later, ensuring repeatability. If the parsed code package is not directly referenced by the main module, new dependencies added in the go.mod file have a // indirect comment.

Go. Mod file


As mentioned earlier, the definition of a module is defined by a UTF-8 encoded text file called go.mod. This file is line-oriented. Each line has a separate instruction, consisting of a reserved key and some parameters. Such as:

Module example.com/my/thing go 1.17 require example.com/other/thing v1.0.2 require example.com/new/thing/v2 v2.3.4 Exclude example.com/old/thing v1.2.3 replace example.com/bad/thing v1.4.5 => example.com/good/thing v1.4.5 retract [v1.9.0, v1.9.5]Copy the code

The opening keywords can be lumped together as rows, just like the imports we use everyday, so it could look something like this:

Require (example.com/new/thing/v2 v2.3.4 example.com/old/thing v1.2.3)Copy the code

The go.mod file is designed for developer readability and machine writability. The go command also provides several subcommands to help developers modify the go.mod file. For example, the go get command updates the go.mod file as needed. The go mod edit command allows you to make low-level changes to a file. If we had similar requirements, we could make the same changes programmatically using the golang.org/x/mod/modfile package. With this package, you can also take a look at the underlying struct structure of go.mod:

Type File struct {Module *Module // Module path go * go // go version Require []*Require // Exclude []*Exclude // Exclude Module Replace []*Replace // Retract Module []*Retract // Retract Module} // A Module is the Module statement Module struct { Mod module.Version Deprecated string } // A Go is the go statement. type Go struct { Version string // "1.23"} // An Exclude is a single Exclude statement. type Exclude struct {Mod module.Version} // a Replace is a single replace statement. type Replace struct { Old module.Version New module.Version } // A Retract is a single retract  statement. type Retract struct { VersionInterval Rationale string }Copy the code

In the early days of Go Modules, there was no Deprecated field in the struct of the Module. For example, if the main version of a module we maintain evolves from V1 to V2, we hope that users can use V2 as much as possible. V1 and V2 have different import paths, and Retract can’t do anything about it. This is where “Deprecated” comes into play, as in the following example:

// Deprecated: in example.com/a/[email protected], the latest supported version is example.com/a/b/v2.
module example.com/a/b
go 1.17
Copy the code

When the user attempts to obtain example.com/a/b, the go command detects that the version is no longer maintained and reports to the user:

Go get -d example.com/a/[email protected] go: Warning: module example.com/deprecated/a is deprecated: In example.com/a/[email protected], the latest supported version is example.com/a/b/v2Copy the code

The user can follow the prompts for v2 code pull.

Module, module path, package, package path, how to find module path through package path, version number and pseudo version number, and finally briefly introduced the go.mod file. Understanding these concepts, design concepts, and compatibility principles will Go a long way in managing and maintaining your own Go modules.

All of these concepts are common in Go, and understanding the difference between version numbers and pseudo-version numbers and design principles can help us understand how important it is to define your own tags according to Semver’s standards. At the same time, by following the compatibility principles defined by Go Modules, upstream and downstream developers will become more friendly and efficient when the community collaborates. The next series of articles will start looking at design details in Go Modules, such as the go.mod file and the Go mod subcommands that Go with it. In addition, Tencent Cloud GoProxy enterprise edition has been productized, students who need to know more can click here.

Go Modules basic refinement, full analysis of six core concepts (part 1)

“Cloud recommendation” is Tencent cloud plus community high-quality content column. Yunjianguan specially invites the top performers in the industry, focusing on the landing of cutting-edge technology and theoretical practice, to continue to interpret hot technologies in the cloud era and explore new opportunities for industry development. Click one button to subscribe and we will send you regular high-quality content.