Merge pull request #4360 from jyapayne/add_walktree

Add walkPattern to list both directories and files
This commit is contained in:
Andreas Rumpf
2016-06-21 02:20:05 +02:00
committed by GitHub
4 changed files with 136 additions and 19 deletions

View File

@@ -778,12 +778,26 @@ iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].}
yield (TaintedString(substr(environment[i], 0, p-1)),
TaintedString(substr(environment[i], p+1)))
iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
## Iterate over all the files that match the `pattern`. On POSIX this uses
## the `glob`:idx: call.
##
## `pattern` is OS dependent, but at least the "\*.ext"
## notation is supported.
# Templates for filtering directories and files
when defined(windows):
template isDir(f: WIN32_FIND_DATA): bool =
(f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32
template isFile(f: WIN32_FIND_DATA): bool =
not isDir(f)
else:
template isDir(f: string): bool =
dirExists(f)
template isFile(f: string): bool =
fileExists(f)
template defaultWalkFilter(item): bool =
## Walk filter used to return true on both
## files and directories
true
template walkCommon(pattern: string, filter) =
## Common code for getting the files and directories with the
## specified `pattern`
when defined(windows):
var
f: WIN32_FIND_DATA
@@ -792,8 +806,7 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
if res != -1:
defer: findClose(res)
while true:
if not skipFindData(f) and
(f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) == 0'i32:
if not skipFindData(f) and filter(f):
# Windows bug/gotcha: 't*.nim' matches 'tfoo.nims' -.- so we check
# that the file extensions have the same length ...
let ff = getFilename(f)
@@ -816,10 +829,33 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
for i in 0.. f.gl_pathc - 1:
assert(f.gl_pathv[i] != nil)
let path = $f.gl_pathv[i]
# Make sure it's a file and not a directory
if fileExists(path):
if filter(path):
yield path
iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect].} =
## Iterate over all the files and directories that match the `pattern`.
## On POSIX this uses the `glob`:idx: call.
##
## `pattern` is OS dependent, but at least the "\*.ext"
## notation is supported.
walkCommon(pattern, defaultWalkFilter)
iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
## Iterate over all the files that match the `pattern`. On POSIX this uses
## the `glob`:idx: call.
##
## `pattern` is OS dependent, but at least the "\*.ext"
## notation is supported.
walkCommon(pattern, isFile)
iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect].} =
## Iterate over all the directories that match the `pattern`.
## On POSIX this uses the `glob`:idx: call.
##
## `pattern` is OS dependent, but at least the "\*.ext"
## notation is supported.
walkCommon(pattern, isDir)
type
PathComponent* = enum ## Enumeration specifying a path component.
pcFile, ## path refers to a file

View File

@@ -1,12 +1,88 @@
# test some things of the os module
discard """
output: '''true
true
true
true
true
true
true
true
true
All:
__really_obscure_dir_name/are.x
__really_obscure_dir_name/created
__really_obscure_dir_name/dirs
__really_obscure_dir_name/files.q
__really_obscure_dir_name/some
__really_obscure_dir_name/test
__really_obscure_dir_name/testing.r
__really_obscure_dir_name/these.txt
Files:
__really_obscure_dir_name/are.x
__really_obscure_dir_name/files.q
__really_obscure_dir_name/testing.r
__really_obscure_dir_name/these.txt
Dirs:
__really_obscure_dir_name/created
__really_obscure_dir_name/dirs
__really_obscure_dir_name/some
__really_obscure_dir_name/test
false
false
false
false
false
false
false
false
false
'''
"""
# test os path creation, iteration, and deletion
import os
proc walkDirTree(root: string) =
for k, f in walkDir(root):
case k
of pcFile, pcLinkToFile: echo(f)
of pcDir: walkDirTree(f)
of pcLinkToDir: discard
let files = @["these.txt", "are.x", "testing.r", "files.q"]
let dirs = @["some", "created", "test", "dirs"]
walkDirTree(".")
let dname = "__really_obscure_dir_name"
createDir(dname)
echo dirExists(dname)
# Test creating files and dirs
for dir in dirs:
createDir(dname/dir)
echo dirExists(dname/dir)
for file in files:
let fh = open(dname/file, fmReadWrite)
fh.close()
echo fileExists(dname/file)
echo "All:"
for path in walkPattern(dname/"*"):
echo path
echo "Files:"
for path in walkFiles(dname/"*"):
echo path
echo "Dirs:"
for path in walkDirs(dname/"*"):
echo path
# Test removal of files dirs
for dir in dirs:
removeDir(dname/dir)
echo dirExists(dname/dir)
for file in files:
removeFile(dname/file)
echo fileExists(dname/file)
removeDir(dname)
echo dirExists(dname)

View File

@@ -253,7 +253,7 @@ proc addFiles(s: var seq[string], patterns: seq[string]) =
walkDirRecursively(s, p, p, false)
else:
var i = 0
for f in walkFiles(p):
for f in walkPattern(p):
if existsDir(f):
walkDirRecursively(s, f, p, false)
elif not ignoreFile(f, p, false):

View File

@@ -30,6 +30,11 @@ Library Additions
operations. Currently contains ``partition``, ``rpartition``
and ``expandTabs``.
- Split out ``walkFiles`` in ``os.nim`` to three separate procs in order
to make a clear distinction of functionality. ``walkPattern`` iterates
over both files and directories, while ``walkFiles`` now only iterates
over files and ``walkDirs`` only iterates over directories.
Compiler Additions
------------------