Russ Cox | e58eda1 | 2018-03-20 13:16:16 -0400 | [diff] [blame] | 1 | # Proposal: Versioned Go Modules |
| 2 | |
| 3 | Author: Russ Cox\ |
| 4 | Last Updated: March 20, 2018\ |
| 5 | Discussion: https://golang.org/issue/24301 |
| 6 | |
| 7 | ## Abstract |
| 8 | |
| 9 | We propose to add awareness of package versions to the Go toolchain, especially the `go` command. |
| 10 | |
| 11 | ## Background |
| 12 | |
| 13 | The first half of the blog post [Go += Package Versioning](https://research.swtch.com/vgo-intro) presents detailed background for this change. |
| 14 | In short, it is long past time to add versions to the working vocabulary of both Go developers and our tools, |
| 15 | and this proposal describes a way to do that. |
| 16 | |
| 17 | [Semantic versioning](https://semver.org) is the name given to an established convention for assigning version numbers |
| 18 | to projects. |
| 19 | In its simplest form, a version number is MAJOR.MINOR.PATCH, where MAJOR, MINOR, and PATCH |
| 20 | are decimal numbers. |
| 21 | The syntax used in this proposal follows the widespread convention of |
| 22 | adding a “v” prefix: vMAJOR.MINOR.PATCH. |
| 23 | Incrementing MAJOR indicates an expected breaking change. |
| 24 | Otherwise, a later version is expected to be backwards compatible |
| 25 | with earlier versions within the same MAJOR version sequence. |
| 26 | Incrementing MINOR indicates a significant change or new features. |
| 27 | Incrementing PATCH is meant to be reserved for very small, very safe changes, |
| 28 | such as small bug fixes or critical security patches. |
| 29 | |
| 30 | The sequence of [vgo-related blog posts](https://research.swtch.com/vgo) presents more detail |
| 31 | about the proposal. |
| 32 | |
| 33 | ## Proposal |
| 34 | |
| 35 | I propose to add versioning to Go using the following approach. |
| 36 | |
| 37 | 1. Introduce the concept of a _Go module_, which is a group of |
| 38 | packages that share a common prefix, the _module path_, and are versioned together as a single unit. |
| 39 | Most projects will adopt a workflow in which a version-control repository |
| 40 | corresponds exactly to a single module. |
| 41 | Larger projects may wish to adopt a workflow in which a |
| 42 | version-control repository can hold multiple modules. |
| 43 | Both workflows will be supported. |
| 44 | |
| 45 | 2. Assign version numbers to modules by tagging specific commits |
| 46 | with [semantic versions](https://semver.org) such as `v1.2.0`. |
| 47 | (See |
He Liu | e71fd13 | 2018-03-25 18:20:57 +0000 | [diff] [blame] | 48 | the [Defining Go Modules](https://research.swtch.com/vgo-module) post |
Russ Cox | e58eda1 | 2018-03-20 13:16:16 -0400 | [diff] [blame] | 49 | for details, including how to tag multi-module repositories.) |
| 50 | |
| 51 | 3. Adopt [semantic import versioning](https://research.swtch.com/vgo-import), |
| 52 | in which each major version has a distinct import path. |
| 53 | Specifically, an import path contains a module path, a version number, |
| 54 | and the the path to a specific package inside the module. |
| 55 | If the major version is v0 or v1, then the version number element |
| 56 | must be omitted; otherwise it must be included. |
| 57 | |
| 58 | <p style="text-align:center"> |
| 59 | <img width=343 height=167 src="24301/impver.png" srcset="24301/impver.png 1x, 24301/[email protected] 1.5x, 24301/[email protected] 2x, 24301/[email protected] 3x, 24301/[email protected] 4x"> |
| 60 | </p> |
| 61 | |
| 62 | The packages imported as `my/thing/sub/pkg`, `my/thing/v2/sub/pkg`, and `my/thing/v3/sub/pkg` |
| 63 | come from major versions v1, v2, and v3 of the module `my/thing`, |
| 64 | but the build treats them simply as three different packages. |
| 65 | A program that imports all three will have all three linked into the final binary, |
| 66 | just as if they were `my/red/pkg`, `my/green/pkg`, and `my/blue/pkg` |
| 67 | or any other set of three different import paths. |
| 68 | |
| 69 | Note that only the major version appears in the import path: `my/thing/v1.2/sub/pkg` is not allowed. |
| 70 | |
| 71 | |
| 72 | 4. Explicitly adopt the “import compatibility rule”: |
| 73 | |
| 74 | > _If an old package and a new package have the same import path,_\ |
| 75 | > _the new package must be backwards compatible with the old package._ |
| 76 | |
| 77 | The Go project has encouraged this convention from the start |
| 78 | of the project, but this proposal gives it more teeth: |
| 79 | upgrades by package users will succeed or fail |
| 80 | only to the extent that package authors follow the import |
| 81 | compatibility rule. |
| 82 | |
| 83 | The import compatibility rule only applies to tagged |
| 84 | releases starting at v1.0.0. |
| 85 | Prerelease (vX.Y.Z-anything) and v0.Y.Z versions |
| 86 | need not follow compatibility with earlier versions, |
| 87 | nor do they impose requirements on future versions. |
| 88 | In contrast, tagging a commit vX.Y.Z for X ≥ 1 explicitly |
| 89 | indicates “users can expect this module to be stable.” |
| 90 | |
| 91 | In general, users should expect a module to follow |
| 92 | the [Go 1 compatibility rules](https://golang.org/doc/go1compat#expectations) |
| 93 | once it reaches v1.0.0, |
| 94 | unless the module's documentation clearly states exceptions. |
| 95 | |
| 96 | 5. Record each module's path and dependency requirements in a |
| 97 | [`go.mod` file](XXX) stored in the root of the module's file tree. |
| 98 | |
| 99 | 6. To decide which module versions to use in a given build, |
| 100 | apply [minimal version selection](https://research.swtch.com/vgo-mvs): |
| 101 | gather the transitive closure of all the listed requirements |
| 102 | and then remove duplicates of a given major version of a module |
| 103 | by keeping the maximum requested version, |
| 104 | which is also the minimum version satisfying all listed requirements. |
| 105 | |
| 106 | Minimal version selection has two critical properties. |
| 107 | First, it is trivial to implement and understand. |
| 108 | Second, it never chooses a module version not listed in some `go.mod` file |
| 109 | involved in the build: new versions are not incorporated |
| 110 | simply because they have been published. |
| 111 | The second property produces [high-fidelity builds](XXX) |
| 112 | and makes sure that upgrades only happen when |
| 113 | developers request them, never unexpectedly. |
| 114 | |
| 115 | 7. Define a specific zip file structure as the |
| 116 | “interchange format” for Go modules. |
| 117 | The vast majority of developers will work directly with |
| 118 | version control and never think much about these zip files, |
| 119 | if at all, but having a single representation |
| 120 | enables proxies, simplifies analysis sites like godoc.org |
| 121 | or continuous integration, and likely enables more |
| 122 | interesting tooling not yet envisioned. |
| 123 | |
| 124 | 8. Define a URL schema for fetching Go modules from proxies, |
| 125 | used both for installing modules using custom domain names |
| 126 | and also when the `$GOPROXY` environment variable is set. |
| 127 | The latter allows companies and individuals to send all |
| 128 | module download requests through a proxy for security, |
| 129 | availability, or other reasons. |
| 130 | |
| 131 | 9. Allow running the `go` command in file trees outside GOPATH, |
| 132 | provided there is a `go.mod` in the current directory or a |
| 133 | parent directory. |
| 134 | That `go.mod` file defines the mapping from file system to import path |
| 135 | as well as the specific module versions used in the build. |
| 136 | See the [Versioned Go Commands](https://research.swtch.com/vgo-cmd) post for details. |
| 137 | |
| 138 | 10. Disallow use of `vendor` directories, except in one limited use: |
| 139 | a `vendor` directory at the top of the file tree of the top-level module |
| 140 | being built is still applied to the build, |
| 141 | to continue to allow self-contained application repositories. |
| 142 | (Ignoring other `vendor` directories ensures that |
| 143 | Go returns to builds in which each import path has the same |
| 144 | meaning throughout the build |
| 145 | and establishes that only one copy of a package with a given import |
| 146 | path is used in a given build.) |
| 147 | |
| 148 | The “[Tour of Versioned Go](https://research.swtch.com/vgo-tour)” |
| 149 | blog post demonstrates how most of this fits together to create a smooth user experience. |
| 150 | |
| 151 | ## Rationale |
| 152 | |
| 153 | Go has struggled with how to incorporate package versions since `goinstall`, |
| 154 | the predecessor to `go get`, was released eight years ago. |
| 155 | This proposal is the result of eight years of experience with `goinstall` and `go get`, |
| 156 | careful examination of how other languages approach the versioning problem, |
| 157 | and lessons learned from Dep, the experimental Go package management tool released in January 2017. |
| 158 | |
| 159 | A few people have asked why we should add the concept of versions to our tools at all. |
| 160 | Packages do have versions, whether the tools understand them or not. |
| 161 | Adding explicit support for versions |
| 162 | lets tools and developers communicate more clearly when |
| 163 | specifying a program to be built, run, or analyzed. |
| 164 | |
| 165 | At the start of the process that led to this proposal, almost two years ago, |
| 166 | we all believed the answer would be to follow the package versioning approach |
| 167 | exemplified by Ruby's Bundler and then Rust's Cargo: |
| 168 | tagged semantic versions, |
| 169 | a hand-edited dependency constraint file known as a manifest, |
| 170 | a machine-generated transitive dependency description known as a lock file, |
| 171 | a version solver to compute a lock file satisfying the manifest, |
| 172 | and repositories as the unit of versioning. |
| 173 | Dep, the community effort led by Sam Boyer, follows this plan almost exactly |
| 174 | and was originally intended to serve as the model for `go` command |
| 175 | integration. |
| 176 | Dep has been a significant help for Go developers |
| 177 | and a positive step for the Go ecosystem. |
| 178 | |
| 179 | Early on, we talked about Dep simply becoming `go dep`, |
| 180 | serving as the prototype of `go` command integration. |
| 181 | However, the more I examined the details of the Bundler/Cargo/Dep |
| 182 | approach and what they would mean for Go, especially built into the `go` command, |
| 183 | a few of the details seemed less and less a good fit. |
| 184 | This proposal adjusts those details in the hope of |
| 185 | shipping a system that is easier for developers to understand |
| 186 | and to use. |
| 187 | |
| 188 | ### Semantic versions, constraints, and solvers |
| 189 | |
| 190 | Semantic versions are a reasonable convention for |
| 191 | specifying software versions, |
| 192 | and version control tags written as semantic versions |
| 193 | have a clear meaning, |
| 194 | but the [semver spec](https://semver.org/) critically does not |
| 195 | prescribe how to build a system using them. |
| 196 | What tools should do with the version information? |
| 197 | Dave Cheney's 2015 [proposal to adopt semantic versioning](https://golang.org/issue/12302) |
| 198 | was eventually closed exactly because, even though everyone |
| 199 | agreed semantic versions seemed like a good idea, |
| 200 | we didn't know the answer to the question of what to do with them. |
| 201 | |
| 202 | The Bundler/Cargo/Dep approach is one answer. |
| 203 | Allow authors to specify arbitrary constraints on their dependencies. |
| 204 | Build a given target by collecting all its dependencies |
| 205 | recursively and finding a configuration satisfying all those |
| 206 | constraints. |
| 207 | |
| 208 | Unfortunately, the arbitrary constraints make finding a |
| 209 | satisfying configuration very difficult. |
| 210 | There may be many satisfying configurations, with no clear way to choose just one. |
| 211 | For example, if the only two ways to build A are by using B 1 and C 2 |
| 212 | or by using B 2 and C 1, which should be preferred, and how should developers remember? |
| 213 | Or there may be no satisfying configuration. |
| 214 | Also, it can be very difficult to tell whether there are many, one, or no |
| 215 | satisfying configurations: |
| 216 | allowing arbitrary constraints makes |
| 217 | version solving problem an NP-complete problem, |
| 218 | [equivalent to solving SAT](https://research.swtch.com/version-sat). |
| 219 | In fact, most package managers now rely on SAT solvers |
| 220 | to decide which packages to install. |
| 221 | But the general problem remains: |
| 222 | there may be many equally good configurations, |
| 223 | with no clear way to choose between them, |
| 224 | there may be a single best configuration, |
| 225 | or there may be no good configurations, |
| 226 | and it can be very expensive to determine |
| 227 | which is the case in a given build. |
| 228 | |
| 229 | This proposal's approach is a new answer, in which authors can specify |
| 230 | only limited constraints on dependencies: only the minimum required versions. |
| 231 | Like in Bundler/Cargo/Dep, this proposal builds a given target by |
| 232 | collecting all dependencies recursively and then finding |
| 233 | a configuration satisfying all constraints. |
| 234 | However, unlike in Bundler/Cargo/Dep, the process of finding a |
| 235 | satisfying configuration is trivial. |
| 236 | As explained in the [minimal version selection](https://research.swtch.com/vgo-mvs) post, |
| 237 | a satisfying configuration always exists, |
| 238 | and the set of satisfying configurations forms a lattice with |
| 239 | a unique minimum. |
| 240 | That unique minimum is the configuration that uses exactly the |
| 241 | specified version of each module, resolving multiple constraints |
| 242 | for a given module by selecting the maximum constraint, |
| 243 | or equivalently the minimum version that satisfies all constraints. |
| 244 | That configuration is trivial to compute and easy for developers |
| 245 | to understand and predict. |
| 246 | |
| 247 | ### Build Control |
| 248 | |
| 249 | A module's dependencies must clearly be given some control over that module's build. |
| 250 | For example, if A uses dependency B, which uses a feature of dependency C introduced in C 1.5, |
| 251 | B must be able to ensure that A's build uses C 1.5 or later. |
| 252 | |
| 253 | At the same time, for builds to remain predictable and understandable, |
| 254 | a build system cannot give dependencies arbitrary, fine-grained control |
| 255 | over the top-level build. |
| 256 | That leads to conflicts and surprises. |
| 257 | For example, suppose B declares that it requires an even version of D, while C declares that it requires a prime version of D. |
| 258 | D is frequently updated and is up to D 1.99. |
| 259 | Using B or C in isolation, it's always possible to use a relatively recent version of D (D 1.98 or D 1.97, respectively). |
| 260 | But when A uses both B and C, |
| 261 | a SAT solver-based build silently selects the much older (and buggier) D 1.2 instead. |
| 262 | To the extent that SAT solver-based build systems actually work, |
| 263 | it is because dependencies don't choose to exercise this level of control. |
| 264 | But then why allow them that control in the first place? |
| 265 | |
| 266 | Although the hypothetical about prime and even versions is clearly unlikely, |
| 267 | real problems do arise. |
| 268 | For example, issue [kubernetes/client-go#325](https://github.com/kubernetes/client-go/issues/325) was filed in November 2017, |
| 269 | complaining that the Kubernetes Go client pinned builds to a specific version of `gopkg.in/yaml.v2` from |
| 270 | September 2015, two years earlier. |
| 271 | When a developer tried to use |
| 272 | a new feature of that YAML library in a program that already |
| 273 | used the Kubernetes Go client, |
| 274 | even after attempting to upgrade to the latest possible version, |
| 275 | code using the new feature failed to compile, |
| 276 | because “latest” had been constrained by the Kubernetes requirement. |
| 277 | In this case, the use of a two-year-old YAML library version may be entirely reasonable within the context of the Kubernetes code base, |
| 278 | and clearly the Kubernetes authors should have complete |
| 279 | control over their own builds, |
| 280 | but that level of control does not make sense to extend to other developers' builds. |
| 281 | The issue was closed after a change in February 2018 |
| 282 | to update the specific YAML version pinned to one from July 2017. |
| 283 | But the issue is not really “fixed”: |
| 284 | Kubernetes still pins a specific, increasingly old version of the YAML library. |
| 285 | The fundamental problem is that the build system |
| 286 | allows the Kubernetes Go client to do this at all, |
| 287 | at least when used as a dependency in a larger build. |
| 288 | |
| 289 | This proposal aims to balance |
| 290 | allowing dependencies enough control to ensure a successful |
| 291 | build with not allowing them so much control that they break the build. |
| 292 | Minimum requirements combine without conflict, |
| 293 | so it is feasible (even easy) to gather them from all dependencies, |
| 294 | and they make it impossible to pin older versions, |
| 295 | as Kubernetes does. |
| 296 | Minimal version selection gives |
| 297 | the top-level module in the build additional control, |
| 298 | allowing it to exclude specific module versions |
| 299 | or replace others with different code, |
| 300 | but those exclusions and replacements only apply |
| 301 | when found in the top-level module, not when the module |
| 302 | is a dependency in a larger build. |
| 303 | |
| 304 | A module author is therefore in complete control of |
| 305 | that module's build when it is the main program being built, |
| 306 | but not in complete control of other users' builds that depend on the module. |
| 307 | I believe this distinction will make this proposal |
| 308 | scale to much larger, more distributed code bases than |
| 309 | the Bundler/Cargo/Dep approach. |
| 310 | |
| 311 | ### Ecosystem Fragmentation |
| 312 | |
| 313 | Allowing all modules involved in a build to impose arbitrary |
| 314 | constraints on the surrounding build harms not just that build |
| 315 | but the entire language ecosystem. |
| 316 | If the author of popular package P finds that |
| 317 | dependency D 1.5 has introduced a change that |
| 318 | makes P no longer work, |
| 319 | other systems encourage the author of P to issue |
| 320 | a new version that explicitly declares it needs D < 1.5. |
| 321 | Suppose also that popular package Q is eager to take |
| 322 | advantage of a new feature in D 1.5 |
| 323 | and issues a new version that explicitly declares it needs D ≥ 1.6. |
| 324 | Now the ecosystem is divided, and programs must choose sides: |
| 325 | are they P-using or Q-using? They cannot be both. |
| 326 | |
| 327 | In contrast, being allowed to specify only a minimum required version |
| 328 | for a dependency makes clear that P's author must either |
| 329 | (1) release a new, fixed version of P; |
| 330 | (2) contact D's author to issue a fixed D 1.6 and then release a new P declaring a requirement on D 1.6 or later; |
| 331 | or else (3) start using a fork of D 1.4 with a different import path. |
| 332 | Note the difference between a new P that requires “D before 1.5” |
| 333 | compared to “D 1.6 or later.” |
| 334 | Both avoid D 1.5, but “D before 1.5” explains only which builds fail, |
| 335 | while “D 1.6 or later” explains how to make a build succeed. |
| 336 | |
| 337 | ### Semantic Import Versions |
| 338 | |
| 339 | The example of ecosystem fragmentation in the previous section |
| 340 | is worse when it involves major versions. |
| 341 | Suppose the author of popular package P has used D 1.X as a dependency, |
| 342 | and then popular package Q decides to update to D 2.X because it |
| 343 | is a nicer API. |
| 344 | If we adopt Dep's semantics, |
| 345 | now the ecosystem is again divided, and programs must again choose sides: |
| 346 | are they P-using (D 1.X-using) or Q-using (D 2.X-using)? |
| 347 | They cannot be both. |
| 348 | Worse, |
| 349 | in this case, because D 1.X and D 2.X are different major versions |
| 350 | with different APIs, it is completely reasonable for the author of P |
| 351 | to continue to use D 1.X, which might even continue to be updated with |
| 352 | features and bug fixes. |
| 353 | That continued usage only prolongs the divide. |
| 354 | The end result is that |
| 355 | a widely-used package like D would in practice either |
| 356 | be practically prohibited from issue version 2 or |
| 357 | else split the ecosystem in half by doing so. |
| 358 | Neither outcome is desirable. |
| 359 | |
| 360 | Rust's Cargo makes a different choice from Dep. |
| 361 | Cargo allows each package to specify whether |
| 362 | a reference to D means D 1.X or D 2.X. |
| 363 | Then, if needed, Cargo links both a D 1.X and a D 2.X into the final binary. |
| 364 | This approach works better than Dep's, |
| 365 | but users can still get stuck. |
| 366 | If P exposes D 1.X in its own API and Q exposes D 2.X in its own API, |
| 367 | then a single client package C cannot use both P and Q, |
| 368 | because it will not be able to refer to both D 1.X (when using P) |
| 369 | and D 2.X (when using Q). |
| 370 | The [dependency story](https://research.swtch.com/vgo-import) in the semantic import versioning post |
| 371 | presents an equivalent scenario in more detail. |
| 372 | In that story, the base package manager starts out being like Dep, |
| 373 | and the `-fmultiverse` flag makes it more like Cargo. |
| 374 | |
| 375 | If Cargo is one step away from Dep, semantic import versioning is two steps away. |
| 376 | In addition to allowing different major versions to be used |
| 377 | in a single build, |
| 378 | semantic import versioning gives the different major versions different names, |
| 379 | so that there's never any ambiguity |
| 380 | about which is meant in a given program file. |
| 381 | Making the import paths precise about the expected |
| 382 | semantics of the thing being imported (is it v1 or v2?) |
| 383 | eliminates the possibility of problems like those client C experienced |
| 384 | in the previous example. |
| 385 | |
| 386 | More generally, in semantic import versioning, |
| 387 | an import of `my/thing` asks for the semantics of v1.X of `my/thing`. |
| 388 | As long as `my/thing` is following the import compatibility rule, |
| 389 | that's a well-defined set of functionality, |
| 390 | satisfied by the latest v1.X and possibly earlier ones |
| 391 | (as constrained by `go.mod`). |
| 392 | Similarly, an import of `my/thing/v2` asks for the semantics of v2.X of `my/thing`, |
| 393 | satisfied by the latest v2.X and possibly earlier ones |
| 394 | (again constrained by `go.mod`). |
| 395 | The meaning of the imports is clear, to both people and tools, |
| 396 | from reading only the Go source code, |
| 397 | without reference to `go.mod`. |
| 398 | If instead we followed the Cargo approach, both imports would be `my/thing`, and the |
| 399 | meaning of that import would be ambiguous from the source code alone, |
| 400 | resolved only by reading `go.mod`. |
| 401 | |
| 402 | Our article “[About the go command](https://golang.org/doc/articles/go_command.html)” explains: |
| 403 | |
| 404 | > An explicit goal for Go from the beginning was to be able to build Go code |
| 405 | > using only the information found in the source itself, not needing to write |
| 406 | > a makefile or one of the many modern replacements for makefiles. |
| 407 | > If Go needed a configuration file to explain how to build your program, |
| 408 | > then Go would have failed. |
| 409 | |
| 410 | It is an explicit goal of this proposal's design to preserve this property, |
| 411 | to avoid making the general semantics of a Go source file change depending on |
| 412 | the contents of `go.mod`. |
| 413 | With semantic import versioning, if `go.mod` is deleted and |
| 414 | recreated from scratch, the effect is only to possibly update |
| 415 | to newer versions of imported packages, but still ones that are |
| 416 | still expected to work, thanks to import compatibility. |
| 417 | In contrast, if we take the Cargo approach, in which the `go.mod` file |
| 418 | must disambiguate between the arbitrarily different semantics of |
| 419 | v1 and v2 of `my/thing`, then `go.mod` becomes a required configuration file, |
| 420 | violating the original goal. |
| 421 | |
| 422 | More generally, the main objection to adding `/v2/` to import paths is that |
| 423 | it's a bit longer, a bit ugly, and it makes explicit a semantically important |
| 424 | detail that other systems abstract away, which in turn induces more work for authors, |
| 425 | compared to other systems, when they change that detail. |
| 426 | But all of these were true when we introduced `goinstall`'s URL-like import paths, |
| 427 | and they've been a clear success. |
| 428 | Before `goinstall`, programmers wrote things like `import "igo/set"`. |
| 429 | To make that import work, you had to know to first check out `github.com/jacobsa/igo` into `$GOPATH/src/igo`. |
| 430 | The abbreviated paths had the benefit that if you preferred |
| 431 | a different version of `igo`, you could check your variant into |
| 432 | `$GOPATH/src/igo` instead, without updating any imports. |
| 433 | But the abbreviated imports also had the very real drawbacks that a build trying to use |
| 434 | both `igo/set` variants could not, and also that the Go source code did not record |
| 435 | anywhere exactly which `igo/set` it meant. |
| 436 | When `goinstall` introduced `import "github.com/jacobsa/igo/set"` instead, |
| 437 | that made the imports a bit longer and a bit ugly, |
| 438 | but it also made explicit a semantically important detail: |
| 439 | exactly which `igo/set` was meant. |
| 440 | The longer paths created a little more work for authors compared |
| 441 | to systems that stashed that information in a single configuration file. |
| 442 | But eight years later, no one notices the longer import paths, |
| 443 | we've stopped seeing them as ugly, |
| 444 | and we now rely on the benefits of being explicit about |
| 445 | exactly which package is meant by a given import. |
| 446 | I expect that once `/v2/` elements in import paths are |
| 447 | common in Go source files, the same will happen: |
| 448 | we will no longer notice the longer paths, |
| 449 | we will stop seeing them as ugly, and we will rely on the benefits of |
| 450 | being explicit about exactly which semantics are meant by a given import. |
| 451 | |
| 452 | ### Update Timing & High-Fidelity Builds |
| 453 | |
| 454 | In the Bundler/Cargo/Dep approach, the package manager always prefers |
| 455 | to use the latest version of any dependency. |
| 456 | These systems use the lock file to override that behavior, |
| 457 | holding the updates back. |
| 458 | But lock files only apply to whole-program builds, |
| 459 | not to newly imported libraries. |
| 460 | If you are working on module A, and you add a new requirement on module B, which in turn requires module C, |
| 461 | these systems will fetch the latest of B and then also the latest of C. |
| 462 | In contrast, this proposal still fetches the latest of B (because it is |
| 463 | what you are adding to the project explicitly, and the default is to |
| 464 | take the latest of explicit additions) but then prefers to use the |
| 465 | exact version of C that B requires. |
| 466 | Although newer versions of C should work, it is safest to |
| 467 | use the one that B did. |
| 468 | Of course, if the build has a different reason to use a newer version of C, it can do that. |
| 469 | For example, if A also imports D, which requires a newer C, then the build should and will use that newer version. |
| 470 | But in the absence of such an overriding requirement, |
| 471 | minimal version selection will build A using the exact version of C requested by B. |
| 472 | If, later, a new version of B is released requesting a newer version of C, |
| 473 | then when A updates to that newer B, |
| 474 | C will be updated only to the version that the new B requires, not farther. |
| 475 | The [minimal version selection](https://research.swtch.com/vgo-mvs) blog post |
| 476 | refers to this kind of build as a “high-fidelity build.” |
| 477 | |
| 478 | Minimal version selection has the key property that a recently-published version of C |
| 479 | is never used automatically. |
| 480 | It is only used when a developer asks for it explicitly. |
| 481 | For example, the developer of A could ask for all dependencies, including transitive dependencies, to be updated. |
| 482 | Or, less directly, the developer of B could update C and release a new B, |
| 483 | and then the developer of A could update B. |
| 484 | But either way, some developer working on some package in the build must |
| 485 | take an explicit action asking for C to be updated, |
| 486 | and then the update does not take effect in A's build until |
| 487 | a developer working on A updates some dependency leading to C. |
| 488 | Waiting until an update is requested ensures that updates only happen |
| 489 | when developers are ready to test them and deal with the possibility |
| 490 | of breakage. |
| 491 | |
| 492 | Many developers recoil at the idea that adding the latest B would not |
| 493 | automatically also add the latest C, |
| 494 | but if C was just released, there's no guarantee it works in this build. |
| 495 | The more conservative position is to avoid using it until the user asks. |
| 496 | For comparison, the Go 1.9 go command does not automatically start using Go 1.10 |
| 497 | the day Go 1.10 is released. |
| 498 | Instead, users are expected to update on their own |
| 499 | schedule, |
| 500 | so that they can control when they take on the risk of things breaking. |
| 501 | The reasons not to update automatically to the latest Go release |
| 502 | applies even more to individual packages: |
| 503 | there are more of them, |
| 504 | and most are not tested for backwards compatibility |
| 505 | as extensively as Go releases are. |
| 506 | |
| 507 | If a developer does want to update all dependencies to the latest version, |
| 508 | that's easy: `go get -u`. |
| 509 | We may also add a `go get -p` that updates all dependencies to their |
| 510 | latest patch versions, so that C 1.2.3 might be updated to C 1.2.5 but not to C 1.3.0. |
| 511 | If the Go community as a whole reserved patch versions only for very safe |
| 512 | or security-critical changes, then that `-p` behavior might be useful. |
| 513 | |
| 514 | ## Compatibility |
| 515 | |
| 516 | The work in this proposal is not constrained by |
| 517 | the [compatibility guidelines](https://golang.org/doc/go1compat) at all. |
| 518 | Those guidelines apply to the language and standard library APIs, not tooling. |
| 519 | Even so, compatibility more generally is a critical concern. |
| 520 | It would be a serious mistake to deploy changes to the `go` command |
| 521 | in a way that breaks all existing Go code or splits the ecosystem into |
| 522 | module-aware and non-module-aware packages. |
| 523 | On the contrary, we must make the transition as smooth and seamless as possible. |
| 524 | |
| 525 | Module-aware builds can import non-module-aware packages |
| 526 | (those outside a tree with a `go.mod` file) |
| 527 | provided they are tagged with a v0 or v1 semantic version. |
| 528 | They can also refer to any specific commit using a “pseudo-version” |
| 529 | of the form v0.0.0-*yyyymmddhhmmss*-*commit*. |
| 530 | The pseudo-version form allows referring to untagged commits |
| 531 | as well as commits that are tagged with semantic versions at v2 or above |
| 532 | but that do not follow the semantic import versioning convention. |
| 533 | |
| 534 | Module-aware builds can also consume requirement information |
| 535 | not just from `go.mod` files but also from all known pre-existing |
| 536 | version metadata files in the Go ecosystem: |
| 537 | `GLOCKFILE`, `Godeps/Godeps.json`, `Gopkg.lock`, `dependencies.tsv`, |
| 538 | `glide.lock`, `vendor.conf`, `vendor.yml`, `vendor/manifest`, |
| 539 | and `vendor/vendor.json`. |
| 540 | |
| 541 | Existing tools like `dep` should have no trouble consuming |
| 542 | Go modules, simply ignoring the `go.mod` file. |
| 543 | It may also be helpful to add support to `dep` to read `go.mod` files in |
| 544 | dependencies, so that `dep` users are unaffected as their |
| 545 | dependencies move from `dep` to the new module support. |
| 546 | |
| 547 | ## Implementation |
| 548 | |
| 549 | A prototype of the proposal is implemented in a fork of the `go` command called `vgo`, |
| 550 | available using `go get -u golang.org/x/vgo`. |
| 551 | We will refine this implementation during the Go 1.11 cycle and |
| 552 | merge it back into `cmd/go` in the main repository. |
| 553 | |
| 554 | The plan, subject to proposal approval, |
| 555 | is to release module support in Go 1.11 |
| 556 | as an optional feature that may still change. |
| 557 | The Go 1.11 release will give users a chance to use modules “for real” |
| 558 | and provide critical feedback. |
| 559 | Even though the details may change, future releases will |
| 560 | be able to consume Go 1.11-compatible source trees. |
| 561 | For example, Go 1.12 will understand how to consume |
| 562 | the Go 1.11 `go.mod` file syntax, even if by then the |
| 563 | file syntax or even the file name has changed. |
| 564 | In a later release (say, Go 1.12), we will declare the module support completed. |
| 565 | In a later release (say, Go 1.13), we will end support for `go` `get` of non-modules. |
| 566 | Support for working in GOPATH will continue indefinitely. |
| 567 | |
| 568 | ## Open issues (if applicable) |
| 569 | |
| 570 | We have not yet converted large, complex repositories to use modules. |
| 571 | We intend to work with the Kubernetes team and others (perhaps CoreOS, Docker) |
| 572 | to convert their use cases. |
| 573 | It is possible those conversions will turn up reasons for adjustments |
| 574 | to the proposal as described here. |
| 575 | |