diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2021-10-24 22:40:08 +0200 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2021-10-24 23:58:03 +0200 |
commit | a1a185370da27f2cc3df84d3a8d7141f9ce7db16 (patch) | |
tree | 6904f6f0549e89d160cbe635713e2864df25c21a /crates/common/src | |
parent | 524985f9449eb2f3a1d01b5f88dc74123d40c43a (diff) | |
download | rebel-a1a185370da27f2cc3df84d3a8d7141f9ce7db16.tar rebel-a1a185370da27f2cc3df84d3a8d7141f9ce7db16.zip |
Split defintions used by both runner and executor into separate crate
Also get rid of the Runner trait - different runner implementations do
not make sense with our current design.
Diffstat (limited to 'crates/common/src')
-rw-r--r-- | crates/common/src/error.rs | 119 | ||||
-rw-r--r-- | crates/common/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/common/src/string_hash.rs | 53 | ||||
-rw-r--r-- | crates/common/src/types.rs | 43 |
4 files changed, 218 insertions, 0 deletions
diff --git a/crates/common/src/error.rs b/crates/common/src/error.rs new file mode 100644 index 0000000..ba25af4 --- /dev/null +++ b/crates/common/src/error.rs @@ -0,0 +1,119 @@ +//! Serializable errors with context + +use std::{error::Error as _, fmt::Display, io, result}; + +use serde::{Deserialize, Serialize}; + +pub trait Contextualizable: Sized { + type Output; + + fn with_context<C: Display, F: FnOnce() -> C>(self, f: F) -> Self::Output; + + fn context<C: Display>(self, c: C) -> Self::Output { + self.with_context(|| c) + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub enum ErrorCause { + Code(i32), + String(String), +} + +impl Display for ErrorCause { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ErrorCause::Code(code) => io::Error::from_raw_os_error(*code).fmt(f), + ErrorCause::String(string) => f.write_str(string), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub struct Error { + pub cause: ErrorCause, + pub context: Vec<String>, +} + +impl Error { + pub fn new<D: Display>(cause: D) -> Self { + Error { + cause: ErrorCause::String(cause.to_string()), + context: Vec::new(), + } + } + + pub fn from_io(err: &io::Error) -> Self { + if let Some(source) = err + .source() + .and_then(|source| source.downcast_ref::<io::Error>()) + { + return Error::from_io(source).context(err.to_string()); + } + + let cause = match err.raw_os_error() { + Some(code) => ErrorCause::Code(code), + None => ErrorCause::String(err.to_string()), + }; + Error { + cause, + context: vec![], + } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("Error: ")?; + + let mut it = self.context.iter().rev(); + if let Some(ctx) = it.next() { + write!(f, "{}\n\nCaused by:\n ", ctx)?; + + for ctx in it { + write!(f, "{}\n ", ctx)?; + } + } + + self.cause.fmt(f) + } +} + +impl Contextualizable for Error { + type Output = Error; + fn with_context<C: Display, F: FnOnce() -> C>(self, f: F) -> Self::Output { + let Error { cause, mut context } = self; + context.push(f().to_string()); + Error { cause, context } + } +} + +impl<E> From<E> for Error +where + E: Into<io::Error>, +{ + fn from(err: E) -> Self { + Error::from_io(&err.into()) + } +} + +pub type Result<T> = result::Result<T, Error>; + +impl<T, E> Contextualizable for result::Result<T, E> +where + E: Into<Error>, +{ + type Output = Result<T>; + + fn with_context<C: Display, F: FnOnce() -> C>(self, f: F) -> Self::Output { + self.map_err(|err| err.into().with_context(f)) + } +} + +impl<T> Contextualizable for Option<T> { + type Output = Result<T>; + + fn with_context<C: Display, F: FnOnce() -> C>(self, f: F) -> Self::Output { + self.ok_or_else(|| Error::new(f())) + } +} diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs new file mode 100644 index 0000000..8d630dd --- /dev/null +++ b/crates/common/src/lib.rs @@ -0,0 +1,3 @@ +pub mod error; +pub mod string_hash; +pub mod types; diff --git a/crates/common/src/string_hash.rs b/crates/common/src/string_hash.rs new file mode 100644 index 0000000..a2b00db --- /dev/null +++ b/crates/common/src/string_hash.rs @@ -0,0 +1,53 @@ +use std::fmt::Display; + +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct StringHash(pub [u8; 32]); + +impl Display for StringHash { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&hex::encode(self.0)) + } +} + +impl std::fmt::Debug for StringHash { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "\"{}\"", self) + } +} + +impl Serialize for StringHash { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + hex::serialize(self.0, serializer) + } +} +impl<'de> Deserialize<'de> for StringHash { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + Ok(StringHash(hex::deserialize(deserializer)?)) + } +} + +macro_rules! stringhash_newtype { + ($id:ident) => { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] + pub struct $id(pub StringHash); + + impl Display for $id { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } + } + }; +} + +stringhash_newtype!(InputHash); +stringhash_newtype!(DependencyHash); +stringhash_newtype!(LayerHash); +stringhash_newtype!(ArchiveHash); diff --git a/crates/common/src/types.rs b/crates/common/src/types.rs new file mode 100644 index 0000000..51f9209 --- /dev/null +++ b/crates/common/src/types.rs @@ -0,0 +1,43 @@ +use std::{ + collections::{HashMap, HashSet}, + fmt::Display, +}; + +use serde::{Deserialize, Serialize}; + +use crate::string_hash::*; + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)] +pub struct TaskID { + pub recipe: String, + pub task: String, +} + +impl Display for TaskID { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:{}", self.recipe, self.task) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)] +#[serde(rename_all = "snake_case")] +pub enum Dependency { + Fetch { name: String, sha256: StringHash }, + Task { output: ArchiveHash, path: String }, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Task { + pub label: String, + pub command: String, + pub inherit: Vec<LayerHash>, + pub depends: HashSet<Dependency>, + pub outputs: HashMap<String, String>, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct TaskOutput { + pub input_hash: InputHash, + pub layer: Option<LayerHash>, + pub outputs: HashMap<String, ArchiveHash>, +} |