use std::collections::{BTreeMap, BTreeSet}; pub struct OutputInfo { pub path: String, pub hash_algo: String, pub hash: String, } pub struct DerivationData { pub name: String, pub outputs: BTreeMap, pub input_drvs: BTreeMap>, pub input_srcs: BTreeSet, pub platform: String, pub builder: String, pub args: Vec, pub env: BTreeMap, } fn escape_string(s: &str) -> String { let mut result = String::with_capacity(s.len() + 2); result.push('"'); for c in s.chars() { match c { '"' => result.push_str("\\\""), '\\' => result.push_str("\\\\"), '\n' => result.push_str("\\n"), '\r' => result.push_str("\\r"), '\t' => result.push_str("\\t"), _ => result.push(c), } } result.push('"'); result } fn quote_string(s: &str) -> String { format!("\"{}\"", s) } impl DerivationData { pub fn generate_aterm(&self) -> String { let mut output_entries = Vec::new(); for (name, info) in &self.outputs { output_entries.push(format!( "({},{},{},{})", quote_string(name), quote_string(&info.path), quote_string(&info.hash_algo), quote_string(&info.hash), )); } let outputs = output_entries.join(","); let mut input_drv_entries = Vec::new(); for (drv_path, output_names) in &self.input_drvs { let sorted_outs: Vec = output_names.iter().map(|s| quote_string(s)).collect(); let out_list = format!("[{}]", sorted_outs.join(",")); input_drv_entries.push(format!("({},{})", quote_string(drv_path), out_list)); } let input_drvs = input_drv_entries.join(","); let input_srcs: Vec = self.input_srcs.iter().map(|s| quote_string(s)).collect(); let input_srcs = input_srcs.join(","); let args: Vec = self.args.iter().map(|s| escape_string(s)).collect(); let args = args.join(","); let mut env_entries: Vec = Vec::new(); for (k, v) in &self.env { env_entries.push(format!("({},{})", escape_string(k), escape_string(v))); } format!( "Derive([{}],[{}],[{}],{},{},[{}],[{}])", outputs, input_drvs, input_srcs, quote_string(&self.platform), escape_string(&self.builder), args, env_entries.join(","), ) } pub fn generate_aterm_modulo(&self, input_drv_hashes: &BTreeMap) -> String { let mut output_entries = Vec::new(); for (name, info) in &self.outputs { output_entries.push(format!( "({},{},{},{})", quote_string(name), quote_string(&info.path), quote_string(&info.hash_algo), quote_string(&info.hash), )); } let outputs = output_entries.join(","); let mut input_drv_entries = Vec::new(); for (drv_hash, outputs_csv) in input_drv_hashes { let mut sorted_outs: Vec<&str> = outputs_csv.split(',').collect(); sorted_outs.sort(); let out_list: Vec = sorted_outs.iter().map(|s| quote_string(s)).collect(); let out_list = format!("[{}]", out_list.join(",")); input_drv_entries.push(format!("({},{})", quote_string(drv_hash), out_list)); } let input_drvs = input_drv_entries.join(","); let input_srcs: Vec = self.input_srcs.iter().map(|s| quote_string(s)).collect(); let input_srcs = input_srcs.join(","); let args: Vec = self.args.iter().map(|s| escape_string(s)).collect(); let args = args.join(","); let mut env_entries: Vec = Vec::new(); for (k, v) in &self.env { env_entries.push(format!("({},{})", escape_string(k), escape_string(v))); } format!( "Derive([{}],[{}],[{}],{},{},[{}],[{}])", outputs, input_drvs, input_srcs, quote_string(&self.platform), escape_string(&self.builder), args, env_entries.join(","), ) } pub fn collect_references(&self) -> Vec { let mut refs = BTreeSet::new(); for src in &self.input_srcs { refs.insert(src.clone()); } for drv_path in self.input_drvs.keys() { refs.insert(drv_path.clone()); } refs.into_iter().collect() } }