Skip to content

Commit

Permalink
Added athena for test caching; fixed output; added rename/clone logic.
Browse files Browse the repository at this point in the history
Signed-off-by: Bartlomiej Plotka <bwplotka@gmail.com>
  • Loading branch information
bwplotka committed Jun 9, 2020
1 parent 090913b commit bf0e447
Show file tree
Hide file tree
Showing 10 changed files with 305 additions and 149 deletions.
16 changes: 11 additions & 5 deletions .bingo/Variables.mk
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
# 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
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) <flags/args..>
#command: $(ATHENS_PROXY)
# @echo "Running athens-proxy"
# @$(ATHENS_PROXY) <flags/args..>
#
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.
Expand Down
5 changes: 5 additions & 0 deletions .bingo/athens-proxy.mod
Original file line number Diff line number Diff line change
@@ -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
18 changes: 10 additions & 8 deletions .bingo/variables.env
Original file line number Diff line number Diff line change
@@ -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"

2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
202 changes: 113 additions & 89 deletions get.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"os"
"path"
"path/filepath"
"strconv"
"strings"
"time"

Expand All @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit bf0e447

Please sign in to comment.