title |
---|
Gopkg.lock |
The Gopkg.lock
file is generated by dep ensure
and dep init
. It is the output of the solving function: a transitively complete snapshot of a project's dependency graph, expressed as a series of [[project]]
stanzas. That means:
Gopkg.lock
also contains some metadata about the algorithm and inputs used to arrive at the final graph, under [solve-meta]
.
Gopkg.lock
always includes a revision
for all listed dependencies, as the semantics of revision
guarantee them to be immutable. Thus, the Gopkg.lock
acts as a reproducible build list - as long as the upstream remains available, all dependencies can be precisely reproduced.
Gopkg.lock
is autogenerated; editing it manually is generally an antipattern. If there is a goal you can only achieve by hand-editing Gopkg.lock
, it is at least a feature request, and likely a bug.
The dependency graph is expressed as a series of [[projects]]
stanzas, each representing a single dependency project. A given project can only appear once in the list, and the version information expressed about them encompasses all contained packages - it is not possible to have multiple packages from a single project at different versions.
These are all the properties that can appear in a [[projects]]
stanza, and whether or not they are guaranteed to be present/must be present for a stanza to be valid.
Property | Always present? |
---|---|
name |
Y |
packages |
Y |
source |
N |
revision |
Y |
version |
N |
branch |
N |
pruneopts |
Y |
digest |
Y |
The project to which the stanza applies, as identified by its project root.
If present, it indicates the upstream source from which the project should be retrieved. It has the same properties as source
in Gopkg.toml
.
A complete list of directories from within the source that dep determined to be necessary for the build.
In general, this is the set of packages that were found to be participants in the package import graph, through at least one but as many as all of the following mechanisms:
- Being in the current project's
required
list - Being imported by a package from either the current project or a different dependency
- Being imported by a package from within this project that, directly or transitively, is imported by a package from a different project
A compactly-encoded form of the prune options designated in Gopkg.toml
. Each character represents one of the three possible rules:
Character | Pruning Rule in Gopkg.toml |
---|---|
N |
non-go |
U |
unused-packages |
T |
go-tests |
If the character is present in pruneopts
, the pruning rule is enabled for that project. Thus, NUT
indicates that all three pruning rules are active.
The hash digest of the contents of vendor/
for this project, after pruning rules have been applied. The digest is versioned, by way of a colon-delimited prefix; the string is of the form <version>:<hex-encoded digest>
. The hashing algorithm corresponding to version 1 is SHA256, as implemented in the stdlib package crypto/sha256
.
There are some tweaks that differentiate the hasher apart from a naive filesystem tree hashing implementation:
- Symlinks are ignored.
- Line endings are normalized to LF (using an algorithm similar to git's) in order to ensure digests do not vary across platforms.
In order to provide reproducible builds, it is an absolute requirement that every project stanza contain a revision
, no matter what kinds of constraints were encountered in Gopkg.toml
files. It is further possible that exactly one of either version
or branch
will additionally be present.
When one of the other two are present, the revision
is understood to be the underlying, immutable identifier that corresponded to that version
or branch
at the time when the Gopkg.lock
was written.
Metadata contained in this section tells us about the algorithm that was used to generate the Gopkg.lock
file. These are very coarse indicators, primarily used to trigger a re-evaluation of the lock when it might have become invalid, as well as warn a team when its members are using algorithms with potentially subtly different effects.
More details on "analyzer" and "solver" follow, but the versioning principle is the same: algorithmic changes that result in a decrease to the set of acceptable solutions for at least one input set generally require a version bump, while changes that increase the size of that set do not. However, this is not a formal definition; we leave room for judgment calls on small changes and bug fixes, and we bump at most once per release.
By bumping versions only on solution set contractions, but not expansions, it allows us to avoid having to bump constantly (which could make using dep across teams awkward), while still making it likely that when the solver and version numbers match between Gopkg.lock
and a running version of dep, what's recorded in the file is acceptable by the running version's rules.
A sorted list of all the import inputs that were present at the time the Gopkg.lock
was computed. This list includes both actual import
statements from the project, as well as any required
import paths listed in Gopkg.toml
, excluding any that were ignored
.
The analyzer is an internal dep component responsible for interpreting the contents of Gopkg.toml
files, as well as metadata files from any tools dep knows about: glide.yaml
, vendor.json
, etc.
The analyzer is named because the dep needs to identify itself to its engine, gps (github.com/golang/dep/gps
); gps knows nothing about dep. The analyzer version is bumped when something in the analyzer's logic begins treating data that it already accepted in a significantly different way, or stops accepting a particular class of data. It is not changed when support for entirely new types of data are added.
For example, if dep's analyzer stopped supporting automated conversions from glide, then that would not require bumping the analyzer version, as doing so makes more solutions possible. Adding support for converting from a new tool, or changing the interpretation of version
fields in Gopkg.toml
so that it was only allowed to specify minimum versions, would entail a version bump.
The solver is the algorithm behind the solving function. It selects all the versions that ultimately appear in Gopkg.lock
by finding a combination that satisfies all the rules, including those from Gopkg.toml
(fed to the solver by the analyzer).
The solver is named because, like the analyzer, it is pluggable; an alternative algorithm could be written that applies different rules to achieve the same goal. The one dep uses, "gps-cdcl", is named after the general class of SAT solving algorithm it most resembles, though the algorithm is actually a specialized, domain-specific SMT solver.
The same general principles of version-bumping apply to the solver version: if the solver starts enforcing Go 1.4 import path comments, that entails a bump, because it can only narrow the solution set. If it were to later relax that requirement, it would not require a bump, as that can only expand the solution set.