cargo/util/context/
path.rs1use 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 if value.contains("{") {
62 return Err(ResolveTemplateError::UnexpectedBracket {
63 bracket_type: BracketType::Opening,
64 raw_template: self.0.val.clone(),
65 });
66 }
67
68 if value.contains("}") {
69 return Err(ResolveTemplateError::UnexpectedBracket {
70 bracket_type: BracketType::Closing,
71 raw_template: self.0.val.clone(),
72 });
73 }
74
75 Ok(self.0.definition.root(gctx).join(&value))
76 }
77
78 pub fn resolve_program(&self, gctx: &GlobalContext) -> PathBuf {
85 gctx.string_to_path(&self.0.val, &self.0.definition)
86 }
87}
88
89#[derive(Debug, Clone, PartialEq)]
104pub struct PathAndArgs {
105 pub path: ConfigRelativePath,
106 pub args: Vec<String>,
107}
108
109impl<'de> serde::Deserialize<'de> for PathAndArgs {
110 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
111 where
112 D: serde::Deserializer<'de>,
113 {
114 let vsl = Value::<StringList>::deserialize(deserializer)?;
115 let mut strings = vsl.val.0;
116 if strings.is_empty() {
117 return Err(D::Error::invalid_length(0, &"at least one element"));
118 }
119 let first = strings.remove(0);
120 let crp = Value {
121 val: first,
122 definition: vsl.definition,
123 };
124 Ok(PathAndArgs {
125 path: ConfigRelativePath(crp),
126 args: strings,
127 })
128 }
129}
130
131impl PathAndArgs {
132 pub fn from_whitespace_separated_string(p: &Value<String>) -> PathAndArgs {
136 let mut iter = p.val.split_ascii_whitespace().map(str::to_string);
137 let val = iter.next().unwrap_or_default();
138 let args = iter.collect();
139 let crp = Value {
140 val,
141 definition: p.definition.clone(),
142 };
143 PathAndArgs {
144 path: ConfigRelativePath(crp),
145 args,
146 }
147 }
148}
149
150#[derive(Debug)]
151pub enum ResolveTemplateError {
152 UnexpectedVariable {
153 variable: String,
154 raw_template: String,
155 },
156 UnexpectedBracket {
157 bracket_type: BracketType,
158 raw_template: String,
159 },
160}
161
162#[derive(Debug)]
163pub enum BracketType {
164 Opening,
165 Closing,
166}