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"
|
name = "chrysopoeia"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
"clap-cargo",
|
||||||
"config",
|
"config",
|
||||||
"git2",
|
"git2",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
@ -107,6 +110,16 @@ dependencies = [
|
||||||
"clap_derive",
|
"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]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.32"
|
version = "4.5.32"
|
||||||
|
|
|
@ -5,8 +5,11 @@ edition = "2024"
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anstream = "0.6.18"
|
||||||
|
anstyle = "1.0.10"
|
||||||
anyhow = "1.0.97"
|
anyhow = "1.0.97"
|
||||||
clap = { version = "4.5.32", features = ["derive"] }
|
clap = { version = "4.5.32", features = ["derive"] }
|
||||||
|
clap-cargo = "0.15.2"
|
||||||
config = { version = "0.15.11", default-features = false, features = ["toml"] }
|
config = { version = "0.15.11", default-features = false, features = ["toml"] }
|
||||||
git2 = "0.20.1"
|
git2 = "0.20.1"
|
||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
|
|
|
@ -11,8 +11,8 @@ pub enum Error {
|
||||||
NoCompiler,
|
NoCompiler,
|
||||||
|
|
||||||
/// user specified a compiler and it didn't work
|
/// user specified a compiler and it didn't work
|
||||||
#[error("couldn't execute `{cmd}`: {src}")]
|
#[error("couldn't execute `{cmd}`: {e}")]
|
||||||
BadCompiler { cmd: String, src: io::Error },
|
BadCompiler { cmd: String, e: io::Error },
|
||||||
|
|
||||||
/// user specified a compiler and it's nonsense
|
/// user specified a compiler and it's nonsense
|
||||||
#[error("compiler can't be empty")]
|
#[error("compiler can't be empty")]
|
||||||
|
@ -57,7 +57,7 @@ impl<'a> Build<'a> {
|
||||||
return match self.try_compile(cmd, output_path) {
|
return match self.try_compile(cmd, output_path) {
|
||||||
Err(e) => Err(Error::BadCompiler {
|
Err(e) => Err(Error::BadCompiler {
|
||||||
cmd: compiler.to_owned(),
|
cmd: compiler.to_owned(),
|
||||||
src: e,
|
e,
|
||||||
}),
|
}),
|
||||||
Ok(output) => to_res(output),
|
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::Parser;
|
||||||
|
use clap_cargo::style::CLAP_STYLING;
|
||||||
use git2::Repository;
|
use git2::Repository;
|
||||||
|
|
||||||
mod cc;
|
mod cc;
|
||||||
|
mod console;
|
||||||
mod languages;
|
mod languages;
|
||||||
mod settings;
|
mod settings;
|
||||||
|
|
||||||
|
use console::{Color, error};
|
||||||
use languages::{InstallInfo, get_install_info};
|
use languages::{InstallInfo, get_install_info};
|
||||||
use settings::{Settings, get_settings};
|
use settings::{Settings, get_settings};
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
|
#[command(styles = CLAP_STYLING)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
|
/// when to use terminal colors
|
||||||
|
#[arg(short, long, value_enum, default_value_t = Color::Auto)]
|
||||||
|
color: Color,
|
||||||
|
|
||||||
language: String,
|
language: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> ExitCode {
|
||||||
let Cli { language } = Cli::parse();
|
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 {
|
let Settings {
|
||||||
parser_dir,
|
parser_dir,
|
||||||
compiler,
|
compiler,
|
||||||
|
@ -31,23 +50,43 @@ fn main() -> anyhow::Result<()> {
|
||||||
// have to use a canonical path bc compiler runs elsewhere
|
// have to use a canonical path bc compiler runs elsewhere
|
||||||
let parser_dir = parser_dir.canonicalize()?;
|
let parser_dir = parser_dir.canonicalize()?;
|
||||||
|
|
||||||
let InstallInfo { url, files } =
|
Ok(install(
|
||||||
get_install_info(&language).ok_or(anyhow::anyhow!("unknown language `{language}`"))?;
|
&language,
|
||||||
|
&parser_dir,
|
||||||
|
src_dir.as_ref(),
|
||||||
|
compiler.as_deref(),
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
|
||||||
let repo_path = src_dir.as_ref().join(&language);
|
#[derive(Debug, thiserror::Error)]
|
||||||
Repository::clone(url, &repo_path)?;
|
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 output_path = parser_dir.join(language).with_extension(DLL_EXTENSION);
|
||||||
|
|
||||||
let mut build = cc::Build::new();
|
let mut build = cc::Build::new();
|
||||||
build
|
build.compiler(compiler).dir(&repo_path).input_files(files);
|
||||||
.compiler(compiler.as_deref())
|
|
||||||
.dir(&repo_path)
|
|
||||||
.input_files(files);
|
|
||||||
build.compile(&output_path)?;
|
build.compile(&output_path)?;
|
||||||
|
|
||||||
// close explicitly to prevent premature drop
|
|
||||||
src_dir.close()?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue