Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/go: allow versioned go build commands #44469

Open
hyangah opened this issue Feb 20, 2021 · 18 comments
Open

cmd/go: allow versioned go build commands #44469

hyangah opened this issue Feb 20, 2021 · 18 comments

Comments

@hyangah
Copy link
Contributor

@hyangah hyangah commented Feb 20, 2021

Alternative: allow to change the installed main package name in go install command

Since go1.16, go install accepts arguments with version suffixes. go install places the output in $GOPATH/bin or $GOBIN, but does not allow the output binary's name change.

When a user wants to use multiple versions of tools, the user need to be careful not to overwrite other versions.

Different versions may be coming from different module paths.
e.g. VS Code Go extension uses two different versions of gocode (stamblerre/gocode and mdempsky/gocode). In order to install the former, it does switching GOBIN to use a temporary directory, installing it, and renaming and copying it to the real GOBIN.

Alternative: There are other proposals for applying the same to go run (#42088) and go list(#44203). Extending go build in the same way (or extending go install) will help simplifying the tool installation workflow.

cc @jayconrod @bcmills @matloob

@mvdan
Copy link
Member

@mvdan mvdan commented Feb 21, 2021

On #44203, @jayconrod said:

Though I think we should talk about allowing @version on all commands that take packages (where it makes sense; not go generate).

If the plan is indeed to support versioned variants of multiple commands, perhaps we should use a single issue for all of them at once instead of one per command.

@bcmills
Copy link
Member

@bcmills bcmills commented Feb 22, 2021

Alternative: allow to change the installed main package name in go install command

I think we should definitely do that, regardless of whether we add @version support for go build. go install ought to support the same -o flag as go build and go test -c.

Can we make this issue about that, and discuss generalizing @version support in a separate issue?

@hyangah
Copy link
Contributor Author

@hyangah hyangah commented Feb 23, 2021

Assuming the scope of #44203 is not limited to go list but all applicable commands including go build, I am fine with repurposing this issue to discuss the possibility of adding -o to go install.

What will be the expected behavior of -o? For my use case, I hope to see

go install -o gopls-master golang.org/x/tools/gopls@master

which installs the output in $GOBIN/gopls-master (or $GOBIN\gopls-master.exe).
That can be achievable with go build -o "$(go env GOBIN)/gopls-master" golang.org/x/tools/gopls@master in some platforms if go build has version support, but still not as convenient as the above command.

@bcmills
Copy link
Member

@bcmills bcmills commented Feb 23, 2021

I would expect -o to mean exactly the same thing for go install that it means for go build. So you would still need the command to be something like:

$ go install -o $(go env GOBIN)/gopls-master golang.org/x/tools/gopls@master

Although honestly, in my own use I would probably spell that as:

$ go install -o ~/bin/gopls-master golang.org/x/tools/gopls@master

@mvdan
Copy link
Member

@mvdan mvdan commented Feb 23, 2021

go install -o $(go env GOBIN)/gopls-master

The downside of that is that it depends on POSIX Shell syntax, so it wouldn't be portable to e.g. Windows. I see little benefit of go install having a -o flag if one can use go build in exactly the same way, to be honest.

I do see the point in flags being consistent between commands, but the whole point of go install is to put the binary in GOBIN, hence the flag could be more of a "rename the binary when installing it". That could always be a separate flag, though.

@bcmills
Copy link
Member

@bcmills bcmills commented Feb 23, 2021

If there were such a flag, I would not want to name it -o. GOFLAGS=-o=a.out should mean the same thing whether it is applying to go build or go install.

@mvdan
Copy link
Member

@mvdan mvdan commented Feb 23, 2021

Maybe. The flip side of the coin is that go install -o would make little sense, since go build -o would be much clearer :)

@hyangah
Copy link
Contributor Author

@hyangah hyangah commented Feb 23, 2021

go build -o foo leaves the output foo in the current directory if foo doesn't include the directory path.
Is it too different if go install -o foo installs the main package as foo in the default install directory?

@bcmills
Copy link
Member

@bcmills bcmills commented Feb 24, 2021

Is it too different if go install -o foo installs the main package as foo in the default install directory?

IMO yes, but I'd like to see what others think. 😅

@jayconrod
Copy link
Contributor

@jayconrod jayconrod commented Feb 24, 2021

