README
File::Directory::Bubble
A file-removal tool that
optionally bubbles deletion up the directory tree until it hits a non-empty directory;
allows for dry runs, only showing you what would be deleted.
Installation
With zef:
just running
zef install File::Directory::Bubbleshould work once the module has been indexed;or clone this repo and issue
zef install <path-to-cloned-repo>;or clone,
cdinto the repo, andzef install ..
Usage
The module provides the executable bin/bbrm for access to (what I believe would be) the most common functionality.
First, you can run bbrm --help for a quick breakdown of the usage. For the examples, I will assume access to the tree utility in order to visualize the directory structure that bbrm is meant to alter.
Throughout, assume you're in a directory with the following structure:
$ tree .
.
āāā a
āĀ Ā āāā b
āĀ Ā āĀ Ā āāā c
āĀ Ā āāā b1
āĀ Ā āĀ Ā āāā c
āĀ Ā āĀ Ā āāā d
āĀ Ā āāā b2
āĀ Ā āāā c
āĀ Ā āāā d
āāā foo.txt
9 directories, 1 fileI will run the bbrm command with the --dry option, so it only shows us what it would remove.
$ bbrm a/b* --dry
Would remove:
<fully-expanded path>/a/b/c
<fully-expanded path>/a/b
<fully-expanded path>/a/b1/c/d
<fully-expanded path>/a/b1/c
<fully-expanded path>/a/b1
<fully-expanded path>/a/b2/c/d
<fully-expanded path>/a/b2/c
<fully-expanded path>/a/b2As expected, that would remove everything under the directories ./a/b*. On the other hand, the --up flag would also remove the ./a directory, because it would become empty upon removing the other ones:
$ bbrm a/b* --dry --up
Would remove:
<fully-expanded path>/a/b2/c/d
<fully-expanded path>/a/b2/c
<fully-expanded path>/a/b2
<fully-expanded path>/a/b1/c/d
<fully-expanded path>/a/b1/c
<fully-expanded path>/a/b1
<fully-expanded path>/a/b/c
<fully-expanded path>/a/b
<fully-expanded path>/aIn fact, the same would happen if you were to first remove everything at lower levels: empty-directory deletion would still bubble up.
$ bbrm a/b*/c --dry --up
Would remove:
<fully-expanded path>/a/b2/c/d
<fully-expanded path>/a/b2/c
<fully-expanded path>/a/b2
<fully-expanded path>/a/b1/c/d
<fully-expanded path>/a/b1/c
<fully-expanded path>/a/b1
<fully-expanded path>/a/b/c
<fully-expanded path>/a/b
<fully-expanded path>/aThough again, that only happens with the --up flag. Without it you're only deleting down the directory tree.
$ bbrm a/b*/c --dry
Would remove:
<fully-expanded path>/a/b/c
<fully-expanded path>/a/b1/c/d
<fully-expanded path>/a/b1/c
<fully-expanded path>/a/b2/c/d
<fully-expanded path>/a/b2/cOther modules in the Raku ecosystem
There's of course File::Directory::Tree, but because it deletes files/directories recursively using unlink and rmdir, it's not easy to build a --dry option on top of it:
If you're doing a dry run you're not actually emptying directories, so rmdir doesn't know what it would remove if you were..
Module functions
The library lib/File/Directory/Bubble.rakumod exports a number of functions, some of which are used by the bbrm utility discussed above.
A summary follows.
sub listParents
sub listParents(
IO::Path $file
) returns MuList the argument's parents, as far up as possible.
sub bbUpWith
sub bbUpWith(
IO::Path $file,
&cond
) returns MuStarting with a file, walk up its parent list until a callback function (of your choosing) returns false. Returns the list of parents for which the callback holds.
Starting with the $file you pass in, it builds the increasingly longer lists of ancestors, as in
$file, parent$file, parent, parent-of-parentetc.
The predicate &cond is called on these lists, so there's quite a bit of generality built into the kinds of conditions you can check for.
The iteration stops when &cond first returns false, giving you back the last list of parents before that happened.
sub noChildrenExcept
sub noChildrenExcept(
IO::Path $dir where { ... },
$fList
) returns MuCheck whether a directory has no children except those in a given list.
sub has1childExcept
sub has1childExcept(
$dirList,
$fList
) returns MuA check whether, in a lost of directories, the last one's children consist at most of the next-to-last one plus a list you pass as a second argument.
This is a utility function, for use with &bbUpWith above to produce &bbUpEmpty below.
sub bbUpEmpty
sub bbUpEmpty(
IO::Path $file,
$fList
) returns MuGiven a file and a list of other files, bubble up the parent list of the former until you hit directories that have other children, apart from the list you passed and the children you've already walked over.
This function allows the bbrm script to list what it would remove upon passing the --up flag, even during a --dry run.
You can presumably build your own more complicated examples using the more general callback-driven &bbUpWith above.
sub bbDown
sub bbDown(
IO::Path $file
) returns MuRecurse down a directory, retrieving the files/directories under it.
sub smartRm
sub smartRm(
IO::Path $file
) returns MuUnlink a file or remove an empty directory.