And just to close out the example more fully for @chalybeum, since he said he
was a beginning programmer, he could probably start from the code below (after
a `nimble install 'cligen@#head'`) to do whatever it was he wanted to six
months ago if he even stuck with programming, with Nim and/or this forum:
import sets, posix, cligen/[dents, statx, posixUt]
proc chalybeum(prunePath="", recurse=0, chase=false,
xdev=false, roots: seq[string]) =
## ``prunePath`` file fmt is one base name per line.
var prune: HashSet[string]
for line in lines(prunePath): prune.incl line
for root in roots:
forPath(root, recurse, false, chase, xdev, depth,
path, nameAt, ino, dt, lst, st, recFail):
case errno
of EXDEV, ENOTDIR: discard # Expected sometimes
of EMFILE, ENFILE: return # Too deep;Stop recurse
else:
let m = "chalybeum: \"" & path & "\")"
perror cstring(m), m.len
do:
echo path # chalybeum logic on `path` goes here
do: # Pre-recurse: skip dirs w/base names in prune
if dt == DT_DIR and path[nameAt..^1] in prune:
continue
do: # Post-recurse; only `path` valid now
if recFail: echo "did not recurse into ", path
when isMainModule:
import cligen; cligen.dispatch(chalybeum)
Run
Replacing HashSet checking with regex prunes/excludes is not so hard. It is
fast, does avoid symlink infinite loops (when optionally chasing), and
conditionally avoids cross-device links which is kind of the standard set of
Unix tree walk functionality, BUT I totally admit it's not a very easy to use
programming interface. The logic of the recursive loop leaks out plenty. I just
threw it together. I'm not sure it's much better than the example expanded
recursion code would be. Maybe a little.