use crate::{manifest::DependencyType, names::PackageNames, Project}; use semver::Version; use serde::{Deserialize, Serialize}; use std::{ collections::BTreeMap, fmt::{Debug, Display}, path::Path, }; pub mod pesde; pub(crate) fn hash(struc: &S) -> String { use std::{collections::hash_map::DefaultHasher, hash::Hasher}; let mut hasher = DefaultHasher::new(); struc.hash(&mut hasher); hasher.finish().to_string() } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] #[serde(untagged)] pub enum DependencySpecifiers { Pesde(pesde::PesdeDependencySpecifier), } pub trait DependencySpecifier: Debug + Display {} impl DependencySpecifier for DependencySpecifiers {} impl Display for DependencySpecifiers { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { DependencySpecifiers::Pesde(specifier) => write!(f, "{}", specifier), } } } #[derive(Debug, Serialize, Deserialize, Clone)] pub enum PackageRefs { Pesde(pesde::PesdePackageRef), } pub trait PackageRef: Debug { fn dependencies(&self) -> &BTreeMap; } impl PackageRef for PackageRefs { fn dependencies(&self) -> &BTreeMap { match self { PackageRefs::Pesde(pkg_ref) => pkg_ref.dependencies(), } } } pub type ResolveResult = (PackageNames, BTreeMap); #[derive(Debug, Eq, PartialEq, Hash, Clone)] pub enum PackageSources { Pesde(pesde::PesdePackageSource), } pub trait PackageSource: Debug { type Ref: PackageRef; type Specifier: DependencySpecifier; type RefreshError: std::error::Error; type ResolveError: std::error::Error; type DownloadError: std::error::Error; fn refresh(&self, _project: &Project) -> Result<(), Self::RefreshError> { Ok(()) } fn resolve( &self, specifier: &Self::Specifier, project: &Project, ) -> Result, Self::ResolveError>; fn download( &self, pkg_ref: &Self::Ref, destination: &Path, project: &Project, ) -> Result<(), Self::DownloadError>; } impl PackageSource for PackageSources { type Ref = PackageRefs; type Specifier = DependencySpecifiers; type RefreshError = errors::RefreshError; type ResolveError = errors::ResolveError; type DownloadError = errors::DownloadError; fn refresh(&self, project: &Project) -> Result<(), Self::RefreshError> { match self { PackageSources::Pesde(source) => source.refresh(project).map_err(Into::into), } } fn resolve( &self, specifier: &Self::Specifier, project: &Project, ) -> Result, Self::ResolveError> { match (self, specifier) { (PackageSources::Pesde(source), DependencySpecifiers::Pesde(specifier)) => source .resolve(specifier, project) .map(|(name, results)| { ( name, results .into_iter() .map(|(version, pkg_ref)| (version, PackageRefs::Pesde(pkg_ref))) .collect(), ) }) .map_err(Into::into), _ => Err(errors::ResolveError::Mismatch), } } fn download( &self, pkg_ref: &Self::Ref, destination: &Path, project: &Project, ) -> Result<(), Self::DownloadError> { match (self, pkg_ref) { (PackageSources::Pesde(source), PackageRefs::Pesde(pkg_ref)) => source .download(pkg_ref, destination, project) .map_err(Into::into), _ => Err(errors::DownloadError::Mismatch), } } } pub mod errors { use thiserror::Error; #[derive(Debug, Error)] #[non_exhaustive] pub enum RefreshError { #[error("error refreshing pesde package source")] Pesde(#[from] crate::source::pesde::errors::RefreshError), } #[derive(Debug, Error)] #[non_exhaustive] pub enum ResolveError { #[error("mismatched dependency specifier for source")] Mismatch, #[error("error resolving pesde package")] Pesde(#[from] crate::source::pesde::errors::ResolveError), } #[derive(Debug, Error)] #[non_exhaustive] pub enum DownloadError { #[error("mismatched package ref for source")] Mismatch, #[error("error downloading pesde package")] Pesde(#[from] crate::source::pesde::errors::DownloadError), } }