From 88617fd1cb492fc1a92c139753d7ed0b2a69a69f Mon Sep 17 00:00:00 2001 From: Biniam Bekele Date: Fri, 12 Nov 2021 12:44:08 -0500 Subject: [PATCH] Refactor --- cmd/cmd.go | 7 +-- cmd/paths.go | 2 +- cmd/repositorycmd/repositorycmd.go | 45 ++++------------ internal/git/git.go | 34 ++++++++++++ internal/link/link.go | 30 ++++++++++- internal/repository/git.go | 26 --------- internal/repository/{sync.go => manage.go} | 62 ++++++++++++++-------- internal/repository/repository.go | 23 +++++++- internal/repository/validate.go | 17 +++--- 9 files changed, 152 insertions(+), 94 deletions(-) create mode 100644 internal/git/git.go delete mode 100644 internal/repository/git.go rename internal/repository/{sync.go => manage.go} (61%) diff --git a/cmd/cmd.go b/cmd/cmd.go index 4f7f32f..939e06e 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -2,6 +2,7 @@ package cmd import ( "github.com/andornaut/gog/cmd/repositorycmd" + "github.com/andornaut/gog/internal/git" "github.com/andornaut/gog/internal/link" "github.com/andornaut/gog/internal/repository" "github.com/spf13/cobra" @@ -41,7 +42,7 @@ var apply = &cobra.Command{ }, } -var git = &cobra.Command{ +var git_ = &cobra.Command{ Use: "git [git command and arguments...]", Short: "Run a git command in a repository's directory", DisableFlagParsing: true, @@ -52,7 +53,7 @@ var git = &cobra.Command{ if err != nil { return err } - return repository.GitRun(repoPath, args...) + return git.Run(repoPath, args...) }, } @@ -89,5 +90,5 @@ func init() { apply.Flags().StringVarP(&repositoryFlag, "repository", "r", "", "name of repository") remove.Flags().StringVarP(&repositoryFlag, "repository", "r", "", "name of repository") Cmd.Flags().StringVarP(&repositoryFlag, "repository", "r", "", "name of repository") - Cmd.AddCommand(add, apply, git, remove, repositorycmd.Cmd) + Cmd.AddCommand(add, apply, git_, remove, repositorycmd.Cmd) } diff --git a/cmd/paths.go b/cmd/paths.go index b0f9516..cb0d3ff 100644 --- a/cmd/paths.go +++ b/cmd/paths.go @@ -42,6 +42,6 @@ func repoPath() (string, error) { if err != nil { return "", err } - fmt.Println("REPOSITORY:", filepath.Base(repoPath)) + fmt.Println("Repository:", filepath.Base(repoPath)) return repoPath, nil } diff --git a/cmd/repositorycmd/repositorycmd.go b/cmd/repositorycmd/repositorycmd.go index 9ada02d..193d401 100644 --- a/cmd/repositorycmd/repositorycmd.go +++ b/cmd/repositorycmd/repositorycmd.go @@ -2,8 +2,6 @@ package repositorycmd import ( "fmt" - "io/ioutil" - "os" "path" "path/filepath" @@ -32,25 +30,11 @@ var add = &cobra.Command{ repoURL = args[1] } - if err := repository.ValidateRepoName(repoName); err != nil { - return err - } - - repoPath := path.Join(repository.BaseDir, repoName) - if err := os.MkdirAll(repoPath, 0755); err != nil { + repoPath, err := repository.Add(repoName, repoURL) + if err != nil { return err } - - if repoURL == "" { - if err := repository.GitInit(repoPath); err != nil { - return err - } - } else { - if err := repository.GitClone(repoPath, repoURL); err != nil { - return err - } - } - fmt.Println(repoPath) + fmt.Printf("Added repository: %s\n", repoPath) return nil }, } @@ -82,19 +66,15 @@ var list = &cobra.Command{ Args: cobra.NoArgs, DisableFlagsInUseLine: true, RunE: func(c *cobra.Command, args []string) error { - entries, err := ioutil.ReadDir(repository.BaseDir) + names, err := repository.List() if err != nil { return err } - - for _, fileInfo := range entries { - if fileInfo.IsDir() { - msg := fileInfo.Name() - if isPath { - msg = path.Join(repository.BaseDir, msg) - } - fmt.Println(msg) + for _, msg := range names { + if isPath { + msg = path.Join(repository.BaseDir, msg) } + fmt.Println(msg) } return nil }, @@ -107,14 +87,11 @@ var remove = &cobra.Command{ DisableFlagsInUseLine: true, RunE: func(c *cobra.Command, args []string) error { repoName := args[0] - if err := repository.ValidateRepoName(repoName); err != nil { - return err - } - repoPath := path.Join(repository.BaseDir, repoName) - if err := os.RemoveAll(repoPath); err != nil { + repoPath, err := repository.Remove(repoName) + if err != nil { return err } - fmt.Println(repoPath) + fmt.Printf("Removed repository: %s\n", repoPath) return nil }, } diff --git a/internal/git/git.go b/internal/git/git.go new file mode 100644 index 0000000..d41e72a --- /dev/null +++ b/internal/git/git.go @@ -0,0 +1,34 @@ +package git + +import ( + "os" + "os/exec" +) + +// GitClone clones a git repostory +func Clone(baseDir, repoPath string, repoURL string) error { + return Run(baseDir, "clone", repoURL, repoPath) +} + +// GitInit initializes a git repository +func Init(baseDir, repoPath string) error { + return Run(baseDir, "init", repoPath) +} + +// Is returns true if the given directory is a git repository +func Is(baseDir string) bool { + cmd := exec.Command("git", "rev-parse", "--git-dir") + cmd.Dir = baseDir + err := cmd.Run() + return err == nil +} + +// GitRun runs a git command in a repository +func Run(baseDir string, arguments ...string) error { + cmd := exec.Command("git", arguments...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Dir = baseDir + return cmd.Run() +} diff --git a/internal/link/link.go b/internal/link/link.go index 620d26b..7e15bc6 100644 --- a/internal/link/link.go +++ b/internal/link/link.go @@ -20,12 +20,38 @@ var ( // Unlink unlinks the given paths func Unlink(repoPath string, paths []string) error { - return repository.SyncLinks(repoPath, paths, UnlinkDir, UnlinkFile) + return syncLinks(repoPath, paths, UnlinkDir, UnlinkFile) } // Link unlinks the given paths func Link(repoPath string, paths []string) error { - return repository.SyncLinks(repoPath, paths, Dir, File) + return syncLinks(repoPath, paths, Dir, File) +} + +type syncFunc func(string, string) error + +func syncLinks(repoPath string, paths []string, updateDir, updateFile syncFunc) error { + for _, extPath := range paths { + intPath := repository.ToInternalPath(repoPath, extPath) + intFileInfo, err := os.Lstat(intPath) + if err != nil { + if os.IsNotExist(err) { + // Nothing to update + continue + } + return err + } + if intFileInfo.IsDir() { + if err := updateDir(repoPath, intPath); err != nil { + return err + } + continue + } + if err := updateFile(repoPath, intPath); err != nil { + return err + } + } + return nil } // Dir recursively creates symbolic links from a repository directory's files diff --git a/internal/repository/git.go b/internal/repository/git.go deleted file mode 100644 index a7ddde9..0000000 --- a/internal/repository/git.go +++ /dev/null @@ -1,26 +0,0 @@ -package repository - -import ( - "os" - "os/exec" -) - -// GitClone clones a git repostory -func GitClone(repoPath string, repoURL string) error { - return GitRun(BaseDir, "clone", repoURL, repoPath) -} - -// GitInit initializes a git repository -func GitInit(repoPath string) error { - return GitRun(BaseDir, "init", repoPath) -} - -// GitRun runs a git command in a repository -func GitRun(cwd string, arguments ...string) error { - cmd := exec.Command("git", arguments...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Dir = cwd - return cmd.Run() -} diff --git a/internal/repository/sync.go b/internal/repository/manage.go similarity index 61% rename from internal/repository/sync.go rename to internal/repository/manage.go index a41bbdd..df32f22 100644 --- a/internal/repository/sync.go +++ b/internal/repository/manage.go @@ -1,37 +1,55 @@ package repository import ( + "fmt" "os" + "path" "path/filepath" "github.com/andornaut/gog/internal/copy" + "github.com/andornaut/gog/internal/git" ) -type syncFunc func(string, string) error +// Add adds a new repository +func Add(repoName, repoURL string) (string, error) { + if err := validateRepoName(repoName); err != nil { + return "", err + } -// SyncLinks synchronizes all given paths within `repoPath` -func SyncLinks(repoPath string, paths []string, updateDir, updateFile syncFunc) error { - for _, extPath := range paths { - intPath := ToInternalPath(repoPath, extPath) - intFileInfo, err := os.Lstat(intPath) - if err != nil { - if os.IsNotExist(err) { - // Nothing to update - continue - } - return err - } - if intFileInfo.IsDir() { - if err := updateDir(repoPath, intPath); err != nil { - return err - } - continue + repoPath := path.Join(BaseDir, repoName) + if err := validateRepoPath(repoPath); err == nil { + return "", fmt.Errorf("repository already exists: %s", repoPath) + } + + if err := os.MkdirAll(repoPath, 0755); err != nil { + return "", err + } + + if repoURL == "" { + if err := git.Init(BaseDir, repoPath); err != nil { + return "", err } - if err := updateFile(repoPath, intPath); err != nil { - return err + } else { + if err := git.Clone(BaseDir, repoPath, repoURL); err != nil { + return "", err } } - return nil + return repoPath, nil +} + +// Remove removes an existing repository +func Remove(repoName string) (string, error) { + if err := validateRepoName(repoName); err != nil { + return "", err + } + repoPath := path.Join(BaseDir, repoName) + if err := validateRepoPath(repoPath); err != nil { + return "", err + } + if err := os.RemoveAll(repoPath); err != nil { + return "", err + } + return repoPath, nil } // AddPaths adds the given paths from the given repository @@ -82,6 +100,8 @@ func removePath(repoPath, targetPath string) error { return os.RemoveAll(intPath) } +type syncFunc func(string, string) error + // syncRepository synchronizes all given paths within `repoPath` func syncRepository(repoPath string, paths []string, updateRepository syncFunc) error { for _, extPath := range paths { diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 9bce7f8..b2d5966 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -24,6 +24,27 @@ func GetDefault() (string, error) { return getFirst() } +// List returns a list of repositories +func List() ([]string, error) { + entries, err := ioutil.ReadDir(BaseDir) + if err != nil { + return nil, err + } + repoNames := []string{} + for _, fileInfo := range entries { + repoName := fileInfo.Name() + if err := validateRepoName(repoName); err != nil { + continue + } + repoPath := path.Join(BaseDir, repoName) + if err := validateRepoPath(repoPath); err != nil { + continue + } + repoNames = append(repoNames, repoName) + } + return repoNames, nil +} + // RootPath returns an absolute filesystem path which corresponds to the given // repository name or the default repository's path if the given name is empty func RootPath(name string) (string, error) { @@ -31,7 +52,7 @@ func RootPath(name string) (string, error) { return GetDefault() } - if err := ValidateRepoName(name); err != nil { + if err := validateRepoName(name); err != nil { return "", err } p := path.Join(BaseDir, name) diff --git a/internal/repository/validate.go b/internal/repository/validate.go index df6d977..da0240f 100644 --- a/internal/repository/validate.go +++ b/internal/repository/validate.go @@ -5,13 +5,15 @@ import ( "os" "regexp" "strings" + + "github.com/andornaut/gog/internal/git" ) -// ValidateRepoName returns an error if the repo name is invalid -func ValidateRepoName(name string) error { +// validateRepoName returns an error if the repo name is invalid +func validateRepoName(name string) error { validRepoName := regexp.MustCompile(`^[\w-_]+$`) if !validRepoName.MatchString(name) { - return fmt.Errorf("Invalid repository name: %s", name) + return fmt.Errorf("invalid repository name: %s", name) } return nil } @@ -19,17 +21,20 @@ func ValidateRepoName(name string) error { func validateRepoPath(p string) error { fileInfo, err := os.Stat(p) if err != nil { - return fmt.Errorf("Invalid repository path: %s", p) + return fmt.Errorf("invalid repository path: %s", p) } if !fileInfo.IsDir() { - return fmt.Errorf("Repository path must be a directory: %s", p) + return fmt.Errorf("repository path must be a directory: %s", p) + } + if !git.Is(p) { + return fmt.Errorf("repository must be initialized as a git repository") } return nil } func validateTargetPath(p string) error { if shouldSkip(p, "") { - return fmt.Errorf("Invalid target path: %s", p) + return fmt.Errorf("invalid target path: %s", p) } return nil }