// Copyright 2022-2024 The Jujutsu Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License. use std::error;use std::error::Error as _;use std::io;use std::io::Write as _;use std::iter;use std::sync::Arc; use itertools::Itertools as _;use jj_lib::absorb::AbsorbError;use jj_lib::backend::BackendError;use jj_lib::backend::CommitId;use jj_lib::bisect::BisectionError;use jj_lib::config::ConfigFileSaveError;use jj_lib::config::ConfigGetError;use jj_lib::config::ConfigLoadError;use jj_lib::config::ConfigMigrateError;use jj_lib::dsl_util::Diagnostics;use jj_lib::evolution::WalkPredecessorsError;use jj_lib::fileset::FilePatternParseError;use jj_lib::fileset::FilesetParseError;use jj_lib::fileset::FilesetParseErrorKind;use jj_lib::fix::FixError;use jj_lib::gitignore::GitIgnoreError;use jj_lib::index::IndexError;use jj_lib::op_heads_store::OpHeadResolutionError;use jj_lib::op_heads_store::OpHeadsStoreError;use jj_lib::op_store::OpStoreError;use jj_lib::op_walk::OpsetEvaluationError;use jj_lib::op_walk::OpsetResolutionError;use jj_lib::repo::CheckOutCommitError;use jj_lib::repo::EditCommitError;use jj_lib::repo::RepoLoaderError;use jj_lib::repo::RewriteRootCommit;use jj_lib::repo_path::RepoPathBuf;use jj_lib::repo_path::UiPathParseError;use jj_lib::revset;use jj_lib::revset::RevsetEvaluationError;use jj_lib::revset::RevsetParseError;use jj_lib::revset::RevsetParseErrorKind;use jj_lib::revset::RevsetResolutionError;use jj_lib::str_util::StringPatternParseError;use jj_lib::trailer::TrailerParseError;use jj_lib::transaction::TransactionCommitError;use jj_lib::view::RenameWorkspaceError;use jj_lib::working_copy::RecoverWorkspaceError;use jj_lib::working_copy::ResetError;use jj_lib::working_copy::SnapshotError;use jj_lib::working_copy::WorkingCopyStateError;use jj_lib::workspace::WorkspaceInitError;use thiserror::Error; use crate::cli_util::short_operation_hash;use crate::description_util::ParseBulkEditMessageError;use crate::description_util::TempTextEditError;use crate::description_util::TextEditError;use crate::diff_util::DiffRenderError;use crate::formatter::FormatRecorder;use crate::formatter::Formatter;use crate::formatter::FormatterExt as _;use crate::merge_tools::ConflictResolveError;use crate::merge_tools::DiffEditError;use crate::merge_tools::MergeToolConfigError;use crate::merge_tools::MergeToolPartialResolutionError;use crate::revset_util::BookmarkNameParseError;use crate::revset_util::TagNameParseError;use crate::revset_util::UserRevsetEvaluationError;use crate::template_parser::TemplateParseError;use crate::template_parser::TemplateParseErrorKind;use crate::ui::Ui; #[derive(Clone, Copy, Debug, Eq, PartialEq)]pub enum CommandErrorKind { User, Config, /// Invalid command line. The inner error type may be `clap::Error`. Cli, BrokenPipe, Internal,} #[derive(Clone, Debug)]pub struct CommandError { pub kind: CommandErrorKind, pub error: Arc<dyn error::Error + Send + Sync>, pub hints: Vec<ErrorHint>,} impl CommandError { pub fn new( kind: CommandErrorKind, err: impl Into<Box<dyn error::Error + Send + Sync>>, ) -> Self { Self { kind, error: Arc::from(err.into()), hints: vec![], } } pub fn with_message( kind: CommandErrorKind, message: impl Into<String>, source: impl Into<Box<dyn error::Error + Send + Sync>>, ) -> Self { Self::new(kind, ErrorWithMessage::new(message, source)) } /// Returns error with the given plain-text `hint` attached. pub fn hinted(mut self, hint: impl Into<String>) -> Self { self.add_hint(hint); self } /// Appends plain-text `hint` to the error. pub fn add_hint(&mut self, hint: impl Into<String>) { self.hints.push(ErrorHint::PlainText(hint.into())); } /// Appends formatted `hint` to the error. pub fn add_formatted_hint(&mut self, hint: FormatRecorder) { self.hints.push(ErrorHint::Formatted(hint)); } /// Constructs formatted hint and appends it to the error. pub fn add_formatted_hint_with( &mut self, write: impl FnOnce(&mut dyn Formatter) -> io::Result<()>, ) { let mut formatter = FormatRecorder::new(); write(&mut formatter).expect("write() to FormatRecorder should never fail"); self.add_formatted_hint(formatter); } /// Appends 0 or more plain-text `hints` to the error. pub fn extend_hints(&mut self, hints: impl IntoIterator<Item = String>) { self.hints .extend(hints.into_iter().map(ErrorHint::PlainText)); }} #[derive(Clone, Debug)]pub enum ErrorHint { PlainText(String), Formatted(FormatRecorder),} /// Wraps error with user-visible message.#[derive(Debug, Error)]#[error("{message}")]struct ErrorWithMessage { message: String, source: Box<dyn error::Error + Send + Sync>,} impl ErrorWithMessage { fn new( message: impl Into<String>, source: impl Into<Box<dyn error::Error + Send + Sync>>, ) -> Self { Self { message: message.into(), source: source.into(), } }} pub fn user_error(err: impl Into<Box<dyn error::Error + Send + Sync>>) -> CommandError { CommandError::new(CommandErrorKind::User, err)} pub fn user_error_with_hint( err: impl Into<Box<dyn error::Error + Send + Sync>>, hint: impl Into<String>,) -> CommandError { user_error(err).hinted(hint)} pub fn user_error_with_message( message: impl Into<String>, source: impl Into<Box<dyn error::Error + Send + Sync>>,) -> CommandError { CommandError::with_message(CommandErrorKind::User, message, source)} pub fn config_error(err: impl Into<Box<dyn error::Error + Send + Sync>>) -> CommandError { CommandError::new(CommandErrorKind::Config, err)} pub fn config_error_with_message( message: impl Into<String>, source: impl Into<Box<dyn error::Error + Send + Sync>>,) -> CommandError { CommandError::with_message(CommandErrorKind::Config, message, source)} pub fn cli_error(err: impl Into<Box<dyn error::Error + Send + Sync>>) -> CommandError { CommandError::new(CommandErrorKind::Cli, err)} pub fn cli_error_with_message( message: impl Into<String>, source: impl Into<Box<dyn error::Error + Send + Sync>>,) -> CommandError { CommandError::with_message(CommandErrorKind::Cli, message, source)} pub fn internal_error(err: impl Into<Box<dyn error::Error + Send + Sync>>) -> CommandError { CommandError::new(CommandErrorKind::Internal, err)} pub fn internal_error_with_message( message: impl Into<String>, source: impl Into<Box<dyn error::Error + Send + Sync>>,) -> CommandError { CommandError::with_message(CommandErrorKind::Internal, message, source)} fn format_similarity_hint<S: AsRef<str>>(candidates: &[S]) -> Option<String> { match candidates { [] => None, names => { let quoted_names = names.iter().map(|s| format!("`{}`", s.as_ref())).join(", "); Some(format!("Did you mean {quoted_names}?")) } }} impl From<io::Error> for CommandError { fn from(err: io::Error) -> Self { let kind = match err.kind() { io::ErrorKind::BrokenPipe => CommandErrorKind::BrokenPipe, _ => CommandErrorKind::User, }; Self::new(kind, err) }} impl From<jj_lib::file_util::PathError> for CommandError { fn from(err: jj_lib::file_util::PathError) -> Self { user_error(err) }} impl From<ConfigFileSaveError> for CommandError { fn from(err: ConfigFileSaveError) -> Self { user_error(err) }} impl From<ConfigGetError> for CommandError { fn from(err: ConfigGetError) -> Self { let hint = config_get_error_hint(&err); let mut cmd_err = config_error(err); cmd_err.extend_hints(hint); cmd_err }} impl From<ConfigLoadError> for CommandError { fn from(err: ConfigLoadError) -> Self { let hint = match &err { ConfigLoadError::Read(_) => None, ConfigLoadError::Parse { source_path, .. } => source_path .as_ref() .map(|path| format!("Check the config file: {}", path.display())), }; let mut cmd_err = config_error(err); cmd_err.extend_hints(hint); cmd_err }} impl From<ConfigMigrateError> for CommandError { fn from(err: ConfigMigrateError) -> Self { let hint = err .source_path .as_ref() .map(|path| format!("Check the config file: {}", path.display())); let mut cmd_err = config_error(err); cmd_err.extend_hints(hint); cmd_err }} impl From<RewriteRootCommit> for CommandError { fn from(err: RewriteRootCommit) -> Self { internal_error_with_message("Attempted to rewrite the root commit", err) }} impl From<EditCommitError> for CommandError { fn from(err: EditCommitError) -> Self { internal_error_with_message("Failed to edit a commit", err) }} impl From<CheckOutCommitError> for CommandError { fn from(err: CheckOutCommitError) -> Self { internal_error_with_message("Failed to check out a commit", err) }} impl From<RenameWorkspaceError> for CommandError { fn from(err: RenameWorkspaceError) -> Self { user_error_with_message("Failed to rename a workspace", err) }} impl From<BackendError> for CommandError { fn from(err: BackendError) -> Self { match &err { BackendError::Unsupported(_) => user_error(err), _ => internal_error_with_message("Unexpected error from backend", err), } }} impl From<IndexError> for CommandError { fn from(err: IndexError) -> Self { internal_error_with_message("Unexpected error from index", err) }} impl From<OpHeadsStoreError> for CommandError { fn from(err: OpHeadsStoreError) -> Self { internal_error_with_message("Unexpected error from operation heads store", err) }} impl From<WorkspaceInitError> for CommandError { fn from(err: WorkspaceInitError) -> Self { match err { WorkspaceInitError::DestinationExists(_) => { user_error("The target repo already exists") } WorkspaceInitError::EncodeRepoPath(_) => user_error(err), WorkspaceInitError::CheckOutCommit(err) => { internal_error_with_message("Failed to check out the initial commit", err) } WorkspaceInitError::Path(err) => { internal_error_with_message("Failed to access the repository", err) } WorkspaceInitError::OpHeadsStore(err) => { user_error_with_message("Failed to record initial operation", err) } WorkspaceInitError::Backend(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) => user_error(err), WorkspaceInitError::TransactionCommit(err) => err.into(), } }} impl From<OpHeadResolutionError> for CommandError { fn from(err: OpHeadResolutionError) -> Self { match err { OpHeadResolutionError::NoHeads => { internal_error_with_message("Corrupt repository", err) } } }} impl From<OpsetEvaluationError> for CommandError { fn from(err: OpsetEvaluationError) -> Self { match err { OpsetEvaluationError::OpsetResolution(err) => { let hint = opset_resolution_error_hint(&err); let mut cmd_err = user_error(err); cmd_err.extend_hints(hint); cmd_err } OpsetEvaluationError::OpHeadResolution(err) => err.into(), OpsetEvaluationError::OpHeadsStore(err) => err.into(), OpsetEvaluationError::OpStore(err) => err.into(), } }} impl From<SnapshotError> for CommandError { fn from(err: SnapshotError) -> Self { internal_error_with_message("Failed to snapshot the working copy", err) }} impl From<OpStoreError> for CommandError { fn from(err: OpStoreError) -> Self { internal_error_with_message("Failed to load an operation", err) }} impl From<RepoLoaderError> for CommandError { fn from(err: RepoLoaderError) -> Self { internal_error_with_message("Failed to load the repo", err) }} impl From<ResetError> for CommandError { fn from(err: ResetError) -> Self { internal_error_with_message("Failed to reset the working copy", err) }} impl From<TransactionCommitError> for CommandError { fn from(err: TransactionCommitError) -> Self { internal_error(err) }} impl From<WalkPredecessorsError> for CommandError { fn from(err: WalkPredecessorsError) -> Self { match err { WalkPredecessorsError::Backend(err) => err.into(), WalkPredecessorsError::Index(err) => err.into(), WalkPredecessorsError::OpStore(err) => err.into(), WalkPredecessorsError::CycleDetected(_) => internal_error(err), } }} impl From<DiffEditError> for CommandError { fn from(err: DiffEditError) -> Self { user_error_with_message("Failed to edit diff", err) }} impl From<DiffRenderError> for CommandError { fn from(err: DiffRenderError) -> Self { match err { DiffRenderError::DiffGenerate(_) => user_error(err), DiffRenderError::Backend(err) => err.into(), DiffRenderError::AccessDenied { .. } => user_error(err), DiffRenderError::InvalidRepoPath(_) => user_error(err), DiffRenderError::Io(err) => err.into(), } }} impl From<ConflictResolveError> for CommandError { fn from(err: ConflictResolveError) -> Self { match err { ConflictResolveError::Backend(err) => err.into(), ConflictResolveError::Io(err) => err.into(), _ => { let hint = match &err { ConflictResolveError::ConflictTooComplicated { .. } => { Some("Edit the conflict markers manually to resolve this.".to_owned()) } ConflictResolveError::ExecutableConflict { .. } => { Some("Use `jj file chmod` to update the executable bit.".to_owned()) } _ => None, }; let mut cmd_err = user_error_with_message("Failed to resolve conflicts", err); cmd_err.extend_hints(hint); cmd_err } } }} impl From<MergeToolPartialResolutionError> for CommandError { fn from(err: MergeToolPartialResolutionError) -> Self { user_error(err) }} impl From<MergeToolConfigError> for CommandError { fn from(err: MergeToolConfigError) -> Self { match &err { MergeToolConfigError::MergeArgsNotConfigured { tool_name } => { let tool_name = tool_name.clone(); user_error_with_hint( err, format!( "To use `{tool_name}` as a merge tool, the config \ `merge-tools.{tool_name}.merge-args` must be defined (see docs for \ details)" ), ) } _ => user_error_with_message("Failed to load tool configuration", err),Lines 1–500 of 1122. Load more
// Copyright 2022-2024 The Jujutsu Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use std::error; use std::error::Error as _; use std::io; use std::io::Write as _; use std::iter; use std::sync::Arc; use itertools::Itertools as _; use jj_lib::absorb::AbsorbError; use jj_lib::backend::BackendError; use jj_lib::backend::CommitId; use jj_lib::bisect::BisectionError; use jj_lib::config::ConfigFileSaveError; use jj_lib::config::ConfigGetError; use jj_lib::config::ConfigLoadError; use jj_lib::config::ConfigMigrateError; use jj_lib::dsl_util::Diagnostics; use jj_lib::evolution::WalkPredecessorsError; use jj_lib::fileset::FilePatternParseError; use jj_lib::fileset::FilesetParseError; use jj_lib::fileset::FilesetParseErrorKind; use jj_lib::fix::FixError; use jj_lib::gitignore::GitIgnoreError; use jj_lib::index::IndexError; use jj_lib::op_heads_store::OpHeadResolutionError; use jj_lib::op_heads_store::OpHeadsStoreError; use jj_lib::op_store::OpStoreError; use jj_lib::op_walk::OpsetEvaluationError; use jj_lib::op_walk::OpsetResolutionError; use jj_lib::repo::CheckOutCommitError; use jj_lib::repo::EditCommitError; use jj_lib::repo::RepoLoaderError; use jj_lib::repo::RewriteRootCommit; use jj_lib::repo_path::RepoPathBuf; use jj_lib::repo_path::UiPathParseError; use jj_lib::revset; use jj_lib::revset::RevsetEvaluationError; use jj_lib::revset::RevsetParseError; use jj_lib::revset::RevsetParseErrorKind; use jj_lib::revset::RevsetResolutionError; use jj_lib::str_util::StringPatternParseError; use jj_lib::trailer::TrailerParseError; use jj_lib::transaction::TransactionCommitError; use jj_lib::view::RenameWorkspaceError; use jj_lib::working_copy::RecoverWorkspaceError; use jj_lib::working_copy::ResetError; use jj_lib::working_copy::SnapshotError; use jj_lib::working_copy::WorkingCopyStateError; use jj_lib::workspace::WorkspaceInitError; use thiserror::Error; use crate::cli_util::short_operation_hash; use crate::description_util::ParseBulkEditMessageError; use crate::description_util::TempTextEditError; use crate::description_util::TextEditError; use crate::diff_util::DiffRenderError; use crate::formatter::FormatRecorder; use crate::formatter::Formatter; use crate::formatter::FormatterExt as _; use crate::merge_tools::ConflictResolveError; use crate::merge_tools::DiffEditError; use crate::merge_tools::MergeToolConfigError; use crate::merge_tools::MergeToolPartialResolutionError; use crate::revset_util::BookmarkNameParseError; use crate::revset_util::TagNameParseError; use crate::revset_util::UserRevsetEvaluationError; use crate::template_parser::TemplateParseError; use crate::template_parser::TemplateParseErrorKind; use crate::ui::Ui; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum CommandErrorKind { User, Config, /// Invalid command line. The inner error type may be `clap::Error`. Cli, BrokenPipe, Internal, } #[derive(Clone, Debug)] pub struct CommandError { pub kind: CommandErrorKind, pub error: Arc<dyn error::Error + Send + Sync>, pub hints: Vec<ErrorHint>, } impl CommandError { pub fn new( kind: CommandErrorKind, err: impl Into<Box<dyn error::Error + Send + Sync>>, ) -> Self { Self { kind, error: Arc::from(err.into()), hints: vec![], } } pub fn with_message( kind: CommandErrorKind, message: impl Into<String>, source: impl Into<Box<dyn error::Error + Send + Sync>>, ) -> Self { Self::new(kind, ErrorWithMessage::new(message, source)) } /// Returns error with the given plain-text `hint` attached. pub fn hinted(mut self, hint: impl Into<String>) -> Self { self.add_hint(hint); self } /// Appends plain-text `hint` to the error. pub fn add_hint(&mut self, hint: impl Into<String>) { self.hints.push(ErrorHint::PlainText(hint.into())); } /// Appends formatted `hint` to the error. pub fn add_formatted_hint(&mut self, hint: FormatRecorder) { self.hints.push(ErrorHint::Formatted(hint)); } /// Constructs formatted hint and appends it to the error. pub fn add_formatted_hint_with( &mut self, write: impl FnOnce(&mut dyn Formatter) -> io::Result<()>, ) { let mut formatter = FormatRecorder::new(); write(&mut formatter).expect("write() to FormatRecorder should never fail"); self.add_formatted_hint(formatter); } /// Appends 0 or more plain-text `hints` to the error. pub fn extend_hints(&mut self, hints: impl IntoIterator<Item = String>) { self.hints .extend(hints.into_iter().map(ErrorHint::PlainText)); } } #[derive(Clone, Debug)] pub enum ErrorHint { PlainText(String), Formatted(FormatRecorder), } /// Wraps error with user-visible message. #[derive(Debug, Error)] #[error("{message}")] struct ErrorWithMessage { message: String, source: Box<dyn error::Error + Send + Sync>, } impl ErrorWithMessage { fn new( message: impl Into<String>, source: impl Into<Box<dyn error::Error + Send + Sync>>, ) -> Self { Self { message: message.into(), source: source.into(), } } } pub fn user_error(err: impl Into<Box<dyn error::Error + Send + Sync>>) -> CommandError { CommandError::new(CommandErrorKind::User, err) } pub fn user_error_with_hint( err: impl Into<Box<dyn error::Error + Send + Sync>>, hint: impl Into<String>, ) -> CommandError { user_error(err).hinted(hint) } pub fn user_error_with_message( message: impl Into<String>, source: impl Into<Box<dyn error::Error + Send + Sync>>, ) -> CommandError { CommandError::with_message(CommandErrorKind::User, message, source) } pub fn config_error(err: impl Into<Box<dyn error::Error + Send + Sync>>) -> CommandError { CommandError::new(CommandErrorKind::Config, err) } pub fn config_error_with_message( message: impl Into<String>, source: impl Into<Box<dyn error::Error + Send + Sync>>, ) -> CommandError { CommandError::with_message(CommandErrorKind::Config, message, source) } pub fn cli_error(err: impl Into<Box<dyn error::Error + Send + Sync>>) -> CommandError { CommandError::new(CommandErrorKind::Cli, err) } pub fn cli_error_with_message( message: impl Into<String>, source: impl Into<Box<dyn error::Error + Send + Sync>>, ) -> CommandError { CommandError::with_message(CommandErrorKind::Cli, message, source) } pub fn internal_error(err: impl Into<Box<dyn error::Error + Send + Sync>>) -> CommandError { CommandError::new(CommandErrorKind::Internal, err) } pub fn internal_error_with_message( message: impl Into<String>, source: impl Into<Box<dyn error::Error + Send + Sync>>, ) -> CommandError { CommandError::with_message(CommandErrorKind::Internal, message, source) } fn format_similarity_hint<S: AsRef<str>>(candidates: &[S]) -> Option<String> { match candidates { [] => None, names => { let quoted_names = names.iter().map(|s| format!("`{}`", s.as_ref())).join(", "); Some(format!("Did you mean {quoted_names}?")) } } } impl From<io::Error> for CommandError { fn from(err: io::Error) -> Self { let kind = match err.kind() { io::ErrorKind::BrokenPipe => CommandErrorKind::BrokenPipe, _ => CommandErrorKind::User, }; Self::new(kind, err) } } impl From<jj_lib::file_util::PathError> for CommandError { fn from(err: jj_lib::file_util::PathError) -> Self { user_error(err) } } impl From<ConfigFileSaveError> for CommandError { fn from(err: ConfigFileSaveError) -> Self { user_error(err) } } impl From<ConfigGetError> for CommandError { fn from(err: ConfigGetError) -> Self { let hint = config_get_error_hint(&err); let mut cmd_err = config_error(err); cmd_err.extend_hints(hint); cmd_err } } impl From<ConfigLoadError> for CommandError { fn from(err: ConfigLoadError) -> Self { let hint = match &err { ConfigLoadError::Read(_) => None, ConfigLoadError::Parse { source_path, .. } => source_path .as_ref() .map(|path| format!("Check the config file: {}", path.display())), }; let mut cmd_err = config_error(err); cmd_err.extend_hints(hint); cmd_err } } impl From<ConfigMigrateError> for CommandError { fn from(err: ConfigMigrateError) -> Self { let hint = err .source_path .as_ref() .map(|path| format!("Check the config file: {}", path.display())); let mut cmd_err = config_error(err); cmd_err.extend_hints(hint); cmd_err } } impl From<RewriteRootCommit> for CommandError { fn from(err: RewriteRootCommit) -> Self { internal_error_with_message("Attempted to rewrite the root commit", err) } } impl From<EditCommitError> for CommandError { fn from(err: EditCommitError) -> Self { internal_error_with_message("Failed to edit a commit", err) } } impl From<CheckOutCommitError> for CommandError { fn from(err: CheckOutCommitError) -> Self { internal_error_with_message("Failed to check out a commit", err) } } impl From<RenameWorkspaceError> for CommandError { fn from(err: RenameWorkspaceError) -> Self { user_error_with_message("Failed to rename a workspace", err) } } impl From<BackendError> for CommandError { fn from(err: BackendError) -> Self { match &err { BackendError::Unsupported(_) => user_error(err), _ => internal_error_with_message("Unexpected error from backend", err), } } } impl From<IndexError> for CommandError { fn from(err: IndexError) -> Self { internal_error_with_message("Unexpected error from index", err) } } impl From<OpHeadsStoreError> for CommandError { fn from(err: OpHeadsStoreError) -> Self { internal_error_with_message("Unexpected error from operation heads store", err) } } impl From<WorkspaceInitError> for CommandError { fn from(err: WorkspaceInitError) -> Self { match err { WorkspaceInitError::DestinationExists(_) => { user_error("The target repo already exists") } WorkspaceInitError::EncodeRepoPath(_) => user_error(err), WorkspaceInitError::CheckOutCommit(err) => { internal_error_with_message("Failed to check out the initial commit", err) } WorkspaceInitError::Path(err) => { internal_error_with_message("Failed to access the repository", err) } WorkspaceInitError::OpHeadsStore(err) => { user_error_with_message("Failed to record initial operation", err) } WorkspaceInitError::Backend(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) => user_error(err), WorkspaceInitError::TransactionCommit(err) => err.into(), } } } impl From<OpHeadResolutionError> for CommandError { fn from(err: OpHeadResolutionError) -> Self { match err { OpHeadResolutionError::NoHeads => { internal_error_with_message("Corrupt repository", err) } } } } impl From<OpsetEvaluationError> for CommandError { fn from(err: OpsetEvaluationError) -> Self { match err { OpsetEvaluationError::OpsetResolution(err) => { let hint = opset_resolution_error_hint(&err); let mut cmd_err = user_error(err); cmd_err.extend_hints(hint); cmd_err } OpsetEvaluationError::OpHeadResolution(err) => err.into(), OpsetEvaluationError::OpHeadsStore(err) => err.into(), OpsetEvaluationError::OpStore(err) => err.into(), } } } impl From<SnapshotError> for CommandError { fn from(err: SnapshotError) -> Self { internal_error_with_message("Failed to snapshot the working copy", err) } } impl From<OpStoreError> for CommandError { fn from(err: OpStoreError) -> Self { internal_error_with_message("Failed to load an operation", err) } } impl From<RepoLoaderError> for CommandError { fn from(err: RepoLoaderError) -> Self { internal_error_with_message("Failed to load the repo", err) } } impl From<ResetError> for CommandError { fn from(err: ResetError) -> Self { internal_error_with_message("Failed to reset the working copy", err) } } impl From<TransactionCommitError> for CommandError { fn from(err: TransactionCommitError) -> Self { internal_error(err) } } impl From<WalkPredecessorsError> for CommandError { fn from(err: WalkPredecessorsError) -> Self { match err { WalkPredecessorsError::Backend(err) => err.into(), WalkPredecessorsError::Index(err) => err.into(), WalkPredecessorsError::OpStore(err) => err.into(), WalkPredecessorsError::CycleDetected(_) => internal_error(err), } } } impl From<DiffEditError> for CommandError { fn from(err: DiffEditError) -> Self { user_error_with_message("Failed to edit diff", err) } } impl From<DiffRenderError> for CommandError { fn from(err: DiffRenderError) -> Self { match err { DiffRenderError::DiffGenerate(_) => user_error(err), DiffRenderError::Backend(err) => err.into(), DiffRenderError::AccessDenied { .. } => user_error(err), DiffRenderError::InvalidRepoPath(_) => user_error(err), DiffRenderError::Io(err) => err.into(), } } } impl From<ConflictResolveError> for CommandError { fn from(err: ConflictResolveError) -> Self { match err { ConflictResolveError::Backend(err) => err.into(), ConflictResolveError::Io(err) => err.into(), _ => { let hint = match &err { ConflictResolveError::ConflictTooComplicated { .. } => { Some("Edit the conflict markers manually to resolve this.".to_owned()) } ConflictResolveError::ExecutableConflict { .. } => { Some("Use `jj file chmod` to update the executable bit.".to_owned()) } _ => None, }; let mut cmd_err = user_error_with_message("Failed to resolve conflicts", err); cmd_err.extend_hints(hint); cmd_err } } } } impl From<MergeToolPartialResolutionError> for CommandError { fn from(err: MergeToolPartialResolutionError) -> Self { user_error(err) } } impl From<MergeToolConfigError> for CommandError { fn from(err: MergeToolConfigError) -> Self { match &err { MergeToolConfigError::MergeArgsNotConfigured { tool_name } => { let tool_name = tool_name.clone(); user_error_with_hint( err, format!( "To use `{tool_name}` as a merge tool, the config \ `merge-tools.{tool_name}.merge-args` must be defined (see docs for \ details)" ), ) } _ => user_error_with_message("Failed to load tool configuration", err),