use std::collections::BTreeMap; use crate::{ manifest::{errors, DependencyType}, names::wally::WallyPackageName, source::{specifiers::DependencySpecifiers, wally::specifier::WallyDependencySpecifier}, }; use semver::{Version, VersionReq}; use serde::{Deserialize, Deserializer}; use tracing::instrument; #[derive(Deserialize, Clone, Debug)] #[serde(rename_all = "lowercase")] pub enum Realm { #[serde(alias = "dev")] Shared, Server, } #[derive(Deserialize, Clone, Debug)] #[serde(rename_all = "kebab-case")] pub struct WallyPackage { pub name: WallyPackageName, pub version: Version, pub registry: url::Url, pub realm: Realm, } pub fn deserialize_specifiers<'de, D: Deserializer<'de>>( deserializer: D, ) -> Result, D::Error> { // specifier is in form of `name@version_req` BTreeMap::::deserialize(deserializer)? .into_iter() .map(|(k, v)| { let (name, version) = v.split_once('@').ok_or_else(|| { serde::de::Error::custom("invalid specifier format, expected `name@version_req`") })?; Ok(( k, WallyDependencySpecifier { name: name.parse().map_err(serde::de::Error::custom)?, version: VersionReq::parse(version).map_err(serde::de::Error::custom)?, index: None, }, )) }) .collect() } #[derive(Deserialize, Clone, Debug)] #[serde(rename_all = "kebab-case")] pub struct WallyManifest { pub package: WallyPackage, #[serde(default, deserialize_with = "deserialize_specifiers")] pub dependencies: BTreeMap, #[serde(default, deserialize_with = "deserialize_specifiers")] pub server_dependencies: BTreeMap, #[serde(default, deserialize_with = "deserialize_specifiers")] pub dev_dependencies: BTreeMap, } impl WallyManifest { /// Get all dependencies from the manifest #[instrument(skip(self), ret(level = "trace"), level = "debug")] pub fn all_dependencies( &self, ) -> Result< BTreeMap, errors::AllDependenciesError, > { let mut all_deps = BTreeMap::new(); for (deps, ty) in [ (&self.dependencies, DependencyType::Standard), (&self.server_dependencies, DependencyType::Standard), (&self.dev_dependencies, DependencyType::Dev), ] { for (alias, spec) in deps { let mut spec = spec.clone(); spec.index = Some(self.package.registry.to_string()); if all_deps .insert(alias.clone(), (DependencySpecifiers::Wally(spec), ty)) .is_some() { return Err(errors::AllDependenciesError::AliasConflict(alias.clone())); } } } Ok(all_deps) } }