diff options
Diffstat (limited to 'dotup_cli/src/commands/link.rs')
| -rw-r--r-- | dotup_cli/src/commands/link.rs | 120 |
1 files changed, 70 insertions, 50 deletions
diff --git a/dotup_cli/src/commands/link.rs b/dotup_cli/src/commands/link.rs index 81c396b..518bd4a 100644 --- a/dotup_cli/src/commands/link.rs +++ b/dotup_cli/src/commands/link.rs | |||
| @@ -32,19 +32,25 @@ pub fn main(config: Config, opts: Opts) -> anyhow::Result<()> { | |||
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | if let Some(destination) = destination { | 34 | if let Some(destination) = destination { |
| 35 | let collected_paths = if opts.directory { | 35 | let params = if opts.directory { |
| 36 | origins.to_vec() | 36 | origins |
| 37 | .iter() | ||
| 38 | .map(|p| LinkCreateParams { | ||
| 39 | origin: p.to_path_buf(), | ||
| 40 | destination: destination.clone(), | ||
| 41 | }) | ||
| 42 | .collect() | ||
| 37 | } else { | 43 | } else { |
| 38 | collect_file_type(origins, FileType::File)? | 44 | let mut params = Vec::new(); |
| 45 | for origin in origins { | ||
| 46 | link(&depot, &origin, &destination, &origin, &mut params)?; | ||
| 47 | } | ||
| 48 | params | ||
| 39 | }; | 49 | }; |
| 40 | 50 | ||
| 41 | for path in collected_paths { | 51 | for link_params in params { |
| 42 | let link_desc = LinkCreateParams { | 52 | log::info!("Creating link : {}", link_params); |
| 43 | origin: path, | 53 | depot.create_link(link_params)?; |
| 44 | destination: destination.clone(), | ||
| 45 | }; | ||
| 46 | log::info!("Creating link : {}", link_desc); | ||
| 47 | depot.create_link(link_desc)?; | ||
| 48 | } | 54 | } |
| 49 | } else { | 55 | } else { |
| 50 | let base_path = match origins { | 56 | let base_path = match origins { |
| @@ -63,48 +69,62 @@ pub fn main(config: Config, opts: Opts) -> anyhow::Result<()> { | |||
| 63 | Ok(()) | 69 | Ok(()) |
| 64 | } | 70 | } |
| 65 | 71 | ||
| 66 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 72 | fn link( |
| 67 | enum FileType { | 73 | depot: &Depot, |
| 68 | File, | 74 | origin: &Path, |
| 69 | Directory, | 75 | destination: &Path, |
| 76 | base: &Path, | ||
| 77 | params: &mut Vec<LinkCreateParams>, | ||
| 78 | ) -> anyhow::Result<()> { | ||
| 79 | let metadata = std::fs::metadata(origin)?; | ||
| 80 | if metadata.is_file() { | ||
| 81 | link_file(depot, origin, destination, base, params)?; | ||
| 82 | } else if metadata.is_dir() { | ||
| 83 | link_directory_recursive(depot, origin, destination, base, params)?; | ||
| 84 | } | ||
| 85 | Ok(()) | ||
| 70 | } | 86 | } |
| 71 | 87 | ||
| 72 | /// Collects canonical files of the given type starting from, and including, entry_paths | 88 | fn link_file( |
| 73 | fn collect_file_type( | 89 | depot: &Depot, |
| 74 | entry_paths: impl IntoIterator<Item = impl AsRef<Path>>, | 90 | origin: &Path, |
| 75 | collect_type: FileType, | 91 | destination: &Path, |
| 76 | ) -> anyhow::Result<Vec<PathBuf>> { | 92 | base: &Path, |
| 77 | let entry_paths: Vec<PathBuf> = entry_paths | 93 | params: &mut Vec<LinkCreateParams>, |
| 78 | .into_iter() | 94 | ) -> anyhow::Result<()> { |
| 79 | .map(|p| p.as_ref().to_path_buf()) | 95 | let origin_canonical = origin |
| 80 | .collect(); | 96 | .canonicalize() |
| 81 | let mut collected = Vec::new(); | 97 | .expect("Failed to canonicalize origin path"); |
| 82 | let mut pending: Vec<_> = entry_paths.iter().cloned().filter(|p| p.is_dir()).collect(); | 98 | let base_canonical = base |
| 83 | 99 | .canonicalize() | |
| 84 | for path in entry_paths { | 100 | .expect("Failed to canonicalize base path"); |
| 85 | let path = path.canonicalize()?; | 101 | |
| 86 | if (path.is_file() && collect_type == FileType::File) | 102 | log::debug!("Origin canonical : {}", origin_canonical.display()); |
| 87 | || (path.is_dir() && collect_type == FileType::Directory) | 103 | log::debug!("Base : {}", base.display()); |
| 88 | { | 104 | |
| 89 | collected.push(path); | 105 | let partial = origin_canonical |
| 90 | } | 106 | .strip_prefix(base_canonical) |
| 91 | } | 107 | .expect("Failed to remove prefix from origin path"); |
| 108 | let destination = destination.join(partial); | ||
| 109 | |||
| 110 | let link_params = LinkCreateParams { | ||
| 111 | origin: origin_canonical, | ||
| 112 | destination, | ||
| 113 | }; | ||
| 114 | params.push(link_params); | ||
| 115 | Ok(()) | ||
| 116 | } | ||
| 92 | 117 | ||
| 93 | while let Some(dir_path) = pending.pop() { | 118 | fn link_directory_recursive( |
| 94 | for entry in dir_path.read_dir()? { | 119 | depot: &Depot, |
| 95 | let entry = entry?; | 120 | dir_path: &Path, |
| 96 | let filetype = entry.file_type()?; | 121 | destination: &Path, |
| 97 | 122 | base: &Path, | |
| 98 | if filetype.is_file() && collect_type == FileType::File { | 123 | params: &mut Vec<LinkCreateParams>, |
| 99 | collected.push(entry.path()); | 124 | ) -> anyhow::Result<()> { |
| 100 | } else if filetype.is_dir() { | 125 | for origin in dir_path.read_dir()? { |
| 101 | if collect_type == FileType::Directory { | 126 | let origin = origin?.path(); |
| 102 | collected.push(entry.path()); | 127 | link(depot, &origin, destination, base, params)?; |
| 103 | } | ||
| 104 | pending.push(entry.path()); | ||
| 105 | } | ||
| 106 | } | ||
| 107 | } | 128 | } |
| 108 | 129 | Ok(()) | |
| 109 | Ok(collected) | ||
| 110 | } | 130 | } |
