1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//! `blue run --receipts DIR` and `blue receipt verify FILE`.
//!
//! The run hands the runtime an [`Account`] that tallies host calls and knows
//! how to name a definition (`blue_lang_mondou::def_hash::identify`); each
//! held process writes its own receipt when an incarnation ends, and the run
//! writes one when it ends (`blue_lang_runtime::receipt`).
use std::path::{Path, PathBuf};
use std::process::ExitCode;
use blue_lang_runtime::pipeline::{Run, RunError};
use blue_lang_runtime::{Account, Hold};
#[derive(clap::Subcommand)]
pub enum ReceiptCmd {
/// Recompute a receipt's name from its bytes and check its form; any
/// edit fails.
Verify { file: PathBuf },
}
/// `blue receipt …`.
pub fn run(cmd: ReceiptCmd) -> ExitCode {
match cmd {
ReceiptCmd::Verify { file } => match blue_lang_runtime::receipt::verify(&file) {
Ok(hash) => {
println!("verified {hash}");
ExitCode::SUCCESS
}
Err(e) => {
eprintln!("blue: {e}");
ExitCode::FAILURE
}
},
}
}
/// The account every `blue run` gives of itself: crash traces name their
/// definition's `def_hash`, and with `receipts` each held process writes a
/// receipt there.
pub fn account(receipts: Option<PathBuf>) -> Account {
Account {
identify: Some(blue_lang_mondou::def_hash::identify),
receipts,
..Account::default()
}
}
/// The hold a run with receipts runs under: its own, or the top, so every
/// host call goes through a counting shim.
pub fn hold_for(hold: Option<Hold>, receipts: Option<&Path>) -> Option<Hold> {
match (hold, receipts) {
(None, Some(_)) => Some(Hold::from(blue_lang_waku::Waku::top())),
(hold, _) => hold,
}
}
/// Write the run's receipt into `dir`. A receipt that cannot be written is
/// said and costs the run nothing.
pub fn write_run(
dir: &Path,
hold: Option<&Hold>,
account: &Account,
outcome: &Result<Run, RunError>,
) {
let Some(hold) = hold else { return };
let receipt = blue_lang_runtime::receipt::of_run(
hold,
account,
blue_lang_runtime::receipt::exit_of(outcome),
);
if let Err(e) = blue_lang_runtime::receipt::write(dir, &receipt) {
eprintln!(
"blue: the run's receipt could not be written to {}: {e}",
dir.display()
);
}
}