Skip to main content

warden_core/
path.rs

1use dirs;
2use failure::{self, Error};
3use path_abs::{PathArc, PathAbs, PathDir};
4use std::iter::FromIterator;
5use std::ffi::OsStr;
6use std::path::{self, Path};
7use uuid::Uuid;
8
9pub fn from_str(path: &str) -> Result<PathArc, Error> {
10    let path = if let Some(at) = path.rfind('~') {
11        path.split_at(at).1
12    } else {
13        path
14    };
15
16    expand_home(Path::new(path))
17}
18
19pub fn normalise(path: &Path) -> Result<PathAbs, Error> {
20    Ok(expand_home(path)?.absolute()?)
21}
22
23fn expand_home(path: &Path) -> Result<PathArc, Error> {
24    if path.starts_with("~") {
25        if let Some(home) = dirs::home_dir() {
26            Ok(PathArc::new(home).join(path.strip_prefix("~")?))
27        } else {
28            Err(failure::err_msg("Could not determine home dir"))
29        }
30    } else {
31        Ok(PathArc::new(path))
32    }
33}
34
35pub fn relpath(path: &PathArc) -> Result<String, Error> {
36    Ok(relpath_to_base(&PathDir::current_dir()?, path))
37}
38
39pub fn relpath_to_base(base: &PathDir, path: &PathArc) -> String {
40    let matching = {
41        let mut base_compos = base.components();
42        let mut path_compos = path.components();
43        let mut matching = 0;
44
45        loop {
46            if let Some(ref base_item) = base_compos.next() {
47                if let Some(ref path_item) = path_compos.next() {
48                    if base_item == path_item {
49                        matching += 1;
50                    } else {
51                        break;
52                    }
53                } else {
54                    break;
55                }
56            } else {
57                break;
58            }
59        };
60
61        matching
62    };
63
64    if matching == 0 {
65        return format!("{}", path.as_path().display());
66    }
67
68    let base_compos = base.components().skip(matching);
69    let path_compos = path.components().skip(matching);
70
71    let result = path::PathBuf::from_iter(
72        base_compos
73            .map(|_| path::Component::ParentDir)
74            .chain(path_compos)
75    );
76
77    format!("{}", result.as_path().display())
78}
79
80
81pub fn to_uuid(source: &Path) -> Uuid {
82    Uuid::new_v5(&Uuid::NAMESPACE_OID, &format!("{:?}", source).as_bytes()[..])
83}
84
85
86pub fn folder_name(dir: &PathDir) -> Result<&str, Error> {
87    match dir.file_name() {
88        None => Err(failure::err_msg(format!("Path does not have folder name: {}", dir.as_path().to_string_lossy()))),
89        Some(name) => {
90            match name.to_str() {
91                None => Err(failure::err_msg(format!("Could not read the folder name: {}", name.to_string_lossy()))),
92                Some(name) => Ok(name)
93            }
94        }
95    }
96}
97
98
99pub fn os_string(os_str: &OsStr) -> Result<String, Error> {
100    os_str.to_os_string().into_string()
101    .or_else(|string| Err(
102        failure::err_msg(
103            format!(
104                "Could not convert \"{:?}\" into string",
105                string
106            )
107        )
108    ))
109}
110
111pub fn os_str(os_str: &OsStr) -> Result<&str, Error> {
112    os_str.to_str()
113    .ok_or_else(||
114        failure::err_msg(
115            format!(
116                "Could not convert \"{:?}\" into string",
117                os_str
118            )
119        )
120    )
121}