diff --git a/cmd/cmd.go b/cmd/cmd.go deleted file mode 100644 index 2b383ae..0000000 --- a/cmd/cmd.go +++ /dev/null @@ -1,468 +0,0 @@ -package cmd - -import ( - "errors" - "fmt" - "os" - "os/exec" - "path/filepath" - "regexp" - "runtime" - "strings" - - "gitea.antoine-langlois.net/datahearth/doggo-fetcher/pkg" - "github.com/sirupsen/logrus" - "github.com/urfave/cli/v2" - "golang.org/x/exp/slices" -) - -var ( - dgfFolder = strings.ReplaceAll("~/.local/doggofetcher", "~", os.Getenv("HOME")) - hashFile = filepath.Join(dgfFolder, "hash.txt") - aliasFile = filepath.Join(dgfFolder, "alias.txt") - re = regexp.MustCompile(`\d*\.?\d*\.?\d(rc|beta)?\d*?`) - Logger = &logrus.Logger{ - Out: os.Stdout, - Formatter: new(pkg.LoggerFormatter), - Hooks: make(logrus.LevelHooks), - Level: logrus.InfoLevel, - } - app = &cli.App{ - Name: "doggo-fetcher", - Usage: "I bring you your latest GoLang release with ease and efficiency (like a stick) !", - Description: `Doggo-fetcher is a utility tool that manage for you your installed GoLang releases. -You can select a specific GoLang release or even set a specific one for directories.`, - EnableBashCompletion: true, - Authors: []*cli.Author{ - { - Name: "Antoine Langlois", - Email: "antoine.l@antoine-langlois.net", - }, - }, - Suggest: true, - Version: "0.1.0", - Commands: []*cli.Command{ - { - Name: "use", - Usage: "Set a specific golang version", - Description: `Use a specific golang version as primary golang binary for the user. -If the version is not already downloaded, it'll downloaded and installed automatically.`, - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "latest", - Aliases: []string{"lts"}, - Usage: "Use latest release", - }, - &cli.BoolFlag{ - Name: "rc", - Usage: "Allow \"rc\" version to be fetched", - }, - &cli.BoolFlag{ - Name: "beta", - Usage: "Allow \"beta\" version to be fetched", - }, - }, - Action: use, - }, - { - Name: "init", - Usage: "Initialize doggofetcher", - Description: `Initialize doggofetcher by adding a custom path inside your sheel configuration file. -It also creates a folder at "~/.local/doggofetcher" to store your custom golang binaries.`, - Action: initFunc, - }, - { - Name: "uninstall", - Usage: "Uninstall golang release", - Description: `Uninstall current golang release. -It will remove the folder at "~/.local/doggofetcher/go"`, - Action: uninstall, - }, - { - Name: "ls", - Usage: "List available releases", - Description: `List available releases. -It will list all available releases in the "~/.local/doggofetcher/go*" folder.`, - Action: ls, - }, - { - Name: "remove", - Usage: "Remove one or more releases", - Description: `Remove one or more releases. -Release(s) folder will be removed from "~/.local/doggofetcher" and thus not available.`, - Action: remove, - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "all", - Aliases: []string{"a"}, - Usage: "Remove all releases", - }, - }, - }, - { - Name: "exec", - Usage: "Execute a go command", - Action: execCommand, - }, - { - Name: "ls-remote", - Usage: "List all remote references", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "rc", - Usage: "Allow \"rc\" version to be fetched", - }, - &cli.BoolFlag{ - Name: "beta", - Usage: "Allow \"beta\" version to be fetched", - }, - }, - Action: lsRemote, - }, - { - Name: "alias", - Usage: "Set an alias for a GoLang version", - Action: alias, - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "list", - Aliases: []string{"l"}, - Usage: "List all set alias and their version", - }, - &cli.StringFlag{ - Name: "get", - Usage: "Get a version for a given alias", - }, - &cli.StringSliceFlag{ - Name: "rename", - Usage: "Rename an already existing alias", - Value: nil, - }, - }, - }, - }, - Flags: []cli.Flag{ - &cli.BoolFlag{Name: "verbose", Aliases: []string{"v"}, Usage: "Enable verbose mode"}, - }, - } -) - -// todo: alias (set alias for a release) - -func Execute() error { - cli.VersionFlag = &cli.BoolFlag{ - Name: "version", - Aliases: []string{"V"}, - Usage: "print the version", - } - - return app.Run(os.Args) -} - -func use(ctx *cli.Context) error { - if err := checkInitialized(); err != nil { - return err - } - - if ctx.Bool("verbose") { - Logger.Level = logrus.DebugLevel - } - - alias, err := pkg.NewAlias(aliasFile) - if err != nil { - return err - } - - var release string - if ctx.NArg() == 0 { - if !ctx.Bool("latest") { - return errors.New("a release is required if \"--latest|--lts\" is not passed") - } - release = pkg.LTS - } else { - release = ctx.Args().First() - if !re.Match([]byte(release)) { - release = alias.GetAliasVersion(release) - if release == "" { - return fmt.Errorf("release doesn't match \"%s\" format nor is an existing alias", re.String()) - } - } - } - - release, err = pkg.NewTags(release, ctx.Context).GetRelease(ctx.Bool("beta"), ctx.Bool("rc")) - if err != nil { - return err - } - - hash, err := pkg.NewHash(hashFile) - if err != nil { - return err - } - r := pkg.NewRelease(release, filepath.Join(dgfFolder, release)) - - if err := r.CheckReleaseExists(); err != nil { - if err != pkg.ErrReleaseNotFound { - return err - } - - Logger.Info("Release not found, downloading...") - if err := r.DownloadRelease(); err != nil { - return err - } - - Logger.Info("Release downloaded, installing...") - if err := r.ExtractRelease(); err != nil { - return err - } - - Logger.Debug("Release installed, generating hash...") - h, err := hash.GetFolderHash(r.GetReleaseFolder()) - if err != nil { - return err - } - if err := hash.AddHash(r.GetReleaseFolder(), h); err != nil { - return err - } - } else { - Logger.Debug("Release found, checking hash...") - h, err := hash.GetFolderHash(r.GetReleaseFolder()) - if err != nil { - return err - } - - if err := hash.CompareReleaseHash(r.GetReleaseFolder(), h); err != nil { - if err == pkg.ErrHashNotFound { - Logger.Warnln("Hash not found in hash table, adding...") - if err := hash.AddHash(r.GetReleaseFolder(), h); err != nil { - return err - } - } else if err == pkg.ErrHashInvalid { - Logger.Warnln("Hash invalid, replacing...") - if err := hash.ReplaceHash(r.GetReleaseFolder(), h); err != nil { - return err - } - } else { - return err - } - } - } - - Logger.Info("Setting golang binary") - if err := pkg.UpdateRelease(filepath.Join(dgfFolder, "go"), r.GetReleaseFolder()); err != nil { - return err - } - - Logger.Info("Everything done!") - return nil -} - -func initFunc(ctx *cli.Context) error { - if ctx.Bool("verbose") { - Logger.Level = logrus.DebugLevel - } - - Logger.WithField("folder", dgfFolder).Infoln("Initializing doggofetcher folder") - - if err := os.MkdirAll(dgfFolder, 0755); err != nil { - return err - } - f, err := os.Create(hashFile) - if err != nil { - return err - } - f.Close() - - f, err = os.Create(aliasFile) - if err != nil { - return err - } - f.Close() - - Logger.Infoln("Add doggofetcher to your shell configuration file with the following command:") - fmt.Fprintln(os.Stdout, "\n# doggofetcher section") - fmt.Fprintf(os.Stdout, "export PATH=%s:$PATH\n", filepath.Join(dgfFolder, "go", "bin")) - - return nil -} - -func uninstall(ctx *cli.Context) error { - return os.RemoveAll(filepath.Join(dgfFolder, "go")) -} - -func ls(ctx *cli.Context) error { - if err := checkInitialized(); err != nil { - return err - } - - if ctx.Bool("verbose") { - Logger.Level = logrus.DebugLevel - } - - items, err := os.ReadDir(dgfFolder) - if err != nil { - return err - } - - for _, i := range items { - if i.IsDir() && i.Name() != "go" { - fmt.Println(strings.Replace(i.Name(), "go", "", 1)) - } - } - - return nil -} - -func remove(ctx *cli.Context) error { - if err := checkInitialized(); err != nil { - return err - } - - if ctx.Bool("verbose") { - Logger.Level = logrus.DebugLevel - } - - entries, err := os.ReadDir(dgfFolder) - if err != nil { - return err - } - - releasesPath := []string{} - if ctx.Bool("all") { - for _, e := range entries { - if !e.IsDir() || !strings.Contains(e.Name(), "go") || e.Name() == "go" { - continue - } - - releasesPath = append(releasesPath, filepath.Join(dgfFolder, e.Name())) - } - } else { - found := slices.ContainsFunc(entries, func(e os.DirEntry) bool { - return e.IsDir() && e.Name() == fmt.Sprintf("go%s", ctx.Args().First()) - }) - if !found { - return fmt.Errorf("release %s not found", ctx.Args().First()) - } - releasesPath = append(releasesPath, filepath.Join(dgfFolder, fmt.Sprintf("go%s", ctx.Args().First()))) - } - - hash, err := pkg.NewHash(hashFile) - if err != nil { - return err - } - - for _, e := range releasesPath { - Logger.Infof("Removing %s...", filepath.Base(e)) - if err := os.RemoveAll(e); err != nil { - return err - } - if err := hash.RemoveHash(e); err != nil { - return err - } - } - - if strings.Contains(runtime.Version(), ctx.Args().First()) { - Logger.Infoln("Removing installed version...") - if err := os.RemoveAll(filepath.Join(dgfFolder, "go")); err != nil { - return fmt.Errorf("could not remove installed release: %s", err) - } - } - - Logger.Infoln("All done!") - - return nil -} - -func execCommand(ctx *cli.Context) error { - if err := checkInitialized(); err != nil { - return err - } - - if ctx.Bool("verbose") { - Logger.Level = logrus.DebugLevel - } - - if ctx.NArg() == 0 { - return errors.New("a release is required") - } - - release := ctx.Args().First() - if !re.Match([]byte(release)) { - return errors.New("release doesn't match \"\\d*\\.?\\d*\\.?\\d(rc|beta)?\\d*?\" format") - } - - cmd := exec.Command(filepath.Join(dgfFolder, fmt.Sprintf("go%s", release), "bin", "go"), ctx.Args().Tail()...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - return cmd.Run() -} - -func lsRemote(ctx *cli.Context) error { - refs, err := pkg.NewTags("", ctx.Context).GetTagsRef() - if err != nil { - return err - } - - for _, r := range refs { - ref := r.GetRef() - if (!ctx.Bool("rc") && strings.Contains(ref, "rc")) || (!ctx.Bool("beta") && strings.Contains(ref, "beta")) { - continue - } - - fmt.Println(strings.ReplaceAll(strings.Split(ref, "/")[2], "go", "")) - } - - return nil -} - -func alias(ctx *cli.Context) error { - if err := checkInitialized(); err != nil { - return err - } - - alias, err := pkg.NewAlias(aliasFile) - if err != nil { - return err - } - if ctx.Bool("list") { - for a, v := range alias.GetAllAlias() { - fmt.Printf("alias: %s | version: %s\n", a, v) - } - return nil - } else if a := ctx.String("get"); a != "" { - fmt.Printf("alias: %s | version: %s\n", a, alias.GetAliasVersion(a)) - return nil - } else if values := ctx.StringSlice("rename"); len(values) != 0 { - if len(values) != 2 { - return errors.New("rename takes 2 parameters") - } - - if err := alias.RenameAlias(ctx.Args().Get(0), ctx.Args().Get(1)); err != nil { - return err - } - } else { - if ctx.NArg() != 2 { - return errors.New("an alias needs an alias name and a golang version") - } - - alias.SetAlias(ctx.Args().Get(0), ctx.Args().Get(1)) - } - - return alias.WriteAliasFile() -} - -func checkInitialized() error { - fi, err := os.Stat(dgfFolder) - if err != nil { - if os.IsNotExist(err) { - return fmt.Errorf("\"%s\" not initialized. Initialize it with \"doggo-fetcher init\"", dgfFolder) - } - - return err - } - if !fi.IsDir() { - return fmt.Errorf("\"%s\" is not a directory", dgfFolder) - } - - return nil -} diff --git a/pkg/alias.go b/internal/alias.go similarity index 98% rename from pkg/alias.go rename to internal/alias.go index a8fce4a..e76b781 100644 --- a/pkg/alias.go +++ b/internal/alias.go @@ -1,4 +1,4 @@ -package pkg +package internal import ( "bufio" diff --git a/pkg/hash.go b/internal/hash.go similarity index 99% rename from pkg/hash.go rename to internal/hash.go index 2684811..d31ec98 100644 --- a/pkg/hash.go +++ b/internal/hash.go @@ -1,4 +1,4 @@ -package pkg +package internal import ( "bufio" diff --git a/pkg/logger.go b/internal/logger.go similarity index 98% rename from pkg/logger.go rename to internal/logger.go index e221072..fd158e0 100644 --- a/pkg/logger.go +++ b/internal/logger.go @@ -1,4 +1,4 @@ -package pkg +package internal import ( "fmt" diff --git a/pkg/release.go b/internal/release.go similarity index 99% rename from pkg/release.go rename to internal/release.go index bfce5c9..774c0ad 100644 --- a/pkg/release.go +++ b/internal/release.go @@ -1,4 +1,4 @@ -package pkg +package internal import ( "archive/tar" diff --git a/pkg/tags.go b/internal/tags.go similarity index 99% rename from pkg/tags.go rename to internal/tags.go index a7a01b3..291befa 100644 --- a/pkg/tags.go +++ b/internal/tags.go @@ -1,4 +1,4 @@ -package pkg +package internal import ( "context" diff --git a/pkg/utils.go b/internal/utils.go similarity index 98% rename from pkg/utils.go rename to internal/utils.go index 9d03ca7..c8ab027 100644 --- a/pkg/utils.go +++ b/internal/utils.go @@ -1,4 +1,4 @@ -package pkg +package internal import ( "io" diff --git a/pkg/variables.go b/internal/variables.go similarity index 95% rename from pkg/variables.go rename to internal/variables.go index 33fe9a6..5297b23 100644 --- a/pkg/variables.go +++ b/internal/variables.go @@ -1,4 +1,4 @@ -package pkg +package internal import "errors" diff --git a/main.go b/main.go index d37d62a..d3ba841 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,468 @@ package main -import "gitea.antoine-langlois.net/datahearth/doggo-fetcher/cmd" +import ( + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strings" + + "gitea.antoine-langlois.net/datahearth/doggo-fetcher/internal" + "github.com/sirupsen/logrus" + "github.com/urfave/cli/v2" + "golang.org/x/exp/slices" +) + +var ( + dgfFolder = strings.ReplaceAll("~/.local/doggofetcher", "~", os.Getenv("HOME")) + hashFile = filepath.Join(dgfFolder, "hash.txt") + aliasFile = filepath.Join(dgfFolder, "alias.txt") + re = regexp.MustCompile(`\d*\.?\d*\.?\d(rc|beta)?\d*?`) + Logger = &logrus.Logger{ + Out: os.Stdout, + Formatter: new(internal.LoggerFormatter), + Hooks: make(logrus.LevelHooks), + Level: logrus.InfoLevel, + } + app = &cli.App{ + Name: "doggo-fetcher", + Usage: "I bring you your latest GoLang release with ease and efficiency (like a stick) !", + Description: `Doggo-fetcher is a utility tool that manage for you your installed GoLang releases. +You can select a specific GoLang release or even set a specific one for directories.`, + EnableBashCompletion: true, + Authors: []*cli.Author{ + { + Name: "Antoine Langlois", + Email: "antoine.l@antoine-langlois.net", + }, + }, + Suggest: true, + Version: "0.1.0", + Commands: []*cli.Command{ + { + Name: "use", + Usage: "Set a specific golang version", + Description: `Use a specific golang version as primary golang binary for the user. +If the version is not already downloaded, it'll downloaded and installed automatically.`, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "latest", + Aliases: []string{"lts"}, + Usage: "Use latest release", + }, + &cli.BoolFlag{ + Name: "rc", + Usage: "Allow \"rc\" version to be fetched", + }, + &cli.BoolFlag{ + Name: "beta", + Usage: "Allow \"beta\" version to be fetched", + }, + }, + Action: use, + }, + { + Name: "init", + Usage: "Initialize doggofetcher", + Description: `Initialize doggofetcher by adding a custom path inside your sheel configuration file. +It also creates a folder at "~/.local/doggofetcher" to store your custom golang binaries.`, + Action: initFunc, + }, + { + Name: "uninstall", + Usage: "Uninstall golang release", + Description: `Uninstall current golang release. +It will remove the folder at "~/.local/doggofetcher/go"`, + Action: uninstall, + }, + { + Name: "ls", + Usage: "List available releases", + Description: `List available releases. +It will list all available releases in the "~/.local/doggofetcher/go*" folder.`, + Action: ls, + }, + { + Name: "remove", + Usage: "Remove one or more releases", + Description: `Remove one or more releases. +Release(s) folder will be removed from "~/.local/doggofetcher" and thus not available.`, + Action: remove, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "all", + Aliases: []string{"a"}, + Usage: "Remove all releases", + }, + }, + }, + { + Name: "exec", + Usage: "Execute a go command", + Action: execCommand, + }, + { + Name: "ls-remote", + Usage: "List all remote references", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "rc", + Usage: "Allow \"rc\" version to be fetched", + }, + &cli.BoolFlag{ + Name: "beta", + Usage: "Allow \"beta\" version to be fetched", + }, + }, + Action: lsRemote, + }, + { + Name: "alias", + Usage: "Set an alias for a GoLang version", + Action: alias, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "list", + Aliases: []string{"l"}, + Usage: "List all set alias and their version", + }, + &cli.StringFlag{ + Name: "get", + Usage: "Get a version for a given alias", + }, + &cli.StringSliceFlag{ + Name: "rename", + Usage: "Rename an already existing alias", + Value: nil, + }, + }, + }, + }, + Flags: []cli.Flag{ + &cli.BoolFlag{Name: "verbose", Aliases: []string{"v"}, Usage: "Enable verbose mode"}, + }, + } +) func main() { - if err := cmd.Execute(); err != nil { - cmd.Logger.Errorln(err) + cli.VersionFlag = &cli.BoolFlag{ + Name: "version", + Aliases: []string{"V"}, + Usage: "print the version", + } + + if err := app.Run(os.Args); err != nil { + Logger.Fatalln(err) } } + +func use(ctx *cli.Context) error { + if err := checkInitialized(); err != nil { + return err + } + + if ctx.Bool("verbose") { + Logger.Level = logrus.DebugLevel + } + + alias, err := internal.NewAlias(aliasFile) + if err != nil { + return err + } + + var release string + if ctx.NArg() == 0 { + if !ctx.Bool("latest") { + return errors.New("a release is required if \"--latest|--lts\" is not passed") + } + release = internal.LTS + } else { + release = ctx.Args().First() + if !re.Match([]byte(release)) { + release = alias.GetAliasVersion(release) + if release == "" { + return fmt.Errorf("release doesn't match \"%s\" format nor is an existing alias", re.String()) + } + } + } + + release, err = internal.NewTags(release, ctx.Context).GetRelease(ctx.Bool("beta"), ctx.Bool("rc")) + if err != nil { + return err + } + + hash, err := internal.NewHash(hashFile) + if err != nil { + return err + } + r := internal.NewRelease(release, filepath.Join(dgfFolder, release)) + + if err := r.CheckReleaseExists(); err != nil { + if err != internal.ErrReleaseNotFound { + return err + } + + Logger.Info("Release not found, downloading...") + if err := r.DownloadRelease(); err != nil { + return err + } + + Logger.Info("Release downloaded, installing...") + if err := r.ExtractRelease(); err != nil { + return err + } + + Logger.Debug("Release installed, generating hash...") + h, err := hash.GetFolderHash(r.GetReleaseFolder()) + if err != nil { + return err + } + if err := hash.AddHash(r.GetReleaseFolder(), h); err != nil { + return err + } + } else { + Logger.Debug("Release found, checking hash...") + h, err := hash.GetFolderHash(r.GetReleaseFolder()) + if err != nil { + return err + } + + if err := hash.CompareReleaseHash(r.GetReleaseFolder(), h); err != nil { + if err == internal.ErrHashNotFound { + Logger.Warnln("Hash not found in hash table, adding...") + if err := hash.AddHash(r.GetReleaseFolder(), h); err != nil { + return err + } + } else if err == internal.ErrHashInvalid { + Logger.Warnln("Hash invalid, replacing...") + if err := hash.ReplaceHash(r.GetReleaseFolder(), h); err != nil { + return err + } + } else { + return err + } + } + } + + Logger.Info("Setting golang binary") + if err := internal.UpdateRelease(filepath.Join(dgfFolder, "go"), r.GetReleaseFolder()); err != nil { + return err + } + + Logger.Info("Everything done!") + return nil +} + +func initFunc(ctx *cli.Context) error { + if ctx.Bool("verbose") { + Logger.Level = logrus.DebugLevel + } + + Logger.WithField("folder", dgfFolder).Infoln("Initializing doggofetcher folder") + + if err := os.MkdirAll(dgfFolder, 0755); err != nil { + return err + } + f, err := os.Create(hashFile) + if err != nil { + return err + } + f.Close() + + f, err = os.Create(aliasFile) + if err != nil { + return err + } + f.Close() + + Logger.Infoln("Add doggofetcher to your shell configuration file with the following command:") + fmt.Fprintln(os.Stdout, "\n# doggofetcher section") + fmt.Fprintf(os.Stdout, "export PATH=%s:$PATH\n", filepath.Join(dgfFolder, "go", "bin")) + + return nil +} + +func uninstall(ctx *cli.Context) error { + return os.RemoveAll(filepath.Join(dgfFolder, "go")) +} + +func ls(ctx *cli.Context) error { + if err := checkInitialized(); err != nil { + return err + } + + if ctx.Bool("verbose") { + Logger.Level = logrus.DebugLevel + } + + items, err := os.ReadDir(dgfFolder) + if err != nil { + return err + } + + for _, i := range items { + if i.IsDir() && i.Name() != "go" { + fmt.Println(strings.Replace(i.Name(), "go", "", 1)) + } + } + + return nil +} + +func remove(ctx *cli.Context) error { + if err := checkInitialized(); err != nil { + return err + } + + if ctx.Bool("verbose") { + Logger.Level = logrus.DebugLevel + } + + entries, err := os.ReadDir(dgfFolder) + if err != nil { + return err + } + + releasesPath := []string{} + if ctx.Bool("all") { + for _, e := range entries { + if !e.IsDir() || !strings.Contains(e.Name(), "go") || e.Name() == "go" { + continue + } + + releasesPath = append(releasesPath, filepath.Join(dgfFolder, e.Name())) + } + } else { + found := slices.ContainsFunc(entries, func(e os.DirEntry) bool { + return e.IsDir() && e.Name() == fmt.Sprintf("go%s", ctx.Args().First()) + }) + if !found { + return fmt.Errorf("release %s not found", ctx.Args().First()) + } + releasesPath = append(releasesPath, filepath.Join(dgfFolder, fmt.Sprintf("go%s", ctx.Args().First()))) + } + + hash, err := internal.NewHash(hashFile) + if err != nil { + return err + } + + for _, e := range releasesPath { + Logger.Infof("Removing %s...", filepath.Base(e)) + if err := os.RemoveAll(e); err != nil { + return err + } + if err := hash.RemoveHash(e); err != nil { + return err + } + } + + if strings.Contains(runtime.Version(), ctx.Args().First()) { + Logger.Infoln("Removing installed version...") + if err := os.RemoveAll(filepath.Join(dgfFolder, "go")); err != nil { + return fmt.Errorf("could not remove installed release: %s", err) + } + } + + Logger.Infoln("All done!") + + return nil +} + +func execCommand(ctx *cli.Context) error { + if err := checkInitialized(); err != nil { + return err + } + + if ctx.Bool("verbose") { + Logger.Level = logrus.DebugLevel + } + + if ctx.NArg() == 0 { + return errors.New("a release is required") + } + + release := ctx.Args().First() + if !re.Match([]byte(release)) { + return errors.New("release doesn't match \"\\d*\\.?\\d*\\.?\\d(rc|beta)?\\d*?\" format") + } + + cmd := exec.Command(filepath.Join(dgfFolder, fmt.Sprintf("go%s", release), "bin", "go"), ctx.Args().Tail()...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + return cmd.Run() +} + +func lsRemote(ctx *cli.Context) error { + refs, err := internal.NewTags("", ctx.Context).GetTagsRef() + if err != nil { + return err + } + + for _, r := range refs { + ref := r.GetRef() + if (!ctx.Bool("rc") && strings.Contains(ref, "rc")) || (!ctx.Bool("beta") && strings.Contains(ref, "beta")) { + continue + } + + fmt.Println(strings.ReplaceAll(strings.Split(ref, "/")[2], "go", "")) + } + + return nil +} + +func alias(ctx *cli.Context) error { + if err := checkInitialized(); err != nil { + return err + } + + alias, err := internal.NewAlias(aliasFile) + if err != nil { + return err + } + if ctx.Bool("list") { + for a, v := range alias.GetAllAlias() { + fmt.Printf("alias: %s | version: %s\n", a, v) + } + return nil + } else if a := ctx.String("get"); a != "" { + fmt.Printf("alias: %s | version: %s\n", a, alias.GetAliasVersion(a)) + return nil + } else if values := ctx.StringSlice("rename"); len(values) != 0 { + if len(values) != 2 { + return errors.New("rename takes 2 parameters") + } + + if err := alias.RenameAlias(ctx.Args().Get(0), ctx.Args().Get(1)); err != nil { + return err + } + } else { + if ctx.NArg() != 2 { + return errors.New("an alias needs an alias name and a golang version") + } + + alias.SetAlias(ctx.Args().Get(0), ctx.Args().Get(1)) + } + + return alias.WriteAliasFile() +} + +func checkInitialized() error { + fi, err := os.Stat(dgfFolder) + if err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("\"%s\" not initialized. Initialize it with \"doggo-fetcher init\"", dgfFolder) + } + + return err + } + if !fi.IsDir() { + return fmt.Errorf("\"%s\" is not a directory", dgfFolder) + } + + return nil +}