feat(project): remove Error::List and use Vec<Error>
This commit is contained in:
parent
70164282f8
commit
b55726c90f
|
@ -1,10 +1,10 @@
|
|||
use crate::{package_name::PackageName, Error};
|
||||
use crate::{package_name::PackageName, paths, Error};
|
||||
use aiken_lang::ast::Span;
|
||||
use miette::NamedSource;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{fmt::Display, fs, io, path::Path};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub struct Config {
|
||||
pub name: PackageName,
|
||||
pub version: String,
|
||||
|
@ -16,7 +16,7 @@ pub struct Config {
|
|||
pub dependencies: Vec<Dependency>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub struct Repository {
|
||||
pub user: String,
|
||||
pub project: String,
|
||||
|
@ -72,13 +72,13 @@ impl Config {
|
|||
}
|
||||
|
||||
pub fn save(&self, dir: &Path) -> Result<(), io::Error> {
|
||||
let aiken_toml_path = dir.join("aiken.toml");
|
||||
let aiken_toml_path = dir.join(paths::project_config());
|
||||
let aiken_toml = toml::to_string_pretty(self).unwrap();
|
||||
fs::write(aiken_toml_path, aiken_toml)
|
||||
}
|
||||
|
||||
pub fn load(dir: &Path) -> Result<Config, Error> {
|
||||
let config_path = dir.join("aiken.toml");
|
||||
let config_path = dir.join(paths::project_config());
|
||||
let raw_config = fs::read_to_string(&config_path).map_err(|_| Error::MissingManifest {
|
||||
path: dir.to_path_buf(),
|
||||
})?;
|
||||
|
|
|
@ -69,10 +69,6 @@ pub enum Error {
|
|||
#[error("I just found a cycle in module hierarchy!")]
|
||||
ImportCycle { modules: Vec<String> },
|
||||
|
||||
/// Useful for returning many [`Error::Parse`] at once
|
||||
#[error("A list of errors")]
|
||||
List(Vec<Self>),
|
||||
|
||||
#[error("While parsing files...")]
|
||||
Parse {
|
||||
path: PathBuf,
|
||||
|
@ -139,25 +135,11 @@ pub enum Error {
|
|||
}
|
||||
|
||||
impl Error {
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Error::List(errors) => errors.len(),
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn report(&self) {
|
||||
match self {
|
||||
Error::List(errors) => {
|
||||
for error in errors {
|
||||
eprintln!("Error: {error:?}")
|
||||
}
|
||||
}
|
||||
rest => eprintln!("Error: {rest:?}"),
|
||||
}
|
||||
eprintln!("Error: {self:?}")
|
||||
}
|
||||
|
||||
pub fn from_parse_errors(errs: Vec<ParseError>, path: &Path, src: &str) -> Self {
|
||||
pub fn from_parse_errors(errs: Vec<ParseError>, path: &Path, src: &str) -> Vec<Self> {
|
||||
let mut errors = Vec::with_capacity(errs.len());
|
||||
|
||||
for error in errs {
|
||||
|
@ -209,7 +191,6 @@ impl Error {
|
|||
Error::MissingManifest { path } => Some(path.to_path_buf()),
|
||||
Error::TomlLoading { path, .. } => Some(path.to_path_buf()),
|
||||
Error::ImportCycle { .. } => None,
|
||||
Error::List(_) => None,
|
||||
Error::Parse { path, .. } => Some(path.to_path_buf()),
|
||||
Error::Type { path, .. } => Some(path.to_path_buf()),
|
||||
Error::ValidatorMustReturnBool { path, .. } => Some(path.to_path_buf()),
|
||||
|
@ -226,7 +207,7 @@ impl Error {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn src(&self) -> Option<String> {
|
||||
fn src(&self) -> Option<String> {
|
||||
match self {
|
||||
Error::DuplicateModule { .. } => None,
|
||||
Error::FileIo { .. } => None,
|
||||
|
@ -236,7 +217,6 @@ impl Error {
|
|||
Error::MissingManifest { .. } => None,
|
||||
Error::TomlLoading { src, .. } => Some(src.to_string()),
|
||||
Error::ImportCycle { .. } => None,
|
||||
Error::List(_) => None,
|
||||
Error::Parse { src, .. } => Some(src.to_string()),
|
||||
Error::Type { src, .. } => Some(src.to_string()),
|
||||
Error::ValidatorMustReturnBool { src, .. } => Some(src.to_string()),
|
||||
|
@ -284,7 +264,6 @@ impl Diagnostic for Error {
|
|||
Error::FileIo { .. } => None,
|
||||
Error::Blueprint(e) => e.code(),
|
||||
Error::ImportCycle { .. } => Some(Box::new("aiken::module::cyclical")),
|
||||
Error::List(_) => None,
|
||||
Error::Parse { .. } => Some(Box::new("aiken::parser")),
|
||||
Error::Type { error, .. } => Some(Box::new(format!(
|
||||
"aiken::check{}",
|
||||
|
@ -321,7 +300,6 @@ impl Diagnostic for Error {
|
|||
"Try moving the shared code to a separate module that the others can depend on\n- {}",
|
||||
modules.join("\n- ")
|
||||
))),
|
||||
Error::List(_) => None,
|
||||
Error::Parse { error, .. } => error.kind.help(),
|
||||
Error::Type { error, .. } => error.help(),
|
||||
Error::StandardIo(_) => None,
|
||||
|
@ -388,7 +366,6 @@ impl Diagnostic for Error {
|
|||
Error::FileIo { .. } => None,
|
||||
Error::ImportCycle { .. } => None,
|
||||
Error::Blueprint(e) => e.labels(),
|
||||
Error::List(_) => None,
|
||||
Error::Parse { error, .. } => error.labels(),
|
||||
Error::MissingManifest { .. } => None,
|
||||
Error::Type { error, .. } => error.labels(),
|
||||
|
@ -427,7 +404,6 @@ impl Diagnostic for Error {
|
|||
Error::FileIo { .. } => None,
|
||||
Error::ImportCycle { .. } => None,
|
||||
Error::Blueprint(e) => e.source_code(),
|
||||
Error::List(_) => None,
|
||||
Error::Parse { named, .. } => Some(named),
|
||||
Error::Type { named, .. } => Some(named),
|
||||
Error::StandardIo(_) => None,
|
||||
|
@ -454,7 +430,6 @@ impl Diagnostic for Error {
|
|||
Error::FileIo { .. } => None,
|
||||
Error::ImportCycle { .. } => None,
|
||||
Error::Blueprint(e) => e.url(),
|
||||
Error::List { .. } => None,
|
||||
Error::Parse { .. } => None,
|
||||
Error::Type { error, .. } => error.url(),
|
||||
Error::StandardIo(_) => None,
|
||||
|
@ -481,7 +456,6 @@ impl Diagnostic for Error {
|
|||
Error::FileIo { .. } => None,
|
||||
Error::Blueprint(e) => e.related(),
|
||||
Error::ImportCycle { .. } => None,
|
||||
Error::List { .. } => None,
|
||||
Error::Parse { .. } => None,
|
||||
Error::Type { error, .. } => error.related(),
|
||||
Error::StandardIo(_) => None,
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::{
|
|||
is_aiken_path,
|
||||
};
|
||||
|
||||
pub fn run(stdin: bool, check: bool, files: Vec<String>) -> Result<(), Error> {
|
||||
pub fn run(stdin: bool, check: bool, files: Vec<String>) -> Result<(), Vec<Error>> {
|
||||
if stdin {
|
||||
process_stdin(check)
|
||||
} else {
|
||||
|
@ -20,7 +20,7 @@ pub fn run(stdin: bool, check: bool, files: Vec<String>) -> Result<(), Error> {
|
|||
}
|
||||
}
|
||||
|
||||
fn process_stdin(check: bool) -> Result<(), Error> {
|
||||
fn process_stdin(check: bool) -> Result<(), Vec<Error>> {
|
||||
let src = read_stdin()?;
|
||||
|
||||
let mut out = String::new();
|
||||
|
@ -36,20 +36,20 @@ fn process_stdin(check: bool) -> Result<(), Error> {
|
|||
}
|
||||
|
||||
if src != out {
|
||||
return Err(Error::Format {
|
||||
return Err(vec![Error::Format {
|
||||
problem_files: vec![Unformatted {
|
||||
source: PathBuf::from("<standard input>"),
|
||||
destination: PathBuf::from("<standard output>"),
|
||||
input: src,
|
||||
output: out,
|
||||
}],
|
||||
});
|
||||
}]);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_files(check: bool, files: Vec<String>) -> Result<(), Error> {
|
||||
fn process_files(check: bool, files: Vec<String>) -> Result<(), Vec<Error>> {
|
||||
if check {
|
||||
check_files(files)
|
||||
} else {
|
||||
|
@ -57,39 +57,39 @@ fn process_files(check: bool, files: Vec<String>) -> Result<(), Error> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_files(files: Vec<String>) -> Result<(), Error> {
|
||||
fn check_files(files: Vec<String>) -> Result<(), Vec<Error>> {
|
||||
let problem_files = unformatted_files(files)?;
|
||||
|
||||
if problem_files.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::Format { problem_files })
|
||||
Err(Error::Format { problem_files }.into())
|
||||
}
|
||||
}
|
||||
|
||||
fn format_files(files: Vec<String>) -> Result<(), Error> {
|
||||
fn format_files(files: Vec<String>) -> Result<(), Vec<Error>> {
|
||||
for file in unformatted_files(files)? {
|
||||
fs::write(file.destination, file.output)?;
|
||||
fs::write(file.destination, file.output).map_err(Error::from)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unformatted_files(files: Vec<String>) -> Result<Vec<Unformatted>, Error> {
|
||||
fn unformatted_files(files: Vec<String>) -> Result<Vec<Unformatted>, Vec<Error>> {
|
||||
let mut problem_files = Vec::with_capacity(files.len());
|
||||
let mut errors = Error::List(vec![]);
|
||||
let mut errors = vec![];
|
||||
|
||||
for file_path in files {
|
||||
let path = PathBuf::from_str(&file_path).unwrap();
|
||||
|
||||
if path.is_dir() {
|
||||
for path in aiken_files_excluding_gitignore(&path) {
|
||||
if let Err(err) = format_file(&mut problem_files, path) {
|
||||
errors = errors.append(err);
|
||||
if let Err(mut errs) = format_file(&mut problem_files, path) {
|
||||
errors.append(&mut errs);
|
||||
};
|
||||
}
|
||||
} else if let Err(err) = format_file(&mut problem_files, path) {
|
||||
errors = errors.append(err);
|
||||
} else if let Err(mut errs) = format_file(&mut problem_files, path) {
|
||||
errors.append(&mut errs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ fn unformatted_files(files: Vec<String>) -> Result<Vec<Unformatted>, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
fn format_file(problem_files: &mut Vec<Unformatted>, path: PathBuf) -> Result<(), Error> {
|
||||
fn format_file(problem_files: &mut Vec<Unformatted>, path: PathBuf) -> Result<(), Vec<Error>> {
|
||||
let src = fs::read_to_string(&path).map_err(|error| Error::FileIo {
|
||||
error,
|
||||
path: path.clone(),
|
||||
|
|
|
@ -67,7 +67,7 @@ where
|
|||
module_types: HashMap<String, TypeInfo>,
|
||||
root: PathBuf,
|
||||
sources: Vec<Source>,
|
||||
pub warnings: Vec<Warning>,
|
||||
warnings: Vec<Warning>,
|
||||
event_listener: T,
|
||||
functions: IndexMap<FunctionAccessKey, TypedFunction>,
|
||||
data_types: IndexMap<DataTypeKey, TypedDataType>,
|
||||
|
@ -78,6 +78,14 @@ where
|
|||
T: EventListener,
|
||||
{
|
||||
pub fn new(root: PathBuf, event_listener: T) -> Result<Project<T>, Error> {
|
||||
let config = Config::load(&root)?;
|
||||
|
||||
let project = Project::new_with_config(config, root, event_listener);
|
||||
|
||||
Ok(project)
|
||||
}
|
||||
|
||||
pub fn new_with_config(config: Config, root: PathBuf, event_listener: T) -> Project<T> {
|
||||
let id_gen = IdGenerator::new();
|
||||
|
||||
let mut module_types = HashMap::new();
|
||||
|
@ -89,9 +97,7 @@ where
|
|||
|
||||
let data_types = builtins::prelude_data_types(&id_gen);
|
||||
|
||||
let config = Config::load(&root)?;
|
||||
|
||||
Ok(Project {
|
||||
Project {
|
||||
config,
|
||||
checked_modules: CheckedModules::default(),
|
||||
defined_modules: HashMap::new(),
|
||||
|
@ -103,10 +109,30 @@ where
|
|||
event_listener,
|
||||
functions,
|
||||
data_types,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(&mut self, uplc: bool, tracing: Tracing) -> Result<(), Error> {
|
||||
pub fn warnings(&mut self) -> Vec<Warning> {
|
||||
std::mem::take(&mut self.warnings)
|
||||
}
|
||||
|
||||
pub fn modules(&self) -> Vec<CheckedModule> {
|
||||
self.checked_modules.values().cloned().collect()
|
||||
}
|
||||
|
||||
pub fn checkpoint(&self) -> Checkpoint {
|
||||
Checkpoint {
|
||||
module_types: self.module_types.clone(),
|
||||
defined_modules: self.defined_modules.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn restore(&mut self, checkpoint: Checkpoint) {
|
||||
self.module_types = checkpoint.module_types;
|
||||
self.defined_modules = checkpoint.defined_modules;
|
||||
}
|
||||
|
||||
pub fn build(&mut self, uplc: bool, tracing: Tracing) -> Result<(), Vec<Error>> {
|
||||
let options = Options {
|
||||
code_gen_mode: CodeGenMode::Build(uplc),
|
||||
tracing,
|
||||
|
@ -115,7 +141,7 @@ where
|
|||
self.compile(options)
|
||||
}
|
||||
|
||||
pub fn docs(&mut self, destination: Option<PathBuf>) -> Result<(), Error> {
|
||||
pub fn docs(&mut self, destination: Option<PathBuf>) -> Result<(), Vec<Error>> {
|
||||
self.compile_deps()?;
|
||||
|
||||
self.event_listener
|
||||
|
@ -145,8 +171,8 @@ where
|
|||
|
||||
for file in doc_files {
|
||||
let path = destination.join(file.path);
|
||||
fs::create_dir_all(path.parent().unwrap())?;
|
||||
fs::write(&path, file.content)?;
|
||||
fs::create_dir_all(path.parent().unwrap()).map_err(Error::from)?;
|
||||
fs::write(&path, file.content).map_err(Error::from)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -159,7 +185,7 @@ where
|
|||
verbose: bool,
|
||||
exact_match: bool,
|
||||
tracing: Tracing,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), Vec<Error>> {
|
||||
let options = Options {
|
||||
tracing,
|
||||
code_gen_mode: if skip_tests {
|
||||
|
@ -198,7 +224,7 @@ where
|
|||
self.root.join("plutus.json")
|
||||
}
|
||||
|
||||
pub fn compile(&mut self, options: Options) -> Result<(), Error> {
|
||||
pub fn compile(&mut self, options: Options) -> Result<(), Vec<Error>> {
|
||||
self.compile_deps()?;
|
||||
|
||||
self.event_listener
|
||||
|
@ -239,9 +265,13 @@ where
|
|||
}
|
||||
|
||||
let json = serde_json::to_string_pretty(&blueprint).unwrap();
|
||||
fs::write(self.blueprint_path(), json).map_err(|error| Error::FileIo {
|
||||
|
||||
fs::write(self.blueprint_path(), json).map_err(|error| {
|
||||
Error::FileIo {
|
||||
error,
|
||||
path: self.blueprint_path(),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
}
|
||||
CodeGenMode::Test {
|
||||
|
@ -278,7 +308,7 @@ where
|
|||
.handle_event(Event::FinishedTests { tests: results });
|
||||
|
||||
if !errors.is_empty() {
|
||||
Err(Error::List(errors))
|
||||
Err(errors)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -372,7 +402,7 @@ where
|
|||
Ok(blueprint)
|
||||
}
|
||||
|
||||
fn compile_deps(&mut self) -> Result<(), Error> {
|
||||
fn compile_deps(&mut self) -> Result<(), Vec<Error>> {
|
||||
let manifest = deps::download(
|
||||
&self.event_listener,
|
||||
UseManifest::Yes,
|
||||
|
@ -416,7 +446,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_sources(&mut self, package_name: PackageName) -> Result<ParsedModules, Error> {
|
||||
fn parse_sources(&mut self, package_name: PackageName) -> Result<ParsedModules, Vec<Error>> {
|
||||
let mut errors = Vec::new();
|
||||
let mut parsed_modules = HashMap::with_capacity(self.sources.len());
|
||||
|
||||
|
@ -450,7 +480,8 @@ where
|
|||
module: module.name.clone(),
|
||||
first,
|
||||
second: module.path,
|
||||
});
|
||||
}
|
||||
.into());
|
||||
}
|
||||
|
||||
module.attach_doc_and_module_comments();
|
||||
|
@ -473,7 +504,7 @@ where
|
|||
if errors.is_empty() {
|
||||
Ok(parsed_modules.into())
|
||||
} else {
|
||||
Err(Error::List(errors))
|
||||
Err(errors)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,10 @@ use crate::{error::Error, package_name::PackageName};
|
|||
use reqwest::Client;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn project_config() -> PathBuf {
|
||||
PathBuf::from("aiken.toml")
|
||||
}
|
||||
|
||||
pub fn manifest() -> PathBuf {
|
||||
PathBuf::from("aiken.lock")
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::script::EvalInfo;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub trait EventListener: std::fmt::Debug {
|
||||
fn handle_event(&self, event: Event);
|
||||
pub trait EventListener {
|
||||
fn handle_event(&self, _event: Event) {}
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
|
|
|
@ -56,9 +56,12 @@ pub fn exec(
|
|||
|
||||
let json = serde_json::to_string_pretty(&blueprint).unwrap();
|
||||
|
||||
fs::write(p.blueprint_path(), json).map_err(|error| Error::FileIo {
|
||||
fs::write(p.blueprint_path(), json).map_err(|error| {
|
||||
Error::FileIo {
|
||||
error,
|
||||
path: p.blueprint_path(),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -21,10 +21,12 @@ pub fn exec(
|
|||
files,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
if let Err(err) = aiken_project::format::run(stdin, check, files) {
|
||||
if let Err(errs) = aiken_project::format::run(stdin, check, files) {
|
||||
for err in &errs {
|
||||
err.report();
|
||||
}
|
||||
|
||||
miette::bail!("failed: {} error(s)", err.len());
|
||||
miette::bail!("failed: {} error(s)", errs.len());
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -8,7 +8,7 @@ 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>,
|
||||
A: FnMut(&mut Project<Terminal>) -> Result<(), Vec<aiken_project::error::Error>>,
|
||||
{
|
||||
let project_path = if let Some(d) = directory {
|
||||
d
|
||||
|
@ -26,23 +26,28 @@ where
|
|||
|
||||
let build_result = action(&mut project);
|
||||
|
||||
let warning_count = project.warnings.len();
|
||||
let warnings = project.warnings();
|
||||
|
||||
for warning in project.warnings {
|
||||
let warning_count = warnings.len();
|
||||
|
||||
for warning in warnings {
|
||||
warning.report()
|
||||
}
|
||||
|
||||
let plural = if warning_count == 1 { "" } else { "s" };
|
||||
|
||||
if let Err(err) = build_result {
|
||||
err.report();
|
||||
if let Err(errs) = build_result {
|
||||
for err in &errs {
|
||||
err.report()
|
||||
}
|
||||
|
||||
println!("\n{}", "Summary".purple().bold());
|
||||
|
||||
let warning_text = format!("{warning_count} warning{plural}");
|
||||
|
||||
let plural = if err.len() == 1 { "" } else { "s" };
|
||||
let plural = if errs.len() == 1 { "" } else { "s" };
|
||||
|
||||
let error_text = format!("{} error{}", err.len(), plural);
|
||||
let error_text = format!("{} error{}", errs.len(), plural);
|
||||
|
||||
let full_summary = format!(" {}, {}", error_text.red(), warning_text.yellow());
|
||||
|
||||
|
|
Loading…
Reference in New Issue