Skip to content

Commit

Permalink
Task for Go toolchain install command (#71)
Browse files Browse the repository at this point in the history
As of Go version 1.16 `go install $pkg@$version` [1] allows to install
commands without affecting the `main` module. Additionally commands
like `go build` and `go test` no longer modify `go.mod` and `go.sum`
files by default but report an error if a module requirement or checksum
needs to be added or updated (as if the `-mod=readonly` flag were used).
This can be used as alternative to the already existing `gobin` runner
[2].

To support the `go install` command of the Go toolchain [3], a new
`Task` [4] has been implemented in the new `install` [5] package that
can be used through a Go toolchain `Runner` [6].
The task is customizable through the following functions:

- `WithEnv(env map[string]string) install.Option` - sets the task
  specific environment.
- `WithModulePath(path string) install.Option` - sets the module import
  path.
- `WithModuleVersion(version *semver.Version) install.Option` - sets the
  module version.

[1]: https://blog.golang.org/go116-module-changes#TOC_4.
[2]: https://pkg.go.dev/github.com/svengreb/[email protected]/pkg/task/gobin
[3]: https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies
[4]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task#Task
[5]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task/golang/install
[6]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task/golang#Runner

Closes GH-70
  • Loading branch information
svengreb authored Apr 21, 2021
1 parent 569559e commit c36e8f3
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ The package also already provides tasks for basic [Go toolchain][go-pkg-cmd/go]
- **`goimports`** — the [`goimports`][go-pkg-task/goimports] package provides a task for the [`golang.org/x/tools/cmd/goimports`][go-pkg-golang.org/x/tools/cmd/goimports] Go module command. `goimports` allows to update Go import lines, add missing ones and remove unreferenced ones. It also formats code in the same style as [`gofmt`][go-pkg-cmd/gofmt] so it can be used as a replacement. The source code of `goimports` is [available in the GitHub repository][gh-golang/tools-tree-cmd/goimports].
- **Go** — The [`golang`][go-pkg-task/golang] package provides tasks for [Go toolchain][go-pkg-cmd/go] commands.
- **`build`** — to run the [`build` command of the Go toolchain][go-pkg-cmd/go#build] the task of the [`build`][go-pkg-task/golang/build] package can be used.
- **`install`** — to run the [`install` command of the Go toolchain][go-pkg-cmd/go#install] the task of the [`install`][go-pkg-task/golang/install] package can be used.
- **`test`** — to run the [`test` command of the Go toolchain][go-pkg-cmd/go#test] the task of the [`test`][go-pkg-task/golang/test] package can be used.
- **`golangci-lint`** — the [`golangcilint`][go-pkg-task/golangcilint] package provides a task for the [`github.com/golangci/golangci-lint/cmd/golangci-lint`][go-pkg-github.com/golangci/golangci-lint/cmd/golangci-lint] Go module command. `golangci-lint` is a fast, parallel runner for dozens of Go linters that uses caching, supports YAML configurations and has integrations with all major IDEs. The source code of `golangci-lint` is [available in the GitHub repository][gh-golangci/golangci-lint].
- **`gox`** — the [`gox`][go-pkg-task/gox] package provides a task for the [`github.com/mitchellh/gox`][go-pkg-github.com/mitchellh/gox] Go module command. `gox` is a dead simple, no frills Go cross compile tool that behaves a lot like the standard [Go toolchain `build` command][go-pkg-cmd/go#build]. The source code of `gox` is [available in the GitHub repository][gh-mitchellh/gox].
Expand Down Expand Up @@ -363,6 +364,7 @@ The guide also includes information about [minimal, complete, and verifiable exa
[go-pkg-task/goimports]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task/goimports
[go-pkg-task/golang]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task/golang
[go-pkg-task/golang/build]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task/golang/build
[go-pkg-task/golang/install]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task/golang/install
[go-pkg-task/golang/test]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task/golang/test
[go-pkg-task/golangcilint]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task/golangcilint
[go-pkg-task/gox]: https://pkg.go.dev/github.com/svengreb/wand/pkg/task/gox
Expand Down
75 changes: 75 additions & 0 deletions pkg/task/golang/install/install.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) 2019-present Sven Greb <[email protected]>
// This source code is licensed under the MIT license found in the LICENSE file.

// Package install provides a task for the Go toolchain "install" command.
// It requires at least Go version 1.16 which comes with support to install commands via `go install` (1) without
// affecting the `main` module and will not "pollute" the `go.mod` file (2) anymore.
// See https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies for more details about the
// `go install` command.
//
// References
//
// (1) https://blog.golang.org/go116-module-changes#TOC_4.
// (2) https://blog.golang.org/go116-module-changes#TOC_3.
package install

import (
"github.com/svengreb/wand"
"github.com/svengreb/wand/pkg/app"
"github.com/svengreb/wand/pkg/task"
)

// Task is a task for the Go toolchain "install" command.
// It requires at least Go version 1.16 which comes with support to install commands via `go install` (1) without
// affecting the `main` module and will not "pollute" the `go.mod` file (2) anymore.
// See https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies for more details about the
// `go install` command.
//
// References
//
// (1) https://blog.golang.org/go116-module-changes#TOC_4.
// (2) https://blog.golang.org/go116-module-changes#TOC_3.
type Task struct {
ac app.Config
opts *Options
}

// BuildParams builds the parameters.
// Note that configured flags are applied after the "GOFLAGS" environment variable and could overwrite already defined
// flags.
//
// See `go help environment`, `go help env` and the `go` command documentations for more details:
// https://golang.org/cmd/go/#hdr-Environment_variables
func (t *Task) BuildParams() []string {
params := []string{"install"}

params = append(params, t.opts.goModule.String())

return params
}

// Env returns the task specific environment.
func (t *Task) Env() map[string]string {
return t.opts.env
}

// Kind returns the task kind.
func (t *Task) Kind() task.Kind {
return task.KindExec
}

// Options returns the task options.
func (t *Task) Options() task.Options {
return *t.opts
}

// New creates a new task for the Go toolchain "install" command.
//nolint:gocritic // The app.Config struct is passed as value by design to ensure immutability.
func New(wand wand.Wand, ac app.Config, opts ...Option) (*Task, error) {
opt, optErr := NewOptions(opts...)
if optErr != nil {
return nil, optErr
}

return &Task{ac: ac, opts: opt}, nil
}
66 changes: 66 additions & 0 deletions pkg/task/golang/install/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) 2019-present Sven Greb <[email protected]>
// This source code is licensed under the MIT license found in the LICENSE file.

package install

import (
"github.com/Masterminds/semver/v3"

"github.com/svengreb/wand/pkg/project"
)

const (
// TaskName is the name of the task.
TaskName = "go/install"
)

// Option is a task option.
type Option func(*Options)

// Options are task options.
type Options struct {
// env is the task specific environment.
env map[string]string

// goModule is the Go module identifier.
goModule *project.GoModuleID
}

// NewOptions creates new task options.
func NewOptions(opts ...Option) (*Options, error) {
opt := &Options{
goModule: &project.GoModuleID{},
}
for _, o := range opts {
o(opt)
}

if opt.goModule.Version == nil {
opt.goModule.IsLatest = true
}

return opt, nil
}

// WithEnv sets the task specific environment.
func WithEnv(env map[string]string) Option {
return func(o *Options) {
o.env = env
}
}

// WithModulePath sets the module import path.
func WithModulePath(path string) Option {
return func(o *Options) {
if path != "" {
o.goModule.Path = path
}
}
}

// WithModuleVersion sets the module version.
func WithModuleVersion(version *semver.Version) Option {
return func(o *Options) {
o.goModule.Version = version
}
}

0 comments on commit c36e8f3

Please sign in to comment.