mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-26 22:10:52 +00:00
cli: preserve source of user error, print source chain one by one
"Caused by" lines are inserted before the hint because they are more strongly related to the error.
This commit is contained in:
parent
fb6c834f59
commit
30666dfbcf
8 changed files with 135 additions and 102 deletions
|
@ -91,7 +91,7 @@ use crate::{commit_templater, text_util};
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum CommandError {
|
||||
UserError {
|
||||
message: String,
|
||||
err: Arc<dyn std::error::Error + Send + Sync>,
|
||||
hint: Option<String>,
|
||||
},
|
||||
ConfigError(String),
|
||||
|
@ -123,16 +123,39 @@ impl ErrorWithMessage {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn user_error(message: impl Into<String>) -> CommandError {
|
||||
CommandError::UserError {
|
||||
message: message.into(),
|
||||
hint: None,
|
||||
}
|
||||
pub fn user_error(err: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> CommandError {
|
||||
user_error_with_hint_opt(err, None)
|
||||
}
|
||||
pub fn user_error_with_hint(message: impl Into<String>, hint: impl Into<String>) -> CommandError {
|
||||
|
||||
pub fn user_error_with_hint(
|
||||
err: impl Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
hint: impl Into<String>,
|
||||
) -> CommandError {
|
||||
user_error_with_hint_opt(err, Some(hint.into()))
|
||||
}
|
||||
|
||||
pub fn user_error_with_message(
|
||||
message: impl Into<String>,
|
||||
source: impl Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
) -> CommandError {
|
||||
user_error_with_hint_opt(ErrorWithMessage::new(message, source), None)
|
||||
}
|
||||
|
||||
pub fn user_error_with_message_and_hint(
|
||||
message: impl Into<String>,
|
||||
hint: impl Into<String>,
|
||||
source: impl Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
) -> CommandError {
|
||||
user_error_with_hint_opt(ErrorWithMessage::new(message, source), Some(hint.into()))
|
||||
}
|
||||
|
||||
pub fn user_error_with_hint_opt(
|
||||
err: impl Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
hint: Option<String>,
|
||||
) -> CommandError {
|
||||
CommandError::UserError {
|
||||
message: message.into(),
|
||||
hint: Some(hint.into()),
|
||||
err: Arc::from(err.into()),
|
||||
hint,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,8 +215,7 @@ impl From<std::io::Error> for CommandError {
|
|||
if err.kind() == std::io::ErrorKind::BrokenPipe {
|
||||
CommandError::BrokenPipe
|
||||
} else {
|
||||
// TODO: Record the error as a chained cause
|
||||
user_error(format!("I/O error: {err}"))
|
||||
user_error_with_message("I/O error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -253,14 +275,12 @@ impl From<WorkspaceInitError> for CommandError {
|
|||
user_error(format!("{} doesn't exist", path.display()))
|
||||
}
|
||||
WorkspaceInitError::Backend(err) => {
|
||||
user_error(format!("Failed to access the repository: {err}"))
|
||||
user_error_with_message("Failed to access the repository", err)
|
||||
}
|
||||
WorkspaceInitError::WorkingCopyState(err) => {
|
||||
internal_error_with_message("Failed to access the repository", err)
|
||||
}
|
||||
WorkspaceInitError::SignInit(err @ SignInitError::UnknownBackend(_)) => {
|
||||
user_error(format!("{err}"))
|
||||
}
|
||||
WorkspaceInitError::SignInit(err @ SignInitError::UnknownBackend(_)) => user_error(err),
|
||||
WorkspaceInitError::SignInit(err) => internal_error(err),
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +299,7 @@ impl From<OpHeadResolutionError> for CommandError {
|
|||
impl From<OpsetEvaluationError> for CommandError {
|
||||
fn from(err: OpsetEvaluationError) -> Self {
|
||||
match err {
|
||||
OpsetEvaluationError::OpsetResolution(err) => user_error(err.to_string()),
|
||||
OpsetEvaluationError::OpsetResolution(err) => user_error(err),
|
||||
OpsetEvaluationError::OpHeadResolution(err) => err.into(),
|
||||
OpsetEvaluationError::OpStore(err) => err.into(),
|
||||
}
|
||||
|
@ -289,10 +309,11 @@ impl From<OpsetEvaluationError> for CommandError {
|
|||
impl From<SnapshotError> for CommandError {
|
||||
fn from(err: SnapshotError) -> Self {
|
||||
match err {
|
||||
SnapshotError::NewFileTooLarge { .. } => user_error_with_hint(
|
||||
format!("Failed to snapshot the working copy: {err}"),
|
||||
SnapshotError::NewFileTooLarge { .. } => user_error_with_message_and_hint(
|
||||
"Failed to snapshot the working copy",
|
||||
r#"Increase the value of the `snapshot.max-new-file-size` config option if you
|
||||
want this file to be snapshotted. Otherwise add it to your `.gitignore` file."#,
|
||||
err,
|
||||
),
|
||||
err => internal_error_with_message("Failed to snapshot the working copy", err),
|
||||
}
|
||||
|
@ -325,25 +346,25 @@ impl From<ResetError> for CommandError {
|
|||
|
||||
impl From<DiffEditError> for CommandError {
|
||||
fn from(err: DiffEditError) -> Self {
|
||||
user_error(format!("Failed to edit diff: {err}"))
|
||||
user_error_with_message("Failed to edit diff", err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DiffGenerateError> for CommandError {
|
||||
fn from(err: DiffGenerateError) -> Self {
|
||||
user_error(format!("Failed to generate diff: {err}"))
|
||||
user_error_with_message("Failed to generate diff", err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConflictResolveError> for CommandError {
|
||||
fn from(err: ConflictResolveError) -> Self {
|
||||
user_error(format!("Failed to resolve conflicts: {err}"))
|
||||
user_error_with_message("Failed to resolve conflicts", err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<git2::Error> for CommandError {
|
||||
fn from(err: git2::Error) -> Self {
|
||||
user_error(format!("Git operation failed: {err}"))
|
||||
user_error_with_message("Git operation failed", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,7 +390,7 @@ repository contents."
|
|||
GitImportError::InternalGitError(_) => None,
|
||||
GitImportError::UnexpectedBackend => None,
|
||||
};
|
||||
CommandError::UserError { message, hint }
|
||||
user_error_with_hint_opt(message, hint)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -381,13 +402,13 @@ impl From<GitExportError> for CommandError {
|
|||
|
||||
impl From<GitRemoteManagementError> for CommandError {
|
||||
fn from(err: GitRemoteManagementError) -> Self {
|
||||
user_error(format!("{err}"))
|
||||
user_error(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RevsetEvaluationError> for CommandError {
|
||||
fn from(err: RevsetEvaluationError) -> Self {
|
||||
user_error(format!("{err}"))
|
||||
user_error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,10 +433,7 @@ impl From<RevsetParseError> for CommandError {
|
|||
} => format_similarity_hint(candidates),
|
||||
_ => None,
|
||||
};
|
||||
CommandError::UserError {
|
||||
message: format!("Failed to parse revset: {message}"),
|
||||
hint,
|
||||
}
|
||||
user_error_with_hint_opt(format!("Failed to parse revset: {message}"), hint)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,11 +450,7 @@ impl From<RevsetResolutionError> for CommandError {
|
|||
| RevsetResolutionError::AmbiguousChangeIdPrefix(_)
|
||||
| RevsetResolutionError::StoreError(_) => None,
|
||||
};
|
||||
|
||||
CommandError::UserError {
|
||||
message: format!("{err}"),
|
||||
hint,
|
||||
}
|
||||
user_error_with_hint_opt(err, hint)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -449,7 +463,7 @@ impl From<TemplateParseError> for CommandError {
|
|||
|
||||
impl From<FsPathParseError> for CommandError {
|
||||
fn from(err: FsPathParseError) -> Self {
|
||||
user_error(format!("{err}"))
|
||||
user_error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1175,15 +1189,15 @@ Set which revision the branch points to with `jj branch set {branch_name} -r <RE
|
|||
} else {
|
||||
self.resolve_single_rev(revision_str, ui)
|
||||
.map_err(|err| match err {
|
||||
CommandError::UserError { message, hint } => user_error_with_hint(
|
||||
message,
|
||||
format!(
|
||||
CommandError::UserError { err, hint } => CommandError::UserError {
|
||||
err,
|
||||
hint: Some(format!(
|
||||
"{old_hint}Prefix the expression with 'all' to allow any number of \
|
||||
revisions (i.e. 'all:{}').",
|
||||
revision_str,
|
||||
old_hint = hint.map(|hint| format!("{hint}\n")).unwrap_or_default()
|
||||
),
|
||||
),
|
||||
)),
|
||||
},
|
||||
err => err,
|
||||
})
|
||||
.map(|commit| vec![commit])
|
||||
|
@ -1887,8 +1901,9 @@ jj init --git-repo=.",
|
|||
"The repository directory at {} is missing. Was it moved?",
|
||||
repo_dir.display(),
|
||||
)),
|
||||
// TODO: Record the error as a chained cause
|
||||
WorkspaceLoadError::Path(e) => user_error(format!("{}: {}", e, e.error)),
|
||||
WorkspaceLoadError::NonUnicodePath => user_error(err.to_string()),
|
||||
WorkspaceLoadError::NonUnicodePath => user_error(err),
|
||||
WorkspaceLoadError::StoreLoadError(err @ StoreLoadError::UnsupportedType { .. }) => {
|
||||
internal_error_with_message(
|
||||
"This version of the jj binary doesn't support this type of repo",
|
||||
|
@ -1900,7 +1915,7 @@ jj init --git-repo=.",
|
|||
) => internal_error_with_message("The repository appears broken or inaccessible", err),
|
||||
WorkspaceLoadError::StoreLoadError(StoreLoadError::Signing(
|
||||
err @ SignInitError::UnknownBackend(_),
|
||||
)) => user_error(format!("{err}")),
|
||||
)) => user_error(err),
|
||||
WorkspaceLoadError::StoreLoadError(err) => internal_error(err),
|
||||
}
|
||||
}
|
||||
|
@ -2293,17 +2308,17 @@ pub fn write_config_value_to_file(
|
|||
match err.kind() {
|
||||
// If config doesn't exist yet, read as empty and we'll write one.
|
||||
std::io::ErrorKind::NotFound => Ok("".to_string()),
|
||||
_ => Err(user_error(format!(
|
||||
"Failed to read file {path}: {err}",
|
||||
path = path.display()
|
||||
))),
|
||||
_ => Err(user_error_with_message(
|
||||
format!("Failed to read file {path}", path = path.display()),
|
||||
err,
|
||||
)),
|
||||
}
|
||||
})?;
|
||||
let mut doc = toml_edit::Document::from_str(&config_toml).map_err(|err| {
|
||||
user_error(format!(
|
||||
"Failed to parse file {path}: {err}",
|
||||
path = path.display()
|
||||
))
|
||||
user_error_with_message(
|
||||
format!("Failed to parse file {path}", path = path.display()),
|
||||
err,
|
||||
)
|
||||
})?;
|
||||
|
||||
// Apply config value
|
||||
|
@ -2342,10 +2357,10 @@ pub fn write_config_value_to_file(
|
|||
|
||||
// Write config back
|
||||
std::fs::write(path, doc.to_string()).map_err(|err| {
|
||||
user_error(format!(
|
||||
"Failed to write file {path}: {err}",
|
||||
path = path.display()
|
||||
))
|
||||
user_error_with_message(
|
||||
format!("Failed to write file {path}", path = path.display()),
|
||||
err,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2374,11 +2389,14 @@ pub fn run_ui_editor(settings: &UserSettings, edit_path: &PathBuf) -> Result<(),
|
|||
.get("ui.editor")
|
||||
.map_err(|err| CommandError::ConfigError(format!("ui.editor: {err}")))?;
|
||||
let exit_status = editor.to_command().arg(edit_path).status().map_err(|err| {
|
||||
user_error(format!(
|
||||
// The executable couldn't be found or run; command-line arguments are not relevant
|
||||
"Failed to run editor '{name}': {err}",
|
||||
name = editor.split_name(),
|
||||
))
|
||||
user_error_with_message(
|
||||
format!(
|
||||
// The executable couldn't be found or run; command-line arguments are not relevant
|
||||
"Failed to run editor '{name}'",
|
||||
name = editor.split_name(),
|
||||
),
|
||||
err,
|
||||
)
|
||||
})?;
|
||||
if !exit_status.success() {
|
||||
return Err(user_error(format!(
|
||||
|
@ -2406,23 +2424,23 @@ pub fn edit_temp_file(
|
|||
Ok(path)
|
||||
})()
|
||||
.map_err(|e| {
|
||||
user_error(format!(
|
||||
"Failed to create {} file in \"{}\": {}",
|
||||
error_name,
|
||||
dir.display(),
|
||||
e
|
||||
))
|
||||
user_error_with_message(
|
||||
format!(
|
||||
r#"Failed to create {} file in "{}""#,
|
||||
error_name,
|
||||
dir.display(),
|
||||
),
|
||||
e,
|
||||
)
|
||||
})?;
|
||||
|
||||
run_ui_editor(settings, &path)?;
|
||||
|
||||
let edited = fs::read_to_string(&path).map_err(|e| {
|
||||
user_error(format!(
|
||||
r#"Failed to read {} file "{}": {}"#,
|
||||
error_name,
|
||||
path.display(),
|
||||
e
|
||||
))
|
||||
user_error_with_message(
|
||||
format!(r#"Failed to read {} file "{}""#, error_name, path.display()),
|
||||
e,
|
||||
)
|
||||
})?;
|
||||
|
||||
// Delete the file only if everything went well.
|
||||
|
@ -2822,8 +2840,9 @@ pub fn handle_command_result(
|
|||
) -> std::io::Result<ExitCode> {
|
||||
match &result {
|
||||
Ok(()) => Ok(ExitCode::SUCCESS),
|
||||
Err(CommandError::UserError { message, hint }) => {
|
||||
writeln!(ui.error(), "Error: {message}")?;
|
||||
Err(CommandError::UserError { err, hint }) => {
|
||||
writeln!(ui.error(), "Error: {}", strip_error_source(err))?;
|
||||
print_error_sources(ui, err.source())?;
|
||||
if let Some(hint) = hint {
|
||||
writeln!(ui.hint(), "Hint: {hint}")?;
|
||||
}
|
||||
|
|
|
@ -40,8 +40,8 @@ use maplit::hashset;
|
|||
|
||||
use crate::cli_util::{
|
||||
parse_string_pattern, resolve_multiple_nonempty_revsets, short_change_hash, short_commit_hash,
|
||||
user_error, user_error_with_hint, CommandError, CommandHelper, RevisionArg,
|
||||
WorkspaceCommandHelper,
|
||||
user_error, user_error_with_hint, user_error_with_hint_opt, user_error_with_message,
|
||||
CommandError, CommandHelper, RevisionArg, WorkspaceCommandHelper,
|
||||
};
|
||||
use crate::git_util::{
|
||||
get_git_repo, print_failed_git_export, print_git_import_stats, with_remote_git_callbacks,
|
||||
|
@ -221,7 +221,7 @@ fn map_git_error(err: git2::Error) -> CommandError {
|
|||
/dev/null` to the host work?"
|
||||
};
|
||||
|
||||
user_error_with_hint(err.to_string(), hint)
|
||||
user_error_with_hint(err, hint)
|
||||
} else {
|
||||
user_error(err.to_string())
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ pub fn maybe_add_gitignore(workspace_command: &WorkspaceCommandHelper) -> Result
|
|||
.join(".gitignore"),
|
||||
"/*\n",
|
||||
)
|
||||
.map_err(|e| user_error(format!("Failed to write .jj/.gitignore file: {e}")))
|
||||
.map_err(|e| user_error_with_message("Failed to write .jj/.gitignore file", e))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -346,16 +346,16 @@ fn cmd_git_fetch(
|
|||
.any(|pattern| pattern.as_exact().map_or(false, |s| s.contains('*')))
|
||||
{
|
||||
user_error_with_hint(
|
||||
err.to_string(),
|
||||
err,
|
||||
"Prefix the pattern with `glob:` to expand `*` as a glob",
|
||||
)
|
||||
} else {
|
||||
user_error(err.to_string())
|
||||
user_error(err)
|
||||
}
|
||||
}
|
||||
GitFetchError::GitImportError(err) => err.into(),
|
||||
GitFetchError::InternalGitError(err) => map_git_error(err),
|
||||
_ => user_error(err.to_string()),
|
||||
_ => user_error(err),
|
||||
})?;
|
||||
print_git_import_stats(ui, &stats.import_stats)?;
|
||||
}
|
||||
|
@ -458,7 +458,12 @@ fn cmd_git_clone(
|
|||
let wc_path_existed = match fs::create_dir(&wc_path) {
|
||||
Ok(()) => false,
|
||||
Err(err) if err.kind() == io::ErrorKind::AlreadyExists => true,
|
||||
Err(err) => return Err(user_error(format!("Failed to create {wc_path_str}: {err}"))),
|
||||
Err(err) => {
|
||||
return Err(user_error_with_message(
|
||||
format!("Failed to create {wc_path_str}"),
|
||||
err,
|
||||
));
|
||||
}
|
||||
};
|
||||
if wc_path_existed && !is_empty_dir(&wc_path) {
|
||||
return Err(user_error(
|
||||
|
@ -470,7 +475,7 @@ fn cmd_git_clone(
|
|||
// `/some/path/.`
|
||||
let canonical_wc_path: PathBuf = wc_path
|
||||
.canonicalize()
|
||||
.map_err(|err| user_error(format!("Failed to create {wc_path_str}: {err}")))?;
|
||||
.map_err(|err| user_error_with_message(format!("Failed to create {wc_path_str}"), err))?;
|
||||
let clone_result = do_git_clone(
|
||||
ui,
|
||||
command,
|
||||
|
@ -865,7 +870,7 @@ fn cmd_git_push(
|
|||
"Try fetching from the remote, then make the branch point to where you want it to be, \
|
||||
and push again.",
|
||||
),
|
||||
_ => user_error(err.to_string()),
|
||||
_ => user_error(err),
|
||||
})?;
|
||||
tx.finish(ui, tx_description)?;
|
||||
Ok(())
|
||||
|
@ -908,7 +913,7 @@ impl RejectedBranchUpdateReason {
|
|||
impl From<RejectedBranchUpdateReason> for CommandError {
|
||||
fn from(reason: RejectedBranchUpdateReason) -> Self {
|
||||
let RejectedBranchUpdateReason { message, hint } = reason;
|
||||
CommandError::UserError { message, hint }
|
||||
user_error_with_hint_opt(message, hint)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ use jj_lib::workspace::Workspace;
|
|||
use tracing::instrument;
|
||||
|
||||
use super::git;
|
||||
use crate::cli_util::{user_error, user_error_with_hint, CommandError, CommandHelper};
|
||||
use crate::cli_util::{user_error_with_hint, user_error_with_message, CommandError, CommandHelper};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Create a new repo in the given directory
|
||||
|
@ -55,11 +55,11 @@ pub(crate) fn cmd_init(
|
|||
match fs::create_dir(&wc_path) {
|
||||
Ok(()) => {}
|
||||
Err(_) if wc_path.is_dir() => {}
|
||||
Err(e) => return Err(user_error(format!("Failed to create workspace: {e}"))),
|
||||
Err(e) => return Err(user_error_with_message("Failed to create workspace", e)),
|
||||
}
|
||||
let wc_path = wc_path
|
||||
.canonicalize()
|
||||
.map_err(|e| user_error(format!("Failed to create workspace: {e}")))?; // raced?
|
||||
.map_err(|e| user_error_with_message("Failed to create workspace", e))?; // raced?
|
||||
let cwd = command.cwd().canonicalize().unwrap();
|
||||
let relative_wc_path = file_util::relative_path(&cwd, &wc_path);
|
||||
|
||||
|
|
|
@ -52,7 +52,8 @@ fn test_diffedit() {
|
|||
// Nothing happens if the diff-editor exits with an error
|
||||
std::fs::write(&edit_script, "rm file2\0fail").unwrap();
|
||||
insta::assert_snapshot!(&test_env.jj_cmd_failure(&repo_path, &["diffedit"]), @r###"
|
||||
Error: Failed to edit diff: Tool exited with a non-zero code (run with --verbose to see the exact invocation). Exit code: 1.
|
||||
Error: Failed to edit diff
|
||||
Caused by: Tool exited with a non-zero code (run with --verbose to see the exact invocation). Exit code: 1.
|
||||
"###);
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
|
@ -395,7 +396,8 @@ fn test_diffedit_old_restore_interactive_tests() {
|
|||
// Nothing happens if the diff-editor exits with an error
|
||||
std::fs::write(&edit_script, "rm file2\0fail").unwrap();
|
||||
insta::assert_snapshot!(&test_env.jj_cmd_failure(&repo_path, &["diffedit", "--from", "@-"]), @r###"
|
||||
Error: Failed to edit diff: Tool exited with a non-zero code (run with --verbose to see the exact invocation). Exit code: 1.
|
||||
Error: Failed to edit diff
|
||||
Caused by: Tool exited with a non-zero code (run with --verbose to see the exact invocation). Exit code: 1.
|
||||
"###);
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
|
|
|
@ -163,11 +163,13 @@ fn test_init_git_external_non_existent_git_directory() {
|
|||
let stderr =
|
||||
test_env.jj_cmd_failure(test_env.env_root(), &["init", "repo", "--git-repo", "repo"]);
|
||||
|
||||
insta::with_settings!({filters => vec![
|
||||
(r"(Failed to open git repository:)(?s).*", "Failed to open git repository:"),
|
||||
]}, {
|
||||
insta::assert_snapshot!(&stderr, @"Error: Failed to access the repository: Failed to open git repository:");
|
||||
});
|
||||
insta::assert_snapshot!(&stderr, @r###"
|
||||
Error: Failed to access the repository
|
||||
Caused by:
|
||||
1: Failed to open git repository
|
||||
2: "$TEST_ENV/repo" does not appear to be a git repository
|
||||
3: Missing HEAD at '.git/HEAD'
|
||||
"###);
|
||||
let jj_path = workspace_root.join(".jj");
|
||||
assert!(!jj_path.exists());
|
||||
}
|
||||
|
|
|
@ -149,7 +149,8 @@ fn test_next_fails_on_branching_children_no_stdin() {
|
|||
let assert = test_env.jj_cmd(&repo_path, &["next"]).assert().code(1);
|
||||
let stderr = test_env.normalize_output(&get_stderr_string(&assert));
|
||||
insta::assert_snapshot!(stderr,@r###"
|
||||
Error: I/O error: Cannot prompt for input since the output is not connected to a terminal
|
||||
Error: I/O error
|
||||
Caused by: Cannot prompt for input since the output is not connected to a terminal
|
||||
"###);
|
||||
}
|
||||
|
||||
|
|
|
@ -300,9 +300,9 @@ fn check_resolve_produces_input_file(
|
|||
// in the future. See also https://github.com/mitsuhiko/insta/issues/313.
|
||||
assert_eq!(
|
||||
&test_env.jj_cmd_failure(repo_path, &["resolve", "--config-toml", &merge_arg_config]),
|
||||
"Resolving conflicts in: file\nError: Failed to resolve conflicts: The output file is \
|
||||
either unchanged or empty after the editor quit (run with --verbose to see the exact \
|
||||
invocation).\n"
|
||||
"Resolving conflicts in: file\nError: Failed to resolve conflicts\nCaused by: The output \
|
||||
file is either unchanged or empty after the editor quit (run with --verbose to see the \
|
||||
exact invocation).\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -411,7 +411,8 @@ fn test_too_many_parents() {
|
|||
let error = test_env.jj_cmd_failure(&repo_path, &["resolve"]);
|
||||
insta::assert_snapshot!(error, @r###"
|
||||
Resolving conflicts in: file
|
||||
Error: Failed to resolve conflicts: The conflict at "file" has 3 sides. At most 2 sides are supported.
|
||||
Error: Failed to resolve conflicts
|
||||
Caused by: The conflict at "file" has 3 sides. At most 2 sides are supported.
|
||||
"###);
|
||||
}
|
||||
|
||||
|
@ -487,7 +488,8 @@ fn test_file_vs_dir() {
|
|||
let error = test_env.jj_cmd_failure(&repo_path, &["resolve"]);
|
||||
insta::assert_snapshot!(error, @r###"
|
||||
Resolving conflicts in: file
|
||||
Error: Failed to resolve conflicts: Only conflicts that involve normal files (not symlinks, not executable, etc.) are supported. Conflict summary for "file":
|
||||
Error: Failed to resolve conflicts
|
||||
Caused by: Only conflicts that involve normal files (not symlinks, not executable, etc.) are supported. Conflict summary for "file":
|
||||
Conflict:
|
||||
Removing file with id df967b96a579e45a18b8251732d16804b2e56a55
|
||||
Adding file with id 78981922613b2afb6025042ff6bd878ac1994e85
|
||||
|
@ -542,7 +544,8 @@ fn test_description_with_dir_and_deletion() {
|
|||
let error = test_env.jj_cmd_failure(&repo_path, &["resolve"]);
|
||||
insta::assert_snapshot!(error, @r###"
|
||||
Resolving conflicts in: file
|
||||
Error: Failed to resolve conflicts: Only conflicts that involve normal files (not symlinks, not executable, etc.) are supported. Conflict summary for "file":
|
||||
Error: Failed to resolve conflicts
|
||||
Caused by: Only conflicts that involve normal files (not symlinks, not executable, etc.) are supported. Conflict summary for "file":
|
||||
Conflict:
|
||||
Removing file with id df967b96a579e45a18b8251732d16804b2e56a55
|
||||
Removing file with id df967b96a579e45a18b8251732d16804b2e56a55
|
||||
|
|
|
@ -26,7 +26,8 @@ fn test_snapshot_large_file() {
|
|||
std::fs::write(repo_path.join("large"), "a lot of text").unwrap();
|
||||
let stderr = test_env.jj_cmd_failure(&repo_path, &["files"]);
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Error: Failed to snapshot the working copy: New file $TEST_ENV/repo/large of size ~13.0B exceeds snapshot.max-new-file-size (10.0B)
|
||||
Error: Failed to snapshot the working copy
|
||||
Caused by: New file $TEST_ENV/repo/large of size ~13.0B exceeds snapshot.max-new-file-size (10.0B)
|
||||
Hint: Increase the value of the `snapshot.max-new-file-size` config option if you
|
||||
want this file to be snapshotted. Otherwise add it to your `.gitignore` file.
|
||||
"###);
|
||||
|
|
Loading…
Reference in a new issue