diff --git a/pkgfile/src/lib.rs b/pkgfile/src/lib.rs index 407055c..5db8e6f 100644 --- a/pkgfile/src/lib.rs +++ b/pkgfile/src/lib.rs @@ -1,3 +1,8 @@ +use std::error::Error; +use std::fmt::{Display, Formatter}; +use std::io; +use std::path::Path; + #[derive(Debug, Clone)] pub struct PKGFile { pub manifest: String, @@ -23,28 +28,56 @@ impl Default for PKGFile { } } -impl TryFrom> for PKGFile { - type Error = (); +#[derive(Debug)] +pub enum PKGFileError { + IOError(io::Error), + ParsingError(String) +} - fn try_from(value: Vec) -> Result { +impl Display for PKGFileError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + PKGFileError::IOError(e) => write!(f, "IOError: {}", e), + PKGFileError::ParsingError(s) => write!(f, "ParsingError: {}", s) + } + } +} + +impl Error for PKGFileError {} + +impl<'a> TryFrom<&'a Path> for PKGFile { + type Error = PKGFileError; + fn try_from(path: &'a Path) -> Result { + let d = match std::fs::read(path) { + Ok(d) => d, + Err(e) => return Err(PKGFileError::IOError(e)) + }; + PKGFile::try_from(d) + } +} + +impl TryFrom> for PKGFile { + type Error = PKGFileError; + + fn try_from(value: Vec) -> Result { match value[0] { 1 => { let header: Vec = value[..3].iter().map(|v| u32::from(*v)).collect(); let manifest_size: u32 = (header[1] << 8) | header[2]; if manifest_size > value.len() as u32 { - return Err(()); + return Err(PKGFileError::ParsingError("Invalid header length".into())); } Ok(PKGFile { manifest: match String::from_utf8( value[3..(manifest_size as usize + 3)].to_vec(), ) { Ok(s) => s, - _ => return Err(()), + _ => return Err(PKGFileError::ParsingError("Could not parse manifest".into())), }, data: value[(manifest_size as usize + 3)..].to_vec(), }) } - _ => Err(()), + _ => Err(PKGFileError::ParsingError("Unknown pkgfile version".into())), } } } diff --git a/pkgr/src/commands.rs b/pkgr/src/commands.rs index a1904a7..01a1619 100644 --- a/pkgr/src/commands.rs +++ b/pkgr/src/commands.rs @@ -7,6 +7,7 @@ use log::{debug, error, info, trace, warn}; use std::process::exit; use crate::CONFIG; use crate::process::Process; +use crate::types::fetch::TryFetch; #[derive(Parser, Debug)] #[clap(name = "pkgr", version)] @@ -60,7 +61,7 @@ impl Command { info!("Parsing package..."); trace!("Fetching package: {}", package_identifier); - let mut pkg = Package::fetch(package_identifier.clone()).unwrap(); + let mut pkg = Package::try_fetch(package_identifier.clone()).unwrap(); debug!("manifest size: {}kb", pkg.pkgfile.manifest.len() / 1024); debug!("files size: {}kb", pkg.pkgfile.data.len() / 1024); diff --git a/pkgr/src/main.rs b/pkgr/src/main.rs index 0191923..7ce334c 100644 --- a/pkgr/src/main.rs +++ b/pkgr/src/main.rs @@ -4,13 +4,13 @@ use clap::Parser; use log::trace; - mod commands; mod logging; mod package; mod process; mod tmpfs; mod config; +mod types; thread_local! { static CONFIG: config::Config = config::Config::from_path("/etc/pkgr.toml") diff --git a/pkgr/src/package/fetch.rs b/pkgr/src/package/fetch.rs deleted file mode 100644 index bc385ea..0000000 --- a/pkgr/src/package/fetch.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::package::identifier::PackageLocator; -use pkgfile::PKGFile; -use reqwest::blocking::get; -use std::error::Error; -use std::fmt::Display; -use std::io::Read; - -#[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 Error for FetchError {} - -pub fn fetch_by_path>(path: S) -> Result { - std::fs::read(path.into()) - .map_err(|e| FetchError::IOError(e)) - .and_then(|bytes| PKGFile::try_from(bytes).map_err(|_| FetchError::ParseError)) -} - -pub fn fetch_by_uri>(uri: S) -> Result { - // get file contents as bytes - let mut bytes = Vec::new(); - match get(uri.into()) { - Ok(response) => { - match response.take(1024 * 1024).read_to_end(&mut bytes) { - Ok(_) => (), - Err(e) => return Err(FetchError::IOError(e)), - }; - } - 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), - } -} - -pub fn fetch_by_package_locator(_package_locator: PackageLocator) -> Result { - // TODO: search index for package locator - Ok(PKGFile::default()) -} diff --git a/pkgr/src/package/installer/mod.rs b/pkgr/src/package/installer/mod.rs index a28f849..3300ddf 100644 --- a/pkgr/src/package/installer/mod.rs +++ b/pkgr/src/package/installer/mod.rs @@ -8,6 +8,7 @@ use std::process::exit; use crate::CONFIG; use crate::package::identifier::{PackageIdentifier, PackageLocator}; use crate::package::Package; +use crate::types::fetch::TryFetch; pub mod errors; @@ -67,7 +68,7 @@ impl PackageInstaller { let build_manifest = self.manifest.build.clone().unwrap(); // TODO: Check dependencies for pkg_tuple in build_manifest.dependencies { - let mut pkg = Package::fetch( + let mut pkg = Package::try_fetch( PackageIdentifier::PackageLocator( PackageLocator::from(pkg_tuple) ) diff --git a/pkgr/src/package/mod.rs b/pkgr/src/package/mod.rs index 79de18d..9ade687 100644 --- a/pkgr/src/package/mod.rs +++ b/pkgr/src/package/mod.rs @@ -1,6 +1,11 @@ +use std::fmt::Display; +use std::path::Path; use log::{info, trace}; +use reqwest::blocking::get; +use pkgfile::PKGFile; +use crate::package::identifier::PackageIdentifier; +use crate::types::fetch::TryFetch; -pub mod fetch; pub mod identifier; pub mod installer; @@ -13,7 +18,7 @@ pub struct Package { impl Package { /// Create a new package from a package identifier and a package file. - pub fn new(identifier: identifier::PackageIdentifier, pkgfile: pkgfile::PKGFile) -> Package { + pub fn new(identifier: PackageIdentifier, pkgfile: PKGFile) -> Package { Package { identifier, pkgfile, @@ -22,29 +27,6 @@ impl Package { } } - /// Fetch a package from a package identifier. - pub fn fetch( - package_identifier: identifier::PackageIdentifier, - ) -> Result { - match &package_identifier { - identifier::PackageIdentifier::Path(path) => { - trace!("fetching package from path: {}", path); - let pkgfile = fetch::fetch_by_path(path).unwrap(); - Ok(Package::new(package_identifier, pkgfile)) - } - identifier::PackageIdentifier::URI(url) => { - trace!("fetching package from uri: {}", url); - let pkgfile = fetch::fetch_by_uri(url).unwrap(); - Ok(Package::new(package_identifier, pkgfile)) - } - identifier::PackageIdentifier::PackageLocator(locator) => { - trace!("fetching package from locator: {}", locator); - let pkgfile = fetch::fetch_by_package_locator(locator.clone()).unwrap(); - Ok(Package::new(package_identifier, pkgfile)) - } - } - } - /// Get the package manifest. pub fn manifest(&self) -> manifest::Manifest { manifest::Manifest::try_from(self.pkgfile.manifest.clone()).unwrap() @@ -96,3 +78,54 @@ impl Package { 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 { + 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(); + match get::(s.into()) { + Ok(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) => Ok(PKGFile::default()) + }; + + pkgfile + .map(|p| Package::new(query, p)) + } +} \ No newline at end of file diff --git a/pkgr/src/types/fetch.rs b/pkgr/src/types/fetch.rs new file mode 100644 index 0000000..d3b7eac --- /dev/null +++ b/pkgr/src/types/fetch.rs @@ -0,0 +1,10 @@ +/// Get a result from an external source +pub trait Fetch { + fn fetch(query: Q) -> R; +} + +/// Try to get a result from an external source +pub trait TryFetch { + type Error; + fn try_fetch(query: Q) -> Result; +} \ No newline at end of file diff --git a/pkgr/src/types/mod.rs b/pkgr/src/types/mod.rs new file mode 100644 index 0000000..c798af5 --- /dev/null +++ b/pkgr/src/types/mod.rs @@ -0,0 +1 @@ +pub mod fetch; \ No newline at end of file