ok/jj
1
0
Fork 0
forked from mirrors/jj

cli: add more CommandError factory functions, consolidate inner type

I'm going to reorganize CommandError as (kind, err, hints) tuple so that we
can add_hint() to the constructed error object.

Some config error messages are slightly adjusted because the inner error is
now printed in separate line.
This commit is contained in:
Yuya Nishihara 2024-03-18 09:44:39 +09:00
parent c311131ee2
commit c333481496
7 changed files with 49 additions and 32 deletions

View file

@ -74,8 +74,9 @@ use tracing_chrome::ChromeLayerBuilder;
use tracing_subscriber::prelude::*;
use crate::command_error::{
handle_command_result, internal_error, internal_error_with_message, user_error,
user_error_with_hint, user_error_with_message, CommandError,
cli_error, config_error_with_message, handle_command_result, internal_error,
internal_error_with_message, user_error, user_error_with_hint, user_error_with_message,
CommandError,
};
use crate::commit_templater::{CommitTemplateLanguage, CommitTemplateLanguageExtension};
use crate::config::{
@ -886,7 +887,10 @@ Set which revision the branch points to with `jj branch set {branch_name} -r <RE
.unwrap_or_else(|_| self.settings.default_revset());
if !revset_string.is_empty() {
let disambiguation_revset = self.parse_revset(&revset_string).map_err(|err| {
CommandError::ConfigError(format!("Invalid `revsets.short-prefixes`: {err}"))
config_error_with_message(
"Invalid `revsets.short-prefixes`",
revset_util::format_parse_error(&err),
)
})?;
context = context.disambiguate_within(revset::optimize(disambiguation_revset));
}
@ -1884,7 +1888,7 @@ pub fn run_ui_editor(settings: &UserSettings, edit_path: &PathBuf) -> Result<(),
let editor: CommandNameAndArgs = settings
.config()
.get("ui.editor")
.map_err(|err| CommandError::ConfigError(format!("ui.editor: {err}")))?;
.map_err(|err| config_error_with_message("Invalid `ui.editor`", err))?;
let exit_status = editor.to_command().arg(edit_path).status().map_err(|err| {
user_error_with_message(
format!(
@ -2309,7 +2313,7 @@ pub fn expand_args(
if let Some(string_arg) = arg_os.to_str() {
string_args.push(string_arg.to_owned());
} else {
return Err(CommandError::CliError("Non-utf8 argument".to_string()));
return Err(cli_error("Non-utf8 argument"));
}
}

View file

@ -48,9 +48,9 @@ pub enum CommandError {
err: Arc<dyn error::Error + Send + Sync>,
hint: Option<String>,
},
ConfigError(String),
ConfigError(Arc<dyn error::Error + Send + Sync>),
/// Invalid command line
CliError(String),
CliError(Arc<dyn error::Error + Send + Sync>),
/// Invalid command line detected by clap
ClapCliError {
err: Arc<clap::Error>,
@ -116,6 +116,21 @@ pub fn user_error_with_hint_opt(
}
}
pub fn config_error(err: impl Into<Box<dyn error::Error + Send + Sync>>) -> CommandError {
CommandError::ConfigError(Arc::from(err.into()))
}
pub fn config_error_with_message(
message: impl Into<String>,
source: impl Into<Box<dyn error::Error + Send + Sync>>,
) -> CommandError {
config_error(ErrorWithMessage::new(message, source))
}
pub fn cli_error(err: impl Into<Box<dyn error::Error + Send + Sync>>) -> CommandError {
CommandError::CliError(Arc::from(err.into()))
}
pub fn internal_error(err: impl Into<Box<dyn error::Error + Send + Sync>>) -> CommandError {
CommandError::InternalError(Arc::from(err.into()))
}
@ -152,13 +167,13 @@ impl From<io::Error> for CommandError {
impl From<config::ConfigError> for CommandError {
fn from(err: config::ConfigError) -> Self {
CommandError::ConfigError(err.to_string())
config_error(err)
}
}
impl From<crate::config::ConfigError> for CommandError {
fn from(err: crate::config::ConfigError) -> Self {
CommandError::ConfigError(err.to_string())
config_error(err)
}
}
@ -475,16 +490,18 @@ fn try_handle_command_result(
}
Ok(ExitCode::from(1))
}
Err(CommandError::ConfigError(message)) => {
writeln!(ui.error(), "Config error: {message}")?;
Err(CommandError::ConfigError(err)) => {
writeln!(ui.error(), "Config error: {err}")?;
print_error_sources(ui, err.source())?;
writeln!(
ui.hint(),
"For help, see https://github.com/martinvonz/jj/blob/main/docs/config.md."
)?;
Ok(ExitCode::from(1))
}
Err(CommandError::CliError(message)) => {
writeln!(ui.error(), "Error: {message}")?;
Err(CommandError::CliError(err)) => {
writeln!(ui.error(), "Error: {err}")?;
print_error_sources(ui, err.source())?;
Ok(ExitCode::from(2))
}
Err(CommandError::ClapCliError { err, hint }) => {

View file

@ -22,7 +22,7 @@ use crate::cli_util::{
get_new_config_file_path, run_ui_editor, serialize_config_value, write_config_value_to_file,
CommandHelper,
};
use crate::command_error::{user_error, CommandError};
use crate::command_error::{config_error, user_error, CommandError};
use crate::config::{AnnotatedValue, ConfigSource};
use crate::generic_templater::GenericTemplateLanguage;
use crate::template_builder::TemplateLanguage as _;
@ -295,7 +295,7 @@ pub(crate) fn cmd_config_get(
if let Some(origin) = origin {
write!(buf, " in {origin}").unwrap();
}
CommandError::ConfigError(buf.to_string())
config_error(buf)
}
err => err.into(),
})?;

View file

@ -16,7 +16,7 @@ use tracing::instrument;
use super::new;
use crate::cli_util::CommandHelper;
use crate::command_error::CommandError;
use crate::command_error::{cli_error, CommandError};
use crate::ui::Ui;
#[instrument(skip_all)]
@ -34,9 +34,7 @@ pub(crate) fn cmd_merge(
"warning: `jj merge` will be removed in a future version, and this will be a hard error"
)?;
if args.revisions.len() < 2 {
return Err(CommandError::CliError(String::from(
"Merge requires at least two revisions",
)));
return Err(cli_error("Merge requires at least two revisions"));
}
new::cmd_new(ui, command, args)
}

View file

@ -23,7 +23,7 @@ use jj_lib::repo_path::RepoPathBuf;
use tracing::instrument;
use crate::cli_util::{CommandHelper, WorkspaceCommandHelper};
use crate::command_error::CommandError;
use crate::command_error::{cli_error, CommandError};
use crate::formatter::Formatter;
use crate::ui::Ui;
@ -81,14 +81,11 @@ pub(crate) fn cmd_resolve(
.filter(|path| matcher.matches(&path.0))
.collect_vec();
if conflicts.is_empty() {
return Err(CommandError::CliError(format!(
"No conflicts found {}",
if args.paths.is_empty() {
"at this revision"
} else {
"at the given path(s)"
}
)));
return Err(cli_error(if args.paths.is_empty() {
"No conflicts found at this revision"
} else {
"No conflicts found at the given path(s)"
}));
}
if args.list {
return print_conflicted_paths(

View file

@ -21,7 +21,7 @@ use std::{env, fmt, io, mem};
use minus::Pager as MinusPager;
use tracing::instrument;
use crate::command_error::CommandError;
use crate::command_error::{config_error_with_message, CommandError};
use crate::config::CommandNameAndArgs;
use crate::formatter::{Formatter, FormatterFactory, LabeledWriter};
@ -233,13 +233,13 @@ pub enum PaginationChoice {
fn pagination_setting(config: &config::Config) -> Result<PaginationChoice, CommandError> {
config
.get::<PaginationChoice>("ui.paginate")
.map_err(|err| CommandError::ConfigError(format!("Invalid `ui.paginate`: {err}")))
.map_err(|err| config_error_with_message("Invalid `ui.paginate`", err))
}
fn pager_setting(config: &config::Config) -> Result<CommandNameAndArgs, CommandError> {
config
.get::<CommandNameAndArgs>("ui.pager")
.map_err(|err| CommandError::ConfigError(format!("Invalid `ui.pager`: {err}")))
.map_err(|err| config_error_with_message("Invalid `ui.pager`", err))
}
impl Ui {

View file

@ -445,7 +445,8 @@ fn test_log_bad_short_prefixes() {
let stderr = test_env.jj_cmd_failure(&repo_path, &["status"]);
insta::assert_snapshot!(stderr,
@r###"
Config error: Invalid `revsets.short-prefixes`: --> 1:1
Config error: Invalid `revsets.short-prefixes`
Caused by: Failed to parse revset: --> 1:1
|
1 | !nval!d
| ^---