diff options
| author | diogo464 <[email protected]> | 2022-02-07 15:45:21 +0000 |
|---|---|---|
| committer | diogo464 <[email protected]> | 2022-02-07 15:52:30 +0000 |
| commit | 406a3e662b3fafd73ab72a6f7bd4e22131654dfb (patch) | |
| tree | bf044ef831f5938fdb21224f434f9e896c98b8b6 /src | |
| parent | cbb2edb0b523f2494fd543857195792a8eda1b62 (diff) | |
snapshot
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 77 |
1 files changed, 54 insertions, 23 deletions
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 { | |||
| 1465 | use std::path::PathBuf; | 1471 | use std::path::PathBuf; |
| 1466 | 1472 | ||
| 1467 | use clap::Parser; | 1473 | use clap::Parser; |
| 1474 | use flexi_logger::Logger; | ||
| 1468 | use utils::DEFAULT_DEPOT_FILE_NAME; | 1475 | use 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)] |
| 1480 | struct Args { | 1487 | struct 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 | ||
| 1498 | fn main() -> anyhow::Result<()> { | 1516 | fn 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), |
