1use std::fs;
2use std::fs::File;
3use std::io::{Read, Write};
4use std::path::Path;
5
6use anyhow::{anyhow, Context, Result};
7use toml::Value;
8use walkdir::WalkDir;
9
10pub fn cp_r(src: &Path, dst: &Path) -> Result<()> {
11 for e in WalkDir::new(src) {
12 let e = e.with_context(|| {
16 format!(
17 "intermittent IO error while iterating directory `{}`",
18 src.display()
19 )
20 })?;
21
22 let src_file = e.path();
23 let relative_path = src_file.strip_prefix(src).with_context(|| {
24 format!(
25 "Could not retrieve relative path of child directory or \
26 file `{}` with regards to parent directory `{}`",
27 src_file.display(),
28 src.display()
29 )
30 })?;
31
32 let dst_file = dst.join(relative_path);
33 let metadata = e
34 .metadata()
35 .with_context(|| format!("Could not retrieve metadata of `{}`", e.path().display()))?;
36
37 if metadata.is_dir() {
38 fs::create_dir_all(&dst_file)
40 .with_context(|| format!("Could not create directory `{}`", dst_file.display()))?;
41 } else {
42 fs::copy(&src_file, &dst_file).with_context(|| {
44 format!(
45 "copying files from `{}` to `{}` failed",
46 src_file.display(),
47 dst_file.display()
48 )
49 })?;
50 };
51 }
52
53 Ok(())
54}
55
56pub fn mkdir(path: &Path) -> Result<()> {
57 fs::create_dir(path).with_context(|| format!("couldn't create directory {}", path.display()))
58}
59
60pub fn parse(path: &Path) -> Result<Value> {
62 Ok(read(path)?
63 .parse::<Value>()
64 .map_err(|e| anyhow!("{} is not valid TOML: {}", path.display(), e))?)
65}
66
67pub fn read(path: &Path) -> Result<String> {
68 let mut s = String::new();
69
70 let p = path.display();
71 File::open(path)
72 .with_context(|| format!("couldn't open {}", p))?
73 .read_to_string(&mut s)
74 .with_context(|| format!("couldn't read {}", p))?;
75
76 Ok(s)
77}
78
79pub fn search<'p>(mut path: &'p Path, file: &str) -> Option<&'p Path> {
81 loop {
82 if path.join(file).exists() {
83 return Some(path);
84 }
85
86 if let Some(p) = path.parent() {
87 path = p;
88 } else {
89 return None;
90 }
91 }
92}
93
94pub fn write(path: &Path, contents: &str) -> Result<()> {
95 let p = path.display();
96 File::create(path)
97 .with_context(|| format!("couldn't open {}", p))?
98 .write_all(contents.as_bytes())
99 .with_context(|| format!("couldn't write to {}", p))
100}