aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordiogo464 <[email protected]>2022-02-07 15:45:21 +0000
committerdiogo464 <[email protected]>2022-02-07 15:52:30 +0000
commit406a3e662b3fafd73ab72a6f7bd4e22131654dfb (patch)
treebf044ef831f5938fdb21224f434f9e896c98b8b6
parentcbb2edb0b523f2494fd543857195792a8eda1b62 (diff)
snapshot
-rw-r--r--Cargo.lock125
-rw-r--r--Cargo.toml2
-rw-r--r--src/main.rs77
3 files changed, 181 insertions, 23 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 835a197..c005523 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,6 +3,15 @@
3version = 3 3version = 3
4 4
5[[package]] 5[[package]]
6name = "aho-corasick"
7version = "0.7.18"
8source = "registry+https://github.com/rust-lang/crates.io-index"
9checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
10dependencies = [
11 "memchr",
12]
13
14[[package]]
6name = "ansi_term" 15name = "ansi_term"
7version = "0.12.1" 16version = "0.12.1"
8source = "registry+https://github.com/rust-lang/crates.io-index" 17source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -41,6 +50,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
41checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 50checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
42 51
43[[package]] 52[[package]]
53name = "cfg-if"
54version = "1.0.0"
55source = "registry+https://github.com/rust-lang/crates.io-index"
56checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
57
58[[package]]
44name = "clap" 59name = "clap"
45version = "3.0.14" 60version = "3.0.14"
46source = "registry+https://github.com/rust-lang/crates.io-index" 61source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -77,12 +92,37 @@ dependencies = [
77 "ansi_term", 92 "ansi_term",
78 "anyhow", 93 "anyhow",
79 "clap", 94 "clap",
95 "flexi_logger",
96 "log",
80 "serde", 97 "serde",
81 "slotmap", 98 "slotmap",
82 "toml", 99 "toml",
83] 100]
84 101
85[[package]] 102[[package]]
103name = "flexi_logger"
104version = "0.22.3"
105source = "registry+https://github.com/rust-lang/crates.io-index"
106checksum = "969940c39bc718475391e53a3a59b0157e64929c80cf83ad5dde5f770ecdc423"
107dependencies = [
108 "ansi_term",
109 "atty",
110 "glob",
111 "lazy_static",
112 "log",
113 "regex",
114 "rustversion",
115 "thiserror",
116 "time",
117]
118
119[[package]]
120name = "glob"
121version = "0.3.0"
122source = "registry+https://github.com/rust-lang/crates.io-index"
123checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
124
125[[package]]
86name = "hashbrown" 126name = "hashbrown"
87version = "0.11.2" 127version = "0.11.2"
88source = "registry+https://github.com/rust-lang/crates.io-index" 128source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -114,6 +154,12 @@ dependencies = [
114] 154]
115 155
116[[package]] 156[[package]]
157name = "itoa"
158version = "1.0.1"
159source = "registry+https://github.com/rust-lang/crates.io-index"
160checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
161
162[[package]]
117name = "lazy_static" 163name = "lazy_static"
118version = "1.4.0" 164version = "1.4.0"
119source = "registry+https://github.com/rust-lang/crates.io-index" 165source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -126,12 +172,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
126checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" 172checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c"
127 173
128[[package]] 174[[package]]
175name = "log"
176version = "0.4.14"
177source = "registry+https://github.com/rust-lang/crates.io-index"
178checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
179dependencies = [
180 "cfg-if",
181]
182
183[[package]]
129name = "memchr" 184name = "memchr"
130version = "2.4.1" 185version = "2.4.1"
131source = "registry+https://github.com/rust-lang/crates.io-index" 186source = "registry+https://github.com/rust-lang/crates.io-index"
132checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 187checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
133 188
134[[package]] 189[[package]]
190name = "num_threads"
191version = "0.1.3"
192source = "registry+https://github.com/rust-lang/crates.io-index"
193checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15"
194dependencies = [
195 "libc",
196]
197
198[[package]]
135name = "os_str_bytes" 199name = "os_str_bytes"
136version = "6.0.0" 200version = "6.0.0"
137source = "registry+https://github.com/rust-lang/crates.io-index" 201source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -183,6 +247,29 @@ dependencies = [
183] 247]
184 248
185[[package]] 249[[package]]
250name = "regex"
251version = "1.5.4"
252source = "registry+https://github.com/rust-lang/crates.io-index"
253checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
254dependencies = [
255 "aho-corasick",
256 "memchr",
257 "regex-syntax",
258]
259
260[[package]]
261name = "regex-syntax"
262version = "0.6.25"
263source = "registry+https://github.com/rust-lang/crates.io-index"
264checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
265
266[[package]]
267name = "rustversion"
268version = "1.0.6"
269source = "registry+https://github.com/rust-lang/crates.io-index"
270checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
271
272[[package]]
186name = "serde" 273name = "serde"
187version = "1.0.136" 274version = "1.0.136"
188source = "registry+https://github.com/rust-lang/crates.io-index" 275source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -244,6 +331,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
244checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" 331checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
245 332
246[[package]] 333[[package]]
334name = "thiserror"
335version = "1.0.30"
336source = "registry+https://github.com/rust-lang/crates.io-index"
337checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
338dependencies = [
339 "thiserror-impl",
340]
341
342[[package]]
343name = "thiserror-impl"
344version = "1.0.30"
345source = "registry+https://github.com/rust-lang/crates.io-index"
346checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
347dependencies = [
348 "proc-macro2",
349 "quote",
350 "syn",
351]
352
353[[package]]
354name = "time"
355version = "0.3.7"
356source = "registry+https://github.com/rust-lang/crates.io-index"
357checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d"
358dependencies = [
359 "itoa",
360 "libc",
361 "num_threads",
362 "time-macros",
363]
364
365[[package]]
366name = "time-macros"
367version = "0.2.3"
368source = "registry+https://github.com/rust-lang/crates.io-index"
369checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6"
370
371[[package]]
247name = "toml" 372name = "toml"
248version = "0.5.8" 373version = "0.5.8"
249source = "registry+https://github.com/rust-lang/crates.io-index" 374source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index ea24a57..b7a73a0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,8 @@ edition = "2021"
9ansi_term = "0.12.1" 9ansi_term = "0.12.1"
10anyhow = "1.0.53" 10anyhow = "1.0.53"
11clap = { version = "3.0.14", features = ["derive"] } 11clap = { version = "3.0.14", features = ["derive"] }
12flexi_logger = "0.22.3"
13log = "0.4.14"
12serde = { version = "1.0.136", features = ["derive"] } 14serde = { version = "1.0.136", features = ["derive"] }
13slotmap = "1.0.6" 15slotmap = "1.0.6"
14toml = "0.5.8" 16toml = "0.5.8"
diff --git a/src/main.rs b/src/main.rs
index 1cb68d4..f623450 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -923,7 +923,7 @@ pub mod dotup {
923 923
924 pub fn link(&mut self, origin: impl AsRef<Path>, destination: impl AsRef<Path>) { 924 pub fn link(&mut self, origin: impl AsRef<Path>, destination: impl AsRef<Path>) {
925 let link_result: anyhow::Result<()> = try { 925 let link_result: anyhow::Result<()> = try {
926 let origin = self.prepare_origin_path(origin.as_ref())?; 926 let origin = self.prepare_relative_path(origin.as_ref())?;
927 let destination = destination.as_ref(); 927 let destination = destination.as_ref();
928 self.depot.link_create(origin, destination)?; 928 self.depot.link_create(origin, destination)?;
929 }; 929 };
@@ -936,7 +936,7 @@ pub mod dotup {
936 pub fn unlink(&mut self, paths: impl Iterator<Item = impl AsRef<Path>>) { 936 pub fn unlink(&mut self, paths: impl Iterator<Item = impl AsRef<Path>>) {
937 for origin in paths { 937 for origin in paths {
938 let unlink_result: anyhow::Result<()> = try { 938 let unlink_result: anyhow::Result<()> = try {
939 let origin = self.prepare_origin_path(origin.as_ref())?; 939 let origin = self.prepare_relative_path(origin.as_ref())?;
940 let search_results = self.depot.link_search(&origin)?; 940 let search_results = self.depot.link_search(&origin)?;
941 match search_results { 941 match search_results {
942 depot::SearchResult::Found(link_id) => { 942 depot::SearchResult::Found(link_id) => {
@@ -959,7 +959,7 @@ pub mod dotup {
959 let mut already_linked: HashSet<LinkID> = Default::default(); 959 let mut already_linked: HashSet<LinkID> = Default::default();
960 for origin in paths { 960 for origin in paths {
961 let install_result: anyhow::Result<()> = try { 961 let install_result: anyhow::Result<()> = try {
962 let origin = self.prepare_origin_path(origin.as_ref())?; 962 let origin = self.prepare_relative_path(origin.as_ref())?;
963 let canonical_pairs = self.canonical_pairs_under(&origin)?; 963 let canonical_pairs = self.canonical_pairs_under(&origin)?;
964 for pair in canonical_pairs { 964 for pair in canonical_pairs {
965 if already_linked.contains(&pair.link_id) { 965 if already_linked.contains(&pair.link_id) {
@@ -978,7 +978,7 @@ pub mod dotup {
978 pub fn uninstall(&self, paths: impl Iterator<Item = impl AsRef<Path>>) { 978 pub fn uninstall(&self, paths: impl Iterator<Item = impl AsRef<Path>>) {
979 for origin in paths { 979 for origin in paths {
980 let uninstall_result: anyhow::Result<()> = try { 980 let uninstall_result: anyhow::Result<()> = try {
981 let origin = self.prepare_origin_path(origin.as_ref())?; 981 let origin = self.prepare_relative_path(origin.as_ref())?;
982 let canonical_pairs = self.canonical_pairs_under(&origin)?; 982 let canonical_pairs = self.canonical_pairs_under(&origin)?;
983 for pair in canonical_pairs { 983 for pair in canonical_pairs {
984 self.symlink_uninstall(&pair.origin, &pair.destination)?; 984 self.symlink_uninstall(&pair.origin, &pair.destination)?;
@@ -1001,7 +1001,7 @@ pub mod dotup {
1001 let origins = { 1001 let origins = {
1002 let mut v = Vec::new(); 1002 let mut v = Vec::new();
1003 for origin in origins { 1003 for origin in origins {
1004 match self.prepare_origin_path(origin.as_ref()) { 1004 match self.prepare_relative_path(origin.as_ref()) {
1005 Ok(origin) => v.push(origin), 1005 Ok(origin) => v.push(origin),
1006 Err(e) => { 1006 Err(e) => {
1007 println!("invalid link {} : {e}", origin.as_ref().display()); 1007 println!("invalid link {} : {e}", origin.as_ref().display());
@@ -1066,7 +1066,7 @@ pub mod dotup {
1066 fn status_path_to_item(&self, canonical_path: &Path) -> anyhow::Result<StatusItem> { 1066 fn status_path_to_item(&self, canonical_path: &Path) -> anyhow::Result<StatusItem> {
1067 debug_assert!(canonical_path.is_absolute()); 1067 debug_assert!(canonical_path.is_absolute());
1068 debug_assert!(canonical_path.exists()); 1068 debug_assert!(canonical_path.exists());
1069 let relative_path = self.prepare_origin_path(&canonical_path)?; 1069 let relative_path = self.prepare_relative_path(&canonical_path)?;
1070 1070
1071 let item = if canonical_path.is_dir() { 1071 let item = if canonical_path.is_dir() {
1072 if let Some(link_id) = self.depot.link_find(&relative_path)? { 1072 if let Some(link_id) = self.depot.link_find(&relative_path)? {
@@ -1204,7 +1204,7 @@ pub mod dotup {
1204 .unwrap_or_default() 1204 .unwrap_or_default()
1205 } 1205 }
1206 1206
1207 fn prepare_origin_path(&self, origin: &Path) -> anyhow::Result<PathBuf> { 1207 fn prepare_relative_path(&self, origin: &Path) -> anyhow::Result<PathBuf> {
1208 let canonical = utils::weakly_canonical(origin); 1208 let canonical = utils::weakly_canonical(origin);
1209 let relative = canonical 1209 let relative = canonical
1210 .strip_prefix(&self.depot_dir) 1210 .strip_prefix(&self.depot_dir)
@@ -1214,7 +1214,7 @@ pub mod dotup {
1214 1214
1215 // returns the canonical pairs for all links under `path`. 1215 // returns the canonical pairs for all links under `path`.
1216 fn canonical_pairs_under(&self, path: &Path) -> anyhow::Result<Vec<CanonicalPair>> { 1216 fn canonical_pairs_under(&self, path: &Path) -> anyhow::Result<Vec<CanonicalPair>> {
1217 let origin = self.prepare_origin_path(path)?; 1217 let origin = self.prepare_relative_path(path)?;
1218 let mut canonical_pairs = Vec::new(); 1218 let mut canonical_pairs = Vec::new();
1219 for link_id in self.depot.links_under(origin)? { 1219 for link_id in self.depot.links_under(origin)? {
1220 canonical_pairs.push(self.canonical_pair_from_link_id(link_id)); 1220 canonical_pairs.push(self.canonical_pair_from_link_id(link_id));
@@ -1250,11 +1250,19 @@ pub mod dotup {
1250 fn symlink_install(&self, origin: &Path, destination: &Path) -> anyhow::Result<()> { 1250 fn symlink_install(&self, origin: &Path, destination: &Path) -> anyhow::Result<()> {
1251 debug_assert!(origin.is_absolute()); 1251 debug_assert!(origin.is_absolute());
1252 debug_assert!(destination.is_absolute()); 1252 debug_assert!(destination.is_absolute());
1253 log::debug!(
1254 "symlink_install : {} -> {}",
1255 origin.display(),
1256 destination.display()
1257 );
1253 1258
1254 if let Some(destination_parent) = destination.parent() { 1259 let destination_parent = destination
1255 std::fs::create_dir_all(destination_parent) 1260 .parent()
1256 .context("Failed to create directories")?; 1261 .ok_or_else(|| anyhow::anyhow!("destination has no parent component"))?;
1257 } 1262 std::fs::create_dir_all(destination_parent).context("Failed to create directories")?;
1263 // need to do this beacause if the destination path ends in '/' because the symlink
1264 // functions will treat it as a directory but we want a file with that name.
1265 let destination = destination.with_file_name(destination.file_name().unwrap());
1258 1266
1259 let destination_exists = destination.exists(); 1267 let destination_exists = destination.exists();
1260 let destination_is_symlink = destination.is_symlink(); 1268 let destination_is_symlink = destination.is_symlink();
@@ -1264,9 +1272,16 @@ pub mod dotup {
1264 } 1272 }
1265 1273
1266 if destination_is_symlink { 1274 if destination_is_symlink {
1275 log::debug!("symlink already exists, removing before recreating");
1267 std::fs::remove_file(&destination)?; 1276 std::fs::remove_file(&destination)?;
1268 } 1277 }
1269 std::os::unix::fs::symlink(origin, destination).context("Failed to create symlink")?; 1278
1279 log::debug!(
1280 "creating filesystem symlink {} -> {}",
1281 origin.display(),
1282 destination.display()
1283 );
1284 std::os::unix::fs::symlink(origin, destination).context("failed to create symlink")?;
1270 1285
1271 Ok(()) 1286 Ok(())
1272 } 1287 }
@@ -1274,6 +1289,7 @@ pub mod dotup {
1274 fn symlink_uninstall(&self, origin: &Path, destination: &Path) -> anyhow::Result<()> { 1289 fn symlink_uninstall(&self, origin: &Path, destination: &Path) -> anyhow::Result<()> {
1275 debug_assert!(origin.is_absolute()); 1290 debug_assert!(origin.is_absolute());
1276 debug_assert!(destination.is_absolute()); 1291 debug_assert!(destination.is_absolute());
1292 let destination = destination.with_file_name(destination.file_name().unwrap());
1277 1293
1278 if destination.is_symlink() { 1294 if destination.is_symlink() {
1279 let symlink_destination = destination.read_link()?.canonicalize()?; 1295 let symlink_destination = destination.read_link()?.canonicalize()?;
@@ -1329,16 +1345,6 @@ mod utils {
1329 1345
1330 pub const DEFAULT_DEPOT_FILE_NAME: &str = ".depot"; 1346 pub const DEFAULT_DEPOT_FILE_NAME: &str = ".depot";
1331 1347
1332 /// collects the result of std::fs::read_dir into two vecs, the first one contains all the
1333 /// directories and the second one all the files.
1334 pub fn collect_read_dir_split(
1335 dir: impl AsRef<Path>,
1336 ) -> anyhow::Result<(Vec<PathBuf>, Vec<PathBuf>)> {
1337 Ok(collect_paths_in_dir(dir)?
1338 .into_iter()
1339 .partition(|p| p.is_dir()))
1340 }
1341
1342 pub fn collect_paths_in_dir(dir: impl AsRef<Path>) -> anyhow::Result<Vec<PathBuf>> { 1348 pub fn collect_paths_in_dir(dir: impl AsRef<Path>) -> anyhow::Result<Vec<PathBuf>> {
1343 Ok(std::fs::read_dir(dir)? 1349 Ok(std::fs::read_dir(dir)?
1344 .filter_map(|e| e.ok()) 1350 .filter_map(|e| e.ok())
@@ -1465,6 +1471,7 @@ mod utils {
1465use std::path::PathBuf; 1471use std::path::PathBuf;
1466 1472
1467use clap::Parser; 1473use clap::Parser;
1474use flexi_logger::Logger;
1468use utils::DEFAULT_DEPOT_FILE_NAME; 1475use utils::DEFAULT_DEPOT_FILE_NAME;
1469 1476
1470#[derive(Parser, Debug)] 1477#[derive(Parser, Debug)]
@@ -1478,8 +1485,19 @@ pub struct Flags {
1478#[derive(Parser, Debug)] 1485#[derive(Parser, Debug)]
1479#[clap(author, version, about, long_about = None)] 1486#[clap(author, version, about, long_about = None)]
1480struct Args { 1487struct Args {
1488 /// A level of verbosity, and can be used multiple times
1489 ///
1490 /// Level 1 - Info
1491 ///
1492 /// Level 2 - Debug
1493 ///
1494 /// Level 3 - Trace
1495 #[clap(short, long, parse(from_occurrences))]
1496 verbose: i32,
1497
1481 #[clap(flatten)] 1498 #[clap(flatten)]
1482 flags: Flags, 1499 flags: Flags,
1500
1483 #[clap(subcommand)] 1501 #[clap(subcommand)]
1484 command: SubCommand, 1502 command: SubCommand,
1485} 1503}
@@ -1497,6 +1515,19 @@ enum SubCommand {
1497 1515
1498fn main() -> anyhow::Result<()> { 1516fn main() -> anyhow::Result<()> {
1499 let args = Args::parse(); 1517 let args = Args::parse();
1518
1519 let log_level = match args.verbose {
1520 0 => "warn",
1521 1 => "info",
1522 2 => "debug",
1523 _ => "trace",
1524 };
1525
1526 Logger::try_with_env_or_str(log_level)?
1527 .format(flexi_logger::colored_default_format)
1528 .set_palette("196;208;32;198;15".to_string())
1529 .start()?;
1530
1500 match args.command { 1531 match args.command {
1501 SubCommand::Init(cmd_args) => command_init(args.flags, cmd_args), 1532 SubCommand::Init(cmd_args) => command_init(args.flags, cmd_args),
1502 SubCommand::Link(cmd_args) => command_link(args.flags, cmd_args), 1533 SubCommand::Link(cmd_args) => command_link(args.flags, cmd_args),