From a1a185370da27f2cc3df84d3a8d7141f9ce7db16 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 24 Oct 2021 22:40:08 +0200 Subject: 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. --- Cargo.lock | 10 +++- Cargo.toml | 5 +- crates/common/Cargo.toml | 12 ++++ crates/common/src/error.rs | 119 ++++++++++++++++++++++++++++++++++++++ crates/common/src/lib.rs | 3 + crates/common/src/string_hash.rs | 53 +++++++++++++++++ crates/common/src/types.rs | 43 ++++++++++++++ src/context.rs | 7 ++- src/executor.rs | 24 ++++---- src/main.rs | 4 +- src/paths.rs | 2 +- src/recipe.rs | 7 +-- src/resolve.rs | 3 +- src/runner/container/init.rs | 4 +- src/runner/container/jobserver.rs | 3 +- src/runner/container/mod.rs | 19 +++--- src/runner/container/ns.rs | 3 +- src/runner/container/tar.rs | 4 +- src/runner/container/task.rs | 37 ++++++------ src/runner/container/util/fs.rs | 2 +- src/runner/container/util/unix.rs | 2 +- src/runner/mod.rs | 33 +---------- src/task.rs | 3 +- src/template.rs | 4 +- src/types.rs | 65 --------------------- src/util/error.rs | 119 -------------------------------------- src/util/mod.rs | 1 - 27 files changed, 313 insertions(+), 278 deletions(-) create mode 100644 crates/common/Cargo.toml create mode 100644 crates/common/src/error.rs create mode 100644 crates/common/src/lib.rs create mode 100644 crates/common/src/string_hash.rs create mode 100644 crates/common/src/types.rs delete mode 100644 src/types.rs delete mode 100644 src/util/error.rs delete mode 100644 src/util/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 1c3d6bc..9cee169 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -747,13 +747,13 @@ dependencies = [ "digest 0.9.0", "enum-kinds", "handlebars", - "hex", "indoc", "ipc-channel", "lazy_static", "libc", "nix", "olpc-cjson", + "rebel-common", "regex", "scoped-tls-hkt", "serde", @@ -764,6 +764,14 @@ dependencies = [ "walkdir", ] +[[package]] +name = "rebel-common" +version = "0.1.0" +dependencies = [ + "hex", + "serde", +] + [[package]] name = "redox_syscall" version = "0.2.10" diff --git a/Cargo.toml b/Cargo.toml index 25b2105..6024b79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,14 +7,17 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[workspace] + [dependencies] +common = { path = "crates/common", package = "rebel-common" } + blake3 = { version = "1.0.0", features = ["traits-preview"] } capctl = "0.2.0" clap = "3.0.0-beta.2" digest = "0.9.0" enum-kinds = "0.5.1" handlebars = "4.1.3" -hex = { version = "0.4.3", features = ["std", "serde"] } indoc = "1.0.3" ipc-channel = { git = "https://github.com/servo/ipc-channel.git" } lazy_static = "1.4.0" diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml new file mode 100644 index 0000000..2d5b70d --- /dev/null +++ b/crates/common/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rebel-common" +version = "0.1.0" +authors = ["Matthias Schiffer "] +license = "MIT" +edition = "2018" + +# 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/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>(self, f: F) -> Self::Output; + + fn context(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, +} + +impl Error { + pub fn new(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::()) + { + 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>(self, f: F) -> Self::Output { + let Error { cause, mut context } = self; + context.push(f().to_string()); + Error { cause, context } + } +} + +impl From for Error +where + E: Into, +{ + fn from(err: E) -> Self { + Error::from_io(&err.into()) + } +} + +pub type Result = result::Result; + +impl Contextualizable for result::Result +where + E: Into, +{ + type Output = Result; + + fn with_context C>(self, f: F) -> Self::Output { + self.map_err(|err| err.into().with_context(f)) + } +} + +impl Contextualizable for Option { + type Output = Result; + + fn with_context 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(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + hex::serialize(self.0, serializer) + } +} +impl<'de> Deserialize<'de> for StringHash { + fn deserialize(deserializer: D) -> Result + 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, + pub depends: HashSet, + pub outputs: HashMap, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct TaskOutput { + pub input_hash: InputHash, + pub layer: Option, + pub outputs: HashMap, +} diff --git a/src/context.rs b/src/context.rs index 4ec74a3..8953f0d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -13,12 +13,15 @@ use lazy_static::lazy_static; use regex::Regex; use serde::Serialize; +use common::{ + error::{self, Contextualizable}, + types::TaskID, +}; + use crate::{ args::{self, arg, Arg, ArgMapping, ArgType, PlatformRelation, TaskArgs}, paths, task::*, - types::TaskID, - util::error::{self, Contextualizable}, }; #[derive(Debug, Clone, Copy)] diff --git a/src/executor.rs b/src/executor.rs index a13b358..9828543 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -3,14 +3,14 @@ use std::collections::{HashMap, HashSet}; use indoc::indoc; use ipc_channel::ipc; +use common::{error::*, string_hash::*, types::*}; + use crate::{ context::{Context, TaskRef}, paths, resolve, - runner::{self, TaskOutput}, + runner::Runner, task::*, template::TemplateEngine, - types::*, - util::error::*, }; pub struct Executor<'ctx> { @@ -66,13 +66,13 @@ impl<'ctx> Executor<'ctx> { .all(|dep| self.tasks_done.contains_key(&dep)) } - fn fetch_deps(&self, task: &TaskRef<'ctx>) -> Result> { + fn fetch_deps(&self, task: &TaskRef<'ctx>) -> Result> { let task_def = &self.ctx[task.id]; task_def .fetch .iter() .map(|Fetch { name, sha256 }| { - Ok(runner::Dependency::Fetch { + Ok(Dependency::Fetch { name: self.tpl.eval_raw(name, &task.args).with_context(|| { format!("Failed to evaluate fetch filename for task {}", task) })?, @@ -82,7 +82,7 @@ impl<'ctx> Executor<'ctx> { .collect() } - fn task_deps(&self, task: &TaskRef<'ctx>) -> Result> { + fn task_deps(&self, task: &TaskRef<'ctx>) -> Result> { Ok(self .fetch_deps(task)? .into_iter() @@ -96,7 +96,7 @@ impl<'ctx> Executor<'ctx> { .expect("invalid runtime depends of build_depends") .into_iter() .filter_map(|dep| self.tasks_done[&dep.task].outputs.get(dep.output)) - .map(|&output| runner::Dependency::Task { + .map(|&output| Dependency::Task { output, path: "".to_string(), }), @@ -111,7 +111,7 @@ impl<'ctx> Executor<'ctx> { .expect("invalid runtime depends of host_depends") .into_iter() .filter_map(|dep| self.tasks_done[&dep.task].outputs.get(dep.output)) - .map(|&output| runner::Dependency::Task { + .map(|&output| Dependency::Task { output, path: paths::abs(paths::TASK_SYSROOT), }), @@ -208,7 +208,7 @@ impl<'ctx> Executor<'ctx> { fn spawn_one( &self, task_ref: &TaskRef<'ctx>, - runner: &impl runner::Runner, + runner: &Runner, ) -> Result>> { let task_def = &self.ctx[task_ref.id]; let task_deps = self.task_deps(task_ref)?; @@ -235,7 +235,7 @@ impl<'ctx> Executor<'ctx> { format!("Failed to evaluate command template for task {}", task_ref) })?; - let task = runner::Task { + let task = Task { label: format!("{:#}", task_ref), command, inherit: inherit_chain, @@ -246,7 +246,7 @@ impl<'ctx> Executor<'ctx> { Ok(runner.spawn(&task)) } - fn run_tasks(&mut self, runner: &impl runner::Runner) -> Result<()> { + fn run_tasks(&mut self, runner: &Runner) -> Result<()> { while let Some(task_ref) = self.tasks_runnable.pop() { let channel = self.spawn_one(&task_ref, runner)?; let id = self @@ -312,7 +312,7 @@ impl<'ctx> Executor<'ctx> { Ok(()) } - pub fn run(&mut self, runner: &impl runner::Runner) -> Result<()> { + pub fn run(&mut self, runner: &Runner) -> Result<()> { while !(self.tasks_runnable.is_empty() && self.tasks_running.is_empty()) { self.run_tasks(runner)?; self.wait_for_task()?; diff --git a/src/main.rs b/src/main.rs index ee432c3..aff055a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,6 @@ mod resolve; mod runner; mod task; mod template; -mod types; -mod util; use clap::Parser; @@ -22,7 +20,7 @@ struct Opts { fn main() { let opts: Opts = Opts::parse(); - let runner = unsafe { runner::container::ContainerRunner::new() }.unwrap(); + let runner = unsafe { runner::container::Runner::new() }.unwrap(); let ctx = context::Context::new(recipe::read_recipes("examples").unwrap()); diff --git a/src/paths.rs b/src/paths.rs index 6ecf3db..632f030 100644 --- a/src/paths.rs +++ b/src/paths.rs @@ -36,7 +36,7 @@ //! └── depends/ # overlayed on rootfs in container //! ``` -use crate::types::*; +use common::string_hash::*; pub const ROOTFS_ARCHIVE: &str = "build/rootfs.tar"; diff --git a/src/recipe.rs b/src/recipe.rs index 5155474..04f356b 100644 --- a/src/recipe.rs +++ b/src/recipe.rs @@ -4,10 +4,9 @@ use scoped_tls_hkt::scoped_thread_local; use serde::{Deserialize, Deserializer}; use walkdir::WalkDir; -use crate::{ - task::{RecipeMeta, TaskDef}, - types::TaskID, -}; +use common::types::*; + +use crate::task::{RecipeMeta, TaskDef}; scoped_thread_local!(static CURRENT_RECIPE: str); diff --git a/src/resolve.rs b/src/resolve.rs index ac1dbb5..338ce3f 100644 --- a/src/resolve.rs +++ b/src/resolve.rs @@ -2,9 +2,10 @@ use std::collections::{HashMap, HashSet}; use std::fmt; use std::rc::Rc; +use common::types::TaskID; + use crate::args::TaskArgs; use crate::context::{self, Context, OutputRef, TaskRef}; -use crate::types::TaskID; #[derive(Debug)] pub struct DepChain<'ctx>(pub Vec>); diff --git a/src/runner/container/init.rs b/src/runner/container/init.rs index 8ebbdd0..783faf4 100644 --- a/src/runner/container/init.rs +++ b/src/runner/container/init.rs @@ -2,8 +2,10 @@ use std::fs::File; use nix::mount::{self, MsFlags}; +use common::error::*; + use super::{tar, util::fs}; -use crate::{paths, util::error::*}; +use crate::paths; fn prepare_rootfs(rootfs: &str) -> Result<()> { tar::unpack(File::open(paths::ROOTFS_ARCHIVE)?, rootfs) diff --git a/src/runner/container/jobserver.rs b/src/runner/container/jobserver.rs index b8fc9f3..3b6c856 100644 --- a/src/runner/container/jobserver.rs +++ b/src/runner/container/jobserver.rs @@ -2,8 +2,9 @@ use std::{os::unix::prelude::RawFd, slice}; use nix::{errno::Errno, fcntl::OFlag, poll, unistd}; +use common::error::*; + use super::util::unix; -use crate::util::error::*; #[derive(Debug)] pub struct Jobserver { diff --git a/src/runner/container/mod.rs b/src/runner/container/mod.rs index 17f4042..375b7ed 100644 --- a/src/runner/container/mod.rs +++ b/src/runner/container/mod.rs @@ -14,22 +14,23 @@ use nix::{ }; use serde::{Deserialize, Serialize}; +use common::{error::*, types::*}; + use self::{ jobserver::Jobserver, util::{clone, unix}, }; -use crate::{runner, util::error::*}; #[derive(Debug, Deserialize, Serialize)] enum Message { - Request(runner::Task, ipc::IpcSender>), + Request(Task, ipc::IpcSender>), } fn handle_request( jobserver: Jobserver, channel: ipc::IpcReceiver, - task: runner::Task, - reply_channel: ipc::IpcSender>, + task: Task, + reply_channel: ipc::IpcSender>, ) -> (Jobserver, ipc::IpcReceiver) { let child = |(mut jobserver, channel): (Jobserver, ipc::IpcReceiver)| { drop(channel); @@ -95,11 +96,11 @@ fn runner(uid: Uid, gid: Gid, channel: ipc::IpcReceiver) { } } -pub struct ContainerRunner { +pub struct Runner { channel: ipc::IpcSender, } -impl ContainerRunner { +impl Runner { /// Creates a new container runner /// /// Unsafe: Do not call in multithreaded processes @@ -120,12 +121,12 @@ impl ContainerRunner { .expect("clone()") .1; - Ok(ContainerRunner { channel: tx }) + Ok(Runner { channel: tx }) } } -impl super::Runner for ContainerRunner { - fn spawn(&self, task: &runner::Task) -> ipc::IpcReceiver> { +impl Runner { + pub fn spawn(&self, task: &Task) -> ipc::IpcReceiver> { let (reply_tx, reply_rx) = ipc::channel().expect("IPC channel creation failed"); self.channel diff --git a/src/runner/container/ns.rs b/src/runner/container/ns.rs index f0abb6f..a075931 100644 --- a/src/runner/container/ns.rs +++ b/src/runner/container/ns.rs @@ -4,8 +4,9 @@ use nix::{ unistd::{self, Gid, Pid, Uid}, }; +use common::error::*; + use super::util::clone; -use crate::util::error::*; pub fn mount_proc() { mount::mount::<_, _, _, str>(Some("proc"), "/proc", Some("proc"), MsFlags::empty(), None) diff --git a/src/runner/container/tar.rs b/src/runner/container/tar.rs index 2b61520..9306775 100644 --- a/src/runner/container/tar.rs +++ b/src/runner/container/tar.rs @@ -12,11 +12,13 @@ use nix::{ sys::wait, }; +use common::error::*; + use super::{ ns, util::{fs, Checkable}, }; -use crate::{paths, util::error::*}; +use crate::paths; pub fn pack>(archive: &mut W, source: P) -> Result<()> { let (mut piper, pipew) = fs::pipe()?; diff --git a/src/runner/container/task.rs b/src/runner/container/task.rs index 39dcd81..296c1a0 100644 --- a/src/runner/container/task.rs +++ b/src/runner/container/task.rs @@ -17,12 +17,14 @@ use nix::{ use serde::Serialize; use tee_readwrite::TeeWriter; +use common::{error::*, string_hash::*, types::*}; + use super::{ jobserver::Jobserver, ns, tar, util::{cjson, fs, Checkable}, }; -use crate::{paths, runner, types::*, util::error::*}; +use crate::paths; const BUILD_UID: Uid = Uid::from_raw(1000); const BUILD_GID: Gid = Gid::from_raw(1000); @@ -32,18 +34,18 @@ type DependencyHasher = blake3::Hasher; type LayerHasher = blake3::Hasher; type ArchiveHasher = blake3::Hasher; -fn dependency_hash(dep: &runner::Dependency) -> DependencyHash { +fn dependency_hash(dep: &Dependency) -> DependencyHash { DependencyHash(StringHash( cjson::digest::(dep).unwrap().into(), )) } -fn input_hash(task: &runner::Task) -> InputHash { +fn input_hash(task: &Task) -> InputHash { #[derive(Debug, Serialize)] struct HashInput<'a> { pub command: &'a str, pub inherit: &'a [LayerHash], - pub depends: HashMap, + pub depends: HashMap, pub outputs: &'a HashMap, } let input = HashInput { @@ -62,7 +64,7 @@ fn input_hash(task: &runner::Task) -> InputHash { )) } -fn init_task(input_hash: &InputHash, task: &runner::Task) -> Result { +fn init_task(input_hash: &InputHash, task: &Task) -> Result { // Remove metadata first to ensure task invalidation fs::ensure_removed(&paths::task_cache_filename(input_hash))?; @@ -163,7 +165,7 @@ fn unpack_dependency, P2: AsRef>(filename: P1, dest: P2) - }) } -fn unpack_dependencies(input_hash: &InputHash, task: &runner::Task) -> Result<()> { +fn unpack_dependencies(input_hash: &InputHash, task: &Task) -> Result<()> { let task_tmp_dir = paths::task_tmp_dir(input_hash); let downloads_dir = paths::join(&[&task_tmp_dir, paths::TASK_DLDIR]); let depends_dir = paths::join(&[&task_tmp_dir, paths::TASK_TMP_DEPENDS_SUBDIR]); @@ -173,13 +175,13 @@ fn unpack_dependencies(input_hash: &InputHash, task: &runner::Task) -> Result<() for dep in &task.depends { match dep { - runner::Dependency::Fetch { name, .. } => { + Dependency::Fetch { name, .. } => { fs::copy( paths::join(&[paths::DOWNLOADS_DIR, name]), paths::join(&[&downloads_dir, name]), )?; } - runner::Dependency::Task { output, path } => { + Dependency::Task { output, path } => { unpack_dependency( paths::archive_filename(output), paths::join(&[&depends_dir, path]), @@ -223,10 +225,7 @@ fn collect_output(input_hash: &InputHash, path: &str) -> Result Result> { +fn collect_outputs(input_hash: &InputHash, task: &Task) -> Result> { let mut ret = HashMap::new(); for (name, path) in &task.outputs { @@ -238,7 +237,7 @@ fn collect_outputs( Ok(ret) } -fn run_task(input_hash: &InputHash, task: &runner::Task, mut jobserver: Jobserver) -> Result<()> { +fn run_task(input_hash: &InputHash, task: &Task, mut jobserver: Jobserver) -> Result<()> { let _workdir_mount = init_task(input_hash, task).context("Failed to initialize task")?; unpack_dependencies(input_hash, task).context("Failed to unpack dependencies")?; let _rootfs_mount = init_task_rootfs(input_hash).context("Failed to initialize task rootfs")?; @@ -392,9 +391,9 @@ fn move_layer(input_hash: &InputHash, hash: &Option) -> Result<()> { fn run_and_hash_task( input_hash: &InputHash, - task: &runner::Task, + task: &Task, jobserver: Jobserver, -) -> Result { +) -> Result { run_task(input_hash, task, jobserver)?; let outputs = collect_outputs(input_hash, task)?; @@ -402,14 +401,14 @@ fn run_and_hash_task( let layer = hash_layer(input_hash)?; move_layer(input_hash, &layer)?; - Ok(runner::TaskOutput { + Ok(TaskOutput { input_hash: *input_hash, layer, outputs, }) } -fn load_cached(input_hash: &InputHash) -> Result { +fn load_cached(input_hash: &InputHash) -> Result { let filename = paths::task_cache_filename(input_hash); let file = fs::open(&filename)?; @@ -417,7 +416,7 @@ fn load_cached(input_hash: &InputHash) -> Result { .with_context(|| format!("Failed to read task cache data from {}", filename)) } -fn save_cached(input_hash: &InputHash, output: &runner::TaskOutput) -> Result<()> { +fn save_cached(input_hash: &InputHash, output: &TaskOutput) -> Result<()> { fs::mkdir(&paths::task_state_dir(input_hash))?; let tmp_filename = paths::task_cache_tmp_filename(input_hash); @@ -431,7 +430,7 @@ fn save_cached(input_hash: &InputHash, output: &runner::TaskOutput) -> Result<() Ok(()) } -pub fn handle(task: runner::Task, jobserver: Jobserver) -> Result { +pub fn handle(task: Task, jobserver: Jobserver) -> Result { let input_hash = input_hash(&task); if let Ok(task_output) = load_cached(&input_hash) { diff --git a/src/runner/container/util/fs.rs b/src/runner/container/util/fs.rs index cfc7610..099a339 100644 --- a/src/runner/container/util/fs.rs +++ b/src/runner/container/util/fs.rs @@ -11,7 +11,7 @@ use nix::{ unistd, }; -use crate::util::error::*; +use common::error::*; pub fn open>(path: P) -> Result { fs::File::open(path.as_ref()) diff --git a/src/runner/container/util/unix.rs b/src/runner/container/util/unix.rs index 1b7722c..48db764 100644 --- a/src/runner/container/util/unix.rs +++ b/src/runner/container/util/unix.rs @@ -6,7 +6,7 @@ use nix::{ unistd::Pid, }; -use crate::util::error::*; +use common::error::*; pub fn set_blocking(fd: RawFd, blocking: bool) -> Result<()> { let flags = unsafe { diff --git a/src/runner/mod.rs b/src/runner/mod.rs index b140a84..b88045a 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -1,34 +1,3 @@ pub mod container; -use ipc_channel::ipc; -use serde::{Deserialize, Serialize}; -use std::collections::{HashMap, HashSet}; - -use crate::{types::*, util::error::*}; - -#[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, - pub depends: HashSet, - pub outputs: HashMap, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct TaskOutput { - pub input_hash: InputHash, - pub layer: Option, - pub outputs: HashMap, -} - -pub trait Runner { - fn spawn(&self, task: &Task) -> ipc::IpcReceiver>; -} +pub use container::Runner; diff --git a/src/task.rs b/src/task.rs index 594e849..fe9572c 100644 --- a/src/task.rs +++ b/src/task.rs @@ -2,10 +2,11 @@ use std::collections::{HashMap, HashSet}; use serde::Deserialize; +use common::{string_hash::StringHash, types::TaskID}; + use crate::{ args::{ArgMapping, ArgType}, recipe, - types::{StringHash, TaskID}, }; #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Hash, Default)] diff --git a/src/template.rs b/src/template.rs index 947fa76..0caa30d 100644 --- a/src/template.rs +++ b/src/template.rs @@ -1,6 +1,8 @@ use handlebars::Handlebars; -use crate::{args::TaskArgs, util::error::*}; +use common::error::*; + +use crate::args::TaskArgs; fn escape(s: &str) -> String { format!("'{}'", s.replace("'", "'\\''")) diff --git a/src/types.rs b/src/types.rs deleted file mode 100644 index 4bb019f..0000000 --- a/src/types.rs +++ /dev/null @@ -1,65 +0,0 @@ -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(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - hex::serialize(self.0, serializer) - } -} -impl<'de> Deserialize<'de> for StringHash { - fn deserialize(deserializer: D) -> Result - 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); - -#[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) - } -} diff --git a/src/util/error.rs b/src/util/error.rs deleted file mode 100644 index ba25af4..0000000 --- a/src/util/error.rs +++ /dev/null @@ -1,119 +0,0 @@ -//! 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>(self, f: F) -> Self::Output; - - fn context(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, -} - -impl Error { - pub fn new(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::()) - { - 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>(self, f: F) -> Self::Output { - let Error { cause, mut context } = self; - context.push(f().to_string()); - Error { cause, context } - } -} - -impl From for Error -where - E: Into, -{ - fn from(err: E) -> Self { - Error::from_io(&err.into()) - } -} - -pub type Result = result::Result; - -impl Contextualizable for result::Result -where - E: Into, -{ - type Output = Result; - - fn with_context C>(self, f: F) -> Self::Output { - self.map_err(|err| err.into().with_context(f)) - } -} - -impl Contextualizable for Option { - type Output = Result; - - fn with_context C>(self, f: F) -> Self::Output { - self.ok_or_else(|| Error::new(f())) - } -} diff --git a/src/util/mod.rs b/src/util/mod.rs deleted file mode 100644 index a91e735..0000000 --- a/src/util/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod error; -- cgit v1.2.3