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

Add commands to help add tools to the configuration #5

Merged
merged 3 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .binny.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ tools:
module: .
entrypoint: cmd/binny
ldflags:
- -X main.version={{ .Version }}
- -X main.gitCommit={{ .Version }}
- -X main.gitDescription={{ .Version }}
# note: sprig functions are available: http://masterminds.github.io/sprig/
- -X main.buildDate={{ now | date "2006-01-02T15:04:05Z07:00" }}
- -X main.version={{ .Version }}
- -X main.gitCommit={{ .Version }}
- -X main.gitDescription={{ .Version }}
# note: sprig functions are available: http://masterminds.github.io/sprig/
- -X main.buildDate={{ now | date "2006-01-02T15:04:05Z07:00" }}

- name: gh
version:
Expand Down
1 change: 1 addition & 0 deletions cmd/binny/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func New(id clio.Identification) clio.Application {

root.AddCommand(
clio.VersionCommand(id),
command.Add(app),
command.Install(app),
command.Check(app),
command.Run(app),
Expand Down
21 changes: 21 additions & 0 deletions cmd/binny/cli/command/add.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package command

import (
"github.com/spf13/cobra"

"github.com/anchore/clio"
)

func Add(app clio.Application) *cobra.Command {
cmd := app.SetupCommand(&cobra.Command{
Use: "add",
Short: "Add a new tool to the configuration",
})

cmd.AddCommand(
AddGoInstall(app),
AddGithubRelease(app),
)

return cmd
}
100 changes: 100 additions & 0 deletions cmd/binny/cli/command/add_github_release.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package command

import (
"fmt"
"strings"

"github.com/scylladb/go-set/strset"
"github.com/spf13/cobra"

"github.com/anchore/binny/cmd/binny/cli/internal/yamlpatch"
"github.com/anchore/binny/cmd/binny/cli/option"
"github.com/anchore/binny/internal/log"
"github.com/anchore/binny/tool/githubrelease"
"github.com/anchore/clio"
)

type AddGithubReleaseConfig struct {
Config string `json:"config" yaml:"config" mapstructure:"config"`
option.Core `json:"" yaml:",inline" mapstructure:",squash"`

VersionResolution option.VersionResolution `json:"version-resolver" yaml:"version-resolver" mapstructure:"version-resolver"`
}

func AddGithubRelease(app clio.Application) *cobra.Command {
cfg := &AddGithubReleaseConfig{
Core: option.DefaultCore(),
}

return app.SetupCommand(&cobra.Command{
Use: "github-release OWNER/REPO@VERSION",
Short: "Add a new tool configuration that sources binaries from GitHub releases",
Args: cobra.ExactArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) error {
if !strings.Contains(args[0], "/") {
return fmt.Errorf("invalid 'owner/project@version' format: %q", args[0])
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
return runGithubReleaseConfig(*cfg, args[0])
},
}, cfg)
}

func runGithubReleaseConfig(cmdCfg AddGithubReleaseConfig, repoVersion string) error {
fields := strings.Split(repoVersion, "@")
var repo, name, version string

switch len(fields) {
case 1:
repo = repoVersion
version = "latest"
case 2:
repo = fields[0]
version = fields[1]
default:
return fmt.Errorf("invalid owner/project@version format: %s", repoVersion)
}

fields = strings.Split(repo, "/")
if len(fields) != 2 {
return fmt.Errorf("invalid owner/project format: %s", repo)
}

name = fields[1]

if strset.New(cmdCfg.Tools.Names()...).Has(name) {
// TODO: should this be an error?
log.Warnf("tool %q already configured", name)
return nil
}

vCfg := cmdCfg.VersionResolution

coreInstallParams := githubrelease.InstallerParameters{
Repo: repo,
}

installParamMap, err := toMap(coreInstallParams)
if err != nil {
return fmt.Errorf("unable to encode install params: %w", err)
}

installMethod := githubrelease.InstallMethod

log.WithFields("name", name, "version", version, "method", installMethod).Info("adding tool")

toolCfg := option.Tool{
Name: name,
Version: option.ToolVersionConfig{
Want: version,
Constraint: vCfg.Constraint,
ResolveMethod: vCfg.Method,
},
InstallMethod: installMethod,
Parameters: installParamMap,
}

return yamlpatch.Write(cmdCfg.Config, yamlToolAppender{toolCfg: toolCfg})
}
106 changes: 106 additions & 0 deletions cmd/binny/cli/command/add_go_install.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package command

import (
"fmt"
"strings"

"github.com/google/shlex"
"github.com/scylladb/go-set/strset"
"github.com/spf13/cobra"

"github.com/anchore/binny/cmd/binny/cli/internal/yamlpatch"
"github.com/anchore/binny/cmd/binny/cli/option"
"github.com/anchore/binny/internal/log"
"github.com/anchore/binny/tool/goinstall"
"github.com/anchore/clio"
)

type AddGoInstallConfig struct {
Config string `json:"config" yaml:"config" mapstructure:"config"`
option.Core `json:"" yaml:",inline" mapstructure:",squash"`

// CLI options
Install struct {
GoInstall option.GoInstall `json:"go-install" yaml:"go-install" mapstructure:"go-install"`
} `json:"install" yaml:"install" mapstructure:"install"`

VersionResolution option.VersionResolution `json:"version-resolver" yaml:"version-resolver" mapstructure:"version-resolver"`
}

func AddGoInstall(app clio.Application) *cobra.Command {
cfg := &AddGoInstallConfig{
Core: option.DefaultCore(),
}

return app.SetupCommand(&cobra.Command{
Use: "go-install NAME@VERSION --module GOMODULE [--entrypoint PATH] [--ldflags FLAGS]",
Short: "Add a new tool configuration from 'go install ...' invocations",
Args: cobra.ExactArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) error {
if cfg.Install.GoInstall.Module == "" {
return fmt.Errorf("go-install configuration requires '--module' option")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
return runAddGoInstallConfig(*cfg, args[0])
},
}, cfg)
}

func runAddGoInstallConfig(cmdCfg AddGoInstallConfig, nameVersion string) error {
fields := strings.Split(nameVersion, "@")
var name, version string

switch len(fields) {
case 1:
name = nameVersion
case 2:
name = fields[0]
version = fields[1]
default:
return fmt.Errorf("invalid name@version format: %s", nameVersion)
}

if strset.New(cmdCfg.Tools.Names()...).Has(name) {
// TODO: should this be an error?
log.Warnf("tool %q already configured", name)
return nil
}

iCfg := cmdCfg.Install.GoInstall
vCfg := cmdCfg.VersionResolution

ldFlagsList, err := shlex.Split(iCfg.LDFlags)
if err != nil {
return fmt.Errorf("invalid ldflags: %w", err)
}

coreInstallParams := goinstall.InstallerParameters{
Module: iCfg.Module,
Entrypoint: iCfg.Entrypoint,
LDFlags: ldFlagsList,
}

installParamMap, err := toMap(coreInstallParams)
if err != nil {
return fmt.Errorf("unable to encode install params: %w", err)
}

installMethod := goinstall.InstallMethod

log.WithFields("name", name, "version", version, "method", installMethod).Info("adding tool")

toolCfg := option.Tool{
Name: name,
Version: option.ToolVersionConfig{
Want: version,
Constraint: vCfg.Constraint,
ResolveMethod: vCfg.Method,
},
InstallMethod: installMethod,
Parameters: installParamMap,
}

return yamlpatch.Write(cmdCfg.Config, yamlToolAppender{toolCfg: toolCfg})
}
6 changes: 3 additions & 3 deletions cmd/binny/cli/command/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import (
)

type CheckConfig struct {
Config string `json:"config" yaml:"config" mapstructure:"config"`
option.AppConfig `json:"" yaml:",inline" mapstructure:",squash"`
Config string `json:"config" yaml:"config" mapstructure:"config"`
option.Core `json:"" yaml:",inline" mapstructure:",squash"`
}

func Check(app clio.Application) *cobra.Command {
cfg := &CheckConfig{
AppConfig: option.DefaultAppConfig(),
Core: option.DefaultCore(),
}

var names []string
Expand Down
6 changes: 3 additions & 3 deletions cmd/binny/cli/command/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import (
)

type InstallConfig struct {
Config string `json:"config" yaml:"config" mapstructure:"config"`
option.AppConfig `json:"" yaml:",inline" mapstructure:",squash"`
Config string `json:"config" yaml:"config" mapstructure:"config"`
option.Core `json:"" yaml:",inline" mapstructure:",squash"`
}

func Install(app clio.Application) *cobra.Command {
cfg := &InstallConfig{
AppConfig: option.DefaultAppConfig(),
Core: option.DefaultCore(),
}

var names []string
Expand Down
6 changes: 3 additions & 3 deletions cmd/binny/cli/command/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ import (
)

type RunConfig struct {
Config string `json:"config" yaml:"config" mapstructure:"config"`
option.AppConfig `json:"" yaml:",inline" mapstructure:",squash"`
Config string `json:"config" yaml:"config" mapstructure:"config"`
option.Core `json:"" yaml:",inline" mapstructure:",squash"`
}

func Run(app clio.Application) *cobra.Command {
cfg := &RunConfig{
AppConfig: option.DefaultAppConfig(),
Core: option.DefaultCore(),
}

return app.SetupCommand(&cobra.Command{
Expand Down
Loading