diff --git a/src/cli/parameters.rs b/src/cli/parameters.rs index 21d216d..d23de05 100644 --- a/src/cli/parameters.rs +++ b/src/cli/parameters.rs @@ -18,6 +18,9 @@ pub(crate) enum Commands { /// Run a single build. Build(BuildArgs), + /// Clean up builds. + Clean(CleanArgs), + /// Launch a daemon to run builds. Daemon(DaemonArgs), @@ -36,6 +39,13 @@ pub(crate) struct BuildArgs { pub(crate) target: Vec, } +#[derive(Args, Debug)] +pub(crate) struct CleanArgs { + /// Path to the nix_builder config file. + #[arg(short, long)] + pub(crate) config: PathBuf, +} + #[derive(Args, Debug)] pub(crate) struct DaemonArgs { /// Path to the nix_builder config file. diff --git a/src/command/clean/mod.rs b/src/command/clean/mod.rs new file mode 100644 index 0000000..ac12c0d --- /dev/null +++ b/src/command/clean/mod.rs @@ -0,0 +1,3 @@ +mod runner; + +pub(crate) use runner::run_clean; diff --git a/src/command/clean/runner.rs b/src/command/clean/runner.rs new file mode 100644 index 0000000..2b2c348 --- /dev/null +++ b/src/command/clean/runner.rs @@ -0,0 +1,43 @@ +use std::collections::HashSet; + +use tracing::info; + +use crate::Result; +use crate::cli::parameters::CleanArgs; +use crate::config::Config; + +pub(crate) async fn run_clean(args: CleanArgs) -> Result<()> { + let config = Config::load_from_file(args.config).await?; + + let target_directory = config.get_target_root_directory()?; + let existing_target_names = { + let mut existing_entries = tokio::fs::read_dir(&target_directory).await?; + let mut existing_target_names = HashSet::new(); + while let Some(existing_target) = existing_entries.next_entry().await? { + existing_target_names.insert(existing_target.file_name()); + } + existing_target_names + }; + + let configured_target_names = config + .get_target_configs() + .iter() + .map(|target| { + target + .get_target_directory(&config) + .and_then(|target_path| { + target_path + .file_name() + .map(|name| name.to_os_string()) + .ok_or("Entry with no file name in target directory.".into()) + }) + }) + .collect::>>()?; + + for dir in existing_target_names.difference(&configured_target_names) { + info!("DELETE TARGET: {:?}", dir); + tokio::fs::remove_dir_all(target_directory.join(dir)).await?; + } + + Ok(()) +} diff --git a/src/command/mod.rs b/src/command/mod.rs index d783347..c7ed7e5 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -1,3 +1,4 @@ pub(crate) mod build; +pub(crate) mod clean; pub(crate) mod daemon; pub(crate) mod feed_logs; diff --git a/src/config/root.rs b/src/config/root.rs index 6f6d0be..7e447c6 100644 --- a/src/config/root.rs +++ b/src/config/root.rs @@ -63,6 +63,10 @@ impl Config { Ok(target_config) } + pub(crate) fn get_target_configs(&self) -> &Vec { + &self.targets + } + /// The root directory where all the output is stored. pub(crate) fn get_output_directory(&self) -> Result, CustomError> { let maybe_repo_directory = self.output_directory.as_deref().map(Cow::Borrowed); @@ -80,4 +84,20 @@ impl Config { let database_path = output_directory.join("nix_builder.sqlite"); Ok(Cow::Owned(database_path)) } + + /// The folder that contains the folders for the build targets. + pub(crate) fn get_target_root_directory<'target>( + &'target self, + ) -> Result, CustomError> { + let output_directory = self.get_output_directory()?; + Ok(Cow::Owned(output_directory.join("target"))) + } + + /// The folder that contains the folders containing the checkouts of the git repositories. + pub(crate) fn get_repo_root_directory<'target>( + &'target self, + ) -> Result, CustomError> { + let output_directory = self.get_output_directory()?; + Ok(Cow::Owned(output_directory.join("repo"))) + } } diff --git a/src/config/target.rs b/src/config/target.rs index 11452dd..f65847f 100644 --- a/src/config/target.rs +++ b/src/config/target.rs @@ -36,33 +36,15 @@ pub(crate) struct TargetConfig { } impl TargetConfig { - /// The folder that contains the folders for the build targets. - pub(crate) fn get_target_root_directory<'target, 'root>( - &'target self, - config_root: &'root Config, - ) -> Result, CustomError> { - let output_directory = config_root.get_output_directory()?; - Ok(Cow::Owned(output_directory.join("target"))) - } - /// The root directory for this specific build target. pub(crate) fn get_target_directory<'target, 'root>( &'target self, config_root: &'root Config, ) -> Result, CustomError> { - let target_root = self.get_target_root_directory(config_root)?; + let target_root = config_root.get_target_root_directory()?; Ok(Cow::Owned(target_root.join(&self.name))) } - /// The folder that contains the folders containing the checkouts of the git repositories. - pub(crate) fn get_repo_root_directory<'target, 'root>( - &'target self, - config_root: &'root Config, - ) -> Result, CustomError> { - let output_directory = config_root.get_output_directory()?; - Ok(Cow::Owned(output_directory.join("repo"))) - } - /// The root of the checkout of the git repository. pub(crate) fn get_repo_directory<'target, 'root>( &'target self, @@ -71,7 +53,7 @@ impl TargetConfig { let hashed_repo = Sha256::digest(&self.repo); let hashed_repo = hex_string(&hashed_repo); - let repo_root = self.get_repo_root_directory(config_root)?; + let repo_root = config_root.get_repo_root_directory()?; Ok(Cow::Owned(repo_root.join(hashed_repo))) } diff --git a/src/main.rs b/src/main.rs index b184aee..9fbad30 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use clap::Parser; use self::cli::parameters::Cli; use self::cli::parameters::Commands; use self::command::build::run_build; +use self::command::clean::run_clean; use self::command::daemon::start_daemon; use self::command::feed_logs::feed_logs; use self::error::CustomError; @@ -38,6 +39,9 @@ async fn main_body() -> Result { Commands::Build(args) => { run_build(args).await?; } + Commands::Clean(args) => { + run_clean(args).await?; + } Commands::Daemon(args) => { start_daemon(args).await?; }