Improve error reporting
This commit is contained in:
parent
fae58994e4
commit
c271780b63
9 changed files with 93 additions and 17 deletions
10
src/cli.rs
10
src/cli.rs
|
@ -56,13 +56,19 @@ macro_rules! register_command {
|
|||
macro_rules! handle_command {
|
||||
($module:ident, $matches:ident) => {
|
||||
if let Some(sub_matches) = $matches.subcommand_matches(stringify!($module)) {
|
||||
command::$module::run(&$matches, &sub_matches).await;
|
||||
crate::troubleshooter::run_wrapped(
|
||||
&$matches, &sub_matches,
|
||||
command::$module::run,
|
||||
).await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
($name:expr, $module:ident, $matches:ident) => {
|
||||
if let Some(sub_matches) = $matches.subcommand_matches($name) {
|
||||
command::$module::run(&$matches, &sub_matches).await;
|
||||
crate::troubleshooter::run_wrapped(
|
||||
&$matches, &sub_matches,
|
||||
command::$module::run,
|
||||
).await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@ use crate::nix::deployment::{
|
|||
EvaluationNodeLimit,
|
||||
ParallelismLimit,
|
||||
};
|
||||
use crate::nix::NixError;
|
||||
use crate::nix::host::local as localhost;
|
||||
use crate::util;
|
||||
|
||||
|
@ -114,13 +115,13 @@ pub fn subcommand() -> App<'static, 'static> {
|
|||
util::register_selector_args(command)
|
||||
}
|
||||
|
||||
pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
||||
let hive = util::hive_from_args(local_args).await.unwrap();
|
||||
pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) -> Result<(), NixError> {
|
||||
let hive = util::hive_from_args(local_args).await?;
|
||||
|
||||
log::info!("Enumerating nodes...");
|
||||
let all_nodes = hive.deployment_info().await.unwrap();
|
||||
let all_nodes = hive.deployment_info().await?;
|
||||
|
||||
let nix_options = hive.nix_options().await.unwrap();
|
||||
let nix_options = hive.nix_options().await?;
|
||||
|
||||
let selected_nodes = match local_args.value_of("on") {
|
||||
Some(filter) => {
|
||||
|
@ -241,4 +242,6 @@ pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
|||
if !success {
|
||||
quit::with_code(10);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::nix::deployment::{
|
|||
Target,
|
||||
DeploymentOptions,
|
||||
};
|
||||
use crate::nix::host;
|
||||
use crate::nix::{NixError, host};
|
||||
use crate::util;
|
||||
|
||||
pub fn subcommand() -> App<'static, 'static> {
|
||||
|
@ -57,7 +57,7 @@ By default, Colmena will deploy keys set in `deployment.keys` before activating
|
|||
.takes_value(false))
|
||||
}
|
||||
|
||||
pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
||||
pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) -> Result<(), NixError> {
|
||||
// Sanity check: Are we running NixOS?
|
||||
if let Ok(os_release) = fs::read_to_string("/etc/os-release").await {
|
||||
if !os_release.contains("ID=nixos\n") {
|
||||
|
@ -131,6 +131,8 @@ pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
|||
if !success {
|
||||
quit::with_code(10);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn escalate(sudo: &str) -> ! {
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::path::PathBuf;
|
|||
use clap::{Arg, App, AppSettings, SubCommand, ArgMatches};
|
||||
|
||||
use crate::util;
|
||||
use crate::nix::NixError;
|
||||
|
||||
pub fn subcommand() -> App<'static, 'static> {
|
||||
SubCommand::with_name("eval")
|
||||
|
@ -37,12 +38,12 @@ pub fn deprecated_alias() -> App<'static, 'static> {
|
|||
.setting(AppSettings::Hidden)
|
||||
}
|
||||
|
||||
pub async fn run(global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
||||
pub async fn run(global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) -> Result<(), NixError> {
|
||||
if let Some("introspect") = global_args.subcommand_name() {
|
||||
log::warn!("`colmena introspect` has been renamed to `colmena eval`. Please update your scripts.");
|
||||
}
|
||||
|
||||
let hive = util::hive_from_args(local_args).await.unwrap();
|
||||
let hive = util::hive_from_args(local_args).await?;
|
||||
|
||||
if !(local_args.is_present("expression") ^ local_args.is_present("expression_file")) {
|
||||
log::error!("Either an expression (-E) or a .nix file containing an expression should be specified, not both.");
|
||||
|
@ -57,11 +58,13 @@ pub async fn run(global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
|||
};
|
||||
|
||||
let instantiate = local_args.is_present("instantiate");
|
||||
let result = hive.introspect(expression, instantiate).await.unwrap();
|
||||
let result = hive.introspect(expression, instantiate).await?;
|
||||
|
||||
if instantiate {
|
||||
print!("{}", result);
|
||||
} else {
|
||||
println!("{}", result);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -54,11 +54,11 @@ It's recommended to use -- to separate Colmena options from the command to run.
|
|||
util::register_selector_args(command)
|
||||
}
|
||||
|
||||
pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
||||
let hive = util::hive_from_args(local_args).await.unwrap();
|
||||
pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) -> Result<(), NixError> {
|
||||
let hive = util::hive_from_args(local_args).await?;
|
||||
|
||||
log::info!("Enumerating nodes...");
|
||||
let all_nodes = hive.deployment_info().await.unwrap();
|
||||
let all_nodes = hive.deployment_info().await?;
|
||||
|
||||
let selected_nodes = match local_args.value_of("on") {
|
||||
Some(filter) => {
|
||||
|
@ -167,4 +167,6 @@ pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
|||
|
||||
join_all(futures).await;
|
||||
}).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
use clap::{App, SubCommand, ArgMatches};
|
||||
|
||||
use crate::nix::NixCheck;
|
||||
use crate::nix::{NixCheck, NixError};
|
||||
|
||||
pub fn subcommand() -> App<'static, 'static> {
|
||||
SubCommand::with_name("nix-info")
|
||||
.about("Show information about the current Nix installation")
|
||||
}
|
||||
|
||||
pub async fn run(_global_args: &ArgMatches<'_>, _local_args: &ArgMatches<'_>) {
|
||||
pub async fn run(_global_args: &ArgMatches<'_>, _local_args: &ArgMatches<'_>) -> Result<(), NixError> {
|
||||
let check = NixCheck::detect().await;
|
||||
check.print_version_info();
|
||||
check.print_flakes_info(false);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::time::Duration;
|
|||
use clap::{App, AppSettings, SubCommand, ArgMatches};
|
||||
use tokio::time;
|
||||
|
||||
use crate::nix::NixError;
|
||||
use crate::progress::{Progress, OutputStyle};
|
||||
|
||||
pub fn subcommand() -> App<'static, 'static> {
|
||||
|
@ -11,7 +12,7 @@ pub fn subcommand() -> App<'static, 'static> {
|
|||
.setting(AppSettings::Hidden)
|
||||
}
|
||||
|
||||
pub async fn run(_global_args: &ArgMatches<'_>, _local_args: &ArgMatches<'_>) {
|
||||
pub async fn run(_global_args: &ArgMatches<'_>, _local_args: &ArgMatches<'_>) -> Result<(), NixError> {
|
||||
let progress = Progress::with_style(OutputStyle::Condensed);
|
||||
let mut task = progress.create_task_progress(String::from("test"));
|
||||
|
||||
|
@ -21,4 +22,6 @@ pub async fn run(_global_args: &ArgMatches<'_>, _local_args: &ArgMatches<'_>) {
|
|||
}
|
||||
|
||||
task.success("Completed");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ mod nix;
|
|||
mod cli;
|
||||
mod command;
|
||||
mod progress;
|
||||
mod troubleshooter;
|
||||
mod util;
|
||||
|
||||
#[tokio::main]
|
||||
|
|
54
src/troubleshooter.rs
Normal file
54
src/troubleshooter.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
//! Automatic troubleshooter.
|
||||
//!
|
||||
//! Tries to provide some useful hints when things go wrong.
|
||||
|
||||
use std::env;
|
||||
use std::future::Future;
|
||||
|
||||
use clap::ArgMatches;
|
||||
|
||||
use crate::nix::NixError;
|
||||
|
||||
/// Runs a closure and tries to troubleshoot if it returns an error.
|
||||
pub async fn run_wrapped<'a, F, U, T>(global_args: &'a ArgMatches<'a>, local_args: &'a ArgMatches<'a>, f: U) -> T
|
||||
where U: FnOnce(&'a ArgMatches<'a>, &'a ArgMatches<'a>) -> F,
|
||||
F: Future<Output = Result<T, NixError>>,
|
||||
{
|
||||
match f(global_args, local_args).await {
|
||||
Ok(r) => r,
|
||||
Err(error) => {
|
||||
log::error!("-----");
|
||||
log::error!("Operation failed with error: {}", error);
|
||||
|
||||
if let Err(own_error) = troubleshoot(global_args, local_args, &error) {
|
||||
log::error!("Error occurred while trying to troubleshoot another error: {}", own_error);
|
||||
}
|
||||
|
||||
// Ensure we exit with a code
|
||||
quit::with_code(1);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn troubleshoot(global_args: &ArgMatches<'_>, _local_args: &ArgMatches<'_>, error: &NixError) -> Result<(), NixError> {
|
||||
match error {
|
||||
NixError::NoFlakesSupport => {
|
||||
// People following the tutorial might put hive.nix directly
|
||||
// in their Colmena checkout, and encounter NoFlakesSupport
|
||||
// because Colmena always prefers flake.nix when it exists.
|
||||
|
||||
if global_args.occurrences_of("config") == 0 {
|
||||
let cwd = env::current_dir()?;
|
||||
if cwd.join("flake.nix").is_file() && cwd.join("hive.nix").is_file() {
|
||||
eprintln!("Hint: You have both flake.nix and hive.nix in the current directory, and");
|
||||
eprintln!(" Colmena will always prefer flake.nix if it exists.");
|
||||
eprintln!();
|
||||
eprintln!(" Try passing `-f hive.nix` explicitly if this is what you want.");
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in a new issue