1use path_clean::{self, PathClean};
2use std::path::{Path, PathBuf};
3use std::{env, fs, io};
4
5#[derive(PartialEq, Debug)]
6pub struct Paths {
7 pub links_dir: String,
8 pub src_path: String,
9 pub dest_path: String,
10}
11
12impl Paths {
13 pub fn new(links_dir_str: &str, src_path: &str, dest_path: &str) -> Result<Paths, String> {
14 let pb_links_dir = PathBuf::from(links_dir_str);
15 let pb_src_path = PathBuf::from(src_path);
16 let mut pb_dest_path = PathBuf::from(dest_path);
17
18 let pb_links_dir = match fs::canonicalize(&pb_links_dir) {
19 Ok(x) => x,
20 Err(_) => return Err(format!("links_dir: {:#?} is invalid", pb_links_dir)),
21 };
22
23 let pb_src_path = match fs::canonicalize(&pb_src_path) {
24 Ok(x) => x,
25 Err(_) => return Err(format!("src_path: {:#?} is invalid", pb_src_path)),
26 };
27
28 if pb_dest_path.is_relative() {
29 pb_dest_path = absolute_path(&pb_dest_path).unwrap();
30 }
31 if pb_dest_path.exists() {
32 if pb_dest_path.is_dir() {
33 pb_dest_path.push(pb_src_path.file_name().unwrap());
34 } else {
35 return Err(format!(
36 "dest_path: {:#?} is invalid: a file with that name already exists",
37 pb_dest_path
38 ));
39 }
40 } else {
41 let mut pb_tmp = pb_dest_path.clone();
42 pb_tmp.pop();
43 if !pb_tmp.exists() {
44 return Err(format!(
45 "dest_path: {:#?} is invalid: path does not exist",
46 pb_dest_path
47 ));
48 }
49 }
50 let links_dir = pb_links_dir.into_os_string().into_string().unwrap();
51 let src_path = pb_src_path.into_os_string().into_string().unwrap();
52 let dest_path = pb_dest_path.into_os_string().into_string().unwrap();
53
54 Ok(Paths {
55 links_dir,
56 src_path,
57 dest_path,
58 })
59 }
60}
61
62fn absolute_path(path: impl AsRef<Path>) -> io::Result<PathBuf> {
63 let path = path.as_ref();
64 let absolute_path = if path.is_absolute() {
65 path.to_path_buf()
66 } else {
67 env::current_dir()?.join(path)
68 }
69 .clean();
70 Ok(absolute_path)
71}