1use std::collections::HashMap;
4use std::process::Command;
5
6use crate::config::DeploymentPlan;
7use crate::error::{NixError, Result};
8
9pub struct CopyResults {
11 pub succeeded: Vec<String>,
13 pub errors: HashMap<String, NixError>,
15}
16
17pub fn copy_closures(plan: &DeploymentPlan) -> Result<CopyResults> {
19 let mut results = CopyResults {
20 succeeded: Vec::new(),
21 errors: HashMap::new(),
22 };
23
24 for target in &plan.targets {
26 if !target.needs_copy {
27 results.succeeded.push(target.node.name.clone());
28 continue;
29 }
30
31 let store_uri = format!(
32 "ssh-ng://{}@{}",
33 target.node.target_user, target.node.target_host
34 );
35
36 match copy_closure(&target.toplevel_path, &store_uri) {
37 Ok(()) => {
38 results.succeeded.push(target.node.name.clone());
39 }
40 Err(e) => {
41 results.errors.insert(target.node.name.clone(), e);
42 }
43 }
44 }
45
46 Ok(results)
47}
48
49pub fn copy_closure(store_path: &str, store_uri: &str) -> Result<()> {
55 let output = Command::new("nix")
56 .args(["copy", "--no-check-sigs", "--to", store_uri, store_path])
57 .output()
58 .map_err(|e| NixError::CopyFailed {
59 host: store_uri.to_string(),
60 message: format!("failed to run nix copy: {}", e),
61 })?;
62
63 if !output.status.success() {
64 let stderr = String::from_utf8_lossy(&output.stderr);
65 return Err(NixError::CopyFailed {
66 host: store_uri.to_string(),
67 message: stderr.to_string(),
68 });
69 }
70
71 Ok(())
72}