1
use color_eyre::eyre::ContextCompat;
2
use color_eyre::{eyre::Context, Result};
3
use serde::{Deserialize, Serialize};
4
use std::{
5
    fs::{DirBuilder, File},
6
    io::{BufReader, Write},
7
    path::{Path, PathBuf},
8
};
9
use walkdir::WalkDir;
10

            
11
use super::constants::error_messages;
12

            
13
/// Creates a new file in the filesystem if the given does not exists yet at the specified location
14
10
pub fn create_file<'a>(path: &Path, filename: &'a str, buff_write: &'a [u8]) -> Result<()> {
15
10
    let file_path = path.join(filename);
16

            
17
10
    if !file_path.exists() {
18
10
        File::create(&file_path)
19
            .with_context(|| format!("Could not create file {file_path:?}"))?
20
            .write_all(buff_write)
21
            .with_context(|| format!("Could not write to file {file_path:?}"))
22
10
    } else {
23
        Ok(())
24
    }
25
10
}
26

            
27
/// Tries fo find a file from a given root path by its filename
28
pub fn find_file(search_root: &Path, target_filename: &str) -> Option<walkdir::DirEntry> {
29
    WalkDir::new(search_root)
30
        .into_iter()
31
        .filter_map(Result::ok)
32
        .find(|file| {
33
            file.file_name()
34
                .to_str()
35
                .map(|filename| filename.contains(target_filename))
36
                .unwrap_or(false)
37
        })
38
}
39

            
40
pub fn delete_file(path: &Path) -> Result<()> {
41
    if path.exists() {
42
        return std::fs::remove_file(path).with_context(|| error_messages::REMOVE_FILE);
43
    }
44
    Ok(())
45
}
46

            
47
/// Recursively creates a new directory pointed at the value of target if not exists yet
48
28
pub fn create_directory(target: &Path) -> Result<()> {
49
28
    if !target.exists() {
50
28
        DirBuilder::new()
51
            .recursive(true)
52
            .create(target)
53
            .with_context(|| format!("Could not create directory {target:?}"))
54
    } else {
55
        Ok(())
56
    }
57
28
}
58

            
59
#[inline(always)]
60
5
pub fn get_project_root_absolute_path(project_root: &Path) -> Result<PathBuf> {
61
5
    let mut canonical = project_root.canonicalize().with_context(|| {
62
        format!("Error getting the canonical path for the project root: {project_root:?}")
63
    })?;
64
    if cfg!(target_os = "windows") {
65
        canonical = canonical
66
            .to_str()
67
            .map(|unc| &unc[4..])
68
            .unwrap_or_default()
69
            .into()
70
    }
71

            
72
5
    Ok(canonical)
73
5
}
74

            
75
/// Returns a tuple of elements containing the directory of a file, its file stem and its extension
76
40
pub fn get_file_details<P: AsRef<Path>>(p: P) -> Result<(PathBuf, String, String)> {
77
40
    let file_stem = p
78
        .as_ref()
79
        .file_stem()
80
        .with_context(|| format!("Unable to get the file stem for {:?}", p.as_ref()))?;
81

            
82
40
    Ok((
83
40
        p.as_ref()
84
            .parent()
85
            .unwrap_or_else(|| panic!("Unexpected error getting the parent of {:?}", p.as_ref()))
86
            .to_path_buf(),
87
40
        file_stem.to_str().unwrap_or_default().to_string(),
88
40
        p.as_ref().extension().map_or_else(
89
            || String::with_capacity(0),
90
40
            |os_str| os_str.to_str().unwrap_or_default().to_string(),
91
        ),
92
    ))
93
40
}
94

            
95
6
pub fn save_file<T>(path: &Path, data: &T) -> Result<()>
96
where
97
    T: Serialize + ?Sized,
98
{
99
6
    serde_json::to_writer_pretty(
100
6
        File::create(path).with_context(|| format!("Error opening file: {:?}", path))?,
101
        data,
102
    )
103
    .with_context(|| "Error serializing data to the cache")
104
6
}
105

            
106
pub fn load_and_deserialize<T, P>(path: &P) -> Result<T>
107
where
108
    T: for<'a> Deserialize<'a> + Default,
109
    P: AsRef<Path> + std::fmt::Debug,
110
{
111
    let buffer = BufReader::new(
112
        File::open(path.as_ref()).with_context(|| format!("Error opening {:?}", path))?,
113
    );
114

            
115
    Ok(serde_json::from_reader(buffer).unwrap_or_default())
116
}