cargo/util/config/path.rs
1use super::{Config, StringList, Value};
2use serde::{de::Error, Deserialize};
3use std::path::PathBuf;
4
5/// Use with the `get` API to fetch a string that will be converted to a
6/// `PathBuf`. Relative paths are converted to absolute paths based on the
7/// location of the config file.
8#[derive(Debug, Deserialize, PartialEq, Clone)]
9#[serde(transparent)]
10pub struct ConfigRelativePath(Value<String>);
11
12impl ConfigRelativePath {
13 /// Returns the raw underlying configuration value for this key.
14 pub fn raw_value(&self) -> &str {
15 &self.0.val
16 }
17
18 /// Resolves this configuration-relative path to an absolute path.
19 ///
20 /// This will always return an absolute path where it's relative to the
21 /// location for configuration for this value.
22 pub fn resolve_path(&self, config: &Config) -> PathBuf {
23 self.0.definition.root(config).join(&self.0.val)
24 }
25
26 /// Resolves this configuration-relative path to either an absolute path or
27 /// something appropriate to execute from `PATH`.
28 ///
29 /// Values which don't look like a filesystem path (don't contain `/` or
30 /// `\`) will be returned as-is, and everything else will fall through to an
31 /// absolute path.
32 pub fn resolve_program(self, config: &Config) -> PathBuf {
33 config.string_to_path(self.0.val, &self.0.definition)
34 }
35}
36
37/// A config type that is a program to run.
38///
39/// This supports a list of strings like `['/path/to/program', 'somearg']`
40/// or a space separated string like `'/path/to/program somearg'`.
41///
42/// This expects the first value to be the path to the program to run.
43/// Subsequent values are strings of arguments to pass to the program.
44///
45/// Typically you should use `ConfigRelativePath::resolve_program` on the path
46/// to get the actual program.
47#[derive(Debug, Clone)]
48pub struct PathAndArgs {
49 pub path: ConfigRelativePath,
50 pub args: Vec<String>,
51}
52
53impl<'de> serde::Deserialize<'de> for PathAndArgs {
54 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
55 where
56 D: serde::Deserializer<'de>,
57 {
58 let vsl = Value::<StringList>::deserialize(deserializer)?;
59 let mut strings = vsl.val.0;
60 if strings.is_empty() {
61 return Err(D::Error::invalid_length(0, &"at least one element"));
62 }
63 let first = strings.remove(0);
64 let crp = Value {
65 val: first,
66 definition: vsl.definition,
67 };
68 Ok(PathAndArgs {
69 path: ConfigRelativePath(crp),
70 args: strings,
71 })
72 }
73}