Move nix json types to extra crate

Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
Marcel Müller 2025-12-30 10:05:27 +01:00
parent d662ac59a3
commit a7986584d5
7 changed files with 934 additions and 8 deletions

1
.gitignore vendored
View file

@ -1,5 +1,6 @@
# Rust/Cargo # Rust/Cargo
/target /target
**/target
# Direnv # Direnv
/.direnv /.direnv

548
Cargo.lock generated
View file

@ -2,6 +2,554 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "bytes"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.2",
]
[[package]]
name = "fixedbitset"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "futures"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-executor"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-macro"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]]
name = "futures-task"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "hashbrown"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"foldhash",
]
[[package]]
name = "hashbrown"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]]
name = "indexmap"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [
"equivalent",
"hashbrown 0.16.1",
]
[[package]]
name = "itoa"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "libc"
version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "memchr"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "mio"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
dependencies = [
"libc",
"wasi",
"windows-sys 0.61.2",
]
[[package]]
name = "nix-json"
version = "0.1.0"
dependencies = [
"serde",
"serde_json",
]
[[package]] [[package]]
name = "nixie-build" name = "nixie-build"
version = "0.1.0" version = "0.1.0"
dependencies = [
"displaydoc",
"futures",
"nix-json",
"petgraph",
"serde",
"serde_json",
"thiserror",
"tokio",
]
[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]]
name = "petgraph"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
dependencies = [
"fixedbitset",
"hashbrown 0.15.5",
"indexmap",
"serde",
]
[[package]]
name = "pin-project-lite"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "proc-macro2"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
dependencies = [
"errno",
"libc",
]
[[package]]
name = "slab"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "socket2"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
dependencies = [
"libc",
"windows-sys 0.60.2",
]
[[package]]
name = "syn"
version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tokio"
version = "1.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
dependencies = [
"bytes",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.61.2",
]
[[package]]
name = "tokio-macros"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "zmij"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f4a4e8e9dc5c62d159f04fcdbe07f4c3fb710415aab4754bf11505501e3251d"

View file

@ -1,12 +1,23 @@
[workspace] [workspace]
members = ["nixie-build"] members = ["nix-json", "nixie-build"]
resolver = "3" resolver = "3"
[workspace.package] [workspace.package]
edition = "2024" edition = "2024"
version = "0.1.0" version = "0.1.0"
license = "EUPL-1.2" license = "EUPLs-1.2"
authors = ["Marcel Müller <neikos@neikos.email>"] authors = ["Marcel Müller <neikos@neikos.email>"]
readme = "./README.md" readme = "./README.md"
[workspace.dependencies]
thiserror = "2"
displaydoc = "0.2"
serde_json = "1"
serde = { features = ["derive"], version = "1" }
petgraph = "0.8"
tokio = { features = ["full"], version = "1.48" }
futures = "0.3"
nix-json = { version = "0.1.0", path = "./nix-json" }

11
nix-json/Cargo.toml Normal file
View file

@ -0,0 +1,11 @@
[package]
name = "nix-json"
edition.workspace = true
version = "0.1.0"
license.workspace = true
authors.workspace = true
readme.workspace = true
[dependencies]
serde.workspace = true
serde_json.workspace = true

96
nix-json/src/lib.rs Normal file
View file

