Motivation
AI-generated CLI programs frequently need idempotent cleanup of a path whose current state is not important. Without a high-level API, they often generate a helper like this:
async fn remove_path_if_present(path : @path.Path) -> Unit {
let path_string = path.to_string()
let kind = @fs.kind(path_string, follow_symlink=false) catch {
@os_error.OSError(_) as error if error.is_ENOENT() => return
error => raise error
}
if kind is Directory {
@fs.rmdir(path_string, recursive=true)
} else {
@fs.remove(path_string)
}
}
The existing low-level operations are useful, but this common cleanup operation currently has to:
- inspect whether the path is a directory;
- choose between
@fs.remove and @fs.rmdir(recursive=true);
- catch
ENOENT explicitly; and
- introduce a check-then-remove race that a library implementation may be better positioned to avoid or minimize.
Requested behavior
Please consider adding a high-level @fs.remove_all operation with these semantics:
- accept a file, symbolic link, or directory without requiring the caller to distinguish them;
- recursively remove a directory, while removing a symbolic link itself rather than following it;
- treat a missing path as a successful no-op; and
- continue to report real errors such as permission failures.
The exact missing-path API is open to design. Two possible shapes are:
pub async fn remove_all(path : StringView) -> Unit
with idempotent behavior built in, or:
pub async fn remove_all(
path : StringView,
missing_ok? : Bool = true,
) -> Unit
if callers should be able to request an error for a missing path. The parameter name and default would need further discussion.
Prior art
Several standard libraries provide this higher-level operation:
- Go
os.RemoveAll removes a file or directory tree and returns nil when the path does not exist.
- Node.js
fs.rm with { recursive: true, force: true } removes files or directories and ignores a missing path.
- C++17
std::filesystem::remove_all removes a file or directory tree and returns 0 when the path does not exist.
- Elixir
File.rm_rf removes files or directories recursively and returns {:ok, []} for a missing path.
- Ruby
FileUtils.rm_rf accepts files or directories and does not fail for a missing path, although its force semantics suppress a broader class of errors.
A high-level API in @fs would make the common intent explicit, reduce repetitive error handling, and give generated CLI code a safer default primitive.
Motivation
AI-generated CLI programs frequently need idempotent cleanup of a path whose current state is not important. Without a high-level API, they often generate a helper like this:
The existing low-level operations are useful, but this common cleanup operation currently has to:
@fs.removeand@fs.rmdir(recursive=true);ENOENTexplicitly; andRequested behavior
Please consider adding a high-level
@fs.remove_alloperation with these semantics:The exact missing-path API is open to design. Two possible shapes are:
with idempotent behavior built in, or:
if callers should be able to request an error for a missing path. The parameter name and default would need further discussion.
Prior art
Several standard libraries provide this higher-level operation:
os.RemoveAllremoves a file or directory tree and returnsnilwhen the path does not exist.fs.rmwith{ recursive: true, force: true }removes files or directories and ignores a missing path.std::filesystem::remove_allremoves a file or directory tree and returns0when the path does not exist.File.rm_rfremoves files or directories recursively and returns{:ok, []}for a missing path.FileUtils.rm_rfaccepts files or directories and does not fail for a missing path, although its force semantics suppress a broader class of errors.A high-level API in
@fswould make the common intent explicit, reduce repetitive error handling, and give generated CLI code a safer default primitive.