in src/main.rs [233:530]
fn real_main() -> Result<(), miette::Report> {
use cli::Commands::*;
let fake_cli = cli::FakeCli::parse();
let cli::FakeCli::Vet(cli) = fake_cli;
//////////////////////////////////////////////////////
// Setup logging / output
//////////////////////////////////////////////////////
// Init the logger (and make trace logging less noisy)
if let Some(log_path) = &cli.log_file {
let log_file = File::create(log_path).unwrap();
tracing_subscriber::fmt::fmt()
.with_max_level(cli.verbose)
.with_target(false)
.without_time()
.with_ansi(false)
.with_writer(log_file)
.init();
} else {
tracing_subscriber::fmt::fmt()
.with_max_level(cli.verbose)
.with_target(false)
.without_time()
.with_ansi(console::colors_enabled_stderr())
.with_writer(StderrLogWriter::new)
.init();
}
// Control how errors are formatted by setting the miette hook. This will
// only be used for errors presented to humans, when formatting an error as
// JSON, it will be handled by a custom `report_error` override, bypassing
// the hook.
let using_log_file = cli.log_file.is_some();
miette::set_hook(Box::new(move |_| {
let graphical_theme = if console::colors_enabled_stderr() && !using_log_file {
miette::GraphicalTheme::unicode()
} else {
miette::GraphicalTheme::unicode_nocolor()
};
Box::new(
miette::MietteHandlerOpts::new()
.graphical_theme(graphical_theme)
.build(),
)
}))
.expect("failed to initialize error handler");
// Now that miette is set up, use it to format panics.
panic::set_hook(Box::new(move |panic_info| {
if panic_info.payload().is::<ExitPanic>() {
return;
}
let payload = panic_info.payload();
let message = if let Some(msg) = payload.downcast_ref::<&str>() {
msg
} else if let Some(msg) = payload.downcast_ref::<String>() {
&msg[..]
} else {
"something went wrong"
};
#[derive(Debug, Error, Diagnostic)]
#[error("{message}")]
pub struct PanicError {
pub message: String,
#[help]
pub help: Option<String>,
}
report_error(
&miette::Report::from(PanicError {
message: message.to_owned(),
help: panic_info
.location()
.map(|loc| format!("at {}:{}:{}", loc.file(), loc.line(), loc.column())),
})
.wrap_err("cargo vet panicked"),
);
}));
// Initialize the MULTIPROGRESS's draw target, so that future progress
// events are rendered to stderr.
MULTIPROGRESS.set_draw_target(ProgressDrawTarget::stderr());
// Setup our output stream
let out: Arc<dyn Out> = if let Some(output_path) = &cli.output_file {
Arc::new(File::create(output_path).unwrap())
} else {
Arc::new(Term::stdout())
};
// If we're outputting JSON, replace the error report method such that it
// writes errors out to the normal output stream as JSON.
if cli.output_format == OutputFormat::Json {
set_report_errors_as_json(out.clone());
}
////////////////////////////////////////////////////
// Potentially handle freestanding commands
////////////////////////////////////////////////////
let cache_dir = cli.cache_dir.clone().unwrap_or_else(|| {
dirs::cache_dir()
.unwrap_or_else(std::env::temp_dir)
.join(CACHE_DIR_SUFFIX)
});
let now = cli
.current_time
.unwrap_or_else(|| chrono::DateTime::from(SystemTime::now()));
let partial_cfg = PartialConfig {
cli,
now,
cache_dir,
mock_cache: false,
};
match &partial_cfg.cli.command {
Some(Aggregate(sub_args)) => return cmd_aggregate(&out, &partial_cfg, sub_args),
Some(HelpMarkdown(sub_args)) => return cmd_help_md(&out, &partial_cfg, sub_args),
Some(Gc(sub_args)) => return cmd_gc(&out, &partial_cfg, sub_args),
_ => {
// Not a freestanding command, time to do full parsing and setup
}
}
///////////////////////////////////////////////////
// Fetch cargo metadata
///////////////////////////////////////////////////
let cli = &partial_cfg.cli;
let cargo_path = std::env::var_os(CARGO_ENV).expect("Cargo failed to set $CARGO, how?");
let mut cmd = cargo_metadata::MetadataCommand::new();
cmd.cargo_path(cargo_path);
if let Some(manifest_path) = &cli.manifest_path {
cmd.manifest_path(manifest_path);
}
if !cli.no_all_features {
cmd.features(cargo_metadata::CargoOpt::AllFeatures);
}
if cli.no_default_features {
cmd.features(cargo_metadata::CargoOpt::NoDefaultFeatures);
}
if !cli.features.is_empty() {
cmd.features(cargo_metadata::CargoOpt::SomeFeatures(cli.features.clone()));
}
// We never want cargo-vet to update the Cargo.lock.
// For frozen runs we also don't want to touch the network.
let mut other_options = Vec::new();
if cli.frozen {
other_options.push("--frozen".to_string());
} else {
other_options.push("--locked".to_string());
}
if !using_log_file
&& cli.output_format == OutputFormat::Human
&& console::colors_enabled_stderr()
{
other_options.push("--color=always".to_string());
}
other_options.extend(cli.cargo_arg.iter().cloned());
cmd.other_options(other_options);
info!("Running: {:#?}", cmd.cargo_command());
// ERRORS: immediate fatal diagnostic
let metadata = {
let _spinner = indeterminate_spinner("Running", "`cargo metadata`");
cmd.exec().map_err(MetadataAcquireError::from)?
};
// trace!("Got Metadata! {:#?}", metadata);
trace!("Got Metadata!");
//////////////////////////////////////////////////////
// Parse out our own configuration
//////////////////////////////////////////////////////
let default_config = MetaConfigInstance {
version: Some(1),
store: Some(StoreInfo {
path: Some(
metadata
.workspace_root
.join(storage::DEFAULT_STORE)
.into_std_path_buf(),
),
}),
};
// FIXME: what is `store.path` relative to here?
let workspace_metacfg = metadata
.workspace_metadata
.get(WORKSPACE_VET_CONFIG)
.map(|cfg| {
// ERRORS: immediate fatal diagnostic
MetaConfigInstance::deserialize(cfg)
.into_diagnostic()
.wrap_err("Workspace had [{WORKSPACE_VET_CONFIG}] but it was malformed")
})
.transpose()?;
// FIXME: what is `store.path` relative to here?
let package_metacfg = metadata
.root_package()
.and_then(|r| r.metadata.get(PACKAGE_VET_CONFIG))
.map(|cfg| {
// ERRORS: immediate fatal diagnostic
MetaConfigInstance::deserialize(cfg)
.into_diagnostic()
.wrap_err("Root package had [{PACKAGE_VET_CONFIG}] but it was malformed")
})
.transpose()?;
let cli_metacfg = cli.store_path.as_ref().map(|path| MetaConfigInstance {
version: Some(1),
store: Some(StoreInfo {
path: Some(path.clone()),
}),
});
if workspace_metacfg.is_some() && package_metacfg.is_some() {
// ERRORS: immediate fatal diagnostic
return Err(miette!("Both a workspace and a package defined [metadata.vet]! We don't know what that means, if you do, let us know!"));
}
let mut metacfgs = vec![default_config];
if let Some(metacfg) = workspace_metacfg {
metacfgs.push(metacfg);
}
if let Some(metacfg) = package_metacfg {
metacfgs.push(metacfg);
}
if let Some(metacfg) = cli_metacfg {
metacfgs.push(metacfg);
}
let metacfg = MetaConfig(metacfgs);
info!("Final Metadata Config: ");
info!(" - version: {}", metacfg.version());
info!(" - store.path: {:#?}", metacfg.store_path());
//////////////////////////////////////////////////////
// Run the actual command
//////////////////////////////////////////////////////
let init = Store::is_init(&metacfg);
if matches!(cli.command, Some(Commands::Init { .. })) {
if init {
// ERRORS: immediate fatal diagnostic
return Err(miette!(
"'cargo vet' already initialized (store found at {})",
metacfg.store_path().display()
));
}
} else if !init {
// ERRORS: immediate fatal diagnostic
return Err(miette!(
"You must run 'cargo vet init' (store not found at {})",
metacfg.store_path().display()
));
}
let cfg = Config {
metacfg,
metadata,
_rest: partial_cfg,
};
use RegenerateSubcommands::*;
match &cfg.cli.command {
None => cmd_check(&out, &cfg, &cfg.cli.check_args),
Some(Check(sub_args)) => cmd_check(&out, &cfg, sub_args),
Some(Init(sub_args)) => cmd_init(&out, &cfg, sub_args),
Some(Certify(sub_args)) => cmd_certify(&out, &cfg, sub_args),
Some(Import(sub_args)) => cmd_import(&out, &cfg, sub_args),
Some(Trust(sub_args)) => cmd_trust(&out, &cfg, sub_args),
Some(AddExemption(sub_args)) => cmd_add_exemption(&out, &cfg, sub_args),
Some(RecordViolation(sub_args)) => cmd_record_violation(&out, &cfg, sub_args),
Some(Suggest(sub_args)) => cmd_suggest(&out, &cfg, sub_args),
Some(Fmt(sub_args)) => cmd_fmt(&out, &cfg, sub_args),
Some(Prune(sub_args)) => cmd_prune(&out, &cfg, sub_args),
Some(DumpGraph(sub_args)) => cmd_dump_graph(&out, &cfg, sub_args),
Some(Inspect(sub_args)) => cmd_inspect(&out, &cfg, sub_args),
Some(Diff(sub_args)) => cmd_diff(&out, &cfg, sub_args),
Some(Regenerate(Imports(sub_args))) => cmd_regenerate_imports(&out, &cfg, sub_args),
Some(Regenerate(Exemptions(sub_args))) => cmd_regenerate_exemptions(&out, &cfg, sub_args),
Some(Regenerate(AuditAsCratesIo(sub_args))) => {
cmd_regenerate_audit_as(&out, &cfg, sub_args)
}
Some(Regenerate(Unpublished(sub_args))) => cmd_regenerate_unpublished(&out, &cfg, sub_args),
Some(Renew(sub_args)) => cmd_renew(&out, &cfg, sub_args),
Some(Aggregate(_)) | Some(HelpMarkdown(_)) | Some(Gc(_)) => unreachable!("handled earlier"),
}
}