I think if go install gets an -o flag, it would be confusing if it didn't do the same thing as go build. If it only changes the file name, it should be called something else. I think it would be better to just have -o though.

Agree that it's redundant with go build -o if go build gets an @version form though (which I think is a good idea).

@hyangah
Copy link
Contributor Author

@hyangah hyangah commented Feb 24, 2021

Currently we are using the sequence of

cd $(mktemp -d)
go mod init something
go get -d <tool>
go build -o <destination> <tool>
and cleanup... 

go build -o <destination> tool@version will definitely help us, but still computing <destination> for all platforms needs a bit of work. (checking GOBIN, GOPATH, and adding the right file extension, ...)

@jayconrod
Copy link
Contributor

@jayconrod jayconrod commented Feb 24, 2021

If it helps, <destination> can be a directory. The executable will be named after the package in that case, but it will have the .exe on Windows at least.

When you say "for all platforms", are you cross-compiling? If GOOS or GOARCH are set to something other than the default, go install puts the result in ${GOBIN}/${GOOS}_${GOARCH}/ instead of ${GOBIN}.

@hyangah
Copy link
Contributor Author

@hyangah hyangah commented Feb 24, 2021

In our specific case, we don't do cross compiling which simplifies things.
We will need to rename the executable (e.g. gocode -> gocode-gomod, dlv -> dlv-dap, ...).
Currently we are using various hacks
https://github.com/golang/vscode-go/blob/master/build/all.bash#L108-L111 and so on
and also in our js/ts code (where I just found another bug in computing the directory :-) .

To me -o semantic isn't too different from go build's -o.

  • if it's the full path, leave the binary there
  • if it's a binary name (without directory), leave the binary with the name in the default directory. For go build, the default directory is the current directory where the command runs. For go install, the default directory is the default installation directory determined by GOBIN, GOPATH (and GOOS and GOARCH if you cross compile).

@seankhliao
Copy link
Contributor

@seankhliao seankhliao commented Feb 24, 2021

Do I have this right? Though I'm not sure when you'd want go build pkg@version

cmd code output
go build pkg current module local directory
go build -o out pkg current module explicit path
go build pkg@version remote code local directory
go build -o out pkg@version remote code explicit path
go install pkg current module global directory
go install -o out pkg current module explicit path
go install pkg@version remote code global directory
go install -o out pkg@version remote code explicit path

@meling
Copy link

@meling meling commented Mar 1, 2021

IMO, the go install -o out pkg should install in the default location as suggested by @hyangah above, if out is just a file name. Otherwise, the build and install cases become the same... And there isn’t a convenient way to install a differently named binary in the default location.

@bcmills
Copy link
Member

@bcmills bcmills commented Mar 1, 2021

@meling

Otherwise, the build and install cases become the same... And there isn’t a convenient way to install a differently named binary in the default location.

I would rather we have consistent meanings for flags than make every subcommand completely orthogonal.

It's not obvious to me that “installing a differently named binary in the default location” really needs to be convenient.

@hyangah
Copy link
Contributor Author

@hyangah hyangah commented Mar 1, 2021

Thanks @seankhliao.
go install -o out pkg@version and go build -o out pkg@version are indeed same except that - go install uses the global directory as the default directory while go build uses the local directory as the default directory. If out is the full path, yes, they are identical.

Is there any command that can provide the default installation directory? If so, I am happy to use it to formulate the right go build command. (Furthermore, if there is a command that returns the default installation directory, maybe one would argue to deprecate go install)

@bcmills
Copy link
Member

@bcmills bcmills commented Mar 1, 2021

Is there any command that can provide the default installation directory?

Within a module, something like go get -d golang.org/x/tools/gopls && go list -f {{.Target}} golang.org/x/tools/gopls would do the trick.

If we accept #44203, that would shorten to go list -f {{.Target}} golang.org/x/tools/gopls@latest.

svengreb added a commit to svengreb/wand that referenced this issue Apr 26, 2021
GH-89 [1] supersedes GH-78 [2] which documents how the official
deprecation [3] of `gobin` [4] in favor of the new Go 1.16
`go install pkg@version` [5] syntax feature should have been handled for
this project. The idea was to replace the `gobin` task runner [6] with a
one that leverages "bingo" [7], a project similar to `gobin`, that comes
with many great features and also allows to manage development tools on
a per-module basis. The problem is that `bingo` uses some non-default
and nontransparent mechanisms under the hood and automatically generates
files in the repository without the option to disable this behavior.
It does not make use of the `go install` command but relies on custom
dependency resolution mechanisms, making it prone to future changes in
the Go toolchain and therefore not a good choice for the maintainability
of projects.

