Skip to content

Commit

Permalink
feat: add --print-all-depedencies
Browse files Browse the repository at this point in the history
Uses `nix-store --query --requisites --include-outputs <drv-path>` to print all the build and runtime dependencies of a given derivation path
  • Loading branch information
shivaraj-bh committed May 3, 2024
1 parent b247e76 commit ba48c5a
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 14 deletions.
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ reqwest = { version = "0.11", features = ["blocking", "json"] }
try-guard = "0.2.0"
clap = { version = "4.4", features = ["derive"] }
urlencoding = "2.1.3"
nix_rs = { version = "0.3.3" }
nix_rs = { git = "https://github.com/shivaraj-bh/nix-rs.git", branch = "nix-store-cmd" }
# nix_rs = { version = "0.3.2", path = "../nix-rs" }
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
tracing = "0.1.37"
Expand Down
4 changes: 4 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ pub struct BuildConfig {
"auto".to_string(),
])]
pub extra_nix_build_args: Vec<String>,

/// Recursively print all build and runtime dependencies of the outputs generated by `nixci build`
#[clap(long, short)]
pub print_all_dependencies: bool,
}

impl BuildConfig {
Expand Down
40 changes: 32 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,29 @@ use tokio::sync::OnceCell;

use cli::{BuildConfig, CliArgs};
use colored::Colorize;
use nix::devour_flake::{DevourFlakeOutput, DrvOut};
use nix_rs::{command::NixCmd, flake::url::FlakeUrl};
use nix::{all_deps::DrvPaths, devour_flake::DevourFlakeOutput};
use nix_rs::{
command::{NixCmd, NixStoreCmd},
flake::url::FlakeUrl,
};
use tracing::instrument;

static NIXCMD: OnceCell<NixCmd> = OnceCell::const_new();
static NIX_STORE_CMD: OnceCell<NixStoreCmd> = OnceCell::const_new();

pub async fn nixcmd() -> &'static NixCmd {
NIXCMD
.get_or_init(|| async { NixCmd::with_flakes().await.unwrap() })
.await
}

pub async fn nix_store_cmd() -> &'static NixStoreCmd {
NIX_STORE_CMD.get_or_init(|| async { NixStoreCmd }).await
}

/// Run nixci on the given [CliArgs], returning the built outputs in sorted order.
#[instrument(name = "nixci", skip(args))]
pub async fn nixci(args: CliArgs) -> anyhow::Result<Vec<DrvOut>> {
pub async fn nixci(args: CliArgs) -> anyhow::Result<Vec<DrvPaths>> {
tracing::debug!("Args: {args:?}");
let cfg = args.command.get_config().await?;
match args.command {
Expand All @@ -40,7 +48,7 @@ async fn nixci_build(
verbose: bool,
build_cfg: &BuildConfig,
cfg: &config::Config,
) -> anyhow::Result<Vec<DrvOut>> {
) -> anyhow::Result<Vec<DrvPaths>> {
let mut all_outs = HashSet::new();

let systems = build_cfg.get_systems().await?;
Expand All @@ -59,7 +67,7 @@ async fn nixci_build(
if subflake.can_build_on(&systems) {
let outs =
nixci_subflake(verbose, build_cfg, &cfg.flake_url, subflake_name, subflake).await?;
all_outs.extend(outs.0);
all_outs.extend(outs.0.into_iter().map(DrvPaths::DrvOut));
} else {
tracing::info!(
"🍊 {} {}",
Expand All @@ -68,6 +76,25 @@ async fn nixci_build(
);
}
}

if build_cfg.print_all_dependencies {
let mut all_drvs = Vec::new();
for out in all_outs.iter() {
if let DrvPaths::DrvOut(drv_out) = out {
let drv = nix::all_deps::nix_store_query_deriver(drv_out.clone()).await?;
all_drvs.push(drv);
}
}
for drv in all_drvs {
let deps = nix::all_deps::nix_store_query_requisites_with_outputs(drv.clone()).await?;
all_outs.extend(deps.into_iter());
}
}

for out in &all_outs {
println!("{}", out);
}

Ok(all_outs.into_iter().collect())
}

Expand All @@ -85,8 +112,5 @@ async fn nixci_subflake(

let nix_args = subflake.nix_build_args_for_flake(build_cfg, url);
let outs = nix::devour_flake::devour_flake(verbose, nix_args).await?;
for out in &outs.0 {
println!("{}", out.0.bold());
}
Ok(outs)
}
75 changes: 75 additions & 0 deletions src/nix/all_deps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use std::fmt;

use anyhow::{bail, Result};

use super::devour_flake::DrvOut;

/// Nix derivation path
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Hash)]
pub struct Drv(pub String);

/// Encompasses both derivation and derivation output paths
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Hash)]
pub enum DrvPaths {
DrvOut(DrvOut),
Drv(Drv),
}

