From 9ad2862b7de64a47e0e897de43b08cd1ed1aaef7 Mon Sep 17 00:00:00 2001 From: jguer Date: Tue, 18 Aug 2020 01:19:51 +0200 Subject: [PATCH] feat(vcs): test upDevel and extract OS runner --- exec.go | 49 ++------------- pkg/settings/runtime.go | 65 ++++++++++++++++++++ upgrade_test.go | 129 ++++++++++++++++++++++++++++++++++++---- vcs.go | 27 +-------- 4 files changed, 190 insertions(+), 80 deletions(-) diff --git a/exec.go b/exec.go index da87affb..3515e652 100644 --- a/exec.go +++ b/exec.go @@ -121,56 +121,17 @@ func passToMakepkg(dir string, args ...string) *exec.Cmd { } func passToGit(dir string, _args ...string) *exec.Cmd { - gitflags := strings.Fields(config.GitFlags) - args := []string{"-C", dir} - args = append(args, gitflags...) + args := strings.Fields(config.GitFlags) + if dir != "" { + args = append(args, "-C", dir) + } args = append(args, _args...) cmd := exec.Command(config.GitBin, args...) + cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0") return cmd } func isTty() bool { return terminal.IsTerminal(int(os.Stdout.Fd())) } - -type Runner interface { - Capture(string, int64, ...string) (string, string, error) -} - -type OSRunner struct{} - -func (r *OSRunner) Capture(command string, timeout int64, args ...string) (stdout, stderr string, err error) { - var outbuf, errbuf bytes.Buffer - var timer *time.Timer - - cmd := exec.Command(command, args...) - cmd.Stdout = &outbuf - cmd.Stderr = &errbuf - err = cmd.Start() - if err != nil { - return "", "", err - } - - if timeout != 0 { - timer = time.AfterFunc(time.Duration(timeout)*time.Second, func() { - err = cmd.Process.Kill() - if err != nil { - text.Errorln(err) - } - }) - } - - err = cmd.Wait() - if timeout != 0 { - timer.Stop() - } - if err != nil { - return "", "", err - } - - stdout = strings.TrimSpace(outbuf.String()) - stderr = strings.TrimSpace(errbuf.String()) - - return stdout, stderr, err -} diff --git a/pkg/settings/runtime.go b/pkg/settings/runtime.go index 741fa1ce..c53f4403 100644 --- a/pkg/settings/runtime.go +++ b/pkg/settings/runtime.go @@ -1,12 +1,19 @@ package settings import ( + "bytes" + "fmt" "os" + "os/exec" "path/filepath" + "strings" + "time" "github.com/Morganamilo/go-pacmanconf" "github.com/leonelquinteros/gotext" "github.com/pkg/errors" + + "github.com/Jguer/yay/v10/pkg/text" ) type TargetMode int @@ -25,6 +32,62 @@ const ( ModeRepo ) +type Runner interface { + Capture(cmd *exec.Cmd, timeout int64) (stdout string, stderr string, err error) + Show(cmd *exec.Cmd) error +} + +type OSRunner struct { +} + +func (r *OSRunner) Show(cmd *exec.Cmd) error { + cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr + err := cmd.Run() + if err != nil { + return fmt.Errorf("") + } + return nil +} + +func (r *OSRunner) Capture(cmd *exec.Cmd, timeout int64) (stdout, stderr string, err error) { + var outbuf, errbuf bytes.Buffer + var timer *time.Timer + timedOut := false + + cmd.Stdout = &outbuf + cmd.Stderr = &errbuf + err = cmd.Start() + if err != nil { + return "", "", err + } + + if timeout != 0 { + timer = time.AfterFunc(time.Duration(timeout)*time.Second, func() { + err = cmd.Process.Kill() + if err != nil { + text.Errorln(err) + } + timedOut = true + }) + } + + err = cmd.Wait() + if timeout != 0 { + timer.Stop() + } + if err != nil { + return "", "", err + } + + stdout = strings.TrimSpace(outbuf.String()) + stderr = strings.TrimSpace(errbuf.String()) + if timedOut { + err = fmt.Errorf("command timed out") + } + + return stdout, stderr, err +} + type Runtime struct { Mode TargetMode SaveConfig bool @@ -32,6 +95,7 @@ type Runtime struct { ConfigPath string VCSPath string PacmanConf *pacmanconf.Config + CmdRunner Runner } func MakeRuntime() (*Runtime, error) { @@ -42,6 +106,7 @@ func MakeRuntime() (*Runtime, error) { Mode: ModeAny, SaveConfig: false, CompletionPath: "", + CmdRunner: &OSRunner{}, } if configHome = os.Getenv("XDG_CONFIG_HOME"); configHome != "" { diff --git a/upgrade_test.go b/upgrade_test.go index ed77fbc5..8b80572a 100644 --- a/upgrade_test.go +++ b/upgrade_test.go @@ -1,17 +1,22 @@ package main import ( + "fmt" "io/ioutil" "os" + "os/exec" + "strconv" "testing" "time" - "github.com/Jguer/yay/v10/pkg/db" - "github.com/Jguer/yay/v10/pkg/db/mock" - "github.com/Jguer/yay/v10/pkg/upgrade" "github.com/bradleyjkemp/cupaloy" rpc "github.com/mikkeloscar/aur" "github.com/stretchr/testify/assert" + + "github.com/Jguer/yay/v10/pkg/db" + "github.com/Jguer/yay/v10/pkg/db/mock" + "github.com/Jguer/yay/v10/pkg/settings" + "github.com/Jguer/yay/v10/pkg/upgrade" ) func Test_upAUR(t *testing.T) { @@ -68,16 +73,51 @@ func Test_upAUR(t *testing.T) { } } +type MockRunner struct { + Returned []string + Index int + t *testing.T +} + +func (r *MockRunner) Show(cmd *exec.Cmd) error { + return nil +} + +func (r *MockRunner) Capture(cmd *exec.Cmd, timeout int64) (stdout, stderr string, err error) { + i, _ := strconv.Atoi(cmd.Args[len(cmd.Args)-1]) + if i >= len(r.Returned) { + fmt.Println(r.Returned) + fmt.Println(cmd.Args) + fmt.Println(i) + } + stdout = r.Returned[i] + assert.Contains(r.t, cmd.Args, "ls-remote") + return stdout, stderr, err +} + func Test_upDevel(t *testing.T) { + config = settings.MakeConfig() + config.Runtime, _ = settings.MakeRuntime() + config.Runtime.CmdRunner = &MockRunner{ + Returned: []string{ + "7f4c277ce7149665d1c79b76ca8fbb832a65a03b HEAD", + "7f4c277ce7149665d1c79b76ca8fbb832a65a03b HEAD", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa HEAD", + "cccccccccccccccccccccccccccccccccccccccc HEAD", + "991c5b4146fd27f4aacf4e3111258a848934aaa1 HEAD", + }, + } + type args struct { remote []db.RepoPackage aurdata map[string]*rpc.Pkg cached vcsInfo } tests := []struct { - name string - args args - want upgrade.UpSlice + name string + args args + want upgrade.UpSlice + finalLen int }{ {name: "No Updates", args: args{ @@ -92,22 +132,89 @@ func Test_upDevel(t *testing.T) { }, want: upgrade.UpSlice{}}, {name: "Simple Update", + finalLen: 3, args: args{ cached: vcsInfo{ "hello": shaInfos{ - "github.com/Jguer/yay.git": shaInfo{ + "github.com/Jguer/z.git": shaInfo{ Protocols: []string{"https"}, - Branch: "main", + Branch: "0", + SHA: "991c5b4146fd27f4aacf4e3111258a848934aaa1"}}, + "hello-non-existant": shaInfos{ + "github.com/Jguer/y.git": shaInfo{ + Protocols: []string{"https"}, + Branch: "0", + SHA: "991c5b4146fd27f4aacf4e3111258a848934aaa1"}}, + "hello2": shaInfos{ + "github.com/Jguer/a.git": shaInfo{ + Protocols: []string{"https"}, + Branch: "1", + SHA: "7f4c277ce7149665d1c79b76ca8fbb832a65a03b"}}, + "hello4": shaInfos{ + "github.com/Jguer/b.git": shaInfo{ + Protocols: []string{"https"}, + Branch: "2", + SHA: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, + "github.com/Jguer/c.git": shaInfo{ + Protocols: []string{"https"}, + Branch: "3", + SHA: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}, + }, + }, + remote: []db.RepoPackage{ + &mock.Package{PName: "hello", PVersion: "2.0.0"}, + &mock.Package{PName: "hello2", PVersion: "3.0.0"}, + &mock.Package{PName: "hello4", PVersion: "4.0.0"}}, + aurdata: map[string]*rpc.Pkg{ + "hello": {Version: "2.0.0", Name: "hello"}, + "hello2": {Version: "2.0.0", Name: "hello2"}, + "hello4": {Version: "2.0.0", Name: "hello4"}, + }, + }, + want: upgrade.UpSlice{upgrade.Upgrade{ + Name: "hello", + Repository: "devel", + LocalVersion: "2.0.0", + RemoteVersion: "latest-commit"}, + upgrade.Upgrade{ + Name: "hello4", + Repository: "devel", + LocalVersion: "4.0.0", + RemoteVersion: "latest-commit"}, + }}, + {name: "No update returned", + finalLen: 1, + args: args{ + cached: vcsInfo{ + "hello": shaInfos{ + "github.com/Jguer/d.git": shaInfo{ + Protocols: []string{"https"}, + Branch: "4", SHA: "991c5b4146fd27f4aacf4e3111258a848934aaa1"}}}, remote: []db.RepoPackage{&mock.Package{PName: "hello", PVersion: "2.0.0"}}, - aurdata: map[string]*rpc.Pkg{"hello": {Version: "2.1.0", Name: "hello"}}, + aurdata: map[string]*rpc.Pkg{"hello": {Version: "2.0.0", Name: "hello"}}, }, - want: upgrade.UpSlice{upgrade.Upgrade{Name: "hello", Repository: "aur", LocalVersion: "2.0.0", RemoteVersion: "2.1.0"}}}, + want: upgrade.UpSlice{}}, + {name: "No update returned - ignored", + finalLen: 1, + args: args{ + cached: vcsInfo{ + "hello": shaInfos{ + "github.com/Jguer/e.git": shaInfo{ + Protocols: []string{"https"}, + Branch: "3", + SHA: "991c5b4146fd27f4aacf4e3111258a848934aaa1"}}}, + remote: []db.RepoPackage{&mock.Package{PName: "hello", PVersion: "2.0.0", PShouldIgnore: true}}, + aurdata: map[string]*rpc.Pkg{"hello": {Version: "2.0.0", Name: "hello"}}, + }, + want: upgrade.UpSlice{}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + config.Runtime.CmdRunner.(*MockRunner).t = t got := upDevel(tt.args.remote, tt.args.aurdata, tt.args.cached) - assert.EqualValues(t, tt.want, got) + assert.ElementsMatch(t, tt.want, got) + assert.Equal(t, tt.finalLen, len(tt.args.cached)) }) } } diff --git a/vcs.go b/vcs.go index 51f978ee..6264acc1 100644 --- a/vcs.go +++ b/vcs.go @@ -1,13 +1,11 @@ package main import ( - "bytes" "encoding/json" "fmt" "os" "strings" "sync" - "time" gosrc "github.com/Morganamilo/go-srcinfo" "github.com/leonelquinteros/gotext" @@ -165,35 +163,14 @@ func updateVCSData(vcsFilePath, pkgName string, sources []gosrc.ArchString, mux func getCommit(url, branch string, protocols []string) string { if len(protocols) > 0 { protocol := protocols[len(protocols)-1] - var outbuf bytes.Buffer cmd := passToGit("", "ls-remote", protocol+"://"+url, branch) - cmd.Stdout = &outbuf - cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0") - - err := cmd.Start() + stdout, _, err := config.Runtime.CmdRunner.Capture(cmd, 5) if err != nil { + text.Warnln(err) return "" } - // for some reason - // git://bitbucket.org/volumesoffun/polyvox.git` hangs on my - // machine but using http:// instead of git does not hang. - // Introduce a time out so this can not hang - timer := time.AfterFunc(5*time.Second, func() { - err = cmd.Process.Kill() - if err != nil { - text.Errorln(err) - } - }) - - err = cmd.Wait() - timer.Stop() - if err != nil { - return "" - } - - stdout := outbuf.String() split := strings.Fields(stdout) if len(split) < 2 {