1use std::path::PathBuf;
11
12use clap::Parser;
13
14#[derive(Parser, Debug)]
21#[command(
22 name = "confium-publish",
23 about = "Author a signed registry release for a Confium plugin",
24 long_about = "Confium plugin publishing tool — load, manifest, sign, output.",
25 disable_version_flag = true,
29)]
30pub struct PublishArgs {
31 pub artifact: PathBuf,
33
34 #[arg(long)]
36 pub name: Option<String>,
37
38 #[arg(long)]
40 pub version: Option<String>,
41
42 #[arg(long)]
44 pub publisher: String,
45
46 #[arg(long)]
48 pub signing_key: PathBuf,
49
50 #[arg(long, default_value = "git@github.com:confium/registry.git")]
52 pub registry: String,
53
54 #[arg(long)]
57 pub artifact_base: Option<String>,
58
59 #[arg(long, value_delimiter = ',')]
62 pub interfaces: Option<Vec<String>>,
63
64 #[arg(long, value_delimiter = ',')]
66 pub algorithms: Option<Vec<String>>,
67
68 #[arg(long, default_value_t = false)]
71 pub dry_run: bool,
72}
73
74pub fn parse_interface_overrides(raw: &[String]) -> Result<Vec<(String, u8)>, String> {
78 let mut out = Vec::with_capacity(raw.len());
79 for entry in raw {
80 let (name, ver) = entry
81 .split_once(':')
82 .ok_or_else(|| format!("interface '{entry}' missing ':version'"))?;
83 let version: u8 = ver
84 .parse()
85 .map_err(|_| format!("interface '{name}' version '{ver}' not a u8"))?;
86 out.push((name.to_string(), version));
87 }
88 Ok(out)
89}
90
91pub fn parse_algorithm_overrides(raw: &[String]) -> Result<Vec<(String, Vec<String>)>, String> {
94 let mut out = Vec::with_capacity(raw.len());
95 for entry in raw {
96 let (iface, algos) = entry
97 .split_once(':')
98 .ok_or_else(|| format!("algorithm '{entry}' missing ':list'"))?;
99 let list: Vec<String> = algos.split(';').map(str::to_string).collect();
100 out.push((iface.to_string(), list));
101 }
102 Ok(out)
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn parse_interface_overrides_splits_name_version() {
111 let raw = vec!["hash:0".to_string(), "aead:1".to_string()];
112 let got = parse_interface_overrides(&raw).unwrap();
113 assert_eq!(got, vec![("hash".into(), 0), ("aead".into(), 1)]);
114 }
115
116 #[test]
117 fn parse_interface_overrides_rejects_missing_colon() {
118 let raw = vec!["hash".to_string()];
119 assert!(parse_interface_overrides(&raw).is_err());
120 }
121
122 #[test]
123 fn parse_algorithm_overrides_splits_semicolons() {
124 let raw = vec!["hash:SHA-256;SHA-512".to_string()];
125 let got = parse_algorithm_overrides(&raw).unwrap();
126 assert_eq!(
127 got,
128 vec![("hash".into(), vec!["SHA-256".into(), "SHA-512".into()])]
129 );
130 }
131}