From 7443543d8b672dc8053f3a4dde5e9bde040672cc Mon Sep 17 00:00:00 2001 From: Seth Flynn Date: Thu, 13 Mar 2025 20:32:42 -0400 Subject: feat: home-manager configuration support Closes https://github.com/getchoo/nix-forecast/issues/59 --- src/cli.rs | 9 +++++++++ src/command.rs | 5 ++++- src/nix.rs | 46 +++++++++++++++++++++++++++++++++------------- 3 files changed, 46 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/cli.rs b/src/cli.rs index edfba5d..da8635b 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -11,6 +11,15 @@ pub struct Cli { #[arg(short, long, conflicts_with("installables"))] pub configuration: Option, + /// Flake reference pointing to a standalone home-manager configuration + #[arg( + short = 'o', + long, + conflicts_with("configuration"), + conflicts_with("installables") + )] + pub home: Option, + /// URLs of the substituters to check (can be passed more than once) #[arg( alias = "binary-cache", diff --git a/src/command.rs b/src/command.rs index be1dd4c..3d630ca 100644 --- a/src/command.rs +++ b/src/command.rs @@ -19,7 +19,10 @@ impl Run for crate::Cli { resolve_installables(installables).await? } else if let Some(configuration) = &self.configuration { println!("❓ Indexing requisites of configuration closure"); - nix::configuration_closure_paths(configuration)? + nix::system_configuration_closure_paths(configuration)? + } else if let Some(home) = &self.home { + println!("❓ Indexing requisites of home configuration closure"); + nix::home_configuration_closure_paths(home)? } else { println!("❓ Indexing all installables of flake `{}`", self.flake); let installables = nix::all_flake_installables(&self.flake)?; diff --git a/src/nix.rs b/src/nix.rs index 99e7f96..7132e8d 100644 --- a/src/nix.rs +++ b/src/nix.rs @@ -24,6 +24,18 @@ struct PathInfo { path: String, } +/// Strip derivations from a list of store paths +fn strip_drvs(paths: Vec) -> Vec { + paths + .into_iter() + .filter(|path| { + std::path::Path::new(path) + .extension() + .is_some_and(|ext| !ext.eq_ignore_ascii_case("drv")) + }) + .collect() +} + #[instrument(skip(installable))] pub fn dry_build_output(installable: &str) -> Result> { event!(Level::TRACE, "Running command `nix build --extra-experimental-features 'nix-command flakes' --dry-run --json {installable}`"); @@ -105,22 +117,30 @@ pub fn closure_paths(store_path: &str, with_outputs: bool) -> Result } } +/// Get all paths in an installable's closure +#[instrument(skip(installable))] +fn installable_closure_paths(installable: &str) -> Result> { + let store_path = drv_path(&installable)?; + let paths = closure_paths(&store_path, true)?; + let out_paths = strip_drvs(paths); + + Ok(out_paths) +} + /// Get all paths in a NixOS or nix-darwin configuration's closure #[instrument(skip(configuration_ref))] -pub fn configuration_closure_paths(configuration_ref: &str) -> Result> { +pub fn system_configuration_closure_paths(configuration_ref: &str) -> Result> { let installable = format!("{configuration_ref}.config.system.build.toplevel"); - let store_path = drv_path(&installable)?; - let paths = closure_paths(&store_path, true)?; - // Operate only on the out paths of requisites of the closure - let out_paths = paths - .iter() - .filter(|path| { - std::path::Path::new(path) - .extension() - .is_some_and(|ext| !ext.eq_ignore_ascii_case("drv")) - }) - .map(ToString::to_string) - .collect(); + let out_paths = installable_closure_paths(&installable)?; + + Ok(out_paths) +} + +/// Get all paths in a home-manager configuration's closure +#[instrument(skip(configuration_ref))] +pub fn home_configuration_closure_paths(configuration_ref: &str) -> Result> { + let installable = format!("{configuration_ref}.activationPackage"); + let out_paths = installable_closure_paths(&installable)?; Ok(out_paths) } -- cgit v1.2.3