From e03e6af17679f439f3bbf696603efc47b2f5b0ec Mon Sep 17 00:00:00 2001 From: Noah Huetter Date: Thu, 5 May 2022 11:40:44 +0200 Subject: [PATCH] Add `rm` subcommand to locally remove output artifacts --- src/cache.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/cli.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/src/cache.rs b/src/cache.rs index aaba46e..d7bc500 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -403,6 +403,53 @@ impl<'a> Cache<'a> { Ok((true, req_obj)) } + /// Remove local output of artifact + pub fn rm( + &self, + artifact: &'a Artifact, + dry_run: bool, + ) -> std::result::Result { + for oup in &artifact.outputs { + let dst = self.repo.path.as_path().join(oup); + // Get metadata to check if file exists and is file or directory + let md = match std::fs::metadata(&dst) { + Ok(md) => md, + Err(_e) => { + continue; + } + }; + // If output is a directory, remove it recursively + if md.is_dir() { + if dry_run { + println!("Would remove {:?}", dst); + continue; + } + debug!("Removing {:?}", dst); + match fs::remove_dir_all(&dst) { + Ok(()) => (), + Err(e) => { + error!("Failed to remove directory {:?}: {:?}", &dst, e); + return Err(e); + } + } + } else if md.is_file() { + if dry_run { + println!("Would remove {:?}", dst); + continue; + } + debug!("Removing {:?}", dst); + match fs::remove_file(&dst) { + Ok(()) => (), + Err(e) => { + error!("Failed to remove file {:?}: {:?}", &dst, e); + return Err(e); + } + } + } + } + Ok(true) + } + fn objects_identical_for_path(&self, a: &Object, b: &Object, path: &Path) -> bool { let key = (a.oid.clone(), b.oid.clone(), path.to_path_buf()); if let Some(entry) = self.objects_path_identity_cache.borrow().get(&key) { diff --git a/src/cli.rs b/src/cli.rs index 991d04e..3239e7f 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -54,6 +54,18 @@ pub fn main() -> Result { .takes_value(true) .required(true) ) + ) + .subcommand(SubCommand::with_name("rm") + .about("Locally remove the outputs of an artifact.") + .arg(Arg::with_name("artifact") + .takes_value(true) + .required(true) + ) + .arg(Arg::with_name("dry-run") + .long("dry-run") + .short("n") + .help("Print the files that would be deleted, but do not remove them.") + ) ); // Parse command-line arguments. @@ -159,6 +171,10 @@ pub fn main() -> Result { false => lookup(&cache, matches, ignore_uncommitted_changes), true => Ok(false), }, + ("rm", Some(matches)) => match disabled { + false => rm(&cache, matches), + true => Ok(false), + }, _ => Error::result("Unknown combination of subcommand and arguments!"), } } @@ -230,3 +246,22 @@ pub fn lookup( } } } + +pub fn rm(cache: &Cache, matches: &ArgMatches) -> Result { + let artifact_name = artifact_name(matches)?; + let artifact = cache.artifact(artifact_name)?; + let dry_run = matches.is_present("dry-run"); + + if dry_run { + info!("Dry-run"); + } + + match cache.rm(&artifact, dry_run) { + Ok(true) => { + info!("Output removal successful."); + Ok(true) + }, + Ok(false) => Ok(false), + Err(_e) => Ok(false), + } +}