Created
November 4, 2016 07:49
-
-
Save wking/4ec91412fbd72f4bf7b22193b96b6bc0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"regexp" | |
"strings" | |
) | |
var multiSlashRegexp = regexp.MustCompile("//*") | |
var multiBackslashRegexp = regexp.MustCompile("\\\\*") | |
func main() { | |
for _, test := range []struct { | |
os string | |
pathA string | |
pathB string | |
cwd string | |
expected bool | |
}{ | |
{ | |
os: "linux", | |
pathA: "/", | |
pathB: "/a", | |
cwd: "/cwd", | |
expected: true, | |
}, | |
{ | |
os: "linux", | |
pathA: "/a", | |
pathB: "/a", | |
cwd: "/cwd", | |
expected: false, | |
}, | |
{ | |
os: "linux", | |
pathA: "/a", | |
pathB: "/", | |
cwd: "/cwd", | |
expected: false, | |
}, | |
{ | |
os: "linux", | |
pathA: "/a", | |
pathB: "/ab", | |
cwd: "/cwd", | |
expected: false, | |
}, | |
{ | |
os: "linux", | |
pathA: "/a/", | |
pathB: "/a", | |
cwd: "/cwd", | |
expected: false, | |
}, | |
{ | |
os: "linux", | |
pathA: "//a", | |
pathB: "/a", | |
cwd: "/cwd", | |
expected: false, | |
}, | |
{ | |
os: "linux", | |
pathA: "//a", | |
pathB: "/a/b", | |
cwd: "/cwd", | |
expected: true, | |
}, | |
{ | |
os: "linux", | |
pathA: "/a", | |
pathB: "/a/", | |
cwd: "/cwd", | |
expected: false, | |
}, | |
{ | |
os: "linux", | |
pathA: "/a", | |
pathB: ".", | |
cwd: "/cwd", | |
expected: false, | |
}, | |
{ | |
os: "linux", | |
pathA: "/a", | |
pathB: "b", | |
cwd: "/a", | |
expected: true, | |
}, | |
{ | |
os: "linux", | |
pathA: "/a", | |
pathB: "../a", | |
cwd: "/cwd", | |
expected: false, | |
}, | |
{ | |
os: "linux", | |
pathA: "/a", | |
pathB: "../a/b", | |
cwd: "/cwd", | |
expected: true, | |
}, | |
} { | |
ancestor, err := IsAncestor(test.os, test.pathA, test.pathB, test.cwd) | |
if err != nil { | |
fmt.Printf("error: %s %s %s %s -> %s\n", test.os, test.pathA, test.pathB, test.cwd, err) | |
} else if ancestor != test.expected { | |
fmt.Printf("unexpected result: %s %s %s %s -> %t\n", test.os, test.pathA, test.pathB, test.cwd, ancestor) | |
} | |
} | |
} | |
// Abs is an explicit-OS version of path/filepath's Abs. | |
func Abs(os, path, cwd string) (_ string, err error) { | |
if IsAbs(os, path) { | |
return path, nil | |
} | |
return Join(os, cwd, path), nil | |
} | |
// Clean is an explicit-OS version of path/filepath's Clean. | |
func Clean(os, path string) string { | |
// FIXME: implement all logic described for path/filepath's Clean. | |
sep := Separator(os) | |
if os == "windows" { | |
path = multiBackslashRegexp.ReplaceAllString(path, string(sep)) | |
} else { | |
path = multiSlashRegexp.ReplaceAllString(path, string(sep)) | |
} | |
// FIXME: eliminate . | |
// FIXME: eliminate inner .. | |
// FIXME: eliminate .. elements that begin with a rooted path | |
if os == "windows" { | |
if path == "C:\\" { | |
return path | |
} | |
} else if path == string(sep) { | |
return path | |
} | |
return strings.TrimRight(path, string(sep)) | |
} | |
// IsAbs is an explicit-OS version of path/filepath's IsAbs. | |
func IsAbs(os, path string) bool { | |
if os == "windows" { | |
// FIXME: copy hideous logic from Go's | |
// src/path/filepath/path_windows.go into somewhere where we can | |
// put 3-clause BSD licensed code. | |
return false | |
} | |
sep := Separator(os) | |
return strings.HasPrefix(path, string(sep)) | |
} | |
// Join is an explicit-OS version of path/filepath's Join. | |
func Join(os string, elem ...string) string { | |
sep := Separator(os) | |
// FIXME: do this right | |
return fmt.Sprintf("%s%c%s", elem[0], sep, elem[1]) | |
} | |
// Separator is an explicit-OS version of path/filepath's Separator. | |
func Separator(os string) rune { | |
if os == "windows" { | |
return '\\' | |
} | |
return '/' | |
} | |
// IsAncestor returns true when pathB is an strict ancestor of pathA, | |
// and false where the paths are equal or pathB is outside of pathA. | |
// Paths that are not absolute will be made absolute with Abs. | |
func IsAncestor(os, pathA, pathB, cwd string) (_ bool, err error) { | |
if pathA == pathB { | |
return false, nil | |
} | |
pathA, err = Abs(os, pathA, cwd) | |
if err != nil { | |
return false, err | |
} | |
pathB, err = Abs(os, pathB, cwd) | |
if err != nil { | |
return false, err | |
} | |
sep := Separator(os) | |
if !strings.HasSuffix(pathA, string(sep)) { | |
pathA = fmt.Sprintf("%s%c", pathA, sep) | |
} | |
if pathA == pathB { | |
return false, nil | |
} | |
//fmt.Printf(" %s has prefix %s?\n", pathB, pathA) | |
return strings.HasPrefix(pathB, pathA), nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment