From 74e595401f2bab28d3eb8cb4b4fbbd5ec127bb57 Mon Sep 17 00:00:00 2001 From: DataHearth Date: Sat, 1 Oct 2022 18:13:18 +0200 Subject: [PATCH] feat: add alias command --- cmd/cmd.go | 155 ++++++++++++++++++++++++++++++++++++----------- pkg/alias.go | 96 +++++++++++++++++++++++++++++ pkg/hash.go | 17 +++--- pkg/utils.go | 33 ++-------- pkg/variables.go | 2 - 5 files changed, 228 insertions(+), 75 deletions(-) create mode 100644 pkg/alias.go diff --git a/cmd/cmd.go b/cmd/cmd.go index f61e8b3..16d8e3f 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -16,7 +16,9 @@ import ( ) var ( - dgfFolder = strings.Replace(pkg.DGF_FOLDER, "~", os.Getenv("HOME"), 1) + 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, @@ -117,19 +119,25 @@ Release(s) folder will be removed from "~/.local/doggofetcher" and thus not avai Action: lsRemote, }, { - Name: "ls-remote", - Usage: "List all remote references", + Name: "alias", + Usage: "Set an alias for a GoLang version", + Action: alias, Flags: []cli.Flag{ &cli.BoolFlag{ - Name: "rc", - Usage: "Allow \"rc\" version to be fetched", + Name: "list", + Aliases: []string{"l"}, + Usage: "List all set alias and their version", }, - &cli.BoolFlag{ - Name: "beta", - Usage: "Allow \"beta\" version to be fetched", + &cli.StringFlag{ + Name: "get", + Usage: "Get a version for a given alias", + }, + &cli.StringSliceFlag{ + Name: "rename", + Usage: "Rename an already existing alias", + Value: nil, }, }, - Action: lsRemote, }, }, Flags: []cli.Flag{ @@ -151,10 +159,19 @@ func Execute() error { } 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") { @@ -164,27 +181,9 @@ func use(ctx *cli.Context) error { } else { release = ctx.Args().First() if !re.Match([]byte(release)) { - return errors.New("release doesn't match \"\\d*\\.?\\d*\\.?\\d(rc|beta)?\\d*?\" format") - } - } - - localFolder := dgfFolder - fi, err := os.Stat(localFolder) - if err != nil { - if !os.IsNotExist(err) { - return err - } - - if err := os.MkdirAll(localFolder, 0755); err != nil { - return err - } - } else { - if !fi.IsDir() { - if err := os.RemoveAll(localFolder); err != nil { - return err - } - if err := os.MkdirAll(localFolder, 0755); err != nil { - return err + release = alias.GetAliasVersion(release) + if release == "" { + return fmt.Errorf("release doesn't match \"%s\" format nor is an existing alias", re.String()) } } } @@ -194,11 +193,11 @@ func use(ctx *cli.Context) error { return err } - hash, err := pkg.NewHash(localFolder) + hash, err := pkg.NewHash(hashFile) if err != nil { return err } - r := pkg.NewRelease(release, filepath.Join(localFolder, release)) + r := pkg.NewRelease(release, filepath.Join(dgfFolder, release)) if err := r.CheckReleaseExists(); err != nil { if err != pkg.ErrReleaseNotFound { @@ -248,7 +247,7 @@ func use(ctx *cli.Context) error { } Logger.Info("Setting golang binary") - if err := pkg.UpdateRelease(r.GetReleaseFolder()); err != nil { + if err := pkg.UpdateRelease(filepath.Join(dgfFolder, "go"), r.GetReleaseFolder()); err != nil { return err } @@ -261,14 +260,40 @@ func initFunc(ctx *cli.Context) error { Logger.Level = logrus.DebugLevel } - return pkg.Init(Logger) + 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 } +// todo: 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 } @@ -288,6 +313,10 @@ func ls(ctx *cli.Context) error { } func remove(ctx *cli.Context) error { + if err := checkInitialized(); err != nil { + return err + } + if ctx.Bool("verbose") { Logger.Level = logrus.DebugLevel } @@ -360,6 +389,10 @@ func remove(ctx *cli.Context) error { } func execCommand(ctx *cli.Context) error { + if err := checkInitialized(); err != nil { + return err + } + if ctx.Bool("verbose") { Logger.Level = logrus.DebugLevel } @@ -392,7 +425,59 @@ func lsRemote(ctx *cli.Context) error { continue } - fmt.Println(strings.Split(r.GetRef(), "/")[2]) + 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/pkg/alias.go new file mode 100644 index 0000000..a8fce4a --- /dev/null +++ b/pkg/alias.go @@ -0,0 +1,96 @@ +package pkg + +import ( + "bufio" + "errors" + "fmt" + "os" + "strings" +) + +type Alias struct { + file string + aliases map[string]string +} + +type Aliaser interface { + GetAliasVersion(alias string) string + GetAllAlias() map[string]string + SetAlias(alias, version string) + RenameAlias(old, new string) error + WriteAliasFile() error +} + +func NewAlias(path string) (Aliaser, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + + alias := make(map[string]string) + sc := bufio.NewScanner(f) + for sc.Scan() { + splittedLine := strings.Split(sc.Text(), " ") + if len(splittedLine) != 2 { + return nil, errors.New("alias file malformatted") + } + if splittedLine[1] == "" { + continue + } + + alias[splittedLine[0]] = splittedLine[1] + } + + return &Alias{ + file: path, + aliases: alias, + }, nil +} + +func (a *Alias) GetAliasVersion(alias string) string { + if v, ok := a.aliases[alias]; !ok { + return "" + } else { + return v + } +} + +func (a *Alias) GetAllAlias() map[string]string { + return a.aliases +} + +func (a *Alias) SetAlias(alias, version string) { + a.aliases[alias] = strings.ReplaceAll(version, "go", "") +} + +func (a *Alias) WriteAliasFile() error { + f, err := os.OpenFile(a.file, os.O_WRONLY|os.O_TRUNC, 06664) + if err != nil { + return err + } + defer f.Close() + + d := []byte{} + for k, v := range a.aliases { + d = append(d, []byte(fmt.Sprintf("%s %s", k, v))...) + } + + if _, err := f.Write(d); err != nil { + return err + } + + return nil +} + +func (a *Alias) RenameAlias(old, new string) error { + if _, ok := a.aliases[old]; !ok { + return fmt.Errorf("\"%s\" isn't an alias", old) + } + + version := a.aliases[old] + a.aliases[new] = version + + delete(a.aliases, old) + + return nil +} diff --git a/pkg/hash.go b/pkg/hash.go index ac010ac..2684811 100644 --- a/pkg/hash.go +++ b/pkg/hash.go @@ -22,21 +22,20 @@ type HashActions interface { } type Hash struct { - hashTable map[string]string - hashTablePath string + hashTable map[string]string + hashFile string } // NewHash returns a new Hash object. It reads the hashes from the ~/.local/doggofetcher/hashes.txt file then loads // them into the hash table. -func NewHash(localFolder string) (HashActions, error) { - hashTablePath := filepath.Join(localFolder, HASHES_FILE) - f, err := os.OpenFile(hashTablePath, os.O_CREATE|os.O_RDONLY, 0644) +func NewHash(hashFile string) (HashActions, error) { + f, err := os.Open(hashFile) if err != nil { return &Hash{}, err } defer f.Close() - hashTable := map[string]string{} + hashTable := make(map[string]string) sc := bufio.NewScanner(f) for sc.Scan() { l := strings.Split(sc.Text(), " ") @@ -44,8 +43,8 @@ func NewHash(localFolder string) (HashActions, error) { } return &Hash{ - hashTable: hashTable, - hashTablePath: hashTablePath, + hashTable: hashTable, + hashFile: hashFile, }, nil } @@ -153,5 +152,5 @@ func (h *Hash) writeHashTable() error { data = append(data, []byte(fmt.Sprintf("%s %s", path, hash))...) } - return os.WriteFile(h.hashTablePath, data, 0644) + return os.WriteFile(h.hashFile, data, 0644) } diff --git a/pkg/utils.go b/pkg/utils.go index d1cc34e..9d03ca7 100644 --- a/pkg/utils.go +++ b/pkg/utils.go @@ -1,25 +1,20 @@ package pkg import ( - "fmt" "io" "os" "path/filepath" - "strings" - - "github.com/sirupsen/logrus" ) -func UpdateRelease(releaseFolder string) error { - activeReleaseFolder := filepath.Join(strings.Replace(DGF_FOLDER, "~", os.Getenv("HOME"), 1), "go") - if err := os.RemoveAll(activeReleaseFolder); err != nil { +func UpdateRelease(activeRelease, releaseFolder string) error { + if err := os.RemoveAll(activeRelease); err != nil { return err } - if err := os.MkdirAll(activeReleaseFolder, 0755); err != nil { + if err := os.MkdirAll(activeRelease, 0755); err != nil { return err } - return CopyFolder(releaseFolder, activeReleaseFolder, true) + return CopyFolder(releaseFolder, activeRelease, true) } func CopyFolder(src, dst string, init bool) error { @@ -68,23 +63,3 @@ func CopyFolder(src, dst string, init bool) error { return nil } - -func Init(logger *logrus.Logger) error { - dgfFolder := strings.Replace(DGF_FOLDER, "~", os.Getenv("HOME"), 1) - logger.WithField("folder", dgfFolder).Infoln("Initializing doggofetcher folder") - - if err := os.MkdirAll(dgfFolder, 0755); err != nil { - return err - } - f, err := os.Create(filepath.Join(dgfFolder, "hashes.txt")) - 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 -} diff --git a/pkg/variables.go b/pkg/variables.go index 9225f4d..33fe9a6 100644 --- a/pkg/variables.go +++ b/pkg/variables.go @@ -3,8 +3,6 @@ package pkg import "errors" const GO_DL_SERVER = "https://go.dev/dl" -const DGF_FOLDER = "~/.local/doggofetcher" -const HASHES_FILE = "hashes.txt" const LTS = "lts" var (