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 {
|
macro_rules! handle_command {
|
||||||
($module:ident, $matches:ident) => {
|
($module:ident, $matches:ident) => {
|
||||||
if let Some(sub_matches) = $matches.subcommand_matches(stringify!($module)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($name:expr, $module:ident, $matches:ident) => {
|
($name:expr, $module:ident, $matches:ident) => {
|
||||||
if let Some(sub_matches) = $matches.subcommand_matches($name) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,6 +13,7 @@ use crate::nix::deployment::{
|
||||||
EvaluationNodeLimit,
|
EvaluationNodeLimit,
|
||||||
ParallelismLimit,
|
ParallelismLimit,
|
||||||
};
|
};
|
||||||
|
use crate::nix::NixError;
|
||||||
use crate::nix::host::local as localhost;
|
use crate::nix::host::local as localhost;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
|
@ -114,13 +115,13 @@ pub fn subcommand() -> App<'static, 'static> {
|
||||||
util::register_selector_args(command)
|
util::register_selector_args(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) -> Result<(), NixError> {
|
||||||
let hive = util::hive_from_args(local_args).await.unwrap();
|
let hive = util::hive_from_args(local_args).await?;
|
||||||
|
|
||||||
log::info!("Enumerating nodes...");
|
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") {
|
let selected_nodes = match local_args.value_of("on") {
|
||||||
Some(filter) => {
|
Some(filter) => {
|
||||||
|
@ -241,4 +242,6 @@ pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
||||||
if !success {
|
if !success {
|
||||||
quit::with_code(10);
|
quit::with_code(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::nix::deployment::{
|
||||||
Target,
|
Target,
|
||||||
DeploymentOptions,
|
DeploymentOptions,
|
||||||
};
|
};
|
||||||
use crate::nix::host;
|
use crate::nix::{NixError, host};
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
pub fn subcommand() -> App<'static, 'static> {
|
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))
|
.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?
|
// Sanity check: Are we running NixOS?
|
||||||
if let Ok(os_release) = fs::read_to_string("/etc/os-release").await {
|
if let Ok(os_release) = fs::read_to_string("/etc/os-release").await {
|
||||||
if !os_release.contains("ID=nixos\n") {
|
if !os_release.contains("ID=nixos\n") {
|
||||||
|
@ -131,6 +131,8 @@ pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
||||||
if !success {
|
if !success {
|
||||||
quit::with_code(10);
|
quit::with_code(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn escalate(sudo: &str) -> ! {
|
async fn escalate(sudo: &str) -> ! {
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::path::PathBuf;
|
||||||
use clap::{Arg, App, AppSettings, SubCommand, ArgMatches};
|
use clap::{Arg, App, AppSettings, SubCommand, ArgMatches};
|
||||||
|
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
use crate::nix::NixError;
|
||||||
|
|
||||||
pub fn subcommand() -> App<'static, 'static> {
|
pub fn subcommand() -> App<'static, 'static> {
|
||||||
SubCommand::with_name("eval")
|
SubCommand::with_name("eval")
|
||||||
|
@ -37,12 +38,12 @@ pub fn deprecated_alias() -> App<'static, 'static> {
|
||||||
.setting(AppSettings::Hidden)
|
.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() {
|
if let Some("introspect") = global_args.subcommand_name() {
|
||||||
log::warn!("`colmena introspect` has been renamed to `colmena eval`. Please update your scripts.");
|
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")) {
|
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.");
|
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 instantiate = local_args.is_present("instantiate");
|
||||||
let result = hive.introspect(expression, instantiate).await.unwrap();
|
let result = hive.introspect(expression, instantiate).await?;
|
||||||
|
|
||||||
if instantiate {
|
if instantiate {
|
||||||
print!("{}", result);
|
print!("{}", result);
|
||||||
} else {
|
} else {
|
||||||
println!("{}", result);
|
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)
|
util::register_selector_args(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) -> Result<(), NixError> {
|
||||||
let hive = util::hive_from_args(local_args).await.unwrap();
|
let hive = util::hive_from_args(local_args).await?;
|
||||||
|
|
||||||
log::info!("Enumerating nodes...");
|
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") {
|
let selected_nodes = match local_args.value_of("on") {
|
||||||
Some(filter) => {
|
Some(filter) => {
|
||||||
|
@ -167,4 +167,6 @@ pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) {
|
||||||
|
|
||||||
join_all(futures).await;
|
join_all(futures).await;
|
||||||
}).await;
|
}).await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
use clap::{App, SubCommand, ArgMatches};
|
use clap::{App, SubCommand, ArgMatches};
|
||||||
|
|
||||||
use crate::nix::NixCheck;
|
use crate::nix::{NixCheck, NixError};
|
||||||
|
|
||||||
pub fn subcommand() -> App<'static, 'static> {
|
pub fn subcommand() -> App<'static, 'static> {
|
||||||
SubCommand::with_name("nix-info")
|
SubCommand::with_name("nix-info")
|
||||||
.about("Show information about the current Nix installation")
|
.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;
|
let check = NixCheck::detect().await;
|
||||||
check.print_version_info();
|
check.print_version_info();
|
||||||
check.print_flakes_info(false);
|
check.print_flakes_info(false);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::time::Duration;
|
||||||
use clap::{App, AppSettings, SubCommand, ArgMatches};
|
use clap::{App, AppSettings, SubCommand, ArgMatches};
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
|
|
||||||
|
use crate::nix::NixError;
|
||||||
use crate::progress::{Progress, OutputStyle};
|
use crate::progress::{Progress, OutputStyle};
|
||||||
|
|
||||||
pub fn subcommand() -> App<'static, 'static> {
|
pub fn subcommand() -> App<'static, 'static> {
|
||||||
|
@ -11,7 +12,7 @@ pub fn subcommand() -> App<'static, 'static> {
|
||||||
.setting(AppSettings::Hidden)
|
.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 progress = Progress::with_style(OutputStyle::Condensed);
|
||||||
let mut task = progress.create_task_progress(String::from("test"));
|
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");
|
task.success("Completed");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ mod nix;
|
||||||
mod cli;
|
mod cli;
|
||||||
mod command;
|
mod command;
|
||||||
mod progress;
|
mod progress;
|
||||||
|
mod troubleshooter;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
#[tokio::main]
|
#[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