>>> `go install` is still not perfect

Support for the new `go install` features, which allow to install
commands without affecting the `main` module, have already been added in
GH-71 [8] as an alternative to `gobin`, but one significant problem was
still not addressed: install module/package executables globally without
overriding already installed executables of different versions.
Since `go install` will always place compiled binaries in the path
defined by `go env GOBIN`, any already existing executable with the same
name will be replaced. It is not possible to install a module command
with two different versions since `go install` still messes up the local
user environment.

>>> The Workaround: Hybrid `go install` task runner

This commit therefore implements the solution through a custom
`Runner` [9] that uses `go install` under the hood, but places the
compiled executable in a custom cache directory instead of
`go env GOBIN`. The runner checks if the executable already exists,
installs it if not so, and executes it afterwards.

The concept of storing dependencies locally on a per-project basis is
well-known from the `node_modules` directory [10] of the "Node" [11]
package manager "npm" [12]. Storing executables in a cache directory
within the repository (not tracked by Git) allows to use `go install`
mechanisms while not affect the global user environment and executables
stored in `go env GOBIN`. The runner achieves this by changing the
`GOBIN` environment variable to the custom cache directory during the
execution of `go install`. This way it bypasses the need for
"dirty hacks" while using a custom output path.

The only known disadvantage is the increased usage of storage disk
space, but since most Go executables are small in size anyway, this is
perfectly acceptable compared to the clearly outweighing advantages.

Note that the runner dynamically runs executables based on the given
task so `Validate() error` is a NOOP.

>>> Upcoming Changes

The solution described above works totally fine, but is still not a
clean solution that uses the Go toolchain without any special logic so
as soon as the following changes are made to the
Go toolchain (Go 1.17 or later), the custom runner will be removed
again:

- golang/go/issues#42088 [13] — tracks the process of adding support for
  the Go module syntax to the `go run` command. This will allow to let
  the Go toolchain handle the way how compiled executable are stored,
  located and executed.
- golang/go#44469 [14] — tracks the process of making `go install`
  aware of the `-o` flag like the `go build` command which is the only
  reason why the custom runner has been implemented.

>>> Further Adjustments

Because the new custom task runner dynamically runs executables based on
the given task, the `Bootstrap` method [15] of the `Wand` [16] reference
implementation `Elder` [17] additionally allows to pass Go module import
paths, optionally including a version suffix (`pkg@version`), to install
executables from Go module-based `main` packages into the local cache
directory. This way the local development environment can be set up,
for e.g. by running it as startup task [18] in "JetBrains" IDEs.
The method also ensures that the local cache directory exists and
creates a `.gitignore` file that includes ignore pattern for the cache
directory.

[1]: #89
[2]: #78
[3]: myitcv/gobin#103
[4]: https://github.com/myitcv/gobin
[5]: https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies
[6]: https://pkg.go.dev/github.com/svengreb/wand@v0.5.0/pkg/task/gobin#Runner
[7]: https://github.com/bwplotka/bingo
[8]: #71
[9]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task#Runner
[10]: https://docs.npmjs.com/cli/v7/configuring-npm/folders#node-modules
[11]: https://nodejs.org
[12]: https://www.npmjs.com
[13]: golang/go#42088
[14]: golang/go#44469 (comment)
[15]: https://pkg.go.dev/github.com/svengreb/wand@v0.5.0/pkg/elder#Elder.Bootstrap
[16]: https://pkg.go.dev/github.com/svengreb/wand#Wand
[17]: https://pkg.go.dev/github.com/svengreb/wand/pkg/elder#Elder
[18]: https://www.jetbrains.com/help/idea/settings-tools-startup-tasks.html

GH-89
svengreb added a commit to svengreb/wand that referenced this issue Apr 26, 2021
GH-89 [1] supersedes GH-78 [2] which documents how the official
deprecation [3] of `gobin` [4] in favor of the new Go 1.16
`go install pkg@version` [5] syntax feature should have been handled for
this project. The idea was to replace the `gobin` task runner [6] with a
one that leverages "bingo" [7], a project similar to `gobin`, that comes
with many great features and also allows to manage development tools on
a per-module basis. The problem is that `bingo` uses some non-default
and nontransparent mechanisms under the hood and automatically generates
files in the repository without the option to disable this behavior.
It does not make use of the `go install` command but relies on custom
dependency resolution mechanisms, making it prone to future changes in
the Go toolchain and therefore not a good choice for the maintainability
of projects.

