mirror of
https://github.com/grdl/git-get.git
synced 2026-02-05 04:24:41 +00:00
Refactor implementations of get and list commands
- Simplify the main functions by moving actual implementation to "pkg" package - Remove the "path" package and move files into the root "pkg" package - Replace viper with explicit Cfg structs
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package path
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
@@ -1,4 +1,4 @@
|
||||
package path
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -60,11 +60,11 @@ type gitconfig struct {
|
||||
*config.Config
|
||||
}
|
||||
|
||||
// InitConfig initializes viper config registry. Values are looked up in the following order: cli flag, env variable, gitconfig file, default value
|
||||
// Init initializes viper config registry. Values are looked up in the following order: cli flag, env variable, gitconfig file, default value
|
||||
// Viper doesn't support gitconfig file format so it can't find missing values there automatically. They need to be specified in setMissingValues func.
|
||||
//
|
||||
// Because it reads the cli flags it needs to be called after the cmd.Execute().
|
||||
func InitConfig() {
|
||||
func Init() {
|
||||
viper.SetEnvPrefix(strings.ToUpper(GitgetPrefix))
|
||||
viper.AutomaticEnv()
|
||||
|
||||
|
||||
58
pkg/get.go
Normal file
58
pkg/get.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"git-get/pkg/repo"
|
||||
"path"
|
||||
)
|
||||
|
||||
// GetCfg provides configuration for the Get command.
|
||||
type GetCfg struct {
|
||||
Branch string
|
||||
Dump string
|
||||
Root string
|
||||
URL string
|
||||
}
|
||||
|
||||
// Get executes the "git get" command.
|
||||
func Get(c *GetCfg) error {
|
||||
if c.Dump != "" {
|
||||
return cloneDumpFile(c)
|
||||
}
|
||||
|
||||
if c.URL != "" {
|
||||
return cloneSingleRepo(c)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func cloneSingleRepo(c *GetCfg) error {
|
||||
url, err := ParseURL(c.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cloneOpts := &repo.CloneOpts{
|
||||
URL: url,
|
||||
Path: path.Join(c.Root, URLToPath(url)),
|
||||
Branch: c.Branch,
|
||||
}
|
||||
|
||||
_, err = repo.Clone(cloneOpts)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func cloneDumpFile(c *GetCfg) error {
|
||||
opts, err := ParseBundleFile(c.Dump)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
path := path.Join(c.Root, URLToPath(opt.URL))
|
||||
opt.Path = path
|
||||
_, _ = repo.Clone(opt)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package path
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git-get/pkg/cfg"
|
||||
"git-get/pkg/print"
|
||||
"git-get/pkg/repo"
|
||||
"os"
|
||||
"sort"
|
||||
@@ -11,27 +12,62 @@ import (
|
||||
|
||||
"github.com/karrick/godirwalk"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// skipNode is used as an error indicating that .git directory has been found.
|
||||
// errSkipNode is used as an error indicating that .git directory has been found.
|
||||
// It's handled by ErrorsCallback to tell the WalkCallback to skip this dir.
|
||||
var skipNode = errors.New(".git directory found, skipping this node")
|
||||
var errSkipNode = errors.New(".git directory found, skipping this node")
|
||||
|
||||
var repos []string
|
||||
|
||||
func FindRepos() ([]string, error) {
|
||||
repos = []string{}
|
||||
// ListCfg provides configuration for the List command.
|
||||
type ListCfg struct {
|
||||
Fetch bool
|
||||
Output string
|
||||
PrivateKey string
|
||||
Root string
|
||||
}
|
||||
|
||||
root := viper.GetString(cfg.KeyReposRoot)
|
||||
// List executes the "git list" command.
|
||||
func List(c *ListCfg) error {
|
||||
paths, err := findRepos(c.Root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
repos, err := openAll(paths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var printer print.Printer
|
||||
switch c.Output {
|
||||
case cfg.OutFlat:
|
||||
printer = &print.FlatPrinter{}
|
||||
case cfg.OutTree:
|
||||
printer = &print.SimpleTreePrinter{}
|
||||
case cfg.OutSmart:
|
||||
printer = &print.SmartTreePrinter{}
|
||||
case cfg.OutDump:
|
||||
printer = &print.DumpPrinter{}
|
||||
default:
|
||||
return fmt.Errorf("invalid --out flag; allowed values: %v", []string{cfg.OutFlat, cfg.OutTree, cfg.OutSmart})
|
||||
}
|
||||
|
||||
fmt.Println(printer.Print(c.Root, repos))
|
||||
return nil
|
||||
}
|
||||
|
||||
func findRepos(root string) ([]string, error) {
|
||||
repos = []string{}
|
||||
|
||||
if _, err := os.Stat(root); err != nil {
|
||||
return nil, fmt.Errorf("Repos root %s does not exist or can't be accessed", root)
|
||||
}
|
||||
|
||||
walkOpts := &godirwalk.Options{
|
||||
ErrorCallback: ErrorCb,
|
||||
Callback: WalkCb,
|
||||
ErrorCallback: errorCb,
|
||||
Callback: walkCb,
|
||||
// Use Unsorted to improve speed because repos will be processed by goroutines in a random order anyway.
|
||||
Unsorted: true,
|
||||
}
|
||||
@@ -48,24 +84,24 @@ func FindRepos() ([]string, error) {
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
func WalkCb(path string, ent *godirwalk.Dirent) error {
|
||||
func walkCb(path string, ent *godirwalk.Dirent) error {
|
||||
if ent.IsDir() && ent.Name() == ".git" {
|
||||
repos = append(repos, strings.TrimSuffix(path, ".git"))
|
||||
return skipNode
|
||||
return errSkipNode
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ErrorCb(_ string, err error) godirwalk.ErrorAction {
|
||||
func errorCb(_ string, err error) godirwalk.ErrorAction {
|
||||
// Skip .git directory and directories we don't have permissions to access
|
||||
// TODO: Will syscall.EACCES work on windows?
|
||||
if errors.Is(err, skipNode) || errors.Is(err, syscall.EACCES) {
|
||||
if errors.Is(err, errSkipNode) || errors.Is(err, syscall.EACCES) {
|
||||
return godirwalk.SkipNode
|
||||
}
|
||||
return godirwalk.Halt
|
||||
}
|
||||
|
||||
func OpenAll(paths []string) ([]*repo.Repo, error) {
|
||||
func openAll(paths []string) ([]*repo.Repo, error) {
|
||||
var repos []*repo.Repo
|
||||
reposChan := make(chan *repo.Repo)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package path
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"git-get/pkg/cfg"
|
||||
@@ -11,9 +11,8 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrEmptyURLPath = errors.New("Parsed URL path is empty")
|
||||
)
|
||||
// ErrEmptyURLPath is an error indicating that the path part of URL is empty.
|
||||
var ErrEmptyURLPath = errors.New("Parsed URL path is empty")
|
||||
|
||||
// scpSyntax matches the SCP-like addresses used by the ssh protocol (eg, [user@]host.xz:path/to/repo.git/).
|
||||
// See: https://golang.org/src/cmd/go/internal/get/vcs.go
|
||||
@@ -1,4 +1,4 @@
|
||||
package path
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"git-get/pkg/cfg"
|
||||
@@ -50,7 +50,7 @@ func TestURLParse(t *testing.T) {
|
||||
}
|
||||
|
||||
// We need to init config first so the default values are correctly loaded
|
||||
cfg.InitConfig()
|
||||
cfg.Init()
|
||||
|
||||
for _, test := range tests {
|
||||
url, err := ParseURL(test.in)
|
||||
Reference in New Issue
Block a user