aboutsummaryrefslogtreecommitdiff
path: root/src/utils.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils.rs')
-rw-r--r--src/utils.rs156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/utils.rs b/src/utils.rs
new file mode 100644
index 0000000..a7e945a
--- /dev/null
+++ b/src/utils.rs
@@ -0,0 +1,156 @@
1use std::{
2 collections::VecDeque,
3 path::{Component, Path, PathBuf},
4};
5
6use crate::{
7 dotup::{self, Dotup},
8 Flags,
9};
10
11pub const DEFAULT_DEPOT_FILE_NAME: &str = ".depot";
12
13/// Returns a list of canonical paths to all the files in `dir`. This includes files in
14/// subdirectories.
15/// Fails if dir isnt a directory or if there is some other io error.
16pub fn collect_files_in_dir_recursive(dir: impl Into<PathBuf>) -> anyhow::Result<Vec<PathBuf>> {
17 let mut paths = Vec::new();
18 let mut dirs = VecDeque::new();
19 dirs.push_back(dir.into());
20
21 while let Some(dir) = dirs.pop_front() {
22 for entry in std::fs::read_dir(dir)? {
23 let entry = entry?;
24 let filetype = entry.file_type()?;
25 if filetype.is_dir() {
26 dirs.push_back(entry.path());
27 } else {
28 paths.push(entry.path());
29 }
30 }
31 }
32
33 Ok(paths)
34}
35
36pub fn collect_paths_in_dir(dir: impl AsRef<Path>) -> anyhow::Result<Vec<PathBuf>> {
37 Ok(std::fs::read_dir(dir)?
38 .filter_map(|e| e.ok())
39 .map(|e| e.path())
40 .collect())
41}
42
43pub fn read_dotup(flags: &Flags) -> anyhow::Result<Dotup> {
44 let depot_path = depot_path_from_flags(flags)?;
45 let install_base = install_base_from_flags(flags);
46 dotup::read(depot_path, install_base)
47}
48
49pub fn write_dotup(dotup: &Dotup) -> anyhow::Result<()> {
50 dotup::write(dotup)
51}
52
53pub fn depot_path_from_flags(flags: &Flags) -> anyhow::Result<PathBuf> {
54 match flags.depot {
55 Some(ref path) => Ok(path.clone()),
56 None => find_depot_path().ok_or_else(|| anyhow::anyhow!("Failed to find depot path")),
57 }
58}
59
60pub fn default_depot_path() -> PathBuf {
61 current_working_directory().join(DEFAULT_DEPOT_FILE_NAME)
62}
63
64pub fn find_depot_path() -> Option<PathBuf> {
65 let mut cwd = current_working_directory();
66 loop {
67 let path = cwd.join(DEFAULT_DEPOT_FILE_NAME);
68 if path.exists() {
69 break Some(path);
70 }
71 if !cwd.pop() {
72 break None;
73 }
74 }
75}
76
77pub fn install_base_from_flags(flags: &Flags) -> PathBuf {
78 match flags.install_base {
79 Some(ref path) => path.clone(),
80 None => default_install_base(),
81 }
82}
83
84pub fn default_install_base() -> PathBuf {
85 PathBuf::from(std::env::var("HOME").expect("Failed to obtain HOME environment variable"))
86}
87pub fn weakly_canonical(path: impl AsRef<Path>) -> PathBuf {
88 let cwd = current_working_directory();
89 weakly_canonical_cwd(path, cwd)
90}
91
92fn weakly_canonical_cwd(path: impl AsRef<Path>, cwd: PathBuf) -> PathBuf {
93 // Adapated from
94 // https://github.com/rust-lang/cargo/blob/fede83ccf973457de319ba6fa0e36ead454d2e20/src/cargo/util/paths.rs#L61
95 let path = path.as_ref();
96
97 let mut components = path.components().peekable();
98 let mut canonical = cwd;
99 let prefix = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
100 components.next();
101 PathBuf::from(c.as_os_str())
102 } else {
103 PathBuf::new()
104 };
105
106 for component in components {
107 match component {
108 Component::Prefix(_) => unreachable!(),
109 Component::RootDir => {
110 canonical = prefix.clone();
111 canonical.push(component.as_os_str())
112 }
113 Component::CurDir => {}
114 Component::ParentDir => {
115 canonical.pop();
116 }
117 Component::Normal(p) => canonical.push(p),
118 };
119 }
120
121 canonical
122}
123
124pub fn current_working_directory() -> PathBuf {
125 std::env::current_dir().expect("Failed to obtain current working directory")
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn weak_canonical_test() {
134 let cwd = PathBuf::from("/home/user");
135 assert_eq!(
136 PathBuf::from("/home/dest"),
137 weakly_canonical_cwd("../dest", cwd.clone())
138 );
139 assert_eq!(
140 PathBuf::from("/home/dest/configs/init.vim"),
141 weakly_canonical_cwd("../dest/configs/init.vim", cwd.clone())
142 );
143 assert_eq!(
144 PathBuf::from("/dest/configs/init.vim"),
145 weakly_canonical_cwd("/dest/configs/init.vim", cwd.clone())
146 );
147 assert_eq!(
148 PathBuf::from("/home/user/configs/nvim/lua/setup.lua"),
149 weakly_canonical_cwd("./configs/nvim/lua/setup.lua", cwd.clone())
150 );
151 assert_eq!(
152 PathBuf::from("/home/user/configs/nvim/lua/setup.lua"),
153 weakly_canonical_cwd("configs/nvim/lua/setup.lua", cwd)
154 );
155 }
156}