diff options
| author | tv <tv@krebsco.de> | 2026-11-13 16:23:34 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-13 16:23:34 +0100 |
| commit | 50a2b8f9628bacdc8f13848e98b909e7be44c640 (patch) | |
| tree | 3ecc002e39c7cd7147f4a49d7c3e874fa4b344dd /pkgs/populate/src/main.rs | |
| parent | 4afd7d2793e85f260a2a3c20a423f0d1a4844ea7 (diff) | |
populate: add a Rust implementation, selectable for the tests
pkgs.populate takes implementation: "shell", the default, generates a
script from populate's arguments, and "rust" passes them as JSON to the
program in pkgs/populate, built from the crate there by program.nix.
The program checks the spec as checks.nix does during evaluation, with the
same messages, and reports that delivering sources isn't implemented yet.
rustProgram replaces the program, e.g. with one built some other way.
checks.nix holds the checks of populate's arguments during evaluation.
Both implementations check the names of sources and the target path with
it, and the Rust one's wrapper also checks drawing inputs, which the shell
implementation checks where it draws them.
nix-build tests --argstr implementation rust runs the scenarios with the
Rust implementation. They expect it to refuse copying flakes to targets
using sudo when it runs, not during evaluation, because only then it
decides whether the target is local.
Diffstat (limited to 'pkgs/populate/src/main.rs')
| -rw-r--r-- | pkgs/populate/src/main.rs | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/pkgs/populate/src/main.rs b/pkgs/populate/src/main.rs new file mode 100644 index 0000000..a095b74 --- /dev/null +++ b/pkgs/populate/src/main.rs @@ -0,0 +1,55 @@ +//! populate SPEC: delivers sources to a target directory, as the spec, a +//! JSON file or - for standard input, says. See docs/design.md. + +mod check; +mod spec; + +use std::io::Read; +use std::process::ExitCode; + +/// Exit status when the spec can't be read, isn't JSON, or isn't a spec. +const USAGE: u8 = 2; + +fn main() -> ExitCode { + let args: Vec<String> = std::env::args().skip(1).collect(); + let [path] = args.as_slice() else { + eprintln!("usage: populate SPEC"); + return ExitCode::from(USAGE); + }; + let text = if path == "-" { + let mut text = String::new(); + std::io::stdin().read_to_string(&mut text).map(|_| text) + } else { + std::fs::read_to_string(path) + }; + let text = match text { + Ok(text) => text, + Err(e) => { + eprintln!("populate: can't read {path}: {e}"); + return ExitCode::from(USAGE); + } + }; + let version = serde_json::from_str::<serde_json::Value>(&text) + .ok() + .and_then(|value| value.get("version").and_then(|v| v.as_u64())); + if let Some(version) = version.filter(|v| *v != spec::VERSION) { + eprintln!( + "populate: {path} is a spec of version {version}, this populate reads version {}", + spec::VERSION + ); + return ExitCode::from(USAGE); + } + let spec: spec::Spec = match serde_json::from_str(&text) { + Ok(spec) => spec, + Err(e) => { + eprintln!("populate: {path} isn't a spec: {e}"); + return ExitCode::from(USAGE); + } + }; + if let Err(message) = check::spec(&spec) { + eprintln!("{message}"); + return ExitCode::FAILURE; + } + eprintln!("populate: delivering sources isn't implemented yet"); + ExitCode::FAILURE +} |