>>> `go install` is still not perfect

Support for the new `go install` features, which allow to install
commands without affecting the `main` module, have already been added in
GH-71 [8] as an alternative to `gobin`, but one significant problem was
still not addressed: install module/package executables globally without
overriding already installed executables of different versions.
Since `go install` will always place compiled binaries in the path
defined by `go env GOBIN`, any already existing executable with the same
name will be replaced. It is not possible to install a module command
with two different versions since `go install` still messes up the local
user environment.

>>> The Workaround: Hybrid `go install` task runner

This commit therefore implements the solution through a custom
`Runner` [9] that uses `go install` under the hood, but places the
compiled executable in a custom cache directory instead of
`go env GOBIN`. The runner checks if the executable already exists,
installs it if not so, and executes it afterwards.

The concept of storing dependencies locally on a per-project basis is
well-known from the `node_modules` directory [10] of the "Node" [11]
package manager "npm" [12]. Storing executables in a cache directory
within the repository (not tracked by Git) allows to use `go install`
mechanisms while not affect the global user environment and executables
stored in `go env GOBIN`. The runner achieves this by changing the
`GOBIN` environment variable to the custom cache directory during the
execution of `go install`. This way it bypasses the need for
"dirty hacks" while using a custom output path.

The only known disadvantage is the increased usage of storage disk
space, but since most Go executables are small in size anyway, this is
perfectly acceptable compared to the clearly outweighing advantages.

Note that the runner dynamically runs executables based on the given
task so `Validate() error` is a NOOP.

>>> Upcoming Changes

The solution described above works totally fine, but is still not a
clean solution that uses the Go toolchain without any special logic so
as soon as the following changes are made to the
Go toolchain (Go 1.17 or later), the custom runner will be removed
again:

- golang/go/issues#42088 [13] — tracks the process of adding support for
  the Go module syntax to the `go run` command. This will allow to let
  the Go toolchain handle the way how compiled executable are stored,
  located and executed.
- golang/go#44469 [14] — tracks the process of making `go install`
  aware of the `-o` flag like the `go build` command which is the only
  reason why the custom runner has been implemented.

>>> Further Adjustments

Because the new custom task runner dynamically runs executables based on
the given task, the `Bootstrap` method [15] of the `Wand` [16] reference
implementation `Elder` [17] additionally allows to pass Go module import
paths, optionally including a version suffix (`pkg@version`), to install
executables from Go module-based `main` packages into the local cache
directory. This way the local development environment can be set up,
for e.g. by running it as startup task [18] in "JetBrains" IDEs.
The method also ensures that the local cache directory exists and
creates a `.gitignore` file that includes ignore pattern for the cache
directory.

[1]: #89
[2]: #78
[3]: myitcv/gobin#103
[4]: https://github.com/myitcv/gobin
[5]: https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies
[6]: https://pkg.go.dev/github.com/svengreb/wand@v0.5.0/pkg/task/gobin#Runner
[7]: https://github.com/bwplotka/bingo
[8]: #71
[9]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task#Runner
[10]: https://docs.npmjs.com/cli/v7/configuring-npm/folders#node-modules
[11]: https://nodejs.org
[12]: https://www.npmjs.com
[13]: golang/go#42088
[14]: golang/go#44469 (comment)
[15]: https://pkg.go.dev/github.com/svengreb/wand@v0.5.0/pkg/elder#Elder.Bootstrap
[16]: https://pkg.go.dev/github.com/svengreb/wand#Wand
[17]: https://pkg.go.dev/github.com/svengreb/wand/pkg/elder#Elder
[18]: https://www.jetbrains.com/help/idea/settings-tools-startup-tasks.html

GH-89
svengreb added a commit to svengreb/wand that referenced this issue Apr 26, 2021
…#90)

