prettier error reporting
This commit is contained in:
parent
01090ac792
commit
d84b074dde
5 changed files with 142 additions and 17 deletions
13
Cargo.lock
generated
13
Cargo.lock
generated
|
@ -85,8 +85,11 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
name = "chrysopoeia"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap-cargo",
|
||||
"config",
|
||||
"git2",
|
||||
"lazy_static",
|
||||
|
@ -107,6 +110,16 @@ dependencies = [
|
|||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap-cargo"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d546f0e84ff2bfa4da1ce9b54be42285767ba39c688572ca32412a09a73851e5"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.32"
|
||||
|
|
|
@ -5,8 +5,11 @@ edition = "2024"
|
|||
license = "GPL-3.0-only"
|
||||
|
||||
[dependencies]
|
||||
anstream = "0.6.18"
|
||||
anstyle = "1.0.10"
|
||||
anyhow = "1.0.97"
|
||||
clap = { version = "4.5.32", features = ["derive"] }
|
||||
clap-cargo = "0.15.2"
|
||||
config = { version = "0.15.11", default-features = false, features = ["toml"] }
|
||||
git2 = "0.20.1"
|
||||
lazy_static = "1.5.0"
|
||||
|
|
|
@ -11,8 +11,8 @@ pub enum Error {
|
|||
NoCompiler,
|
||||
|
||||
/// user specified a compiler and it didn't work
|
||||
#[error("couldn't execute `{cmd}`: {src}")]
|
||||
BadCompiler { cmd: String, src: io::Error },
|
||||
#[error("couldn't execute `{cmd}`: {e}")]
|
||||
BadCompiler { cmd: String, e: io::Error },
|
||||
|
||||
/// user specified a compiler and it's nonsense
|
||||
#[error("compiler can't be empty")]
|
||||
|
@ -57,7 +57,7 @@ impl<'a> Build<'a> {
|
|||
return match self.try_compile(cmd, output_path) {
|
||||
Err(e) => Err(Error::BadCompiler {
|
||||
cmd: compiler.to_owned(),
|
||||
src: e,
|
||||
e,
|
||||
}),
|
||||
Ok(output) => to_res(output),
|
||||
};
|
||||
|
|
70
src/console.rs
Normal file
70
src/console.rs
Normal file
|
@ -0,0 +1,70 @@
|
|||
use std::{
|
||||
fmt::Display,
|
||||
io::{Write, stderr},
|
||||
sync::OnceLock,
|
||||
};
|
||||
|
||||
use anstream::AutoStream;
|
||||
use anstyle::{AnsiColor, Effects, Style};
|
||||
use clap::ValueEnum;
|
||||
|
||||
pub const ERROR: Style = AnsiColor::Red.on_default().effects(Effects::BOLD);
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
|
||||
pub enum Color {
|
||||
Auto,
|
||||
Always,
|
||||
Never,
|
||||
}
|
||||
|
||||
impl From<Color> for anstream::ColorChoice {
|
||||
fn from(value: Color) -> Self {
|
||||
match value {
|
||||
Color::Always => Self::Always,
|
||||
Color::Never => Self::Never,
|
||||
Color::Auto => Self::Auto,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Console(anstream::ColorChoice);
|
||||
|
||||
impl Console {
|
||||
fn new(color: Color) -> Self {
|
||||
Self(color.into())
|
||||
}
|
||||
|
||||
pub fn print(&self, status: &str, style: &Style, msg: impl Display) {
|
||||
let mut stream = AutoStream::new(stderr(), self.0).lock();
|
||||
let _ = writeln!(stream, "{style}{status}{style:#} {msg}");
|
||||
}
|
||||
}
|
||||
|
||||
static CONSOLE: OnceLock<Console> = OnceLock::new();
|
||||
|
||||
pub fn console() -> &'static Console {
|
||||
CONSOLE.get().expect("console should be initialized")
|
||||
}
|
||||
|
||||
pub fn init(color: Color) {
|
||||
CONSOLE
|
||||
.set(Console::new(color))
|
||||
.expect("console should only be initialized once")
|
||||
}
|
||||
|
||||
macro_rules! error {
|
||||
($arg:expr) => (
|
||||
crate::console::console().print("error:", &crate::console::ERROR, ($arg))
|
||||
);
|
||||
|
||||
($($arg:tt)+) => (
|
||||
crate::console::console().print(
|
||||
"error:",
|
||||
&crate::console::ERROR,
|
||||
format_args!($($arg)+),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) use error;
|
67
src/main.rs
67
src/main.rs
|
@ -1,24 +1,43 @@
|
|||
use std::{env::consts::DLL_EXTENSION, fs::create_dir_all};
|
||||
use std::{env::consts::DLL_EXTENSION, fs::create_dir_all, path::Path, process::ExitCode};
|
||||
|
||||
use clap::Parser;
|
||||
use clap_cargo::style::CLAP_STYLING;
|
||||
use git2::Repository;
|
||||
|
||||
mod cc;
|
||||
mod console;
|
||||
mod languages;
|
||||
mod settings;
|
||||
|
||||
use console::{Color, error};
|
||||
use languages::{InstallInfo, get_install_info};
|
||||
use settings::{Settings, get_settings};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(version, about, long_about = None)]
|
||||
#[command(styles = CLAP_STYLING)]
|
||||
struct Cli {
|
||||
/// when to use terminal colors
|
||||
#[arg(short, long, value_enum, default_value_t = Color::Auto)]
|
||||
color: Color,
|
||||
|
||||
language: String,
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let Cli { language } = Cli::parse();
|
||||
fn main() -> ExitCode {
|
||||
let cli = Cli::parse();
|
||||
|
||||
console::init(cli.color);
|
||||
|
||||
if let Err(e) = main_inner(cli) {
|
||||
error!(e);
|
||||
ExitCode::FAILURE
|
||||
} else {
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
fn main_inner(Cli { language, .. }: Cli) -> anyhow::Result<()> {
|
||||
let Settings {
|
||||
parser_dir,
|
||||
compiler,
|
||||
|
@ -31,23 +50,43 @@ fn main() -> anyhow::Result<()> {
|
|||
// have to use a canonical path bc compiler runs elsewhere
|
||||
let parser_dir = parser_dir.canonicalize()?;
|
||||
|
||||
let InstallInfo { url, files } =
|
||||
get_install_info(&language).ok_or(anyhow::anyhow!("unknown language `{language}`"))?;
|
||||
Ok(install(
|
||||
&language,
|
||||
&parser_dir,
|
||||
src_dir.as_ref(),
|
||||
compiler.as_deref(),
|
||||
)?)
|
||||
}
|
||||
|
||||
let repo_path = src_dir.as_ref().join(&language);
|
||||
Repository::clone(url, &repo_path)?;
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
enum InstallError {
|
||||
#[error("unknown language `{0}`")]
|
||||
UnknownLanguage(String),
|
||||
|
||||
#[error("couldn't clone `{0}`")]
|
||||
Clone(&'static str),
|
||||
|
||||
#[error(transparent)]
|
||||
Compile(#[from] cc::Error),
|
||||
}
|
||||
|
||||
fn install(
|
||||
language: &str,
|
||||
parser_dir: &Path,
|
||||
src_dir: &Path,
|
||||
compiler: Option<&str>,
|
||||
) -> Result<(), InstallError> {
|
||||
let InstallInfo { url, files } =
|
||||
get_install_info(language).ok_or(InstallError::UnknownLanguage(language.to_owned()))?;
|
||||
|
||||
let repo_path = src_dir.join(language);
|
||||
Repository::clone(url, &repo_path).map_err(|_| InstallError::Clone(url))?;
|
||||
|
||||
let output_path = parser_dir.join(language).with_extension(DLL_EXTENSION);
|
||||
|
||||
let mut build = cc::Build::new();
|
||||
build
|
||||
.compiler(compiler.as_deref())
|
||||
.dir(&repo_path)
|
||||
.input_files(files);
|
||||
build.compiler(compiler).dir(&repo_path).input_files(files);
|
||||
build.compile(&output_path)?;
|
||||
|
||||
// close explicitly to prevent premature drop
|
||||
src_dir.close()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue