use std::fmt::Display; use std::path::Path; use std::process::exit; use log::{debug, error, info, trace}; use reqwest::blocking::get; use manifest::build::Build; use pkgfile::PKGFile; use crate::package::identifier::{PackageIdentifier, PackageLocator}; use crate::types::fetch::TryFetch; pub mod identifier; pub mod installer; pub mod queue; #[derive(Eq, PartialEq)] pub struct Package { pub identifier: PackageIdentifier, pub pkgfile: PKGFile, is_installed: bool, is_indexed: bool, } impl Package { /// Create a new package from a package identifier and a package file. pub fn new(identifier: PackageIdentifier, pkgfile: PKGFile) -> Package { Package { identifier, pkgfile, is_installed: false, is_indexed: false, } } /// Get the package manifest. pub fn manifest(&self) -> manifest::Manifest { manifest::Manifest::try_from(self.pkgfile.manifest.clone()).unwrap() } /// Get package dependencies pub fn dependencies(&self) -> Vec { let mut dependencies = vec![]; for dependency in self.manifest().dependencies { let pkglocate = if let Ok(pl) = PackageLocator::try_from(dependency.clone()) { trace!("parsed pl successfully..."); pl } else { error!("Could not parse package locator: {:?} in dependencies.", &dependency); exit(1); }; let pkg = match Package::try_fetch(PackageIdentifier::PackageLocator(pkglocate)) { Ok(p) => p, Err(e) => { error!("Could not fetch dependency: {}", e); exit(1); } }; dependencies.push(pkg); } dependencies } pub fn build_dependencies(&self) -> Vec { let mut dependencies = vec![]; for dependency in self .manifest() .build .unwrap_or(Build::default()) .dependencies { let pkglocate = if let Ok(pl) = PackageLocator::try_from(dependency.clone()) { trace!("parsed pl successfully..."); pl } else { error!("Could not parse package locator: {:?} in dependencies.", &dependency); exit(1); }; let pkg = match Package::try_fetch(PackageIdentifier::PackageLocator(pkglocate)) { Ok(p) => p, Err(e) => { error!("Could not fetch dependency: {}", e); exit(1); } }; dependencies.push(pkg); } dependencies } /// Install the package. pub fn install(&mut self, build: bool) -> Result<(), installer::errors::InstallError> { let manifest = self.manifest(); let mut installer = installer::PackageInstaller::new( manifest.clone(), self.pkgfile.clone(), if build { info!("building package: {}...", if self.manifest().package.name.is_empty() { self.identifier.to_string() } else { self.manifest().package.name }); installer::InstallType::Build } else { info!("using binary install for package: {}...", if self.manifest().package.name.is_empty() { self.identifier.to_string() } else { self.manifest().package.name }); installer::InstallType::Bin }, ); match installer.install() { Ok(_) => { self.is_installed = true; Ok(()) } Err(e) => Err(e), } } /// Check if the package is installed. pub fn is_installed(&self) -> bool { self.is_installed } /// Check if the package is indexed. pub fn is_indexed(&self) -> bool { self.is_indexed } /// Remove the package from the system. pub fn remove(&mut self) -> Result<(), ()> { unimplemented!(); } } #[derive(Debug)] pub enum FetchError { HTTPError(reqwest::Error), IOError(std::io::Error), ParseError, } impl Display for FetchError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { FetchError::HTTPError(e) => write!(f, "HTTP Error: {}", e), FetchError::IOError(e) => write!(f, "IO Error: {}", e), FetchError::ParseError => write!(f, "Parse Error"), } } } impl TryFetch for Package { type Error = FetchError; /// Fetch a package from a package identifier. fn try_fetch(query: PackageIdentifier) -> Result { trace!("Fetching: {query:#?}"); let pkgfile = match &query { PackageIdentifier::Path(s) => match PKGFile::try_from(Path::new(&s)) { Ok(p) => Ok(p), Err(e) => Err(FetchError::ParseError) }, PackageIdentifier::URI(s) => { let mut bytes = Vec::new(); debug!("sending GET request..."); match get::(s.into()) { Ok(response) => { debug!("Got response!"); if let Ok(b) = response.bytes() { bytes.extend(b); } } Err(e) => return Err(FetchError::HTTPError(e)), }; // parse bytes as PKGFile match PKGFile::try_from(bytes) { Ok(pkgfile) => Ok(pkgfile), Err(_e) => Err(FetchError::ParseError), } } PackageIdentifier::PackageLocator(l) => unimplemented!() }; pkgfile .map(|p| Package::new(query, p)) } }