///|
async fn run_find_child(argv : Array[String]) -> Int32 {
guard argv.get(0) is Some(program) else { abort("empty find child argv") }
let spec = @process.child(program, argv[1:].to_owned())
@async.with_task_group() <| group => {
let child = @child_process.spawn(
group,
spec.program,
spec.args,
extra_env=spec.context.env,
inherit_env=false,
cwd=spec.context.cwd,
no_console_window=true,
cancel_handler=@child_process.hard_cancel(),
) catch {
@os_error.OSError(_) as error => {
@stdio.stderr.write("find: '\{program}': \{find_os_message(error)}\n")
return 1
}
error => raise error
}
child.wait()
}
}
///|
async fn FindAction::execute(
self : FindAction,
entry : FindEntry,
context : FindEvaluation,
) -> Bool {
match self {
Print(zero) => {
@stdio.stdout.write(entry.path + (if zero { "\u0000" } else { "\n" }))
true
}
Exec(command, grouped) =>
if grouped {
if !context.batch.unwrap().push(entry.path) {
entry.failed = true
}
true
} else {
let argv = command.map(argument => {
if argument == "{}" {
entry.path
} else {
argument
}
})
let code = run_find_child(argv)
if code < 0 {
@stdio.stderr.write(
"find: '\{command[0]}' terminated by signal \{-code}\n",
)
}
code == 0
}
Delete => {
// GNU protects the literal starting point ".". Other dot spellings are
// passed to the filesystem and retain their actual deletion errors.
if entry.path == "." {
return true
}
try {
if entry.kind == Directory {
@fs.rmdir(entry.path)
if entry.directory is Some(directory) {
directory.state = Unread
}
} else {
@fs.remove(entry.path)
}
true
} catch {
@os_error.OSError(_) as error => {
entry.metadata_error(error, "deletion")
false
}
error => raise error
}
}
}
}