diff options
Diffstat (limited to 'pkgs/populate/src/main.rs')
| -rw-r--r-- | pkgs/populate/src/main.rs | 65 |
1 files changed, 45 insertions, 20 deletions
diff --git a/pkgs/populate/src/main.rs b/pkgs/populate/src/main.rs index 2884fd0..eeed1ef 100644 --- a/pkgs/populate/src/main.rs +++ b/pkgs/populate/src/main.rs @@ -1,7 +1,9 @@ -//! populate SPEC: delivers sources to a target directory, as the spec, a -//! JSON file or - for standard input, says. See docs/design.md. +//! populate [OPTION]... SOURCES [TARGET]: delivers the sources in the JSON +//! file SOURCES, or standard input for -, to the target directory TARGET. +//! See README.md. mod check; +mod cli; mod flake; mod flake_input; mod populate; @@ -13,15 +15,36 @@ 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. +/// Exit status when the command line is wrong, or the sources can't be read +/// or aren't sources. 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 options = match cli::parse(&args) { + Ok(cli::Command::Help) => { + print!("{}", cli::USAGE); + return ExitCode::SUCCESS; + } + Ok(cli::Command::Version) => { + println!("populate {}", env!("CARGO_PKG_VERSION")); + return ExitCode::SUCCESS; + } + Ok(cli::Command::Populate(options)) => options, + Err(message) => { + eprintln!("populate: {message}"); + eprint!( + "{}", + cli::USAGE + .lines() + .next() + .map(|l| format!("{l}\n")) + .unwrap_or_default() + ); + return ExitCode::from(USAGE); + } }; + let path = &options.sources; let text = if path == "-" { let mut text = String::new(); std::io::stdin().read_to_string(&mut text).map(|_| text) @@ -35,29 +58,31 @@ fn main() -> ExitCode { 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, + let source: spec::Sources = match serde_json::from_str(&text) { + Ok(source) => source, Err(e) => { - eprintln!("populate: {path} isn't a spec: {e}"); + eprintln!("populate: {path} doesn't contain sources: {e}"); return ExitCode::from(USAGE); } }; + let origin = run::Origin::from_env(); + let target = options + .target + .complete(&origin, options.sudo, options.ssh_args); + let local = options.local.unwrap_or_else(|| origin.is_local(&target)); + let spec = spec::Spec { + backup: options.backup, + force: options.force, + prune: options.prune, + source, + target, + }; if let Err(message) = check::spec(&spec) { eprintln!("{message}"); return ExitCode::FAILURE; } run::trap_signals(); - let context = match run::Context::new(spec.target.clone(), spec.target.local) { + let context = match run::Context::new(spec.target.clone(), local) { Ok(context) => context, Err(failure) => return exit(failure), }; |
