cargo/util/context/
path.rs
1use super::{GlobalContext, StringList, Value};
2use regex::Regex;
3use serde::{de::Error, Deserialize};
4use std::path::PathBuf;
5
6#[derive(Debug, Deserialize, PartialEq, Clone)]
10#[serde(transparent)]
11pub struct ConfigRelativePath(Value<String>);
12
13impl ConfigRelativePath {
14 pub fn new(path: Value<String>) -> ConfigRelativePath {
15 ConfigRelativePath(path)
16 }
17
18 pub fn value(&self) -> &Value<String> {
20 &self.0
21 }
22
23 pub fn raw_value(&self) -> &str {
25 &self.0.val
26 }
27
28 pub fn resolve_path(&self, gctx: &GlobalContext) -> PathBuf {
33 self.0.definition.root(gctx).join(&self.0.val)
34 }
35
36 pub fn resolve_templated_path(
42 &self,
43 gctx: &GlobalContext,
44 replacements: impl IntoIterator<Item = (impl AsRef<str>, impl AsRef<str>)>,
45 ) -> Result<PathBuf, ResolveTemplateError> {
46 let mut value = self.0.val.clone();
47
48 for (from, to) in replacements {
49 value = value.replace(from.as_ref(), to.as_ref());
50 }
51
52 let re = Regex::new(r"\{(.*)\}").unwrap();
54 if let Some(caps) = re.captures(&value) {
55 return Err(ResolveTemplateError::UnexpectedVariable {
56 variable: caps[1].to_string(),
57 raw_template: self.0.val.clone(),
58 });
59 };
60
61 Ok(self.0.definition.root(gctx).join(&value))
62 }
63
64 pub fn resolve_program(&self, gctx: &GlobalContext) -> PathBuf {
71 gctx.string_to_path(&self.0.val, &self.0.definition)
72 }
73}
74
75#[derive(Debug, Clone, PartialEq)]
90pub struct PathAndArgs {
91 pub path: ConfigRelativePath,
92 pub args: Vec<String>,
93}
94
95impl<'de> serde::Deserialize<'de> for PathAndArgs {
96 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
97 where
98 D: serde::Deserializer<'de>,
99 {
100 let vsl = Value::<StringList>::deserialize(deserializer)?;
101 let mut strings = vsl.val.0;
102 if strings.is_empty() {
103 return Err(D::Error::invalid_length(0, &"at least one element"));
104 }
105 let first = strings.remove(0);
106 let crp = Value {
107 val: first,
108 definition: vsl.definition,
109 };
110 Ok(PathAndArgs {
111 path: ConfigRelativePath(crp),
112 args: strings,
113 })
114 }
115}
116
117impl PathAndArgs {
118 pub fn from_whitespace_separated_string(p: &Value<String>) -> PathAndArgs {
122 let mut iter = p.val.split_ascii_whitespace().map(str::to_string);
123 let val = iter.next().unwrap_or_default();
124 let args = iter.collect();
125 let crp = Value {
126 val,
127 definition: p.definition.clone(),
128 };
129 PathAndArgs {
130 path: ConfigRelativePath(crp),
131 args,
132 }
133 }
134}
135
136#[derive(Debug)]
137pub enum ResolveTemplateError {
138 UnexpectedVariable {
139 variable: String,
140 raw_template: String,
141 },
142}