use cargo_metadata::PackageId;
use semver::Version;
use crate::package_source::PackageSource;
#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct PackageIdInfo {
pub source: PackageSource,
pub path: String,
pub name: String,
pub version: Version,
}
impl PackageIdInfo {
pub fn from_package_id(pkg_id: &PackageId) -> Option<Self> {
let Some((source, tail)) = pkg_id.repr.split_once('+') else {
eprintln!("[ERROR] Cannot extract source: {pkg_id}");
return None;
};
let Some((path, tail)) = tail.split_once('#') else {
eprintln!("[ERROR] Cannot extract path: {pkg_id}");
return None;
};
let (name, version) = if let Some(name_version) = tail.split_once('@') {
name_version
} else {
let Some((_, name)) = path.rsplit_once("/") else {
eprintln!("[ERROR] Cannot extract package name: {path}");
return None;
};
(name, tail)
};
let source = source.into();
let name = if source == PackageSource::Git
&& let Some((name, _)) = name.split_once('?')
{
name
} else {
name
};
let version = match Version::parse(version) {
anyhow::Result::Ok(version) => version,
Err(err) => {
eprintln!("[ERROR] Cannot parse version: {version}. Error: {err}");
return None;
}
};
Some(PackageIdInfo {
source,
path: path.into(),
name: name.into(),
version,
})
}
pub fn parse_source(pkg_id: &PackageId) -> Option<PackageSource> {
let Some((source, _tail)) = pkg_id.repr.split_once('+') else {
eprintln!("[ERROR] Cannot extract source: {pkg_id}");
return None;
};
Some(source.into())
}
}
impl From<&PackageIdInfo> for PackageId {
fn from(value: &PackageIdInfo) -> Self {
Self {
repr: format!(
"{}+{}#{}@{}",
value.source.as_str(),
value.path,
value.name,
value.version
),
}
}
}