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::Bubble
should work once the module has been indexed;or clone this repo and issue
zef install <path-to-cloned-repo>
;or clone,
cd
into 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 file
I 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/b2
As 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>/a
In 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>/a
Though 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/c
Other 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 Mu
List the argument's parents, as far up as possible.
sub bbUpWith
sub bbUpWith(
IO::Path $file,
&cond
) returns Mu
Starting 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-parent
etc.
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 Mu
Check whether a directory has no children except those in a given list.
sub has1childExcept
sub has1childExcept(
$dirList,
$fList
) returns Mu
A 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 Mu
Given 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 Mu
Recurse down a directory, retrieving the files/directories under it.
sub smartRm
sub smartRm(
IO::Path $file
) returns Mu
Unlink a file or remove an empty directory.