diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2024-04-20 14:28:05 +0200 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2024-04-20 14:38:17 +0200 |
commit | e9bf0fc40c0eb7e9d4228b804d62f31b0a136528 (patch) | |
tree | 7872f587782d5635eadbf82ae861d474d4da2efe /crates/rebel-common | |
parent | 35e68444dd5e9d3d5fc39409c48be6eb3fa05e07 (diff) | |
download | rebel-e9bf0fc40c0eb7e9d4228b804d62f31b0a136528.tar rebel-e9bf0fc40c0eb7e9d4228b804d62f31b0a136528.zip |
Rename directories to match crate names
Diffstat (limited to 'crates/rebel-common')
-rw-r--r-- | crates/rebel-common/Cargo.toml | 12 | ||||
-rw-r--r-- | crates/rebel-common/src/error.rs | 119 | ||||
-rw-r--r-- | crates/rebel-common/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/rebel-common/src/string_hash.rs | 53 | ||||
-rw-r--r-- | crates/rebel-common/src/types.rs | 54 |
5 files changed, 241 insertions, 0 deletions
diff --git a/crates/rebel-common/Cargo.toml b/crates/rebel-common/Cargo.toml new file mode 100644 index 0000000..954ebe5 --- /dev/null +++ b/crates/rebel-common/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rebel-common" +version = "0.1.0" +authors = ["Matthias Schiffer <mschiffer@universe-factory.net>"] +license = "MIT" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +hex = { version = "0.4.3", features = ["std", "serde"] } +serde = { version = "1", features = ["derive"] } diff --git a/crates/rebel-common/src/error.rs b/crates/rebel-common/src/error.rs new file mode 100644 index 0000000..ba25af4 --- /dev/null +++ b/crates/rebel-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/rebel-common/src/lib.rs b/crates/rebel-common/src/lib.rs new file mode 100644 index 0000000..8d630dd --- /dev/null +++ b/crates/rebel-common/src/lib.rs @@ -0,0 +1,3 @@ +pub mod error; +pub mod string_hash; +pub mod types; diff --git a/crates/rebel-common/src/string_hash.rs b/crates/rebel-common/src/string_hash.rs new file mode 100644 index 0000000..a2b00db --- /dev/null +++ b/crates/rebel-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/rebel-common/src/types.rs b/crates/rebel-common/src/types.rs new file mode 100644 index 0000000..2a06275 --- /dev/null +++ b/crates/rebel-common/src/types.rs @@ -0,0 +1,54 @@ +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, + target_dir: String, + sha256: StringHash, + }, + Task { + output: ArchiveHash, + path: String, + }, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Task { + pub label: String, + pub command: String, + pub workdir: String, + pub rootfs: ArchiveHash, + pub ancestors: Vec<LayerHash>, + pub depends: HashSet<Dependency>, + pub outputs: HashMap<String, String>, + pub pins: HashMap<ArchiveHash, String>, + pub force_run: bool, +} + +#[derive(Clone, Debug, Deserialize, Serialize, Default)] +pub struct TaskOutput { + pub input_hash: Option<InputHash>, + pub layer: Option<LayerHash>, + pub outputs: HashMap<String, ArchiveHash>, +} |