1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use std::path::{Path, PathBuf};

use crate::{error::fs_err, gsl, Result};

pub fn rm_rf(path: impl AsRef<Path>) -> Result<()> {
    _rm_rf(path.as_ref())
}
fn _rm_rf(path: &Path) -> Result<()> {
    let _guard = gsl::read();
    if !path.exists() {
        return Ok(());
    }
    with_path(path, if path.is_file() { std::fs::remove_file(path) } else { remove_dir_all(path) })
}

pub fn read_file(path: impl AsRef<Path>) -> Result<String> {
    _read_file(path.as_ref())
}
fn _read_file(path: &Path) -> Result<String> {
    let _guard = gsl::read();
    with_path(path, std::fs::read_to_string(path))
}

pub fn write_file(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> Result<()> {
    _write_file(path.as_ref(), contents.as_ref())
}
fn _write_file(path: &Path, contents: &[u8]) -> Result<()> {
    let _guard = gsl::read();
    with_path(path, std::fs::write(path, contents))
}

pub fn mkdir_p(path: impl AsRef<Path>) -> Result<()> {
    _mkdir_p(path.as_ref())
}
fn _mkdir_p(path: &Path) -> Result<()> {
    let _guard = gsl::read();
    with_path(path, std::fs::create_dir_all(path))
}

pub fn cp(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> Result<()> {
    _cp(src.as_ref(), dst.as_ref())
}
fn _cp(src: &Path, dst: &Path) -> Result<()> {
    let _guard = gsl::read();
    with_path(src, std::fs::copy(src, dst)).map(|_size| ())
}

pub fn read_dir(path: impl AsRef<Path>) -> Result<Vec<PathBuf>> {
    _read_dir(path.as_ref())
}
fn _read_dir(path: &Path) -> Result<Vec<PathBuf>> {
    let _guard = gsl::read();
    with_path(path, read_dir_aux(path))
}

pub fn cwd() -> Result<PathBuf> {
    let _guard = gsl::read();
    with_path(&Path::new("."), std::env::current_dir())
}

fn with_path<T>(path: &Path, res: Result<T, std::io::Error>) -> Result<T> {
    res.map_err(|io_err| fs_err(path.to_path_buf(), io_err))
}

#[cfg(not(windows))]
fn remove_dir_all(path: &Path) -> std::io::Result<()> {
    std::fs::remove_dir_all(path)
}

#[cfg(windows)]
fn remove_dir_all(path: &Path) -> std::io::Result<()> {
    for _ in 0..99 {
        if std::fs::remove_dir_all(path).is_ok() {
            return Ok(());
        }
        std::thread::sleep(std::time::Duration::from_millis(10))
    }
    std::fs::remove_dir_all(path)
}

fn read_dir_aux(path: &Path) -> std::io::Result<Vec<PathBuf>> {
    let mut res = Vec::new();
    for entry in std::fs::read_dir(path)? {
        let entry = entry?;
        res.push(entry.path())
    }
    res.sort();
    Ok(res)
}