Skip to main content

cargo_zng/res/built_in/
copy.rs

1use super::*;
2
3const COPY_HELP: &str = "
4Copy the file or dir
5
6The request file:
7  source/foo.txt.zr-copy
8   | # comment
9   | path/bar.txt
10
11Copies `path/bar.txt` to:
12  target/foo.txt
13
14Paths are relative to the Cargo workspace root
15";
16pub(super) fn copy() {
17    help(COPY_HELP);
18
19    // read source
20    let source = read_path(&path(ZR_REQUEST)).unwrap_or_else(|e| fatal!("{e}"));
21    // target derived from the request file name
22    let mut target = path(ZR_TARGET);
23    // request without name "./.zr-copy", take name from source (this is deliberate not documented)
24    if target.ends_with(".zr-copy") {
25        target = target.with_file_name(source.file_name().unwrap());
26    }
27
28    if source.is_dir() {
29        println!("{}", display_path(&target));
30        fs::create_dir(&target).unwrap_or_else(|e| {
31            if e.kind() != io::ErrorKind::AlreadyExists {
32                fatal!("{e}")
33            }
34        });
35        copy_dir_all(&source, &target, true);
36    } else if source.is_file() {
37        println!("{}", display_path(&target));
38        fs::copy(source, &target).unwrap_or_else(|e| fatal!("{e}"));
39    } else if source.is_symlink() {
40        symlink_warn(&source);
41    } else {
42        warn!("cannot copy '{}', not found", source.display());
43    }
44}
45
46fn copy_dir_all(from: &Path, to: &Path, trace: bool) {
47    for entry in walkdir::WalkDir::new(from).min_depth(1).max_depth(1).sort_by_file_name() {
48        let entry = entry.unwrap_or_else(|e| fatal!("cannot walkdir entry `{}`, {e}", from.display()));
49        let from = entry.path();
50        let to = to.join(entry.file_name());
51        if entry.file_type().is_dir() {
52            fs::create_dir(&to).unwrap_or_else(|e| {
53                if e.kind() != io::ErrorKind::AlreadyExists {
54                    fatal!("cannot create_dir `{}`, {e}", to.display())
55                }
56            });
57            if trace {
58                println!("{}", display_path(&to));
59            }
60            copy_dir_all(from, &to, trace);
61        } else if entry.file_type().is_file() {
62            fs::copy(from, &to).unwrap_or_else(|e| fatal!("cannot copy `{}` to `{}`, {e}", from.display(), to.display()));
63            if trace {
64                println!("{}", display_path(&to));
65            }
66        } else if entry.file_type().is_symlink() {
67            symlink_warn(entry.path())
68        }
69    }
70}