diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2020-03-20 08:39:55 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-20 16:39:55 +0100 |
commit | 1d665adecde3b3bf16e64068e83c0b3cb0171856 (patch) | |
tree | 5081cb220073d43212c968af5861dfe3e3b0df4e /lib | |
parent | 8215c576664e0bd689c16739f72d5b79cf302ec8 (diff) | |
download | Nim-1d665adecde3b3bf16e64068e83c0b3cb0171856.tar.gz |
[RFC] 'walkDir' now has a new 'checkDir' flag, to mimic behaviour of other languages (#13642)
Co-authored-by: narimiran
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/os.nim | 36 | ||||
-rw-r--r-- | lib/system/nimscript.nim | 6 |
2 files changed, 28 insertions, 14 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 1ee71c1fb..e90d3c514 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2028,8 +2028,8 @@ proc staticWalkDir(dir: string; relative: bool): seq[ tuple[kind: PathComponent, path: string]] = discard -iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: string] {. - tags: [ReadDirEffect].} = +iterator walkDir*(dir: string; relative = false, checkDir = false): + tuple[kind: PathComponent, path: string] {.tags: [ReadDirEffect].} = ## Walks over the directory `dir` and yields for each directory or file in ## `dir`. The component type and full path for each item are returned. ## @@ -2038,7 +2038,6 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: ## Example: This directory structure:: ## dirA / dirB / fileB1.txt ## / dirC - ## / fileA1.txt ## / fileA2.txt ## ## and this code: @@ -2069,7 +2068,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: elif defined(windows): var f: WIN32_FIND_DATA var h = findFirstFile(dir / "*", f) - if h != -1: + if h == -1: + if checkDir: + raiseOSError(osLastError(), dir) + else: defer: findClose(h) while true: var k = pcFile @@ -2087,7 +2089,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: else: raiseOSError(errCode.OSErrorCode) else: var d = opendir(dir) - if d != nil: + if d == nil: + if checkDir: + raiseOSError(osLastError(), dir) + else: defer: discard closedir(d) while true: var x = readdir(d) @@ -2122,7 +2127,7 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: iterator walkDirRec*(dir: string, yieldFilter = {pcFile}, followFilter = {pcDir}, - relative = false): string {.tags: [ReadDirEffect].} = + relative = false, checkDir = false): string {.tags: [ReadDirEffect].} = ## Recursively walks over the directory `dir` and yields for each file ## or directory in `dir`. ## @@ -2159,14 +2164,20 @@ iterator walkDirRec*(dir: string, ## * `walkDir iterator <#walkDir.i,string>`_ var stack = @[""] + var checkDir = checkDir while stack.len > 0: let d = stack.pop() - for k, p in walkDir(dir / d, relative = true): + for k, p in walkDir(dir / d, relative = true, checkDir = checkDir): let rel = d / p if k in {pcDir, pcLinkToDir} and k in followFilter: stack.add rel if k in yieldFilter: yield if relative: rel else: dir / rel + checkDir = false + # We only check top-level dir, otherwise if a subdir is invalid (eg. wrong + # permissions), it'll abort iteration and there would be no way to + # continue iteration. + # Future work can provide a way to customize this and do error reporting. proc rawRemoveDir(dir: string) {.noNimScript.} = when defined(windows): @@ -2181,13 +2192,13 @@ proc rawRemoveDir(dir: string) {.noNimScript.} = else: if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError(), dir) -proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [ +proc removeDir*(dir: string, checkDir = false) {.rtl, extern: "nos$1", tags: [ WriteDirEffect, ReadDirEffect], benign, noNimScript.} = ## Removes the directory `dir` including all subdirectories and files ## in `dir` (recursively). ## ## If this fails, `OSError` is raised. This does not fail if the directory never - ## existed in the first place. + ## existed in the first place, unless `checkDir` = true ## ## See also: ## * `tryRemoveFile proc <#tryRemoveFile,string>`_ @@ -2197,10 +2208,13 @@ proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [ ## * `copyDir proc <#copyDir,string,string>`_ ## * `copyDirWithPermissions proc <#copyDirWithPermissions,string,string>`_ ## * `moveDir proc <#moveDir,string,string>`_ - for kind, path in walkDir(dir): + for kind, path in walkDir(dir, checkDir = checkDir): case kind of pcFile, pcLinkToFile, pcLinkToDir: removeFile(path) - of pcDir: removeDir(path) + of pcDir: removeDir(path, true) + # for subdirectories there is no benefit in `checkDir = false` + # (unless perhaps for edge case of concurrent processes also deleting + # the same files) rawRemoveDir(dir) proc rawCreateDir(dir: string): bool {.noNimScript.} = diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index b8abdaa38..f2a843652 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -30,7 +30,7 @@ proc listDirsImpl(dir: string): seq[string] {. tags: [ReadIOEffect], raises: [OSError].} = builtin proc listFilesImpl(dir: string): seq[string] {. tags: [ReadIOEffect], raises: [OSError].} = builtin -proc removeDir(dir: string) {. +proc removeDir(dir: string, checkDir = true) {. tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin proc removeFile(dir: string) {. tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin @@ -204,10 +204,10 @@ proc listFiles*(dir: string): seq[string] = result = listFilesImpl(dir) checkOsError() -proc rmDir*(dir: string) {.raises: [OSError].} = +proc rmDir*(dir: string, checkDir = false) {.raises: [OSError].} = ## Removes the directory `dir`. log "rmDir: " & dir: - removeDir dir + removeDir(dir, checkDir = checkDir) checkOsError() proc rmFile*(file: string) {.raises: [OSError].} = |