204 lines
5.9 KiB
Rust
204 lines
5.9 KiB
Rust
use std::{env, path::PathBuf};
|
|
|
|
use aiken_project::{
|
|
config::Config,
|
|
telemetry::{self, EvalInfo},
|
|
Project,
|
|
};
|
|
use miette::IntoDiagnostic;
|
|
use owo_colors::OwoColorize;
|
|
use uplc::machine::cost_model::ExBudget;
|
|
|
|
pub mod cmd;
|
|
|
|
pub fn with_project<A>(directory: Option<PathBuf>, mut action: A) -> miette::Result<()>
|
|
where
|
|
A: FnMut(&mut Project<Terminal>) -> Result<(), aiken_project::error::Error>,
|
|
{
|
|
let project_path = if let Some(d) = directory {
|
|
d
|
|
} else {
|
|
env::current_dir().into_diagnostic()?
|
|
};
|
|
|
|
let config = Config::load(project_path.clone()).into_diagnostic()?;
|
|
|
|
let mut project = Project::new(config, project_path, Terminal::default());
|
|
|
|
let build_result = action(&mut project);
|
|
|
|
let warning_count = project.warnings.len();
|
|
|
|
for warning in project.warnings {
|
|
warning.report()
|
|
}
|
|
|
|
if let Err(err) = build_result {
|
|
err.report();
|
|
|
|
miette::bail!("Failed: {} error(s), {warning_count} warning(s)", err.len(),);
|
|
};
|
|
|
|
println!("\nFinished with {warning_count} warning(s)\n");
|
|
|
|
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::StartingCompilation {
|
|
name,
|
|
version,
|
|
root,
|
|
} => {
|
|
println!(
|
|
"{} {} {} ({})",
|
|
"Compiling".bold().purple(),
|
|
name.bold(),
|
|
version,
|
|
root.to_str().unwrap_or("").bright_blue()
|
|
);
|
|
}
|
|
telemetry::Event::ParsingProjectFiles => {
|
|
println!("{}", "...Parsing project files".bold().purple());
|
|
}
|
|
telemetry::Event::TypeChecking => {
|
|
println!("{}", "...Type-checking project".bold().purple());
|
|
}
|
|
telemetry::Event::GeneratingUPLC { output_path } => {
|
|
println!(
|
|
"{} in {}",
|
|
"...Generating Untyped Plutus Core".bold().purple(),
|
|
output_path.to_str().unwrap_or("").bright_blue()
|
|
);
|
|
}
|
|
telemetry::Event::EvaluatingFunction { results } => {
|
|
println!("{}\n", "...Evaluating function".bold().purple());
|
|
|
|
let (max_mem, max_cpu) = find_max_execution_units(&results);
|
|
|
|
for eval_info in &results {
|
|
println!("{}", fmt_eval(eval_info, max_mem, max_cpu))
|
|
}
|
|
}
|
|
telemetry::Event::RunningTests => {
|
|
println!("{}\n", "...Running tests".bold().purple());
|
|
}
|
|
telemetry::Event::FinishedTests { tests } => {
|
|
let (max_mem, max_cpu) = find_max_execution_units(&tests);
|
|
|
|
for eval_info in &tests {
|
|
println!("{}", fmt_test(eval_info, max_mem, max_cpu))
|
|
}
|
|
|
|
let (n_passed, n_failed) =
|
|
tests
|
|
.iter()
|
|
.fold((0, 0), |(n_passed, n_failed), test_info| {
|
|
if test_info.success {
|
|
(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(eval_info: &EvalInfo, max_mem: i32, max_cpu: i32) -> String {
|
|
let EvalInfo {
|
|
success,
|
|
script,
|
|
spent_budget,
|
|
..
|
|
} = eval_info;
|
|
|
|
let ExBudget { mem, cpu } = spent_budget;
|
|
|
|
format!(
|
|
" [{}] [mem: {}, cpu: {}] {}::{}",
|
|
if *success {
|
|
"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, " "),
|
|
script.module.blue(),
|
|
script.name.bright_blue()
|
|
)
|
|
}
|
|
|
|
fn fmt_eval(eval_info: &EvalInfo, max_mem: i32, max_cpu: i32) -> String {
|
|
let EvalInfo {
|
|
output,
|
|
script,
|
|
spent_budget,
|
|
..
|
|
} = eval_info;
|
|
|
|
let ExBudget { mem, cpu } = spent_budget;
|
|
|
|
format!(
|
|
" {}::{} [mem: {}, cpu: {}]\n │\n ╰─▶ {}",
|
|
script.module.blue(),
|
|
script.name.bright_blue(),
|
|
pad_left(mem.to_string(), max_mem, " "),
|
|
pad_left(cpu.to_string(), max_cpu, " "),
|
|
output
|
|
.as_ref()
|
|
.map(|x| format!("{}", x))
|
|
.unwrap_or_else(|| "Error.".to_string()),
|
|
)
|
|
}
|
|
|
|
fn find_max_execution_units(xs: &[EvalInfo]) -> (i32, i32) {
|
|
let (max_mem, max_cpu) = xs.iter().fold(
|
|
(0, 0),
|
|
|(max_mem, max_cpu), EvalInfo { 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)
|
|
}
|
|
},
|
|
);
|
|
|
|
(
|
|
max_mem.to_string().len() as i32,
|
|
max_cpu.to_string().len() as i32,
|
|
)
|
|
}
|
|
|
|
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
|
|
}
|