GH-89 [1] supersedes GH-78 [2] which documents how the official
deprecation [3] of `gobin` [4] in favor of the new Go 1.16
`go install pkg@version` [5] syntax feature should have been handled for
this project. The idea was to replace the `gobin` task runner [6] with a
one that leverages "bingo" [7], a project similar to `gobin`, that comes
with many great features and also allows to manage development tools on
a per-module basis. The problem is that `bingo` uses some non-default
and nontransparent mechanisms under the hood and automatically generates
files in the repository without the option to disable this behavior.
It does not make use of the `go install` command but relies on custom
dependency resolution mechanisms, making it prone to future changes in
the Go toolchain and therefore not a good choice for the maintainability
of projects.

>>> `go install` is still not perfect

Support for the new `go install` features, which allow to install
commands without affecting the `main` module, have already been added in
GH-71 [8] as an alternative to `gobin`, but one significant problem was
still not addressed: install module/package executables globally without
overriding already installed executables of different versions.
Since `go install` will always place compiled binaries in the path
defined by `go env GOBIN`, any already existing executable with the same
name will be replaced. It is not possible to install a module command
with two different versions since `go install` still messes up the local
user environment.

>>> The Workaround: Hybrid `go install` task runner

This commit therefore implements the solution through a custom
`Runner` [9] that uses `go install` under the hood, but places the
compiled executable in a custom cache directory instead of
`go env GOBIN`. The runner checks if the executable already exists,
installs it if not so, and executes it afterwards.

The concept of storing dependencies locally on a per-project basis is
well-known from the `node_modules` directory [10] of the "Node" [11]
package manager "npm" [12]. Storing executables in a cache directory
within the repository (not tracked by Git) allows to use `go install`
mechanisms while not affect the global user environment and executables
stored in `go env GOBIN`. The runner achieves this by changing the
`GOBIN` environment variable to the custom cache directory during the
execution of `go install`. This way it bypasses the need for
"dirty hacks" while using a custom output path.

The only known disadvantage is the increased usage of storage disk
space, but since most Go executables are small in size anyway, this is
perfectly acceptable compared to the clearly outweighing advantages.

Note that the runner dynamically runs executables based on the given
task so `Validate() error` is a NOOP.

>>> Upcoming Changes

The solution described above works totally fine, but is still not a
clean solution that uses the Go toolchain without any special logic so
as soon as the following changes are made to the
Go toolchain (Go 1.17 or later), the custom runner will be removed
again:

- golang/go/issues#42088 [13] — tracks the process of adding support for
  the Go module syntax to the `go run` command. This will allow to let
  the Go toolchain handle the way how compiled executable are stored,
  located and executed.
- golang/go#44469 [14] — tracks the process of making `go install`
  aware of the `-o` flag like the `go build` command which is the only
  reason why the custom runner has been implemented.

>>> Further Adjustments

Because the new custom task runner dynamically runs executables based on
the given task, the `Bootstrap` method [15] of the `Wand` [16] reference
implementation `Elder` [17] additionally allows to pass Go module import
paths, optionally including a version suffix (`pkg@version`), to install
executables from Go module-based `main` packages into the local cache
directory. This way the local development environment can be set up,
for e.g. by running it as startup task [18] in "JetBrains" IDEs.
The method also ensures that the local cache directory exists and
creates a `.gitignore` file that includes ignore pattern for the cache
directory.

[1]: #89
[2]: #78
[3]: myitcv/gobin#103
[4]: https://github.com/myitcv/gobin
[5]: https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies
[6]: https://pkg.go.dev/github.com/svengreb/wand@v0.5.0/pkg/task/gobin#Runner
[7]: https://github.com/bwplotka/bingo
[8]: #71
[9]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task#Runner
[10]: https://docs.npmjs.com/cli/v7/configuring-npm/folders#node-modules
[11]: https://nodejs.org
[12]: https://www.npmjs.com
[13]: golang/go#42088
[14]: golang/go#44469 (comment)
[15]: https://pkg.go.dev/github.com/svengreb/wand@v0.5.0/pkg/elder#Elder.Bootstrap
[16]: https://pkg.go.dev/github.com/svengreb/wand#Wand
[17]: https://pkg.go.dev/github.com/svengreb/wand/pkg/elder#Elder
[18]: https://www.jetbrains.com/help/idea/settings-tools-startup-tasks.html

Closes GH-89
svengreb added a commit to svengreb/wand that referenced this issue Apr 26, 2021
…#90)

