diff --git a/plugin.go b/plugin.go index 6708686..5ea3940 100644 --- a/plugin.go +++ b/plugin.go @@ -86,21 +86,43 @@ func trimPath(keys []string) []string { return newKeys } -func globList(paths []string) []string { - var newPaths []string +func globList(paths []string) fileList { + var list fileList for _, pattern := range paths { + ignore := false pattern = strings.Trim(pattern, " ") + if string(pattern[0]) == "!" { + pattern = pattern[1:] + ignore = true + } matches, err := filepath.Glob(pattern) if err != nil { fmt.Printf("Glob error for %q: %s\n", pattern, err) continue } - newPaths = append(newPaths, matches...) + if ignore { + list.Ignore = append(list.Ignore, matches...) + } else { + list.Source = append(list.Source, matches...) + } } - return newPaths + return list +} + +func buildArgs(tar string, files fileList) []string { + args := []string{} + if len(files.Ignore) > 0 { + args = append(args, "--exclude") + args = append(args, files.Ignore...) + } + args = append(args, "-cf") + args = append(args, getRealPath(tar)) + args = append(args, files.Source...) + + return args } func (p Plugin) log(host string, message ...interface{}) { @@ -157,6 +179,11 @@ func (p *Plugin) removeAllDestFile() error { return nil } +type fileList struct { + Ignore []string + Source []string +} + // Exec executes the plugin. func (p *Plugin) Exec() error { @@ -184,8 +211,7 @@ func (p *Plugin) Exec() error { // run archive command fmt.Println("tar all files into " + tar) - args := append(append([]string{}, "-cf", getRealPath(tar)), files...) - + args := buildArgs(tar, files) cmd := exec.Command(p.Config.TarExec, args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr diff --git a/plugin_test.go b/plugin_test.go index c3f2ae4..da0e563 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -80,7 +80,9 @@ func TestTrimElement(t *testing.T) { func TestSCPFileFromPublicKey(t *testing.T) { if os.Getenv("SSH_AUTH_SOCK") != "" { - exec.Command("eval", "`ssh-agent -k`").Run() + if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil { + t.Fatalf("exec: %v", err) + } } u, err := user.Lookup("drone-scp") @@ -128,7 +130,9 @@ func TestSCPFileFromPublicKey(t *testing.T) { func TestSCPWildcardFileList(t *testing.T) { if os.Getenv("SSH_AUTH_SOCK") != "" { - exec.Command("eval", "`ssh-agent -k`").Run() + if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil { + t.Fatalf("exec: %v", err) + } } u, err := user.Lookup("drone-scp") @@ -202,7 +206,9 @@ func TestSCPFromProxySetting(t *testing.T) { func TestStripComponentsFlag(t *testing.T) { if os.Getenv("SSH_AUTH_SOCK") != "" { - exec.Command("eval", "`ssh-agent -k`").Run() + if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil { + t.Fatalf("exec: %v", err) + } } u, err := user.Lookup("drone-scp") @@ -237,6 +243,45 @@ func TestStripComponentsFlag(t *testing.T) { } } +func TestIgnoreList(t *testing.T) { + if os.Getenv("SSH_AUTH_SOCK") != "" { + if err := exec.Command("eval", "`ssh-agent -k`").Run(); err != nil { + t.Fatalf("exec: %v", err) + } + } + + u, err := user.Lookup("drone-scp") + if err != nil { + t.Fatalf("Lookup: %v", err) + } + + plugin := Plugin{ + Config: Config{ + Host: []string{"localhost"}, + Username: "drone-scp", + Port: "22", + KeyPath: "tests/.ssh/id_rsa", + Source: []string{"tests/global/*", "!tests/global/c.txt"}, + StripComponents: 2, + Target: []string{filepath.Join(u.HomeDir, "123")}, + CommandTimeout: 60, + TarExec: "tar", + }, + } + + err = plugin.Exec() + assert.Nil(t, err) + + // check file exist + if _, err := os.Stat(filepath.Join(u.HomeDir, "123/c.txt")); os.IsExist(err) { + t.Fatalf("SCP-error: %v", err) + } + + if _, err := os.Stat(filepath.Join(u.HomeDir, "123/d.txt")); os.IsNotExist(err) { + t.Fatalf("SCP-error: %v", err) + } +} + // func TestSCPFileFromSSHAgent(t *testing.T) { // if os.Getenv("SSH_AUTH_SOCK") == "" { // exec.Command("eval", "`ssh-agent -s`").Run() @@ -333,24 +378,50 @@ func TestGlobList(t *testing.T) { // wrong patern paterns := []string{"[]a]", "tests/?.txt"} expects := []string{"tests/a.txt", "tests/b.txt"} - assert.Equal(t, expects, globList(paterns)) + assert.Equal(t, expects, globList(paterns).Source) paterns = []string{"tests/*.txt", "tests/.ssh/*", "abc*"} expects = []string{"tests/a.txt", "tests/b.txt", "tests/.ssh/id_rsa", "tests/.ssh/id_rsa.pub"} - assert.Equal(t, expects, globList(paterns)) + assert.Equal(t, expects, globList(paterns).Source) paterns = []string{"tests/?.txt"} expects = []string{"tests/a.txt", "tests/b.txt"} - assert.Equal(t, expects, globList(paterns)) + assert.Equal(t, expects, globList(paterns).Source) // remove item which file not found. paterns = []string{"tests/aa.txt", "tests/b.txt"} expects = []string{"tests/b.txt"} - assert.Equal(t, expects, globList(paterns)) + assert.Equal(t, expects, globList(paterns).Source) paterns = []string{"./tests/b.txt"} expects = []string{"./tests/b.txt"} - assert.Equal(t, expects, globList(paterns)) + assert.Equal(t, expects, globList(paterns).Source) + + paterns = []string{"./tests/*.txt", "!./tests/b.txt"} + expectSources := []string{"tests/a.txt", "tests/b.txt"} + expectIgnores := []string{"./tests/b.txt"} + result := globList(paterns) + assert.Equal(t, expectSources, result.Source) + assert.Equal(t, expectIgnores, result.Ignore) +} + +func TestBuildArgs(t *testing.T) { + list := fileList{ + Source: []string{"tests/a.txt", "tests/b.txt"}, + Ignore: []string{"tests/a.txt"}, + } + + result := buildArgs("test.tar.gz", list) + expects := []string{"--exclude", "tests/a.txt", "-cf", "test.tar.gz", "tests/a.txt", "tests/b.txt"} + assert.Equal(t, expects, result) + + list = fileList{ + Source: []string{"tests/a.txt", "tests/b.txt"}, + } + + result = buildArgs("test.tar.gz", list) + expects = []string{"-cf", "test.tar.gz", "tests/a.txt", "tests/b.txt"} + assert.Equal(t, expects, result) } func TestRemoveDestFile(t *testing.T) {