feat: add init command

This commit is contained in:
Kevin Franklin Kim 2023-01-04 16:36:25 +01:00
parent 8ae6b7ba33
commit 14b23c1edf
30 changed files with 523 additions and 239 deletions

View File

@ -1,7 +1,8 @@
package cmd
import (
"github.com/foomo/posh/internal/util"
intconfig "github.com/foomo/posh/internal/config"
intplugin "github.com/foomo/posh/internal/plugin"
"github.com/foomo/posh/pkg/config"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@ -11,15 +12,21 @@ import (
var dependenciesCmd = &cobra.Command{
Use: "dependencies",
Short: "Run dependency validations",
SilenceErrors: true,
SilenceUsage: true,
SilenceErrors: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := intconfig.Load(l, flagConfig); err != nil {
return err
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
var cfg config.Dependencies
if err := viper.UnmarshalKey("dependencies", &cfg); err != nil {
return err
}
plg, err := util.LoadPlugin(cmd.Context(), m)
plg, err := intplugin.Load(cmd.Context(), l)
if err != nil {
return err
}

View File

@ -1,22 +1,31 @@
package cmd
import (
"github.com/foomo/posh/internal/util"
intconfig "github.com/foomo/posh/internal/config"
intplugin "github.com/foomo/posh/internal/plugin"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
// execCmd represents the exec command
var execCmd = &cobra.Command{
Use: "execute",
Short: "Execute a single Project Oriented Shell command",
Args: cobra.ArbitraryArgs,
Use: "execute",
Short: "Execute a single Project Oriented Shell command",
Args: cobra.ArbitraryArgs,
SilenceUsage: true,
SilenceErrors: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := intconfig.Load(l, flagConfig); err != nil {
return err
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errors.New("missing [cmd] argument")
}
plg, err := util.LoadPlugin(cmd.Context(), m)
plg, err := intplugin.Load(cmd.Context(), l)
if err != nil {
return err
}

View File

@ -2,16 +2,22 @@ package cmd
import (
"os"
"path/filepath"
"path"
"github.com/foomo/posh/embed"
"github.com/foomo/posh/internal/util"
"github.com/foomo/posh/pkg/env"
"github.com/foomo/posh/pkg/scaffold"
"github.com/spf13/cobra"
)
var (
initCmdFlagDry bool
)
// initCmd represents the init command
var initCmd = &cobra.Command{
Use: "init [path]",
Use: "init",
Short: "Initialize a Project Oriented Shell",
Long: `Initialize (posh init) will create a new Project Oriented Shell with the appropriate structure.
@ -19,13 +25,13 @@ Posh init must be run inside of a go module (please run "go mod init <MODNAME> f
SilenceErrors: true,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
wd, err := os.Getwd()
if err != nil {
return err
}
data := map[string]interface{}{}
if len(args) > 0 && args[0] != "." {
wd = filepath.Join(wd, args[0])
// define module
if gitRemoteURL, err := util.GitRemoteURL(); err == nil {
data["module"] = gitRemoteURL
} else {
data["module"] = path.Base(os.Getenv(env.ProjectRoot))
}
fs, err := embed.Scaffold("init")
@ -35,15 +41,22 @@ Posh init must be run inside of a go module (please run "go mod init <MODNAME> f
sc, err := scaffold.New(
scaffold.WithLogger(l),
scaffold.WithDry(initCmdFlagDry),
scaffold.WithDirectories(scaffold.Directory{
Source: fs,
Target: os.Getenv(env.ProjectRoot),
Data: data,
}),
)
if err != nil {
return err
}
return sc.Render(fs, wd, nil)
return sc.Render(cmd.Context())
},
}
func init() {
rootCmd.AddCommand(initCmd)
initCmd.Flags().BoolVar(&initCmdFlagDry, "dry", false, "don't render files")
}

View File

@ -1,7 +1,8 @@
package cmd
import (
"github.com/foomo/posh/internal/util"
intconfig "github.com/foomo/posh/internal/config"
intplugin "github.com/foomo/posh/internal/plugin"
"github.com/foomo/posh/pkg/config"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@ -11,15 +12,21 @@ import (
var packagesCmd = &cobra.Command{
Use: "packages",
Short: "Check and install required packages.",
SilenceErrors: true,
SilenceUsage: true,
SilenceErrors: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := intconfig.Load(l, flagConfig); err != nil {
return err
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
var cfg []config.Package
if err := viper.UnmarshalKey("packages", &cfg); err != nil {
return err
}
plg, err := util.LoadPlugin(cmd.Context(), m)
plg, err := intplugin.Load(cmd.Context(), l)
if err != nil {
return err
}

View File

@ -1,7 +1,8 @@
package cmd
import (
"github.com/foomo/posh/internal/util"
intconfig "github.com/foomo/posh/internal/config"
intplugin "github.com/foomo/posh/internal/plugin"
"github.com/foomo/posh/pkg/config"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@ -11,15 +12,21 @@ import (
var promptCmd = &cobra.Command{
Use: "prompt",
Short: "Start the interactive Project Oriented Shell",
SilenceErrors: true,
SilenceUsage: true,
SilenceErrors: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := intconfig.Load(l, flagConfig); err != nil {
return err
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
var cfg config.Prompt
if err := viper.UnmarshalKey("prompt", &cfg); err != nil {
return err
}
plg, err := util.LoadPlugin(cmd.Context(), m)
plg, err := intplugin.Load(cmd.Context(), l)
if err != nil {
return err
}

View File

@ -2,25 +2,18 @@ package cmd
import (
"context"
"fmt"
"os"
"os/signal"
"strings"
"github.com/foomo/posh/internal/env"
log2 "github.com/foomo/posh/internal/log"
"github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/plugin"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const (
EnvProjectRoot = "PROJECT_ROOT"
)
var (
l log.Logger
m *plugin.Manager
flagLevel string
flagConfig string
flagNoColor bool
@ -65,69 +58,19 @@ func Execute() {
func init() {
cobra.OnInitialize(initialize)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
rootCmd.PersistentFlags().BoolVar(&flagNoColor, "no-color", false, "disabled colors (default is false)")
rootCmd.PersistentFlags().StringVar(&flagLevel, "level", "info", "set log level (default is warn)")
rootCmd.PersistentFlags().StringVar(&flagConfig, "config", "", "config file (default is $HOME/.posh.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().Bool("no-validate", false, "Skip validation")
}
// initialize reads in config file and ENV variables if set.
func initialize() {
// setup logger
if value, err := log.NewPTerm(
log.PTermWithDisableColor(flagNoColor),
log.PTermWithLevel(log.GetLevel(flagLevel)),
); err != nil {
cobra.CheckErr(err)
} else {
l = value
}
// setup viper
if flagConfig != "" {
// Use config file from the flag.
viper.SetConfigFile(flagConfig)
} else {
wd, err := os.Getwd()
l.Must(err)
viper.AddConfigPath(wd)
viper.SetConfigType("yaml")
viper.SetConfigName(".posh")
}
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
l.Must(viper.ReadInConfig())
l.Debug("using config file:", viper.ConfigFileUsed())
// validate version
if v := viper.GetString("version"); v != "v1.0" {
l.Must(fmt.Errorf("invalid config version: %s (v1.0)", v))
}
// setup env
if value := os.Getenv(EnvProjectRoot); value != "" {
// continue
} else if value, err := os.Getwd(); err != nil {
l.Must(errors.Wrap(err, "failed to retrieve project root"))
} else if err := os.Setenv(EnvProjectRoot, value); err != nil {
l.Must(errors.Wrap(err, "failed to set project root env"))
}
for key, value := range viper.GetStringMapString("env") {
l.Must(os.Setenv(key, os.ExpandEnv(value)))
}
// setup manager
var err error
m, err = plugin.NewManager(l)
l.Must(err)
// init logger
l, err = log2.Init(flagLevel, flagNoColor)
cobra.CheckErr(err)
// init env
l.Must(env.Init())
}

View File

@ -0,0 +1,3 @@
module {{ .module }}/posh
go 1.19

View File

@ -0,0 +1,52 @@
.DEFAULT_GOAL:=help
## === Tasks ===
.PHONY: dependencies
## Validate dependencies
dependencies:
@posh dependencies
.PHONY: shell
## Install project specific packages
packages:
@posh packages
.PHONY: shell
## Start the interactive
shell: dependencies packages
@posh prompt
## === Utils ===
## Show help text
help:
@awk '{ \
if ($$0 ~ /^.PHONY: [a-zA-Z\-\_0-9]+$$/) { \
helpCommand = substr($$0, index($$0, ":") + 2); \
if (helpMessage) { \
printf "\033[36m%-23s\033[0m %s\n", \
helpCommand, helpMessage; \
helpMessage = ""; \
} \
} else if ($$0 ~ /^[a-zA-Z\-\_0-9.]+:/) { \
helpCommand = substr($$0, 0, index($$0, ":")); \
if (helpMessage) { \
printf "\033[36m%-23s\033[0m %s\n", \
helpCommand, helpMessage"\n"; \
helpMessage = ""; \
} \
} else if ($$0 ~ /^##/) { \
if (helpMessage) { \
helpMessage = helpMessage"\n "substr($$0, 3); \
} else { \
helpMessage = substr($$0, 3); \
} \
} else { \
if (helpMessage) { \
print "\n "helpMessage"\n" \
} \
helpMessage = ""; \
} \
}' \
$(MAKEFILE_LIST)

View File

@ -2,9 +2,19 @@
## === Tasks ===
.PHONY: posh
posh:
.PHONY: dependencies
## Validate dependencies
dependencies:
@posh dependencies
.PHONY: shell
## Install project specific packages
packages:
@posh packages
.PHONY: shell
## Start the interactive
shell: dependencies packages
@posh prompt
## === Utils ===

View File

@ -1,9 +0,0 @@
package main
import (
"fmt"
)
func main() {
fmt.Println("hello")
}

19
go.mod
View File

@ -8,20 +8,29 @@ require (
github.com/Masterminds/sprig/v3 v3.2.3
github.com/c-bata/go-prompt v0.2.6
github.com/foomo/fender v0.4.4
github.com/go-git/go-git/v5 v5.5.1
github.com/gofrs/flock v0.8.1
github.com/joho/godotenv v1.4.0
github.com/pkg/errors v0.9.1
github.com/pterm/pterm v0.12.51
github.com/spf13/cobra v1.6.1
github.com/spf13/viper v1.14.0
github.com/whilp/git-urls v1.0.0
)
require (
atomicgo.dev/cursor v0.1.1 // indirect
atomicgo.dev/keyboard v0.2.8 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/cloudflare/circl v1.1.0 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.0 // indirect
@ -29,8 +38,10 @@ require (
github.com/gookit/color v1.5.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.11 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lithammer/fuzzysearch v1.1.5 // indirect
github.com/magiconair/properties v1.8.6 // indirect
@ -44,9 +55,12 @@ require (
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pjbgf/sha1cd v0.2.3 // indirect
github.com/pkg/term v1.1.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/skeema/knownhosts v1.1.0 // indirect
github.com/spf13/afero v1.9.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
@ -54,13 +68,16 @@ require (
github.com/subosito/gotenv v1.4.1 // indirect
github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/crypto v0.3.0 // indirect
golang.org/x/net v0.2.0 // indirect
golang.org/x/sys v0.2.0 // indirect
golang.org/x/term v0.2.0 // indirect
golang.org/x/text v0.4.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

61
go.sum
View File

@ -61,13 +61,26 @@ github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7Y
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 h1:ra2OtmuW0AE5csawV4YXMNGNQQXvLRps3z2Z59OPO+I=
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8=
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY=
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@ -78,6 +91,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@ -92,6 +107,16 @@ github.com/franklinkim/go-prompt v0.2.7-0.20210427061716-a8f4995d7aa5 h1:kXNtle4
github.com/franklinkim/go-prompt v0.2.7-0.20210427061716-a8f4995d7aa5/go.mod h1:+syUfnvYJUO5A+6QMQYXAyzkxHMNlj9dH2LIeQfBSjc=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ=
github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
github.com/go-git/go-git/v5 v5.5.1 h1:5vtv2TB5PM/gPM+EvsHJ16hJh4uAkdGcKilcwY7FYwo=
github.com/go-git/go-git/v5 v5.5.1/go.mod h1:uz5PQ3d0gz7mSgzZhSJToM6ALPaKCdSnl58/Xb5hzr8=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@ -143,6 +168,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@ -176,15 +202,21 @@ github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
@ -205,6 +237,8 @@ github.com/lithammer/fuzzysearch v1.1.5 h1:Ag7aKU08wp0R9QCfF4GoGST9HbmAIeLP7xwMr
github.com/lithammer/fuzzysearch v1.1.5/go.mod h1:1R1LRNk7yKid1BaQkmuLQaHruxcC4HmAH30Dh61Ih1Q=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
@ -234,6 +268,8 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
github.com/pjbgf/sha1cd v0.2.3 h1:uKQP/7QOzNtKYH7UTohZLcjF5/55EnTw0jO/Ru4jZwI=
github.com/pjbgf/sha1cd v0.2.3/go.mod h1:HOK9QrgzdHpbc2Kzip0Q1yi3M2MFGPADtR6HjG65m5M=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -259,10 +295,14 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0=
github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag=
github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw=
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@ -294,6 +334,10 @@ github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaO
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/whilp/git-urls v1.0.0 h1:95f6UMWN5FKW71ECsXRUd3FVYiXdrE7aX4NZKcPmIjU=
github.com/whilp/git-urls v1.0.0/go.mod h1:J16SAmobsqc3Qcy98brfl5f5+e0clUvg1krgwk/qCfE=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -318,6 +362,9 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -391,6 +438,8 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -424,6 +473,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -451,6 +501,7 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -458,10 +509,14 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -469,6 +524,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -639,6 +695,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -646,6 +704,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -65,7 +65,7 @@ func New(l log.Logger, cache cache.Cache, opts ...Option) (*OnePassword, error)
}
}
if client, err := connect.NewClientFromEnvironment(); err != nil {
l.Debug("not able to create connect client", err.Error())
l.Debug("connect client:", err.Error())
} else {
inst.connect = client
}

View File

@ -1,55 +0,0 @@
package cli
import (
"encoding/json"
"os/exec"
"path"
"path/filepath"
"strings"
"github.com/spf13/cobra"
)
type (
Mod struct {
Path, Dir, GoMod string
}
CurDir struct {
Dir string
}
)
func GetModImportPath() string {
mod, cd := parseModInfo()
return path.Join(mod.Path, fileToURL(strings.TrimPrefix(cd.Dir, mod.Dir)))
}
func parseModInfo() (Mod, CurDir) {
var mod Mod
var dir CurDir
m := modInfoJSON("-m")
cobra.CheckErr(json.Unmarshal(m, &mod))
// Unsure why, but if no module is present Path is set to this string.
if mod.Path == "command-line-arguments" {
cobra.CheckErr("Please run `go mod init <MODNAME>` before `cobra-cli init`")
}
e := modInfoJSON("-e")
cobra.CheckErr(json.Unmarshal(e, &dir))
return mod, dir
}
func fileToURL(in string) string {
i := strings.Split(in, string(filepath.Separator))
return path.Join(i...)
}
func modInfoJSON(args ...string) []byte {
cmdArgs := append([]string{"list", "-json"}, args...)
out, err := exec.Command("go", cmdArgs...).Output()
cobra.CheckErr(err)
return out
}

44
internal/config/load.go Normal file
View File

@ -0,0 +1,44 @@
package config
import (
"fmt"
"os"
"strings"
"github.com/foomo/posh/pkg/log"
"github.com/spf13/viper"
)
func Load(l log.Logger, configFile string) error {
// setup viper
if configFile != "" {
viper.SetConfigFile(configFile)
} else {
viper.AddConfigPath(".")
viper.SetConfigType("yaml")
viper.SetConfigName(".posh")
}
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil {
return err
} else {
l.Debug("using config file:", viper.ConfigFileUsed())
}
// validate version
if v := viper.GetString("version"); v != Version {
return fmt.Errorf("invalid config version: %s (%s)", v, Version)
}
// set configured env
for key, value := range viper.GetStringMapString("env") {
if err := os.Setenv(key, os.ExpandEnv(value)); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,3 @@
package config
const Version = "v1.0"

20
internal/env/init.go vendored Normal file
View File

@ -0,0 +1,20 @@
package env
import (
"os"
"github.com/foomo/posh/pkg/env"
"github.com/pkg/errors"
)
func Init() error {
// setup env
if value := os.Getenv(env.ProjectRoot); value != "" {
// continue
} else if wd, err := os.Getwd(); err != nil {
return errors.Wrap(err, "failed to retrieve project root")
} else if err := os.Setenv(env.ProjectRoot, wd); err != nil {
return errors.Wrap(err, "failed to set project root env")
}
return nil
}

16
internal/log/init.go Normal file
View File

@ -0,0 +1,16 @@
package log
import (
"github.com/foomo/posh/pkg/log"
)
func Init(level string, noColor bool) (log.Logger, error) {
if value, err := log.NewPTerm(
log.PTermWithDisableColor(noColor),
log.PTermWithLevel(log.GetLevel(level)),
); err != nil {
return nil, err
} else {
return value, nil
}
}

23
internal/plugin/load.go Normal file
View File

@ -0,0 +1,23 @@
package plugin
import (
"context"
"github.com/foomo/posh/pkg/config"
"github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/plugin"
"github.com/spf13/viper"
)
func Load(ctx context.Context, l log.Logger) (plugin.Plugin, error) {
m, err := manager(l)
if err != nil {
return nil, err
}
var cfg config.Plugin
if err := viper.UnmarshalKey("plugin", &cfg); err != nil {
return nil, err
}
return m.BuildAndLoadPlugin(ctx, cfg.Source, cfg.Provider)
}

View File

@ -0,0 +1,19 @@
package plugin
import (
"github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/plugin"
)
var m *plugin.Manager
func manager(l log.Logger) (*plugin.Manager, error) {
if m == nil {
if value, err := plugin.NewManager(l); err != nil {
return nil, err
} else {
m = value
}
}
return m, nil
}

View File

@ -1,17 +1,26 @@
package util
import (
"context"
"path"
"strings"
"github.com/foomo/posh/pkg/config"
"github.com/foomo/posh/pkg/plugin"
"github.com/spf13/viper"
"github.com/go-git/go-git/v5"
giturls "github.com/whilp/git-urls"
)
func LoadPlugin(ctx context.Context, m *plugin.Manager) (plugin.Plugin, error) {
var cfg config.Plugin
if err := viper.UnmarshalKey("plugin", &cfg); err != nil {
return nil, err
func GitRemoteURL() (string, error) {
r, err := git.PlainOpen(".")
if err != nil {
return "", err
}
if value, err := r.Remote("origin"); err != nil {
return "", err
} else if len(value.Config().URLs) == 0 {
return "", nil
} else if value, err := giturls.Parse(value.Config().URLs[0]); err != nil {
return "", err
} else {
return value.Hostname() + "/" + strings.TrimSuffix(value.Path, path.Ext(value.Path)), nil
}
return m.BuildAndLoadPlugin(ctx, cfg.Source, cfg.Provider)
}

3
pkg/env/env.go vendored Normal file
View File

@ -0,0 +1,3 @@
package env
const ProjectRoot = "PROJECT_ROOT"

View File

@ -9,21 +9,10 @@ import (
"plugin"
"strings"
"github.com/foomo/posh/pkg/config"
"github.com/foomo/posh/pkg/log"
"github.com/pkg/errors"
)
type (
Plugin interface {
Prompt(ctx context.Context, cfg config.Prompt) error
Execute(ctx context.Context, args []string) error
Packages(ctx context.Context, cfg []config.Package) error
Dependencies(ctx context.Context, cfg config.Dependencies) error
}
Provider func(l log.Logger) (Plugin, error)
)
type Manager struct {
l log.Logger
plugins map[string]*plugin.Plugin
@ -46,23 +35,34 @@ func NewManager(l log.Logger) (*Manager, error) {
// ------------------------------------------------------------------------------------------------
func (m *Manager) BuildAndLoadPlugin(ctx context.Context, filename, provider string) (Plugin, error) {
if err := m.Tidy(ctx, filename); err != nil {
return nil, err
}
if err := m.Build(ctx, filename); err != nil {
return nil, err
}
return m.LoadPlugin(filename, provider)
}
func (m *Manager) Tidy(ctx context.Context, filename string) error {
m.l.Debug("tidying:", filename)
cmd := exec.CommandContext(ctx, "go", "mod", "tidy")
cmd.Dir = filepath.Dir(filename)
if output, err := cmd.CombinedOutput(); err != nil {
return errors.Wrap(err, string(output))
}
return nil
}
func (m *Manager) Build(ctx context.Context, filename string) error {
m.l.Debug("building:", filename)
dir := filepath.Dir(filename)
base := path.Base(filename)
cmd := exec.CommandContext(ctx, "go", "build",
"-buildmode=plugin",
"-o", strings.ReplaceAll(base, ".go", ".so"),
base,
)
cmd.Dir = dir
cmd.Dir = filepath.Dir(filename)
if output, err := cmd.CombinedOutput(); err != nil {
return errors.Wrap(err, string(output))
}

14
pkg/plugin/plugin.go Normal file
View File

@ -0,0 +1,14 @@
package plugin
import (
"context"
"github.com/foomo/posh/pkg/config"
)
type Plugin interface {
Prompt(ctx context.Context, cfg config.Prompt) error
Execute(ctx context.Context, args []string) error
Packages(ctx context.Context, cfg []config.Package) error
Dependencies(ctx context.Context, cfg config.Dependencies) error
}

7
pkg/plugin/provider.go Normal file
View File

@ -0,0 +1,7 @@
package plugin
import (
"github.com/foomo/posh/pkg/log"
)
type Provider func(l log.Logger) (Plugin, error)

11
pkg/scaffold/directory.go Normal file
View File

@ -0,0 +1,11 @@
package scaffold
import (
"io/fs"
)
type Directory struct {
Source fs.FS
Target string
Data any
}

View File

@ -1,11 +1,10 @@
package scaffold
import (
"context"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"strings"
"text/template"
@ -16,9 +15,10 @@ import (
type (
Scaffold struct {
l log.Logger
dry bool
force bool
l log.Logger
dry bool
override bool
directories []Directory
}
Option func(*Scaffold) error
)
@ -34,9 +34,9 @@ func WithDry(v bool) Option {
}
}
func WithForce(v bool) Option {
func WithOverride(v bool) Option {
return func(o *Scaffold) error {
o.force = v
o.override = v
return nil
}
}
@ -48,15 +48,22 @@ func WithLogger(v log.Logger) Option {
}
}
func WithDirectories(v ...Directory) Option {
return func(o *Scaffold) error {
o.directories = append(o.directories, v...)
return nil
}
}
// ------------------------------------------------------------------------------------------------
// ~ Constructor
// ------------------------------------------------------------------------------------------------
func New(opts ...Option) (*Scaffold, error) {
inst := &Scaffold{
l: log.NewFmt(),
dry: false,
force: false,
l: log.NewFmt(),
dry: false,
override: false,
}
for _, opt := range opts {
if opt != nil {
@ -68,72 +75,117 @@ func New(opts ...Option) (*Scaffold, error) {
return inst, nil
}
func (s *Scaffold) Render(source fs.FS, target string, vars any) error {
// validate target
// ------------------------------------------------------------------------------------------------
// ~ Public methods
// ------------------------------------------------------------------------------------------------
func (s *Scaffold) Render(ctx context.Context) error {
if err := s.renderDirectories(); err != nil {
return err
}
return nil
}
// ------------------------------------------------------------------------------------------------
// ~ Private methods
// ------------------------------------------------------------------------------------------------
func (s *Scaffold) scaffoldDir(target string) error {
s.l.Info("mkdir:", s.filename(target))
if stat, err := os.Stat(target); errors.Is(err, os.ErrNotExist) {
s.l.Print("scaffold:", target)
if err := os.MkdirAll(target, os.ModePerm); err != nil {
return errors.Wrapf(err, "failed to create target folder (%s)", target)
return err
}
} else if err != nil {
return errors.Wrapf(err, "failed to stat target folder (%s)", target)
} else if !stat.IsDir() {
return fmt.Errorf("target not a directory (%s)", target)
}
return nil
}
// iterate source
if err := fs.WalkDir(source, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return errors.Wrapf(err, "failed to walk fs dir")
func (s *Scaffold) scaffoldTemplate(target string, tpl *template.Template, data any) error {
s.l.Info("file:", s.filename(target))
file, err := os.Create(target)
if err != nil {
return errors.Wrapf(err, "failed to create target file (%s)", target)
}
defer func() {
if err := file.Close(); err != nil {
s.l.Warnf("failed to close file: %s", err.Error())
}
}()
return tpl.Execute(file, data)
}
filename := filepath.Join(target, strings.ReplaceAll(path, "$", ""))
func (s *Scaffold) printTemplate(msg, target string, tpl *template.Template, data any) error {
border := strings.Repeat("-", 80)
s.l.Infof("%s\n%s: %s\n%s", border, msg, target, border)
return tpl.Execute(os.Stdout, data)
}
if path == "." {
func (s *Scaffold) renderDirectories() error {
for _, directory := range s.directories {
if err := s.renderDirectory(directory); err != nil {
return err
}
}
return nil
}
func (s *Scaffold) renderDirectory(directory Directory) error {
s.l.Info("scaffolding directory:", directory.Target)
if err := s.scaffoldDir(directory.Target); err != nil {
return err
}
if err := fs.WalkDir(directory.Source, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
} else if path == "." {
return nil
} else if d.IsDir() {
s.l.Print("scaffold:", filename)
return os.MkdirAll(filename, os.ModePerm)
return s.scaffoldDir(s.filename(path))
}
filename := s.filename(path)
tpl, err := template.New(d.Name()).Funcs(sprig.FuncMap()).ParseFS(directory.Source, path)
if err != nil {
return errors.Wrapf(err, "failed to parse source file (%s)", path)
}
if s.dry {
return s.printTemplate("file", filename, tpl, directory.Data)
} else if exists, err := s.fileExists(filename); err != nil {
return s.printTemplate(err.Error(), filename, tpl, directory.Data)
} else if exists && !s.override {
return s.printTemplate("file exists", filename, tpl, directory.Data)
} else {
tpl, err := template.New(d.Name()).Funcs(sprig.FuncMap()).ParseFS(source, path)
if err != nil {
return err
}
if stat, err := os.Stat(filename); errors.Is(err, fs.ErrNotExist) {
// all good
} else if err != nil {
return errors.Wrapf(err, "failed to stat target (%s)", filename)
} else if stat.IsDir() {
return fmt.Errorf("target file is an existing directory (%s)", filename)
} else if !s.force {
return fmt.Errorf("target file already exists (%s)", filename)
}
var out io.Writer
if s.dry {
out = os.Stdout
} else {
s.l.Print("scaffold:", filename)
if file, err := os.Create(filename); err != nil {
return errors.Wrapf(err, "failed to create target file (%s)", filename)
} else {
out = file
defer func() {
_ = file.Close()
}()
}
}
if err := tpl.Execute(out, vars); err != nil {
return errors.Wrapf(err, "failed to render target file (%s)", filename)
}
return nil
return s.scaffoldTemplate(filename, tpl, directory.Data)
}
}); err != nil {
return errors.Wrapf(err, "failed to render scaffold to %s", target)
return errors.Wrapf(err, "failed to render scaffold to %s", directory.Target)
}
return nil
}
func (s *Scaffold) fileExists(target string) (bool, error) {
if stat, err := os.Stat(target); errors.Is(err, fs.ErrNotExist) {
return false, nil
} else if err != nil {
return false, errors.Wrapf(err, "failed to stat target (%s)", target)
} else if stat.IsDir() {
return true, fmt.Errorf("target file is an existing directory (%s)", target)
} else {
return true, nil
}
}
func (s *Scaffold) filename(v string) string {
v = strings.ReplaceAll(v, "$", "")
v = strings.TrimSuffix(v, ".gotext")
v = strings.TrimSuffix(v, ".gohtml")
return v
}