GH-89 [1] supersedes GH-78 [2] which documents how the official
deprecation [3] of `gobin` [4] in favor of the new Go 1.16
`go install pkg@version` [5] syntax feature should have been handled for
this project. The idea was to replace the `gobin` task runner [6] with a
one that leverages "bingo" [7], a project similar to `gobin`, that comes
with many great features and also allows to manage development tools on
a per-module basis. The problem is that `bingo` uses some non-default
and nontransparent mechanisms under the hood and automatically generates
files in the repository without the option to disable this behavior.
It does not make use of the `go install` command but relies on custom
dependency resolution mechanisms, making it prone to future changes in
the Go toolchain and therefore not a good choice for the maintainability
of projects.

>>> `go install` is still not perfect

Support for the new `go install` features, which allow to install
commands without affecting the `main` module, have already been added in
GH-71 [8] as an alternative to `gobin`, but one significant problem was
still not addressed: install module/package executables globally without
overriding already installed executables of different versions.
Since `go install` will always place compiled binaries in the path
defined by `go env GOBIN`, any already existing executable with the same
name will be replaced. It is not possible to install a module command
with two different versions since `go install` still messes up the local
user environment.

>>> The Workaround: Hybrid `go install` task runner

This commit therefore implements the solution through a custom
`Runner` [9] that uses `go install` under the hood, but places the
compiled executable in a custom cache directory instead of
`go env GOBIN`. The runner checks if the executable already exists,
installs it if not so, and executes it afterwards.

The concept of storing dependencies locally on a per-project basis is
well-known from the `node_modules` directory [10] of the "Node" [11]
package manager "npm" [12]. Storing executables in a cache directory
within the repository (not tracked by Git) allows to use `go install`
mechanisms while not affect the global user environment and executables
stored in `go env GOBIN`. The runner achieves this by changing the
`GOBIN` environment variable to the custom cache directory during the
execution of `go install`. This way it bypasses the need for
"dirty hacks" while using a custom output path.

The only known disadvantage is the increased usage of storage disk
space, but since most Go executables are small in size anyway, this is
perfectly acceptable compared to the clearly outweighing advantages.

Note that the runner dynamically runs executables based on the given
task so `Validate() error` is a NOOP.

>>> Upcoming Changes

The solution described above works totally fine, but is still not a
clean solution that uses the Go toolchain without any special logic so
as soon as the following changes are made to the
Go toolchain (Go 1.17 or later), the custom runner will be removed
again:

- golang/go/issues#42088 [13] — tracks the process of adding support for
  the Go module syntax to the `go run` command. This will allow to let
  the Go toolchain handle the way how compiled executable are stored,
  located and executed.
- golang/go#44469 [14] — tracks the process of making `go install`
  aware of the `-o` flag like the `go build` command which is the only
  reason why the custom runner has been implemented.

>>> Further Adjustments

Because the new custom task runner dynamically runs executables based on
the given task, the `Bootstrap` method [15] of the `Wand` [16] reference
implementation `Elder` [17] additionally allows to pass Go module import
paths, optionally including a version suffix (`pkg@version`), to install
executables from Go module-based `main` packages into the local cache
directory. This way the local development environment can be set up,
for e.g. by running it as startup task [18] in "JetBrains" IDEs.
The method also ensures that the local cache directory exists and
creates a `.gitignore` file that includes ignore pattern for the cache
directory.

[1]: #89
[2]: #78
[3]: myitcv/gobin#103
[4]: https://github.com/myitcv/gobin
[5]: https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies
[6]: https://pkg.go.dev/github.com/svengreb/wand@v0.5.0/pkg/task/gobin#Runner
[7]: https://github.com/bwplotka/bingo
[8]: #71
[9]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task#Runner
[10]: https://docs.npmjs.com/cli/v7/configuring-npm/folders#node-modules
[11]: https://nodejs.org
[12]: https://www.npmjs.com
[13]: golang/go#42088
[14]: golang/go#44469 (comment)
[15]: https://pkg.go.dev/github.com/svengreb/wand@v0.5.0/pkg/elder#Elder.Bootstrap
[16]: https://pkg.go.dev/github.com/svengreb/wand#Wand
[17]: https://pkg.go.dev/github.com/svengreb/wand/pkg/elder#Elder
[18]: https://www.jetbrains.com/help/idea/settings-tools-startup-tasks.html

Closes GH-89
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants