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}