// 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::io;use std::io::Write as _;use std::iter;use std::process::ExitCode;use std::str;use std::sync::Arc; use itertools::Itertools as _;use jj_lib::backend::BackendError;use jj_lib::dsl_util::Diagnostics;use jj_lib::fileset::FilePatternParseError;use jj_lib::fileset::FilesetParseError;use jj_lib::fileset::FilesetParseErrorKind;use jj_lib::git::GitConfigParseError;use jj_lib::git::GitExportError;use jj_lib::git::GitImportError;use jj_lib::git::GitRemoteManagementError;use jj_lib::gitignore::GitIgnoreError;use jj_lib::op_heads_store::OpHeadResolutionError;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::RevsetEvaluationError;use jj_lib::revset::RevsetParseError;use jj_lib::revset::RevsetParseErrorKind;use jj_lib::revset::RevsetResolutionError;use jj_lib::signing::SignInitError;use jj_lib::str_util::StringPatternParseError;use jj_lib::view::RenameWorkspaceError;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::diff_util::DiffRenderError;use crate::formatter::FormatRecorder;use crate::formatter::Formatter;use crate::merge_tools::ConflictResolveError;use crate::merge_tools::DiffEditError;use crate::merge_tools::MergeToolConfigError;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 { CommandError { 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 { ErrorWithMessage { 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 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!(r#""{}""#, 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, }; CommandError::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<config::ConfigError> for CommandError { fn from(err: config::ConfigError) -> Self { config_error(err) }} impl From<crate::config::ConfigError> for CommandError { fn from(err: crate::config::ConfigError) -> Self { config_error(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<WorkspaceInitError> for CommandError { fn from(err: WorkspaceInitError) -> Self { match err { WorkspaceInitError::DestinationExists(_) => { user_error("The target repo already exists") } WorkspaceInitError::NonUnicodePath => { user_error("The target repo path contains non-unicode characters") } 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::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 @ SignInitError::UnknownBackend(_)) => user_error(err), WorkspaceInitError::SignInit(err) => internal_error(err), } }} 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::OpStore(err) => err.into(), } }} impl From<SnapshotError> for CommandError { fn from(err: SnapshotError) -> Self { match err { SnapshotError::NewFileTooLarge { path, size, max_size, } => { // if the size difference is < 1KiB, then show exact bytes. // otherwise, show in human-readable form; this avoids weird cases // where a file is 400 bytes too large but the error says something // like '1.0MiB, maximum size allowed is ~1.0MiB' let size_diff = size.0 - max_size.0; let err_str = if size_diff <= 1024 { format!( "it is {} bytes too large; the maximum size allowed is {} bytes ({}).", size_diff, max_size.0, max_size, ) } else { format!("it is {size}; the maximum size allowed is ~{max_size}.") }; user_error(format!( "Failed to snapshot the working copy\nThe file '{}' is too large to be \ snapshotted: {}", path.display(), err_str, )) .hinted(format!( "This is to prevent large files from being added on accident. You can fix \ this error by: - Adding the file to `.gitignore` - Run `jj config set --repo snapshot.max-new-file-size {}` This will increase the maximum file size allowed for new files, in this repository only. - Run `jj --config-toml 'snapshot.max-new-file-size={}' st` This will increase the maximum file size allowed for new files, for this command only.", size.0, size.0 )) } err => 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<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 { user_error_with_message("Failed to resolve conflicts", 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), } }} impl From<git2::Error> for CommandError { fn from(err: git2::Error) -> Self { user_error_with_message("Git operation failed", err) }} impl From<GitImportError> for CommandError { fn from(err: GitImportError) -> Self { let hint = match &err { GitImportError::MissingHeadTarget { .. } | GitImportError::MissingRefAncestor { .. } => Some( "\Is this Git repository a partial clone (cloned with the --filter argument)?jj currently does not support partial clones. To use jj with this repository, try re-cloning with \ the full repository contents." .to_string(), ), GitImportError::RemoteReservedForLocalGitRepo => { Some("Run `jj git remote rename` to give different name.".to_string()) } GitImportError::InternalBackend(_) => None, GitImportError::InternalGitError(_) => None, GitImportError::UnexpectedBackend => None, }; let mut cmd_err = user_error_with_message("Failed to import refs from underlying Git repo", err); cmd_err.extend_hints(hint); cmd_err }} impl From<GitExportError> for CommandError { fn from(err: GitExportError) -> Self { internal_error_with_message("Failed to export refs to underlying Git repo", err) }} impl From<GitRemoteManagementError> for CommandError { fn from(err: GitRemoteManagementError) -> Self { user_error(err) }} impl From<RevsetEvaluationError> for CommandError { fn from(err: RevsetEvaluationError) -> Self { user_error(err) }} impl From<FilesetParseError> for CommandError { fn from(err: FilesetParseError) -> Self { let hint = fileset_parse_error_hint(&err); let mut cmd_err = user_error_with_message(format!("Failed to parse fileset: {}", err.kind()), err); cmd_err.extend_hints(hint); cmd_err }} impl From<RevsetParseError> for CommandError {Lines 1–500 of 856. 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::io; use std::io::Write as _; use std::iter; use std::process::ExitCode; use std::str; use std::sync::Arc; use itertools::Itertools as _; use jj_lib::backend::BackendError; use jj_lib::dsl_util::Diagnostics; use jj_lib::fileset::FilePatternParseError; use jj_lib::fileset::FilesetParseError; use jj_lib::fileset::FilesetParseErrorKind; use jj_lib::git::GitConfigParseError; use jj_lib::git::GitExportError; use jj_lib::git::GitImportError; use jj_lib::git::GitRemoteManagementError; use jj_lib::gitignore::GitIgnoreError; use jj_lib::op_heads_store::OpHeadResolutionError; 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::RevsetEvaluationError; use jj_lib::revset::RevsetParseError; use jj_lib::revset::RevsetParseErrorKind; use jj_lib::revset::RevsetResolutionError; use jj_lib::signing::SignInitError; use jj_lib::str_util::StringPatternParseError; use jj_lib::view::RenameWorkspaceError; 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::diff_util::DiffRenderError; use crate::formatter::FormatRecorder; use crate::formatter::Formatter; use crate::merge_tools::ConflictResolveError; use crate::merge_tools::DiffEditError; use crate::merge_tools::MergeToolConfigError; 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 { CommandError { 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 { ErrorWithMessage { 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 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!(r#""{}""#, 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, }; CommandError::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<config::ConfigError> for CommandError { fn from(err: config::ConfigError) -> Self { config_error(err) } } impl From<crate::config::ConfigError> for CommandError { fn from(err: crate::config::ConfigError) -> Self { config_error(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<WorkspaceInitError> for CommandError { fn from(err: WorkspaceInitError) -> Self { match err { WorkspaceInitError::DestinationExists(_) => { user_error("The target repo already exists") } WorkspaceInitError::NonUnicodePath => { user_error("The target repo path contains non-unicode characters") } 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::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 @ SignInitError::UnknownBackend(_)) => user_error(err), WorkspaceInitError::SignInit(err) => internal_error(err), } } } 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::OpStore(err) => err.into(), } } } impl From<SnapshotError> for CommandError { fn from(err: SnapshotError) -> Self { match err { SnapshotError::NewFileTooLarge { path, size, max_size, } => { // if the size difference is < 1KiB, then show exact bytes. // otherwise, show in human-readable form; this avoids weird cases // where a file is 400 bytes too large but the error says something // like '1.0MiB, maximum size allowed is ~1.0MiB' let size_diff = size.0 - max_size.0; let err_str = if size_diff <= 1024 { format!( "it is {} bytes too large; the maximum size allowed is {} bytes ({}).", size_diff, max_size.0, max_size, ) } else { format!("it is {size}; the maximum size allowed is ~{max_size}.") }; user_error(format!( "Failed to snapshot the working copy\nThe file '{}' is too large to be \ snapshotted: {}", path.display(), err_str, )) .hinted(format!( "This is to prevent large files from being added on accident. You can fix \ this error by: - Adding the file to `.gitignore` - Run `jj config set --repo snapshot.max-new-file-size {}` This will increase the maximum file size allowed for new files, in this repository only. - Run `jj --config-toml 'snapshot.max-new-file-size={}' st` This will increase the maximum file size allowed for new files, for this command only.", size.0, size.0 )) } err => 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<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 { user_error_with_message("Failed to resolve conflicts", 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), } } } impl From<git2::Error> for CommandError { fn from(err: git2::Error) -> Self { user_error_with_message("Git operation failed", err) } } impl From<GitImportError> for CommandError { fn from(err: GitImportError) -> Self { let hint = match &err { GitImportError::MissingHeadTarget { .. } | GitImportError::MissingRefAncestor { .. } => Some( "\ Is this Git repository a partial clone (cloned with the --filter argument)? jj currently does not support partial clones. To use jj with this repository, try re-cloning with \ the full repository contents." .to_string(), ), GitImportError::RemoteReservedForLocalGitRepo => { Some("Run `jj git remote rename` to give different name.".to_string()) } GitImportError::InternalBackend(_) => None, GitImportError::InternalGitError(_) => None, GitImportError::UnexpectedBackend => None, }; let mut cmd_err = user_error_with_message("Failed to import refs from underlying Git repo", err); cmd_err.extend_hints(hint); cmd_err } } impl From<GitExportError> for CommandError { fn from(err: GitExportError) -> Self { internal_error_with_message("Failed to export refs to underlying Git repo", err) } } impl From<GitRemoteManagementError> for CommandError { fn from(err: GitRemoteManagementError) -> Self { user_error(err) } } impl From<RevsetEvaluationError> for CommandError { fn from(err: RevsetEvaluationError) -> Self { user_error(err) } } impl From<FilesetParseError> for CommandError { fn from(err: FilesetParseError) -> Self { let hint = fileset_parse_error_hint(&err); let mut cmd_err = user_error_with_message(format!("Failed to parse fileset: {}", err.kind()), err); cmd_err.extend_hints(hint); cmd_err } } impl From<RevsetParseError> for CommandError {