chiark / gitweb /
substitutions in string values
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 25 Jul 2021 17:43:32 +0000 (18:43 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 25 Jul 2021 18:19:46 +0000 (19:19 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Cargo.lock
Cargo.toml
src/config.rs
src/prelude.rs

index 7c607a920200b9a19d4da41addeaffd7ed76f536..2cb430d59d7415e5c4bd6829f04813f88e366595 100644 (file)
@@ -341,6 +341,7 @@ dependencies = [
  "itertools",
  "lazy-regex",
  "log",
+ "parking_lot",
  "regex",
  "structopt",
  "tokio",
index a343a6fe83e99f5ce6c115efc06ef0c26a9130e9..4037659af72d9f4c33d3db88dffebd7019ec10da 100644 (file)
@@ -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"
index 76cafdb0620950e4f43f9740b419ebc3872955d8..e6d7e5920590b70838c64c3cc27790ed0818782b 100644 (file)
@@ -684,6 +684,64 @@ impl InstanceConfig {
         }
       },
     }
+
+    #[throws(AE)]
+    fn subst(var: &mut String,
+             kv: &mut dyn Iterator<Item=(&'static str, &dyn Display)>
+    ) {
+      let substs = kv
+        .map(|(k,v)| (k.to_string(), v.to_string()))
+        .collect::<HashMap<String, String>>();
+      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<T:Display>(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")?;
+    }
   }
 }
 
index b7c11781e78203a6f405bc9945d7c63f400de70b..40847fa8e9d60aea74c9f5ab6c0d397f844a1126 100644 (file)
@@ -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;