lib/model: Scanning unknown items is OK as long as the parent is known (fixes #2915)

This commit is contained in:
Michael Ploujnikov 2016-04-09 11:25:06 +00:00 committed by Jakob Borg
parent 6130578d18
commit 467d338fe4
2 changed files with 36 additions and 22 deletions

View File

@ -2086,31 +2086,39 @@ func stringSliceWithout(ss []string, s string) []string {
return ss return ss
} }
// unifySubs takes a list of files or directories and trims them down to // The exists function is expected to return true for all known paths
// themselves or the closest parent that exists() returns true for, while // (excluding "" and ".")
// removing duplicates and subdirectories. That is, if we have foo/ in the
// list, we don't also need foo/bar/ because that's already covered.
func unifySubs(dirs []string, exists func(dir string) bool) []string { func unifySubs(dirs []string, exists func(dir string) bool) []string {
var subs []string subs := trimUntilParentKnown(dirs, exists)
sort.Strings(subs)
return simplifySortedPaths(subs)
}
// Trim each item to itself or its closest known parent func trimUntilParentKnown(dirs []string, exists func(dir string) bool) []string {
var subs []string
for _, sub := range dirs { for _, sub := range dirs {
for sub != "" && sub != ".stfolder" && sub != ".stignore" { for sub != "" && sub != ".stfolder" && sub != ".stignore" {
if exists(sub) { sub = filepath.Clean(sub)
parent := filepath.Dir(sub)
if parent == "." || exists(parent) {
break break
} }
sub = filepath.Dir(sub) sub = parent
if sub == "." || sub == string(filepath.Separator) { if sub == "." || sub == string(filepath.Separator) {
// Shortcut. We are going to scan the full folder, so we can // Shortcut. We are going to scan the full folder, so we can
// just return an empty list of subs at this point. // just return an empty list of subs at this point.
return nil return nil
} }
} }
if sub == "" {
return nil
}
subs = append(subs, sub) subs = append(subs, sub)
} }
return subs
}
// Remove any paths that are already covered by their parent func simplifySortedPaths(subs []string) []string {
sort.Strings(subs)
var cleaned []string var cleaned []string
next: next:
for _, sub := range subs { for _, sub := range subs {

View File

@ -1236,50 +1236,56 @@ func TestUnifySubs(t *testing.T) {
out []string // expected output out []string // expected output
}{ }{
{ {
// trailing slashes are cleaned, known paths are just passed on // 0. trailing slashes are cleaned, known paths are just passed on
[]string{"foo/", "bar//"}, []string{"foo/", "bar//"},
[]string{"foo", "bar"}, []string{"foo", "bar"},
[]string{"bar", "foo"}, // the output is sorted []string{"bar", "foo"}, // the output is sorted
}, },
{ {
// "foo/bar" gets trimmed as it's covered by foo // 1. "foo/bar" gets trimmed as it's covered by foo
[]string{"foo", "bar/", "foo/bar/"}, []string{"foo", "bar/", "foo/bar/"},
[]string{"foo", "bar"}, []string{"foo", "bar"},
[]string{"bar", "foo"}, []string{"bar", "foo"},
}, },
{ {
// "bar" gets trimmed to "" as it's unknown, // 2. "" gets simplified to the empty list; ie scan all
// "" gets simplified to the empty list []string{"foo", ""},
[]string{"foo", "bar", "foo/bar"},
[]string{"foo"}, []string{"foo"},
nil, nil,
}, },
{ {
// two independent known paths, both are kept // 3. "foo/bar" is unknown, but it's kept
// because its parent is known
[]string{"foo/bar"},
[]string{"foo"},
[]string{"foo/bar"},
},
{
// 4. two independent known paths, both are kept
// "usr/lib" is not a prefix of "usr/libexec" // "usr/lib" is not a prefix of "usr/libexec"
[]string{"usr/lib", "usr/libexec"}, []string{"usr/lib", "usr/libexec"},
[]string{"usr/lib", "usr/libexec"}, []string{"usr", "usr/lib", "usr/libexec"},
[]string{"usr/lib", "usr/libexec"}, []string{"usr/lib", "usr/libexec"},
}, },
{ {
// "usr/lib" is a prefix of "usr/lib/exec" // 5. "usr/lib" is a prefix of "usr/lib/exec"
[]string{"usr/lib", "usr/lib/exec"}, []string{"usr/lib", "usr/lib/exec"},
[]string{"usr/lib", "usr/libexec"}, []string{"usr", "usr/lib", "usr/libexec"},
[]string{"usr/lib"}, []string{"usr/lib"},
}, },
{ {
// .stignore and .stfolder are special and are passed on // 6. .stignore and .stfolder are special and are passed on
// verbatim even though they are unknown // verbatim even though they are unknown
[]string{".stfolder", ".stignore"}, []string{".stfolder", ".stignore"},
[]string{}, []string{},
[]string{".stfolder", ".stignore"}, []string{".stfolder", ".stignore"},
}, },
{ {
// but the presense of something else unknown forces an actual // 7. but the presense of something else unknown forces an actual
// scan // scan
[]string{".stfolder", ".stignore", "foo/bar"}, []string{".stfolder", ".stignore", "foo/bar"},
[]string{}, []string{},
nil, []string{".stfolder", ".stignore", "foo"},
}, },
} }