This is a creation in Article, where the information may have evolved or changed.
This article is translated from the 2nd part of a tour of versioned Go (vgo), Go & Versioning, Copyright @ the original.
For me, design means building, dismantling and building again, over and over again.
To write a new version control proposal, I built a prototype vgo to handle a lot of subtle details. This blog post shows how to use it vgo .
You can now go get golang.org/x/vgo download and try by running vgo . Vgo is go a direct replacement of the command (and branch copy).
You run vgo instead go , it will use $GOROOT the compilers and standard libraries that you installed (Go 1.10 beta1 or later).
As we learn more about what works and what doesn't, vgo the semantics and command-line details can change.
However, we intend to avoid backward incompatible changes to the go.mod file format so that the items that are added today go.mod can also work later. As we refine our proposals, we will update them accordingly vgo .
Example
This section shows how to use it vgo . Follow the steps to experiment.
Starting from installation vgo :
$ go get -u golang.org/x/vgo
You're going to have fun bug , because there vgo are only a few tests now. Use go issue tracking to bug escalate, with the title beginning with "X/vgo". Thank you.
Hello, World
Let's write an interesting "Hello, World" program. GOPATH/srcCreate a directory outside the directory and switch to it:
$ cd $HOME$ mkdir hello$ cd hello
Then create a hello.go :
package main // import "github.com/you/hello"import ( "fmt" "rsc.io/quote")func main() { fmt.Println(quote.Hello())}
or download it:
$ curl -sS https://swtch.com/hello.go >hello.go
Create an empty go.mod file to mark the root of this module, and then build and run the new program:
$ echo >go.mod$ vgo buildvgo: resolving import "rsc.io/quote"vgo: finding rsc.io/quote (latest)vgo: adding rsc.io/quote v1.5.2vgo: finding rsc.io/quote v1.5.2vgo: finding rsc.io/sampler v1.3.0vgo: finding golang.org/x/text v0.0.0-20170915032832-14c0d48ead0cvgo: downloading rsc.io/quote v1.5.2vgo: downloading rsc.io/sampler v1.3.0vgo: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c$ ./helloHello, world.$
Note that there is no explicit need to run vgo get . Normal vgo build will look for the module that contains it when an unknown import is encountered and add the latest version of the module as a dependency to the current module.
vgoa side effect of running any command is updated if necessary go.mod . In this case, a vgo build new file is written go.mod :
$ cat go.modmodule "github.com/you/hello"require "rsc.io/quote" v1.5.2$
Because go.mod it has been written, the next time vgo build it will not parse as many imports or prints again:
$ vgo build$ ./helloHello, world.$
Even if it is released tomorrow rsc.io/quote v1.5.3 or v1.6.0 , the build in that directory will continue to be used v1.5.2 unless an explicit upgrade is made (see below).
go.modThe file lists the minimum set of dependencies, ignoring what is implied in the enumeration.
In this case, rsc.io/quote v1.5.2 depending on the specific version of the rsc.io/sampler and golang.org/x/text , so in the go.mod repeating enumeration they are redundant.
vgo list -myou can still find the complete set of modules needed for the build:
$ vgo list -mMODULE VERSIONgithub.com/you/hello -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0crsc.io/quote v1.5.2rsc.io/sampler v1.3.0$
At this point you may wonder why our simple "Hello World" program will be used golang.org/x/text .
In rsc.io/quote fact rsc.io/sampler , the latter relies on golang.org/x/text the language matching.
$ LANG=fr ./helloBonjour le monde.$
Upgrade
As we have seen, the vgo latest modules are used when new modules must be added to the build to resolve the new import.
Previously, it was needed and rsc.io/quote found to be up to v1.5.2 date. But in addition to parsing the new import, vgo only go.mod the versions listed in the file are used.
In our case, it is rsc.io/quote indirectly dependent on golang.org/x/text rsc.io/sampler the specific version.
It turns out that both packages have newer versions, as we've vgo list -u seen through (checking for newer packages):
$ vgo list -m -uMODULE VERSION LATESTgithub.com/you/hello - -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c v0.0.0-20180208041248-4e4a3210bb54rsc.io/quote v1.5.2 (2018-02-14 10:44) -rsc.io/sampler v1.3.0 (2018-02-13 14:05) v1.99.99 (2018-02-13 17:20)$
Both packages have newer versions, so we might want to hello upgrade them in our program.
Upgrade First golang.org/x/text :
$ vgo get golang.org/x/textvgo: finding golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54vgo: downloading golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54$ cat go.modmodule "github.com/you/hello"require ( "golang.org/x/text" v0.0.0-20180208041248-4e4a3210bb54 "rsc.io/quote" v1.5.2)$
vgo getThe command will look up the latest version of the given module and go.mod add that version as a dependency of the current module with the update.
From now on, future builds will use newer text modules:
$ vgo list -mMODULE VERSIONgithub.com/you/hello -golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54rsc.io/quote v1.5.2rsc.io/sampler v1.3.0$
Of course, after the upgrade, testing everything still works well is a good idea.
Our dependencies are rsc.io/quote rsc.io/sampler not tested with newer text modules. We can run their tests in the configuration we created:
$ vgo test all? github.com/you/hello [no test files]? golang.org/x/text/internal/gen [no test files]ok golang.org/x/text/internal/tag 0.020s? golang.org/x/text/internal/testtext [no test files]ok golang.org/x/text/internal/ucd 0.020sok golang.org/x/text/language 0.068sok golang.org/x/text/unicode/cldr 0.063sok rsc.io/quote 0.015sok rsc.io/sampler 0.016s$
In the original go command, the package pattern all means GOPATH all packages that can be found in the. It's almost always too much to be useless.
In vgo , we have all reduced the meaning to "all packages in the current module, and the packages that they are imported recursively." rsc.io/quote the version of the module 1.5.2 contains a buggy package:
$ vgo test rsc.io/quote/...ok rsc.io/quote (cached)--- FAIL: Test (0.00s) buggy_test.go:10: buggy!FAILFAIL rsc.io/quote/buggy 0.014s(exit status 1)$
However, unless a package in our module is imported buggy , it is irrelevant, so it is not included all . Anyway, the upgrade x/text looks like it can work. At this point we can probably submit go.mod .
Another option is to use vgo get -u all the modules required to build the upgrade:
$ vgo get -uvgo: finding golang.org/x/text latestvgo: finding rsc.io/quote latestvgo: finding rsc.io/sampler latestvgo: finding rsc.io/sampler v1.99.99vgo: finding golang.org/x/text latestvgo: downloading rsc.io/sampler v1.99.99$ cat go.modmodule "github.com/you/hello"require ( "golang.org/x/text" v0.0.0-20180208041248-4e4a3210bb54 "rsc.io/quote" v1.5.2 "rsc.io/sampler" v1.99.99)$
Here, the vgo get -u upgraded module is retained text and will be rsc.io/sampler upgraded to its latest version v1.99.99 .
Let's run the test:
$ vgo test all? github.com/you/hello [no test files]? golang.org/x/text/internal/gen [no test files]ok golang.org/x/text/internal/tag (cached)? golang.org/x/text/internal/testtext [no test files]ok golang.org/x/text/internal/ucd (cached)ok golang.org/x/text/language 0.070sok golang.org/x/text/unicode/cldr (cached)--- FAIL: TestHello (0.00s) quote_test.go:19: Hello() = "99 bottles of beer on the wall, 99 bottles of beer, ...", want "Hello, world."FAILFAIL rsc.io/quote 0.014s--- FAIL: TestHello (0.00s) hello_test.go:31: Hello([en-US fr]) = "99 bottles of beer on the wall, 99 bottles of beer, ...", want "Hello, world." hello_test.go:31: Hello([fr en-US]) = "99 bottles of beer on the wall, 99 bottles of beer, ...", want "Bonjour le monde."FAILFAIL rsc.io/sampler 0.014s(exit status 1)$
Looks like something rsc.io/sampler v1.99.99 's wrong. Sure enough:
$ vgo build$ ./hello99 bottles of beer on the wall, 99 bottles of beer, ...$
vgo get -uThe behavior of getting the latest version of each dependency is the go get same as downloading all the packages that are not present GOPATH . On a system that is GOPATH empty:
$ go get -d rsc.io/hello$ go build -o badhello rsc.io/hello$ ./badhello99 bottles of beer on the wall, 99 bottles of beer, ...$
The important difference is that, by default, vgo it does not run in this way. You can also undo it by downgrading it.
Downgrade
To downgrade a package, use vgo list -t the show available tags (tag) version:
$ vgo list -t rsc.io/samplerrsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99$
Then use vgo the specific version that gets the requirement, for example v1.3.1 :
$ cat Go.modmodule "Github.com/you/hello" Require ("Golang.org/x/text" v0.0.0-20180208041248-4e4a3210bb54 "Rsc.io/qu Ote "v1.5.2" Rsc.io/sampler "v1.99.99) $ vgo get rsc.io/[email protected]vgo:finding Rsc.io/sampler V1.3.1vgo:dow Nloading rsc.io/sampler v1.3.1$ vgo list-mmodule versiongithub.com/you/hello-golang.org/x/text v0.0. 0-20180208041248-4e4a3210bb54rsc.io/quote V1.5.2rsc.io/sampler v1.3.1$ cat go.modmodule "github.com/you/he Llo "Require (" Golang.org/x/text "v0.0.0-20180208041248-4e4a3210bb54" Rsc.io/quote "v1.5.2" Rsc.io/sampler "v1.3. 1) $ vgo test all? Github.com/you/hello [no test files]? Golang.org/x/text/internal/gen [No Test Files]ok golang.org/x/text/internal/tag (cached)? Golang.org/x/text/internal/testtext [No Test Files]ok GOLANG.ORG/X/TEXT/INTERNAL/UCD (cached) OK golang.org/x/te Xt/language (cached) OK Golang.org/x/text/unicode/cldr (cached) OK Rsc.io/quote 0.016sok Rsc.io/sampler 0.015s$
Downgrading a package may require downgrading other packages. For example:
$ vgo get rsc.io/[email protected]vgo: finding rsc.io/sampler v1.2.0vgo: finding rsc.io/quote v1.5.1vgo: finding rsc.io/quote v1.5.0vgo: finding rsc.io/quote v1.4.0vgo: finding rsc.io/sampler v1.0.0vgo: downloading rsc.io/sampler v1.2.0$ vgo list -mMODULE VERSIONgithub.com/you/hello -golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54rsc.io/quote v1.4.0rsc.io/sampler v1.2.0$ cat go.modmodule "github.com/you/hello"require ( "golang.org/x/text" v0.0.0-20180208041248-4e4a3210bb54 "rsc.io/quote" v1.4.0 "rsc.io/sampler" v1.2.0)$
In this case, rsc.io/quote v1.5.0 it is the first required rsc.io/sampler v1.3.0 version; the earlier version only needs v1.0.0 (or later).
Downgrade selected rsc.io/quote v1.4.0 , this is the v1.2.0 latest version compatible with.
It is also possible to none completely remove a dependency by specifying as a version, which is an extreme form of demotion:
$ vgo get rsc.io/[email protected]vgo: downloading rsc.io/quote v1.4.0vgo: finding rsc.io/quote v1.3.0$ vgo list -mMODULE VERSIONgithub.com/you/hello -golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54rsc.io/quote v1.3.0$ cat go.modmodule "github.com/you/hello"require ( "golang.org/x/text" v0.0.0-20180208041248-4e4a3210bb54 "rsc.io/quote" v1.3.0)$ vgo test allvgo: downloading rsc.io/quote v1.3.0? github.com/you/hello [no test files]ok rsc.io/quote 0.014s$
Let's go back to everything is the latest version of the state, including rsc.io/sampler v1.99.99 :
$ vgo get -uvgo: finding golang.org/x/text latestvgo: finding rsc.io/quote latestvgo: finding rsc.io/sampler latestvgo: finding golang.org/x/text latest$ vgo list -mMODULE VERSIONgithub.com/you/hello -golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54rsc.io/quote v1.5.2rsc.io/sampler v1.99.99$
Exclude (excluding)
After determining that the v1.99.99 procedure does not apply to us hello world , we may want to record this fact to avoid future problems.
We can go.mod exclude do this by adding instructions to:
exclude "rsc.io/sampler" v1.99.99
The subsequent operation behaves as if the module does not exist:
$ echo ' Exclude ' Rsc.io/sampler "v1.99.99 ' >>go.mod$ vgo list-t rsc.io/samplerrsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99 # excluded$ vgo get-uvgo:finding golang.org/x/text latestvgo:finding rsc.io/quo Te latestvgo:finding rsc.io/sampler latestvgo:finding rsc.io/sampler latestvgo:finding golang.org/x/text latest$ vgo li St-mmodule Versiongithub.com/you/hello-golang.org/x/text V0.0.0-20180208041248-4e4a3210bb54rsc.io/qu OTE V1.5.2rsc.io/sampler v1.3.1$ cat go.modmodule "Github.com/you/hello" Require ("Golang.org/x/text" V 0.0.0-20180208041248-4e4a3210bb54 "Rsc.io/quote" v1.5.2 "Rsc.io/sampler" v1.3.1) exclude "Rsc.io/sampler" v1.99.99$ V Go Test all? Github.com/you/hello [no test files]? Golang.org/x/text/internal/gen [No Test Files]ok golang.org/x/text/internal/tag (cached)? Golang.org/x/text/internal/testtext [No Test Files]ok GOLANG.ORG/X/TEXT/INTERNAL/UCD (cached)OK golang.org/x/text/language (cached) OK Golang.org/x/text/unicode/cldr (cached) OK Rsc.io/quote (cache D) ok Rsc.io/sampler (cached) $
Exclusions apply only to the build of the current module. Exclusions are not applicable if the current module is dependent on a larger build.
For example, the rsc.io/quote go.mod exclusions in are not applicable to our "Hello, world" build.
The tradeoff of this strategy allows the authors of the current module to have almost arbitrary control over their own builds without the effect of almost arbitrary control of the modules they rely on.
At this point, the correct next step is to contact rsc.io/sampler the author and v1.99.99 report the problem in, so it can be v1.99.100 fixed in. Unfortunately, the author has a blog post that relies on it and does not fix it.
Replace (replacing)
If you do find a problem in dependencies, you need a way to temporarily replace it with an appropriate copy. Suppose we want to change something about rsc.io/quote the behavior.
Maybe we want to solve rsc.io/sampler the problem, or we want to do something else. The first step is to check out the module using the usual git commands quote :
$ git clone https://github.com/rsc/quote ../quoteCloning into '../quote'...
Then edit ../quote/quote.go to change func Hello some of the content. For example, I changed its return value from change sampler.Hello() sampler.Glass() to, which is a more interesting greeting.
$ cd ../quote$ <edit quote.go>$
After changing the clone code, we can go.mod replace use it instead of a real build by adding instructions to our Build:
replace "rsc.io/quote" v1.5.2 => "../quote"
Then we can use it to build our program:
$ cd ../hello$ echo 'replace "rsc.io/quote" v1.5.2 => "../quote"' >>go.mod$ vgo list -mMODULE VERSIONgithub.com/you/hello -golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54rsc.io/quote v1.5.2 => ../quotersc.io/sampler v1.3.1$ vgo build$ ./helloI can eat glass and it doesn't hurt me.$
You can also name a different module as the replacement module. For example, you can clone github.com/rsc/quote and then push the changes to your own branch.
$ cd ../quote$ git commit -a -m 'my fork'[master 6151719] my fork 1 file changed, 1 insertion(+), 1 deletion(-)$ git tag v0.0.0-myfork$ git push https://github.com/you/quote v0.0.0-myforkTo https://github.com/you/quote * [new tag] v0.0.0-myfork -> v0.0.0-myfork$
Then you can use it as a replacement:
$ cd ../hello$ echo 'replace "rsc.io/quote" v1.5.2 => "github.com/you/quote" v0.0.0-myfork' >>go.mod$ vgo list -mvgo: finding github.com/you/quote v0.0.0-myforkMODULE VERSIONgithub.com/you/hello -golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54rsc.io/quote v1.5.2 => github.com/you/quote v0.0.0-myforkrsc.io/sampler v1.3.1$ vgo buildvgo: downloading github.com/you/quote v0.0.0-myfork$ LANG=fr ./helloJe peux manger du verre, ça ne me fait pas mal.$
Backwards compatibility
Even if you want to use it for your project vgo , you will not be able to ask all of your users to have it vgo .
Instead, you can create a vendor directory to allow go the command user to generate almost the same build (of course, GOPATH compile in):
$ vgo vendor$ mkdir -p $GOPATH/src/github.com/you$ cp -a . $GOPATH/src/github.com/you/hello$ go build -o vhello github.com/you/hello$ LANG=es ./vhelloPuedo comer vidrio, no me hace daño.$
I say these builds are "almost the same", because the tool chain sees different import paths that are recorded in the final binary file. vendoredversion See vendor Table of Contents:
$ go tool nm hello | grep sampler.hello 1170908 B rsc.io/sampler.hello$ go tool nm vhello | grep sampler.hello 11718e8 B github.com/you/hello/vendor/rsc.io/sampler.hello$
In addition to this difference, the build should produce the same binary files. In order to provide graceful conversions, the build-based vgo architecture ignores the vendor directory completely, as always, the module-aware go command is built.
Next?
Please try vgo . The start tag (tagging) version in the Repository. Create and check in a (check in) go.mod file. golang.org/issue escalate the issue and add "X/vgo:" At the beginning of the title to have more posts tomorrow. Thank you, have fun!