diff options
| author | Stefan Majewsky <majewsky@gmx.net> | 2017-05-09 21:32:16 +0200 |
|---|---|---|
| committer | Stefan Majewsky <majewsky@gmx.net> | 2017-05-09 21:38:24 +0200 |
| commit | a92faf7689fa01595fd613ddd3880e9c301ed558 (patch) | |
| tree | f6607fa23ac41385f9f18d8ed6ad0f970c4ba6df /pkg | |
| parent | a4dfbab3b06360245f6b2fce4b56d6caf2729f8f (diff) | |
| download | gofu-a92faf7689fa01595fd613ddd3880e9c301ed558.tar.gz | |
refactor cli.Interface yet again
- Only one global instance now, so we don't need to pass it around all
the time.
- Allow to swap out the Command.Run implementation for unit tests.
- Can now use cli.Interface during func init() of packages importing
pkg/cli.
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/cli/command.go | 10 | ||||
| -rw-r--r-- | pkg/cli/interface.go | 76 | ||||
| -rw-r--r-- | pkg/cli/query.go | 6 | ||||
| -rw-r--r-- | pkg/rtree/index.go | 48 | ||||
| -rw-r--r-- | pkg/rtree/main.go | 80 | ||||
| -rw-r--r-- | pkg/rtree/remote.go | 14 | ||||
| -rw-r--r-- | pkg/rtree/repo.go | 26 |
7 files changed, 136 insertions, 124 deletions
diff --git a/pkg/cli/command.go b/pkg/cli/command.go index 5b3ded5..d07a120 100644 --- a/pkg/cli/command.go +++ b/pkg/cli/command.go @@ -26,7 +26,7 @@ import ( ) //Command describes a command that can be run using the methods in the -//Interface interface. +//Implementation interface. type Command struct { Program []string WorkDir string @@ -49,8 +49,14 @@ func (e commandError) Error() string { ) } -func (c Command) run(stdout, stderr io.Writer) error { +//CommandRunner is a function that can execute commands given to it. +//This interface is only useful for unit tests; the default CommandRunner +//suffices for all regular operation. +type CommandRunner func(c Command, stdin io.Reader, stdout, stderr io.Writer) error + +func DefaultCommandRunner(c Command, stdin io.Reader, stdout, stderr io.Writer) error { cmd := exec.Command(c.Program[0], c.Program[1:]...) + cmd.Stdin = stdin cmd.Stdout = stdout cmd.Stderr = stderr cmd.Dir = c.WorkDir diff --git a/pkg/cli/interface.go b/pkg/cli/interface.go index c188c77..0f1ba74 100644 --- a/pkg/cli/interface.go +++ b/pkg/cli/interface.go @@ -30,32 +30,40 @@ import ( "golang.org/x/crypto/ssh/terminal" ) -//NewInterface creates an Interface instance. -func NewInterface(stdin, stdout, stderr *os.File) *Interface { - i := &Interface{ - stdin: stdin, - stdout: stdout, - stderr: stderr, - stdinBuf: bufio.NewReader(stdin), +//Interface wraps access to the CLI, including input, output and subprocesses. +var Interface *Implementation + +func init() { + SetupInterface(os.Stdin, os.Stdout, os.Stderr, DefaultCommandRunner) +} + +//SetupInterface prepares the Interface instance with nonstandard file streams +//or a nonstandard CommandRunner. This is only required for unit tests. +func SetupInterface(stdin io.Reader, stdout, stderr io.Writer, commandRunner CommandRunner) { + Interface = &Implementation{ + stdin: stdin, + stdout: stdout, + stderr: stderr, + stdinBuf: bufio.NewReader(stdin), + commandRunner: commandRunner, } - if terminal.IsTerminal(int(stdin.Fd())) { - i.tui = &terminalTUI{i} + if stdinFile, ok := stdin.(*os.File); ok && terminal.IsTerminal(int(stdinFile.Fd())) { + Interface.tui = &terminalTUI{Interface} } else { - i.tui = &pipeTUI{i} + Interface.tui = &pipeTUI{Interface} } - - return i } -//Interface wraps access to the CLI, including input, output and subprocesses. -type Interface struct { +//Implementation wraps access to the CLI, including input, output and subprocesses. +type Implementation struct { //TODO: flag isStdinTerminal that disables color output and swaps out the TUI instance - stdin io.Reader - stdout io.Writer - stderr io.Writer - stdinBuf *bufio.Reader - tui TUI + stdin io.Reader + stdout io.Writer + stderr io.Writer + stdinBuf *bufio.Reader + tui TUI + commandRunner CommandRunner //If this flag is set, only ShowResult() will write into stdout; everything //else that usually goes to stdout goes to stderr instead. // @@ -65,7 +73,7 @@ type Interface struct { StdoutProtected bool } -//TUI provides the interactive parts of the cli.Interface, so that these can be +//TUI provides the interactive parts of the cli.Implementation, so that these can be //easily swapped out for mock implementations in unit tests. type TUI interface { //ReadLine reads a line from stdin (if tty: uses canonical mode). @@ -77,7 +85,7 @@ type TUI interface { Query(prompt string, choices ...Choice) (string, error) } -func (i *Interface) safeStdout() io.Writer { +func (i *Implementation) safeStdout() io.Writer { if i.StdoutProtected { return i.stderr } @@ -88,18 +96,18 @@ func (i *Interface) safeStdout() io.Writer { // input //ReadLine reads a line from stdin (if tty: uses canonical mode). -func (i *Interface) ReadLine(prompt string) (string, error) { +func (i *Implementation) ReadLine(prompt string) (string, error) { return i.tui.ReadLine(prompt) } //Confirm displays a yes/no question and returns whether the user answered "yes". -func (i *Interface) Confirm(question string) (bool, error) { +func (i *Implementation) Confirm(question string) (bool, error) { return i.tui.Confirm(question) } //Query displays a question and a set of answers and allows the user to select //one of the answers. Returns the Return attribute of the selected Choice. -func (i *Interface) Query(prompt string, choices ...Choice) (string, error) { +func (i *Implementation) Query(prompt string, choices ...Choice) (string, error) { return i.tui.Query(prompt, choices...) } @@ -107,14 +115,14 @@ func (i *Interface) Query(prompt string, choices ...Choice) (string, error) { // subprocesses //Run executes the given command on the same stdout and stderr. -func (i *Interface) Run(c Command) error { - return c.run(i.safeStdout(), i.stderr) +func (i *Implementation) Run(c Command) error { + return i.commandRunner(c, nil, i.safeStdout(), i.stderr) } //CaptureStdout executes the given command on the same stderr and captures its stdout. -func (i *Interface) CaptureStdout(c Command) (string, error) { +func (i *Implementation) CaptureStdout(c Command) (string, error) { var buf bytes.Buffer - err := c.run(&buf, i.stderr) + err := i.commandRunner(c, nil, &buf, i.stderr) return string(buf.Bytes()), err } @@ -122,13 +130,13 @@ func (i *Interface) CaptureStdout(c Command) (string, error) { // output //ShowResult displays the result of a computation on stdout. -func (i *Interface) ShowResult(str string) { +func (i *Implementation) ShowResult(str string) { str = strings.TrimSpace(str) + "\n" i.stdout.Write([]byte(str)) } //ShowResultsSorted calls ShowResult() on each of the results after sorting them. -func (i *Interface) ShowResultsSorted(strs []string) { +func (i *Implementation) ShowResultsSorted(strs []string) { sort.Strings(strs) for _, str := range strs { i.ShowResult(str) @@ -136,22 +144,22 @@ func (i *Interface) ShowResultsSorted(strs []string) { } //ShowProgress displays a progress message on stderr. -func (i *Interface) ShowProgress(str string) { +func (i *Implementation) ShowProgress(str string) { fmt.Fprintf(i.stderr, "\x1B[0;1;36m>>\x1B[0;36m %s\x1B[0m", strings.TrimSpace(str)) } //ShowWarning displays a warning message on stderr. -func (i *Interface) ShowWarning(str string) { +func (i *Implementation) ShowWarning(str string) { fmt.Fprintf(i.stderr, "\x1B[0;1;33m!!\x1B[0;36m %s\x1B[0m", strings.TrimSpace(str)) } //ShowError displays an error message on stderr. -func (i *Interface) ShowError(str string) { +func (i *Implementation) ShowError(str string) { fmt.Fprintf(i.stderr, "\x1B[0;1;31m!!\x1B[0;36m %s\x1B[0m", strings.TrimSpace(str)) } //ShowUsage displays a usage synopsis on stderr. -func (i *Interface) ShowUsage(str string) { +func (i *Implementation) ShowUsage(str string) { str = strings.TrimSpace(str) + "\n" i.stderr.Write([]byte(str)) } diff --git a/pkg/cli/query.go b/pkg/cli/query.go index ed9e913..d9aa9a2 100644 --- a/pkg/cli/query.go +++ b/pkg/cli/query.go @@ -41,7 +41,7 @@ func (e errInterrupted) Error() string { // TUI implementation for when stdin is a terminal type terminalTUI struct { - i *Interface + i *Implementation } func (t terminalTUI) ReadLine(prompt string) (string, error) { @@ -78,7 +78,7 @@ type Choice struct { Shortcut byte //The display string that describes this choice. Text string - //The string to return from Interface.Query(). + //The string to return from Implementation.Query(). Return string } @@ -228,7 +228,7 @@ func (b *buffer) getNextInput() []byte { // TUI implementation for when stdin is a pipe type pipeTUI struct { - i *Interface + i *Implementation } func (t *pipeTUI) ReadLine(prompt string) (string, error) { diff --git a/pkg/rtree/index.go b/pkg/rtree/index.go index d0813fe..49ef385 100644 --- a/pkg/rtree/index.go +++ b/pkg/rtree/index.go @@ -104,7 +104,7 @@ func (r reposByAbsPath) Less(i, j int) bool { return r[i].AbsolutePath() < r[j]. func (r reposByAbsPath) Swap(i, j int) { r[i], r[j] = r[j], r[i] } //Write writes the index file to disk. -func (i *Index) Write(ci *cli.Interface) error { +func (i *Index) Write() error { buf, err := yaml.Marshal(i) if err != nil { return err @@ -125,7 +125,7 @@ func (i *Index) Write(ci *cli.Interface) error { warned := make(map[string]bool) for _, repo := range i.Repos { if seen[repo.CheckoutPath] && !warned[repo.CheckoutPath] { - ci.ShowWarning( + cli.Interface.ShowWarning( fmt.Sprintf("repo %s appears multiple times in the index file!", repo.AbsolutePath()), ) warned[repo.CheckoutPath] = true @@ -137,7 +137,7 @@ func (i *Index) Write(ci *cli.Interface) error { } //Rebuild implements the `rtree index` subcommand. -func (i *Index) Rebuild(ci *cli.Interface) error { +func (i *Index) Rebuild() error { //check if existing index entries are still checked out var newRepos []*Repo for _, repo := range i.Repos { @@ -167,13 +167,13 @@ func (i *Index) Rebuild(ci *cli.Interface) error { var selection string if len(remoteURLs) == 0 { - selection, err = ci.Query( + selection, err = cli.Interface.Query( fmt.Sprintf("repository %s has been deleted; no remote to restore from", filepath.Join(RootPath, repo.CheckoutPath)), cli.Choice{Return: "d", Shortcut: 'd', Text: "delete from index"}, cli.Choice{Return: "s", Shortcut: 's', Text: "skip"}, ) } else { - selection, err = ci.Query( + selection, err = cli.Interface.Query( fmt.Sprintf("repository %s has been deleted", filepath.Join(RootPath, repo.CheckoutPath)), cli.Choice{Return: "r", Shortcut: 'r', Text: "(r)estore from " + strings.Join(remoteURLs, " and ")}, cli.Choice{Return: "d", Shortcut: 'd', Text: "delete from index"}, @@ -186,7 +186,7 @@ func (i *Index) Rebuild(ci *cli.Interface) error { switch selection { case "r": - err := repo.Checkout(ci) + err := repo.Checkout() if err != nil { return err } @@ -204,7 +204,7 @@ func (i *Index) Rebuild(ci *cli.Interface) error { } //index new repos - err := ForeachPhysicalRepo(ci, func(newRepo Repo) error { + err := ForeachPhysicalRepo(func(newRepo Repo) error { repo, exists := existingRepos[newRepo.CheckoutPath] if exists { //update the existing index entry with the new remotes @@ -225,7 +225,7 @@ func (i *Index) Rebuild(ci *cli.Interface) error { //FindRepo locates the repo with the given remote if it exists on disk or (if //allowClone is set) clones it and adds it to the index. This is the meat of //`rtree get`, and is also used by `rtree drop`. -func (i *Index) FindRepo(ci *cli.Interface, remoteURL string, allowClone bool) (*Repo, error) { +func (i *Index) FindRepo(remoteURL string, allowClone bool) (*Repo, error) { //make sure that stdout is not used for prompts originalStdout := os.Stdout os.Stdout = os.Stderr @@ -277,12 +277,12 @@ func (i *Index) FindRepo(ci *cli.Interface, remoteURL string, allowClone bool) ( //if no fork candidates found, clone as new repo if len(candidates) == 0 { - err := newRepo.Checkout(ci) + err := newRepo.Checkout() if err != nil { return nil, err } i.Repos = append(i.Repos, &newRepo) - i.Write(ci) + i.Write() return &newRepo, nil } @@ -300,18 +300,18 @@ func (i *Index) FindRepo(ci *cli.Interface, remoteURL string, allowClone bool) ( Shortcut: 'n', Text: "clone to " + newRepo.AbsolutePath(), } - selection, err := ci.Query("Found possible fork candidates. What to do?", choices...) + selection, err := cli.Interface.Query("Found possible fork candidates. What to do?", choices...) if err != nil { return nil, err } if selection == "clone" { - err := newRepo.Checkout(ci) + err := newRepo.Checkout() if err != nil { return nil, err } i.Repos = append(i.Repos, &newRepo) - i.Write(ci) + i.Write() return &newRepo, nil } @@ -330,12 +330,12 @@ func (i *Index) FindRepo(ci *cli.Interface, remoteURL string, allowClone bool) ( prompt += fmt.Sprintf("\t(%s) %s\n", remote.Name, remote.URL) } prompt += fmt.Sprintf("Enter remote name for %s:", remoteURL) - remoteName, err := ci.ReadLine(prompt) + remoteName, err := cli.Interface.ReadLine(prompt) if err != nil { return nil, err } - err = ci.Run(cli.Command{ + err = cli.Interface.Run(cli.Command{ Program: []string{"git", "remote", "add", remoteName, remoteURL}, WorkDir: target.AbsolutePath(), }) @@ -343,7 +343,7 @@ func (i *Index) FindRepo(ci *cli.Interface, remoteURL string, allowClone bool) ( return nil, err } - err = ci.Run(cli.Command{ + err = cli.Interface.Run(cli.Command{ Program: []string{"git", "remote", "update", remoteName}, WorkDir: target.AbsolutePath(), }) @@ -355,18 +355,18 @@ func (i *Index) FindRepo(ci *cli.Interface, remoteURL string, allowClone bool) ( Name: remoteName, URL: remoteURL, }) - i.Write(ci) + i.Write() return target, nil } //ImportRepo moves the given repo into the rtree and adds it to the index. -func (i *Index) ImportRepo(ci *cli.Interface, dirPath string) error { +func (i *Index) ImportRepo(dirPath string) error { //need to make dirPath absolute first dirPath, err := filepath.Abs(dirPath) if err != nil { return err } - repo, err := NewRepoFromAbsolutePath(ci, dirPath) + repo, err := NewRepoFromAbsolutePath(dirPath) if err != nil { return err } @@ -399,7 +399,7 @@ func (i *Index) ImportRepo(ci *cli.Interface, dirPath string) error { } question := fmt.Sprintf("Repo has multiple remotes. Where to put below %s?", RootPath) - checkoutPath, err = ci.Query(question, choices...) + checkoutPath, err = cli.Interface.Query(question, choices...) if err != nil { return err } @@ -422,12 +422,12 @@ func (i *Index) ImportRepo(ci *cli.Interface, dirPath string) error { } //DropRepo deletes the given repo from the rtree and removes it from the index. -func (i *Index) DropRepo(ci *cli.Interface, repo *Repo) error { - err := repo.Exec(ci, "git", "status") +func (i *Index) DropRepo(repo *Repo) error { + err := repo.Exec("git", "status") if err != nil { return err } - ok, err := ci.Confirm(">> Drop this repo?") + ok, err := cli.Interface.Confirm(">> Drop this repo?") if !ok || err != nil { return err } @@ -444,5 +444,5 @@ func (i *Index) DropRepo(ci *cli.Interface, repo *Repo) error { } } i.Repos = reposNew - return i.Write(ci) + return i.Write() } diff --git a/pkg/rtree/main.go b/pkg/rtree/main.go index 42e540e..581fa7e 100644 --- a/pkg/rtree/main.go +++ b/pkg/rtree/main.go @@ -26,15 +26,15 @@ import ( //Exec executes the rtree applet and does not return. The argument is os.Args //minus the leading "rtree" or "gofu rtree". -func Exec(ci *cli.Interface, args []string) int { +func Exec(args []string) int { if len(args) == 0 { - return usage(ci) + return usage() } index, errs := ReadIndex() if len(errs) > 0 { for _, err := range errs { - ci.ShowError(err.Error()) + cli.Interface.ShowError(err.Error()) } return 1 } @@ -43,47 +43,47 @@ func Exec(ci *cli.Interface, args []string) int { switch args[0] { case "get": if len(args) != 2 { - return usage(ci) + return usage() } - err = commandGet(ci, index, args[1]) + err = commandGet(index, args[1]) case "drop": if len(args) != 2 { - return usage(ci) + return usage() } - err = commandDrop(ci, index, args[1]) + err = commandDrop(index, args[1]) case "index": if len(args) != 1 { - return usage(ci) + return usage() } - err = commandIndex(ci, index) + err = commandIndex(index) case "repos": if len(args) != 1 { - return usage(ci) + return usage() } - commandRepos(ci, index) + commandRepos(index) case "remotes": if len(args) != 1 { - return usage(ci) + return usage() } - commandRemotes(ci, index) + commandRemotes(index) case "import": if len(args) != 2 { - return usage(ci) + return usage() } - err = commandImport(ci, index, args[1]) + err = commandImport(index, args[1]) case "each": if len(args) < 2 { - return usage(ci) + return usage() } - return commandEach(ci, index, args[1:]) + return commandEach(index, args[1:]) default: - return usage(ci) + return usage() } if err == nil { return 0 } - ci.ShowError(err.Error()) + cli.Interface.ShowError(err.Error()) return 1 } @@ -95,70 +95,70 @@ Usage: rtree each <command> `) -func usage(ci *cli.Interface) int { - ci.ShowUsage(usageStr) +func usage() int { + cli.Interface.ShowUsage(usageStr) return 1 } -func commandGet(ci *cli.Interface, index *Index, url string) error { - repo, err := index.FindRepo(ci, url, true) +func commandGet(index *Index, url string) error { + repo, err := index.FindRepo(url, true) if err != nil { return err } - ci.ShowResult(repo.AbsolutePath()) + cli.Interface.ShowResult(repo.AbsolutePath()) return nil } -func commandDrop(ci *cli.Interface, index *Index, url string) error { - repo, err := index.FindRepo(ci, url, true) +func commandDrop(index *Index, url string) error { + repo, err := index.FindRepo(url, true) if err != nil { return err } - return index.DropRepo(ci, repo) + return index.DropRepo(repo) } -func commandIndex(ci *cli.Interface, index *Index) error { - err := index.Rebuild(ci) +func commandIndex(index *Index) error { + err := index.Rebuild() if err != nil { return err } - return index.Write(ci) + return index.Write() } -func commandRepos(ci *cli.Interface, index *Index) { +func commandRepos(index *Index) { var items []string for _, repo := range index.Repos { items = append(items, repo.CheckoutPath) } - ci.ShowResultsSorted(items) + cli.Interface.ShowResultsSorted(items) } -func commandRemotes(ci *cli.Interface, index *Index) { +func commandRemotes(index *Index) { var items []string for _, repo := range index.Repos { for _, remote := range repo.Remotes { items = append(items, remote.URL) } } - ci.ShowResultsSorted(items) + cli.Interface.ShowResultsSorted(items) } -func commandEach(ci *cli.Interface, index *Index, cmdline []string) (exitCode int) { +func commandEach(index *Index, cmdline []string) (exitCode int) { exitCode = 0 for _, repo := range index.Repos { - err := repo.Exec(ci, cmdline...) + err := repo.Exec(cmdline...) if err != nil { - ci.ShowError(err.Error()) + cli.Interface.ShowError(err.Error()) exitCode = 1 } } return } -func commandImport(ci *cli.Interface, index *Index, dirPath string) error { - err := index.ImportRepo(ci, dirPath) +func commandImport(index *Index, dirPath string) error { + err := index.ImportRepo(dirPath) if err != nil { return err } - return index.Write(ci) + return index.Write() } diff --git a/pkg/rtree/remote.go b/pkg/rtree/remote.go index 353916d..8f88deb 100644 --- a/pkg/rtree/remote.go +++ b/pkg/rtree/remote.go @@ -19,13 +19,12 @@ package rtree import ( - "bytes" "net/url" - "os/exec" "path/filepath" "regexp" "strings" + "github.com/majewsky/gofu/pkg/cli" "github.com/majewsky/gofu/pkg/earlyerrors" ) @@ -39,16 +38,15 @@ type remoteAlias struct { var remoteAliases []*remoteAlias func init() { - cmd := exec.Command("git", "config", "--global", "-l") - var buf bytes.Buffer - cmd.Stdout = &buf - err := cmd.Run() + out, err := cli.Interface.CaptureStdout(cli.Command{ + Program: []string{"git", "config", "--global", "-l"}, + }) if err != nil { - earlyerrors.Put("exec `git config --global -l` failed: " + err.Error()) + earlyerrors.Put(err.Error()) } rx := regexp.MustCompile(`^url\.([^=]+)\.insteadof=(.+)$`) - for _, line := range strings.Split(string(buf.Bytes()), "\n") { + for _, line := range strings.Split(out, "\n") { match := rx.FindStringSubmatch(line) if match == nil { continue diff --git a/pkg/rtree/repo.go b/pkg/rtree/repo.go index 99df30d..636e3a7 100644 --- a/pkg/rtree/repo.go +++ b/pkg/rtree/repo.go @@ -65,14 +65,14 @@ func (r Repo) AbsolutePath() string { //NewRepoFromAbsolutePath initializes a Repo instance by scanning the existing //checkout at the given path. -func NewRepoFromAbsolutePath(ci *cli.Interface, path string) (repo Repo, err error) { +func NewRepoFromAbsolutePath(path string) (repo Repo, err error) { repo.CheckoutPath, err = filepath.Rel(RootPath, path) if err != nil { return } //list remotes - out, err := ci.CaptureStdout(cli.Command{ + out, err := cli.Interface.CaptureStdout(cli.Command{ Program: []string{"git", "config", "-l"}, WorkDir: path, }) @@ -113,7 +113,7 @@ var remoteConfigRx = regexp.MustCompile(`remote\.([^=]+)\.url=(.+)`) //ForeachPhysicalRepo walks over the repository tree, executing the action //function once for every repo encountered (but *not* for repos contained //within other repos, e.g. submodules). -func ForeachPhysicalRepo(ci *cli.Interface, action func(repo Repo) error) error { +func ForeachPhysicalRepo(action func(repo Repo) error) error { return filepath.Walk(RootPath, func(path string, info os.FileInfo, err error) error { if err != nil { return err @@ -128,7 +128,7 @@ func ForeachPhysicalRepo(ci *cli.Interface, action func(repo Repo) error) error } //appears to be a repo - repo, err := NewRepoFromAbsolutePath(ci, path) + repo, err := NewRepoFromAbsolutePath(path) if err == nil { err = action(repo) } @@ -142,7 +142,7 @@ func ForeachPhysicalRepo(ci *cli.Interface, action func(repo Repo) error) error //Checkout creates the repo in the given path with the given remotes. The //working copy will only be initialized if there is an "origin" remote. -func (r Repo) Checkout(ci *cli.Interface) error { +func (r Repo) Checkout() error { //check if we have an "origin" remote to clone from var originURL string for _, remote := range r.Remotes { @@ -153,15 +153,15 @@ func (r Repo) Checkout(ci *cli.Interface) error { } if originURL == "" { - err := ci.Run(cli.Command{ + err := cli.Interface.Run(cli.Command{ Program: []string{"git", "init", r.AbsolutePath()}, }) if err != nil { return err } - ci.ShowWarning(`will not checkout anything since there is no remote named "origin"`) + cli.Interface.ShowWarning(`will not checkout anything since there is no remote named "origin"`) } else { - err := ci.Run(cli.Command{ + err := cli.Interface.Run(cli.Command{ Program: []string{"git", "clone", originURL, r.AbsolutePath()}, }) if err != nil { @@ -172,7 +172,7 @@ func (r Repo) Checkout(ci *cli.Interface) error { remotesAdded := false for _, remote := range r.Remotes { if remote.Name != "origin" { - err := ci.Run(cli.Command{ + err := cli.Interface.Run(cli.Command{ Program: []string{"git", "remote", "add", remote.Name, remote.URL}, WorkDir: r.AbsolutePath(), }) @@ -183,7 +183,7 @@ func (r Repo) Checkout(ci *cli.Interface) error { } } if remotesAdded { - return ci.Run(cli.Command{ + return cli.Interface.Run(cli.Command{ Program: []string{"git", "remote", "update"}, WorkDir: r.AbsolutePath(), }) @@ -194,9 +194,9 @@ func (r Repo) Checkout(ci *cli.Interface) error { //Exec implements the meat of the `rtree exec` command. It returns //true iff the command exited successfully. -func (r Repo) Exec(ci *cli.Interface, cmdline ...string) error { - ci.ShowProgress(r.AbsolutePath()) - return ci.Run(cli.Command{ +func (r Repo) Exec(cmdline ...string) error { + cli.Interface.ShowProgress(r.AbsolutePath()) + return cli.Interface.Run(cli.Command{ Program: cmdline, WorkDir: r.AbsolutePath(), }) |
