#![warn(unused_crate_dependencies)]
use std::{env, process};
use clap::ColorChoice;
use color_eyre::Section;
use color_eyre::config::{HookBuilder, Theme};
use color_eyre::eyre::{Result, WrapErr};
use log::LevelFilter;
use pretty_env_logger::env_logger::WriteStyle;
#[cfg(test)]
use {snapbox as _, tempfile as _, trycmd as _};
mod cargo;
mod cli;
use cli::{LinerArgs, LinerCommands, ShipArgs};
mod config;
use config::{EffectiveJettisonConfig, EffectiveShipConfig, UserConfig};
mod coloring;
use coloring::Colorizer;
mod commands;
#[cfg(test)]
#[path = "../tests/common/mod.rs"]
mod testing;
pub const OPEN_ISSUE_MSG: &str =
"Open an issue using https://github.com/PaulDance/cargo-liner/issues/new/choose.";
fn main() -> Result<()> {
human_panic::setup_panic!();
let args = LinerArgs::parse_env();
if let verb @ 1.. = args.verbosity() {
unsafe {
env::set_var(
"RUST_BACKTRACE",
match verb {
1 => "1",
_ => "full",
},
);
}
}
install_error_hook(&args)?;
try_main(&args).inspect_err(|_| {
if args.verbosity() <= -3 {
process::exit(1);
}
})
}
fn install_error_hook(args: &LinerArgs) -> Result<()> {
if args.color == ColorChoice::Never {
HookBuilder::new().theme(Theme::new()).install()
} else {
color_eyre::install()
}
.wrap_err("Failed to install the error hook.")
.note("This should only happen if it is attempted twice.")
.suggestion(OPEN_ISSUE_MSG)
}
fn try_main(args: &LinerArgs) -> Result<()> {
init_logger(args)?;
let colorizer = Colorizer::new(&std::io::stderr(), args.color);
let cargo_verbosity = match args.verbosity() {
-2..=1 => 0,
v if v > 1 => v - 1,
q if q < -2 => q + 2,
_ => unreachable!(),
};
match &args.command {
Some(LinerCommands::Completions(comp_args)) => {
commands::completions::run(comp_args);
}
Some(LinerCommands::Import(import_args)) => {
commands::import::run(import_args)?;
}
Some(LinerCommands::Jettison(jettison_args)) => {
commands::jettison::run(
&EffectiveJettisonConfig::new(
UserConfig::parse_file().wrap_err("Failed to parse the user configuration.")?,
config::env::jettison_env_args()
.wrap_err("Failed to get one of the environment variables.")?,
jettison_args.as_ref().to_owned(),
),
*colorizer.color(),
cargo_verbosity,
)?;
}
cmd @ (None | Some(LinerCommands::Ship(_))) => {
commands::ship::run(
&EffectiveShipConfig::new(
UserConfig::parse_file().wrap_err("Failed to parse the user configuration.")?,
config::env::ship_env_args()
.wrap_err("Failed to get one of the environment variables.")?,
if let Some(LinerCommands::Ship(ship_args)) = cmd {
ship_args.as_ref().to_owned()
} else {
ShipArgs::default()
},
),
&colorizer,
cargo_verbosity,
)?;
}
}
log::info!("Done.");
Ok(())
}
fn init_logger(args: &LinerArgs) -> Result<()> {
let mut bld = pretty_env_logger::formatted_builder();
bld.parse_default_env();
if args.verbosity().abs() < 2 {
bld.filter_module("::", LevelFilter::Error);
bld.filter_module(
env!("CARGO_CRATE_NAME"),
match args.verbosity() {
0 => LevelFilter::Info,
1 => LevelFilter::Debug,
-1 => LevelFilter::Warn,
_ => unreachable!(),
},
);
} else {
bld.filter_level(match args.verbosity() {
2 => LevelFilter::Debug,
v if v > 2 => LevelFilter::Trace,
-2 => LevelFilter::Error,
q if q < -2 => LevelFilter::Off,
_ => unreachable!(),
});
}
bld.write_style(match args.color {
ColorChoice::Always => WriteStyle::Always,
ColorChoice::Auto => WriteStyle::Auto,
ColorChoice::Never => WriteStyle::Never,
});
bld.try_init()
.wrap_err("Failed to initialize the logger.")
.note("This should only happen if it is attempted twice.")
.suggestion(OPEN_ISSUE_MSG)
}