impl fmt::Display for DrvPaths {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DrvPaths::DrvOut(drv_out) => write!(f, "{}", drv_out.0),
DrvPaths::Drv(drv) => write!(f, "{}", drv.0),
}
}
}

/// Query the deriver of an output path
pub async fn nix_store_query_deriver(out_path: DrvOut) -> Result<Drv> {
let nix_store = crate::nix_store_cmd().await;
let mut cmd = nix_store.command();
cmd.args(["--query", "--deriver", &out_path.0]);
nix_rs::command::trace_cmd(&cmd);
let drv_out = cmd.output().await?;
if drv_out.status.success() {
let drv = String::from_utf8(drv_out.stdout)?.trim().to_string();
Ok(Drv(drv))
} else {
let exit_code = drv_out.status.code().unwrap_or(1);
bail!(
"nix-store --query --deriver failed to run (exited: {})",
exit_code
);
}
}

/// Query the requisites of a derivation path, including outputs
pub async fn nix_store_query_requisites_with_outputs(drv: Drv) -> Result<Vec<DrvPaths>> {
let nix_store = crate::nix_store_cmd().await;
let mut cmd = nix_store.command();
cmd.args(["--query", "--requisites", "--include-outputs", &drv.0]);
nix_rs::command::trace_cmd(&cmd);
let out = cmd.output().await?;
if out.status.success() {
let out = String::from_utf8(out.stdout)?;
let out = out
.lines()
.map(|l| l.trim().to_string())
.filter(|l| !l.is_empty())
.map(|l| {
if l.ends_with(".drv") {
DrvPaths::Drv(Drv(l))
} else {
DrvPaths::DrvOut(DrvOut(l))
}
})
.collect();
Ok(out)
} else {
let exit_code = out.status.code().unwrap_or(1);
bail!(
"nix-store --query --requisites --include-outputs failed to run (exited: {})",
exit_code
);
}
}
1 change: 1 addition & 0 deletions src/nix/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod all_deps;
pub mod devour_flake;
pub mod lock;
pub mod system_list;
29 changes: 26 additions & 3 deletions tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
#[cfg(feature = "integration_test")]
mod integration_test {
use clap::Parser;
use nixci::{self, cli, nix::devour_flake::DrvOut};
use nixci::{
self, cli,
nix::{all_deps::DrvPaths, devour_flake::DrvOut},
};
use regex::Regex;

#[ctor::ctor]
Expand All @@ -23,6 +26,16 @@ mod integration_test {
"github:srid/haskell-multi-nix/c85563721c388629fa9e538a1d97274861bc8321",
]);
let outs = nixci::nixci(args).await?;
let drv_outs: Vec<DrvOut> = outs
.into_iter()
.filter_map(|drv_result| {
if let DrvPaths::DrvOut(drv_out) = drv_result {
Some(drv_out)
} else {
None
}
})
.collect();
let expected = vec![
"/nix/store/3x2kpymc1qmd05da20wnmdyam38jkl7s-ghc-shell-for-packages-0",
"/nix/store/dzhf0i3wi69568m5nvyckck8bbs9yrfd-foo-0.1.0.0",
Expand All @@ -32,7 +45,7 @@ mod integration_test {
.into_iter()
.map(|s| DrvOut(s.to_string()))
.collect::<Vec<_>>();
assert_same_drvs(outs, expected);
assert_same_drvs(drv_outs, expected);
Ok(())
}

Expand All @@ -47,6 +60,16 @@ mod integration_test {
"github:juspay/services-flake/3d764f19d0a121915447641fe49a9b8d02777ff8",
]);
let outs = nixci::nixci(args).await?;
let drv_outs: Vec<DrvOut> = outs
.into_iter()
.filter_map(|drv_result| {
if let DrvPaths::DrvOut(drv_out) = drv_result {
Some(drv_out)
} else {
None
}
})
.collect();
let expected = vec![
"/nix/store/1vlflyqyjnpa9089dgryrhpkypj9zg76-elasticsearch",
"/nix/store/20dz7z6pbzpx6sg61lf2sihj286zs3i2-postgres-test",
Expand All @@ -69,7 +92,7 @@ mod integration_test {
.into_iter()
.map(|s| DrvOut(s.to_string()))
.collect::<Vec<_>>();
assert_same_drvs(outs, expected);
assert_same_drvs(drv_outs, expected);
Ok(())
}

Expand Down

0 comments on commit ba48c5a

Please sign in to comment.