1use std::{
2 fs,
3 io::{self, ErrorKind},
4 path::{Path, PathBuf},
5};
6
7#[derive(Debug, Clone, Copy)]
8pub enum RemoveMode {
9 Files,
10 FilesAndDirectories,
11 Recursive,
12}
13
14fn is_directory(path: &Path) -> io::Result<bool> {
15 Ok(fs::symlink_metadata(path)?.is_dir())
16}
17
18fn remove_file(path: &Path) -> io::Result<()> {
19 if is_directory(path)? {
20 Err(io::Error::new(ErrorKind::Other, "Is a directory"))
21 } else {
22 fs::remove_file(path)
23 }
24}
25
26fn remove_file_or_directory(path: &Path) -> io::Result<()> {
27 if is_directory(path)? {
28 fs::remove_dir(path)
29 } else {
30 fs::remove_file(path)
31 }
32}
33
34fn remove_recursively(path: &Path) -> io::Result<()> {
35 if is_directory(path)? {
36 fs::remove_dir_all(path)
37 } else {
38 fs::remove_file(path)
39 }
40}
41
42fn remove_aux(
43 paths: Vec<PathBuf>,
44 ignore_not_found: bool,
45 operation: impl Fn(&Path) -> io::Result<()>,
46) -> io::Result<()> {
47 let mut result = Ok(());
48
49 for path in paths {
50 if let Err(error) = operation(&path) {
51 if ignore_not_found && matches!(error.kind(), ErrorKind::NotFound) {
52 continue;
53 }
54
55 eprintln!("{}: {}", path.display(), error);
56 result = Err(error);
57 }
58 }
59
60 result
61}
62
63pub fn remove(mode: RemoveMode, paths: Vec<PathBuf>, ignore_not_found: bool) -> io::Result<()> {
64 use RemoveMode as Mode;
65
66 match mode {
67 Mode::Files => remove_aux(paths, ignore_not_found, remove_file),
68 Mode::FilesAndDirectories => remove_aux(paths, ignore_not_found, remove_file_or_directory),
69 Mode::Recursive => remove_aux(paths, ignore_not_found, remove_recursively),
70 }
71}