Commit 60c4c346 authored by Rob Pike's avatar Rob Pike

path/filepath.Glob: add an error return.

The error will only occur for invalid patterns, but without this
error path there is no way to know that Glob has failed due to
an invalid pattern.

R=rsc
CC=golang-dev
https://golang.org/cl/4346044
parent 06ee80d6
...@@ -145,11 +145,14 @@ func setEnvironment() { ...@@ -145,11 +145,14 @@ func setEnvironment() {
} }
// getTestFileNames gets the set of files we're looking at. // getTestFileNames gets the set of files we're looking at.
// If gotest has no arguments, it scans the current directory for _test.go files. // If gotest has no arguments, it scans the current directory for *_test.go files.
func getTestFileNames() { func getTestFileNames() {
names := fileNames names := fileNames
if len(names) == 0 { if len(names) == 0 {
names = filepath.Glob("[^.]*_test.go") names, err = filepath.Glob("[^.]*_test.go")
if err != nil {
Fatalf("Glob pattern error: %s", err)
}
if len(names) == 0 { if len(names) == 0 {
Fatalf(`no test files found: no match for "*_test.go"`) Fatalf(`no test files found: no match for "*_test.go"`)
} }
......
...@@ -32,7 +32,7 @@ var ErrBadPattern = os.NewError("syntax error in pattern") ...@@ -32,7 +32,7 @@ var ErrBadPattern = os.NewError("syntax error in pattern")
// lo '-' hi matches character c for lo <= c <= hi // lo '-' hi matches character c for lo <= c <= hi
// //
// Match requires pattern to match all of name, not just a substring. // Match requires pattern to match all of name, not just a substring.
// The only possible error return is when pattern is malformed. // The only possible error return occurs when the pattern is malformed.
// //
func Match(pattern, name string) (matched bool, err os.Error) { func Match(pattern, name string) (matched bool, err os.Error) {
Pattern: Pattern:
...@@ -211,13 +211,14 @@ func getEsc(chunk string) (r int, nchunk string, err os.Error) { ...@@ -211,13 +211,14 @@ func getEsc(chunk string) (r int, nchunk string, err os.Error) {
// if there is no matching file. The syntax of patterns is the same // if there is no matching file. The syntax of patterns is the same
// as in Match. The pattern may describe hierarchical names such as // as in Match. The pattern may describe hierarchical names such as
// /usr/*/bin/ed (assuming the Separator is '/'). // /usr/*/bin/ed (assuming the Separator is '/').
// The only possible error return occurs when the pattern is malformed.
// //
func Glob(pattern string) (matches []string) { func Glob(pattern string) (matches []string, err os.Error) {
if !hasMeta(pattern) { if !hasMeta(pattern) {
if _, err := os.Stat(pattern); err == nil { if _, err = os.Stat(pattern); err != nil {
return []string{pattern} return
} }
return nil return []string{pattern}, nil
} }
dir, file := Split(pattern) dir, file := Split(pattern)
...@@ -230,21 +231,30 @@ func Glob(pattern string) (matches []string) { ...@@ -230,21 +231,30 @@ func Glob(pattern string) (matches []string) {
dir = dir[0 : len(dir)-1] // chop off trailing separator dir = dir[0 : len(dir)-1] // chop off trailing separator
} }
if hasMeta(dir) { if !hasMeta(dir) {
for _, d := range Glob(dir) {
matches = glob(d, file, matches)
}
} else {
return glob(dir, file, nil) return glob(dir, file, nil)
} }
return matches
var m []string
m, err = Glob(dir)
if err != nil {
return
}
for _, d := range m {
matches, err = glob(d, file, matches)
if err != nil {
return
}
}
return
} }
// glob searches for files matching pattern in the directory dir // glob searches for files matching pattern in the directory dir
// and appends them to matches. If the directory cannot be // and appends them to matches. If the directory cannot be
// opened, it returns the existing matches. New matches are // opened, it returns the existing matches. New matches are
// added in lexicographical order. // added in lexicographical order.
func glob(dir, pattern string, matches []string) (m []string) { // The only possible error return occurs when the pattern is malformed.
func glob(dir, pattern string, matches []string) (m []string, e os.Error) {
m = matches m = matches
fi, err := os.Stat(dir) fi, err := os.Stat(dir)
if err != nil { if err != nil {
...@@ -268,7 +278,7 @@ func glob(dir, pattern string, matches []string) (m []string) { ...@@ -268,7 +278,7 @@ func glob(dir, pattern string, matches []string) (m []string) {
for _, n := range names { for _, n := range names {
matched, err := Match(pattern, n) matched, err := Match(pattern, n)
if err != nil { if err != nil {
break return m, err
} }
if matched { if matched {
m = append(m, Join(dir, n)) m = append(m, Join(dir, n))
......
...@@ -6,7 +6,7 @@ package filepath_test ...@@ -6,7 +6,7 @@ package filepath_test
import ( import (
"os" "os"
"path/filepath" . "path/filepath"
"testing" "testing"
"runtime" "runtime"
) )
...@@ -56,16 +56,16 @@ var matchTests = []MatchTest{ ...@@ -56,16 +56,16 @@ var matchTests = []MatchTest{
{"[\\-x]", "x", true, nil}, {"[\\-x]", "x", true, nil},
{"[\\-x]", "-", true, nil}, {"[\\-x]", "-", true, nil},
{"[\\-x]", "a", false, nil}, {"[\\-x]", "a", false, nil},
{"[]a]", "]", false, filepath.ErrBadPattern}, {"[]a]", "]", false, ErrBadPattern},
{"[-]", "-", false, filepath.ErrBadPattern}, {"[-]", "-", false, ErrBadPattern},
{"[x-]", "x", false, filepath.ErrBadPattern}, {"[x-]", "x", false, ErrBadPattern},
{"[x-]", "-", false, filepath.ErrBadPattern}, {"[x-]", "-", false, ErrBadPattern},
{"[x-]", "z", false, filepath.ErrBadPattern}, {"[x-]", "z", false, ErrBadPattern},
{"[-x]", "x", false, filepath.ErrBadPattern}, {"[-x]", "x", false, ErrBadPattern},
{"[-x]", "-", false, filepath.ErrBadPattern}, {"[-x]", "-", false, ErrBadPattern},
{"[-x]", "a", false, filepath.ErrBadPattern}, {"[-x]", "a", false, ErrBadPattern},
{"\\", "a", false, filepath.ErrBadPattern}, {"\\", "a", false, ErrBadPattern},
{"[a-b-c]", "a", false, filepath.ErrBadPattern}, {"[a-b-c]", "a", false, ErrBadPattern},
{"*x", "xxx", true, nil}, {"*x", "xxx", true, nil},
} }
...@@ -75,7 +75,7 @@ func TestMatch(t *testing.T) { ...@@ -75,7 +75,7 @@ func TestMatch(t *testing.T) {
return return
} }
for _, tt := range matchTests { for _, tt := range matchTests {
ok, err := filepath.Match(tt.pattern, tt.s) ok, err := Match(tt.pattern, tt.s)
if ok != tt.match || err != tt.err { if ok != tt.match || err != tt.err {
t.Errorf("Match(%#q, %#q) = %v, %v want %v, nil", tt.pattern, tt.s, ok, err, tt.match) t.Errorf("Match(%#q, %#q) = %v, %v want %v, nil", tt.pattern, tt.s, ok, err, tt.match)
} }
...@@ -84,7 +84,7 @@ func TestMatch(t *testing.T) { ...@@ -84,7 +84,7 @@ func TestMatch(t *testing.T) {
// contains returns true if vector contains the string s. // contains returns true if vector contains the string s.
func contains(vector []string, s string) bool { func contains(vector []string, s string) bool {
s = filepath.ToSlash(s) s = ToSlash(s)
for _, elem := range vector { for _, elem := range vector {
if elem == s { if elem == s {
return true return true
...@@ -108,9 +108,20 @@ func TestGlob(t *testing.T) { ...@@ -108,9 +108,20 @@ func TestGlob(t *testing.T) {
return return
} }
for _, tt := range globTests { for _, tt := range globTests {
matches := filepath.Glob(tt.pattern) matches, err := Glob(tt.pattern)
if err != nil {
t.Errorf("Glob error for %q: %s", tt.pattern, err)
continue
}
if !contains(matches, tt.result) { if !contains(matches, tt.result) {
t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result) t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result)
} }
} }
} }
func TestGlobError(t *testing.T) {
_, err := Glob("[7]")
if err != nil {
t.Error("expected error for bad pattern; got none")
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment