diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
commit | f154da9e12608589e8d5f0508f908a0c3e88a1bb (patch) | |
tree | f8255d51e10c6f1e0ed69702200b966c9556a431 /src/pkg/path | |
parent | 8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff) | |
download | golang-upstream/1.4.tar.gz |
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/pkg/path')
-rw-r--r-- | src/pkg/path/example_test.go | 63 | ||||
-rw-r--r-- | src/pkg/path/filepath/example_unix_test.go | 39 | ||||
-rw-r--r-- | src/pkg/path/filepath/export_test.go | 7 | ||||
-rw-r--r-- | src/pkg/path/filepath/match.go | 309 | ||||
-rw-r--r-- | src/pkg/path/filepath/match_test.go | 206 | ||||
-rw-r--r-- | src/pkg/path/filepath/path.go | 467 | ||||
-rw-r--r-- | src/pkg/path/filepath/path_plan9.go | 30 | ||||
-rw-r--r-- | src/pkg/path/filepath/path_test.go | 1017 | ||||
-rw-r--r-- | src/pkg/path/filepath/path_unix.go | 32 | ||||
-rw-r--r-- | src/pkg/path/filepath/path_windows.go | 105 | ||||
-rw-r--r-- | src/pkg/path/filepath/path_windows_test.go | 93 | ||||
-rw-r--r-- | src/pkg/path/filepath/symlink.go | 67 | ||||
-rw-r--r-- | src/pkg/path/filepath/symlink_windows.go | 69 | ||||
-rw-r--r-- | src/pkg/path/match.go | 209 | ||||
-rw-r--r-- | src/pkg/path/match_test.go | 79 | ||||
-rw-r--r-- | src/pkg/path/path.go | 218 | ||||
-rw-r--r-- | src/pkg/path/path_test.go | 241 |
17 files changed, 0 insertions, 3251 deletions
diff --git a/src/pkg/path/example_test.go b/src/pkg/path/example_test.go deleted file mode 100644 index fa8c28d2e..000000000 --- a/src/pkg/path/example_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package path_test - -import ( - "fmt" - "path" -) - -func ExampleBase() { - fmt.Println(path.Base("/a/b")) - // Output: b -} - -func ExampleClean() { - paths := []string{ - "a/c", - "a//c", - "a/c/.", - "a/c/b/..", - "/../a/c", - "/../a/b/../././/c", - } - - for _, p := range paths { - fmt.Printf("Clean(%q) = %q\n", p, path.Clean(p)) - } - - // Output: - // Clean("a/c") = "a/c" - // Clean("a//c") = "a/c" - // Clean("a/c/.") = "a/c" - // Clean("a/c/b/..") = "a/c" - // Clean("/../a/c") = "/a/c" - // Clean("/../a/b/../././/c") = "/a/c" -} - -func ExampleDir() { - fmt.Println(path.Dir("/a/b/c")) - // Output: /a/b -} - -func ExampleExt() { - fmt.Println(path.Ext("/a/b/c/bar.css")) - // Output: .css -} - -func ExampleIsAbs() { - fmt.Println(path.IsAbs("/dev/null")) - // Output: true -} - -func ExampleJoin() { - fmt.Println(path.Join("a", "b", "c")) - // Output: a/b/c -} - -func ExampleSplit() { - fmt.Println(path.Split("static/myfile.css")) - // Output: static/ myfile.css -} diff --git a/src/pkg/path/filepath/example_unix_test.go b/src/pkg/path/filepath/example_unix_test.go deleted file mode 100644 index f3fe076c3..000000000 --- a/src/pkg/path/filepath/example_unix_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !windows,!plan9 - -package filepath_test - -import ( - "fmt" - "path/filepath" -) - -func ExampleSplitList() { - fmt.Println("On Unix:", filepath.SplitList("/a/b/c:/usr/bin")) - // Output: - // On Unix: [/a/b/c /usr/bin] -} - -func ExampleRel() { - paths := []string{ - "/a/b/c", - "/b/c", - "./b/c", - } - base := "/a" - - fmt.Println("On Unix:") - for _, p := range paths { - rel, err := filepath.Rel(base, p) - fmt.Printf("%q: %q %v\n", p, rel, err) - } - - // Output: - // On Unix: - // "/a/b/c": "b/c" <nil> - // "/b/c": "../b/c" <nil> - // "./b/c": "" Rel: can't make b/c relative to /a -} diff --git a/src/pkg/path/filepath/export_test.go b/src/pkg/path/filepath/export_test.go deleted file mode 100644 index 0cf9e3bca..000000000 --- a/src/pkg/path/filepath/export_test.go +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package filepath - -var LstatP = &lstat diff --git a/src/pkg/path/filepath/match.go b/src/pkg/path/filepath/match.go deleted file mode 100644 index a9bcc103c..000000000 --- a/src/pkg/path/filepath/match.go +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package filepath - -import ( - "errors" - "os" - "runtime" - "sort" - "strings" - "unicode/utf8" -) - -// ErrBadPattern indicates a globbing pattern was malformed. -var ErrBadPattern = errors.New("syntax error in pattern") - -// Match returns true if name matches the shell file name pattern. -// The pattern syntax is: -// -// pattern: -// { term } -// term: -// '*' matches any sequence of non-Separator characters -// '?' matches any single non-Separator character -// '[' [ '^' ] { character-range } ']' -// character class (must be non-empty) -// c matches character c (c != '*', '?', '\\', '[') -// '\\' c matches character c -// -// character-range: -// c matches character c (c != '\\', '-', ']') -// '\\' c matches character c -// lo '-' hi matches character c for lo <= c <= hi -// -// Match requires pattern to match all of name, not just a substring. -// The only possible returned error is ErrBadPattern, when pattern -// is malformed. -// -// On Windows, escaping is disabled. Instead, '\\' is treated as -// path separator. -// -func Match(pattern, name string) (matched bool, err error) { -Pattern: - for len(pattern) > 0 { - var star bool - var chunk string - star, chunk, pattern = scanChunk(pattern) - if star && chunk == "" { - // Trailing * matches rest of string unless it has a /. - return strings.Index(name, string(Separator)) < 0, nil - } - // Look for match at current position. - t, ok, err := matchChunk(chunk, name) - // if we're the last chunk, make sure we've exhausted the name - // otherwise we'll give a false result even if we could still match - // using the star - if ok && (len(t) == 0 || len(pattern) > 0) { - name = t - continue - } - if err != nil { - return false, err - } - if star { - // Look for match skipping i+1 bytes. - // Cannot skip /. - for i := 0; i < len(name) && name[i] != Separator; i++ { - t, ok, err := matchChunk(chunk, name[i+1:]) - if ok { - // if we're the last chunk, make sure we exhausted the name - if len(pattern) == 0 && len(t) > 0 { - continue - } - name = t - continue Pattern - } - if err != nil { - return false, err - } - } - } - return false, nil - } - return len(name) == 0, nil -} - -// scanChunk gets the next segment of pattern, which is a non-star string -// possibly preceded by a star. -func scanChunk(pattern string) (star bool, chunk, rest string) { - for len(pattern) > 0 && pattern[0] == '*' { - pattern = pattern[1:] - star = true - } - inrange := false - var i int -Scan: - for i = 0; i < len(pattern); i++ { - switch pattern[i] { - case '\\': - if runtime.GOOS != "windows" { - // error check handled in matchChunk: bad pattern. - if i+1 < len(pattern) { - i++ - } - } - case '[': - inrange = true - case ']': - inrange = false - case '*': - if !inrange { - break Scan - } - } - } - return star, pattern[0:i], pattern[i:] -} - -// matchChunk checks whether chunk matches the beginning of s. -// If so, it returns the remainder of s (after the match). -// Chunk is all single-character operators: literals, char classes, and ?. -func matchChunk(chunk, s string) (rest string, ok bool, err error) { - for len(chunk) > 0 { - if len(s) == 0 { - return - } - switch chunk[0] { - case '[': - // character class - r, n := utf8.DecodeRuneInString(s) - s = s[n:] - chunk = chunk[1:] - // We can't end right after '[', we're expecting at least - // a closing bracket and possibly a caret. - if len(chunk) == 0 { - err = ErrBadPattern - return - } - // possibly negated - negated := chunk[0] == '^' - if negated { - chunk = chunk[1:] - } - // parse all ranges - match := false - nrange := 0 - for { - if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 { - chunk = chunk[1:] - break - } - var lo, hi rune - if lo, chunk, err = getEsc(chunk); err != nil { - return - } - hi = lo - if chunk[0] == '-' { - if hi, chunk, err = getEsc(chunk[1:]); err != nil { - return - } - } - if lo <= r && r <= hi { - match = true - } - nrange++ - } - if match == negated { - return - } - - case '?': - if s[0] == Separator { - return - } - _, n := utf8.DecodeRuneInString(s) - s = s[n:] - chunk = chunk[1:] - - case '\\': - if runtime.GOOS != "windows" { - chunk = chunk[1:] - if len(chunk) == 0 { - err = ErrBadPattern - return - } - } - fallthrough - - default: - if chunk[0] != s[0] { - return - } - s = s[1:] - chunk = chunk[1:] - } - } - return s, true, nil -} - -// getEsc gets a possibly-escaped character from chunk, for a character class. -func getEsc(chunk string) (r rune, nchunk string, err error) { - if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' { - err = ErrBadPattern - return - } - if chunk[0] == '\\' && runtime.GOOS != "windows" { - chunk = chunk[1:] - if len(chunk) == 0 { - err = ErrBadPattern - return - } - } - r, n := utf8.DecodeRuneInString(chunk) - if r == utf8.RuneError && n == 1 { - err = ErrBadPattern - } - nchunk = chunk[n:] - if len(nchunk) == 0 { - err = ErrBadPattern - } - 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 (assuming the Separator is '/'). -// -func Glob(pattern string) (matches []string, err error) { - if !hasMeta(pattern) { - if _, err = os.Lstat(pattern); err != nil { - return nil, nil - } - return []string{pattern}, nil - } - - dir, file := Split(pattern) - switch dir { - case "": - dir = "." - case string(Separator): - // nothing - default: - dir = dir[0 : len(dir)-1] // chop off trailing separator - } - - if !hasMeta(dir) { - return glob(dir, file, nil) - } - - 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 -// and appends them to matches. If the directory cannot be -// opened, it returns the existing matches. New matches are -// added in lexicographical order. -func glob(dir, pattern string, matches []string) (m []string, e error) { - m = matches - fi, err := os.Stat(dir) - if err != nil { - return - } - if !fi.IsDir() { - return - } - d, err := os.Open(dir) - if err != nil { - return - } - defer d.Close() - - names, err := d.Readdirnames(-1) - if err != nil { - return - } - sort.Strings(names) - - for _, n := range names { - matched, err := Match(pattern, n) - if err != nil { - return m, err - } - if matched { - m = append(m, Join(dir, n)) - } - } - return -} - -// hasMeta returns true if path contains any of the magic characters -// recognized by Match. -func hasMeta(path string) bool { - // TODO(niemeyer): Should other magic characters be added here? - return strings.IndexAny(path, "*?[") >= 0 -} diff --git a/src/pkg/path/filepath/match_test.go b/src/pkg/path/filepath/match_test.go deleted file mode 100644 index 382692eaa..000000000 --- a/src/pkg/path/filepath/match_test.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package filepath_test - -import ( - "io/ioutil" - "os" - . "path/filepath" - "runtime" - "strings" - "testing" -) - -type MatchTest struct { - pattern, s string - match bool - err error -} - -var matchTests = []MatchTest{ - {"abc", "abc", true, nil}, - {"*", "abc", true, nil}, - {"*c", "abc", true, nil}, - {"a*", "a", true, nil}, - {"a*", "abc", true, nil}, - {"a*", "ab/c", false, nil}, - {"a*/b", "abc/b", true, nil}, - {"a*/b", "a/c/b", false, nil}, - {"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil}, - {"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil}, - {"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil}, - {"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil}, - {"a*b?c*x", "abxbbxdbxebxczzx", true, nil}, - {"a*b?c*x", "abxbbxdbxebxczzy", false, nil}, - {"ab[c]", "abc", true, nil}, - {"ab[b-d]", "abc", true, nil}, - {"ab[e-g]", "abc", false, nil}, - {"ab[^c]", "abc", false, nil}, - {"ab[^b-d]", "abc", false, nil}, - {"ab[^e-g]", "abc", true, nil}, - {"a\\*b", "a*b", true, nil}, - {"a\\*b", "ab", false, nil}, - {"a?b", "a☺b", true, nil}, - {"a[^a]b", "a☺b", true, nil}, - {"a???b", "a☺b", false, nil}, - {"a[^a][^a][^a]b", "a☺b", false, nil}, - {"[a-ζ]*", "α", true, nil}, - {"*[a-ζ]", "A", false, nil}, - {"a?b", "a/b", false, nil}, - {"a*b", "a/b", false, nil}, - {"[\\]a]", "]", true, nil}, - {"[\\-]", "-", true, nil}, - {"[x\\-]", "x", true, nil}, - {"[x\\-]", "-", true, nil}, - {"[x\\-]", "z", false, nil}, - {"[\\-x]", "x", true, nil}, - {"[\\-x]", "-", true, nil}, - {"[\\-x]", "a", false, nil}, - {"[]a]", "]", false, ErrBadPattern}, - {"[-]", "-", false, ErrBadPattern}, - {"[x-]", "x", false, ErrBadPattern}, - {"[x-]", "-", false, ErrBadPattern}, - {"[x-]", "z", false, ErrBadPattern}, - {"[-x]", "x", false, ErrBadPattern}, - {"[-x]", "-", false, ErrBadPattern}, - {"[-x]", "a", false, ErrBadPattern}, - {"\\", "a", false, ErrBadPattern}, - {"[a-b-c]", "a", false, ErrBadPattern}, - {"[", "a", false, ErrBadPattern}, - {"[^", "a", false, ErrBadPattern}, - {"[^bc", "a", false, ErrBadPattern}, - {"a[", "a", false, nil}, - {"a[", "ab", false, ErrBadPattern}, - {"*x", "xxx", true, nil}, -} - -func errp(e error) string { - if e == nil { - return "<nil>" - } - return e.Error() -} - -func TestMatch(t *testing.T) { - for _, tt := range matchTests { - pattern := tt.pattern - s := tt.s - if runtime.GOOS == "windows" { - if strings.Index(pattern, "\\") >= 0 { - // no escape allowed on windows. - continue - } - pattern = Clean(pattern) - s = Clean(s) - } - ok, err := Match(pattern, s) - if ok != tt.match || err != tt.err { - t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", pattern, s, ok, errp(err), tt.match, errp(tt.err)) - } - } -} - -// 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", "../filepath/match.go"}, -} - -func TestGlob(t *testing.T) { - for _, tt := range globTests { - pattern := tt.pattern - result := tt.result - if runtime.GOOS == "windows" { - pattern = Clean(pattern) - result = Clean(result) - } - matches, err := Glob(pattern) - if err != nil { - t.Errorf("Glob error for %q: %s", pattern, err) - continue - } - if !contains(matches, result) { - t.Errorf("Glob(%#q) = %#v want %v", pattern, matches, result) - } - } - for _, pattern := range []string{"no_match", "../*/no_match"} { - matches, err := Glob(pattern) - if err != nil { - t.Errorf("Glob error for %q: %s", pattern, err) - continue - } - if len(matches) != 0 { - t.Errorf("Glob(%#q) = %#v want []", pattern, matches) - } - } -} - -func TestGlobError(t *testing.T) { - _, err := Glob("[7]") - if err != nil { - t.Error("expected error for bad pattern; got none") - } -} - -var globSymlinkTests = []struct { - path, dest string - brokenLink bool -}{ - {"test1", "link1", false}, - {"test2", "link2", true}, -} - -func TestGlobSymlink(t *testing.T) { - switch runtime.GOOS { - case "nacl", "plan9", "windows": - t.Skipf("skipping on %s", runtime.GOOS) - } - - tmpDir, err := ioutil.TempDir("", "globsymlink") - if err != nil { - t.Fatal("creating temp dir:", err) - } - defer os.RemoveAll(tmpDir) - - for _, tt := range globSymlinkTests { - path := Join(tmpDir, tt.path) - dest := Join(tmpDir, tt.dest) - f, err := os.Create(path) - if err != nil { - t.Fatal(err) - } - if err := f.Close(); err != nil { - t.Fatal(err) - } - err = os.Symlink(path, dest) - if err != nil { - t.Fatal(err) - } - if tt.brokenLink { - // Break the symlink. - os.Remove(path) - } - matches, err := Glob(dest) - if err != nil { - t.Errorf("GlobSymlink error for %q: %s", dest, err) - } - if !contains(matches, dest) { - t.Errorf("Glob(%#q) = %#v want %v", dest, matches, dest) - } - } -} diff --git a/src/pkg/path/filepath/path.go b/src/pkg/path/filepath/path.go deleted file mode 100644 index 71603cc59..000000000 --- a/src/pkg/path/filepath/path.go +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package filepath implements utility routines for manipulating filename paths -// in a way compatible with the target operating system-defined file paths. -package filepath - -import ( - "errors" - "os" - "sort" - "strings" -) - -// A lazybuf is a lazily constructed path buffer. -// It supports append, reading previously appended bytes, -// and retrieving the final string. It does not allocate a buffer -// to hold the output until that output diverges from s. -type lazybuf struct { - path string - buf []byte - w int - volAndPath string - volLen int -} - -func (b *lazybuf) index(i int) byte { - if b.buf != nil { - return b.buf[i] - } - return b.path[i] -} - -func (b *lazybuf) append(c byte) { - if b.buf == nil { - if b.w < len(b.path) && b.path[b.w] == c { - b.w++ - return - } - b.buf = make([]byte, len(b.path)) - copy(b.buf, b.path[:b.w]) - } - b.buf[b.w] = c - b.w++ -} - -func (b *lazybuf) string() string { - if b.buf == nil { - return b.volAndPath[:b.volLen+b.w] - } - return b.volAndPath[:b.volLen] + string(b.buf[:b.w]) -} - -const ( - Separator = os.PathSeparator - ListSeparator = os.PathListSeparator -) - -// Clean returns the shortest path name equivalent to path -// by purely lexical processing. It applies the following rules -// iteratively until no further processing can be done: -// -// 1. Replace multiple Separator elements with a single one. -// 2. Eliminate each . path name element (the current directory). -// 3. Eliminate each inner .. path name element (the parent directory) -// along with the non-.. element that precedes it. -// 4. Eliminate .. elements that begin a rooted path: -// that is, replace "/.." by "/" at the beginning of a path, -// assuming Separator is '/'. -// -// The returned path ends in a slash only if it represents a root directory, -// such as "/" on Unix or `C:\` on Windows. -// -// If the result of this process is an empty string, Clean -// returns the string ".". -// -// See also Rob Pike, ``Lexical File Names in Plan 9 or -// Getting Dot-Dot Right,'' -// http://plan9.bell-labs.com/sys/doc/lexnames.html -func Clean(path string) string { - originalPath := path - volLen := volumeNameLen(path) - path = path[volLen:] - if path == "" { - if volLen > 1 && originalPath[1] != ':' { - // should be UNC - return FromSlash(originalPath) - } - return originalPath + "." - } - rooted := os.IsPathSeparator(path[0]) - - // Invariants: - // reading from path; r is index of next byte to process. - // writing to buf; w is index of next byte to write. - // dotdot is index in buf where .. must stop, either because - // it is the leading slash or it is a leading ../../.. prefix. - n := len(path) - out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen} - r, dotdot := 0, 0 - if rooted { - out.append(Separator) - r, dotdot = 1, 1 - } - - for r < n { - switch { - case os.IsPathSeparator(path[r]): - // empty path element - r++ - case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])): - // . element - r++ - case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])): - // .. element: remove to last separator - r += 2 - switch { - case out.w > dotdot: - // can backtrack - out.w-- - for out.w > dotdot && !os.IsPathSeparator(out.index(out.w)) { - out.w-- - } - case !rooted: - // cannot backtrack, but not rooted, so append .. element. - if out.w > 0 { - out.append(Separator) - } - out.append('.') - out.append('.') - dotdot = out.w - } - default: - // real path element. - // add slash if needed - if rooted && out.w != 1 || !rooted && out.w != 0 { - out.append(Separator) - } - // copy element - for ; r < n && !os.IsPathSeparator(path[r]); r++ { - out.append(path[r]) - } - } - } - - // Turn empty string into "." - if out.w == 0 { - out.append('.') - } - - return FromSlash(out.string()) -} - -// ToSlash returns the result of replacing each separator character -// in path with a slash ('/') character. Multiple separators are -// replaced by multiple slashes. -func ToSlash(path string) string { - if Separator == '/' { - return path - } - return strings.Replace(path, string(Separator), "/", -1) -} - -// FromSlash returns the result of replacing each slash ('/') character -// in path with a separator character. Multiple slashes are replaced -// by multiple separators. -func FromSlash(path string) string { - if Separator == '/' { - return path - } - return strings.Replace(path, "/", string(Separator), -1) -} - -// SplitList splits a list of paths joined by the OS-specific ListSeparator, -// usually found in PATH or GOPATH environment variables. -// Unlike strings.Split, SplitList returns an empty slice when passed an empty string. -func SplitList(path string) []string { - return splitList(path) -} - -// Split splits path immediately following the final Separator, -// separating it into a directory and file name component. -// If there is no Separator in path, Split returns an empty dir -// and file set to path. -// The returned values have the property that path = dir+file. -func Split(path string) (dir, file string) { - vol := VolumeName(path) - i := len(path) - 1 - for i >= len(vol) && !os.IsPathSeparator(path[i]) { - i-- - } - return path[:i+1], path[i+1:] -} - -// Join joins any number of path elements into a single path, adding -// a Separator if necessary. The result is Cleaned, in particular -// all empty strings are ignored. -func Join(elem ...string) string { - for i, e := range elem { - if e != "" { - return Clean(strings.Join(elem[i:], string(Separator))) - } - } - return "" -} - -// Ext returns the file name extension used by path. -// The extension is the suffix beginning at the final dot -// in the final element of path; it is empty if there is -// no dot. -func Ext(path string) string { - for i := len(path) - 1; i >= 0 && !os.IsPathSeparator(path[i]); i-- { - if path[i] == '.' { - return path[i:] - } - } - return "" -} - -// EvalSymlinks returns the path name after the evaluation of any symbolic -// links. -// If path is relative the result will be relative to the current directory, -// unless one of the components is an absolute symbolic link. -func EvalSymlinks(path string) (string, error) { - return evalSymlinks(path) -} - -// Abs returns an absolute representation of path. -// If the path is not absolute it will be joined with the current -// working directory to turn it into an absolute path. The absolute -// path name for a given file is not guaranteed to be unique. -func Abs(path string) (string, error) { - if IsAbs(path) { - return Clean(path), nil - } - wd, err := os.Getwd() - if err != nil { - return "", err - } - return Join(wd, path), nil -} - -// Rel returns a relative path that is lexically equivalent to targpath when -// joined to basepath with an intervening separator. That is, -// Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself. -// On success, the returned path will always be relative to basepath, -// even if basepath and targpath share no elements. -// An error is returned if targpath can't be made relative to basepath or if -// knowing the current working directory would be necessary to compute it. -func Rel(basepath, targpath string) (string, error) { - baseVol := VolumeName(basepath) - targVol := VolumeName(targpath) - base := Clean(basepath) - targ := Clean(targpath) - if targ == base { - return ".", nil - } - base = base[len(baseVol):] - targ = targ[len(targVol):] - if base == "." { - base = "" - } - // Can't use IsAbs - `\a` and `a` are both relative in Windows. - baseSlashed := len(base) > 0 && base[0] == Separator - targSlashed := len(targ) > 0 && targ[0] == Separator - if baseSlashed != targSlashed || baseVol != targVol { - return "", errors.New("Rel: can't make " + targ + " relative to " + base) - } - // Position base[b0:bi] and targ[t0:ti] at the first differing elements. - bl := len(base) - tl := len(targ) - var b0, bi, t0, ti int - for { - for bi < bl && base[bi] != Separator { - bi++ - } - for ti < tl && targ[ti] != Separator { - ti++ - } - if targ[t0:ti] != base[b0:bi] { - break - } - if bi < bl { - bi++ - } - if ti < tl { - ti++ - } - b0 = bi - t0 = ti - } - if base[b0:bi] == ".." { - return "", errors.New("Rel: can't make " + targ + " relative to " + base) - } - if b0 != bl { - // Base elements left. Must go up before going down. - seps := strings.Count(base[b0:bl], string(Separator)) - size := 2 + seps*3 - if tl != t0 { - size += 1 + tl - t0 - } - buf := make([]byte, size) - n := copy(buf, "..") - for i := 0; i < seps; i++ { - buf[n] = Separator - copy(buf[n+1:], "..") - n += 3 - } - if t0 != tl { - buf[n] = Separator - copy(buf[n+1:], targ[t0:]) - } - return string(buf), nil - } - return targ[t0:], nil -} - -// SkipDir is used as a return value from WalkFuncs to indicate that -// the directory named in the call is to be skipped. It is not returned -// as an error by any function. -var SkipDir = errors.New("skip this directory") - -// WalkFunc is the type of the function called for each file or directory -// visited by Walk. The path argument contains the argument to Walk as a -// prefix; that is, if Walk is called with "dir", which is a directory -// containing the file "a", the walk function will be called with argument -// "dir/a". The info argument is the os.FileInfo for the named path. -// -// If there was a problem walking to the file or directory named by path, the -// incoming error will describe the problem and the function can decide how -// to handle that error (and Walk will not descend into that directory). If -// an error is returned, processing stops. The sole exception is that if path -// is a directory and the function returns the special value SkipDir, the -// contents of the directory are skipped and processing continues as usual on -// the next file. -type WalkFunc func(path string, info os.FileInfo, err error) error - -var lstat = os.Lstat // for testing - -// walk recursively descends path, calling w. -func walk(path string, info os.FileInfo, walkFn WalkFunc) error { - err := walkFn(path, info, nil) - if err != nil { - if info.IsDir() && err == SkipDir { - return nil - } - return err - } - - if !info.IsDir() { - return nil - } - - names, err := readDirNames(path) - if err != nil { - return walkFn(path, info, err) - } - - for _, name := range names { - filename := Join(path, name) - fileInfo, err := lstat(filename) - if err != nil { - if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir { - return err - } - } else { - err = walk(filename, fileInfo, walkFn) - if err != nil { - if !fileInfo.IsDir() || err != SkipDir { - return err - } - } - } - } - return nil -} - -// Walk walks the file tree rooted at root, calling walkFn for each file or -// directory in the tree, including root. All errors that arise visiting files -// and directories are filtered by walkFn. The files are walked in lexical -// order, which makes the output deterministic but means that for very -// large directories Walk can be inefficient. -// Walk does not follow symbolic links. -func Walk(root string, walkFn WalkFunc) error { - info, err := os.Lstat(root) - if err != nil { - return walkFn(root, nil, err) - } - return walk(root, info, walkFn) -} - -// readDirNames reads the directory named by dirname and returns -// a sorted list of directory entries. -func readDirNames(dirname string) ([]string, error) { - f, err := os.Open(dirname) - if err != nil { - return nil, err - } - names, err := f.Readdirnames(-1) - f.Close() - if err != nil { - return nil, err - } - sort.Strings(names) - return names, nil -} - -// Base returns the last element of path. -// Trailing path separators are removed before extracting the last element. -// If the path is empty, Base returns ".". -// If the path consists entirely of separators, Base returns a single separator. -func Base(path string) string { - if path == "" { - return "." - } - // Strip trailing slashes. - for len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) { - path = path[0 : len(path)-1] - } - // Throw away volume name - path = path[len(VolumeName(path)):] - // Find the last element - i := len(path) - 1 - for i >= 0 && !os.IsPathSeparator(path[i]) { - i-- - } - if i >= 0 { - path = path[i+1:] - } - // If empty now, it had only slashes. - if path == "" { - return string(Separator) - } - return path -} - -// Dir returns all but the last element of path, typically the path's directory. -// After dropping the final element, the path is Cleaned and trailing -// slashes are removed. -// If the path is empty, Dir returns ".". -// If the path consists entirely of separators, Dir returns a single separator. -// The returned path does not end in a separator unless it is the root directory. -func Dir(path string) string { - vol := VolumeName(path) - i := len(path) - 1 - for i >= len(vol) && !os.IsPathSeparator(path[i]) { - i-- - } - dir := Clean(path[len(vol) : i+1]) - last := len(dir) - 1 - if last > 0 && os.IsPathSeparator(dir[last]) { - dir = dir[:last] - } - if dir == "" { - dir = "." - } - return vol + dir -} - -// VolumeName returns leading volume name. -// Given "C:\foo\bar" it returns "C:" under windows. -// Given "\\host\share\foo" it returns "\\host\share". -// On other platforms it returns "". -func VolumeName(path string) (v string) { - return path[:volumeNameLen(path)] -} diff --git a/src/pkg/path/filepath/path_plan9.go b/src/pkg/path/filepath/path_plan9.go deleted file mode 100644 index 12e85aae0..000000000 --- a/src/pkg/path/filepath/path_plan9.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package filepath - -import "strings" - -// IsAbs returns true if the path is absolute. -func IsAbs(path string) bool { - return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#") -} - -// volumeNameLen returns length of the leading volume name on Windows. -// It returns 0 elsewhere. -func volumeNameLen(path string) int { - return 0 -} - -// HasPrefix exists for historical compatibility and should not be used. -func HasPrefix(p, prefix string) bool { - return strings.HasPrefix(p, prefix) -} - -func splitList(path string) []string { - if path == "" { - return []string{} - } - return strings.Split(path, string(ListSeparator)) -} diff --git a/src/pkg/path/filepath/path_test.go b/src/pkg/path/filepath/path_test.go deleted file mode 100644 index 819bd217c..000000000 --- a/src/pkg/path/filepath/path_test.go +++ /dev/null @@ -1,1017 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package filepath_test - -import ( - "errors" - "io/ioutil" - "os" - "path/filepath" - "reflect" - "runtime" - "strings" - "testing" -) - -type PathTest struct { - path, result string -} - -var cleantests = []PathTest{ - // Already clean - {"abc", "abc"}, - {"abc/def", "abc/def"}, - {"a/b/c", "a/b/c"}, - {".", "."}, - {"..", ".."}, - {"../..", "../.."}, - {"../../abc", "../../abc"}, - {"/abc", "/abc"}, - {"/", "/"}, - - // Empty is current dir - {"", "."}, - - // Remove trailing slash - {"abc/", "abc"}, - {"abc/def/", "abc/def"}, - {"a/b/c/", "a/b/c"}, - {"./", "."}, - {"../", ".."}, - {"../../", "../.."}, - {"/abc/", "/abc"}, - - // Remove doubled slash - {"abc//def//ghi", "abc/def/ghi"}, - {"//abc", "/abc"}, - {"///abc", "/abc"}, - {"//abc//", "/abc"}, - {"abc//", "abc"}, - - // Remove . elements - {"abc/./def", "abc/def"}, - {"/./abc/def", "/abc/def"}, - {"abc/.", "abc"}, - - // Remove .. elements - {"abc/def/ghi/../jkl", "abc/def/jkl"}, - {"abc/def/../ghi/../jkl", "abc/jkl"}, - {"abc/def/..", "abc"}, - {"abc/def/../..", "."}, - {"/abc/def/../..", "/"}, - {"abc/def/../../..", ".."}, - {"/abc/def/../../..", "/"}, - {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"}, - {"/../abc", "/abc"}, - - // Combinations - {"abc/./../def", "def"}, - {"abc//./../def", "def"}, - {"abc/../../././../def", "../../def"}, -} - -var wincleantests = []PathTest{ - {`c:`, `c:.`}, - {`c:\`, `c:\`}, - {`c:\abc`, `c:\abc`}, - {`c:abc\..\..\.\.\..\def`, `c:..\..\def`}, - {`c:\abc\def\..\..`, `c:\`}, - {`c:\..\abc`, `c:\abc`}, - {`c:..\abc`, `c:..\abc`}, - {`\`, `\`}, - {`/`, `\`}, - {`\\i\..\c$`, `\c$`}, - {`\\i\..\i\c$`, `\i\c$`}, - {`\\i\..\I\c$`, `\I\c$`}, - {`\\host\share\foo\..\bar`, `\\host\share\bar`}, - {`//host/share/foo/../baz`, `\\host\share\baz`}, - {`\\a\b\..\c`, `\\a\b\c`}, - {`\\a\b`, `\\a\b`}, -} - -func TestClean(t *testing.T) { - tests := cleantests - if runtime.GOOS == "windows" { - for i := range tests { - tests[i].result = filepath.FromSlash(tests[i].result) - } - tests = append(tests, wincleantests...) - } - for _, test := range tests { - if s := filepath.Clean(test.path); s != test.result { - t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result) - } - if s := filepath.Clean(test.result); s != test.result { - t.Errorf("Clean(%q) = %q, want %q", test.result, s, test.result) - } - } - - if testing.Short() { - t.Skip("skipping malloc count in short mode") - } - if runtime.GOMAXPROCS(0) > 1 { - t.Log("skipping AllocsPerRun checks; GOMAXPROCS>1") - return - } - - for _, test := range tests { - allocs := testing.AllocsPerRun(100, func() { filepath.Clean(test.result) }) - if allocs > 0 { - t.Errorf("Clean(%q): %v allocs, want zero", test.result, allocs) - } - } -} - -const sep = filepath.Separator - -var slashtests = []PathTest{ - {"", ""}, - {"/", string(sep)}, - {"/a/b", string([]byte{sep, 'a', sep, 'b'})}, - {"a//b", string([]byte{'a', sep, sep, 'b'})}, -} - -func TestFromAndToSlash(t *testing.T) { - for _, test := range slashtests { - if s := filepath.FromSlash(test.path); s != test.result { - t.Errorf("FromSlash(%q) = %q, want %q", test.path, s, test.result) - } - if s := filepath.ToSlash(test.result); s != test.path { - t.Errorf("ToSlash(%q) = %q, want %q", test.result, s, test.path) - } - } -} - -type SplitListTest struct { - list string - result []string -} - -const lsep = filepath.ListSeparator - -var splitlisttests = []SplitListTest{ - {"", []string{}}, - {string([]byte{'a', lsep, 'b'}), []string{"a", "b"}}, - {string([]byte{lsep, 'a', lsep, 'b'}), []string{"", "a", "b"}}, -} - -var winsplitlisttests = []SplitListTest{ - // quoted - {`"a"`, []string{`a`}}, - - // semicolon - {`";"`, []string{`;`}}, - {`"a;b"`, []string{`a;b`}}, - {`";";`, []string{`;`, ``}}, - {`;";"`, []string{``, `;`}}, - - // partially quoted - {`a";"b`, []string{`a;b`}}, - {`a; ""b`, []string{`a`, ` b`}}, - {`"a;b`, []string{`a;b`}}, - {`""a;b`, []string{`a`, `b`}}, - {`"""a;b`, []string{`a;b`}}, - {`""""a;b`, []string{`a`, `b`}}, - {`a";b`, []string{`a;b`}}, - {`a;b";c`, []string{`a`, `b;c`}}, - {`"a";b";c`, []string{`a`, `b;c`}}, -} - -func TestSplitList(t *testing.T) { - tests := splitlisttests - if runtime.GOOS == "windows" { - tests = append(tests, winsplitlisttests...) - } - for _, test := range tests { - if l := filepath.SplitList(test.list); !reflect.DeepEqual(l, test.result) { - t.Errorf("SplitList(%#q) = %#q, want %#q", test.list, l, test.result) - } - } -} - -type SplitTest struct { - path, dir, file string -} - -var unixsplittests = []SplitTest{ - {"a/b", "a/", "b"}, - {"a/b/", "a/b/", ""}, - {"a/", "a/", ""}, - {"a", "", "a"}, - {"/", "/", ""}, -} - -var winsplittests = []SplitTest{ - {`c:`, `c:`, ``}, - {`c:/`, `c:/`, ``}, - {`c:/foo`, `c:/`, `foo`}, - {`c:/foo/bar`, `c:/foo/`, `bar`}, - {`//host/share`, `//host/share`, ``}, - {`//host/share/`, `//host/share/`, ``}, - {`//host/share/foo`, `//host/share/`, `foo`}, - {`\\host\share`, `\\host\share`, ``}, - {`\\host\share\`, `\\host\share\`, ``}, - {`\\host\share\foo`, `\\host\share\`, `foo`}, -} - -func TestSplit(t *testing.T) { - var splittests []SplitTest - splittests = unixsplittests - if runtime.GOOS == "windows" { - splittests = append(splittests, winsplittests...) - } - for _, test := range splittests { - if d, f := filepath.Split(test.path); d != test.dir || f != test.file { - t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file) - } - } -} - -type JoinTest struct { - elem []string - path string -} - -var jointests = []JoinTest{ - // zero parameters - {[]string{}, ""}, - - // one parameter - {[]string{""}, ""}, - {[]string{"a"}, "a"}, - - // two parameters - {[]string{"a", "b"}, "a/b"}, - {[]string{"a", ""}, "a"}, - {[]string{"", "b"}, "b"}, - {[]string{"/", "a"}, "/a"}, - {[]string{"/", ""}, "/"}, - {[]string{"a/", "b"}, "a/b"}, - {[]string{"a/", ""}, "a"}, - {[]string{"", ""}, ""}, -} - -var winjointests = []JoinTest{ - {[]string{`directory`, `file`}, `directory\file`}, - {[]string{`C:\Windows\`, `System32`}, `C:\Windows\System32`}, - {[]string{`C:\Windows\`, ``}, `C:\Windows`}, - {[]string{`C:\`, `Windows`}, `C:\Windows`}, - {[]string{`C:`, `Windows`}, `C:\Windows`}, - {[]string{`\\host\share`, `foo`}, `\\host\share\foo`}, - {[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`}, -} - -// join takes a []string and passes it to Join. -func join(elem []string, args ...string) string { - args = elem - return filepath.Join(args...) -} - -func TestJoin(t *testing.T) { - if runtime.GOOS == "windows" { - jointests = append(jointests, winjointests...) - } - for _, test := range jointests { - if p := join(test.elem); p != filepath.FromSlash(test.path) { - t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path) - } - } -} - -type ExtTest struct { - path, ext string -} - -var exttests = []ExtTest{ - {"path.go", ".go"}, - {"path.pb.go", ".go"}, - {"a.dir/b", ""}, - {"a.dir/b.go", ".go"}, - {"a.dir/", ""}, -} - -func TestExt(t *testing.T) { - for _, test := range exttests { - if x := filepath.Ext(test.path); x != test.ext { - t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext) - } - } -} - -type Node struct { - name string - entries []*Node // nil if the entry is a file - mark int -} - -var tree = &Node{ - "testdata", - []*Node{ - {"a", nil, 0}, - {"b", []*Node{}, 0}, - {"c", nil, 0}, - { - "d", - []*Node{ - {"x", nil, 0}, - {"y", []*Node{}, 0}, - { - "z", - []*Node{ - {"u", nil, 0}, - {"v", nil, 0}, - }, - 0, - }, - }, - 0, - }, - }, - 0, -} - -func walkTree(n *Node, path string, f func(path string, n *Node)) { - f(path, n) - for _, e := range n.entries { - walkTree(e, filepath.Join(path, e.name), f) - } -} - -func makeTree(t *testing.T) { - walkTree(tree, tree.name, func(path string, n *Node) { - if n.entries == nil { - fd, err := os.Create(path) - if err != nil { - t.Errorf("makeTree: %v", err) - return - } - fd.Close() - } else { - os.Mkdir(path, 0770) - } - }) -} - -func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) } - -func checkMarks(t *testing.T, report bool) { - walkTree(tree, tree.name, func(path string, n *Node) { - if n.mark != 1 && report { - t.Errorf("node %s mark = %d; expected 1", path, n.mark) - } - n.mark = 0 - }) -} - -// Assumes that each node name is unique. Good enough for a test. -// If clear is true, any incoming error is cleared before return. The errors -// are always accumulated, though. -func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) error { - if err != nil { - *errors = append(*errors, err) - if clear { - return nil - } - return err - } - name := info.Name() - walkTree(tree, tree.name, func(path string, n *Node) { - if n.name == name { - n.mark++ - } - }) - return nil -} - -func TestWalk(t *testing.T) { - makeTree(t) - errors := make([]error, 0, 10) - clear := true - markFn := func(path string, info os.FileInfo, err error) error { - return mark(path, info, err, &errors, clear) - } - // Expect no errors. - err := filepath.Walk(tree.name, markFn) - if err != nil { - t.Fatalf("no error expected, found: %s", err) - } - if len(errors) != 0 { - t.Fatalf("unexpected errors: %s", errors) - } - checkMarks(t, true) - errors = errors[0:0] - - // Test permission errors. Only possible if we're not root - // and only on some file systems (AFS, FAT). To avoid errors during - // all.bash on those file systems, skip during go test -short. - if os.Getuid() > 0 && !testing.Short() { - // introduce 2 errors: chmod top-level directories to 0 - os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0) - os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0) - - // 3) capture errors, expect two. - // mark respective subtrees manually - markTree(tree.entries[1]) - markTree(tree.entries[3]) - // correct double-marking of directory itself - tree.entries[1].mark-- - tree.entries[3].mark-- - err := filepath.Walk(tree.name, markFn) - if err != nil { - t.Fatalf("expected no error return from Walk, got %s", err) - } - if len(errors) != 2 { - t.Errorf("expected 2 errors, got %d: %s", len(errors), errors) - } - // the inaccessible subtrees were marked manually - checkMarks(t, true) - errors = errors[0:0] - - // 4) capture errors, stop after first error. - // mark respective subtrees manually - markTree(tree.entries[1]) - markTree(tree.entries[3]) - // correct double-marking of directory itself - tree.entries[1].mark-- - tree.entries[3].mark-- - clear = false // error will stop processing - err = filepath.Walk(tree.name, markFn) - if err == nil { - t.Fatalf("expected error return from Walk") - } - if len(errors) != 1 { - t.Errorf("expected 1 error, got %d: %s", len(errors), errors) - } - // the inaccessible subtrees were marked manually - checkMarks(t, false) - errors = errors[0:0] - - // restore permissions - os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770) - os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770) - } - - // cleanup - if err := os.RemoveAll(tree.name); err != nil { - t.Errorf("removeTree: %v", err) - } -} - -func touch(t *testing.T, name string) { - f, err := os.Create(name) - if err != nil { - t.Fatal(err) - } - if err := f.Close(); err != nil { - t.Fatal(err) - } -} - -func TestWalkFileError(t *testing.T) { - td, err := ioutil.TempDir("", "walktest") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(td) - - touch(t, filepath.Join(td, "foo")) - touch(t, filepath.Join(td, "bar")) - dir := filepath.Join(td, "dir") - if err := os.MkdirAll(filepath.Join(td, "dir"), 0755); err != nil { - t.Fatal(err) - } - touch(t, filepath.Join(dir, "baz")) - touch(t, filepath.Join(dir, "stat-error")) - defer func() { - *filepath.LstatP = os.Lstat - }() - statErr := errors.New("some stat error") - *filepath.LstatP = func(path string) (os.FileInfo, error) { - if strings.HasSuffix(path, "stat-error") { - return nil, statErr - } - return os.Lstat(path) - } - got := map[string]error{} - err = filepath.Walk(td, func(path string, fi os.FileInfo, err error) error { - rel, _ := filepath.Rel(td, path) - got[filepath.ToSlash(rel)] = err - return nil - }) - if err != nil { - t.Errorf("Walk error: %v", err) - } - want := map[string]error{ - ".": nil, - "foo": nil, - "bar": nil, - "dir": nil, - "dir/baz": nil, - "dir/stat-error": statErr, - } - if !reflect.DeepEqual(got, want) { - t.Errorf("Walked %#v; want %#v", got, want) - } -} - -var basetests = []PathTest{ - {"", "."}, - {".", "."}, - {"/.", "."}, - {"/", "/"}, - {"////", "/"}, - {"x/", "x"}, - {"abc", "abc"}, - {"abc/def", "def"}, - {"a/b/.x", ".x"}, - {"a/b/c.", "c."}, - {"a/b/c.x", "c.x"}, -} - -var winbasetests = []PathTest{ - {`c:\`, `\`}, - {`c:.`, `.`}, - {`c:\a\b`, `b`}, - {`c:a\b`, `b`}, - {`c:a\b\c`, `c`}, - {`\\host\share\`, `\`}, - {`\\host\share\a`, `a`}, - {`\\host\share\a\b`, `b`}, -} - -func TestBase(t *testing.T) { - tests := basetests - if runtime.GOOS == "windows" { - // make unix tests work on windows - for i := range tests { - tests[i].result = filepath.Clean(tests[i].result) - } - // add windows specific tests - tests = append(tests, winbasetests...) - } - for _, test := range tests { - if s := filepath.Base(test.path); s != test.result { - t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result) - } - } -} - -var dirtests = []PathTest{ - {"", "."}, - {".", "."}, - {"/.", "/"}, - {"/", "/"}, - {"////", "/"}, - {"/foo", "/"}, - {"x/", "x"}, - {"abc", "."}, - {"abc/def", "abc"}, - {"a/b/.x", "a/b"}, - {"a/b/c.", "a/b"}, - {"a/b/c.x", "a/b"}, -} - -var windirtests = []PathTest{ - {`c:\`, `c:\`}, - {`c:.`, `c:.`}, - {`c:\a\b`, `c:\a`}, - {`c:a\b`, `c:a`}, - {`c:a\b\c`, `c:a\b`}, - {`\\host\share\`, `\\host\share\`}, - {`\\host\share\a`, `\\host\share\`}, - {`\\host\share\a\b`, `\\host\share\a`}, -} - -func TestDir(t *testing.T) { - tests := dirtests - if runtime.GOOS == "windows" { - // make unix tests work on windows - for i := range tests { - tests[i].result = filepath.Clean(tests[i].result) - } - // add windows specific tests - tests = append(tests, windirtests...) - } - for _, test := range tests { - if s := filepath.Dir(test.path); s != test.result { - t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result) - } - } -} - -type IsAbsTest struct { - path string - isAbs bool -} - -var isabstests = []IsAbsTest{ - {"", false}, - {"/", true}, - {"/usr/bin/gcc", true}, - {"..", false}, - {"/a/../bb", true}, - {".", false}, - {"./", false}, - {"lala", false}, -} - -var winisabstests = []IsAbsTest{ - {`C:\`, true}, - {`c\`, false}, - {`c::`, false}, - {`c:`, false}, - {`/`, false}, - {`\`, false}, - {`\Windows`, false}, - {`c:a\b`, false}, - {`\\host\share\foo`, true}, - {`//host/share/foo/bar`, true}, -} - -func TestIsAbs(t *testing.T) { - var tests []IsAbsTest - if runtime.GOOS == "windows" { - tests = append(tests, winisabstests...) - // All non-windows tests should fail, because they have no volume letter. - for _, test := range isabstests { - tests = append(tests, IsAbsTest{test.path, false}) - } - // All non-windows test should work as intended if prefixed with volume letter. - for _, test := range isabstests { - tests = append(tests, IsAbsTest{"c:" + test.path, test.isAbs}) - } - } else { - tests = isabstests - } - - for _, test := range tests { - if r := filepath.IsAbs(test.path); r != test.isAbs { - t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs) - } - } -} - -type EvalSymlinksTest struct { - // If dest is empty, the path is created; otherwise the dest is symlinked to the path. - path, dest string -} - -var EvalSymlinksTestDirs = []EvalSymlinksTest{ - {"test", ""}, - {"test/dir", ""}, - {"test/dir/link3", "../../"}, - {"test/link1", "../test"}, - {"test/link2", "dir"}, - {"test/linkabs", "/"}, -} - -var EvalSymlinksTests = []EvalSymlinksTest{ - {"test", "test"}, - {"test/dir", "test/dir"}, - {"test/dir/../..", "."}, - {"test/link1", "test"}, - {"test/link2", "test/dir"}, - {"test/link1/dir", "test/dir"}, - {"test/link2/..", "test"}, - {"test/dir/link3", "."}, - {"test/link2/link3/test", "test"}, - {"test/linkabs", "/"}, -} - -var EvalSymlinksAbsWindowsTests = []EvalSymlinksTest{ - {`c:\`, `c:\`}, -} - -// simpleJoin builds a file name from the directory and path. -// It does not use Join because we don't want ".." to be evaluated. -func simpleJoin(dir, path string) string { - return dir + string(filepath.Separator) + path -} - -func TestEvalSymlinks(t *testing.T) { - switch runtime.GOOS { - case "nacl", "plan9": - t.Skipf("skipping on %s", runtime.GOOS) - } - - tmpDir, err := ioutil.TempDir("", "evalsymlink") - if err != nil { - t.Fatal("creating temp dir:", err) - } - defer os.RemoveAll(tmpDir) - - // /tmp may itself be a symlink! Avoid the confusion, although - // it means trusting the thing we're testing. - tmpDir, err = filepath.EvalSymlinks(tmpDir) - if err != nil { - t.Fatal("eval symlink for tmp dir:", err) - } - - // Create the symlink farm using relative paths. - for _, d := range EvalSymlinksTestDirs { - var err error - path := simpleJoin(tmpDir, d.path) - if d.dest == "" { - err = os.Mkdir(path, 0755) - } else { - if runtime.GOOS != "windows" { - err = os.Symlink(d.dest, path) - } - } - if err != nil { - t.Fatal(err) - } - } - - var tests []EvalSymlinksTest - if runtime.GOOS == "windows" { - for _, d := range EvalSymlinksTests { - if d.path == d.dest { - // will test only real files and directories - tests = append(tests, d) - // test "canonical" names - d2 := EvalSymlinksTest{ - path: strings.ToUpper(d.path), - dest: d.dest, - } - tests = append(tests, d2) - } - } - } else { - tests = EvalSymlinksTests - } - - // Evaluate the symlink farm. - for _, d := range tests { - path := simpleJoin(tmpDir, d.path) - dest := simpleJoin(tmpDir, d.dest) - if filepath.IsAbs(d.dest) { - dest = d.dest - } - if p, err := filepath.EvalSymlinks(path); err != nil { - t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) - } else if filepath.Clean(p) != filepath.Clean(dest) { - t.Errorf("Clean(%q)=%q, want %q", path, p, dest) - } - } -} - -// Test directories relative to temporary directory. -// The tests are run in absTestDirs[0]. -var absTestDirs = []string{ - "a", - "a/b", - "a/b/c", -} - -// Test paths relative to temporary directory. $ expands to the directory. -// The tests are run in absTestDirs[0]. -// We create absTestDirs first. -var absTests = []string{ - ".", - "b", - "../a", - "../a/b", - "../a/b/./c/../../.././a", - "$", - "$/.", - "$/a/../a/b", - "$/a/b/c/../../.././a", -} - -func TestAbs(t *testing.T) { - oldwd, err := os.Getwd() - if err != nil { - t.Fatal("Getwd failed: ", err) - } - defer os.Chdir(oldwd) - - root, err := ioutil.TempDir("", "TestAbs") - if err != nil { - t.Fatal("TempDir failed: ", err) - } - defer os.RemoveAll(root) - - wd, err := os.Getwd() - if err != nil { - t.Fatal("getwd failed: ", err) - } - err = os.Chdir(root) - if err != nil { - t.Fatal("chdir failed: ", err) - } - defer os.Chdir(wd) - - for _, dir := range absTestDirs { - err = os.Mkdir(dir, 0777) - if err != nil { - t.Fatal("Mkdir failed: ", err) - } - } - - err = os.Chdir(absTestDirs[0]) - if err != nil { - t.Fatal("chdir failed: ", err) - } - - for _, path := range absTests { - path = strings.Replace(path, "$", root, -1) - info, err := os.Stat(path) - if err != nil { - t.Errorf("%s: %s", path, err) - continue - } - - abspath, err := filepath.Abs(path) - if err != nil { - t.Errorf("Abs(%q) error: %v", path, err) - continue - } - absinfo, err := os.Stat(abspath) - if err != nil || !os.SameFile(absinfo, info) { - t.Errorf("Abs(%q)=%q, not the same file", path, abspath) - } - if !filepath.IsAbs(abspath) { - t.Errorf("Abs(%q)=%q, not an absolute path", path, abspath) - } - if filepath.IsAbs(path) && abspath != filepath.Clean(path) { - t.Errorf("Abs(%q)=%q, isn't clean", path, abspath) - } - } -} - -type RelTests struct { - root, path, want string -} - -var reltests = []RelTests{ - {"a/b", "a/b", "."}, - {"a/b/.", "a/b", "."}, - {"a/b", "a/b/.", "."}, - {"./a/b", "a/b", "."}, - {"a/b", "./a/b", "."}, - {"ab/cd", "ab/cde", "../cde"}, - {"ab/cd", "ab/c", "../c"}, - {"a/b", "a/b/c/d", "c/d"}, - {"a/b", "a/b/../c", "../c"}, - {"a/b/../c", "a/b", "../b"}, - {"a/b/c", "a/c/d", "../../c/d"}, - {"a/b", "c/d", "../../c/d"}, - {"a/b/c/d", "a/b", "../.."}, - {"a/b/c/d", "a/b/", "../.."}, - {"a/b/c/d/", "a/b", "../.."}, - {"a/b/c/d/", "a/b/", "../.."}, - {"../../a/b", "../../a/b/c/d", "c/d"}, - {"/a/b", "/a/b", "."}, - {"/a/b/.", "/a/b", "."}, - {"/a/b", "/a/b/.", "."}, - {"/ab/cd", "/ab/cde", "../cde"}, - {"/ab/cd", "/ab/c", "../c"}, - {"/a/b", "/a/b/c/d", "c/d"}, - {"/a/b", "/a/b/../c", "../c"}, - {"/a/b/../c", "/a/b", "../b"}, - {"/a/b/c", "/a/c/d", "../../c/d"}, - {"/a/b", "/c/d", "../../c/d"}, - {"/a/b/c/d", "/a/b", "../.."}, - {"/a/b/c/d", "/a/b/", "../.."}, - {"/a/b/c/d/", "/a/b", "../.."}, - {"/a/b/c/d/", "/a/b/", "../.."}, - {"/../../a/b", "/../../a/b/c/d", "c/d"}, - {".", "a/b", "a/b"}, - {".", "..", ".."}, - - // can't do purely lexically - {"..", ".", "err"}, - {"..", "a", "err"}, - {"../..", "..", "err"}, - {"a", "/a", "err"}, - {"/a", "a", "err"}, -} - -var winreltests = []RelTests{ - {`C:a\b\c`, `C:a/b/d`, `..\d`}, - {`C:\`, `D:\`, `err`}, - {`C:`, `D:`, `err`}, -} - -func TestRel(t *testing.T) { - tests := append([]RelTests{}, reltests...) - if runtime.GOOS == "windows" { - for i := range tests { - tests[i].want = filepath.FromSlash(tests[i].want) - } - tests = append(tests, winreltests...) - } - for _, test := range tests { - got, err := filepath.Rel(test.root, test.path) - if test.want == "err" { - if err == nil { - t.Errorf("Rel(%q, %q)=%q, want error", test.root, test.path, got) - } - continue - } - if err != nil { - t.Errorf("Rel(%q, %q): want %q, got error: %s", test.root, test.path, test.want, err) - } - if got != test.want { - t.Errorf("Rel(%q, %q)=%q, want %q", test.root, test.path, got, test.want) - } - } -} - -type VolumeNameTest struct { - path string - vol string -} - -var volumenametests = []VolumeNameTest{ - {`c:/foo/bar`, `c:`}, - {`c:`, `c:`}, - {`2:`, ``}, - {``, ``}, - {`\\\host`, ``}, - {`\\\host\`, ``}, - {`\\\host\share`, ``}, - {`\\\host\\share`, ``}, - {`\\host`, ``}, - {`//host`, ``}, - {`\\host\`, ``}, - {`//host/`, ``}, - {`\\host\share`, `\\host\share`}, - {`//host/share`, `//host/share`}, - {`\\host\share\`, `\\host\share`}, - {`//host/share/`, `//host/share`}, - {`\\host\share\foo`, `\\host\share`}, - {`//host/share/foo`, `//host/share`}, - {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`}, - {`//host/share//foo///bar////baz`, `//host/share`}, - {`\\host\share\foo\..\bar`, `\\host\share`}, - {`//host/share/foo/../bar`, `//host/share`}, -} - -func TestVolumeName(t *testing.T) { - if runtime.GOOS != "windows" { - return - } - for _, v := range volumenametests { - if vol := filepath.VolumeName(v.path); vol != v.vol { - t.Errorf("VolumeName(%q)=%q, want %q", v.path, vol, v.vol) - } - } -} - -func TestDriveLetterInEvalSymlinks(t *testing.T) { - if runtime.GOOS != "windows" { - return - } - wd, _ := os.Getwd() - if len(wd) < 3 { - t.Errorf("Current directory path %q is too short", wd) - } - lp := strings.ToLower(wd) - up := strings.ToUpper(wd) - flp, err := filepath.EvalSymlinks(lp) - if err != nil { - t.Fatalf("EvalSymlinks(%q) failed: %q", lp, err) - } - fup, err := filepath.EvalSymlinks(up) - if err != nil { - t.Fatalf("EvalSymlinks(%q) failed: %q", up, err) - } - if flp != fup { - t.Errorf("Results of EvalSymlinks do not match: %q and %q", flp, fup) - } -} - -func TestBug3486(t *testing.T) { // http://code.google.com/p/go/issues/detail?id=3486 - root, err := filepath.EvalSymlinks(runtime.GOROOT() + "/test") - if err != nil { - t.Fatal(err) - } - bugs := filepath.Join(root, "bugs") - ken := filepath.Join(root, "ken") - seenBugs := false - seenKen := false - filepath.Walk(root, func(pth string, info os.FileInfo, err error) error { - if err != nil { - t.Fatal(err) - } - - switch pth { - case bugs: - seenBugs = true - return filepath.SkipDir - case ken: - if !seenBugs { - t.Fatal("filepath.Walk out of order - ken before bugs") - } - seenKen = true - } - return nil - }) - if !seenKen { - t.Fatalf("%q not seen", ken) - } -} diff --git a/src/pkg/path/filepath/path_unix.go b/src/pkg/path/filepath/path_unix.go deleted file mode 100644 index 7aba0ab5b..000000000 --- a/src/pkg/path/filepath/path_unix.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris - -package filepath - -import "strings" - -// IsAbs returns true if the path is absolute. -func IsAbs(path string) bool { - return strings.HasPrefix(path, "/") -} - -// volumeNameLen returns length of the leading volume name on Windows. -// It returns 0 elsewhere. -func volumeNameLen(path string) int { - return 0 -} - -// HasPrefix exists for historical compatibility and should not be used. -func HasPrefix(p, prefix string) bool { - return strings.HasPrefix(p, prefix) -} - -func splitList(path string) []string { - if path == "" { - return []string{} - } - return strings.Split(path, string(ListSeparator)) -} diff --git a/src/pkg/path/filepath/path_windows.go b/src/pkg/path/filepath/path_windows.go deleted file mode 100644 index e99997257..000000000 --- a/src/pkg/path/filepath/path_windows.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package filepath - -import ( - "strings" -) - -func isSlash(c uint8) bool { - return c == '\\' || c == '/' -} - -// IsAbs returns true if the path is absolute. -func IsAbs(path string) (b bool) { - l := volumeNameLen(path) - if l == 0 { - return false - } - path = path[l:] - if path == "" { - return false - } - return isSlash(path[0]) -} - -// volumeNameLen returns length of the leading volume name on Windows. -// It returns 0 elsewhere. -func volumeNameLen(path string) int { - if len(path) < 2 { - return 0 - } - // with drive letter - c := path[0] - if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { - return 2 - } - // is it UNC - if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) && - !isSlash(path[2]) && path[2] != '.' { - // first, leading `\\` and next shouldn't be `\`. its server name. - for n := 3; n < l-1; n++ { - // second, next '\' shouldn't be repeated. - if isSlash(path[n]) { - n++ - // third, following something characters. its share name. - if !isSlash(path[n]) { - if path[n] == '.' { - break - } - for ; n < l; n++ { - if isSlash(path[n]) { - break - } - } - return n - } - break - } - } - } - return 0 -} - -// HasPrefix exists for historical compatibility and should not be used. -func HasPrefix(p, prefix string) bool { - if strings.HasPrefix(p, prefix) { - return true - } - return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix)) -} - -func splitList(path string) []string { - // The same implementation is used in LookPath in os/exec; - // consider changing os/exec when changing this. - - if path == "" { - return []string{} - } - - // Split path, respecting but preserving quotes. - list := []string{} - start := 0 - quo := false - for i := 0; i < len(path); i++ { - switch c := path[i]; { - case c == '"': - quo = !quo - case c == ListSeparator && !quo: - list = append(list, path[start:i]) - start = i + 1 - } - } - list = append(list, path[start:]) - - // Remove quotes. - for i, s := range list { - if strings.Contains(s, `"`) { - list[i] = strings.Replace(s, `"`, ``, -1) - } - } - - return list -} diff --git a/src/pkg/path/filepath/path_windows_test.go b/src/pkg/path/filepath/path_windows_test.go deleted file mode 100644 index 8a9be8e89..000000000 --- a/src/pkg/path/filepath/path_windows_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package filepath_test - -import ( - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "reflect" - "testing" -) - -func TestWinSplitListTestsAreValid(t *testing.T) { - comspec := os.Getenv("ComSpec") - if comspec == "" { - t.Fatal("%ComSpec% must be set") - } - - for ti, tt := range winsplitlisttests { - testWinSplitListTestIsValid(t, ti, tt, comspec) - } -} - -func testWinSplitListTestIsValid(t *testing.T, ti int, tt SplitListTest, - comspec string) { - - const ( - cmdfile = `printdir.cmd` - perm os.FileMode = 0700 - ) - - tmp, err := ioutil.TempDir("", "testWinSplitListTestIsValid") - if err != nil { - t.Fatalf("TempDir failed: %v", err) - } - defer os.RemoveAll(tmp) - - for i, d := range tt.result { - if d == "" { - continue - } - if cd := filepath.Clean(d); filepath.VolumeName(cd) != "" || - cd[0] == '\\' || cd == ".." || (len(cd) >= 3 && cd[0:3] == `..\`) { - t.Errorf("%d,%d: %#q refers outside working directory", ti, i, d) - return - } - dd := filepath.Join(tmp, d) - if _, err := os.Stat(dd); err == nil { - t.Errorf("%d,%d: %#q already exists", ti, i, d) - return - } - if err = os.MkdirAll(dd, perm); err != nil { - t.Errorf("%d,%d: MkdirAll(%#q) failed: %v", ti, i, dd, err) - return - } - fn, data := filepath.Join(dd, cmdfile), []byte("@echo "+d+"\r\n") - if err = ioutil.WriteFile(fn, data, perm); err != nil { - t.Errorf("%d,%d: WriteFile(%#q) failed: %v", ti, i, fn, err) - return - } - } - - for i, d := range tt.result { - if d == "" { - continue - } - exp := []byte(d + "\r\n") - cmd := &exec.Cmd{ - Path: comspec, - Args: []string{`/c`, cmdfile}, - Env: []string{`Path=` + tt.list}, - Dir: tmp, - } - out, err := cmd.CombinedOutput() - switch { - case err != nil: - t.Errorf("%d,%d: execution error %v\n%q", ti, i, err, out) - return - case !reflect.DeepEqual(out, exp): - t.Errorf("%d,%d: expected %#q, got %#q", ti, i, exp, out) - return - default: - // unshadow cmdfile in next directory - err = os.Remove(filepath.Join(tmp, d, cmdfile)) - if err != nil { - t.Fatalf("Remove test command failed: %v", err) - } - } - } -} diff --git a/src/pkg/path/filepath/symlink.go b/src/pkg/path/filepath/symlink.go deleted file mode 100644 index 307dd0f8f..000000000 --- a/src/pkg/path/filepath/symlink.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !windows - -package filepath - -import ( - "bytes" - "errors" - "os" - "strings" -) - -func evalSymlinks(path string) (string, error) { - const maxIter = 255 - originalPath := path - // consume path by taking each frontmost path element, - // expanding it if it's a symlink, and appending it to b - var b bytes.Buffer - for n := 0; path != ""; n++ { - if n > maxIter { - return "", errors.New("EvalSymlinks: too many links in " + originalPath) - } - - // find next path component, p - i := strings.IndexRune(path, Separator) - var p string - if i == -1 { - p, path = path, "" - } else { - p, path = path[:i], path[i+1:] - } - - if p == "" { - if b.Len() == 0 { - // must be absolute path - b.WriteRune(Separator) - } - continue - } - - fi, err := os.Lstat(b.String() + p) - if err != nil { - return "", err - } - if fi.Mode()&os.ModeSymlink == 0 { - b.WriteString(p) - if path != "" { - b.WriteRune(Separator) - } - continue - } - - // it's a symlink, put it at the front of path - dest, err := os.Readlink(b.String() + p) - if err != nil { - return "", err - } - if IsAbs(dest) { - b.Reset() - } - path = dest + string(Separator) + path - } - return Clean(b.String()), nil -} diff --git a/src/pkg/path/filepath/symlink_windows.go b/src/pkg/path/filepath/symlink_windows.go deleted file mode 100644 index 9adc8a48a..000000000 --- a/src/pkg/path/filepath/symlink_windows.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package filepath - -import ( - "syscall" -) - -func toShort(path string) (string, error) { - p, err := syscall.UTF16FromString(path) - if err != nil { - return "", err - } - b := p // GetShortPathName says we can reuse buffer - n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b))) - if err != nil { - return "", err - } - if n > uint32(len(b)) { - b = make([]uint16, n) - n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b))) - if err != nil { - return "", err - } - } - return syscall.UTF16ToString(b), nil -} - -func toLong(path string) (string, error) { - p, err := syscall.UTF16FromString(path) - if err != nil { - return "", err - } - b := p // GetLongPathName says we can reuse buffer - n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b))) - if err != nil { - return "", err - } - if n > uint32(len(b)) { - b = make([]uint16, n) - n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b))) - if err != nil { - return "", err - } - } - b = b[:n] - return syscall.UTF16ToString(b), nil -} - -func evalSymlinks(path string) (string, error) { - p, err := toShort(path) - if err != nil { - return "", err - } - p, err = toLong(p) - if err != nil { - return "", err - } - // syscall.GetLongPathName does not change the case of the drive letter, - // but the result of EvalSymlinks must be unique, so we have - // EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`). - // Make drive letter upper case. - if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' { - p = string(p[0]+'A'-'a') + p[1:] - } - return Clean(p), nil -} diff --git a/src/pkg/path/match.go b/src/pkg/path/match.go deleted file mode 100644 index 8154bf602..000000000 --- a/src/pkg/path/match.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package path - -import ( - "errors" - "strings" - "unicode/utf8" -) - -// ErrBadPattern indicates a globbing pattern was malformed. -var ErrBadPattern = errors.New("syntax error in pattern") - -// Match returns true if name matches the shell file name pattern. -// The pattern syntax is: -// -// pattern: -// { term } -// term: -// '*' matches any sequence of non-/ characters -// '?' matches any single non-/ character -// '[' [ '^' ] { character-range } ']' -// character class (must be non-empty) -// c matches character c (c != '*', '?', '\\', '[') -// '\\' c matches character c -// -// character-range: -// c matches character c (c != '\\', '-', ']') -// '\\' c matches character c -// lo '-' hi matches character c for lo <= c <= hi -// -// Match requires pattern to match all of name, not just a substring. -// The only possible returned error is ErrBadPattern, when pattern -// is malformed. -// -func Match(pattern, name string) (matched bool, err error) { -Pattern: - for len(pattern) > 0 { - var star bool - var chunk string - star, chunk, pattern = scanChunk(pattern) - if star && chunk == "" { - // Trailing * matches rest of string unless it has a /. - return strings.Index(name, "/") < 0, nil - } - // Look for match at current position. - t, ok, err := matchChunk(chunk, name) - // if we're the last chunk, make sure we've exhausted the name - // otherwise we'll give a false result even if we could still match - // using the star - if ok && (len(t) == 0 || len(pattern) > 0) { - name = t - continue - } - if err != nil { - return false, err - } - if star { - // Look for match skipping i+1 bytes. - // Cannot skip /. - for i := 0; i < len(name) && name[i] != '/'; i++ { - t, ok, err := matchChunk(chunk, name[i+1:]) - if ok { - // if we're the last chunk, make sure we exhausted the name - if len(pattern) == 0 && len(t) > 0 { - continue - } - name = t - continue Pattern - } - if err != nil { - return false, err - } - } - } - return false, nil - } - return len(name) == 0, nil -} - -// scanChunk gets the next segment of pattern, which is a non-star string -// possibly preceded by a star. -func scanChunk(pattern string) (star bool, chunk, rest string) { - for len(pattern) > 0 && pattern[0] == '*' { - pattern = pattern[1:] - star = true - } - inrange := false - var i int -Scan: - for i = 0; i < len(pattern); i++ { - switch pattern[i] { - case '\\': - // error check handled in matchChunk: bad pattern. - if i+1 < len(pattern) { - i++ - } - case '[': - inrange = true - case ']': - inrange = false - case '*': - if !inrange { - break Scan - } - } - } - return star, pattern[0:i], pattern[i:] -} - -// matchChunk checks whether chunk matches the beginning of s. -// If so, it returns the remainder of s (after the match). -// Chunk is all single-character operators: literals, char classes, and ?. -func matchChunk(chunk, s string) (rest string, ok bool, err error) { - for len(chunk) > 0 { - if len(s) == 0 { - return - } - switch chunk[0] { - case '[': - // character class - r, n := utf8.DecodeRuneInString(s) - s = s[n:] - chunk = chunk[1:] - // possibly negated - notNegated := true - if len(chunk) > 0 && chunk[0] == '^' { - notNegated = false - chunk = chunk[1:] - } - // parse all ranges - match := false - nrange := 0 - for { - if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 { - chunk = chunk[1:] - break - } - var lo, hi rune - if lo, chunk, err = getEsc(chunk); err != nil { - return - } - hi = lo - if chunk[0] == '-' { - if hi, chunk, err = getEsc(chunk[1:]); err != nil { - return - } - } - if lo <= r && r <= hi { - match = true - } - nrange++ - } - if match != notNegated { - return - } - - case '?': - if s[0] == '/' { - return - } - _, n := utf8.DecodeRuneInString(s) - s = s[n:] - chunk = chunk[1:] - - case '\\': - chunk = chunk[1:] - if len(chunk) == 0 { - err = ErrBadPattern - return - } - fallthrough - - default: - if chunk[0] != s[0] { - return - } - s = s[1:] - chunk = chunk[1:] - } - } - return s, true, nil -} - -// getEsc gets a possibly-escaped character from chunk, for a character class. -func getEsc(chunk string) (r rune, nchunk string, err error) { - if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' { - err = ErrBadPattern - return - } - if chunk[0] == '\\' { - chunk = chunk[1:] - if len(chunk) == 0 { - err = ErrBadPattern - return - } - } - r, n := utf8.DecodeRuneInString(chunk) - if r == utf8.RuneError && n == 1 { - err = ErrBadPattern - } - nchunk = chunk[n:] - if len(nchunk) == 0 { - err = ErrBadPattern - } - return -} diff --git a/src/pkg/path/match_test.go b/src/pkg/path/match_test.go deleted file mode 100644 index 6b0676f81..000000000 --- a/src/pkg/path/match_test.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package path - -import "testing" - -type MatchTest struct { - pattern, s string - match bool - err error -} - -var matchTests = []MatchTest{ - {"abc", "abc", true, nil}, - {"*", "abc", true, nil}, - {"*c", "abc", true, nil}, - {"a*", "a", true, nil}, - {"a*", "abc", true, nil}, - {"a*", "ab/c", false, nil}, - {"a*/b", "abc/b", true, nil}, - {"a*/b", "a/c/b", false, nil}, - {"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil}, - {"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil}, - {"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil}, - {"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil}, - {"a*b?c*x", "abxbbxdbxebxczzx", true, nil}, - {"a*b?c*x", "abxbbxdbxebxczzy", false, nil}, - {"ab[c]", "abc", true, nil}, - {"ab[b-d]", "abc", true, nil}, - {"ab[e-g]", "abc", false, nil}, - {"ab[^c]", "abc", false, nil}, - {"ab[^b-d]", "abc", false, nil}, - {"ab[^e-g]", "abc", true, nil}, - {"a\\*b", "a*b", true, nil}, - {"a\\*b", "ab", false, nil}, - {"a?b", "a☺b", true, nil}, - {"a[^a]b", "a☺b", true, nil}, - {"a???b", "a☺b", false, nil}, - {"a[^a][^a][^a]b", "a☺b", false, nil}, - {"[a-ζ]*", "α", true, nil}, - {"*[a-ζ]", "A", false, nil}, - {"a?b", "a/b", false, nil}, - {"a*b", "a/b", false, nil}, - {"[\\]a]", "]", true, nil}, - {"[\\-]", "-", true, nil}, - {"[x\\-]", "x", true, nil}, - {"[x\\-]", "-", true, nil}, - {"[x\\-]", "z", false, nil}, - {"[\\-x]", "x", true, nil}, - {"[\\-x]", "-", true, nil}, - {"[\\-x]", "a", false, nil}, - {"[]a]", "]", false, ErrBadPattern}, - {"[-]", "-", false, ErrBadPattern}, - {"[x-]", "x", false, ErrBadPattern}, - {"[x-]", "-", false, ErrBadPattern}, - {"[x-]", "z", false, ErrBadPattern}, - {"[-x]", "x", false, ErrBadPattern}, - {"[-x]", "-", false, ErrBadPattern}, - {"[-x]", "a", false, ErrBadPattern}, - {"\\", "a", false, ErrBadPattern}, - {"[a-b-c]", "a", false, ErrBadPattern}, - {"[", "a", false, ErrBadPattern}, - {"[^", "a", false, ErrBadPattern}, - {"[^bc", "a", false, ErrBadPattern}, - {"a[", "a", false, nil}, - {"a[", "ab", false, ErrBadPattern}, - {"*x", "xxx", true, nil}, -} - -func TestMatch(t *testing.T) { - for _, tt := range matchTests { - ok, err := Match(tt.pattern, tt.s) - 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) - } - } -} diff --git a/src/pkg/path/path.go b/src/pkg/path/path.go deleted file mode 100644 index bdb85c6b9..000000000 --- a/src/pkg/path/path.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package path implements utility routines for manipulating slash-separated -// paths. -package path - -import ( - "strings" -) - -// A lazybuf is a lazily constructed path buffer. -// It supports append, reading previously appended bytes, -// and retrieving the final string. It does not allocate a buffer -// to hold the output until that output diverges from s. -type lazybuf struct { - s string - buf []byte - w int -} - -func (b *lazybuf) index(i int) byte { - if b.buf != nil { - return b.buf[i] - } - return b.s[i] -} - -func (b *lazybuf) append(c byte) { - if b.buf == nil { - if b.w < len(b.s) && b.s[b.w] == c { - b.w++ - return - } - b.buf = make([]byte, len(b.s)) - copy(b.buf, b.s[:b.w]) - } - b.buf[b.w] = c - b.w++ -} - -func (b *lazybuf) string() string { - if b.buf == nil { - return b.s[:b.w] - } - return string(b.buf[:b.w]) -} - -// Clean returns the shortest path name equivalent to path -// by purely lexical processing. It applies the following rules -// iteratively until no further processing can be done: -// -// 1. Replace multiple slashes with a single slash. -// 2. Eliminate each . path name element (the current directory). -// 3. Eliminate each inner .. path name element (the parent directory) -// along with the non-.. element that precedes it. -// 4. Eliminate .. elements that begin a rooted path: -// that is, replace "/.." by "/" at the beginning of a path. -// -// The returned path ends in a slash only if it is the root "/". -// -// If the result of this process is an empty string, Clean -// returns the string ".". -// -// See also Rob Pike, ``Lexical File Names in Plan 9 or -// Getting Dot-Dot Right,'' -// http://plan9.bell-labs.com/sys/doc/lexnames.html -func Clean(path string) string { - if path == "" { - return "." - } - - rooted := path[0] == '/' - n := len(path) - - // Invariants: - // reading from path; r is index of next byte to process. - // writing to buf; w is index of next byte to write. - // dotdot is index in buf where .. must stop, either because - // it is the leading slash or it is a leading ../../.. prefix. - out := lazybuf{s: path} - r, dotdot := 0, 0 - if rooted { - out.append('/') - r, dotdot = 1, 1 - } - - for r < n { - switch { - case path[r] == '/': - // empty path element - r++ - case path[r] == '.' && (r+1 == n || path[r+1] == '/'): - // . element - r++ - case path[r] == '.' && path[r+1] == '.' && (r+2 == n || path[r+2] == '/'): - // .. element: remove to last / - r += 2 - switch { - case out.w > dotdot: - // can backtrack - out.w-- - for out.w > dotdot && out.index(out.w) != '/' { - out.w-- - } - case !rooted: - // cannot backtrack, but not rooted, so append .. element. - if out.w > 0 { - out.append('/') - } - out.append('.') - out.append('.') - dotdot = out.w - } - default: - // real path element. - // add slash if needed - if rooted && out.w != 1 || !rooted && out.w != 0 { - out.append('/') - } - // copy element - for ; r < n && path[r] != '/'; r++ { - out.append(path[r]) - } - } - } - - // Turn empty string into "." - if out.w == 0 { - return "." - } - - return out.string() -} - -// Split splits path immediately following the final slash. -// separating it into a directory and file name component. -// If there is no slash path, Split returns an empty dir and -// file set to path. -// The returned values have the property that path = dir+file. -func Split(path string) (dir, file string) { - i := strings.LastIndex(path, "/") - return path[:i+1], path[i+1:] -} - -// Join joins any number of path elements into a single path, adding a -// separating slash if necessary. The result is Cleaned; in particular, -// all empty strings are ignored. -func Join(elem ...string) string { - for i, e := range elem { - if e != "" { - return Clean(strings.Join(elem[i:], "/")) - } - } - return "" -} - -// Ext returns the file name extension used by path. -// The extension is the suffix beginning at the final dot -// in the final slash-separated element of path; -// it is empty if there is no dot. -func Ext(path string) string { - for i := len(path) - 1; i >= 0 && path[i] != '/'; i-- { - if path[i] == '.' { - return path[i:] - } - } - return "" -} - -// Base returns the last element of path. -// Trailing slashes are removed before extracting the last element. -// If the path is empty, Base returns ".". -// If the path consists entirely of slashes, Base returns "/". -func Base(path string) string { - if path == "" { - return "." - } - // Strip trailing slashes. - for len(path) > 0 && path[len(path)-1] == '/' { - path = path[0 : len(path)-1] - } - // Find the last element - if i := strings.LastIndex(path, "/"); i >= 0 { - path = path[i+1:] - } - // If empty now, it had only slashes. - if path == "" { - return "/" - } - return path -} - -// IsAbs returns true if the path is absolute. -func IsAbs(path string) bool { - return len(path) > 0 && path[0] == '/' -} - -// Dir returns all but the last element of path, typically the path's directory. -// After dropping the final element using Split, the path is Cleaned and trailing -// slashes are removed. -// If the path is empty, Dir returns ".". -// If the path consists entirely of slashes followed by non-slash bytes, Dir -// returns a single slash. In any other case, the returned path does not end in a -// slash. -func Dir(path string) string { - dir, _ := Split(path) - dir = Clean(dir) - last := len(dir) - 1 - if last > 0 && dir[last] == '/' { - dir = dir[:last] - } - if dir == "" { - dir = "." - } - return dir -} diff --git a/src/pkg/path/path_test.go b/src/pkg/path/path_test.go deleted file mode 100644 index 13b585223..000000000 --- a/src/pkg/path/path_test.go +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package path - -import ( - "runtime" - "testing" -) - -type PathTest struct { - path, result string -} - -var cleantests = []PathTest{ - // Already clean - {"", "."}, - {"abc", "abc"}, - {"abc/def", "abc/def"}, - {"a/b/c", "a/b/c"}, - {".", "."}, - {"..", ".."}, - {"../..", "../.."}, - {"../../abc", "../../abc"}, - {"/abc", "/abc"}, - {"/", "/"}, - - // Remove trailing slash - {"abc/", "abc"}, - {"abc/def/", "abc/def"}, - {"a/b/c/", "a/b/c"}, - {"./", "."}, - {"../", ".."}, - {"../../", "../.."}, - {"/abc/", "/abc"}, - - // Remove doubled slash - {"abc//def//ghi", "abc/def/ghi"}, - {"//abc", "/abc"}, - {"///abc", "/abc"}, - {"//abc//", "/abc"}, - {"abc//", "abc"}, - - // Remove . elements - {"abc/./def", "abc/def"}, - {"/./abc/def", "/abc/def"}, - {"abc/.", "abc"}, - - // Remove .. elements - {"abc/def/ghi/../jkl", "abc/def/jkl"}, - {"abc/def/../ghi/../jkl", "abc/jkl"}, - {"abc/def/..", "abc"}, - {"abc/def/../..", "."}, - {"/abc/def/../..", "/"}, - {"abc/def/../../..", ".."}, - {"/abc/def/../../..", "/"}, - {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"}, - - // Combinations - {"abc/./../def", "def"}, - {"abc//./../def", "def"}, - {"abc/../../././../def", "../../def"}, -} - -func TestClean(t *testing.T) { - for _, test := range cleantests { - if s := Clean(test.path); s != test.result { - t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result) - } - if s := Clean(test.result); s != test.result { - t.Errorf("Clean(%q) = %q, want %q", test.result, s, test.result) - } - } -} - -func TestCleanMallocs(t *testing.T) { - if testing.Short() { - t.Skip("skipping malloc count in short mode") - } - if runtime.GOMAXPROCS(0) > 1 { - t.Log("skipping AllocsPerRun checks; GOMAXPROCS>1") - return - } - - for _, test := range cleantests { - allocs := testing.AllocsPerRun(100, func() { Clean(test.result) }) - if allocs > 0 { - t.Errorf("Clean(%q): %v allocs, want zero", test.result, allocs) - } - } -} - -type SplitTest struct { - path, dir, file string -} - -var splittests = []SplitTest{ - {"a/b", "a/", "b"}, - {"a/b/", "a/b/", ""}, - {"a/", "a/", ""}, - {"a", "", "a"}, - {"/", "/", ""}, -} - -func TestSplit(t *testing.T) { - for _, test := range splittests { - if d, f := Split(test.path); d != test.dir || f != test.file { - t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file) - } - } -} - -type JoinTest struct { - elem []string - path string -} - -var jointests = []JoinTest{ - // zero parameters - {[]string{}, ""}, - - // one parameter - {[]string{""}, ""}, - {[]string{"a"}, "a"}, - - // two parameters - {[]string{"a", "b"}, "a/b"}, - {[]string{"a", ""}, "a"}, - {[]string{"", "b"}, "b"}, - {[]string{"/", "a"}, "/a"}, - {[]string{"/", ""}, "/"}, - {[]string{"a/", "b"}, "a/b"}, - {[]string{"a/", ""}, "a"}, - {[]string{"", ""}, ""}, -} - -// join takes a []string and passes it to Join. -func join(elem []string, args ...string) string { - args = elem - return Join(args...) -} - -func TestJoin(t *testing.T) { - for _, test := range jointests { - if p := join(test.elem); p != test.path { - t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path) - } - } -} - -type ExtTest struct { - path, ext string -} - -var exttests = []ExtTest{ - {"path.go", ".go"}, - {"path.pb.go", ".go"}, - {"a.dir/b", ""}, - {"a.dir/b.go", ".go"}, - {"a.dir/", ""}, -} - -func TestExt(t *testing.T) { - for _, test := range exttests { - if x := Ext(test.path); x != test.ext { - t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext) - } - } -} - -var basetests = []PathTest{ - // Already clean - {"", "."}, - {".", "."}, - {"/.", "."}, - {"/", "/"}, - {"////", "/"}, - {"x/", "x"}, - {"abc", "abc"}, - {"abc/def", "def"}, - {"a/b/.x", ".x"}, - {"a/b/c.", "c."}, - {"a/b/c.x", "c.x"}, -} - -func TestBase(t *testing.T) { - for _, test := range basetests { - if s := Base(test.path); s != test.result { - t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result) - } - } -} - -var dirtests = []PathTest{ - {"", "."}, - {".", "."}, - {"/.", "/"}, - {"/", "/"}, - {"////", "/"}, - {"/foo", "/"}, - {"x/", "x"}, - {"abc", "."}, - {"abc/def", "abc"}, - {"abc////def", "abc"}, - {"a/b/.x", "a/b"}, - {"a/b/c.", "a/b"}, - {"a/b/c.x", "a/b"}, -} - -func TestDir(t *testing.T) { - for _, test := range dirtests { - if s := Dir(test.path); s != test.result { - t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result) - } - } -} - -type IsAbsTest struct { - path string - isAbs bool -} - -var isAbsTests = []IsAbsTest{ - {"", false}, - {"/", true}, - {"/usr/bin/gcc", true}, - {"..", false}, - {"/a/../bb", true}, - {".", false}, - {"./", false}, - {"lala", false}, -} - -func TestIsAbs(t *testing.T) { - for _, test := range isAbsTests { - if r := IsAbs(test.path); r != test.isAbs { - t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs) - } - } -} |