Skip to content

Commit

Permalink
fix(walk): handle leading magic correctly pt. 2
Browse files Browse the repository at this point in the history
Closes #29
  • Loading branch information
citycide committed Sep 26, 2018
1 parent ffd65d3 commit 633a87d
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 24 deletions.
34 changes: 25 additions & 9 deletions src/glob.nim
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,9 @@ func toRelative (path, dir: string): string =
when defined FileSystemCaseSensitive: (path, dir)
else: (path.toLowerAscii, dir.toLowerAscii)

if innerPath.startsWith(innerDir):
if innerPath == innerDir:
return "."
elif innerPath.startsWith(innerDir):
let start = dir.len + dir.endsWith(DirSep).not.int
return path[start..<path.len]
else:
Expand All @@ -270,9 +272,11 @@ proc pathType (path: string, kind: var PathComponent): bool =
discard

func maybeJoin (p1, p2: string): string =
if p2 == "": p1
elif p2.isAbsolute: p2
else: p1 / p2
unixToNativePath(
if p2 == "": p1
elif p2.isAbsolute: p2
else: p1 / p2
)

func makeCaseInsensitive (pattern: string): string {.used.} =
result = ""
Expand All @@ -286,7 +290,7 @@ func makeCaseInsensitive (pattern: string): string {.used.} =
result.add c

# helper to find file system items case insensitively
# on case insensitive systems this is equivalent an existence check
# on case insensitive systems this is equivalent to an existence check
iterator initStack (
path: string,
kinds = {pcFile, pcLinkToFile, pcDir, pcLinkToDir},
Expand All @@ -302,10 +306,10 @@ iterator initStack (
else: path
else: path

# using `walkPattern` even on case sensitive systems (where it can only match
# using `walkPattern` even on case insensitive systems (where it can only match
# one item anyway) gets us a path that matches the casing of the actual filesystem
for realPath in walkPattern(normalized):
push realPath
push realPath.unixToNativePath

proc expandGlob (pattern: string, ignoreCase: bool): string =
if pattern.hasMagic: return pattern
Expand Down Expand Up @@ -386,15 +390,18 @@ func matches* (input, pattern: string; isDos = isDosDefault, ignoreCase = isDosD
proc shouldDescend (
subdir, resultPath, matchPattern: string;
isRec, ignoreCase: bool,
depth: int,
entry: GlobEntry,
filter: FilterDescend
): bool =
if isRec or (not filter.isNil and filter(resultPath)):
return true

let tail = entry.path.toRelative(subdir)
let head = matchPattern.splitPath.head
let patternComponents = matchPattern.split('/', depth + 1)
if depth > patternComponents.len - 1: return false

let head = patternComponents[depth]
if head == tail: return true

let subPattern = head.globToRegex(ignoreCase = ignoreCase)
Expand All @@ -417,6 +424,11 @@ func toOutputPath (

return path.toRelative(internalRoot)

func getPathDepth (parent, child: string): int =
var rel = child.toRelative(parent)
if rel != ".": rel &= DirSep
result = rel.count(DirSep)

iterator walkGlobKinds* (
pattern: string | Glob,
root = "",
Expand Down Expand Up @@ -475,11 +487,13 @@ iterator walkGlobKinds* (

let matcher = matchPattern.globToRegex(ignoreCase = IgnoreCase in options)
let isRec = "**" in matchPattern
var stack = toSeq(initStack(dir, {pcDir, pcLinkToDir}, IgnoreCase in options))

var stack = toSeq(initStack(dir, {pcDir, pcLinkToDir}, IgnoreCase in options))
var last = dir
while stack.len > 0:
let (subdir, _) = stack.pop
let depth = getPathDepth(internalRoot, subdir)

for kind, path in walkDir(subdir):
if Hidden notin options and path.isHidden: continue

Expand All @@ -502,6 +516,7 @@ iterator walkGlobKinds* (
if shouldDescend(
subdir, resultPath, matchPattern,
isRec, IgnoreCase in options,
depth,
(path, kind),
filterDescend
):
Expand All @@ -513,6 +528,7 @@ iterator walkGlobKinds* (
if shouldDescend(
subdir, resultPath, matchPattern,
isRec, IgnoreCase in options,
depth,
(path, kind),
filterDescend
):
Expand Down
45 changes: 30 additions & 15 deletions tests.nim
Original file line number Diff line number Diff line change
Expand Up @@ -316,21 +316,6 @@ suite "pattern walking / listing":
p"temp/shallow.nim"
])

test "leading magic":
let clean = createStructure("temp_leading_magic", @[
p"foo/a.txt",
p"bar/a.txt",
p"baz/a.txt"
])

check seqsEqual(toSeq(walkGlob("*/a.txt", "temp_leading_magic")), @[
p"foo/a.txt",
p"bar/a.txt",
p"baz/a.txt"
])

clean()

check seqsEqual(toSeq(walkGlob("temp/**/*.{nim,jpg}")), @[
p"temp/deep/dir/file.nim",
p"temp/not_as/deep.jpg",
Expand All @@ -348,6 +333,36 @@ suite "pattern walking / listing":
p"temp/shallow.nim"
])

test "leading magic":
let cleanLeadingMagic = createStructure("temp_leading_magic", @[
p"lol/inner/z1.txt",
p"lol/inner/two/z1.txt",
p"lol/inner/three/four/z1.txt",
p"foo/a.txt",
p"bar/a.txt",
p"baz/a.txt"
])

check seqsEqual(toSeq(walkGlob("*/a.txt", "temp_leading_magic")), @[
p"foo/a.txt",
p"bar/a.txt",
p"baz/a.txt"
])

check seqsEqual(toSeq(walkGlob("???/*/z1.txt", "temp_leading_magic")), @[
p"lol/inner/z1.txt"
])

check seqsEqual(toSeq(walkGlob("*/?????/*/z1.txt", "temp_leading_magic")), @[
p"lol/inner/two/z1.txt"
])

check seqsEqual(toSeq(walkGlob("*/*/?????/*/z1.txt", "temp_leading_magic")), @[
p"lol/inner/three/four/z1.txt"
])

cleanLeadingMagic()

test "`Directories` includes matching directories in the results":
let options = defaultGlobOptions + {Directories}
check seqsEqual(toSeq(walkGlob("temp/**", options = options)), @[
Expand Down

0 comments on commit 633a87d

Please sign in to comment.