diff --git a/.goreleaser.yml b/.goreleaser.yml index 4e527df..1671288 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -60,7 +60,7 @@ signs: checksum: name_template: "checksums.txt" snapshot: - name_template: '{{ trimprefix .Summary "v" }}' + version_template: '{{ trimprefix .Summary "v" }}' # We are skipping changelog because we are using semantic release changelog: disable: true diff --git a/pkg/commands/info/info.go b/pkg/commands/info/info.go index 8cafc76..91d0e18 100644 --- a/pkg/commands/info/info.go +++ b/pkg/commands/info/info.go @@ -24,15 +24,15 @@ func Execute(c *cli.Context) error { log.Infof(" arch: %s", runtime.GOARCH) fmt.Println("") log.Infof("configuration") - log.Infof(" home: %s", cfg.HomePath) + log.Infof(" home: %s", cfg.Path) log.Infof(" bin: %s", cfg.BinPath) - log.Infof(" opt: %s", cfg.OptPath) + log.Infof(" opt: %s", cfg.GetOptPath()) log.Infof(" cache: %s", cfg.CachePath) fmt.Println("") log.Warnf("To cleanup all of distillery, remove the following directories:") log.Warnf(" - %s", cfg.GetCachePath()) log.Warnf(" - %s", cfg.BinPath) - log.Warnf(" - %s", cfg.OptPath) + log.Warnf(" - %s", cfg.GetOptPath()) return nil } diff --git a/pkg/commands/install/install.go b/pkg/commands/install/install.go index 0256ca1..6b5ccd6 100644 --- a/pkg/commands/install/install.go +++ b/pkg/commands/install/install.go @@ -13,6 +13,7 @@ import ( "github.com/ekristen/distillery/pkg/common" "github.com/ekristen/distillery/pkg/config" + "github.com/ekristen/distillery/pkg/inventory" "github.com/ekristen/distillery/pkg/provider" ) @@ -32,6 +33,8 @@ func Execute(c *cli.Context) error { _ = c.Set("include-pre-releases", "true") } + inv := inventory.New(os.DirFS(cfg.BinPath), cfg.BinPath, cfg.GetOptPath(), cfg) + src, err := NewSource(c.Args().First(), &provider.Options{ OS: c.String("os"), Arch: c.String("arch"), @@ -40,6 +43,7 @@ func Execute(c *cli.Context) error { "version": c.String("version"), "github-token": c.String("github-token"), "gitlab-token": c.String("gitlab-token"), + "no-signature-verify": c.String("no-signature-verify"), "no-checksum-verify": c.Bool("no-checksum-verify"), "no-score-check": c.Bool("no-score-check"), "include-pre-releases": c.Bool("include-pre-releases"), @@ -49,15 +53,42 @@ func Execute(c *cli.Context) error { return err } + var userFlags []string + if c.Bool("include-pre-releases") { + userFlags = append(userFlags, "including pre-releases") + } + log.Infof("distillery/%s", common.AppVersion.Summary) - log.Infof(" source: %s", src.GetSource()) - log.Infof(" app: %s", src.GetApp()) - log.Infof("version: %s", c.String("version")) - log.Infof(" os: %s", c.String("os")) - log.Infof(" arch: %s", c.String("arch")) + for _, flag := range userFlags { + log.Infof(" flag: %s", flag) + } - if c.Bool("include-pre-releases") { - log.Infof("including pre-releases") + log.Infof("source: %s", src.GetSource()) + log.Infof("app: %s", src.GetApp()) + log.Infof("os: %s", c.String("os")) + log.Infof("arch: %s", c.String("arch")) + + if c.String("version") == common.Latest { + log.Infof("determining latest version") + } else { + log.Infof("version: %s", c.String("version")) + } + + if err := src.PreRun(c.Context); err != nil { + return err + } + + if c.String("version") == common.Latest { + log.Infof("version: %s", src.GetVersion()) + } + + if c.String("version") == "latest" && !c.Bool("force") { + latestInstalled := inv.GetLatestVersion(fmt.Sprintf("%s/%s", src.GetSource(), src.GetApp())) + if latestInstalled.Version == src.GetVersion() { + log.Warnf("already installed") + log.Infof("reinstall with --force (%s)", time.Since(start)) + return nil + } } if err := src.Run(c.Context); err != nil { @@ -183,6 +214,9 @@ func Flags() []cli.Flag { Name: "no-score-check", Usage: "disable scoring check", }, + &cli.BoolFlag{ + Name: "force", + }, } } diff --git a/pkg/commands/list/list.go b/pkg/commands/list/list.go index 7f6fe4c..18233dd 100644 --- a/pkg/commands/list/list.go +++ b/pkg/commands/list/list.go @@ -77,7 +77,7 @@ func Execute(c *cli.Context) error { func init() { cmd := &cli.Command{ Name: "list", - Usage: "list", + Usage: "list installed binaries and versions", Description: `list installed binaries and versions`, Before: common.Before, Flags: common.Flags(), diff --git a/pkg/commands/uninstall/uninstall.go b/pkg/commands/uninstall/uninstall.go index 9a774da..b64bb89 100644 --- a/pkg/commands/uninstall/uninstall.go +++ b/pkg/commands/uninstall/uninstall.go @@ -41,7 +41,7 @@ func Execute(c *cli.Context) error { return err } - path := filepath.Join(cfg.OptPath, src.GetSource(), src.GetOwner(), src.GetRepo()) + path := filepath.Join(cfg.GetOptPath(), src.GetSource(), src.GetOwner(), src.GetRepo()) logrus.Trace("path: ", path) diff --git a/pkg/common/consts.go b/pkg/common/consts.go new file mode 100644 index 0000000..45cdf44 --- /dev/null +++ b/pkg/common/consts.go @@ -0,0 +1,6 @@ +package common + +const ( + Unknown = "unknown" + Latest = "latest" +) diff --git a/pkg/config/config.go b/pkg/config/config.go index a9b5894..d052f96 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -14,18 +14,15 @@ import ( ) type Config struct { - // HomePath - path to store the configuration files, this path is set by default based on the operating system type + // Path - path to store the configuration files, this path is set by default based on the operating system type // and your user's home directory. Typically, this is set to $HOME/.distillery - HomePath string `yaml:"home_path" toml:"home_path"` + Path string `yaml:"path" toml:"path"` // BinPath - path to create symlinks for your binaries, this path is set by default based on the operating system type // This is the path that is added to your PATH environment variable. Typically, this is set to $HOME/.distillery/bin + // This allows you to override the location for symlinks. For example, you can instead put them all in /usr/local/bin BinPath string `yaml:"bin_path" toml:"bin_path"` - // OptPath - path to store the binaries that are installed, this path is set by default based on the operating - // system type. This is where the symlinks in the BinPath point to. Typically, this is set to $HOME/.distillery/opt - OptPath string `yaml:"opt_path" toml:"opt_path"` - // CachePath - path to store cache files, this path is set by default based on the operating system type CachePath string `yaml:"cache_path" toml:"cache_path"` @@ -55,8 +52,12 @@ func (c *Config) GetDownloadsPath() string { return filepath.Join(c.CachePath, common.NAME, "downloads") } +func (c *Config) GetOptPath() string { + return filepath.Join(c.Path, "opt") +} + func (c *Config) MkdirAll() error { - paths := []string{c.BinPath, c.OptPath, c.CachePath, c.GetMetadataPath(), c.GetDownloadsPath()} + paths := []string{c.BinPath, c.GetOptPath(), c.CachePath, c.GetMetadataPath(), c.GetDownloadsPath()} for _, path := range paths { err := os.MkdirAll(path, 0755) @@ -102,12 +103,12 @@ func New(path string) (*Config, error) { cfg.DefaultSource = "github" } - if cfg.HomePath == "" { + if cfg.Path == "" { homeDir, err := os.UserHomeDir() if err != nil { return cfg, err } - cfg.HomePath = filepath.Join(homeDir, fmt.Sprintf(".%s", common.NAME)) + cfg.Path = filepath.Join(homeDir, fmt.Sprintf(".%s", common.NAME)) } if cfg.CachePath == "" { @@ -119,11 +120,7 @@ func New(path string) (*Config, error) { } if cfg.BinPath == "" { - cfg.BinPath = filepath.Join(cfg.HomePath, "bin") - } - - if cfg.OptPath == "" { - cfg.OptPath = filepath.Join(cfg.HomePath, "opt") + cfg.BinPath = filepath.Join(cfg.Path, "bin") } return cfg, nil diff --git a/pkg/inventory/bin.go b/pkg/inventory/bin.go new file mode 100644 index 0000000..2be3559 --- /dev/null +++ b/pkg/inventory/bin.go @@ -0,0 +1,22 @@ +package inventory + +import "path/filepath" + +type Bin struct { + Name string + Versions []*Version + Source string + Owner string + Repo string +} + +func (b *Bin) GetInstallPath(base string) string { + return filepath.Join(base, b.Source, b.Owner, b.Repo) +} + +type Version struct { + Version string + Path string + Latest bool + Target string +} diff --git a/pkg/inventory/inventory.go b/pkg/inventory/inventory.go new file mode 100644 index 0000000..bd9c00e --- /dev/null +++ b/pkg/inventory/inventory.go @@ -0,0 +1,184 @@ +package inventory + +import ( + "io/fs" + "os" + "path/filepath" + "strings" + + "github.com/sirupsen/logrus" + + "github.com/ekristen/distillery/pkg/config" +) + +type Inventory struct { + config *config.Config + Bins map[string]*Bin + + latestPaths map[string]string +} + +func (i *Inventory) AddVersion(path, target string) error { + binName := filepath.Base(path) + version := "latest" + latest := true + + vParts := strings.Split(binName, "@") + if len(vParts) == 2 { + binName = vParts[0] + version = vParts[1] + latest = false + } else { + binName = vParts[0] + } + + if i.Bins == nil { + i.Bins = make(map[string]*Bin) + } + if i.latestPaths == nil { + i.latestPaths = make(map[string]string) + } + + source := strings.TrimPrefix(strings.TrimPrefix(target, i.config.GetOptPath()), "/") + baseSourceParts := strings.SplitAfterN(source, "/", 4) + baseSource := strings.TrimSuffix(strings.Join(baseSourceParts[:3], ""), "/") + + if i.Bins[baseSource] == nil { + src := strings.TrimPrefix(strings.TrimPrefix(target, i.config.GetOptPath()), "/") + parts := strings.Split(src, "/") + + i.Bins[baseSource] = &Bin{ + Name: binName, + Versions: make([]*Version, 0), + Source: parts[0], + Owner: parts[1], + Repo: parts[2], + } + } + + if latest { + i.latestPaths[baseSource] = target + return nil + } + + if i.latestPaths[baseSource] == target { + latest = true + } + + i.Bins[baseSource].Versions = append(i.Bins[baseSource].Versions, &Version{ + Version: version, + Path: path, + Latest: latest, + Target: target, + }) + + return nil +} + +func (i *Inventory) Count() int { + return len(i.Bins) +} + +func (i *Inventory) FullCount() int { + count := 0 + for _, bin := range i.Bins { + count += len(bin.Versions) + } + + return count +} + +func (i *Inventory) GetBinVersions(name string) *Bin { + return i.Bins[name] +} + +func (i *Inventory) GetBinVersion(name, version string) *Version { + bin := i.GetBinVersions(name) + if bin == nil { + return nil + } + + for _, v := range bin.Versions { + if v.Latest && version == "latest" { + return v + } else if v.Version == version { + return v + } + } + + return nil +} + +func (i *Inventory) GetLatestVersion(name string) *Version { + bin := i.GetBinVersions(name) + if bin == nil { + return nil + } + + for _, v := range bin.Versions { + if v.Latest { + return v + } + } + + return nil +} + +func (i *Inventory) setLatestVersion() { + for baseSource, bin := range i.Bins { + latestPath, exists := i.latestPaths[baseSource] + if !exists { + continue + } + + for _, version := range bin.Versions { + if version.Target == latestPath { + version.Latest = true + } + } + } +} + +func New(fileSystem fs.FS, basePath, binPath string, cfg *config.Config) *Inventory { + inv := &Inventory{ + config: cfg, + } + + // scan the ~/.distillery/bin directory + // for all the bins and versions + // and return a new Inventory + _ = fs.WalkDir(fileSystem, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + if d.IsDir() { + return nil + } + + fileInfo, err := d.Info() + if err != nil { + return err + } + + // if a symlink it's a version ... + if fileInfo.Mode()&os.ModeSymlink != os.ModeSymlink { + return nil + } + + target, err := os.Readlink(filepath.Join(basePath, path)) + if err != nil { + logrus.WithError(err).Warn("failed to read symlink") + } + + if err := inv.AddVersion(path, target); err != nil { + logrus.WithError(err).Warn("failed to add version") + } + + return nil + }) + + inv.setLatestVersion() + + return inv +} diff --git a/pkg/inventory/inventory_test.go b/pkg/inventory/inventory_test.go new file mode 100644 index 0000000..9f131a1 --- /dev/null +++ b/pkg/inventory/inventory_test.go @@ -0,0 +1,226 @@ +package inventory_test + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ekristen/distillery/pkg/config" + "github.com/ekristen/distillery/pkg/inventory" +) + +func TestInventory_New(t *testing.T) { + tempDir, err := os.MkdirTemp("", "inventory_test") + if err != nil { + t.Fatalf("Failed to create temp directory: %v", err) + } + defer func(path string) { + _ = os.RemoveAll(path) + }(tempDir) + cfg, err := config.New("") + if err != nil { + t.Fatalf("Failed to create config: %v", err) + } + + symPath := filepath.Join(tempDir, ".distillery", "bin") + binPath := filepath.Join(tempDir, ".distillery", "opt") + _ = os.MkdirAll(symPath, 0755) + _ = os.MkdirAll(binPath, 0755) + + binaries := map[string]string{ + "test": "github/ekristen/test/2.0.0/test", + "test@1.0.0": "github/ekristen/test/1.0.0/test", + "test@2.0.0": "github/ekristen/test/2.0.0/test", + "another-test@1.0.0": "github/ekristen/another-test/1.0.0/another-test", + "another-test@1.0.1": "github/ekristen/another-test/1.0.1/another-test", + } + + for bin, target := range binaries { + targetBase := filepath.Dir(target) + targetName := filepath.Base(target) + realBin := filepath.Join(binPath, targetBase, targetName) + _ = os.MkdirAll(filepath.Join(realBin, targetBase), 0755) + _ = os.WriteFile(realBin, []byte("test"), 0600) + + symlinkPath := filepath.Join(symPath, bin) + if err := os.Symlink(realBin, symlinkPath); err != nil { + t.Fatalf("Failed to create symlink: %v", err) + } + } + + dirFS := os.DirFS(tempDir) + inv := inventory.New(dirFS, tempDir, ".distillery/bin", cfg) + + assert.NotNil(t, inv) + assert.Equal(t, 2, inv.Count()) + assert.Equal(t, len(binaries), inv.FullCount()) +} + +func TestInventory_AddVersion(t *testing.T) { + cases := []struct { + name string + bins map[string]string + expected map[string]*inventory.Bin + }{ + { + name: "simple", + bins: map[string]string{ + "/home/test/.distillery/bin/test@1.0.0": "/home/test/.distillery/opt/github/ekristen/test/1.0.0/test", + }, + expected: map[string]*inventory.Bin{ + "test": { + Name: "test", + Versions: []*inventory.Version{ + { + Version: "1.0.0", + Path: "/home/test/.distillery/bin/test@1.0.0", + Target: "/home/test/.distillery/opt/github/ekristen/test/1.0.0/test", + }, + }, + }, + }, + }, + { + name: "multiple", + bins: map[string]string{ + "/home/test/.distillery/bin/test@1.0.0": "/home/test/.distillery/opt/github/ekristen/test/1.0.0/test", + "/home/test/.distillery/bin/test@2.0.0": "/home/test/.distillery/opt/github/ekristen/test/2.0.0/test", + }, + expected: map[string]*inventory.Bin{ + "test": { + Name: "test", + Versions: []*inventory.Version{ + { + Version: "1.0.0", + Path: "/home/test/.distillery/bin/test@1.0.0", + Target: "/home/test/.distillery/opt/github/ekristen/test/1.0.0/test", + }, + { + Version: "2.0.0", + Path: "/home/test/.distillery/bin/test@2.0.0", + Target: "/home/test/.distillery/opt/github/ekristen/test/2.0.0/test", + }, + }, + }, + }, + }, + { + name: "complex", + bins: map[string]string{ + "/home/test/.distillery/bin/test@1.0.0": "/home/test/.distillery/opt/github/ekristen/test/1.0.0/test", + "/home/test/.distillery/bin/test@1.0.1": "/home/test/.distillery/opt/github/ekristen/test/1.0.1/test", + "/home/test/.distillery/bin/another-test@1.0.0": "/home/test/.distillery/opt/github/ekristen/another-test/1.0.0/another-test", + "/home/test/.distillery/bin/another-test@1.0.1": "/home/test/.distillery/opt/github/ekristen/another-test/1.0.1/another-test", + }, + expected: map[string]*inventory.Bin{ + "test": { + Name: "test", + Versions: []*inventory.Version{ + { + Version: "1.0.0", + Path: "/home/test/.distillery/bin/test@1.0.0", + Target: "/home/test/.distillery/opt/github/ekristen/test/1.0.0/test", + }, + { + Version: "1.0.1", + Path: "/home/test/.distillery/bin/test@1.0.1", + Target: "/home/test/.distillery/opt/github/ekristen/test/1.0.1/test", + }, + }, + }, + "another-test": { + Name: "another-test", + Versions: []*inventory.Version{ + { + Version: "1.0.0", + Path: "/home/test/.distillery/bin/another-test@1.0.0", + Target: "/home/test/.distillery/opt/github/ekristen/another-test/1.0.0/another-test", + }, + { + Version: "1.0.1", + Path: "/home/test/.distillery/bin/another-test@1.0.1", + Target: "/home/test/.distillery/opt/github/ekristen/another-test/1.0.1/another-test", + }, + }, + }, + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + inv := inventory.Inventory{} + for bin, target := range tc.bins { + _ = inv.AddVersion(bin, target) + } + + assert.EqualValues(t, tc.expected, inv.Bins) + }) + } +} + +func BenchmarkInventoryNew(b *testing.B) { + tempDir, err := os.MkdirTemp("", "inventory_test") + if err != nil { + b.Fatalf("Failed to create temp directory: %v", err) + } + defer func(path string) { + _ = os.RemoveAll(path) + }(tempDir) // Clean up the temp directory after the test + cfg, err := config.New("") + if err != nil { + b.Fatalf("Failed to create config: %v", err) + } + + symPath := filepath.Join(tempDir, ".distillery", "bin") + binPath := filepath.Join(tempDir, ".distillery", "opt") + _ = os.MkdirAll(symPath, 0755) + _ = os.MkdirAll(binPath, 0755) + + // Generate fake binary files to simulate version binaries + binaries := map[string]string{ + "test": "github/ekristen/test/2.0.0/test", + "test@1.0.0": "github/ekristen/test/1.0.0/test", + "test@2.0.0": "github/ekristen/test/2.0.0/test", + "another-test@1.0.0": "github/ekristen/another-test/1.0.0/another-test", + "another-test@1.0.1": "github/ekristen/another-test/1.0.1/another-test", + } + + for bin, target := range binaries { + targetBase := filepath.Dir(target) + targetName := filepath.Base(target) + realBin := filepath.Join(binPath, targetBase, targetName) + _ = os.MkdirAll(filepath.Join(realBin, targetBase), 0755) + _ = os.WriteFile(realBin, []byte("test"), 0600) + + symlinkPath := filepath.Join(symPath, bin) + if err := os.Symlink(realBin, symlinkPath); err != nil { + b.Fatalf("Failed to create symlink: %v", err) + } + } + + dirFS := os.DirFS(tempDir) + + b.ResetTimer() // Reset the timer to exclude setup time + + for i := 0; i < b.N; i++ { + _ = inventory.New(dirFS, tempDir, ".distillery/bin", cfg) + } +} + +func BenchmarkInventoryHomeDir(b *testing.B) { + userDir, _ := os.UserHomeDir() + basePath := "/" + baseFS := os.DirFS(basePath) + binPath := filepath.Join(userDir, ".distillery", "bin") + cfg, err := config.New("") + if err != nil { + b.Fatalf("Failed to create config: %v", err) + } + + for i := 0; i < b.N; i++ { + _ = inventory.New(baseFS, basePath, binPath, cfg) + } +} diff --git a/pkg/provider/interface.go b/pkg/provider/interface.go index 095500b..2e77299 100644 --- a/pkg/provider/interface.go +++ b/pkg/provider/interface.go @@ -9,5 +9,7 @@ type ISource interface { GetApp() string GetID() string GetDownloadsDir() string + GetVersion() string + PreRun(context.Context) error Run(context.Context) error } diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index 6e026ee..38233a0 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -61,6 +61,10 @@ func (p *Provider) GetArch() string { return p.Options.Arch } +func (p *Provider) GetVersion() string { + return "not-implemented" +} + // CommonRun - common run logic for all sources that includes download, extract, install and cleanup func (p *Provider) CommonRun(ctx context.Context) error { if err := p.Download(ctx); err != nil { @@ -738,7 +742,7 @@ func (p *Provider) Extract() error { func (p *Provider) Install() error { return p.Binary.Install( - p.Binary.ID(), p.Options.Config.BinPath, filepath.Join(p.Options.Config.OptPath, p.Binary.Path())) + p.Binary.ID(), p.Options.Config.BinPath, filepath.Join(p.Options.Config.GetOptPath(), p.Binary.Path())) } func (p *Provider) Cleanup() error { diff --git a/pkg/source/github.go b/pkg/source/github.go index a1a7e71..28a0506 100644 --- a/pkg/source/github.go +++ b/pkg/source/github.go @@ -3,7 +3,6 @@ package source import ( "context" "fmt" - "path/filepath" "strings" @@ -14,6 +13,7 @@ import ( "github.com/sirupsen/logrus" "github.com/ekristen/distillery/pkg/asset" + "github.com/ekristen/distillery/pkg/common" "github.com/ekristen/distillery/pkg/provider" ) @@ -52,6 +52,22 @@ func (s *GitHub) GetID() string { return strings.Join([]string{s.GetSource(), s.GetOwner(), s.GetRepo(), s.GetOS(), s.GetArch()}, "-") } +func (s *GitHub) GetVersion() string { + if s.Release == nil { + return common.Unknown + } + + return strings.TrimPrefix(s.Release.GetTagName(), "v") +} + +func (s *GitHub) PreRun(ctx context.Context) error { + if err := s.sourceRun(ctx); err != nil { + return err + } + + return nil +} + // Run - run the source func (s *GitHub) Run(ctx context.Context) error { if err := s.sourceRun(ctx); err != nil { @@ -141,8 +157,6 @@ func (s *GitHub) FindRelease(ctx context.Context) error { return fmt.Errorf("release not found") } - log.Infof("selected version: %s", strings.TrimPrefix(release.GetTagName(), "v")) - s.Release = release return nil diff --git a/pkg/source/gitlab.go b/pkg/source/gitlab.go index c486c37..0a4852c 100644 --- a/pkg/source/gitlab.go +++ b/pkg/source/gitlab.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "path/filepath" + "strings" "github.com/gregjones/httpcache" "github.com/gregjones/httpcache/diskcache" @@ -41,6 +42,14 @@ func (s *GitLab) GetID() string { return fmt.Sprintf("%s/%s/%s", s.GetSource(), s.GetOwner(), s.GetRepo()) } +func (s *GitLab) GetVersion() string { + if s.Release == nil { + return "unknown" + } + + return strings.TrimPrefix(s.Release.TagName, "v") +} + func (s *GitLab) GetDownloadsDir() string { return filepath.Join(s.Options.Config.GetDownloadsPath(), s.GetSource(), s.GetOwner(), s.GetRepo(), s.Version) } @@ -86,6 +95,14 @@ func (s *GitLab) sourceRun(ctx context.Context) error { return nil } +func (s *GitLab) PreRun(ctx context.Context) error { + if err := s.sourceRun(ctx); err != nil { + return err + } + + return nil +} + func (s *GitLab) Run(ctx context.Context) error { if err := s.sourceRun(ctx); err != nil { return err diff --git a/pkg/source/hashicorp.go b/pkg/source/hashicorp.go index 45accfd..cc1e5b8 100644 --- a/pkg/source/hashicorp.go +++ b/pkg/source/hashicorp.go @@ -3,6 +3,7 @@ package source import ( "context" "fmt" + "strings" "path/filepath" @@ -43,6 +44,10 @@ func (s *Hashicorp) GetID() string { return fmt.Sprintf("%s-%s", s.GetSource(), s.GetRepo()) } +func (s *Hashicorp) GetVersion() string { + return strings.TrimPrefix(s.Version, "v") +} + func (s *Hashicorp) GetDownloadsDir() string { return filepath.Join(s.Options.Config.GetDownloadsPath(), s.GetSource(), s.GetOwner(), s.GetRepo(), s.Version) } @@ -114,6 +119,14 @@ func (s *Hashicorp) sourceRun(ctx context.Context) error { return nil } +func (s *Hashicorp) PreRun(ctx context.Context) error { + if err := s.sourceRun(ctx); err != nil { + return err + } + + return nil +} + func (s *Hashicorp) Run(ctx context.Context) error { if err := s.sourceRun(ctx); err != nil { return err diff --git a/pkg/source/homebrew.go b/pkg/source/homebrew.go index 1545fe5..2eae519 100644 --- a/pkg/source/homebrew.go +++ b/pkg/source/homebrew.go @@ -42,6 +42,10 @@ func (s *Homebrew) GetID() string { return s.Formula } +func (s *Homebrew) GetVersion() string { + return strings.TrimPrefix(s.Version, "v") +} + func (s *Homebrew) GetDownloadsDir() string { return filepath.Join(s.Options.Config.GetDownloadsPath(), s.GetSource(), s.GetOwner(), s.GetRepo(), s.Version) } @@ -94,6 +98,15 @@ func (s *Homebrew) sourceRun(ctx context.Context) error { return nil } +// PreRun - run the source specific logic +func (s *Homebrew) PreRun(ctx context.Context) error { + if err := s.sourceRun(ctx); err != nil { + return err + } + + return nil +} + func (s *Homebrew) Run(ctx context.Context) error { if err := s.sourceRun(ctx); err != nil { return err diff --git a/pkg/source/kubernetes.go b/pkg/source/kubernetes.go index 87561e9..c94a1df 100644 --- a/pkg/source/kubernetes.go +++ b/pkg/source/kubernetes.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "path/filepath" + "strings" "github.com/apex/log" "github.com/google/go-github/v66/github" @@ -37,6 +38,14 @@ func (s *Kubernetes) GetID() string { return fmt.Sprintf("%s-%s", s.GetSource(), s.GetRepo()) } +func (s *Kubernetes) GetVersion() string { + if s.Release == nil { + return "unknown" + } + + return strings.TrimPrefix(s.Release.GetTagName(), "v") +} + func (s *Kubernetes) GetDownloadsDir() string { return filepath.Join(s.Options.Config.GetDownloadsPath(), s.GetSource(), s.GetOwner(), s.GetRepo(), s.Version) } @@ -90,6 +99,14 @@ func (s *Kubernetes) GetReleaseAssets(_ context.Context) error { return nil } +func (s *Kubernetes) PreRun(ctx context.Context) error { + if err := s.sourceRun(ctx); err != nil { + return err + } + + return nil +} + func (s *Kubernetes) Run(ctx context.Context) error { if err := s.sourceRun(ctx); err != nil { return err