refactor: move prints to cli via EventListener trait
This commit is contained in:
parent
801ab3989e
commit
4ad74bef1f
|
@ -59,6 +59,7 @@ dependencies = [
|
||||||
"ignore",
|
"ignore",
|
||||||
"indoc",
|
"indoc",
|
||||||
"miette",
|
"miette",
|
||||||
|
"owo-colors",
|
||||||
"pallas-addresses",
|
"pallas-addresses",
|
||||||
"pallas-codec",
|
"pallas-codec",
|
||||||
"pallas-crypto",
|
"pallas-crypto",
|
||||||
|
@ -110,7 +111,6 @@ dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
"ignore",
|
"ignore",
|
||||||
"miette",
|
"miette",
|
||||||
"owo-colors",
|
|
||||||
"pallas",
|
"pallas",
|
||||||
"pallas-traverse",
|
"pallas-traverse",
|
||||||
"petgraph",
|
"petgraph",
|
||||||
|
|
|
@ -15,6 +15,7 @@ hex = "0.4.3"
|
||||||
ignore = "0.4.18"
|
ignore = "0.4.18"
|
||||||
indoc = "1.0"
|
indoc = "1.0"
|
||||||
miette = { version = "5.3.0", features = ["fancy"] }
|
miette = { version = "5.3.0", features = ["fancy"] }
|
||||||
|
owo-colors = "3.5.0"
|
||||||
pallas-addresses = "0.14.0"
|
pallas-addresses = "0.14.0"
|
||||||
pallas-codec = "0.14.0"
|
pallas-codec = "0.14.0"
|
||||||
pallas-crypto = "0.14.0"
|
pallas-crypto = "0.14.0"
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
pub mod cmd;
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
use aiken_project::{config::Config, Project};
|
use aiken_project::{
|
||||||
|
config::Config,
|
||||||
|
telemetry::{self, TestInfo},
|
||||||
|
Project,
|
||||||
|
};
|
||||||
use miette::IntoDiagnostic;
|
use miette::IntoDiagnostic;
|
||||||
use std::env;
|
use owo_colors::OwoColorize;
|
||||||
use std::path::PathBuf;
|
use uplc::machine::cost_model::ExBudget;
|
||||||
|
|
||||||
|
pub mod cmd;
|
||||||
|
|
||||||
pub fn with_project<A>(directory: Option<PathBuf>, mut action: A) -> miette::Result<()>
|
pub fn with_project<A>(directory: Option<PathBuf>, mut action: A) -> miette::Result<()>
|
||||||
where
|
where
|
||||||
A: FnMut(&mut Project) -> Result<(), aiken_project::error::Error>,
|
A: FnMut(&mut Project<Terminal>) -> Result<(), aiken_project::error::Error>,
|
||||||
{
|
{
|
||||||
let project_path = if let Some(d) = directory {
|
let project_path = if let Some(d) = directory {
|
||||||
d
|
d
|
||||||
|
@ -17,7 +23,7 @@ where
|
||||||
|
|
||||||
let config = Config::load(project_path.clone()).into_diagnostic()?;
|
let config = Config::load(project_path.clone()).into_diagnostic()?;
|
||||||
|
|
||||||
let mut project = Project::new(config, project_path);
|
let mut project = Project::new(config, project_path, Terminal::default());
|
||||||
|
|
||||||
let build_result = action(&mut project);
|
let build_result = action(&mut project);
|
||||||
|
|
||||||
|
@ -37,3 +43,97 @@ where
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
pub struct Terminal;
|
||||||
|
|
||||||
|
impl telemetry::EventListener for Terminal {
|
||||||
|
fn handle_event(&self, event: telemetry::Event) {
|
||||||
|
match event {
|
||||||
|
telemetry::Event::CompilingPackage { .. } => todo!(),
|
||||||
|
telemetry::Event::RunningTests => {
|
||||||
|
println!("\n{}\n", "Running tests...".bold().underline().purple());
|
||||||
|
}
|
||||||
|
telemetry::Event::FinishedTests { tests } => {
|
||||||
|
let (max_mem, max_cpu) = tests.iter().fold(
|
||||||
|
(0, 0),
|
||||||
|
|(max_mem, max_cpu), TestInfo { spent_budget, .. }| {
|
||||||
|
if spent_budget.mem >= max_mem && spent_budget.cpu >= max_cpu {
|
||||||
|
(spent_budget.mem, spent_budget.cpu)
|
||||||
|
} else if spent_budget.mem > max_mem {
|
||||||
|
(spent_budget.mem, max_cpu)
|
||||||
|
} else if spent_budget.cpu > max_cpu {
|
||||||
|
(max_mem, spent_budget.cpu)
|
||||||
|
} else {
|
||||||
|
(max_mem, max_cpu)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let max_mem = max_mem.to_string().len() as i32;
|
||||||
|
let max_cpu = max_cpu.to_string().len() as i32;
|
||||||
|
|
||||||
|
for test_info in &tests {
|
||||||
|
println!("{}", fmt_test(test_info, max_mem, max_cpu))
|
||||||
|
}
|
||||||
|
|
||||||
|
let (n_passed, n_failed) =
|
||||||
|
tests
|
||||||
|
.iter()
|
||||||
|
.fold((0, 0), |(n_passed, n_failed), test_info| {
|
||||||
|
if test_info.is_passing {
|
||||||
|
(n_passed + 1, n_failed)
|
||||||
|
} else {
|
||||||
|
(n_passed, n_failed + 1)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
format!(
|
||||||
|
"\n Summary: {} test(s), {}; {}.",
|
||||||
|
tests.len(),
|
||||||
|
format!("{} passed", n_passed).bright_green(),
|
||||||
|
format!("{} failed", n_failed).bright_red()
|
||||||
|
)
|
||||||
|
.bold()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_test(test_info: &TestInfo, max_mem: i32, max_cpu: i32) -> String {
|
||||||
|
let TestInfo {
|
||||||
|
is_passing,
|
||||||
|
test,
|
||||||
|
spent_budget,
|
||||||
|
} = test_info;
|
||||||
|
|
||||||
|
let ExBudget { mem, cpu } = spent_budget;
|
||||||
|
|
||||||
|
format!(
|
||||||
|
" [{}] [mem: {}, cpu: {}] {}::{}",
|
||||||
|
if *is_passing {
|
||||||
|
"PASS".bold().green().to_string()
|
||||||
|
} else {
|
||||||
|
"FAIL".bold().red().to_string()
|
||||||
|
},
|
||||||
|
pad_left(mem.to_string(), max_mem, " "),
|
||||||
|
pad_left(cpu.to_string(), max_cpu, " "),
|
||||||
|
test.module.blue(),
|
||||||
|
test.name.bright_blue()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pad_left(mut text: String, n: i32, delimiter: &str) -> String {
|
||||||
|
let diff = n - text.len() as i32;
|
||||||
|
|
||||||
|
if diff.is_positive() {
|
||||||
|
for _ in 0..diff {
|
||||||
|
text.insert_str(0, delimiter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text
|
||||||
|
}
|
||||||
|
|
|
@ -23,4 +23,3 @@ walkdir = "2.3.2"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
pallas = "0.14.0"
|
pallas = "0.14.0"
|
||||||
pallas-traverse = "0.14.0"
|
pallas-traverse = "0.14.0"
|
||||||
owo-colors = "3.5.0"
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ pub mod error;
|
||||||
pub mod format;
|
pub mod format;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod script;
|
pub mod script;
|
||||||
|
pub mod telemetry;
|
||||||
|
|
||||||
use aiken_lang::{
|
use aiken_lang::{
|
||||||
ast::{Definition, Function, ModuleKind, TypedFunction},
|
ast::{Definition, Function, ModuleKind, TypedFunction},
|
||||||
|
@ -18,7 +19,6 @@ use aiken_lang::{
|
||||||
IdGenerator,
|
IdGenerator,
|
||||||
};
|
};
|
||||||
use miette::NamedSource;
|
use miette::NamedSource;
|
||||||
use owo_colors::OwoColorize;
|
|
||||||
use pallas::{
|
use pallas::{
|
||||||
codec::minicbor,
|
codec::minicbor,
|
||||||
ledger::{addresses::Address, primitives::babbage},
|
ledger::{addresses::Address, primitives::babbage},
|
||||||
|
@ -26,6 +26,7 @@ use pallas::{
|
||||||
use pallas_traverse::ComputeHash;
|
use pallas_traverse::ComputeHash;
|
||||||
use script::Script;
|
use script::Script;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
use telemetry::{EventListener, TestInfo};
|
||||||
use uplc::{
|
use uplc::{
|
||||||
ast::{DeBruijn, Program},
|
ast::{DeBruijn, Program},
|
||||||
machine::cost_model::ExBudget,
|
machine::cost_model::ExBudget,
|
||||||
|
@ -35,6 +36,7 @@ use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
error::{Error, Warning},
|
error::{Error, Warning},
|
||||||
module::{CheckedModule, CheckedModules, ParsedModule, ParsedModules},
|
module::{CheckedModule, CheckedModules, ParsedModule, ParsedModules},
|
||||||
|
telemetry::Event,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -51,7 +53,10 @@ pub const MINT: &str = "mint";
|
||||||
pub const WITHDRAWL: &str = "withdrawl";
|
pub const WITHDRAWL: &str = "withdrawl";
|
||||||
pub const VALIDATOR_NAMES: [&str; 4] = [SPEND, CERT, MINT, WITHDRAWL];
|
pub const VALIDATOR_NAMES: [&str; 4] = [SPEND, CERT, MINT, WITHDRAWL];
|
||||||
|
|
||||||
pub struct Project {
|
pub struct Project<T>
|
||||||
|
where
|
||||||
|
T: EventListener,
|
||||||
|
{
|
||||||
config: Config,
|
config: Config,
|
||||||
defined_modules: HashMap<String, PathBuf>,
|
defined_modules: HashMap<String, PathBuf>,
|
||||||
id_gen: IdGenerator,
|
id_gen: IdGenerator,
|
||||||
|
@ -59,10 +64,14 @@ pub struct Project {
|
||||||
root: PathBuf,
|
root: PathBuf,
|
||||||
sources: Vec<Source>,
|
sources: Vec<Source>,
|
||||||
pub warnings: Vec<Warning>,
|
pub warnings: Vec<Warning>,
|
||||||
|
event_listener: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Project {
|
impl<T> Project<T>
|
||||||
pub fn new(config: Config, root: PathBuf) -> Project {
|
where
|
||||||
|
T: EventListener,
|
||||||
|
{
|
||||||
|
pub fn new(config: Config, root: PathBuf, event_listener: T) -> Project<T> {
|
||||||
let id_gen = IdGenerator::new();
|
let id_gen = IdGenerator::new();
|
||||||
|
|
||||||
let mut module_types = HashMap::new();
|
let mut module_types = HashMap::new();
|
||||||
|
@ -78,6 +87,7 @@ impl Project {
|
||||||
root,
|
root,
|
||||||
sources: vec![],
|
sources: vec![],
|
||||||
warnings: vec![],
|
warnings: vec![],
|
||||||
|
event_listener,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,7 +502,7 @@ impl Project {
|
||||||
};
|
};
|
||||||
|
|
||||||
if !tests.is_empty() {
|
if !tests.is_empty() {
|
||||||
println!("\n{}\n", "Running tests...".bold().underline().purple());
|
self.event_listener.handle_event(Event::RunningTests);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
|
@ -500,75 +510,28 @@ impl Project {
|
||||||
for test in tests {
|
for test in tests {
|
||||||
match test.program.eval(initial_budget) {
|
match test.program.eval(initial_budget) {
|
||||||
(Ok(..), remaining_budget, _) => {
|
(Ok(..), remaining_budget, _) => {
|
||||||
results.push((true, test, initial_budget - remaining_budget));
|
let test_info = TestInfo {
|
||||||
// println!("{}", fmt_tests);
|
is_passing: true,
|
||||||
}
|
test,
|
||||||
(Err(_), remaining_budget, _) => {
|
spent_budget: initial_budget - remaining_budget,
|
||||||
results.push((false, test, initial_budget - remaining_budget));
|
|
||||||
// println!("{}", fmt_tests());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (max_mem, max_cpu) =
|
|
||||||
results
|
|
||||||
.iter()
|
|
||||||
.fold((0, 0), |(max_mem, max_cpu), (_, _, budget)| {
|
|
||||||
if budget.mem >= max_mem && budget.cpu >= max_cpu {
|
|
||||||
(budget.mem, budget.cpu)
|
|
||||||
} else if budget.mem > max_mem {
|
|
||||||
(budget.mem, max_cpu)
|
|
||||||
} else if budget.cpu > max_cpu {
|
|
||||||
(max_mem, budget.cpu)
|
|
||||||
} else {
|
|
||||||
(max_mem, max_cpu)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let max_mem = max_mem.to_string().len() as i32;
|
|
||||||
let max_cpu = max_cpu.to_string().len() as i32;
|
|
||||||
|
|
||||||
let fmt_tests = |is_passing: &bool, test: &Script, spent_budget: &ExBudget| -> String {
|
|
||||||
let ExBudget { mem, cpu } = spent_budget;
|
|
||||||
format!(
|
|
||||||
" [{}] [mem: {}, cpu: {}] {}::{}",
|
|
||||||
if *is_passing {
|
|
||||||
"PASS".bold().green().to_string()
|
|
||||||
} else {
|
|
||||||
"FAIL".bold().red().to_string()
|
|
||||||
},
|
|
||||||
pad_left(mem.to_string(), max_mem, " "),
|
|
||||||
pad_left(cpu.to_string(), max_cpu, " "),
|
|
||||||
test.module.blue(),
|
|
||||||
test.name.bright_blue()
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (is_passing, test, spent_budget) in &results {
|
results.push(test_info);
|
||||||
println!("{}", fmt_tests(is_passing, test, spent_budget))
|
}
|
||||||
|
(Err(_), remaining_budget, _) => {
|
||||||
|
let test_info = TestInfo {
|
||||||
|
is_passing: false,
|
||||||
|
test,
|
||||||
|
spent_budget: initial_budget - remaining_budget,
|
||||||
|
};
|
||||||
|
|
||||||
|
results.push(test_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (n_passed, n_failed) =
|
self.event_listener
|
||||||
results
|
.handle_event(Event::FinishedTests { tests: results });
|
||||||
.iter()
|
|
||||||
.fold((0, 0), |(n_passed, n_failed), (is_passing, _, _)| {
|
|
||||||
if *is_passing {
|
|
||||||
(n_passed + 1, n_failed)
|
|
||||||
} else {
|
|
||||||
(n_passed, n_failed + 1)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"{}",
|
|
||||||
format!(
|
|
||||||
"\n Summary: {} test(s), {}; {}.",
|
|
||||||
results.len(),
|
|
||||||
format!("{} passed", n_passed).bright_green(),
|
|
||||||
format!("{} failed", n_failed).bright_red()
|
|
||||||
)
|
|
||||||
.bold()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_build_outputs(&self, programs: Vec<Script>, uplc_dump: bool) -> Result<(), Error> {
|
fn write_build_outputs(&self, programs: Vec<Script>, uplc_dump: bool) -> Result<(), Error> {
|
||||||
|
@ -727,16 +690,3 @@ fn is_aiken_path(path: &Path, dir: impl AsRef<Path>) -> bool {
|
||||||
.expect("is_aiken_path(): to_str"),
|
.expect("is_aiken_path(): to_str"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pad_left(text: String, n: i32, delimiter: &str) -> String {
|
|
||||||
let mut text = text.clone();
|
|
||||||
let diff = n - text.len() as i32;
|
|
||||||
|
|
||||||
if diff.is_positive() {
|
|
||||||
for _ in 0..diff {
|
|
||||||
text.insert_str(0, delimiter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
text
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
use uplc::machine::cost_model::ExBudget;
|
||||||
|
|
||||||
|
use crate::script::Script;
|
||||||
|
|
||||||
|
pub trait EventListener: std::fmt::Debug {
|
||||||
|
fn handle_event(&self, event: Event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Event {
|
||||||
|
CompilingPackage { name: String },
|
||||||
|
RunningTests,
|
||||||
|
FinishedTests { tests: Vec<TestInfo> },
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TestInfo {
|
||||||
|
pub is_passing: bool,
|
||||||
|
pub test: Script,
|
||||||
|
pub spent_budget: ExBudget,
|
||||||
|
}
|
Loading…
Reference in New Issue