From: Ian Jackson Date: Sun, 25 Jul 2021 17:43:32 +0000 (+0100) Subject: substitutions in string values X-Git-Tag: hippotat/1.0.0~446 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=568c964bffbfb547a6ffa46759528bac0485e696;p=hippotat.git substitutions in string values Signed-off-by: Ian Jackson --- diff --git a/Cargo.lock b/Cargo.lock index 7c607a9..2cb430d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -341,6 +341,7 @@ dependencies = [ "itertools", "lazy-regex", "log", + "parking_lot", "regex", "structopt", "tokio", diff --git a/Cargo.toml b/Cargo.toml index a343a6f..4037659 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ hyper = { version = "0.14", features = ["full"] } hyper-tls = "0.5" ipnet = "2" itertools = "0.10" +parking_lot = "0.11" regex = "1.5" log = "0.4" structopt = "0.3" diff --git a/src/config.rs b/src/config.rs index 76cafdb..e6d7e59 100644 --- a/src/config.rs +++ b/src/config.rs @@ -684,6 +684,64 @@ impl InstanceConfig { } }, } + + #[throws(AE)] + fn subst(var: &mut String, + kv: &mut dyn Iterator + ) { + let substs = kv + .map(|(k,v)| (k.to_string(), v.to_string())) + .collect::>(); + let bad = parking_lot::Mutex::new(vec![]); + *var = regex_replace_all!( + r#"%(?:%|\((\w+)\)s|.)"#, + &var, + |whole, k| (|| Ok::<_,String>({ + if whole == "%%" { "%" } + else if k != "" { + substs.get(k).ok_or_else( + || format!("unknown key %({})s", k) + )? + } else { + throw!(format!("bad percent escape {:?}", &whole)); + } + }))().unwrap_or_else(|e| { bad.lock().push(e); "" }) + ).into_owned(); + let bad = bad.into_inner(); + if ! bad.is_empty() { + throw!(anyhow!("substitution failed: {}", bad.iter().format("; "))); + } + } + + let ifname = match match end { + LinkEnd::Client => (&mut self.ifname_client, "ifname_client"), + LinkEnd::Server => (&mut self.ifname_server, "ifname_server"), + } { (var,name) => { + subst(var, &mut iter::empty()).context(name).context("interface name")?; + var + } }; + + { + use LinkEnd::*; + type DD<'d> = &'d dyn Display; + fn dv(v: &[T]) -> String { + format!("{}", v.iter().format(" ")) + } + let vnetwork = dv(&self.vnetwork); + let vroutes = dv(&self.vroutes); + + let keys = &["local", "peer", "rnets", "ifname"]; + let values = match end { + Server => [&self.vaddr as DD , &self.vrelay, &vnetwork, ifname], + Client => [&self.link.client as DD, &self.vaddr, &vroutes, ifname], + }; + subst( + &mut self.ipif, + &mut keys.iter().cloned() + .zip_eq(values) + .chain([( "mtu", &self.mtu as DD )].iter().cloned()), + ).context("ipif")?; + } } } diff --git a/src/prelude.rs b/src/prelude.rs index b7c1178..40847fa 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -7,6 +7,7 @@ pub use std::cmp::{min, max}; pub use std::fs; pub use std::fmt::{self, Debug, Display}; pub use std::io::{self, ErrorKind, Read as _}; +pub use std::iter; pub use std::mem; pub use std::net::{IpAddr, Ipv4Addr}; pub use std::path::{Path, PathBuf}; @@ -23,7 +24,7 @@ pub use hyper::Uri; pub use hyper_tls::HttpsConnector; pub use ipnet::IpNet; pub use itertools::{iproduct, Itertools}; -pub use lazy_regex::regex_is_match; +pub use lazy_regex::{regex_is_match, regex_replace_all}; pub use log::{debug, info, error}; pub use structopt::StructOpt; pub use tokio::task;