#
cargo/ops/cargo_add/
crate_spec.rs

    1//! Crate name parsing.
    2
    3use anyhow::Context as _;
    4
    5use super::Dependency;
    6use crate::util::toml_mut::dependency::RegistrySource;
    7use crate::CargoResult;
    8use cargo_util_schemas::manifest::PackageName;
    9
    10/// User-specified crate
    11///
    12/// This can be a
    13/// - Name (e.g. `docopt`)
    14/// - Name and a version req (e.g. `docopt@^0.8`)
    15#[derive(Debug)]
    16pub struct CrateSpec {
    17    /// Crate name
    18    name: String,
    19    /// Optional version requirement
    20    version_req: Option<String>,
    21}
    22
    23impl CrateSpec {
    24    /// Convert a string to a `Crate`
    25    pub fn resolve(pkg_id: &str) -> CargoResult<Self> {
    26        let (name, version) = pkg_id
    27            .split_once('@')
    28            .map(|(n, v)| (n, Some(v)))
    29            .unwrap_or((pkg_id, None));
    30
    31        PackageName::new(name)?;
    32
    33        if let Some(version) = version {
    34            semver::VersionReq::parse(version)
    35                .with_context(|| format!("invalid version requirement `{version}`"))?;
    36        }
    37
    38        let id = Self {
    39            name: name.to_owned(),
    40            version_req: version.map(|s| s.to_owned()),
    41        };
    42
    43        Ok(id)
    44    }
    45
    46    /// Generate a dependency entry for this crate specifier
    47    pub fn to_dependency(&self) -> CargoResult<Dependency> {
    48        let mut dep = Dependency::new(self.name());
    49        if let Some(version_req) = self.version_req() {
    50            dep = dep.set_source(RegistrySource::new(version_req));
    51        }
    52        Ok(dep)
    53    }
    54
    55    pub fn name(&self) -> &str {
    56        &self.name
    57    }
    58
    59    pub fn version_req(&self) -> Option<&str> {
    60        self.version_req.as_deref()
    61    }
    62}