summaryrefslogtreecommitdiffstats
path: root/crates/rebel-common
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2024-04-20 14:28:05 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2024-04-20 14:38:17 +0200
commite9bf0fc40c0eb7e9d4228b804d62f31b0a136528 (patch)
tree7872f587782d5635eadbf82ae861d474d4da2efe /crates/rebel-common
parent35e68444dd5e9d3d5fc39409c48be6eb3fa05e07 (diff)
downloadrebel-e9bf0fc40c0eb7e9d4228b804d62f31b0a136528.tar
rebel-e9bf0fc40c0eb7e9d4228b804d62f31b0a136528.zip
Rename directories to match crate names
Diffstat (limited to 'crates/rebel-common')
-rw-r--r--crates/rebel-common/Cargo.toml12
-rw-r--r--crates/rebel-common/src/error.rs119
-rw-r--r--crates/rebel-common/src/lib.rs3
-rw-r--r--crates/rebel-common/src/string_hash.rs53
-rw-r--r--crates/rebel-common/src/types.rs54
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>,
+}