diff --git a/.bingo/Variables.mk b/.bingo/Variables.mk index 71ab703..22b111f 100644 --- a/.bingo/Variables.mk +++ b/.bingo/Variables.mk @@ -1,4 +1,4 @@ -# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.2.0. DO NOT EDIT. +# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.2.2. DO NOT EDIT. # All tools are designed to be build inside $GOBIN. GOPATH ?= $(shell go env GOPATH) GOBIN ?= $(firstword $(subst :, ,${GOPATH}))/bin @@ -6,16 +6,22 @@ GO ?= $(shell which go) # Bellow generated variables ensure that every time a tool under each variable is invoked, the correct version # will be used; reinstalling only if needed. -# For example for copyright variable: +# For example for athens-proxy variable: # # In your main Makefile (for non array binaries): # #include .bingo/Variables.mk # Assuming -dir was set to .bingo . # -#command: $(COPYRIGHT) -# @echo "Running copyright" -# @$(COPYRIGHT) +#command: $(ATHENS_PROXY) +# @echo "Running athens-proxy" +# @$(ATHENS_PROXY) # +ATHENS_PROXY := $(GOBIN)/athens-proxy-v0.9.0 +$(ATHENS_PROXY): .bingo/athens-proxy.mod + @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. + @echo "(re)installing $(GOBIN)/athens-proxy-v0.9.0" + @cd .bingo && $(GO) build -modfile=athens-proxy.mod -o=$(GOBIN)/athens-proxy-v0.9.0 "github.com/gomods/athens/cmd/proxy" + COPYRIGHT := $(GOBIN)/copyright-v0.9.0 $(COPYRIGHT): .bingo/copyright.mod @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. diff --git a/.bingo/athens-proxy.mod b/.bingo/athens-proxy.mod new file mode 100644 index 0000000..0e27e35 --- /dev/null +++ b/.bingo/athens-proxy.mod @@ -0,0 +1,5 @@ +module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT + +go 1.14 + +require github.com/gomods/athens v0.9.0 // cmd/proxy diff --git a/.bingo/variables.env b/.bingo/variables.env index 117c360..bb78d66 100644 --- a/.bingo/variables.env +++ b/.bingo/variables.env @@ -1,22 +1,24 @@ -# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.2.0. DO NOT EDIT. +# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.2.2. DO NOT EDIT. # All tools are designed to be build inside $GOBIN. # Those variables will work only until 'bingo get' was invoked, or if tools were installed via Makefile's Variables.mk. local gobin=$(go env GOBIN) -if [ -z "$var" ]; then +if [ -z "$gobin" ]; then gobin="$(go env GOPATH)/bin" fi -COPYRIGHT="${gobin}/copyright-v0.9.0 " +ATHENS_PROXY="${gobin}/athens-proxy-v0.9.0" -EMBEDMD="${gobin}/embedmd-v1.0.0 " +COPYRIGHT="${gobin}/copyright-v0.9.0" -FAILLINT="${gobin}/faillint-v1.5.0 " +EMBEDMD="${gobin}/embedmd-v1.0.0" -GOIMPORTS="${gobin}/goimports-v0.0.0-20200519204825-e64124511800 " +FAILLINT="${gobin}/faillint-v1.5.0" -GOLANGCI_LINT="${gobin}/golangci-lint-v1.26.0 " +GOIMPORTS="${gobin}/goimports-v0.0.0-20200519204825-e64124511800" -MISSPELL="${gobin}/misspell-v0.3.4 " +GOLANGCI_LINT="${gobin}/golangci-lint-v1.26.0" + +MISSPELL="${gobin}/misspell-v0.3.4" diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d81663..e73a01f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ We use *breaking* word for marking changes that are not backward compatible (rel * [#25](https://github.com/bwplotka/bingo/issues/25) Fixed support of `bingo get` for arrays. * Fixed versioning binaries with `+incompatible` version (wrong templating used). * Fixed support `bingo list` for arrays. +* Added rename / clone logic +* Always print to stdout no matter of verbose level. ### Changed diff --git a/Makefile b/Makefile index 7ec1e4f..ad4f824 100644 --- a/Makefile +++ b/Makefile @@ -102,3 +102,8 @@ lint: $(FAILLINT) $(GOLANGCI_LINT) $(COPYRIGHT) $(MISSPELL) format docs check-gi @echo ">> ensuring Copyright headers" @$(COPYRIGHT) $(call require_clean_work_tree,"detected white noise or/and files without copyright; run 'make lint' file and commit changes.") + +.PHONY: run-go-mod-cache +run-go-mod-cache: $(ATHENS_PROXY) + @echo ">> starting athens on address :3000" + @$(ATHENS_PROXY) diff --git a/README.md b/README.md index 9f5e27d..e8f873f 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,9 @@ It will NOT install correct Version if missing. -moddir string Directory where separate modules for each binary will be maintained. Feel free to commit this directory to your VCS to bond binary versions to your project code. If the directory does not exist bingo logs and assumes a fresh project. (default ".bingo") -n string - The -n flag instructs to get binary and name it with given name instead of default, so the last element of package directory. Allowed characters [A-z0-9._-]. If -n is used and no package/binary is specified, bingo get will return error. If -n is used with existing binary name, rename will be done. + The -n flag instructs to get binary and name it with given name instead of default, so the last element of package directory. Allowed characters [A-z0-9._-]. If -n is used and no package/binary is specified, bingo get will return error. If -n is used with existing binary name, copy of this binary will be done. Cannot be used with -r + -r string + The -r flag instructs to get existing binary and rename it with given name. Allowed characters [A-z0-9._-]. If -r is used and no package/binary is specified or non existing binary name is used, bingo will return error. Cannot be used with -n. -u The -u flag instructs get to update modules providing dependencies of packages named on the command line to use newer minor or patch releases when available. -upatch The -upatch flag (not -u patch) also instructs get to update dependencies, but changes the default to select patch releases. diff --git a/get.go b/get.go index 3f9a266..6a52b84 100644 --- a/get.go +++ b/get.go @@ -12,6 +12,7 @@ import ( "os" "path" "path/filepath" + "strconv" "strings" "time" @@ -26,124 +27,165 @@ type getConfig struct { relModDir string update runner.GetUpdatePolicy name string + rename string // target name or target package path, optionally with Version(s). rawTarget string } -func get( +func getAll( ctx context.Context, logger *log.Logger, c getConfig, ) (err error) { - if c.rawTarget == "" { - // Empty means all. - if c.name != "" { - return errors.New("name cannot by specified if no target was given") - } + if c.name != "" { + return errors.New("name cannot by specified if no target was given") + } + if c.rename != "" { + return errors.New("rename cannot by specified if no target was given") + } - pkgs, err := bingo.ListPinnedMainPackages(logger, c.relModDir, false) - if err != nil { - return err - } - for _, p := range pkgs { - mc := c - mc.rawTarget = p.Name - if len(p.Versions) > 1 { - // Compose array target. Order of versions matter. - var versions []string - for _, v := range p.Versions { - versions = append(versions, v.Version) - } - mc.rawTarget += "@" + strings.Join(versions, ",") - } - if err := get(ctx, logger, mc); err != nil { - return err + pkgs, err := bingo.ListPinnedMainPackages(logger, c.relModDir, false) + if err != nil { + return err + } + for _, p := range pkgs { + mc := c + mc.rawTarget = p.Name + if len(p.Versions) > 1 { + // Compose array target. Order of versions matter. + var versions []string + for _, v := range p.Versions { + versions = append(versions, v.Version) } + mc.rawTarget += "@" + strings.Join(versions, ",") + } + if err := get(ctx, logger, mc); err != nil { + return err } - return nil } + return nil +} - var modVersions []string - s := strings.Split(c.rawTarget, "@") +func parseTarget(rawTarget string) (name string, pkgPath string, versions []string, err error) { + s := strings.Split(rawTarget, "@") nameOrPackage := s[0] if len(s) > 1 { - modVersions = strings.Split(s[1], ",") + versions = strings.Split(s[1], ",") } - if len(modVersions) > 1 { + if len(versions) > 1 { + // Check for duplicates or/and none. dup := map[string]struct{}{} - for _, v := range modVersions { + for _, v := range versions { if _, ok := dup[v]; ok { - return errors.Errorf("version duplicates are not allowed, got: %v", modVersions) + return "", "", nil, errors.Errorf("version duplicates are not allowed, got: %v", versions) } dup[v] = struct{}{} - if v == "none" { - return errors.Errorf("none is not allowed when there are more than one specified Version, got: %v", modVersions) + return "", "", nil, errors.Errorf("none is not allowed when there are more than one specified Version, got: %v", versions) } } } - pkgPath := nameOrPackage - name := nameOrPackage - if !strings.Contains(nameOrPackage, "/") { - // Binary referenced by name, get full package name if module file exists. - pkgPath, err = packagePathFromBinaryName(nameOrPackage, c.modDir) - if err != nil { - return err - } - - if c.name != "" && c.name != name { - // Rename requested. Remove old mod(s) in this case, but only at the end. - defer func() { _ = removeAllGlob(filepath.Join(c.modDir, name+".*")) }() - } - } else { + name = nameOrPackage + if strings.Contains(nameOrPackage, "/") { // Binary referenced by path, get default name from package path. + pkgPath = nameOrPackage name = path.Base(pkgPath) + } + return name, pkgPath, versions, nil +} + +func get( + ctx context.Context, + logger *log.Logger, + c getConfig, +) (err error) { + if c.rawTarget == "" { + // Empty means get all. It recursively invokes get for each existing binary. + return getAll(ctx, logger, c) + } + name, pkgPath, versions, err := parseTarget(c.rawTarget) + if err != nil { + return errors.Wrapf(err, "parse %v", c.rawTarget) + } + + existingModFiles, err := filepath.Glob(filepath.Join(c.modDir, name+".mod")) + if err != nil { + return err + } + existingModArrFiles, err := filepath.Glob(filepath.Join(c.modDir, name+".*.mod")) + if err != nil { + return err + } + existingModFiles = append(existingModFiles, existingModArrFiles...) + if pkgPath == "" { + // Binary referenced by name, get full package name if module file exists. - if c.name == "" && name == "cmd" { - return errors.Errorf("package %s would be installed with ambiguous name %s. This is a common, but slightly annoying package layout. "+ - "It's advised to choose unique name with -n flag", pkgPath, name) + // Get full import path from any existing module file for this name. + if len(existingModFiles) == 0 { + return errors.Errorf("binary %q was not installed before. Use full package name to install it", name) + } + pkgPath, _, err = bingo.ModDirectPackage(existingModFiles[0], nil) + if err != nil { + return errors.Wrapf(err, "binary %q was installed, but go modules %s is malformed. Use full package name to reinstall it", name, existingModFiles[0]) } } + // Handle new name/rename. + targetName := name if c.name != "" { - name = c.name + targetName = c.name } - - if name == strings.TrimSuffix(bingo.FakeRootModFileName, ".mod") { - return errors.New("requested binary with name `go`. This is impossible, choose different name using -name flag.") + if c.rename != "" { + targetName = c.rename } - binModFiles, err := filepath.Glob(filepath.Join(c.modDir, name+".*.mod")) - if err != nil { - return err + if targetName == "cmd" { + return errors.Errorf("package %s would be installed with ambiguous name %s. This is a common, but slightly annoying package layout"+ + "It's advised to choose unique name with -n flag", pkgPath, targetName) + } + if targetName == strings.TrimSuffix(bingo.FakeRootModFileName, ".mod") { + return errors.Errorf("requested binary with name %q`. This is impossible, choose different name using -n flag", strings.TrimSuffix(bingo.FakeRootModFileName, ".mod")) } - binModFiles = append([]string{filepath.Join(c.modDir, name+".mod")}, binModFiles...) - if len(modVersions) == 0 { - // No version was specified. This means user want to install what was pinned before. By specifying empty string, - // go get with figure out the version from existing module file under this index. - for range binModFiles { - modVersions = append(modVersions, "") + if len(versions) == 0 { + for _, f := range existingModFiles { + _, version, err := bingo.ModDirectPackage(f, nil) + if err != nil { + return errors.Wrapf(err, "binary %q was installed, but go modules %s is malformed. Use full package name to reinstall it", name, existingModFiles[0]) + } + versions = append(versions, version) } - } else if modVersions[0] == "none" { + } else if versions[0] == "none" { // none means we no longer want to Version this package. // NOTE: We don't remove binaries. return removeAllGlob(filepath.Join(c.modDir, name+".*")) } - for i, v := range modVersions { - if err := getOne(ctx, logger, c, i, v, pkgPath, name); err != nil { - return errors.Wrapf(err, "%d: getting %s", i, v) + for i, version := range versions { + if err := getOne(ctx, logger, c, i, pkgPath, targetName, version); err != nil { + return errors.Wrapf(err, "%d: getting %s", i, version) } } - // Remove unused mod files. - for i := len(binModFiles); i > 0 && i > len(modVersions); i-- { - if err := os.RemoveAll(filepath.Join(c.modDir, fmt.Sprintf("%s.%d.mod", name, i-1))); err != nil { - return err + if c.rename != "" && targetName != name { + // Rename requested. Remove old mod(s) in this case, but only at the end. + defer func() { _ = removeAllGlob(filepath.Join(c.modDir, name+".*")) }() + } + + // Remove target unused arr mod files. + existingTargetModArrFiles, err := filepath.Glob(filepath.Join(c.modDir, targetName+".*.mod")) + if err != nil { + return err + } + for _, f := range existingTargetModArrFiles { + i, err := strconv.ParseInt(strings.Split(filepath.Base(f), ".")[1], 10, 64) + if err != nil || int(i) >= len(versions) { + if err := os.RemoveAll(f); err != nil { + return err + } } } return nil @@ -162,9 +204,9 @@ func getOne( logger *log.Logger, c getConfig, i int, - version string, pkgPath string, name string, + version string, ) (err error) { ctx, cancel := context.WithTimeout(ctx, 3*time.Minute) defer cancel() @@ -226,24 +268,6 @@ func getOne( return c.runner.With(ctx, outModFile, c.modDir).Build(pkgPath, fmt.Sprintf("%s-%s", name, version)) } -func packagePathFromBinaryName(binary string, modDir string) (string, error) { - currModFile := filepath.Join(modDir, binary+".mod") - - // Get full import path from module file which has module and encoded sub path. - if _, err := os.Stat(currModFile); err != nil { - if os.IsNotExist(err) { - return "", errors.Errorf("binary %q was not installed before. Use full package name to install it", binary) - } - return "", err - } - - m, _, err := bingo.ModDirectPackage(currModFile, nil) - if err != nil { - return "", errors.Wrapf(err, "binary %q was installed, but go modules %s is malformed. Use full package name to reinstall it", binary, currModFile) - } - return m, nil -} - const modREADMEFmt = `# Project Development Dependencies. This is directory which stores Go modules with pinned buildable package that is used within this repository, managed by https://github.com/bwplotka/bingo. diff --git a/get_test.go b/get_test.go index 40c3aa8..aa81c51 100644 --- a/get_test.go +++ b/get_test.go @@ -5,13 +5,17 @@ package main_test import ( "bytes" + "context" "fmt" + "io" "io/ioutil" + "net/http" "os" "os/exec" "path/filepath" "strings" "testing" + "time" "github.com/bwplotka/bingo/pkg/testutil" "github.com/bwplotka/bingo/pkg/version" @@ -23,12 +27,45 @@ const ( defaultModDir = ".bingo" ) +func runAthensCache(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cmd := exec.CommandContext(ctx, "make", "run-go-mod-cache") + testutil.Ok(t, cmd.Start()) + + // Wait until cache is responsive. + ctx, cancelt := context.WithTimeout(ctx, 2*time.Minute) + defer cancelt() + for ctx.Err() == nil { + time.Sleep(1 * time.Second) + + r, err := http.Get("http://localhost:3000/readyz") + if err != nil { + continue + } + + _, _ = io.Copy(ioutil.Discard, r.Body) + r.Body.Close() + + if r.StatusCode == 200 { + t.Cleanup(func() { + cancel() + _ = cmd.Wait() + }) + return + } + } + cancel() + _ = cmd.Wait() + s, _ := cmd.Output() + t.Fatal(string(s)) +} + // TODO(bwplotka): Test running versions. To do so we might want to setup small binary printing Version at each commit. // TODO(bwplotka): Add test cases for array versions. // TODO(bwplotka): Test renames. func TestGet(t *testing.T) { currTestCaseDir := fmt.Sprintf("testdata/testproject_with_bingo_%s", strings.ReplaceAll(version.Version, ".", "_")) - + runAthensCache(t) t.Run("Empty project", func(t *testing.T) { for _, isGoProject := range []bool{false, true} { t.Run(fmt.Sprintf("isGoProject=%v", isGoProject), func(t *testing.T) { @@ -133,7 +170,6 @@ func TestGet(t *testing.T) { fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "github.com/prometheus/promu@v0.3.0,v0.5.0,v0.2.0")) testutil.Equals(t, "Name\t\tBinary Name\tPackage @ Version\t\t\t\t\n----\t\t-----------\t-----------------\t\t\t\t\npromu\tpromu-v0.3.0\tgithub.com/prometheus/promu@v0.3.0\t\npromu\tpromu-v0.5.0\tgithub.com/prometheus/promu@v0.5.0\t\npromu\tpromu-v0.2.0\tgithub.com/prometheus/promu@v0.2.0", g.ExecOutput(t, p.root, goBinPath, "list", "promu")) testutil.Equals(t, "Name\t\t\tBinary Name\t\t\t\t\t\t\t\tPackage @ Version\t\t\t\t\t\t\t\t\t\t\t\n----\t\t\t-----------\t\t\t\t\t\t\t\t-----------------\t\t\t\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.3.0\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.3.0\t\t\t\t\t\t\t\t\ngo-bindata\tgo-bindata-v3.1.1+incompatible\t\t\t\tgithub.com/go-bindata/go-bindata/go-bindata@v3.1.1+incompatible\t\t\ngoimports\t\tgoimports-v0.0.0-20200522201501-cb1345f3a375\t\tgolang.org/x/tools/cmd/goimports@v0.0.0-20200522201501-cb1345f3a375\t\ngoimports2\tgoimports2-v0.0.0-20200519175826-7521f6f42533\tgolang.org/x/tools/cmd/goimports@v0.0.0-20200519175826-7521f6f42533\t\npromu\t\tpromu-v0.3.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.3.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.5.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.5.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.2.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.2.0", g.ExecOutput(t, p.root, goBinPath, "list")) - }, existingBinaries: []string{"faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, }, @@ -187,55 +223,100 @@ func TestGet(t *testing.T) { existingBinaries: []string{"f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, }, { - name: "Updating f2 to multiple versions with none should fail", + name: "Creating not existing foo to f3 should fail", do: func(t *testing.T) { - testutil.NotOk(t, g.ExectErr(p.root, goBinPath, "get", "f2@v1.4.0,v1.1.0,none")) + testutil.NotOk(t, g.ExectErr(p.root, goBinPath, "get", "-n", "f3", "x")) }, existingBinaries: []string{"f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, }, { - name: "Updating f2 to non array version should work", + name: "Renaming not existing foo to f3 should fail", do: func(t *testing.T) { - fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "f2@v1.1.0")) + testutil.NotOk(t, g.ExectErr(p.root, goBinPath, "get", "-r", "f3", "x")) }, existingBinaries: []string{"f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, }, - // TODO(bwplotka): Test Rename, different paths, empty paths, gopath + { + name: "Cloning f2 to f2-clone should work", + do: func(t *testing.T) { + fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "-n", "f2-clone", "f2")) + testutil.Equals(t, "Name\t\t\tBinary Name\t\t\t\t\t\t\t\tPackage @ Version\t\t\t\t\t\t\t\t\t\t\t\n----\t\t\t-----------\t\t\t\t\t\t\t\t-----------------\t\t\t\t\t\t\t\t\t\t\t\nf2-clone\t\tf2-clone-v1.3.0\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.3.0\t\t\t\t\t\t\t\t\nf2-clone\t\tf2-clone-v1.4.0\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.4.0\t\t\t\t\t\t\t\t\nf2\t\t\tf2-v1.3.0\t\t\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.3.0\t\t\t\t\t\t\t\t\nf2\t\t\tf2-v1.4.0\t\t\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.4.0\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.1.0\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.1.0\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.0.0\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.0.0\t\t\t\t\t\t\t\t\ngo-bindata\tgo-bindata-v3.1.1+incompatible\t\t\t\tgithub.com/go-bindata/go-bindata/go-bindata@v3.1.1+incompatible\t\t\ngoimports\t\tgoimports-v0.0.0-20200522201501-cb1345f3a375\t\tgolang.org/x/tools/cmd/goimports@v0.0.0-20200522201501-cb1345f3a375\t\ngoimports2\tgoimports2-v0.0.0-20200519175826-7521f6f42533\tgolang.org/x/tools/cmd/goimports@v0.0.0-20200519175826-7521f6f42533\t\npromu\t\tpromu-v0.3.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.3.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.5.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.5.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.2.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.2.0", g.ExecOutput(t, p.root, goBinPath, "list")) + }, + existingBinaries: []string{"f2-clone-v1.3.0", "f2-clone-v1.4.0", "f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, + }, + { + name: "Deleting f2-clone", + do: func(t *testing.T) { + fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "f2-clone@none")) + testutil.Equals(t, "Name\t\t\tBinary Name\t\t\t\t\t\t\t\tPackage @ Version\t\t\t\t\t\t\t\t\t\t\t\n----\t\t\t-----------\t\t\t\t\t\t\t\t-----------------\t\t\t\t\t\t\t\t\t\t\t\nf2\t\t\tf2-v1.3.0\t\t\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.3.0\t\t\t\t\t\t\t\t\nf2\t\t\tf2-v1.4.0\t\t\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.4.0\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.1.0\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.1.0\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.0.0\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.0.0\t\t\t\t\t\t\t\t\ngo-bindata\tgo-bindata-v3.1.1+incompatible\t\t\t\tgithub.com/go-bindata/go-bindata/go-bindata@v3.1.1+incompatible\t\t\ngoimports\t\tgoimports-v0.0.0-20200522201501-cb1345f3a375\t\tgolang.org/x/tools/cmd/goimports@v0.0.0-20200522201501-cb1345f3a375\t\ngoimports2\tgoimports2-v0.0.0-20200519175826-7521f6f42533\tgolang.org/x/tools/cmd/goimports@v0.0.0-20200519175826-7521f6f42533\t\npromu\t\tpromu-v0.3.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.3.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.5.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.5.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.2.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.2.0", g.ExecOutput(t, p.root, goBinPath, "list")) + }, + existingBinaries: []string{"f2-clone-v1.3.0", "f2-clone-v1.4.0", "f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, + }, + { + name: "Renaming f2 to f3 should work", + do: func(t *testing.T) { + fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "-r", "f3", "f2")) + testutil.Equals(t, "Name\t\t\tBinary Name\t\t\t\t\t\t\t\tPackage @ Version\t\t\t\t\t\t\t\t\t\t\t\n----\t\t\t-----------\t\t\t\t\t\t\t\t-----------------\t\t\t\t\t\t\t\t\t\t\t\nf3\t\t\tf3-v1.3.0\t\t\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.3.0\t\t\t\t\t\t\t\t\nf3\t\t\tf3-v1.4.0\t\t\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.4.0\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.1.0\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.1.0\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.0.0\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.0.0\t\t\t\t\t\t\t\t\ngo-bindata\tgo-bindata-v3.1.1+incompatible\t\t\t\tgithub.com/go-bindata/go-bindata/go-bindata@v3.1.1+incompatible\t\t\ngoimports\t\tgoimports-v0.0.0-20200522201501-cb1345f3a375\t\tgolang.org/x/tools/cmd/goimports@v0.0.0-20200522201501-cb1345f3a375\t\ngoimports2\tgoimports2-v0.0.0-20200519175826-7521f6f42533\tgolang.org/x/tools/cmd/goimports@v0.0.0-20200519175826-7521f6f42533\t\npromu\t\tpromu-v0.3.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.3.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.5.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.5.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.2.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.2.0", g.ExecOutput(t, p.root, goBinPath, "list")) + }, + existingBinaries: []string{"f2-clone-v1.3.0", "f2-clone-v1.4.0", "f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "f3-v1.3.0", "f3-v1.4.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, + }, + { + name: "Renaming f3 to f4 with certain version should work", + do: func(t *testing.T) { + fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "-r", "f4", "f3@v1.1.0,v1.0.0")) + testutil.Equals(t, "Name\t\t\tBinary Name\t\t\t\t\t\t\t\tPackage @ Version\t\t\t\t\t\t\t\t\t\t\t\n----\t\t\t-----------\t\t\t\t\t\t\t\t-----------------\t\t\t\t\t\t\t\t\t\t\t\nf4\t\t\tf4-v1.1.0\t\t\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.1.0\t\t\t\t\t\t\t\t\nf4\t\t\tf4-v1.0.0\t\t\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.0.0\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.1.0\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.1.0\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.0.0\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.0.0\t\t\t\t\t\t\t\t\ngo-bindata\tgo-bindata-v3.1.1+incompatible\t\t\t\tgithub.com/go-bindata/go-bindata/go-bindata@v3.1.1+incompatible\t\t\ngoimports\t\tgoimports-v0.0.0-20200522201501-cb1345f3a375\t\tgolang.org/x/tools/cmd/goimports@v0.0.0-20200522201501-cb1345f3a375\t\ngoimports2\tgoimports2-v0.0.0-20200519175826-7521f6f42533\tgolang.org/x/tools/cmd/goimports@v0.0.0-20200519175826-7521f6f42533\t\npromu\t\tpromu-v0.3.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.3.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.5.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.5.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.2.0\t\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.2.0", g.ExecOutput(t, p.root, goBinPath, "list")) + }, + existingBinaries: []string{"f2-clone-v1.3.0", "f2-clone-v1.4.0", "f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "f3-v1.3.0", "f3-v1.4.0", "f4-v1.0.0", "f4-v1.1.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, + }, + { + name: "Updating f4 to multiple versions with none should fail", + do: func(t *testing.T) { + testutil.NotOk(t, g.ExectErr(p.root, goBinPath, "get", "f2@v1.4.0,v1.1.0,none")) + }, + existingBinaries: []string{"f2-clone-v1.3.0", "f2-clone-v1.4.0", "f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "f3-v1.3.0", "f3-v1.4.0", "f4-v1.0.0", "f4-v1.1.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, + }, + { + name: "Updating f4 back to non array version should work", + do: func(t *testing.T) { + fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "f4@v1.1.0")) + }, + existingBinaries: []string{"f2-clone-v1.3.0", "f2-clone-v1.4.0", "f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "f3-v1.3.0", "f3-v1.4.0", "f4-v1.0.0", "f4-v1.1.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, + }, { name: "Remove goimports2 by name", do: func(t *testing.T) { fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "goimports2@none")) - testutil.Equals(t, "Name\t\t\tBinary Name\t\t\t\t\t\t\tPackage @ Version\t\t\t\t\t\t\t\t\t\t\t\n----\t\t\t-----------\t\t\t\t\t\t\t-----------------\t\t\t\t\t\t\t\t\t\t\t\nf2\t\t\tf2-v1.1.0\t\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.1.0\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.1.0\t\t\t\t\t\tgithub.com/fatih/faillint@v1.1.0\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.0.0\t\t\t\t\t\tgithub.com/fatih/faillint@v1.0.0\t\t\t\t\t\t\t\t\ngo-bindata\tgo-bindata-v3.1.1+incompatible\t\t\tgithub.com/go-bindata/go-bindata/go-bindata@v3.1.1+incompatible\t\t\ngoimports\t\tgoimports-v0.0.0-20200522201501-cb1345f3a375\tgolang.org/x/tools/cmd/goimports@v0.0.0-20200522201501-cb1345f3a375\t\npromu\t\tpromu-v0.3.0\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.3.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.5.0\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.5.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.2.0\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.2.0", g.ExecOutput(t, p.root, goBinPath, "list")) + testutil.Equals(t, "Name\t\t\tBinary Name\t\t\t\t\t\t\tPackage @ Version\t\t\t\t\t\t\t\t\t\t\t\n----\t\t\t-----------\t\t\t\t\t\t\t-----------------\t\t\t\t\t\t\t\t\t\t\t\nf4\t\t\tf4-v1.1.0\t\t\t\t\t\t\t\tgithub.com/fatih/faillint@v1.1.0\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.1.0\t\t\t\t\t\tgithub.com/fatih/faillint@v1.1.0\t\t\t\t\t\t\t\t\nfaillint\t\tfaillint-v1.0.0\t\t\t\t\t\tgithub.com/fatih/faillint@v1.0.0\t\t\t\t\t\t\t\t\ngo-bindata\tgo-bindata-v3.1.1+incompatible\t\t\tgithub.com/go-bindata/go-bindata/go-bindata@v3.1.1+incompatible\t\t\ngoimports\t\tgoimports-v0.0.0-20200522201501-cb1345f3a375\tgolang.org/x/tools/cmd/goimports@v0.0.0-20200522201501-cb1345f3a375\t\npromu\t\tpromu-v0.3.0\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.3.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.5.0\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.5.0\t\t\t\t\t\t\t\t\npromu\t\tpromu-v0.2.0\t\t\t\t\t\t\tgithub.com/prometheus/promu@v0.2.0", g.ExecOutput(t, p.root, goBinPath, "list")) }, - existingBinaries: []string{"f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, + existingBinaries: []string{"f2-clone-v1.3.0", "f2-clone-v1.4.0", "f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "f3-v1.3.0", "f3-v1.4.0", "f4-v1.0.0", "f4-v1.1.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, }, { name: "Remove goimports by path", do: func(t *testing.T) { fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "golang.org/x/tools/cmd/goimports@none")) }, - existingBinaries: []string{"f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, + existingBinaries: []string{"f2-clone-v1.3.0", "f2-clone-v1.4.0", "f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "f3-v1.3.0", "f3-v1.4.0", "f4-v1.0.0", "f4-v1.1.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, }, { name: "Remove faillint by name", do: func(t *testing.T) { fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "faillint@none")) }, - existingBinaries: []string{"f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, + existingBinaries: []string{"f2-clone-v1.3.0", "f2-clone-v1.4.0", "f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "f3-v1.3.0", "f3-v1.4.0", "f4-v1.0.0", "f4-v1.1.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, }, { - name: "Remove f2 by name", + name: "Remove f4 by name", do: func(t *testing.T) { - fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "f2@none")) + fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "f4@none")) }, - existingBinaries: []string{"f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, + existingBinaries: []string{"f2-clone-v1.3.0", "f2-clone-v1.4.0", "f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "f3-v1.3.0", "f3-v1.4.0", "f4-v1.0.0", "f4-v1.1.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, }, { name: "Remove promu by name", do: func(t *testing.T) { fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "promu@none")) }, - existingBinaries: []string{"f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, + existingBinaries: []string{"f2-clone-v1.3.0", "f2-clone-v1.4.0", "f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "f3-v1.3.0", "f3-v1.4.0", "f4-v1.0.0", "f4-v1.1.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, }, { name: "Remove go-bindata by name", @@ -243,7 +324,7 @@ func TestGet(t *testing.T) { fmt.Println(g.ExecOutput(t, p.root, goBinPath, "get", "go-bindata@none")) testutil.Equals(t, "Name\tBinary Name\tPackage @ Version\t\n----\t-----------\t-----------------", g.ExecOutput(t, p.root, goBinPath, "list")) }, - existingBinaries: []string{"f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, + existingBinaries: []string{"f2-clone-v1.3.0", "f2-clone-v1.4.0", "f2-v1.0.0", "f2-v1.1.0", "f2-v1.2.0", "f2-v1.3.0", "f2-v1.4.0", "f2-v1.5.0", "f3-v1.3.0", "f3-v1.4.0", "f4-v1.0.0", "f4-v1.1.0", "faillint-v1.0.0", "faillint-v1.1.0", "faillint-v1.3.0", "faillint-v1.4.0", "faillint-v1.5.0", "go-bindata-v3.1.1+incompatible", "goimports-v0.0.0-20200521211927-2b542361a4fc", "goimports-v0.0.0-20200522201501-cb1345f3a375", "goimports2-v0.0.0-20200515010526-7d3b6ebf133d", "goimports2-v0.0.0-20200519175826-7521f6f42533", "promu-v0.2.0", "promu-v0.3.0", "promu-v0.5.0"}, }, } { if ok := t.Run(tcase.name, func(t *testing.T) { @@ -566,6 +647,8 @@ func (g *goEnv) syntheticEnv() []string { return []string{ // Make sure we don't require clang to build etc. fmt.Sprintf("CGO_ENABLED=0"), + // Cache all in memory using athens (make sure runAthensCache function is invoked before test). + fmt.Sprintf("GOPROXY=http://localhost:3000"), fmt.Sprintf("PATH=%s:%s:%s", g.goroot, g.tmpDir, g.gobin), fmt.Sprintf("GO=%s", filepath.Join(g.goroot, "go")), fmt.Sprintf("GOBIN=%s", g.gobin), diff --git a/main.go b/main.go index 5b115c9..0bbc902 100644 --- a/main.go +++ b/main.go @@ -44,7 +44,10 @@ func main() { " does not exist bingo logs and assumes a fresh project.") getName := getFlags.String("n", "", "The -n flag instructs to get binary and name it with given name instead of default,"+ " so the last element of package directory. Allowed characters [A-z0-9._-]. If -n is used and no package/binary is specified,"+ - " bingo get will return error. If -n is used with existing binary name, rename will be done.") + " bingo get will return error. If -n is used with existing binary name, copy of this binary will be done. Cannot be used with -r") + getRename := getFlags.String("r", "", "The -r flag instructs to get existing binary and rename it with given name."+ + " Allowed characters [A-z0-9._-]. If -r is used and no package/binary is specified or non existing binary name is used, bingo"+ + " will return error. Cannot be used with -n.") goCmd := getFlags.String("go", "go", "Path to the go command.") getUpdate := getFlags.Bool("u", false, "The -u flag instructs get to update modules providing dependencies of packages named on the command line to use newer minor or patch releases when available.") getUpdatePatch := getFlags.Bool("upatch", false, "The -upatch flag (not -u patch) also instructs get to update dependencies, but changes the default to select patch releases.") @@ -115,9 +118,15 @@ func main() { } target := getFlags.Arg(0) + if *getRename != "" && *getName != "" { + exitOnUsageError(flags.Usage, "Both -n and -r were specified. You can either rename or create new one.") + } if *getName != "" && !regexp.MustCompile(`[a-zA-Z0-9.-_]+`).MatchString(*getName) { exitOnUsageError(flags.Usage, *getName, "-n name contains not allowed characters") } + if *getRename != "" && !regexp.MustCompile(`[a-zA-Z0-9.-_]+`).MatchString(*getRename) { + exitOnUsageError(flags.Usage, *getRename, "-r name contains not allowed characters") + } cmdFunc = func(ctx context.Context, r *runner.Runner) error { relModDir := *getModDir @@ -134,6 +143,7 @@ func main() { relModDir: relModDir, update: upPolicy, name: *getName, + rename: *getRename, rawTarget: target, }); err != nil { return err @@ -216,7 +226,7 @@ func main() { { ctx, cancel := context.WithCancel(context.Background()) g.Add(func() error { - r, err := runner.NewRunner(ctx, logger, *getInsecure, *goCmd) + r, err := runner.NewRunner(ctx, *getInsecure, *goCmd) if err != nil { return err } diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index ffd8816..6e20920 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -7,7 +7,7 @@ import ( "bytes" "context" "fmt" - "log" + "io" "os" "os/exec" "path/filepath" @@ -18,30 +18,33 @@ import ( // Runner allows to run certain commands against module aware Go CLI. type Runner struct { - logger *log.Logger - goCmd string insecure bool verbose bool + + stdout, stderr io.Writer + output *bytes.Buffer } // NewRunner checks Go version compatibility then returns Runner. -func NewRunner(ctx context.Context, logging *log.Logger, insecure bool, goCmd string) (*Runner, error) { +func NewRunner(ctx context.Context, insecure bool, goCmd string) (*Runner, error) { + output := &bytes.Buffer{} r := &Runner{ - logger: logging, goCmd: goCmd, insecure: insecure, + stdout: output, + stderr: output, + output: output, } - ver, err := r.execGo(ctx, "", "", "version") - if err != nil { + if err := r.execGo(ctx, "", "", "version"); err != nil { return nil, errors.Wrap(err, "exec go to detect the version") } // TODO(bwplotka): Make it more robust and accept newer Go. - if !strings.HasPrefix(ver, "go version go1.14.") { - return nil, errors.Errorf("found unsupported go version: %v. Requires go1.14.x", ver) + if !strings.HasPrefix(strings.TrimRight(r.output.String(), "\n"), "go version go1.14.") { + return nil, errors.Errorf("found unsupported go version: %v. Requires go1.14.x", output.String()) } return r, nil } @@ -58,7 +61,7 @@ var cmdsSupportingModFileArg = map[string]struct{}{ "build": {}, } -func (r *Runner) execGo(ctx context.Context, cd string, modFile string, args ...string) (string, error) { +func (r *Runner) execGo(ctx context.Context, cd string, modFile string, args ...string) error { if modFile != "" { for i, arg := range args { if _, ok := cmdsSupportingModFileArg[arg]; ok { @@ -74,28 +77,29 @@ func (r *Runner) execGo(ctx context.Context, cd string, modFile string, args ... return r.exec(ctx, cd, r.goCmd, args...) } -func (r *Runner) exec(ctx context.Context, cd string, command string, args ...string) (string, error) { +func (r *Runner) exec(ctx context.Context, cd string, command string, args ...string) error { + r.output.Truncate(0) + cmd := exec.CommandContext(ctx, command, args...) cmd.Dir = filepath.Join(cmd.Dir, cd) + // TODO(bwplotka): Might be surpring, let's return err when this env variable is altered. cmd.Env = append(os.Environ(), "GO111MODULE=on") - var b bytes.Buffer - cmd.Stdout = &b - cmd.Stderr = &b - + cmd.Stdout = r.stdout + cmd.Stderr = r.stderr if err := cmd.Run(); err != nil { if _, ok := err.(*exec.ExitError); ok { if r.verbose { - return "", errors.Errorf("error while running command '%s %s'; out: %s; err: %v", command, strings.Join(args, " "), b.String(), err) + return errors.Errorf("error while running command '%s %s'; out: %s; err: %v", command, strings.Join(args, " "), r.output.String(), err) } - return "", errors.New(b.String()) + return errors.New(r.output.String()) } - return "", errors.Errorf("error while running command '%s %s'; out: %s; err: %v", command, strings.Join(args, " "), b.String(), err) + return errors.Errorf("error while running command '%s %s'; out: %s; err: %v", command, strings.Join(args, " "), r.output.String(), err) } if r.verbose { fmt.Printf("exec '%s %s'\n", command, strings.Join(args, " ")) } - return strings.TrimRight(b.String(), "\n"), nil + return nil } type Runnable interface { @@ -121,6 +125,7 @@ func (r *Runner) With(ctx context.Context, modFile string, dir string) Runnable dir: dir, ctx: ctx, } + ru.enableOSStdOutput(true) return ru } @@ -132,15 +137,31 @@ const ( UpdatePatchPolicy = GetUpdatePolicy("-u=patch") ) +func (r *runnable) enableOSStdOutput(enable bool) { + if enable { + r.r.stdout = io.MultiWriter(r.r.output, os.Stdout) + r.r.stderr = io.MultiWriter(r.r.output, os.Stderr) + return + } + r.r.stdout = r.r.output + r.r.stderr = r.r.output +} + // ModInit runs `go mod init` against separate go modules files if any. REMOVE func (r *runnable) ModInit(moduleName string) error { - _, err := r.r.execGo(r.ctx, r.dir, r.modFile, append([]string{"mod", "init"}, moduleName)...) - return err + r.enableOSStdOutput(false) + defer r.enableOSStdOutput(true) + + return r.r.execGo(r.ctx, r.dir, r.modFile, append([]string{"mod", "init"}, moduleName)...) } // List runs `go list` against separate go modules files if any. func (r *runnable) List(args ...string) (string, error) { - return r.r.execGo(r.ctx, r.dir, r.modFile, append([]string{"list"}, args...)...) + r.enableOSStdOutput(false) + defer r.enableOSStdOutput(true) + + err := r.r.execGo(r.ctx, r.dir, r.modFile, append([]string{"list"}, args...)...) + return strings.TrimRight(r.r.output.String(), "\n"), err } // GetD runs 'go get -d' against separate go modules file with given arguments. @@ -152,9 +173,7 @@ func (r *runnable) GetD(update GetUpdatePolicy, packages ...string) error { if update != NoUpdatePolicy { args = append(args, string(update)) } - out, err := r.r.execGo(r.ctx, r.dir, r.modFile, append(args, packages...)...) - r.r.logger.Print(out) - return err + return r.r.execGo(r.ctx, r.dir, r.modFile, append(args, packages...)...) } // Build runs 'go build' against separate go modules file with given packages. @@ -166,7 +185,7 @@ func (r *runnable) Build(pkg, outPath string) error { outPath = filepath.Join(binPath, outPath) // go install does not define -o so we mimic go install with go build instead. - out, err := r.r.execGo( + return r.r.execGo( r.ctx, r.dir, r.modFile, @@ -174,6 +193,4 @@ func (r *runnable) Build(pkg, outPath string) error { []string{"build", "-i", "-o=" + outPath}, pkg, )..., ) - r.r.logger.Print(out) - return err }