unit module PathTools; sub ls(Str(Cool) $path, Bool :$f = True, Bool :$d = True, Bool :$r = False, *%_) is export { return () if !$path.IO.e || (%_:exists && $path !~~ %_); return (?$f ?? $path !! ()) if $path.IO.f; my $cwd-paths = $path.IO.dir(|%_).cache; my $files = $cwd-paths.grep(*.IO.f).cache if ?$f; my $dirs = $cwd-paths.grep(*.IO.d).cache if ?$d; my $rec-paths = $dirs>>.&ls(:$f, :d, :r, |%_) if ?$r && ?$d; ($files.Slip, $dirs.Slip, $rec-paths.Slip).grep(*.so).flat>>.Str; } sub rm(*@paths, Bool :$f = True, Bool :$d = True, Bool :$r, *%_) is export { my @ls = flat (@paths>>.&ls(:$f, :$d, :$r, |%_)>>.Slip)>>.Slip; my @delete-us = (@paths.Slip, @ls.Slip).sort({-.chars}); my @deleted = ~$_ for @delete-us.grep(*.IO.e).grep: {try { $_.IO.d ?? $_.IO.rmdir !! $_.IO.unlink}} } sub mkdirs($path, *%_) is export { my $path-copy = $path; my @mkdirs = eager gather { loop { last if ($path-copy.IO.e && $path-copy.IO.d); take $path-copy; last unless $path-copy := $path-copy.IO.dirname; } } @mkdirs ?? @mkdirs.reverse.grep({ mkdir($_, |%_) }).[*-1] !! (); } sub mktemp($path = &tmppath(), Bool :$f = False, *%_) is export { die "Cannot call mktemp with a path that already exists" if $path.IO.e; state @dirs; state @files; END { rm(|@files, :r, :f, :!d) if @files; rm(|@dirs, :r, :f, :d) if @dirs; } ?$f ?? (do { $path.IO.open(:w).close; @files.append($path); return ~$path.IO.absolute } ) !! (do { with mkdirs($path, |%_) -> $p { @dirs.append(~$p); return ~$p.IO.absolute } }) } sub tmppath(Str(Cool) $base where *.chars = $*TMPDIR) is export { state $lock = Lock.new; state $id = 0; state @cache; $lock.protect({ for ^100 { # retry a max number of times my $gen-path = $base.IO.child("tmppath").child("{time}_{++$id}").IO; if !$gen-path.e && $gen-path !~~ @cache { @cache.append(~$gen-path); return ~$gen-path; } } }); }