Skip to main content

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}