Skip to content

Feature request: add a high-level @fs.remove_all #591

Description

@Yoorkin

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:

  1. inspect whether the path is a directory;
  2. choose between @fs.remove and @fs.rmdir(recursive=true);
  3. catch ENOENT explicitly; and
  4. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions