Merge "veyron/profiles/roaming: Move ListenSpec initialization"
diff --git a/lib/glob/glob.go b/lib/glob/glob.go
index b1356c1..a69be73 100644
--- a/lib/glob/glob.go
+++ b/lib/glob/glob.go
@@ -75,42 +75,49 @@
}
// MatchInitialSegment tries to match segment against the initial element of g.
-// Returns a boolean indicating whether the match was successful and the
-// Glob representing the unmatched remainder of g.
-func (g *Glob) MatchInitialSegment(segment string) (bool, *Glob) {
+// Returns:
+// matched, a boolean indicating whether the match was successful;
+// exact, a boolean indicating whether segment matched a fixed string pattern;
+// remainder, a Glob representing the unmatched remainder of g.
+func (g *Glob) MatchInitialSegment(segment string) (matched bool, exact bool, remainder *Glob) {
if len(g.elems) == 0 {
if !g.recursive {
- return false, nil
+ return false, false, nil
}
- return true, g
+ return true, true, g
}
if matches, err := filepath.Match(g.elems[0], segment); err != nil {
panic("Error in glob pattern found.")
} else if matches {
- return true, g.Split(1)
+ _, fixed := isFixed(g.elems[0])
+ return true, fixed, g.Split(1)
}
- return false, nil
+ return false, false, nil
}
// PartialMatch tries matching elems against part of a glob pattern.
-// The first return value is true if each element e_i of elems matches
-// the (start + i)th element of the glob pattern. If the first return
-// value is true, the second return value returns the unmatched suffix
-// of the pattern. It will be empty if the pattern is completely
-// matched.
+// Returns:
+// matched, a boolean indicating whether each element e_i of elems matches the
+// (start + i)th element of the glob pattern;
+// exact, a boolean indicating whether elems matched a fixed string pattern;
+// remainder, a Glob representing the unmatched remainder of g. remainder will
+// be empty if the pattern is completely matched.
//
// Note that if the glob is recursive elems can have more elements then
// the glob pattern and still get a true result.
-func (g *Glob) PartialMatch(start int, elems []string) (bool, *Glob) {
+func (g *Glob) PartialMatch(start int, elems []string) (matched bool, exact bool, remainder *Glob) {
g = g.Split(start)
- for ; len(elems) > 0; elems = elems[1:] {
- var matched bool
- if matched, g = g.MatchInitialSegment(elems[0]); !matched {
- return false, nil
+ allExact := true
+ for i := 0; i < len(elems); i++ {
+ var matched, exact bool
+ if matched, exact, g = g.MatchInitialSegment(elems[i]); !matched {
+ return false, false, nil
+ } else if !exact {
+ allExact = false
}
}
- return true, g
+ return true, allExact, g
}
// isFixed returns the unescaped string and true if 's' is a pattern specifying
diff --git a/lib/glob/glob_test.go b/lib/glob/glob_test.go
index bbef347..785a1eb 100644
--- a/lib/glob/glob_test.go
+++ b/lib/glob/glob_test.go
@@ -38,3 +38,63 @@
}
}
}
+
+func TestExactMatch(t *testing.T) {
+ tests := []struct {
+ pattern string
+ elems []string
+ matched bool
+ exact bool
+ }{
+ // Test one element, fixed.
+ {"a", []string{"a"}, true, true},
+ {"a", []string{"b"}, false, false},
+ {"\\\\", []string{"\\"}, true, true},
+ // Test one element, containing *.
+ {"*", []string{"*"}, true, false},
+ {"*", []string{"abc"}, true, false},
+ {"\\*", []string{"*"}, true, true},
+ {"\\*", []string{"abc"}, false, false},
+ {"\\\\*", []string{"\\"}, true, false},
+ {"\\\\*", []string{"\\*"}, true, false},
+ {"\\\\*", []string{"\\abc"}, true, false},
+ // Test one element, containing ?.
+ {"?", []string{"?"}, true, false},
+ {"?", []string{"a"}, true, false},
+ {"\\?", []string{"?"}, true, true},
+ {"\\?", []string{"a"}, false, false},
+ {"\\\\?", []string{"\\"}, false, false},
+ {"\\\\?", []string{"\\?"}, true, false},
+ {"\\\\?", []string{"\\a"}, true, false},
+ // Test one element, containing [].
+ {"[abc]", []string{"c"}, true, false},
+ {"\\[abc\\]", []string{"[abc]"}, true, true},
+ {"\\[abc\\]", []string{"a"}, false, false},
+ {"\\\\[abc]", []string{"\\a"}, true, false},
+ {"\\\\[abc]", []string{"a"}, false, false},
+ {"[\\\\]", []string{"\\"}, true, false},
+ {"[\\\\]", []string{"a"}, false, false},
+ // Test multiple elements.
+ {"a/b", []string{"a", "b"}, true, true},
+ {"a/\\*", []string{"a", "*"}, true, true},
+ {"a/\\?", []string{"a", "?"}, true, true},
+ {"a/\\[b\\]", []string{"a", "[b]"}, true, true},
+ {"a/*", []string{"a", "bc"}, true, false},
+ {"a/?", []string{"a", "b"}, true, false},
+ {"a/[bc]", []string{"a", "b"}, true, false},
+ {"a/*/c", []string{"a", "b", "c"}, true, false},
+ {"a/?/c", []string{"a", "b", "c"}, true, false},
+ {"a/[bc]/d", []string{"a", "b", "d"}, true, false},
+ }
+ for _, test := range tests {
+ g, err := Parse(test.pattern)
+ if err != nil {
+ t.Fatalf("parsing %q: %q", test.pattern, err.Error())
+ }
+ matched, exact, _ := g.PartialMatch(0, test.elems)
+ if matched != test.matched || exact != test.exact {
+ t.Fatalf("%v.PartialMatch(0, %v) got (%v, %v), expected (%v, %v)",
+ test.pattern, test.elems, matched, exact, test.matched, test.exact)
+ }
+ }
+}
diff --git a/lib/stats/glob.go b/lib/stats/glob.go
index f2db758..1390853 100644
--- a/lib/stats/glob.go
+++ b/lib/stats/glob.go
@@ -50,7 +50,7 @@
return
}
for name, child := range n.children {
- if ok, left := g.MatchInitialSegment(name); ok {
+ if ok, _, left := g.MatchInitialSegment(name); ok {
globStepLocked(path.Join(prefix, name), left, child, updatedSince, includeValues, result)
}
}
diff --git a/runtimes/google/naming/namespace/all_test.go b/runtimes/google/naming/namespace/all_test.go
index 479b5bd..bbac581 100644
--- a/runtimes/google/naming/namespace/all_test.go
+++ b/runtimes/google/naming/namespace/all_test.go
@@ -91,7 +91,7 @@
if g.Finished() || len(tree) == 0 {
return nil
}
- if ok, left := g.MatchInitialSegment(tree[0]); ok {
+ if ok, _, left := g.MatchInitialSegment(tree[0]); ok {
if err := t.globLoop(call, naming.Join(prefix, tree[0]), left, tree[1:]); err != nil {
return err
}
diff --git a/services/mgmt/debug/dispatcher.go b/services/mgmt/debug/dispatcher.go
index a0c86cc..9c6e3b8 100644
--- a/services/mgmt/debug/dispatcher.go
+++ b/services/mgmt/debug/dispatcher.go
@@ -62,7 +62,7 @@
return err
}
for _, leaf := range i.leaves {
- if ok, left := g.MatchInitialSegment(leaf); ok {
+ if ok, _, left := g.MatchInitialSegment(leaf); ok {
if err := i.leafGlob(call, leaf, left.String()); err != nil {
return err
}
diff --git a/services/mgmt/logreader/impl/logdir_invoker.go b/services/mgmt/logreader/impl/logdir_invoker.go
index 5beb139..ef7a60b 100644
--- a/services/mgmt/logreader/impl/logdir_invoker.go
+++ b/services/mgmt/logreader/impl/logdir_invoker.go
@@ -78,7 +78,7 @@
if fileName == "." || fileName == ".." {
continue
}
- if ok, left := g.MatchInitialSegment(fileName); ok {
+ if ok, _, left := g.MatchInitialSegment(fileName); ok {
if err := i.globStep(path.Join(name, fileName), left, file.IsDir(), call); err != nil {
return err
}
diff --git a/services/mounttable/lib/mounttable.go b/services/mounttable/lib/mounttable.go
index 922f4c7..85936ec 100644
--- a/services/mounttable/lib/mounttable.go
+++ b/services/mounttable/lib/mounttable.go
@@ -357,7 +357,7 @@
// Recurse through the children.
for k, c := range n.children {
- if ok, suffix := pattern.MatchInitialSegment(k); ok {
+ if ok, _, suffix := pattern.MatchInitialSegment(k); ok {
mt.globStep(c, naming.Join(name, k), suffix, context, reply)
}
}
diff --git a/services/mounttable/lib/neighborhood.go b/services/mounttable/lib/neighborhood.go
index ad66bfb..acdb46c 100644
--- a/services/mounttable/lib/neighborhood.go
+++ b/services/mounttable/lib/neighborhood.go
@@ -244,7 +244,7 @@
switch len(ns.elems) {
case 0:
for k, n := range nh.neighbors() {
- if ok, _ := g.MatchInitialSegment(k); !ok {
+ if ok, _, _ := g.MatchInitialSegment(k); !ok {
continue
}
if err := sender.Send(types.MountEntry{Name: k, Servers: n}); err != nil {