diff options
| author | diogo464 <[email protected]> | 2022-02-08 10:59:23 +0000 |
|---|---|---|
| committer | diogo464 <[email protected]> | 2022-02-08 10:59:23 +0000 |
| commit | 4b524a27edb8cd51f04bfc9bd79dfd17ab31003b (patch) | |
| tree | 8939f6f781bd4ec68ca0f3b5e5f067ce01376009 | |
| parent | fc9a52b4ffb0ca124e7a1afa57f48787969f100d (diff) | |
fixed some issues with link and mv
| -rw-r--r-- | src/dotup.rs | 121 | ||||
| -rw-r--r-- | src/main.rs | 18 |
2 files changed, 90 insertions, 49 deletions
diff --git a/src/dotup.rs b/src/dotup.rs index 882d245..a7cccbe 100644 --- a/src/dotup.rs +++ b/src/dotup.rs | |||
| @@ -193,57 +193,96 @@ impl Dotup { | |||
| 193 | origins: impl Iterator<Item = impl AsRef<Path>>, | 193 | origins: impl Iterator<Item = impl AsRef<Path>>, |
| 194 | destination: impl AsRef<Path>, | 194 | destination: impl AsRef<Path>, |
| 195 | ) { | 195 | ) { |
| 196 | let origins = { | 196 | let mv_result: anyhow::Result<()> = try { |
| 197 | let mut v = Vec::new(); | 197 | let origins = { |
| 198 | for origin in origins { | 198 | let mut v = Vec::new(); |
| 199 | match self.prepare_relative_path(origin.as_ref()) { | 199 | for origin in origins { |
| 200 | Ok(origin) => v.push(origin), | 200 | v.push( |
| 201 | Err(e) => { | 201 | origin |
| 202 | println!("invalid link {} : {e}", origin.as_ref().display()); | 202 | .as_ref() |
| 203 | return; | 203 | .canonicalize() |
| 204 | } | 204 | .context("failed to canonicalize origin path")?, |
| 205 | ); | ||
| 205 | } | 206 | } |
| 206 | } | 207 | v |
| 207 | v | 208 | }; |
| 208 | }; | 209 | let destination = utils::weakly_canonical(destination.as_ref()); |
| 209 | let destination = destination.as_ref(); | 210 | log::debug!("mv destination : {}", destination.display()); |
| 210 | 211 | ||
| 211 | // if we are moving multiple links then the destination must be a directory | 212 | // if we are moving multiple links then the destination must be a directory |
| 212 | if origins.len() > 1 && destination.is_dir() { | 213 | if origins.len() > 1 && !destination.is_dir() { |
| 213 | println!("destination must be a directory"); | 214 | println!("destination must be a directory"); |
| 214 | return; | 215 | return; |
| 215 | } | 216 | } |
| 216 | 217 | ||
| 217 | for origin in origins { | 218 | for origin in origins { |
| 218 | if let Err(e) = self.mv_one(&origin, destination) { | 219 | let destination = if destination.is_dir() { |
| 219 | println!("error moving link {} : {e}", origin.display()); | 220 | // unwrap: origin must have a filename |
| 221 | destination.join(origin.file_name().unwrap()) | ||
| 222 | } else { | ||
| 223 | destination.to_owned() | ||
| 224 | }; | ||
| 225 | self.mv_one(&origin, &destination)?; | ||
| 220 | } | 226 | } |
| 227 | }; | ||
| 228 | if let Err(e) = mv_result { | ||
| 229 | println!("error moving : {e}"); | ||
| 221 | } | 230 | } |
| 222 | } | 231 | } |
| 223 | 232 | ||
| 224 | fn mv_one(&mut self, origin: &Path, destination: &Path) -> anyhow::Result<()> { | 233 | fn mv_one(&mut self, origin: &Path, destination: &Path) -> anyhow::Result<()> { |
| 225 | let link_id = match self.depot.link_find(origin)? { | 234 | log::debug!("mv_one : {} to {}", origin.display(), destination.display()); |
| 226 | Some(link_id) => link_id, | 235 | |
| 236 | let relative_origin = self.prepare_relative_path(origin)?; | ||
| 237 | let relative_destination = self.prepare_relative_path(destination)?; | ||
| 238 | match self.depot.link_find(&relative_origin)? { | ||
| 239 | Some(link_id) => { | ||
| 240 | let is_installed = self.symlink_is_installed_by_link_id(link_id)?; | ||
| 241 | let original_origin = self.depot.link_view(link_id).origin().to_owned(); | ||
| 242 | log::debug!("is_installed = {is_installed}",); | ||
| 243 | log::debug!("original_origin = {}", original_origin.display()); | ||
| 244 | log::debug!("link_destination = {}", relative_destination.display()); | ||
| 245 | |||
| 246 | self.depot.link_move(link_id, relative_destination)?; | ||
| 247 | if let Err(e) = std::fs::rename(origin, destination).context("Failed to move file") | ||
| 248 | { | ||
| 249 | // unwrap: moving the link back to its origin place has to work | ||
| 250 | self.depot.link_move(link_id, original_origin).unwrap(); | ||
| 251 | return Err(e); | ||
| 252 | } | ||
| 253 | // reinstall because we just moved the origin | ||
| 254 | if is_installed { | ||
| 255 | self.symlink_install_by_link_id(link_id) | ||
| 256 | .context("failed to reinstall link while moving")?; | ||
| 257 | } | ||
| 258 | } | ||
| 227 | None => { | 259 | None => { |
| 228 | return Err(anyhow::anyhow!(format!( | 260 | if origin.is_dir() { |
| 229 | "{} is not a link", | 261 | let mut links_installed: HashSet<_> = Default::default(); |
| 230 | origin.display() | 262 | if self.depot.has_links_under(&relative_origin)? { |
| 231 | ))) | 263 | let links_under: Vec<_> = |
| 264 | self.depot.links_under(&relative_origin)?.collect(); | ||
| 265 | for &link_id in links_under.iter() { | ||
| 266 | let link_view = self.depot.link_view(link_id); | ||
| 267 | if self.symlink_is_installed_by_link_id(link_id)? { | ||
| 268 | links_installed.insert(link_id); | ||
| 269 | } | ||
| 270 | // unwrap: the link is under `origin` so stripping the prefix should | ||
| 271 | // not fail | ||
| 272 | let origin_extra = | ||
| 273 | link_view.origin().strip_prefix(&relative_origin).unwrap(); | ||
| 274 | let new_destination = relative_destination.join(origin_extra); | ||
| 275 | self.depot.link_move(link_id, new_destination)?; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | std::fs::rename(origin, destination)?; | ||
| 279 | for link_id in links_installed { | ||
| 280 | self.symlink_install_by_link_id(link_id)?; | ||
| 281 | } | ||
| 282 | } else { | ||
| 283 | std::fs::rename(origin, destination)?; | ||
| 284 | } | ||
| 232 | } | 285 | } |
| 233 | }; | ||
| 234 | let is_installed = self.symlink_is_installed_by_link_id(link_id)?; | ||
| 235 | let original_origin = self.depot.link_view(link_id).origin().to_owned(); | ||
| 236 | self.depot.link_move(link_id, destination)?; | ||
| 237 | // move the actual file on disk | ||
| 238 | if let Err(e) = std::fs::rename(origin, destination).context("Failed to move file") { | ||
| 239 | // unwrap: moving the link back to its origin place has to work | ||
| 240 | self.depot.link_move(link_id, original_origin).unwrap(); | ||
| 241 | return Err(e); | ||
| 242 | } | ||
| 243 | // reinstall because we just moved the origin | ||
| 244 | if is_installed { | ||
| 245 | self.symlink_install_by_link_id(link_id) | ||
| 246 | .context("failed to reinstall link while moving")?; | ||
| 247 | } | 286 | } |
| 248 | Ok(()) | 287 | Ok(()) |
| 249 | } | 288 | } |
diff --git a/src/main.rs b/src/main.rs index af20f71..132b418 100644 --- a/src/main.rs +++ b/src/main.rs | |||
| @@ -123,16 +123,18 @@ struct LinkArgs { | |||
| 123 | 123 | ||
| 124 | fn command_link(global_flags: Flags, args: LinkArgs) -> anyhow::Result<()> { | 124 | fn command_link(global_flags: Flags, args: LinkArgs) -> anyhow::Result<()> { |
| 125 | let mut dotup = utils::read_dotup(&global_flags)?; | 125 | let mut dotup = utils::read_dotup(&global_flags)?; |
| 126 | let origins = if args.directory { | 126 | if !args.directory && args.origin.is_dir() { |
| 127 | vec![args.origin] | 127 | let directory = args.origin; |
| 128 | } else if args.origin.is_dir() { | 128 | let origins = utils::collect_files_in_dir_recursive(&directory)?; |
| 129 | utils::collect_files_in_dir_recursive(args.origin)? | 129 | for origin in origins { |
| 130 | // unwrap: origin is under directory so stripping should not fail | ||
| 131 | let path_extra = origin.strip_prefix(&directory).unwrap(); | ||
| 132 | let destination = args.destination.join(path_extra); | ||
| 133 | dotup.link(&origin, &destination); | ||
| 134 | } | ||
| 130 | } else { | 135 | } else { |
| 131 | vec![args.origin] | 136 | dotup.link(&args.origin, &args.destination); |
| 132 | }; | 137 | }; |
| 133 | for origin in origins { | ||
| 134 | dotup.link(origin, &args.destination); | ||
| 135 | } | ||
| 136 | utils::write_dotup(&dotup)?; | 138 | utils::write_dotup(&dotup)?; |
| 137 | Ok(()) | 139 | Ok(()) |
| 138 | } | 140 | } |
