From bbdb2ebfa0bd840a460f5f418b0122d1fd704ef2 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Mon, 13 Jul 2015 22:05:21 +0200 Subject: [PATCH 1/7] Add filter implementation for files --- filter/doc.go | 5 + filter/filter.go | 151 +++++++++++++ filter/filter_test.go | 325 ++++++++++++++++++++++++++++ filter/testdata/libreoffice.txt.bz2 | Bin 0 -> 102857 bytes 4 files changed, 481 insertions(+) create mode 100644 filter/doc.go create mode 100644 filter/filter.go create mode 100644 filter/filter_test.go create mode 100644 filter/testdata/libreoffice.txt.bz2 diff --git a/filter/doc.go b/filter/doc.go new file mode 100644 index 000000000..4e0ba0f4d --- /dev/null +++ b/filter/doc.go @@ -0,0 +1,5 @@ +// Package filter implements filters for files similar to filepath.Glob, but +// in contrast to filepath.Glob a pattern may specify directories. +// +// For a list of valid patterns please see the documentation on filepath.Glob. +package filter diff --git a/filter/filter.go b/filter/filter.go new file mode 100644 index 000000000..493483a88 --- /dev/null +++ b/filter/filter.go @@ -0,0 +1,151 @@ +package filter + +import ( + "errors" + "path/filepath" + "strings" +) + +// ErrBadString is returned when Match is called with the empty string as the +// second argument. +var ErrBadString = errors.New("filter.Match: string is empty") + +// Match returns true if str matches the pattern. When the pattern is +// malformed, filepath.ErrBadPattern is returned. The empty pattern matches +// everything, when str is the empty string ErrBadString is returned. +// +// Pattern can be a combination of patterns suitable for filepath.Match, joined +// by filepath.Separator. +func Match(pattern, str string) (matched bool, err error) { + if pattern == "" { + return true, nil + } + + if str == "" { + return false, ErrBadString + } + + patterns := strings.Split(pattern, string(filepath.Separator)) + strs := strings.Split(str, string(filepath.Separator)) + + return match(patterns, strs) +} + +func match(patterns, strs []string) (matched bool, err error) { + if len(patterns) == 0 && len(strs) == 0 { + return true, nil + } + + if len(patterns) <= len(strs) { + outer: + for offset := len(strs) - len(patterns); offset >= 0; offset-- { + + for i := len(patterns) - 1; i >= 0; i-- { + ok, err := filepath.Match(patterns[i], strs[offset+i]) + if err != nil { + return false, err + } + + if !ok { + continue outer + } + } + + return true, nil + } + } + + return false, nil +} + +// MatchList returns true if str matches one of the patterns. +func MatchList(patterns []string, str string) (matched bool, err error) { + for _, pat := range patterns { + matched, err = Match(pat, str) + if err != nil { + return false, err + } + + if matched { + return true, nil + } + } + + return false, nil +} + +// matchList returns true if str matches one of the patterns. +func matchList(patterns [][]string, str []string) (matched bool, err error) { + for _, pat := range patterns { + matched, err = match(pat, str) + if err != nil { + return false, err + } + + if matched { + return true, nil + } + } + + return false, nil +} + +// Filter contains include and exclude patterns. If both lists of patterns are +// empty, all files are accepted. +type Filter struct { + include, exclude [][]string +} + +// New returns a new filter with the given include/exclude lists of patterns. +func New(include, exclude []string) *Filter { + f := &Filter{} + + for _, pat := range include { + f.include = append(f.include, strings.Split(pat, string(filepath.Separator))) + } + + for _, pat := range exclude { + f.exclude = append(f.exclude, strings.Split(pat, string(filepath.Separator))) + } + + return f +} + +// Match tests a filename against the filter. If include and exclude patterns +// are both empty, true is returned. +// +// If only include patterns and no exclude patterns are configured, true is +// returned iff name matches one of the include patterns. +// +// If only exclude patterns and no include patterns are configured, true is +// returned iff name does not match all of the exclude patterns. +func (f Filter) Match(name string) (matched bool, err error) { + if name == "" { + return false, ErrBadString + } + + if len(f.include) == 0 && len(f.exclude) == 0 { + return true, nil + } + + names := strings.Split(name, string(filepath.Separator)) + if len(f.exclude) == 0 { + return matchList(f.include, names) + } + + if len(f.include) == 0 { + match, err := matchList(f.exclude, names) + return !match, err + } + + excluded, err := matchList(f.exclude, names) + if err != nil { + return false, err + } + + if !excluded { + return true, nil + } + + return matchList(f.include, names) +} diff --git a/filter/filter_test.go b/filter/filter_test.go new file mode 100644 index 000000000..cd21ec054 --- /dev/null +++ b/filter/filter_test.go @@ -0,0 +1,325 @@ +package filter_test + +import ( + "bufio" + "compress/bzip2" + "fmt" + "os" + "testing" + + "github.com/restic/restic/filter" +) + +var matchTests = []struct { + pattern string + path string + match bool +}{ + {"", "", true}, + {"", "foo", true}, + {"", "/x/y/z/foo", true}, + {"*.go", "/foo/bar/test.go", true}, + {"*.c", "/foo/bar/test.go", false}, + {"*", "/foo/bar/test.go", true}, + {"foo*", "/foo/bar/test.go", true}, + {"bar*", "/foo/bar/test.go", true}, + {"/bar*", "/foo/bar/test.go", false}, + {"bar/*", "/foo/bar/test.go", true}, + {"baz/*", "/foo/bar/test.go", false}, + {"bar/test.go", "/foo/bar/test.go", true}, + {"bar/*.go", "/foo/bar/test.go", true}, + {"ba*/*.go", "/foo/bar/test.go", true}, + {"bb*/*.go", "/foo/bar/test.go", false}, + {"test.*", "/foo/bar/test.go", true}, + {"tesT.*", "/foo/bar/test.go", false}, + {"bar/*", "/foo/bar/baz", true}, + {"bar", "/foo/bar", true}, + {"bar", "/foo/bar/baz", true}, + {"bar", "/foo/bar/test.go", true}, + {"/foo/*test.*", "/foo/bar/test.go", false}, + {"/foo/*/test.*", "/foo/bar/test.go", true}, + {"/foo/*/bar/test.*", "/foo/bar/test.go", false}, + {"/*/*/bar/test.*", "/foo/bar/test.go", false}, + {"/*/*/bar/test.*", "/foo/bar/baz/test.go", false}, + {"/*/*/baz/test.*", "/foo/bar/baz/test.go", true}, + {"/*/foo/bar/test.*", "/foo/bar/baz/test.go", false}, + {"/*/foo/bar/test.*", "/foo/bar/baz/test.go", false}, + {"/foo/bar/test.*", "bar/baz/test.go", false}, + {"/x/y/bar/baz/test.*", "bar/baz/test.go", false}, + {"/x/y/bar/baz/test.c", "bar/baz/test.go", false}, + {"baz/test.*", "bar/baz/test.go", true}, + {"baz/tesT.*", "bar/baz/test.go", false}, + {"test.go", "bar/baz/test.go", true}, + {"*.go", "bar/baz/test.go", true}, + {"*.c", "bar/baz/test.go", false}, + {"sdk", "/foo/bar/sdk", true}, + {"sdk", "/foo/bar/sdk/test/sdk_foo.go", true}, + {"sdk/*/cpp/*/*vars*.html", "/usr/share/doc/libreoffice/sdk/docs/cpp/ref/a00517.html", false}, +} + +func TestMatch(t *testing.T) { + for i, test := range matchTests { + match, err := filter.Match(test.pattern, test.path) + if err != nil { + t.Errorf("test %d failed: expected no error for pattern %q, but error returned: %v", + i, test.pattern, err) + continue + } + + if match != test.match { + t.Errorf("test %d: filter.Match(%q, %q): expected %v, got %v", + i, test.pattern, test.path, test.match, match) + } + } +} + +func ExampleMatch() { + match, _ := filter.Match("*.go", "/home/user/file.go") + fmt.Printf("match: %v\n", match) + // Output: + // match: true +} + +func ExampleMatch_wildcards() { + match, _ := filter.Match("/home/[uU]ser/?.go", "/home/user/F.go") + fmt.Printf("match: %v\n", match) + // Output: + // match: true +} + +var filterListTests = []struct { + patterns []string + path string + match bool +}{ + {[]string{"*.go"}, "/foo/bar/test.go", true}, + {[]string{"*.c"}, "/foo/bar/test.go", false}, + {[]string{"*.go", "*.c"}, "/foo/bar/test.go", true}, + {[]string{"*"}, "/foo/bar/test.go", true}, + {[]string{"x"}, "/foo/bar/test.go", false}, + {[]string{"?"}, "/foo/bar/test.go", false}, + {[]string{"?", "x"}, "/foo/bar/x", true}, + {[]string{"/*/*/bar/test.*"}, "/foo/bar/test.go", false}, + {[]string{"/*/*/bar/test.*", "*.go"}, "/foo/bar/test.go", true}, +} + +func TestMatchList(t *testing.T) { + for i, test := range filterListTests { + match, err := filter.MatchList(test.patterns, test.path) + if err != nil { + t.Errorf("test %d failed: expected no error for patterns %q, but error returned: %v", + i, test.patterns, err) + continue + } + + if match != test.match { + t.Errorf("test %d: filter.MatchList(%q, %q): expected %v, got %v", + i, test.patterns, test.path, test.match, match) + } + } +} + +func ExampleMatchList() { + match, _ := filter.MatchList([]string{"*.c", "*.go"}, "/home/user/file.go") + fmt.Printf("match: %v\n", match) + // Output: + // match: true +} + +func extractTestLines(t testing.TB) (lines []string) { + f, err := os.Open("testdata/libreoffice.txt.bz2") + if err != nil { + t.Fatal(err) + } + + defer func() { + if err := f.Close(); err != nil { + t.Fatal(err) + } + }() + + sc := bufio.NewScanner(bzip2.NewReader(f)) + for sc.Scan() { + lines = append(lines, sc.Text()) + } + + return lines +} + +func TestFilterPatternsFile(t *testing.T) { + lines := extractTestLines(t) + + var testPatterns = []struct { + pattern string + hits uint + }{ + {"*.html", 18249}, + {"sdk", 22186}, + {"sdk/*/cpp/*/*vars.html", 3}, + } + + for _, test := range testPatterns { + var c uint + for _, line := range lines { + match, err := filter.Match(test.pattern, line) + if err != nil { + t.Error(err) + continue + } + + if match { + c++ + // fmt.Printf("pattern %q, line %q\n", test.pattern, line) + } + } + + if c != test.hits { + t.Errorf("wrong number of hits for pattern %q: want %d, got %d", + test.pattern, test.hits, c) + } + } +} + +func BenchmarkFilterLines(b *testing.B) { + pattern := "sdk/*/cpp/*/*vars.html" + lines := extractTestLines(b) + var c uint + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + c = 0 + for _, line := range lines { + match, err := filter.Match(pattern, line) + if err != nil { + b.Fatal(err) + } + + if match { + c++ + } + } + + if c != 3 { + b.Fatalf("wrong number of matches: expected 3, got %d", c) + } + } +} + +func BenchmarkFilterSingle(b *testing.B) { + pattern := "sdk/*/cpp/*/*vars.html" + line := "/usr/share/doc/libreoffice/sdk/docs/cpp/ref/a00517.html" + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + filter.Match(pattern, line) + } +} + +type test struct { + path string + match bool +} + +var filterTests = []struct { + include, exclude []string + tests []test +}{ + { + []string{"*.go", "/home/user"}, + []string{}, + []test{ + {"/home/user/foo/test.c", true}, + {"/home/user/foo/test.go", true}, + {"/home/foo/test.go", true}, + {"/home/foo/test.doc", false}, + {"/x", false}, + {"main.go", true}, + }, + }, + { + nil, + []string{"*.docx", "*.xlsx"}, + []test{ + {"/home/user/foo/test.c", true}, + {"/home/user/foo/test.docx", false}, + {"/home/foo/test.xlsx", false}, + {"/home/foo/test.doc", true}, + {"/x", true}, + {"main.go", true}, + }, + }, + { + []string{"accounting.*", "*Partner*"}, + []string{"*.docx", "*.xlsx"}, + []test{ + // {"/home/user/foo/test.c", true}, + {"/home/user/Partner/test.docx", true}, + {"/home/user/bar/test.docx", false}, + {"/home/user/test.xlsx", false}, + {"/home/foo/test.doc", true}, + {"/x", true}, + {"main.go", true}, + {"/users/A/accounting.xlsx", true}, + {"/users/A/Calculation Partner.xlsx", true}, + }, + }, +} + +func TestFilter(t *testing.T) { + for i, test := range filterTests { + f := filter.New(test.include, test.exclude) + + for _, testfile := range test.tests { + matched, err := f.Match(testfile.path) + if err != nil { + t.Error(err) + } + + if matched != testfile.match { + t.Errorf("test %d: filter.Match(%q): expected %v, got %v", + i, testfile.path, testfile.match, matched) + } + } + } +} + +func BenchmarkFilter(b *testing.B) { + lines := extractTestLines(b) + f := filter.New([]string{"sdk", "*.html"}, []string{"*.png"}) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, line := range lines { + f.Match(line) + } + } +} + +func BenchmarkFilterInclude(b *testing.B) { + lines := extractTestLines(b) + f := filter.New([]string{"sdk", "*.html"}, nil) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, line := range lines { + f.Match(line) + } + } +} + +func BenchmarkFilterExclude(b *testing.B) { + lines := extractTestLines(b) + f := filter.New(nil, []string{"*.png"}) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, line := range lines { + f.Match(line) + } + } +} diff --git a/filter/testdata/libreoffice.txt.bz2 b/filter/testdata/libreoffice.txt.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..adc90f2e2eb90298c585fdb11ecafe1078c737c8 GIT binary patch literal 102857 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%0APU-7m_H7Ap)JEBO)OBsElxg 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 p9C~OTnlS-@pI3ss^ixuTcBrTfOgTNg@2#f## literal 0 HcmV?d00001 From e9285539bedfa72d8ad0f62ef7c6903a838184a4 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Mon, 13 Jul 2015 22:51:35 +0200 Subject: [PATCH 2/7] filter: implement handling `**` --- filter/filter.go | 32 ++++++++++++++++++++++++++++++++ filter/filter_test.go | 16 +++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/filter/filter.go b/filter/filter.go index 493483a88..18f7aa718 100644 --- a/filter/filter.go +++ b/filter/filter.go @@ -31,7 +31,39 @@ func Match(pattern, str string) (matched bool, err error) { return match(patterns, strs) } +func hasDoubleWildcard(list []string) (ok bool, pos int) { + for i, item := range list { + if item == "**" { + return true, i + } + } + + return false, 0 +} + func match(patterns, strs []string) (matched bool, err error) { + if ok, pos := hasDoubleWildcard(patterns); ok { + // gradually expand '**' into separate wildcards + for i := 0; i <= len(strs)-len(patterns)+1; i++ { + newPat := patterns[:pos] + for k := 0; k < i; k++ { + newPat = append(newPat, "*") + } + newPat = append(newPat, patterns[pos+1:]...) + + matched, err := match(newPat, strs) + if err != nil { + return false, err + } + + if matched { + return true, nil + } + } + + return false, nil + } + if len(patterns) == 0 && len(strs) == 0 { return true, nil } diff --git a/filter/filter_test.go b/filter/filter_test.go index cd21ec054..fb4ab94b7 100644 --- a/filter/filter_test.go +++ b/filter/filter_test.go @@ -54,7 +54,21 @@ var matchTests = []struct { {"*.c", "bar/baz/test.go", false}, {"sdk", "/foo/bar/sdk", true}, {"sdk", "/foo/bar/sdk/test/sdk_foo.go", true}, - {"sdk/*/cpp/*/*vars*.html", "/usr/share/doc/libreoffice/sdk/docs/cpp/ref/a00517.html", false}, + { + "sdk/*/cpp/*/*vars*.html", + "/usr/share/doc/libreoffice/sdk/docs/cpp/ref/a00517.html", + false, + }, + {"foo/**/bar/*.go", "/home/user/foo/work/special/project/bar/test.go", true}, + {"foo/**/bar/*.go", "/home/user/foo/bar/test.go", true}, + {"foo/**/bar/*.go", "x/foo/bar/test.go", true}, + {"foo/**/bar/*.go", "foo/bar/test.go", true}, + {"foo/**/bar/*.go", "/home/user/foo/test.c", false}, + {"foo/**/bar/*.go", "bar/foo/main.go", false}, + {"foo/**/bar/*.go", "/foo/bar/main.go", true}, + {"foo/**/bar/*.go", "bar/main.go", false}, + {"foo/**/bar", "/home/user/foo/x/y/bar", true}, + {"foo/**/bar", "/home/user/foo/x/y/bar/main.go", true}, } func TestMatch(t *testing.T) { From b425ea19e5ddee388308947f904613e93f9fb8be Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Mon, 13 Jul 2015 23:15:57 +0200 Subject: [PATCH 3/7] filter: fix bug, copy slice with new pattern --- filter/filter.go | 3 ++- filter/filter_test.go | 22 +++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/filter/filter.go b/filter/filter.go index 18f7aa718..6f9f55cc7 100644 --- a/filter/filter.go +++ b/filter/filter.go @@ -45,7 +45,8 @@ func match(patterns, strs []string) (matched bool, err error) { if ok, pos := hasDoubleWildcard(patterns); ok { // gradually expand '**' into separate wildcards for i := 0; i <= len(strs)-len(patterns)+1; i++ { - newPat := patterns[:pos] + newPat := make([]string, pos) + copy(newPat, patterns[:pos]) for k := 0; k < i; k++ { newPat = append(newPat, "*") } diff --git a/filter/filter_test.go b/filter/filter_test.go index fb4ab94b7..112fd931d 100644 --- a/filter/filter_test.go +++ b/filter/filter_test.go @@ -69,6 +69,8 @@ var matchTests = []struct { {"foo/**/bar/*.go", "bar/main.go", false}, {"foo/**/bar", "/home/user/foo/x/y/bar", true}, {"foo/**/bar", "/home/user/foo/x/y/bar/main.go", true}, + {"user/**/important*", "/home/user/work/x/y/hidden/x", false}, + {"user/**/hidden*/**/c", "/home/user/work/x/y/hidden/z/a/b/c", true}, } func TestMatch(t *testing.T) { @@ -268,7 +270,7 @@ var filterTests = []struct { []string{"accounting.*", "*Partner*"}, []string{"*.docx", "*.xlsx"}, []test{ - // {"/home/user/foo/test.c", true}, + {"/home/user/foo/test.c", true}, {"/home/user/Partner/test.docx", true}, {"/home/user/bar/test.docx", false}, {"/home/user/test.xlsx", false}, @@ -279,6 +281,24 @@ var filterTests = []struct { {"/users/A/Calculation Partner.xlsx", true}, }, }, + { + []string{"accounting.*", "*Partner*", "user/**/important*"}, + []string{"*.docx", "*.xlsx", "user/**/*hidden*"}, + []test{ + {"/home/user/foo/test.c", true}, + {"/home/user/Partner/test.docx", true}, + {"/home/user/bar/test.docx", false}, + {"/home/user/test.xlsx", false}, + {"/home/foo/test.doc", true}, + {"/x", true}, + {"main.go", true}, + {"/users/A/accounting.xlsx", true}, + {"/users/A/Calculation Partner.xlsx", true}, + {"/home/user/work/shared/test/important Calculations/help.txt", true}, + {"/home/user/work/shared/test/important.xlsx", true}, + {"/home/user/work/x/y/hidden/x", false}, + }, + }, } func TestFilter(t *testing.T) { From 0d8bad273d35ebe743a7a2580035978e9944b66a Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 19 Jul 2015 22:26:01 +0200 Subject: [PATCH 4/7] Remove combined include/exclude filters --- filter/filter.go | 76 ----------------------- filter/filter_test.go | 137 +++++------------------------------------- 2 files changed, 15 insertions(+), 198 deletions(-) diff --git a/filter/filter.go b/filter/filter.go index 6f9f55cc7..274d1f960 100644 --- a/filter/filter.go +++ b/filter/filter.go @@ -106,79 +106,3 @@ func MatchList(patterns []string, str string) (matched bool, err error) { return false, nil } - -// matchList returns true if str matches one of the patterns. -func matchList(patterns [][]string, str []string) (matched bool, err error) { - for _, pat := range patterns { - matched, err = match(pat, str) - if err != nil { - return false, err - } - - if matched { - return true, nil - } - } - - return false, nil -} - -// Filter contains include and exclude patterns. If both lists of patterns are -// empty, all files are accepted. -type Filter struct { - include, exclude [][]string -} - -// New returns a new filter with the given include/exclude lists of patterns. -func New(include, exclude []string) *Filter { - f := &Filter{} - - for _, pat := range include { - f.include = append(f.include, strings.Split(pat, string(filepath.Separator))) - } - - for _, pat := range exclude { - f.exclude = append(f.exclude, strings.Split(pat, string(filepath.Separator))) - } - - return f -} - -// Match tests a filename against the filter. If include and exclude patterns -// are both empty, true is returned. -// -// If only include patterns and no exclude patterns are configured, true is -// returned iff name matches one of the include patterns. -// -// If only exclude patterns and no include patterns are configured, true is -// returned iff name does not match all of the exclude patterns. -func (f Filter) Match(name string) (matched bool, err error) { - if name == "" { - return false, ErrBadString - } - - if len(f.include) == 0 && len(f.exclude) == 0 { - return true, nil - } - - names := strings.Split(name, string(filepath.Separator)) - if len(f.exclude) == 0 { - return matchList(f.include, names) - } - - if len(f.include) == 0 { - match, err := matchList(f.exclude, names) - return !match, err - } - - excluded, err := matchList(f.exclude, names) - if err != nil { - return false, err - } - - if !excluded { - return true, nil - } - - return matchList(f.include, names) -} diff --git a/filter/filter_test.go b/filter/filter_test.go index 112fd931d..ce9474efc 100644 --- a/filter/filter_test.go +++ b/filter/filter_test.go @@ -222,138 +222,31 @@ func BenchmarkFilterLines(b *testing.B) { } } -func BenchmarkFilterSingle(b *testing.B) { - pattern := "sdk/*/cpp/*/*vars.html" - line := "/usr/share/doc/libreoffice/sdk/docs/cpp/ref/a00517.html" +func BenchmarkFilterPatterns(b *testing.B) { + patterns := []string{ + "sdk/*", + "*.html", + } + lines := extractTestLines(b) + var c uint b.ResetTimer() for i := 0; i < b.N; i++ { - filter.Match(pattern, line) - } -} - -type test struct { - path string - match bool -} - -var filterTests = []struct { - include, exclude []string - tests []test -}{ - { - []string{"*.go", "/home/user"}, - []string{}, - []test{ - {"/home/user/foo/test.c", true}, - {"/home/user/foo/test.go", true}, - {"/home/foo/test.go", true}, - {"/home/foo/test.doc", false}, - {"/x", false}, - {"main.go", true}, - }, - }, - { - nil, - []string{"*.docx", "*.xlsx"}, - []test{ - {"/home/user/foo/test.c", true}, - {"/home/user/foo/test.docx", false}, - {"/home/foo/test.xlsx", false}, - {"/home/foo/test.doc", true}, - {"/x", true}, - {"main.go", true}, - }, - }, - { - []string{"accounting.*", "*Partner*"}, - []string{"*.docx", "*.xlsx"}, - []test{ - {"/home/user/foo/test.c", true}, - {"/home/user/Partner/test.docx", true}, - {"/home/user/bar/test.docx", false}, - {"/home/user/test.xlsx", false}, - {"/home/foo/test.doc", true}, - {"/x", true}, - {"main.go", true}, - {"/users/A/accounting.xlsx", true}, - {"/users/A/Calculation Partner.xlsx", true}, - }, - }, - { - []string{"accounting.*", "*Partner*", "user/**/important*"}, - []string{"*.docx", "*.xlsx", "user/**/*hidden*"}, - []test{ - {"/home/user/foo/test.c", true}, - {"/home/user/Partner/test.docx", true}, - {"/home/user/bar/test.docx", false}, - {"/home/user/test.xlsx", false}, - {"/home/foo/test.doc", true}, - {"/x", true}, - {"main.go", true}, - {"/users/A/accounting.xlsx", true}, - {"/users/A/Calculation Partner.xlsx", true}, - {"/home/user/work/shared/test/important Calculations/help.txt", true}, - {"/home/user/work/shared/test/important.xlsx", true}, - {"/home/user/work/x/y/hidden/x", false}, - }, - }, -} - -func TestFilter(t *testing.T) { - for i, test := range filterTests { - f := filter.New(test.include, test.exclude) - - for _, testfile := range test.tests { - matched, err := f.Match(testfile.path) + c = 0 + for _, line := range lines { + match, err := filter.MatchList(patterns, line) if err != nil { - t.Error(err) + b.Fatal(err) } - if matched != testfile.match { - t.Errorf("test %d: filter.Match(%q): expected %v, got %v", - i, testfile.path, testfile.match, matched) + if match { + c++ } } - } -} -func BenchmarkFilter(b *testing.B) { - lines := extractTestLines(b) - f := filter.New([]string{"sdk", "*.html"}, []string{"*.png"}) - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - for _, line := range lines { - f.Match(line) - } - } -} - -func BenchmarkFilterInclude(b *testing.B) { - lines := extractTestLines(b) - f := filter.New([]string{"sdk", "*.html"}, nil) - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - for _, line := range lines { - f.Match(line) - } - } -} - -func BenchmarkFilterExclude(b *testing.B) { - lines := extractTestLines(b) - f := filter.New(nil, []string{"*.png"}) - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - for _, line := range lines { - f.Match(line) + if c != 22185 { + b.Fatalf("wrong number of matches: expected 22185, got %d", c) } } } From 7fd52f9f5701151bffa7fc5a9503cc8024cac27c Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Mon, 20 Jul 2015 00:13:39 +0200 Subject: [PATCH 5/7] Add exclude filter to archiver and 'backup' command --- archiver.go | 19 +++++-- cmd/restic/cmd_backup.go | 24 ++++++--- cmd/restic/cmd_ls.go | 18 ++++--- cmd/restic/integration_test.go | 97 +++++++++++++++++++++++++++++++++- filter/filter.go | 4 +- filter/filter_test.go | 6 +-- pipe/pipe.go | 28 +++++++--- pipe/pipe_test.go | 12 +++-- walk_test.go | 7 ++- 9 files changed, 179 insertions(+), 36 deletions(-) diff --git a/archiver.go b/archiver.go index 69b1d0b4a..1182a85c5 100644 --- a/archiver.go +++ b/archiver.go @@ -34,8 +34,8 @@ type Archiver struct { blobToken chan struct{} - Error func(dir string, fi os.FileInfo, err error) error - Filter func(item string, fi os.FileInfo) bool + Error func(dir string, fi os.FileInfo, err error) error + SelectFilter pipe.SelectFunc } // NewArchiver returns a new archiver. @@ -50,7 +50,7 @@ func NewArchiver(repo *repository.Repository) *Archiver { } arch.Error = archiverAbortOnAllErrors - arch.Filter = archiverAllowAllFiles + arch.SelectFilter = archiverAllowAllFiles return arch } @@ -577,7 +577,7 @@ func (arch *Archiver) Snapshot(p *Progress, paths []string, parentID backend.ID) pipeCh := make(chan pipe.Job) resCh := make(chan pipe.Result, 1) go func() { - err := pipe.Walk(paths, done, pipeCh, resCh) + err := pipe.Walk(paths, arch.SelectFilter, done, pipeCh, resCh) if err != nil { debug.Log("Archiver.Snapshot", "pipe.Walk returned error %v", err) return @@ -659,7 +659,7 @@ func isRegularFile(fi os.FileInfo) bool { // Scan traverses the dirs to collect Stat information while emitting progress // information with p. -func Scan(dirs []string, p *Progress) (Stat, error) { +func Scan(dirs []string, filter pipe.SelectFunc, p *Progress) (Stat, error) { p.Start() defer p.Done() @@ -678,6 +678,15 @@ func Scan(dirs []string, p *Progress) (Stat, error) { fmt.Fprintf(os.Stderr, "error for %v: FileInfo is nil\n", str) return nil } + + if !filter(str, fi) { + debug.Log("Scan.Walk", "path %v excluded", str) + if fi.IsDir() { + return filepath.SkipDir + } + return nil + } + s := Stat{} if fi.IsDir() { s.Dirs++ diff --git a/cmd/restic/cmd_backup.go b/cmd/restic/cmd_backup.go index 99c91aef3..3e18c3402 100644 --- a/cmd/restic/cmd_backup.go +++ b/cmd/restic/cmd_backup.go @@ -10,13 +10,15 @@ import ( "github.com/restic/restic" "github.com/restic/restic/backend" + "github.com/restic/restic/filter" "github.com/restic/restic/repository" "golang.org/x/crypto/ssh/terminal" ) type CmdBackup struct { - Parent string `short:"p" long:"parent" description:"use this parent snapshot (default: last snapshot in repo that has the same target)"` - Force bool `short:"f" long:"force" description:"Force re-reading the target. Overrides the \"parent\" flag"` + Parent string `short:"p" long:"parent" description:"use this parent snapshot (default: last snapshot in repo that has the same target)"` + Force bool `short:"f" long:"force" description:"Force re-reading the target. Overrides the \"parent\" flag"` + Exclude []string `short:"e" long:"exclude" description:"Exclude a pattern (can be specified multiple times)"` global *GlobalOptions } @@ -282,14 +284,22 @@ func (cmd CmdBackup) Execute(args []string) error { cmd.global.Verbosef("scan %v\n", target) - stat, err := restic.Scan(target, cmd.newScanProgress()) + selectFilter := func(item string, fi os.FileInfo) bool { + matched, err := filter.List(cmd.Exclude, item) + if err != nil { + cmd.global.Warnf("error for exclude pattern: %v", err) + } - // TODO: add filter - // arch.Filter = func(dir string, fi os.FileInfo) bool { - // return true - // } + return !matched + } + + stat, err := restic.Scan(target, selectFilter, cmd.newScanProgress()) + if err != nil { + return err + } arch := restic.NewArchiver(repo) + arch.SelectFilter = selectFilter arch.Error = func(dir string, fi os.FileInfo, err error) error { // TODO: make ignoring errors configurable diff --git a/cmd/restic/cmd_ls.go b/cmd/restic/cmd_ls.go index 8ec904bbd..91c9507e3 100644 --- a/cmd/restic/cmd_ls.go +++ b/cmd/restic/cmd_ls.go @@ -11,6 +11,8 @@ import ( ) type CmdLs struct { + Long bool `short:"l" long:"long" description:"Use a long listing format showing size and mode"` + global *GlobalOptions } @@ -24,7 +26,11 @@ func init() { } } -func printNode(prefix string, n *restic.Node) string { +func (cmd CmdLs) printNode(prefix string, n *restic.Node) string { + if !cmd.Long { + return filepath.Join(prefix, n.Name) + } + switch n.Type { case "file": return fmt.Sprintf("%s %5d %5d %6d %s %s", @@ -40,17 +46,17 @@ func printNode(prefix string, n *restic.Node) string { } } -func printTree(prefix string, repo *repository.Repository, id backend.ID) error { +func (cmd CmdLs) printTree(prefix string, repo *repository.Repository, id backend.ID) error { tree, err := restic.LoadTree(repo, id) if err != nil { return err } for _, entry := range tree.Nodes { - fmt.Println(printNode(prefix, entry)) + cmd.global.Printf(cmd.printNode(prefix, entry) + "\n") if entry.Type == "dir" && entry.Subtree != nil { - err = printTree(filepath.Join(prefix, entry.Name), repo, entry.Subtree) + err = cmd.printTree(filepath.Join(prefix, entry.Name), repo, entry.Subtree) if err != nil { return err } @@ -89,7 +95,7 @@ func (cmd CmdLs) Execute(args []string) error { return err } - fmt.Printf("snapshot of %v at %s:\n", sn.Paths, sn.Time) + cmd.global.Verbosef("snapshot of %v at %s:\n", sn.Paths, sn.Time) - return printTree("", repo, sn.Tree) + return cmd.printTree("", repo, sn.Tree) } diff --git a/cmd/restic/integration_test.go b/cmd/restic/integration_test.go index b06b85745..21323e8cc 100644 --- a/cmd/restic/integration_test.go +++ b/cmd/restic/integration_test.go @@ -10,6 +10,7 @@ import ( "os" "path/filepath" "regexp" + "strings" "syscall" "testing" "time" @@ -44,7 +45,11 @@ func cmdInit(t testing.TB, global GlobalOptions) { } func cmdBackup(t testing.TB, global GlobalOptions, target []string, parentID backend.ID) { - cmd := &CmdBackup{global: &global} + cmdBackupExcludes(t, global, target, parentID, nil) +} + +func cmdBackupExcludes(t testing.TB, global GlobalOptions, target []string, parentID backend.ID, excludes []string) { + cmd := &CmdBackup{global: &global, Exclude: excludes} cmd.Parent = parentID.String() t.Logf("backing up %v", target) @@ -73,6 +78,16 @@ func cmdCheck(t testing.TB, global GlobalOptions) { OK(t, cmd.Execute(nil)) } +func cmdLs(t testing.TB, global GlobalOptions, snapshotID string) []string { + var buf bytes.Buffer + global.stdout = &buf + + cmd := &CmdLs{global: &global} + OK(t, cmd.Execute([]string{snapshotID})) + + return strings.Split(string(buf.Bytes()), "\n") +} + func TestBackup(t *testing.T) { withTestEnvironment(t, func(env *testEnvironment, global GlobalOptions) { datafile := filepath.Join("testdata", "backup-data.tar.gz") @@ -237,6 +252,86 @@ func TestBackupMissingFile2(t *testing.T) { }) } +func includes(haystack []string, needle string) bool { + for _, s := range haystack { + if s == needle { + return true + } + } + + return false +} + +func loadSnapshotMap(t testing.TB, global GlobalOptions) map[string]struct{} { + snapshotIDs := cmdList(t, global, "snapshots") + + m := make(map[string]struct{}) + for _, id := range snapshotIDs { + m[id.String()] = struct{}{} + } + + return m +} + +func lastSnapshot(old, new map[string]struct{}) (map[string]struct{}, string) { + for k := range new { + if _, ok := old[k]; !ok { + old[k] = struct{}{} + return old, k + } + } + + return old, "" +} + +var backupExcludeFilenames = []string{ + "testfile1", + "foo.tar.gz", + "private/secret/passwords.txt", + "work/source/test.c", +} + +func TestBackupExclude(t *testing.T) { + withTestEnvironment(t, func(env *testEnvironment, global GlobalOptions) { + cmdInit(t, global) + + datadir := filepath.Join(env.base, "testdata") + + for _, filename := range backupExcludeFilenames { + fp := filepath.Join(datadir, filename) + OK(t, os.MkdirAll(filepath.Dir(fp), 0755)) + + f, err := os.Create(fp) + OK(t, err) + + fmt.Fprintf(f, filename) + OK(t, f.Close()) + } + + snapshots := make(map[string]struct{}) + + cmdBackup(t, global, []string{datadir}, nil) + snapshots, snapshotID := lastSnapshot(snapshots, loadSnapshotMap(t, global)) + files := cmdLs(t, global, snapshotID) + Assert(t, includes(files, filepath.Join("testdata", "foo.tar.gz")), + "expected file %q in first snapshot, but it's not included", "foo.tar.gz") + + cmdBackupExcludes(t, global, []string{datadir}, nil, []string{"*.tar.gz"}) + snapshots, snapshotID = lastSnapshot(snapshots, loadSnapshotMap(t, global)) + files = cmdLs(t, global, snapshotID) + Assert(t, !includes(files, filepath.Join("testdata", "foo.tar.gz")), + "expected file %q not in first snapshot, but it's included", "foo.tar.gz") + + cmdBackupExcludes(t, global, []string{datadir}, nil, []string{"*.tar.gz", "private/secret"}) + snapshots, snapshotID = lastSnapshot(snapshots, loadSnapshotMap(t, global)) + files = cmdLs(t, global, snapshotID) + Assert(t, !includes(files, filepath.Join("testdata", "foo.tar.gz")), + "expected file %q not in first snapshot, but it's included", "foo.tar.gz") + Assert(t, !includes(files, filepath.Join("testdata", "private", "secret", "passwords.txt")), + "expected file %q not in first snapshot, but it's included", "passwords.txt") + }) +} + const ( incrementalFirstWrite = 20 * 1042 * 1024 incrementalSecondWrite = 12 * 1042 * 1024 diff --git a/filter/filter.go b/filter/filter.go index 274d1f960..f8c335e34 100644 --- a/filter/filter.go +++ b/filter/filter.go @@ -91,8 +91,8 @@ func match(patterns, strs []string) (matched bool, err error) { return false, nil } -// MatchList returns true if str matches one of the patterns. -func MatchList(patterns []string, str string) (matched bool, err error) { +// List returns true if str matches one of the patterns. +func List(patterns []string, str string) (matched bool, err error) { for _, pat := range patterns { matched, err = Match(pat, str) if err != nil { diff --git a/filter/filter_test.go b/filter/filter_test.go index ce9474efc..78e731b68 100644 --- a/filter/filter_test.go +++ b/filter/filter_test.go @@ -121,7 +121,7 @@ var filterListTests = []struct { func TestMatchList(t *testing.T) { for i, test := range filterListTests { - match, err := filter.MatchList(test.patterns, test.path) + match, err := filter.List(test.patterns, test.path) if err != nil { t.Errorf("test %d failed: expected no error for patterns %q, but error returned: %v", i, test.patterns, err) @@ -136,7 +136,7 @@ func TestMatchList(t *testing.T) { } func ExampleMatchList() { - match, _ := filter.MatchList([]string{"*.c", "*.go"}, "/home/user/file.go") + match, _ := filter.List([]string{"*.c", "*.go"}, "/home/user/file.go") fmt.Printf("match: %v\n", match) // Output: // match: true @@ -235,7 +235,7 @@ func BenchmarkFilterPatterns(b *testing.B) { for i := 0; i < b.N; i++ { c = 0 for _, line := range lines { - match, err := filter.MatchList(patterns, line) + match, err := filter.List(patterns, line) if err != nil { b.Fatal(err) } diff --git a/pipe/pipe.go b/pipe/pipe.go index a419f082d..4e9908315 100644 --- a/pipe/pipe.go +++ b/pipe/pipe.go @@ -82,13 +82,22 @@ func isFile(fi os.FileInfo) bool { var errCancelled = errors.New("walk cancelled") -func walk(basedir, dir string, done chan struct{}, jobs chan<- Job, res chan<- Result) error { +// SelectFunc returns true for all items that should be included (files and +// dirs). If false is returned, files are ignored and dirs are not even walked. +type SelectFunc func(item string, fi os.FileInfo) bool + +func walk(basedir, dir string, selectFunc SelectFunc, done chan struct{}, jobs chan<- Job, res chan<- Result) error { info, err := os.Lstat(dir) if err != nil { debug.Log("pipe.walk", "error for %v: %v", dir, err) return err } + if !selectFunc(dir, info) { + debug.Log("pipe.walk", "file %v excluded by filter", dir) + return nil + } + relpath, _ := filepath.Rel(basedir, dir) if !info.IsDir() { @@ -114,13 +123,18 @@ func walk(basedir, dir string, done chan struct{}, jobs chan<- Job, res chan<- R for _, name := range names { subpath := filepath.Join(dir, name) + fi, statErr := os.Lstat(subpath) + if !selectFunc(subpath, fi) { + debug.Log("pipe.walk", "file %v excluded by filter", subpath) + continue + } + ch := make(chan Result, 1) entries = append(entries, ch) - fi, err := os.Lstat(subpath) - if err != nil { + if statErr != nil { select { - case jobs <- Entry{info: fi, error: err, basedir: basedir, path: filepath.Join(relpath, name), result: ch}: + case jobs <- Entry{info: fi, error: statErr, basedir: basedir, path: filepath.Join(relpath, name), result: ch}: case <-done: return errCancelled } @@ -132,7 +146,7 @@ func walk(basedir, dir string, done chan struct{}, jobs chan<- Job, res chan<- R debug.RunHook("pipe.walk2", filepath.Join(relpath, name)) if isDir(fi) { - err = walk(basedir, subpath, done, jobs, ch) + err = walk(basedir, subpath, selectFunc, done, jobs, ch) if err != nil { return err } @@ -156,7 +170,7 @@ func walk(basedir, dir string, done chan struct{}, jobs chan<- Job, res chan<- R // Walk sends a Job for each file and directory it finds below the paths. When // the channel done is closed, processing stops. -func Walk(paths []string, done chan struct{}, jobs chan<- Job, res chan<- Result) error { +func Walk(paths []string, selectFunc SelectFunc, done chan struct{}, jobs chan<- Job, res chan<- Result) error { defer func() { debug.Log("pipe.Walk", "output channel closed") close(jobs) @@ -166,7 +180,7 @@ func Walk(paths []string, done chan struct{}, jobs chan<- Job, res chan<- Result for _, path := range paths { debug.Log("pipe.Walk", "start walker for %v", path) ch := make(chan Result, 1) - err := walk(filepath.Dir(path), path, done, jobs, ch) + err := walk(filepath.Dir(path), path, selectFunc, done, jobs, ch) if err != nil { debug.Log("pipe.Walk", "error for %v: %v", path, err) continue diff --git a/pipe/pipe_test.go b/pipe/pipe_test.go index 42ff7c31d..001015938 100644 --- a/pipe/pipe_test.go +++ b/pipe/pipe_test.go @@ -19,6 +19,10 @@ type stats struct { dirs, files int } +func acceptAll(string, os.FileInfo) bool { + return true +} + func statPath(path string) (stats, error) { var s stats @@ -118,7 +122,7 @@ func TestPipelineWalkerWithSplit(t *testing.T) { }() resCh := make(chan pipe.Result, 1) - err = pipe.Walk([]string{TestWalkerPath}, done, jobs, resCh) + err = pipe.Walk([]string{TestWalkerPath}, acceptAll, done, jobs, resCh) OK(t, err) // wait for all workers to terminate @@ -198,7 +202,7 @@ func TestPipelineWalker(t *testing.T) { } resCh := make(chan pipe.Result, 1) - err = pipe.Walk([]string{TestWalkerPath}, done, jobs, resCh) + err = pipe.Walk([]string{TestWalkerPath}, acceptAll, done, jobs, resCh) OK(t, err) // wait for all workers to terminate @@ -298,7 +302,7 @@ func BenchmarkPipelineWalker(b *testing.B) { }() resCh := make(chan pipe.Result, 1) - err := pipe.Walk([]string{TestWalkerPath}, done, jobs, resCh) + err := pipe.Walk([]string{TestWalkerPath}, acceptAll, done, jobs, resCh) OK(b, err) // wait for all workers to terminate @@ -375,7 +379,7 @@ func TestPipelineWalkerMultiple(t *testing.T) { } resCh := make(chan pipe.Result, 1) - err = pipe.Walk(paths, done, jobs, resCh) + err = pipe.Walk(paths, acceptAll, done, jobs, resCh) OK(t, err) // wait for all workers to terminate diff --git a/walk_test.go b/walk_test.go index 397655978..4e0f8b930 100644 --- a/walk_test.go +++ b/walk_test.go @@ -1,6 +1,7 @@ package restic_test import ( + "os" "path/filepath" "testing" @@ -33,7 +34,11 @@ func TestWalkTree(t *testing.T) { // start filesystem walker fsJobs := make(chan pipe.Job) resCh := make(chan pipe.Result, 1) - go pipe.Walk(dirs, done, fsJobs, resCh) + + f := func(string, os.FileInfo) bool { + return true + } + go pipe.Walk(dirs, f, done, fsJobs, resCh) for { // receive fs job From c0337a2675a46313f01d6c827c5ce35b60616121 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Mon, 20 Jul 2015 00:38:44 +0200 Subject: [PATCH 6/7] Add exclude filter to restorer and 'restore' command --- cmd/restic/cmd_restore.go | 65 +++++++++++++++------------------- cmd/restic/integration_test.go | 19 ++++++---- restorer.go | 8 ++--- 3 files changed, 45 insertions(+), 47 deletions(-) diff --git a/cmd/restic/cmd_restore.go b/cmd/restic/cmd_restore.go index e4d939fd2..4991423b9 100644 --- a/cmd/restic/cmd_restore.go +++ b/cmd/restic/cmd_restore.go @@ -1,14 +1,18 @@ package main import ( + "errors" "fmt" - "path/filepath" "github.com/restic/restic" "github.com/restic/restic/debug" + "github.com/restic/restic/filter" ) type CmdRestore struct { + Exclude []string `short:"e" long:"exclude" description:"Exclude a pattern (can be specified multiple times)"` + Target string `short:"t" long:"target" description:"Directory to restore to"` + global *GlobalOptions } @@ -23,14 +27,22 @@ func init() { } func (cmd CmdRestore) Usage() string { - return "snapshot-ID TARGETDIR [PATTERN]" + return "snapshot-ID" } func (cmd CmdRestore) Execute(args []string) error { - if len(args) < 2 || len(args) > 3 { + if len(args) != 1 { return fmt.Errorf("wrong number of arguments, Usage: %s", cmd.Usage()) } + if cmd.Target == "" { + return errors.New("please specify a directory to restore to (--target)") + } + + snapshotIDString := args[0] + + debug.Log("restore", "restore %v to %v", snapshotIDString, cmd.Target) + repo, err := cmd.global.OpenRepository() if err != nil { return err @@ -47,14 +59,11 @@ func (cmd CmdRestore) Execute(args []string) error { return err } - id, err := restic.FindSnapshot(repo, args[0]) + id, err := restic.FindSnapshot(repo, snapshotIDString) if err != nil { - cmd.global.Exitf(1, "invalid id %q: %v", args[0], err) + cmd.global.Exitf(1, "invalid id %q: %v", snapshotIDString, err) } - target := args[1] - - // create restorer res, err := restic.NewRestorer(repo, id) if err != nil { cmd.global.Exitf(2, "creating restorer failed: %v\n", err) @@ -62,41 +71,25 @@ func (cmd CmdRestore) Execute(args []string) error { res.Error = func(dir string, node *restic.Node, err error) error { cmd.global.Warnf("error for %s: %+v\n", dir, err) - - // if node.Type == "dir" { - // if e, ok := err.(*os.PathError); ok { - // if errn, ok := e.Err.(syscall.Errno); ok { - // if errn == syscall.EEXIST { - // fmt.Printf("ignoring already existing directory %s\n", dir) - // return nil - // } - // } - // } - // } return err } - // TODO: a filter against the full path sucks as filepath.Match doesn't match - // directory separators on '*'. still, it's better than nothing. - if len(args) > 2 { - pattern := args[2] - cmd.global.Verbosef("filter pattern %q\n", pattern) - - res.SelectForRestore = func(item string, dstpath string, node *restic.Node) bool { - matched, err := filepath.Match(pattern, node.Name) - if err != nil { - panic(err) - } - if !matched { - debug.Log("restic.restore", "item %v doesn't match pattern %q", item, pattern) - } - return matched + selectFilter := func(item string, dstpath string, node *restic.Node) bool { + matched, err := filter.List(cmd.Exclude, item) + if err != nil { + cmd.global.Warnf("error for exclude pattern: %v", err) } + + return !matched } - cmd.global.Verbosef("restoring %s to %s\n", res.Snapshot(), target) + if len(cmd.Exclude) > 0 { + res.SelectFilter = selectFilter + } - err = res.RestoreTo(target) + cmd.global.Verbosef("restoring %s to %s\n", res.Snapshot(), cmd.Target) + + err = res.RestoreTo(cmd.Target) if err != nil { return err } diff --git a/cmd/restic/integration_test.go b/cmd/restic/integration_test.go index 21323e8cc..5803c38e8 100644 --- a/cmd/restic/integration_test.go +++ b/cmd/restic/integration_test.go @@ -17,6 +17,7 @@ import ( "github.com/restic/restic/backend" "github.com/restic/restic/debug" + "github.com/restic/restic/filter" . "github.com/restic/restic/test" ) @@ -68,9 +69,13 @@ func cmdList(t testing.TB, global GlobalOptions, tpe string) []backend.ID { return IDs } -func cmdRestore(t testing.TB, global GlobalOptions, dir string, snapshotID backend.ID, args ...string) { - cmd := &CmdRestore{global: &global} - cmd.Execute(append([]string{snapshotID.String(), dir}, args...)) +func cmdRestore(t testing.TB, global GlobalOptions, dir string, snapshotID backend.ID) { + cmdRestoreExcludes(t, global, dir, snapshotID, nil) +} + +func cmdRestoreExcludes(t testing.TB, global GlobalOptions, dir string, snapshotID backend.ID, excludes []string) { + cmd := &CmdRestore{global: &global, Target: dir, Exclude: excludes} + OK(t, cmd.Execute([]string{snapshotID.String()})) } func cmdCheck(t testing.TB, global GlobalOptions) { @@ -517,10 +522,10 @@ func TestRestoreFilter(t *testing.T) { for i, pat := range []string{"*.c", "*.exe", "*", "*file3*"} { base := filepath.Join(env.base, fmt.Sprintf("restore%d", i+1)) - cmdRestore(t, global, base, snapshotID, pat) + cmdRestoreExcludes(t, global, base, snapshotID, []string{pat}) for _, test := range testfiles { err := testFileSize(filepath.Join(base, "testdata", test.name), int64(test.size)) - if ok, _ := filepath.Match(pat, filepath.Base(test.name)); ok { + if ok, _ := filter.Match(pat, filepath.Base(test.name)); !ok { OK(t, err) } else { Assert(t, os.IsNotExist(err), @@ -558,7 +563,7 @@ func TestRestoreNoMetadataOnIgnoredIntermediateDirs(t *testing.T) { // restore with filter "*.ext", this should restore "file.ext", but // since the directories are ignored and only created because of // "file.ext", no meta data should be restored for them. - cmdRestore(t, global, filepath.Join(env.base, "restore0"), snapshotID, "*.ext") + cmdRestoreExcludes(t, global, filepath.Join(env.base, "restore0"), snapshotID, []string{"*.ext"}) f1 := filepath.Join(env.base, "restore0", "testdata", "subdir1", "subdir2") fi, err := os.Stat(f1) @@ -568,7 +573,7 @@ func TestRestoreNoMetadataOnIgnoredIntermediateDirs(t *testing.T) { "meta data of intermediate directory has been restore although it was ignored") // restore with filter "*", this should restore meta data on everything. - cmdRestore(t, global, filepath.Join(env.base, "restore1"), snapshotID, "*") + cmdRestoreExcludes(t, global, filepath.Join(env.base, "restore1"), snapshotID, []string{"*"}) f2 := filepath.Join(env.base, "restore1", "testdata", "subdir1", "subdir2") fi, err = os.Stat(f2) diff --git a/restorer.go b/restorer.go index 25bb1e3cd..e3e7292ab 100644 --- a/restorer.go +++ b/restorer.go @@ -18,8 +18,8 @@ type Restorer struct { repo *repository.Repository sn *Snapshot - Error func(dir string, node *Node, err error) error - SelectForRestore func(item string, dstpath string, node *Node) bool + Error func(dir string, node *Node, err error) error + SelectFilter func(item string, dstpath string, node *Node) bool } var restorerAbortOnAllErrors = func(str string, node *Node, err error) error { return err } @@ -28,7 +28,7 @@ var restorerAbortOnAllErrors = func(str string, node *Node, err error) error { r func NewRestorer(repo *repository.Repository, id backend.ID) (*Restorer, error) { r := &Restorer{ repo: repo, Error: restorerAbortOnAllErrors, - SelectForRestore: func(string, string, *Node) bool { return true }, + SelectFilter: func(string, string, *Node) bool { return true }, } var err error @@ -48,7 +48,7 @@ func (res *Restorer) restoreTo(dst string, dir string, treeID backend.ID) error } for _, node := range tree.Nodes { - selectedForRestore := res.SelectForRestore(filepath.Join(dir, node.Name), + selectedForRestore := res.SelectFilter(filepath.Join(dir, node.Name), filepath.Join(dst, dir, node.Name), node) debug.Log("Restorer.restoreNodeTo", "SelectForRestore returned %v", selectedForRestore) From 1da89253cffcf13993c75bc6b6ed3e8c0abbb544 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Mon, 20 Jul 2015 19:20:20 +0200 Subject: [PATCH 7/7] Add include filter for restore Include and exclude filter are mutually exclusive. --- cmd/restic/cmd_restore.go | 20 ++++++++++++++++++-- cmd/restic/integration_test.go | 9 +++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/cmd/restic/cmd_restore.go b/cmd/restic/cmd_restore.go index 4991423b9..cb74f4768 100644 --- a/cmd/restic/cmd_restore.go +++ b/cmd/restic/cmd_restore.go @@ -11,6 +11,7 @@ import ( type CmdRestore struct { Exclude []string `short:"e" long:"exclude" description:"Exclude a pattern (can be specified multiple times)"` + Include []string `short:"i" long:"include" description:"Include a pattern, exclude everything else (can be specified multiple times)"` Target string `short:"t" long:"target" description:"Directory to restore to"` global *GlobalOptions @@ -39,6 +40,10 @@ func (cmd CmdRestore) Execute(args []string) error { return errors.New("please specify a directory to restore to (--target)") } + if len(cmd.Exclude) > 0 && len(cmd.Include) > 0 { + return errors.New("exclude and include patterns are mutually exclusive") + } + snapshotIDString := args[0] debug.Log("restore", "restore %v to %v", snapshotIDString, cmd.Target) @@ -74,7 +79,7 @@ func (cmd CmdRestore) Execute(args []string) error { return err } - selectFilter := func(item string, dstpath string, node *restic.Node) bool { + selectExcludeFilter := func(item string, dstpath string, node *restic.Node) bool { matched, err := filter.List(cmd.Exclude, item) if err != nil { cmd.global.Warnf("error for exclude pattern: %v", err) @@ -83,8 +88,19 @@ func (cmd CmdRestore) Execute(args []string) error { return !matched } + selectIncludeFilter := func(item string, dstpath string, node *restic.Node) bool { + matched, err := filter.List(cmd.Include, item) + if err != nil { + cmd.global.Warnf("error for include pattern: %v", err) + } + + return matched + } + if len(cmd.Exclude) > 0 { - res.SelectFilter = selectFilter + res.SelectFilter = selectExcludeFilter + } else if len(cmd.Include) > 0 { + res.SelectFilter = selectIncludeFilter } cmd.global.Verbosef("restoring %s to %s\n", res.Snapshot(), cmd.Target) diff --git a/cmd/restic/integration_test.go b/cmd/restic/integration_test.go index 5803c38e8..93c98fa60 100644 --- a/cmd/restic/integration_test.go +++ b/cmd/restic/integration_test.go @@ -78,6 +78,11 @@ func cmdRestoreExcludes(t testing.TB, global GlobalOptions, dir string, snapshot OK(t, cmd.Execute([]string{snapshotID.String()})) } +func cmdRestoreIncludes(t testing.TB, global GlobalOptions, dir string, snapshotID backend.ID, includes []string) { + cmd := &CmdRestore{global: &global, Target: dir, Include: includes} + OK(t, cmd.Execute([]string{snapshotID.String()})) +} + func cmdCheck(t testing.TB, global GlobalOptions) { cmd := &CmdCheck{global: &global, ReadData: true} OK(t, cmd.Execute(nil)) @@ -563,7 +568,7 @@ func TestRestoreNoMetadataOnIgnoredIntermediateDirs(t *testing.T) { // restore with filter "*.ext", this should restore "file.ext", but // since the directories are ignored and only created because of // "file.ext", no meta data should be restored for them. - cmdRestoreExcludes(t, global, filepath.Join(env.base, "restore0"), snapshotID, []string{"*.ext"}) + cmdRestoreIncludes(t, global, filepath.Join(env.base, "restore0"), snapshotID, []string{"*.ext"}) f1 := filepath.Join(env.base, "restore0", "testdata", "subdir1", "subdir2") fi, err := os.Stat(f1) @@ -573,7 +578,7 @@ func TestRestoreNoMetadataOnIgnoredIntermediateDirs(t *testing.T) { "meta data of intermediate directory has been restore although it was ignored") // restore with filter "*", this should restore meta data on everything. - cmdRestoreExcludes(t, global, filepath.Join(env.base, "restore1"), snapshotID, []string{"*"}) + cmdRestoreIncludes(t, global, filepath.Join(env.base, "restore1"), snapshotID, []string{"*"}) f2 := filepath.Join(env.base, "restore1", "testdata", "subdir1", "subdir2") fi, err = os.Stat(f2)