@ -0,0 +1,96 @@
use std::collections::HashMap;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
#[serde(tag = "action", rename_all = "lowercase")]
pub enum NixBuildLogLine {
Start(NixLogStartAction),
Stop(NixLogStartAction),
Result(NixLogResultAction),
Msg(NixLogMsgAction),
}
#[derive(Debug, Deserialize)]
pub struct NixLogResultAction {
pub id: i64,
#[serde(rename = "type")]
pub kind: i64,
#[serde(default)]
pub fields: Vec<serde_json::Value>,
}
#[derive(Debug, Deserialize)]
pub struct NixLogStopAction {
pub id: i64,
}
#[derive(Debug, Deserialize)]
pub struct NixLogMsgAction {
pub level: Option<i64>,
pub msg: String,
}
#[derive(Debug, Deserialize)]
pub struct NixLogStartAction {
pub id: i64,
pub level: Option<i64>,
pub parent: Option<i64>,
pub text: Option<String>,
#[serde(rename = "type")]
pub kind: Option<i64>,
#[serde(default)]
pub fields: Vec<serde_json::Value>,
}
#[derive(Debug, Deserialize)]
pub struct RawNixDerivationInfoOutput(HashMap<String, RawNixDerivationInfo>);
impl RawNixDerivationInfoOutput {
pub fn info(&self) -> &HashMap<String, RawNixDerivationInfo> {
&self.0
}
}
#[derive(Debug, Deserialize)]
pub struct RawNixDerivationInfo {
args: Vec<String>,
builder: String,
#[serde(rename = "inputDrvs")]
input_derivations: HashMap<String, serde_json::Value>,
#[serde(rename = "inputSrcs")]
input_sources: Vec<String>,
name: String,
outputs: HashMap<String, HashMap<String, String>>,
system: String,
}
impl RawNixDerivationInfo {
pub fn args(&self) -> &[String] {
&self.args
}
pub fn builder(&self) -> &str {
&self.builder
}
pub fn input_derivations(&self) -> &HashMap<String, serde_json::Value> {
&self.input_derivations
}
pub fn input_sources(&self) -> &[String] {
&self.input_sources
}
pub fn name(&self) -> &str {
&self.name
}
pub fn outputs(&self) -> &HashMap<String, HashMap<String, String>> {
&self.outputs
}
pub fn system(&self) -> &str {
&self.system
}
}

View file

@ -7,3 +7,11 @@ authors.workspace = true
readme.workspace = true readme.workspace = true
[dependencies] [dependencies]
thiserror.workspace = true
displaydoc.workspace = true
serde.workspace = true
serde_json.workspace = true
petgraph.workspace = true
tokio.workspace = true
futures.workspace = true
nix-json.workspace = true

View file

@ -1,14 +1,265 @@
pub fn add(left: u64, right: u64) -> u64 { use std::collections::HashMap;
left + right use std::fmt::Write;
use std::process::Stdio;
use futures::FutureExt;
use futures::StreamExt;
use futures::stream::BoxStream;
use nix_json::NixBuildLogLine;
use nix_json::RawNixDerivationInfoOutput;
use petgraph::Directed;
use petgraph::Graph;
use petgraph::prelude::NodeIndex;
use tokio::io::AsyncBufReadExt;
use tokio::process::Command;
#[derive(Debug)]
pub struct NixBuildResult {
derivation: String,
log: String,
success: bool,
}
impl NixBuildResult {
pub fn derivation(&self) -> &str {
&self.derivation
}
pub fn log(&self) -> &str {
&self.log
}
pub fn success(&self) -> bool {
self.success
}
}
#[derive(Debug)]
pub enum NixBuildError {}
pub trait NixInProgressBuild {
fn next_log_line(
&mut self,
) -> impl Future<Output = Option<Result<NixBuildLogLine, NixBuildError>>>;
}
pub trait NixBackend {
type InProgressBuild<'b>: NixInProgressBuild
where
Self: 'b;
fn start_build(
&self,
derivation: &str,
) -> impl Future<Output = Result<Self::InProgressBuild<'_>, NixBuildError>>;
fn get_needed_builds(
&self,
derivation: &str,
) -> impl Future<Output = Result<NixBuildGraph, NixBuildError>>;
}
pub struct NixCliBackend {
command_path: String,
}
pub struct NixCliBackendBuild {
child: BoxStream<'static, String>,
}
impl NixInProgressBuild for NixCliBackendBuild {
fn next_log_line(
&mut self,
) -> impl Future<Output = Option<Result<NixBuildLogLine, NixBuildError>>> {
self.child.next().map(|out| {
out.map(|line| Ok(serde_json::from_str(line.trim_start_matches("@nix ")).unwrap()))
})
}
}
impl NixBackend for NixCliBackend {
type InProgressBuild<'b> = NixCliBackendBuild;
fn start_build(
&self,
derivation: &str,
) -> impl Future<Output = Result<Self::InProgressBuild<'_>, NixBuildError>> {
async move {
let mut cmd = Command::new(&self.command_path)
.args(["build", "--log-format", "internal-json"])
.arg(derivation)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
let init = cmd.stderr.take().unwrap();
Ok(NixCliBackendBuild {
child: futures::stream::unfold(
tokio::io::BufReader::new(init),
move |mut state| async move {
let mut buffer = String::new();
let num_bytes = state.read_line(&mut buffer).await.unwrap();
if num_bytes == 0 {
None
} else {
Some((std::mem::take(&mut buffer), state))
}
},
)
.boxed(),
})
}
}
fn get_needed_builds(
&self,
derivation: &str,
) -> impl Future<Output = Result<NixBuildGraph, NixBuildError>> {
async move {
let cmd = Command::new(&self.command_path)
.args(["derivation", "show", "--recursive"])
.arg(derivation)
.output()
.await
.unwrap();
let output: RawNixDerivationInfoOutput = serde_json::from_slice(&cmd.stdout).unwrap();
let mut build_graph = NixBuildGraph::default();
for (path, _info) in output.info() {
let internal_id = build_graph.dependencies.add_node(path.to_string());
build_graph.build_infos.insert(
path.to_string(),
NixBuildInfo {
internal_id,
present_in_binary_cache: false,
},
);
}
for (path, info) in output.info() {
let build_info = &build_graph.build_infos[path];
let cur_node = build_info.internal_id;
for (dep_path, _dep_info) in info.input_derivations() {
let other_node = build_graph.build_infos[dep_path].internal_id;
build_graph.dependencies.add_edge(
cur_node,
other_node,
NixBuildOutput {
output_name: String::new(),
},
);
}
}
Ok(build_graph)
}
}
}
pub struct NixBuilder<B> {
backend: B,
}
#[derive(Debug, Clone)]
pub struct NixBuildInfo {
internal_id: NodeIndex<usize>,
present_in_binary_cache: bool,
}
#[derive(Debug)]
pub struct NixBuildOutput {
output_name: String,
}
#[derive(Debug, Default)]
pub struct NixBuildGraph {
build_infos: HashMap<String, NixBuildInfo>,
dependencies: Graph<String, NixBuildOutput, Directed, usize>,
}
impl NixBuildGraph {
fn get_non_binary_builds(&self) -> impl Iterator<Item = (String, NixBuildInfo)> {
self.build_infos
.iter()
.filter(|(_, value)| !value.present_in_binary_cache)
.map(|(key, value)| (key.clone(), value.clone()))
}
}
impl<B> NixBuilder<B>
where
B: NixBackend,
{
pub async fn build(
&self,
derivation: String,
) -> Result<HashMap<String, NixBuildResult>, NixBuildError> {
let needed_builds = self.backend.get_needed_builds(&derivation).await?;
let mut started_build = self.backend.start_build(&derivation).await?;
let mut actually_built =
HashMap::from_iter(needed_builds.get_non_binary_builds().map(|(k, _v)| {
(
k.clone(),
NixBuildResult {
derivation: k,
log: String::new(),
success: false,
},
)
}));
let mut id_to_derivation = HashMap::new();
while let Some(next_log_line) = started_build.next_log_line().await {
let next_log_line = next_log_line?;
if let NixBuildLogLine::Start(start_log) = next_log_line {
if start_log.kind == Some(105) {
id_to_derivation.insert(
start_log.id,
start_log.fields[0].as_str().unwrap().to_string(),
);
}
} else if let NixBuildLogLine::Result(result) = next_log_line {
if result.kind == 101 {
if let Some(build) = actually_built.get_mut(&id_to_derivation[&result.id]) {
writeln!(&mut build.log, "{}", result.fields[0].as_str().unwrap()).unwrap()
} else {
panic!("Could not find correct id");
}
}
}
}
actually_built.retain(|_k, v| !v.log.is_empty());
Ok(actually_built)
}
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[tokio::test]
fn it_works() { async fn check_unpure() {
let result = add(2, 2); let builder = NixBuilder {
assert_eq!(result, 4); backend: NixCliBackend {
command_path: String::from("nix"),
},
};
let infos = builder
.build(".#checks.x86_64-linux.crate-fmt".to_string())
.await
.unwrap();
println!("Got: {infos:#?}");
} }
} }