aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordiogo464 <[email protected]>2022-02-08 10:59:23 +0000
committerdiogo464 <[email protected]>2022-02-08 10:59:23 +0000
commit4b524a27edb8cd51f04bfc9bd79dfd17ab31003b (patch)
tree8939f6f781bd4ec68ca0f3b5e5f067ce01376009 /src
parentfc9a52b4ffb0ca124e7a1afa57f48787969f100d (diff)
fixed some issues with link and mv
Diffstat (limited to 'src')
-rw-r--r--src/dotup.rs121
-rw-r--r--src/main.rs18
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
124fn command_link(global_flags: Flags, args: LinkArgs) -> anyhow::Result<()> { 124fn 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}