mirror of
https://github.com/golang/go
synced 2024-11-21 15:24:45 -07:00
path: add Glob
As discussed in http://groups.google.com/group/golang-dev/browse_thread/thread/926b7d550d98ec9e, add a simple "path expander" function, which returns all the files matching the given pattern. This function is called Glob after glob(3) in libc. Also add a convenience function, hasMeta, that checks whether a string contains one of the characters which are specially handled by Match. R=rsc, r, r2 CC=golang-dev https://golang.org/cl/2476041
This commit is contained in:
parent
ea84b4700a
commit
a4f3d647d4
@ -2,6 +2,7 @@ package path
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"utf8"
|
||||
)
|
||||
@ -202,3 +203,72 @@ func getEsc(chunk string) (r int, nchunk string, err os.Error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Glob returns the names of all files matching pattern or nil
|
||||
// if there is no matching file. The syntax of patterns is the same
|
||||
// as in Match. The pattern may describe hierarchical names such as
|
||||
// /usr/*/bin/ed.
|
||||
//
|
||||
func Glob(pattern string) (matches []string) {
|
||||
if !hasMeta(pattern) {
|
||||
if _, err := os.Stat(pattern); err == nil {
|
||||
return []string{pattern}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
dir, file := Split(pattern)
|
||||
switch dir {
|
||||
case "":
|
||||
dir = "."
|
||||
case "/":
|
||||
// nothing
|
||||
default:
|
||||
dir = dir[0 : len(dir)-1] // chop off trailing '/'
|
||||
}
|
||||
|
||||
if hasMeta(dir) {
|
||||
for _, d := range Glob(dir) {
|
||||
matches = glob(d, file, matches)
|
||||
}
|
||||
} else {
|
||||
return glob(dir, file, nil)
|
||||
}
|
||||
return matches
|
||||
}
|
||||
|
||||
// glob searches for files matching pattern in the directory dir
|
||||
// and appends them to matches.
|
||||
func glob(dir, pattern string, matches []string) []string {
|
||||
if fi, err := os.Stat(dir); err != nil || !fi.IsDirectory() {
|
||||
return nil
|
||||
}
|
||||
d, err := os.Open(dir, os.O_RDONLY, 0666)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
names, err := d.Readdirnames(-1)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
sort.SortStrings(names)
|
||||
|
||||
for _, n := range names {
|
||||
matched, err := Match(pattern, n)
|
||||
if err != nil {
|
||||
return matches
|
||||
}
|
||||
if matched {
|
||||
matches = append(matches, Join(dir, n))
|
||||
}
|
||||
}
|
||||
return matches
|
||||
}
|
||||
|
||||
// hasMeta returns true if path contains any of the magic characters
|
||||
// recognized by Match.
|
||||
func hasMeta(path string) bool {
|
||||
return strings.IndexAny(path, "*?[") != -1
|
||||
}
|
||||
|
@ -75,3 +75,31 @@ func TestMatch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// contains returns true if vector contains the string s.
|
||||
func contains(vector []string, s string) bool {
|
||||
for _, elem := range vector {
|
||||
if elem == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var globTests = []struct {
|
||||
pattern, result string
|
||||
}{
|
||||
{"match.go", "match.go"},
|
||||
{"mat?h.go", "match.go"},
|
||||
{"*", "match.go"},
|
||||
{"../*/match.go", "../path/match.go"},
|
||||
}
|
||||
|
||||
func TestGlob(t *testing.T) {
|
||||
for _, tt := range globTests {
|
||||
matches := Glob(tt.pattern)
|
||||
if !contains(matches, tt.result) {
|
||||
t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user