Limit VS Code for Go to download packages only for v 1.11 - go

I am using Visual Studio Code version 1.33.1 as IDE for our Go applications. We would like to use Go version 1.11 for our applications. However looks like one or more of the dependencies we are using has downloaded a package for Go 1.12. Now, VS Code is failing to build the application with the following error:
go build golang.org/x/sys/unix: module requires Go 1.12 go build
github.com/pelletier/go-toml: module requires Go 1.12
go [1,1]
I tried re-installing Go 1.11, removed the offending packages and let it reinstall. No matter when I tried to build VS Code is downloading the 1.12 version fails to build.
I would like VS Code not to download 1.12 version of the packages and restrict it to 1.11 only.

Go 1.12 Release Notes (February 2019)
Modules
The go directive in a go.mod file now indicates the version of the
language used by the files within that module. It will be set to the
current release (go 1.12) if no existing version is present. If the go
directive for a module specifies a version newer than the toolchain in
use, the go command will attempt to build the packages regardless, and
will note the mismatch only if that build fails.
This changed use of the go directive means that if you use Go 1.12 to
build a module, thus recording go 1.12 in the go.mod file, you will
get an error when attempting to build the same module with Go 1.11
through Go 1.11.3. Go 1.11.4 or later will work fine, as will releases
older than Go 1.11. If you must use Go 1.11 through 1.11.3, you can
avoid the problem by setting the language version to 1.11, using the
Go 1.12 go tool, via go mod edit -go=1.11.
$ go help go.mod
The go.mod file itself is line-oriented, with // comments but
no /* */ comments. Each line holds a single directive, made up of a
verb followed by arguments. For example:
module my/thing
go 1.12
require other/thing v1.0.2
require new/thing/v2 v2.3.4
exclude old/thing v1.2.3
replace bad/thing v1.4.5 => good/thing v1.4.5
The verbs are
module, to define the module path;
go, to set the expected language version;
require, to require a particular module at a given version or later;
exclude, to exclude a particular module version from use; and
replace, to replace a module version with a different module version.
A possible solution to your problem was first introduced in Go1.12: the go.mod verb go, to set the expected language version.
UPDATE:
Comment: I tried using the suggested command: go mod edit -go=1.11 I
got an error: flag provided but not defined: -go I manually edited to
add go 1.11 right under my module declaration in all go.mod files, it
did not work. –
user2995358
Your results are expected. As I explained before and the documentation states, the go.mod verb go was first introduced in Go1.12.
For example, the expected results,
$ go version
go version go1.11.10 linux/amd64
$ go mod edit -go=1.11
flag provided but not defined: -go
usage: go mod edit [editing flags] [go.mod]
Run 'go help mod edit' for details.
$
$ go version
go version go1.12.5 linux/amd64
$ go mod edit -go=1.11
$
Read the documentation:
$ go version
go version go1.11.10 linux/amd64
$ go1.11 help modules
Preliminary module support
Go 1.11 includes preliminary support for Go modules,
including a new module-aware 'go get' command.
We intend to keep revising this support, while preserving compatibility,
until it can be declared official (no longer preliminary),
and then at a later point we may remove support for work
in GOPATH and the old 'go get' command.
$
$ go version
go version devel +004fb5cb8d Fri May 3 03:49:11 2019 +0000 linux/amd64
$ go help modules
Module support
Go 1.13 includes official support for Go modules,
including a module-aware 'go get' command.
Module-aware mode is active by default.
$
Go 1.11 includes only preliminary support for Go modules. Go 1.13 includes full official support for Go modules.
Why do you expect everything to work flawlessly in Go1.11 with only preliminary support?

Related

Should `go build` fail if version in `go.mod` is lower than actual?

I have go 1.15 specified in the go.mod file.
The current compiler version is the following:
➜ go version
go version go1.14.4 linux/amd64
Yet, go build still successfully builds a binary.
Is this an expected behaviour? Not sure I can find explanation in the modules description.
Yes, this is an expected behaviour.
The go.mod is more of a tool for dependencies and package management than a tool for managing the output of the build process. That's why, if you're not using any features from 1.15, it should still be able to be built.
The funny part is that if you try to build a project set to a version higher than the one that you're using (i.e. 1.15 built with go tool 1.14) and you mark in your go.mod that it needs to use the higher version, it'll show up in the build process:
# temp/test-go-build
./main.go:10:15: o.Redacted undefined (type url.URL has no field or method Redacted)
note: module requires Go 1.15
So the go tool tries it's best to fit your needs but won't block you from getting where you want to go (get it?).

Pin version with go get

I 'd like to pin the version of one package, so whenever I run
go get -u ./...
..this package would stay unchanged (but the rest refreshed normally).
Use go modules. It was specifically designed to handle precise version control.
In your package's go.mod you can pin any dependencies to a fixed version e.g.
module example.com/hello
go 1.12
require (
golang.org/x/text v0.3.0 // indirect
rsc.io/quote v1.5.2
rsc.io/quote/v3 v3.0.0
rsc.io/sampler v1.3.1 // indirect
)
You can update individual package versions e.g.:
go get rsc.io/quote/v3#master
Will pull the latest commit version (beyond even any semver tagged version).
You can also hand edit go.mod for extra precision.
P.S. you need go version 1.11 or later for go modules. go 1.13 has modules turned on by default. Earlier versions you have to explicitly enable it via the env var GO111MODULE=ON.

Why listing go modules dependencies fail when the module is in my GOPATH?

I am using this project https://github.com/sttts/beerdb. When I clone in into /tmp/, if I run:
go list -m all
I get a list of all the dependencies. If the same project is in my
$GOPATH/src/github.com/stts/beerdb, and then I run the same command I get:
go list -m: not using modules
If in both cases I am in the path where go.mod and go.sum are present, why I get a different behaviour? My go version is go1.12
Go 1.12 only has preliminary support for modules (introduces in Go 1.11). GOPATH is the default mode, but when GO111MODULE env var is set to on, the go command now supports module-aware operations outside of a module directory. For details, see Go 1.12 Release notes: Modules.
Recommended to switch to Go 1.13 which added full module support. In Go 1.13 module-aware mode is active by default whenever a go.mod file is found in, or in a parent of, the current directory.

`go install` adds record in `go.mod`

I'm a bit confused about how Go modules work on installing binaries using go install.
I tried to install (https://github.com/joho/godotenv) binary by executing go install github.com/joho/godotenv/cmd/godotenv and I found out that it adds a record in the go.mod.
I'm lost as we don't use this package in the code and after running go mod tidy it gets deleted (as it is not it the code).
Can someone explain is it expected behaviour of go modules?
Secondly, how I could avoid adding it to the go.mod as we only need to install and execute the binary?
Thanks.
Go version: go version go1.13.4 darwin/amd64
Command go: The go.mod file:
The go command automatically updates go.mod each time it uses the module graph, to make sure go.mod always accurately reflects reality and is properly formatted.
The go tool will update go.mod automatically when it detects dependencies are inaccurate when performing a build.
When you install github.com/joho/godotenv/cmd/godotenv from your module, this install requires at least the package in question being built / installed (and also its dependencies, transitively).
You may safely run go mod tidy to undo the recording of this "one-time" dependency.
In general if you want to disallow the go tool to update the go.mod file, you may use the -mod=readonly flag, but that would fail go install ("can't load package: package xxx: import lookup disabled by -mod=readonly"). You can read more about this here: Go Wiki: Go modules: Can I control when go.mod gets updated and when the go tools use the network to satisfy dependencies?
Alternatively, if you want to avoid this, build / install your tools outside of your module. You may use a "dummy" module for this.

How do I import a specific version of a package using go get?

coming from a Node environment I used to install a specific version of a vendor lib into the project folder (node_modules) by telling npm to install that version of that lib from the package.json or even directly from the console, like so:
$ npm install express#4.0.0
Then I used to import that version of that package in my project just with:
var express = require('express');
Now, I want to do the same thing with go. How can I do that?
Is it possible to install a specific version of a package? If so, using a centralized $GOPATH, how can I import one version instead of another?
I would do something like this:
$ go get github.com/wilk/uuid#0.0.1
$ go get github.com/wilk/uuid#0.0.2
But then, how can I make a difference during the import?
Go 1.11 will have a feature called go modules and you can simply add a dependency with a version. Follow these steps:
go mod init .
go mod edit -require github.com/wilk/uuid#0.0.1
go get -v -t ./...
go build
go install
Here's more info on that topic - https://github.com/golang/go/wiki/Modules
Really surprised nobody has mentioned gopkg.in.
gopkg.in is a service that provides a wrapper (redirect) that lets you express versions as repo urls, without actually creating repos. E.g. gopkg.in/yaml.v1 vs gopkg.in/yaml.v2, even though they both live at https://github.com/go-yaml/yaml
gopkg.in/yaml.v1 redirects to https://github.com/go-yaml/yaml/tree/v1
gopkg.in/yaml.v2 redirects to https://github.com/go-yaml/yaml/tree/v2
This isn't perfect if the author is not following proper versioning practices (by incrementing the version number when breaking backwards compatibility), but it does work with branches and tags.
A little cheat sheet on module queries.
To check all existing versions: e.g. go list -m -versions github.com/gorilla/mux
Specific version #v1.2.8
Specific commit #c783230
Specific branch #master
Version prefix #v2
Comparison #>=2.1.5
Latest #latest
E.g. go get github.com/gorilla/mux#v1.7.4
You can use git checkout to get an specific version and build your program using this version.
Example:
export GOPATH=~/
go get github.com/whateveruser/whateverrepo
cd ~/src/github.com/whateveruser/whateverrepo
git tag -l
# supose tag v0.0.2 is correct version
git checkout tags/v0.0.2
go run whateverpackage/main.go
Glide is a really elegant package management for Go especially if you come from Node's npm or Rust's cargo.
It behaves closely to Godep's new vendor feature in 1.6 but is way more easier. Your dependencies and versions are "locked" inside your projectdir/vendor directory without relying on GOPATH.
Install with brew (OS X)
$ brew install glide
Init the glide.yaml file (akin to package.json). This also grabs the existing imported packages in your project from GOPATH and copy then to the project's vendor/ directory.
$ glide init
Get new packages
$ glide get vcs/namespace/package
Update and lock the packages' versions. This creates glide.lock file in your project directory to lock the versions.
$ glide up
I tried glide and been happily using it for my current project.
Nowadays you can just use go get for it. You can fetch your dependency by the version tag, branch or even the commit.
go get github.com/someone/some_module#master
go get github.com/someone/some_module#v1.1.0
go get github.com/someone/some_module#commit_hash
more details here - How to point Go module dependency in go.mod to a latest commit in a repo?
Go get will also install the binary, like it says in the documentation -
Get downloads the packages named by the import paths, along with their dependencies. It then installs the named packages, like 'go install'.
(from https://golang.org/cmd/go/)
Update 18-11-23: From Go 1.11 mod is official experiment. Please see #krish answer.
Update 19-01-01: From Go 1.12 mod is still official experiment.
Starting in Go 1.13, module mode will be the default for all development.
Update 19-10-17: From Go 1.13 mod is official package manager.
https://blog.golang.org/using-go-modules
Old answer:
You can set version by offical dep
dep ensure --add github.com/gorilla/websocket#1.2.0
From Go 1.5 there's the "vendor experiment" that helps you manage dependencies. As of Go 1.6 this is no longer an experiment. Theres also some other options on the Go wiki..
Edit: as mentioned in this answer gopkg.in is a good option for pinning github-depdencies pre-1.5.
dep is the official experiment for dependency management for Go language. It requires Go 1.8 or newer to compile.
To start managing dependencies using dep, run the following command from your project's root directory:
dep init
After execution two files will be generated: Gopkg.toml ("manifest"), Gopkg.lock and necessary packages will be downloaded into vendor directory.
Let's assume that you have the project which uses github.com/gorilla/websocket package. dep will generate following files:
Gopkg.toml
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
name = "github.com/gorilla/websocket"
version = "1.2.0"
Gopkg.lock
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/gorilla/websocket"
packages = ["."]
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "941e8dbe52e16e8a7dff4068b7ba53ae69a5748b29fbf2bcb5df3a063ac52261"
solver-name = "gps-cdcl"
solver-version = 1
There are commands which help you to update/delete/etc packages, please find more info on official github repo of dep (dependency management tool for Go).
go get is the Go package manager. It works in a completely decentralized way and how package discovery still possible without a central package hosting repository.
Besides locating and downloading packages, the other big role of a package manager is handling multiple versions of the same package. Go takes the most minimal and pragmatic approach of any package manager. There is no such thing as multiple versions of a Go package.
go get always pulls from the HEAD of the default branch in the repository. Always. This has two important implications:
As a package author, you must adhere to the stable HEAD philosophy. Your default branch must always be the stable, released version of your package. You must do work in feature branches and only merge when ready to release.
New major versions of your package must have their own repository. Put simply, each major version of your package (following semantic versioning) would have its own repository and thus its own import path.
e.g. github.com/jpoehls/gophermail-v1 and github.com/jpoehls/gophermail-v2.
As someone building an application in Go, the above philosophy really doesn't have a downside. Every import path is a stable API. There are no version numbers to worry about. Awesome!
For more details : http://zduck.com/2014/go-and-package-versioning/
The approach I've found workable is git's submodule system. Using that you can submodule in a given version of the code and upgrading/downgrading is explicit and recorded - never haphazard.
The folder structure I've taken with this is:
+ myproject
++ src
+++ myproject
+++ github.com
++++ submoduled_project of some kind.
That worked for me
GO111MODULE=on go get -u github.com/segmentio/aws-okta#v0.22.1
There's a go edit -replace command to append a specific commit (even from another forked repository) on top of the current version of a package.
What's cool about this option, is that you don't need to know the exact pseudo version beforehand, just the commit hash id.
For example, I'm using the stable version of package "github.com/onsi/ginkgo v1.8.0".
Now I want - without modifying this line of required package in go.mod - to append a patch from my fork, on top of the ginkgo version:
$ GO111MODULE="on" go mod edit -replace=github.com/onsi/ginkgo=github.com/manosnoam/ginkgo#d6423c2
After the first time you build or test your module, GO will try to pull the new version, and then generate the "replace" line with the correct pseudo version. For example in my case, it will add on the bottom of go.mod:
replace github.com/onsi/ginkgo => github.com/manosnoam/ginkgo v0.0.0-20190902135631-1995eead7451
It might be useful.
Just type this into your command prompt while cd your/package/src/
go get github.com/go-gl/mathgl#v1.0.0
You get specific revision of package in question right into your source code, ready to use in import statement.
The current way to do this is to use go install
https://golang.org/doc/go-get-install-deprecation
Starting in Go 1.17, installing executables with go get is deprecated. go install may be used instead.
go install github.com/someone/some_module
Specific version
go install github.com/someone/some_module#v1.1.0
Specific commit
go install github.com/someone/some_module#commit_hash

Resources