| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
use crate::canonical::{object_hash, Hash}; |
| 5 |
use oxy_core::cbor::{encode, Value}; |
| 6 |
use serde::{Deserialize, Serialize}; |
| 7 |
|
| 8 |
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] |
| 9 |
pub struct Receipt { |
| 10 |
pub job_name: String, |
| 11 |
#[serde(with = "hex32")] |
| 12 |
pub pipeline_hash: Hash, |
| 13 |
#[serde(with = "hex32")] |
| 14 |
pub scope_tree_hash: Hash, |
| 15 |
#[serde(with = "hex32s")] |
| 16 |
pub inputs: Vec<Hash>, |
| 17 |
#[serde(with = "hex32")] |
| 18 |
pub environment: Hash, |
| 19 |
#[serde(with = "hex32s")] |
| 20 |
pub outputs: Vec<Hash>, |
| 21 |
pub exit_code: u32, |
| 22 |
pub duration_ms: u64, |
| 23 |
} |
| 24 |
|
| 25 |
impl Receipt { |
| 26 |
pub fn encode(&self) -> Vec<u8> { |
| 27 |
let refs = |v: &[Hash]| Value::Array(v.iter().map(|h| Value::Bytes(h.to_vec())).collect()); |
| 28 |
encode(&Value::map([ |
| 29 |
(0, Value::Uint(1)), |
| 30 |
(1, Value::Text(self.job_name.clone())), |
| 31 |
(2, Value::Bytes(self.pipeline_hash.to_vec())), |
| 32 |
(3, Value::Bytes(self.scope_tree_hash.to_vec())), |
| 33 |
(4, refs(&self.inputs)), |
| 34 |
(5, Value::Bytes(self.environment.to_vec())), |
| 35 |
(6, refs(&self.outputs)), |
| 36 |
(7, Value::Uint(self.exit_code as u64)), |
| 37 |
(8, Value::Uint(self.duration_ms)), |
| 38 |
])) |
| 39 |
} |
| 40 |
|
| 41 |
|
| 42 |
pub fn hash(&self) -> Hash { |
| 43 |
object_hash("receipt", &self.encode()) |
| 44 |
} |
| 45 |
|
| 46 |
|
| 47 |
|
| 48 |
pub fn to_oxy(&self) -> oxy_core::receipt::Receipt { |
| 49 |
use oxy_core::hash::ObjectRef; |
| 50 |
oxy_core::receipt::Receipt { |
| 51 |
job_name: self.job_name.clone(), |
| 52 |
pipeline_hash: ObjectRef(self.pipeline_hash), |
| 53 |
scope_tree_hash: ObjectRef(self.scope_tree_hash), |
| 54 |
inputs: self.inputs.iter().map(|h| ObjectRef(*h)).collect(), |
| 55 |
environment: ObjectRef(self.environment), |
| 56 |
outputs: self.outputs.iter().map(|h| ObjectRef(*h)).collect(), |
| 57 |
exit_code: self.exit_code, |
| 58 |
duration_ms: self.duration_ms, |
| 59 |
} |
| 60 |
} |
| 61 |
} |
| 62 |
|
| 63 |
|
| 64 |
|
| 65 |
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] |
| 66 |
pub struct Environment { |
| 67 |
pub runtime: String, |
| 68 |
|
| 69 |
pub parts: Vec<(String, String)>, |
| 70 |
pub rootfs: String, |
| 71 |
pub argv: Vec<String>, |
| 72 |
pub env: Vec<(String, String)>, |
| 73 |
} |
| 74 |
|
| 75 |
impl Environment { |
| 76 |
pub fn hash(&self) -> Hash { |
| 77 |
let t = |s: &str| Value::Text(s.to_string()); |
| 78 |
let pairs = |v: &[(String, String)]| Value::Array(v.iter().map(|(a, b)| Value::Array(vec![t(a), t(b)])).collect()); |
| 79 |
let body = encode(&Value::map([ |
| 80 |
(0, t(&self.runtime)), |
| 81 |
(1, pairs(&self.parts)), |
| 82 |
(2, t(&self.rootfs)), |
| 83 |
(3, Value::Array(self.argv.iter().map(|a| t(a)).collect())), |
| 84 |
(4, pairs(&self.env)), |
| 85 |
])); |
| 86 |
object_hash("environment", &body) |
| 87 |
} |
| 88 |
} |
| 89 |
|
| 90 |
mod hex32 { |
| 91 |
use serde::{Deserialize, Deserializer, Serializer}; |
| 92 |
pub fn serialize<S: Serializer>(h: &[u8; 32], s: S) -> Result<S::Ok, S::Error> { |
| 93 |
s.serialize_str(&hex::encode(h)) |
| 94 |
} |
| 95 |
pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<[u8; 32], D::Error> { |
| 96 |
let s = String::deserialize(d)?; |
| 97 |
let v = hex::decode(&s).map_err(serde::de::Error::custom)?; |
| 98 |
v.try_into().map_err(|_| serde::de::Error::custom("expected 32 bytes")) |
| 99 |
} |
| 100 |
} |
| 101 |
|
| 102 |
mod hex32s { |
| 103 |
use serde::{Deserialize, Deserializer, Serializer}; |
| 104 |
pub fn serialize<S: Serializer>(v: &[[u8; 32]], s: S) -> Result<S::Ok, S::Error> { |
| 105 |
s.collect_seq(v.iter().map(hex::encode)) |
| 106 |
} |
| 107 |
pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<[u8; 32]>, D::Error> { |
| 108 |
let v = Vec::<String>::deserialize(d)?; |
| 109 |
v.into_iter() |
| 110 |
.map(|s| { |
| 111 |
let b = hex::decode(&s).map_err(serde::de::Error::custom)?; |
| 112 |
b.try_into().map_err(|_| serde::de::Error::custom("expected 32 bytes")) |
| 113 |
}) |
| 114 |
.collect() |
| 115 |
} |
| 116 |
} |