aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs/populate/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/populate/src/main.rs')
-rw-r--r--pkgs/populate/src/main.rs65
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),
};