Rework 'watch_project' to reuse 'with_project'
Also removed the 'clear' flag to do it by default instead of clogging the terminal view. This now works pretty nicely, and the logic is back under `aiken_project`.
This commit is contained in:
parent
777d30b8ac
commit
6c039708c3
|
@ -1,5 +1,11 @@
|
||||||
|
use crate::pretty;
|
||||||
use crate::script::EvalInfo;
|
use crate::script::EvalInfo;
|
||||||
use std::{fmt::Display, path::PathBuf};
|
use owo_colors::{
|
||||||
|
OwoColorize,
|
||||||
|
Stream::{self, Stderr},
|
||||||
|
};
|
||||||
|
use std::{collections::BTreeMap, fmt::Display, path::PathBuf};
|
||||||
|
use uplc::machine::cost_model::ExBudget;
|
||||||
|
|
||||||
pub trait EventListener {
|
pub trait EventListener {
|
||||||
fn handle_event(&self, _event: Event) {}
|
fn handle_event(&self, _event: Event) {}
|
||||||
|
@ -64,3 +70,339 @@ impl Display for DownloadSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
pub struct Terminal;
|
||||||
|
|
||||||
|
impl EventListener for Terminal {
|
||||||
|
fn handle_event(&self, event: Event) {
|
||||||
|
match event {
|
||||||
|
Event::StartingCompilation {
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
root,
|
||||||
|
} => {
|
||||||
|
eprintln!(
|
||||||
|
"{} {} {} ({})",
|
||||||
|
" Compiling"
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.purple()),
|
||||||
|
name.if_supports_color(Stderr, |s| s.bold()),
|
||||||
|
version,
|
||||||
|
root.display()
|
||||||
|
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Event::BuildingDocumentation {
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
root,
|
||||||
|
} => {
|
||||||
|
eprintln!(
|
||||||
|
"{} {} {} ({})",
|
||||||
|
" Generating documentation"
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.purple()),
|
||||||
|
name.if_supports_color(Stderr, |s| s.bold()),
|
||||||
|
version,
|
||||||
|
root.to_str()
|
||||||
|
.unwrap_or("")
|
||||||
|
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Event::WaitingForBuildDirLock => {
|
||||||
|
eprintln!(
|
||||||
|
"{}",
|
||||||
|
"Waiting for build directory lock ..."
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.purple())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Event::DumpingUPLC { path } => {
|
||||||
|
eprintln!(
|
||||||
|
"{} {} ({})",
|
||||||
|
" Exporting"
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.purple()),
|
||||||
|
"UPLC".if_supports_color(Stderr, |s| s.bold()),
|
||||||
|
path.display()
|
||||||
|
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Event::GeneratingBlueprint { path } => {
|
||||||
|
eprintln!(
|
||||||
|
"{} {} ({})",
|
||||||
|
" Generating"
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.purple()),
|
||||||
|
"project's blueprint".if_supports_color(Stderr, |s| s.bold()),
|
||||||
|
path.display()
|
||||||
|
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Event::GeneratingDocFiles { output_path } => {
|
||||||
|
eprintln!(
|
||||||
|
"{} in {}",
|
||||||
|
" Generating documentation files"
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.purple()),
|
||||||
|
output_path
|
||||||
|
.to_str()
|
||||||
|
.unwrap_or("")
|
||||||
|
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Event::GeneratingUPLCFor { name, path } => {
|
||||||
|
eprintln!(
|
||||||
|
"{} {}.{{{}}}",
|
||||||
|
" Generating UPLC for"
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.purple()),
|
||||||
|
path.to_str()
|
||||||
|
.unwrap_or("")
|
||||||
|
.if_supports_color(Stderr, |s| s.blue()),
|
||||||
|
name.if_supports_color(Stderr, |s| s.bright_blue()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Event::EvaluatingFunction { results } => {
|
||||||
|
eprintln!(
|
||||||
|
"{}\n",
|
||||||
|
" Evaluating function ..."
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.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, Stderr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::RunningTests => {
|
||||||
|
eprintln!(
|
||||||
|
"{} {}\n",
|
||||||
|
" Testing"
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.purple()),
|
||||||
|
"...".if_supports_color(Stderr, |s| s.bold())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Event::FinishedTests { tests } => {
|
||||||
|
let (max_mem, max_cpu) = find_max_execution_units(&tests);
|
||||||
|
|
||||||
|
for (module, infos) in &group_by_module(&tests) {
|
||||||
|
let title = module
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.blue())
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
let tests = infos
|
||||||
|
.iter()
|
||||||
|
.map(|eval_info| fmt_test(eval_info, max_mem, max_cpu, true))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
let summary = fmt_test_summary(infos, true);
|
||||||
|
|
||||||
|
eprintln!(
|
||||||
|
"{}\n",
|
||||||
|
pretty::indent(
|
||||||
|
&pretty::open_box(&title, &tests, &summary, |border| border
|
||||||
|
.if_supports_color(Stderr, |s| s.bright_black())
|
||||||
|
.to_string()),
|
||||||
|
4
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::ResolvingPackages { name } => {
|
||||||
|
eprintln!(
|
||||||
|
"{} {}",
|
||||||
|
" Resolving"
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.purple()),
|
||||||
|
name.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Event::PackageResolveFallback { name } => {
|
||||||
|
eprintln!(
|
||||||
|
"{} {}\n ↳ You're seeing this message because the package version is unpinned and the network is not accessible.",
|
||||||
|
" Using"
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.yellow()),
|
||||||
|
format!("uncertain local version for {name}")
|
||||||
|
.if_supports_color(Stderr, |s| s.yellow())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Event::PackagesDownloaded {
|
||||||
|
start,
|
||||||
|
count,
|
||||||
|
source,
|
||||||
|
} => {
|
||||||
|
let elapsed = format!("{:.2}s", start.elapsed().as_millis() as f32 / 1000.);
|
||||||
|
|
||||||
|
let msg = match count {
|
||||||
|
1 => format!("1 package in {elapsed}"),
|
||||||
|
_ => format!("{count} packages in {elapsed}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
eprintln!(
|
||||||
|
"{} {} from {source}",
|
||||||
|
match source {
|
||||||
|
DownloadSource::Network => " Downloaded",
|
||||||
|
DownloadSource::Cache => " Fetched",
|
||||||
|
}
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.purple()),
|
||||||
|
msg.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Event::ResolvingVersions => {
|
||||||
|
eprintln!(
|
||||||
|
"{}",
|
||||||
|
" Resolving dependencies"
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.purple()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_test(eval_info: &EvalInfo, max_mem: usize, max_cpu: usize, styled: bool) -> String {
|
||||||
|
let EvalInfo {
|
||||||
|
success,
|
||||||
|
script,
|
||||||
|
spent_budget,
|
||||||
|
logs,
|
||||||
|
..
|
||||||
|
} = eval_info;
|
||||||
|
|
||||||
|
let ExBudget { mem, cpu } = spent_budget;
|
||||||
|
let mem_pad = pretty::pad_left(mem.to_string(), max_mem, " ");
|
||||||
|
let cpu_pad = pretty::pad_left(cpu.to_string(), max_cpu, " ");
|
||||||
|
|
||||||
|
let test = format!(
|
||||||
|
"{status} [mem: {mem_unit}, cpu: {cpu_unit}] {module}",
|
||||||
|
status = if *success {
|
||||||
|
pretty::style_if(styled, "PASS".to_string(), |s| {
|
||||||
|
s.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.green())
|
||||||
|
.to_string()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
pretty::style_if(styled, "FAIL".to_string(), |s| {
|
||||||
|
s.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.if_supports_color(Stderr, |s| s.red())
|
||||||
|
.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
mem_unit = pretty::style_if(styled, mem_pad, |s| s
|
||||||
|
.if_supports_color(Stderr, |s| s.cyan())
|
||||||
|
.to_string()),
|
||||||
|
cpu_unit = pretty::style_if(styled, cpu_pad, |s| s
|
||||||
|
.if_supports_color(Stderr, |s| s.cyan())
|
||||||
|
.to_string()),
|
||||||
|
module = pretty::style_if(styled, script.name.clone(), |s| s
|
||||||
|
.if_supports_color(Stderr, |s| s.bright_blue())
|
||||||
|
.to_string()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let logs = if logs.is_empty() {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
logs.iter()
|
||||||
|
.map(|line| {
|
||||||
|
format!(
|
||||||
|
"{arrow} {styled_line}",
|
||||||
|
arrow = "↳".if_supports_color(Stderr, |s| s.bright_yellow()),
|
||||||
|
styled_line = line.if_supports_color(Stderr, |s| s.bright_black())
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
};
|
||||||
|
|
||||||
|
if logs.is_empty() {
|
||||||
|
test
|
||||||
|
} else {
|
||||||
|
[test, logs].join("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_test_summary(tests: &Vec<&EvalInfo>, styled: bool) -> String {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
format!(
|
||||||
|
"{} | {} | {}",
|
||||||
|
pretty::style_if(styled, format!("{} tests", tests.len()), |s| s
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.to_string()),
|
||||||
|
pretty::style_if(styled, format!("{n_passed} passed"), |s| s
|
||||||
|
.if_supports_color(Stderr, |s| s.bright_green())
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.to_string()),
|
||||||
|
pretty::style_if(styled, format!("{n_failed} failed"), |s| s
|
||||||
|
.if_supports_color(Stderr, |s| s.bright_red())
|
||||||
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
|
.to_string()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_eval(eval_info: &EvalInfo, max_mem: usize, max_cpu: usize, stream: Stream) -> String {
|
||||||
|
let EvalInfo {
|
||||||
|
output,
|
||||||
|
script,
|
||||||
|
spent_budget,
|
||||||
|
..
|
||||||
|
} = eval_info;
|
||||||
|
|
||||||
|
let ExBudget { mem, cpu } = spent_budget;
|
||||||
|
|
||||||
|
format!(
|
||||||
|
" {}::{} [mem: {}, cpu: {}]\n │\n ╰─▶ {}",
|
||||||
|
script.module.if_supports_color(stream, |s| s.blue()),
|
||||||
|
script.name.if_supports_color(stream, |s| s.bright_blue()),
|
||||||
|
pretty::pad_left(mem.to_string(), max_mem, " "),
|
||||||
|
pretty::pad_left(cpu.to_string(), max_cpu, " "),
|
||||||
|
output
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| format!("{x}"))
|
||||||
|
.unwrap_or_else(|| "Error.".to_string()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn group_by_module(infos: &Vec<EvalInfo>) -> BTreeMap<String, Vec<&EvalInfo>> {
|
||||||
|
let mut modules = BTreeMap::new();
|
||||||
|
for eval_info in infos {
|
||||||
|
let xs: &mut Vec<&EvalInfo> = modules.entry(eval_info.script.module.clone()).or_default();
|
||||||
|
xs.push(eval_info);
|
||||||
|
}
|
||||||
|
modules
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_max_execution_units(xs: &[EvalInfo]) -> (usize, usize) {
|
||||||
|
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(), max_cpu.to_string().len())
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,57 @@
|
||||||
use miette::IntoDiagnostic;
|
use crate::{telemetry::Terminal, Project};
|
||||||
|
use miette::{Diagnostic, IntoDiagnostic};
|
||||||
use notify::{Event, RecursiveMode, Watcher};
|
use notify::{Event, RecursiveMode, Watcher};
|
||||||
|
use owo_colors::{OwoColorize, Stream::Stderr};
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
env,
|
env,
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
path::PathBuf,
|
fmt::{self, Display},
|
||||||
|
path::Path,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{telemetry, Project};
|
#[derive(Debug, Diagnostic, thiserror::Error)]
|
||||||
|
enum ExitFailure {
|
||||||
|
#[error("")]
|
||||||
|
ExitFailure,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExitFailure {
|
||||||
|
fn into_report() -> miette::Report {
|
||||||
|
ExitFailure::ExitFailure.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Summary {
|
||||||
|
warning_count: usize,
|
||||||
|
error_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Summary {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.write_str(&format!(
|
||||||
|
"{}\n {} {}, {} {}",
|
||||||
|
"Summary"
|
||||||
|
.if_supports_color(Stderr, |s| s.purple())
|
||||||
|
.if_supports_color(Stderr, |s| s.bold()),
|
||||||
|
self.error_count,
|
||||||
|
if self.error_count == 1 {
|
||||||
|
"error"
|
||||||
|
} else {
|
||||||
|
"errors"
|
||||||
|
}
|
||||||
|
.if_supports_color(Stderr, |s| s.red()),
|
||||||
|
self.warning_count,
|
||||||
|
if self.warning_count == 1 {
|
||||||
|
"warning"
|
||||||
|
} else {
|
||||||
|
"warnings"
|
||||||
|
}
|
||||||
|
.if_supports_color(Stderr, |s| s.yellow()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A default filter for file events that catches the most relevant "source" changes
|
/// A default filter for file events that catches the most relevant "source" changes
|
||||||
pub fn default_filter(evt: &Event) -> bool {
|
pub fn default_filter(evt: &Event) -> bool {
|
||||||
|
@ -30,6 +73,65 @@ pub fn default_filter(evt: &Event) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_project<A>(directory: Option<&Path>, deny: bool, mut action: A) -> miette::Result<()>
|
||||||
|
where
|
||||||
|
A: FnMut(&mut Project<Terminal>) -> Result<(), Vec<crate::error::Error>>,
|
||||||
|
{
|
||||||
|
let project_path = if let Some(d) = directory {
|
||||||
|
d.to_path_buf()
|
||||||
|
} else {
|
||||||
|
env::current_dir().into_diagnostic()?
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut project = match Project::new(project_path, Terminal) {
|
||||||
|
Ok(p) => Ok(p),
|
||||||
|
Err(e) => {
|
||||||
|
e.report();
|
||||||
|
Err(ExitFailure::into_report())
|
||||||
|
}
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let build_result = action(&mut project);
|
||||||
|
|
||||||
|
let warnings = project.warnings();
|
||||||
|
|
||||||
|
let warning_count = warnings.len();
|
||||||
|
|
||||||
|
for warning in &warnings {
|
||||||
|
warning.report()
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(errs) = build_result {
|
||||||
|
for err in &errs {
|
||||||
|
err.report()
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln!(
|
||||||
|
"\n{}",
|
||||||
|
Summary {
|
||||||
|
warning_count,
|
||||||
|
error_count: errs.len(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(ExitFailure::into_report());
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"\n{}",
|
||||||
|
Summary {
|
||||||
|
error_count: 0,
|
||||||
|
warning_count
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if warning_count > 0 && deny {
|
||||||
|
Err(ExitFailure::into_report())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Run a function each time a file in the project changes
|
/// Run a function each time a file in the project changes
|
||||||
///
|
///
|
||||||
/// ```text
|
/// ```text
|
||||||
|
@ -41,19 +143,19 @@ pub fn default_filter(evt: &Event) -> bool {
|
||||||
/// Ok(())
|
/// Ok(())
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
pub fn watch_project<T, F, A>(
|
pub fn watch_project<F, A>(
|
||||||
directory: Option<PathBuf>,
|
directory: Option<&Path>,
|
||||||
events: T,
|
|
||||||
filter: F,
|
filter: F,
|
||||||
debounce: u32,
|
debounce: u32,
|
||||||
mut action: A,
|
mut action: A,
|
||||||
) -> miette::Result<()>
|
) -> miette::Result<()>
|
||||||
where
|
where
|
||||||
T: Copy + telemetry::EventListener,
|
|
||||||
F: Fn(&Event) -> bool,
|
F: Fn(&Event) -> bool,
|
||||||
A: FnMut(&mut Project<T>) -> Result<(), Vec<crate::error::Error>>,
|
A: FnMut(&mut Project<Terminal>) -> Result<(), Vec<crate::error::Error>>,
|
||||||
{
|
{
|
||||||
let project_path = directory.unwrap_or(env::current_dir().into_diagnostic()?);
|
let project_path = directory
|
||||||
|
.map(|p| p.to_path_buf())
|
||||||
|
.unwrap_or(env::current_dir().into_diagnostic()?);
|
||||||
|
|
||||||
// Set up a queue for events, primarily so we can debounce on related events
|
// Set up a queue for events, primarily so we can debounce on related events
|
||||||
let queue = Arc::new(Mutex::new(VecDeque::new()));
|
let queue = Arc::new(Mutex::new(VecDeque::new()));
|
||||||
|
@ -108,18 +210,14 @@ where
|
||||||
|
|
||||||
// If we have an event that survived the filter, then we can construct the project and invoke the action
|
// If we have an event that survived the filter, then we can construct the project and invoke the action
|
||||||
if latest.is_some() {
|
if latest.is_some() {
|
||||||
let mut project = match Project::new(project_path.clone(), events) {
|
print!("{esc}c", esc = 27 as char);
|
||||||
Ok(p) => p,
|
println!(
|
||||||
Err(e) => {
|
"{} ...",
|
||||||
// TODO: what should we actually do here?
|
" Watching"
|
||||||
e.report();
|
.if_supports_color(Stderr, |s| s.bold())
|
||||||
return Err(miette::Report::msg("??"));
|
.if_supports_color(Stderr, |s| s.purple()),
|
||||||
}
|
);
|
||||||
};
|
with_project(directory, false, &mut action).unwrap_or(())
|
||||||
|
|
||||||
// Invoke the action, and abort on an error
|
|
||||||
// TODO: what should we actually do with the error here?
|
|
||||||
action(&mut project).or(Err(miette::Report::msg("??")))?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::with_project;
|
|
||||||
use aiken_lang::ast::Tracing;
|
use aiken_lang::ast::Tracing;
|
||||||
|
use aiken_project::watch::with_project;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// Compute a validator's address.
|
/// Compute a validator's address.
|
||||||
|
@ -34,7 +34,7 @@ pub fn exec(
|
||||||
rebuild,
|
rebuild,
|
||||||
}: Args,
|
}: Args,
|
||||||
) -> miette::Result<()> {
|
) -> miette::Result<()> {
|
||||||
with_project(directory, false, |p| {
|
with_project(directory.as_deref(), false, |p| {
|
||||||
if rebuild {
|
if rebuild {
|
||||||
p.build(false, Tracing::NoTraces)?;
|
p.build(false, Tracing::NoTraces)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::with_project;
|
|
||||||
use aiken_project::{
|
use aiken_project::{
|
||||||
blueprint::{
|
blueprint::{
|
||||||
self,
|
self,
|
||||||
|
@ -7,6 +6,7 @@ use aiken_project::{
|
||||||
},
|
},
|
||||||
error::Error,
|
error::Error,
|
||||||
pretty::multiline,
|
pretty::multiline,
|
||||||
|
watch::with_project,
|
||||||
};
|
};
|
||||||
use inquire;
|
use inquire;
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::with_project;
|
|
||||||
use aiken_lang::ast::Tracing;
|
use aiken_lang::ast::Tracing;
|
||||||
|
use aiken_project::watch::with_project;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// Compute a validator's hash
|
/// Compute a validator's hash
|
||||||
|
@ -29,7 +29,7 @@ pub fn exec(
|
||||||
rebuild,
|
rebuild,
|
||||||
}: Args,
|
}: Args,
|
||||||
) -> miette::Result<()> {
|
) -> miette::Result<()> {
|
||||||
with_project(directory, false, |p| {
|
with_project(directory.as_deref(), false, |p| {
|
||||||
if rebuild {
|
if rebuild {
|
||||||
p.build(false, Tracing::NoTraces)?;
|
p.build(false, Tracing::NoTraces)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::with_project;
|
|
||||||
use aiken_lang::ast::Tracing;
|
use aiken_lang::ast::Tracing;
|
||||||
|
use aiken_project::watch::with_project;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// Compute a minting scripts Policy ID
|
/// Compute a minting scripts Policy ID
|
||||||
|
@ -29,7 +29,7 @@ pub fn exec(
|
||||||
rebuild,
|
rebuild,
|
||||||
}: Args,
|
}: Args,
|
||||||
) -> miette::Result<()> {
|
) -> miette::Result<()> {
|
||||||
with_project(directory, false, |p| {
|
with_project(directory.as_deref(), false, |p| {
|
||||||
if rebuild {
|
if rebuild {
|
||||||
p.build(false, Tracing::NoTraces)?;
|
p.build(false, Tracing::NoTraces)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use aiken_project::watch::with_project;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(clap::Args)]
|
#[derive(clap::Args)]
|
||||||
|
@ -27,5 +28,7 @@ pub fn exec(
|
||||||
keep_traces,
|
keep_traces,
|
||||||
}: Args,
|
}: Args,
|
||||||
) -> miette::Result<()> {
|
) -> miette::Result<()> {
|
||||||
crate::with_project(directory, deny, |p| p.build(uplc, keep_traces.into()))
|
with_project(directory.as_deref(), deny, |p| {
|
||||||
|
p.build(uplc, keep_traces.into())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
|
use aiken_project::watch::{self, watch_project, with_project};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use aiken_project::watch;
|
|
||||||
use owo_colors::{OwoColorize, Stream::Stderr};
|
|
||||||
|
|
||||||
use crate::Terminal;
|
|
||||||
|
|
||||||
#[derive(clap::Args)]
|
#[derive(clap::Args)]
|
||||||
/// Type-check an Aiken project
|
/// Type-check an Aiken project
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
|
@ -27,10 +23,6 @@ pub struct Args {
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
watch: bool,
|
watch: bool,
|
||||||
|
|
||||||
/// When enabled, clear the screen before running
|
|
||||||
#[clap(long)]
|
|
||||||
clear: bool,
|
|
||||||
|
|
||||||
/// Only run tests if they match any of these strings.
|
/// Only run tests if they match any of these strings.
|
||||||
/// You can match a module with `-m aiken/list` or `-m list`.
|
/// You can match a module with `-m aiken/list` or `-m list`.
|
||||||
/// You can match a test with `-m "aiken/list.{map}"` or `-m "aiken/option.{flatten_1}"`
|
/// You can match a test with `-m "aiken/list.{map}"` or `-m "aiken/option.{flatten_1}"`
|
||||||
|
@ -57,77 +49,21 @@ pub fn exec(
|
||||||
exact_match,
|
exact_match,
|
||||||
no_traces,
|
no_traces,
|
||||||
watch,
|
watch,
|
||||||
clear,
|
|
||||||
..
|
..
|
||||||
}: Args,
|
}: Args,
|
||||||
) -> miette::Result<()> {
|
) -> miette::Result<()> {
|
||||||
if watch {
|
if watch {
|
||||||
watch::watch_project(directory, Terminal, watch::default_filter, 500, |p| {
|
watch_project(directory.as_deref(), watch::default_filter, 500, |p| {
|
||||||
if clear {
|
p.check(
|
||||||
println!("{esc}c", esc = 27 as char);
|
|
||||||
}
|
|
||||||
let build_result = p.check(
|
|
||||||
skip_tests,
|
skip_tests,
|
||||||
match_tests.clone(),
|
match_tests.clone(),
|
||||||
debug,
|
debug,
|
||||||
exact_match,
|
exact_match,
|
||||||
(!no_traces).into(),
|
(!no_traces).into(),
|
||||||
);
|
)
|
||||||
|
|
||||||
let warnings = p.warnings();
|
|
||||||
|
|
||||||
let warning_count = warnings.len();
|
|
||||||
|
|
||||||
for warning in &warnings {
|
|
||||||
warning.report()
|
|
||||||
}
|
|
||||||
|
|
||||||
let plural = if warning_count == 1 { "" } else { "s" };
|
|
||||||
|
|
||||||
if let Err(errs) = build_result {
|
|
||||||
for err in &errs {
|
|
||||||
err.report()
|
|
||||||
}
|
|
||||||
|
|
||||||
eprintln!(
|
|
||||||
"\n{}",
|
|
||||||
"Summary"
|
|
||||||
.if_supports_color(Stderr, |s| s.purple())
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
);
|
|
||||||
|
|
||||||
let warning_text = format!("{warning_count} warning{plural}");
|
|
||||||
|
|
||||||
let plural = if errs.len() == 1 { "" } else { "s" };
|
|
||||||
|
|
||||||
let error_text = format!("{} error{}", errs.len(), plural);
|
|
||||||
|
|
||||||
let full_summary = format!(
|
|
||||||
" {}, {}",
|
|
||||||
error_text.if_supports_color(Stderr, |s| s.red()),
|
|
||||||
warning_text.if_supports_color(Stderr, |s| s.yellow())
|
|
||||||
);
|
|
||||||
|
|
||||||
eprintln!("{full_summary}");
|
|
||||||
} else {
|
|
||||||
eprintln!(
|
|
||||||
"\n{}",
|
|
||||||
"Summary"
|
|
||||||
.if_supports_color(Stderr, |s| s.purple())
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
);
|
|
||||||
|
|
||||||
let warning_text = format!("{warning_count} warning{plural}");
|
|
||||||
|
|
||||||
eprintln!(
|
|
||||||
" 0 errors, {}",
|
|
||||||
warning_text.if_supports_color(Stderr, |s| s.yellow()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
crate::with_project(directory, deny, |p| {
|
with_project(directory.as_deref(), deny, |p| {
|
||||||
p.check(
|
p.check(
|
||||||
skip_tests,
|
skip_tests,
|
||||||
match_tests.clone(),
|
match_tests.clone(),
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use aiken_project::watch::with_project;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(clap::Args)]
|
#[derive(clap::Args)]
|
||||||
|
@ -22,5 +23,5 @@ pub fn exec(
|
||||||
destination,
|
destination,
|
||||||
}: Args,
|
}: Args,
|
||||||
) -> miette::Result<()> {
|
) -> miette::Result<()> {
|
||||||
crate::with_project(directory, deny, |p| p.docs(destination.clone()))
|
with_project(directory.as_deref(), deny, |p| p.docs(destination.clone()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,458 +0,0 @@
|
||||||
use aiken_project::{
|
|
||||||
pretty,
|
|
||||||
script::EvalInfo,
|
|
||||||
telemetry::{self, DownloadSource},
|
|
||||||
Project,
|
|
||||||
};
|
|
||||||
use miette::Diagnostic;
|
|
||||||
use miette::IntoDiagnostic;
|
|
||||||
use owo_colors::{
|
|
||||||
OwoColorize,
|
|
||||||
Stream::{self, Stderr},
|
|
||||||
};
|
|
||||||
use std::{
|
|
||||||
collections::BTreeMap,
|
|
||||||
env,
|
|
||||||
fmt::{self, Display},
|
|
||||||
path::PathBuf,
|
|
||||||
};
|
|
||||||
use uplc::machine::cost_model::ExBudget;
|
|
||||||
|
|
||||||
pub mod cmd;
|
|
||||||
|
|
||||||
#[derive(Debug, Diagnostic, thiserror::Error)]
|
|
||||||
enum ExitFailure {
|
|
||||||
#[error("")]
|
|
||||||
ExitFailure,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExitFailure {
|
|
||||||
fn into_report() -> miette::Report {
|
|
||||||
ExitFailure::ExitFailure.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_project<A>(directory: Option<PathBuf>, deny: bool, mut action: A) -> miette::Result<()>
|
|
||||||
where
|
|
||||||
A: FnMut(&mut Project<Terminal>) -> Result<(), Vec<aiken_project::error::Error>>,
|
|
||||||
{
|
|
||||||
let project_path = if let Some(d) = directory {
|
|
||||||
d
|
|
||||||
} else {
|
|
||||||
env::current_dir().into_diagnostic()?
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut project = match Project::new(project_path, Terminal) {
|
|
||||||
Ok(p) => Ok(p),
|
|
||||||
Err(e) => {
|
|
||||||
e.report();
|
|
||||||
Err(ExitFailure::into_report())
|
|
||||||
}
|
|
||||||
}?;
|
|
||||||
|
|
||||||
let build_result = action(&mut project);
|
|
||||||
|
|
||||||
let warnings = project.warnings();
|
|
||||||
|
|
||||||
let warning_count = warnings.len();
|
|
||||||
|
|
||||||
for warning in &warnings {
|
|
||||||
warning.report()
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(errs) = build_result {
|
|
||||||
for err in &errs {
|
|
||||||
err.report()
|
|
||||||
}
|
|
||||||
|
|
||||||
eprintln!(
|
|
||||||
"\n{}",
|
|
||||||
Summary {
|
|
||||||
warning_count,
|
|
||||||
error_count: errs.len(),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return Err(ExitFailure::into_report());
|
|
||||||
} else {
|
|
||||||
eprintln!(
|
|
||||||
"\n{}",
|
|
||||||
Summary {
|
|
||||||
error_count: 0,
|
|
||||||
warning_count
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if warning_count > 0 && deny {
|
|
||||||
Err(ExitFailure::into_report())
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Summary {
|
|
||||||
warning_count: usize,
|
|
||||||
error_count: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Summary {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.write_str(&format!(
|
|
||||||
"{}\n {} {}, {} {}",
|
|
||||||
"Summary"
|
|
||||||
.if_supports_color(Stderr, |s| s.purple())
|
|
||||||
.if_supports_color(Stderr, |s| s.bold()),
|
|
||||||
self.error_count,
|
|
||||||
if self.error_count == 1 {
|
|
||||||
"error"
|
|
||||||
} else {
|
|
||||||
"errors"
|
|
||||||
}
|
|
||||||
.if_supports_color(Stderr, |s| s.red()),
|
|
||||||
self.warning_count,
|
|
||||||
if self.warning_count == 1 {
|
|
||||||
"warning"
|
|
||||||
} else {
|
|
||||||
"warnings"
|
|
||||||
}
|
|
||||||
.if_supports_color(Stderr, |s| s.yellow()),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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,
|
|
||||||
} => {
|
|
||||||
eprintln!(
|
|
||||||
"{} {} {} ({})",
|
|
||||||
" Compiling"
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.purple()),
|
|
||||||
name.if_supports_color(Stderr, |s| s.bold()),
|
|
||||||
version,
|
|
||||||
root.display()
|
|
||||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
telemetry::Event::BuildingDocumentation {
|
|
||||||
name,
|
|
||||||
version,
|
|
||||||
root,
|
|
||||||
} => {
|
|
||||||
eprintln!(
|
|
||||||
"{} {} {} ({})",
|
|
||||||
" Generating documentation"
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.purple()),
|
|
||||||
name.if_supports_color(Stderr, |s| s.bold()),
|
|
||||||
version,
|
|
||||||
root.to_str()
|
|
||||||
.unwrap_or("")
|
|
||||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
telemetry::Event::WaitingForBuildDirLock => {
|
|
||||||
eprintln!(
|
|
||||||
"{}",
|
|
||||||
"Waiting for build directory lock ..."
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.purple())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
telemetry::Event::DumpingUPLC { path } => {
|
|
||||||
eprintln!(
|
|
||||||
"{} {} ({})",
|
|
||||||
" Exporting"
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.purple()),
|
|
||||||
"UPLC".if_supports_color(Stderr, |s| s.bold()),
|
|
||||||
path.display()
|
|
||||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
telemetry::Event::GeneratingBlueprint { path } => {
|
|
||||||
eprintln!(
|
|
||||||
"{} {} ({})",
|
|
||||||
" Generating"
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.purple()),
|
|
||||||
"project's blueprint".if_supports_color(Stderr, |s| s.bold()),
|
|
||||||
path.display()
|
|
||||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
telemetry::Event::GeneratingDocFiles { output_path } => {
|
|
||||||
eprintln!(
|
|
||||||
"{} in {}",
|
|
||||||
" Generating documentation files"
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.purple()),
|
|
||||||
output_path
|
|
||||||
.to_str()
|
|
||||||
.unwrap_or("")
|
|
||||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
telemetry::Event::GeneratingUPLCFor { name, path } => {
|
|
||||||
eprintln!(
|
|
||||||
"{} {}.{{{}}}",
|
|
||||||
" Generating UPLC for"
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.purple()),
|
|
||||||
path.to_str()
|
|
||||||
.unwrap_or("")
|
|
||||||
.if_supports_color(Stderr, |s| s.blue()),
|
|
||||||
name.if_supports_color(Stderr, |s| s.bright_blue()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
telemetry::Event::EvaluatingFunction { results } => {
|
|
||||||
eprintln!(
|
|
||||||
"{}\n",
|
|
||||||
" Evaluating function ..."
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.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, Stderr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
telemetry::Event::RunningTests => {
|
|
||||||
eprintln!(
|
|
||||||
"{} {}\n",
|
|
||||||
" Testing"
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.purple()),
|
|
||||||
"...".if_supports_color(Stderr, |s| s.bold())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
telemetry::Event::FinishedTests { tests } => {
|
|
||||||
let (max_mem, max_cpu) = find_max_execution_units(&tests);
|
|
||||||
|
|
||||||
for (module, infos) in &group_by_module(&tests) {
|
|
||||||
let title = module
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.blue())
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let tests = infos
|
|
||||||
.iter()
|
|
||||||
.map(|eval_info| fmt_test(eval_info, max_mem, max_cpu, true))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join("\n");
|
|
||||||
|
|
||||||
let summary = fmt_test_summary(infos, true);
|
|
||||||
|
|
||||||
eprintln!(
|
|
||||||
"{}\n",
|
|
||||||
pretty::indent(
|
|
||||||
&pretty::open_box(&title, &tests, &summary, |border| border
|
|
||||||
.if_supports_color(Stderr, |s| s.bright_black())
|
|
||||||
.to_string()),
|
|
||||||
4
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
telemetry::Event::ResolvingPackages { name } => {
|
|
||||||
eprintln!(
|
|
||||||
"{} {}",
|
|
||||||
" Resolving"
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.purple()),
|
|
||||||
name.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
telemetry::Event::PackageResolveFallback { name } => {
|
|
||||||
eprintln!(
|
|
||||||
"{} {}\n ↳ You're seeing this message because the package version is unpinned and the network is not accessible.",
|
|
||||||
" Using"
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.yellow()),
|
|
||||||
format!("uncertain local version for {name}")
|
|
||||||
.if_supports_color(Stderr, |s| s.yellow())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
telemetry::Event::PackagesDownloaded {
|
|
||||||
start,
|
|
||||||
count,
|
|
||||||
source,
|
|
||||||
} => {
|
|
||||||
let elapsed = format!("{:.2}s", start.elapsed().as_millis() as f32 / 1000.);
|
|
||||||
|
|
||||||
let msg = match count {
|
|
||||||
1 => format!("1 package in {elapsed}"),
|
|
||||||
_ => format!("{count} packages in {elapsed}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
eprintln!(
|
|
||||||
"{} {} from {source}",
|
|
||||||
match source {
|
|
||||||
DownloadSource::Network => " Downloaded",
|
|
||||||
DownloadSource::Cache => " Fetched",
|
|
||||||
}
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.purple()),
|
|
||||||
msg.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
telemetry::Event::ResolvingVersions => {
|
|
||||||
eprintln!(
|
|
||||||
"{}",
|
|
||||||
" Resolving dependencies"
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.purple()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fmt_test(eval_info: &EvalInfo, max_mem: usize, max_cpu: usize, styled: bool) -> String {
|
|
||||||
let EvalInfo {
|
|
||||||
success,
|
|
||||||
script,
|
|
||||||
spent_budget,
|
|
||||||
logs,
|
|
||||||
..
|
|
||||||
} = eval_info;
|
|
||||||
|
|
||||||
let ExBudget { mem, cpu } = spent_budget;
|
|
||||||
let mem_pad = pretty::pad_left(mem.to_string(), max_mem, " ");
|
|
||||||
let cpu_pad = pretty::pad_left(cpu.to_string(), max_cpu, " ");
|
|
||||||
|
|
||||||
let test = format!(
|
|
||||||
"{status} [mem: {mem_unit}, cpu: {cpu_unit}] {module}",
|
|
||||||
status = if *success {
|
|
||||||
pretty::style_if(styled, "PASS".to_string(), |s| {
|
|
||||||
s.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.green())
|
|
||||||
.to_string()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
pretty::style_if(styled, "FAIL".to_string(), |s| {
|
|
||||||
s.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.if_supports_color(Stderr, |s| s.red())
|
|
||||||
.to_string()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
mem_unit = pretty::style_if(styled, mem_pad, |s| s
|
|
||||||
.if_supports_color(Stderr, |s| s.cyan())
|
|
||||||
.to_string()),
|
|
||||||
cpu_unit = pretty::style_if(styled, cpu_pad, |s| s
|
|
||||||
.if_supports_color(Stderr, |s| s.cyan())
|
|
||||||
.to_string()),
|
|
||||||
module = pretty::style_if(styled, script.name.clone(), |s| s
|
|
||||||
.if_supports_color(Stderr, |s| s.bright_blue())
|
|
||||||
.to_string()),
|
|
||||||
);
|
|
||||||
|
|
||||||
let logs = if logs.is_empty() {
|
|
||||||
String::new()
|
|
||||||
} else {
|
|
||||||
logs.iter()
|
|
||||||
.map(|line| {
|
|
||||||
format!(
|
|
||||||
"{arrow} {styled_line}",
|
|
||||||
arrow = "↳".if_supports_color(Stderr, |s| s.bright_yellow()),
|
|
||||||
styled_line = line.if_supports_color(Stderr, |s| s.bright_black())
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\n")
|
|
||||||
};
|
|
||||||
|
|
||||||
if logs.is_empty() {
|
|
||||||
test
|
|
||||||
} else {
|
|
||||||
[test, logs].join("\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fmt_test_summary(tests: &Vec<&EvalInfo>, styled: bool) -> String {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
format!(
|
|
||||||
"{} | {} | {}",
|
|
||||||
pretty::style_if(styled, format!("{} tests", tests.len()), |s| s
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.to_string()),
|
|
||||||
pretty::style_if(styled, format!("{n_passed} passed"), |s| s
|
|
||||||
.if_supports_color(Stderr, |s| s.bright_green())
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.to_string()),
|
|
||||||
pretty::style_if(styled, format!("{n_failed} failed"), |s| s
|
|
||||||
.if_supports_color(Stderr, |s| s.bright_red())
|
|
||||||
.if_supports_color(Stderr, |s| s.bold())
|
|
||||||
.to_string()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fmt_eval(eval_info: &EvalInfo, max_mem: usize, max_cpu: usize, stream: Stream) -> String {
|
|
||||||
let EvalInfo {
|
|
||||||
output,
|
|
||||||
script,
|
|
||||||
spent_budget,
|
|
||||||
..
|
|
||||||
} = eval_info;
|
|
||||||
|
|
||||||
let ExBudget { mem, cpu } = spent_budget;
|
|
||||||
|
|
||||||
format!(
|
|
||||||
" {}::{} [mem: {}, cpu: {}]\n │\n ╰─▶ {}",
|
|
||||||
script.module.if_supports_color(stream, |s| s.blue()),
|
|
||||||
script.name.if_supports_color(stream, |s| s.bright_blue()),
|
|
||||||
pretty::pad_left(mem.to_string(), max_mem, " "),
|
|
||||||
pretty::pad_left(cpu.to_string(), max_cpu, " "),
|
|
||||||
output
|
|
||||||
.as_ref()
|
|
||||||
.map(|x| format!("{x}"))
|
|
||||||
.unwrap_or_else(|| "Error.".to_string()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn group_by_module(infos: &Vec<EvalInfo>) -> BTreeMap<String, Vec<&EvalInfo>> {
|
|
||||||
let mut modules = BTreeMap::new();
|
|
||||||
for eval_info in infos {
|
|
||||||
let xs: &mut Vec<&EvalInfo> = modules.entry(eval_info.script.module.clone()).or_default();
|
|
||||||
xs.push(eval_info);
|
|
||||||
}
|
|
||||||
modules
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_max_execution_units(xs: &[EvalInfo]) -> (usize, usize) {
|
|
||||||
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(), max_cpu.to_string().len())
|
|
||||||
}
|
|
|
@ -1,13 +1,15 @@
|
||||||
use aiken::cmd::{
|
use aiken_project::{config, pretty};
|
||||||
|
use cmd::{
|
||||||
blueprint::{self, address},
|
blueprint::{self, address},
|
||||||
build, check, completion, docs, fmt, lsp, new,
|
build, check, completion, docs, fmt, lsp, new,
|
||||||
packages::{self, add},
|
packages::{self, add},
|
||||||
tx, uplc, Cmd,
|
tx, uplc, Cmd,
|
||||||
};
|
};
|
||||||
use aiken_project::{config, pretty};
|
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
|
mod cmd;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
panic_handler();
|
panic_handler();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue