forked from mirrors/jj
cli: extract CommandError and helper functions to new module
The cli_util module is big enough to slow down Emacs, so let's split it up. This change is an easy one.
This commit is contained in:
parent
4b1948c38e
commit
97024e5be4
55 changed files with 557 additions and 488 deletions
|
@ -18,7 +18,8 @@ use std::path::Path;
|
|||
use std::time::SystemTime;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use jj_cli::cli_util::{CliRunner, CommandError, CommandHelper};
|
||||
use jj_cli::cli_util::{CliRunner, CommandHelper};
|
||||
use jj_cli::command_error::CommandError;
|
||||
use jj_cli::ui::Ui;
|
||||
use jj_lib::backend::{
|
||||
Backend, BackendInitError, BackendLoadError, BackendResult, ChangeId, Commit, CommitId,
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
|
||||
use std::io::Write as _;
|
||||
|
||||
use jj_cli::cli_util::{CliRunner, CommandError, CommandHelper};
|
||||
use jj_cli::cli_util::{CliRunner, CommandHelper};
|
||||
use jj_cli::command_error::CommandError;
|
||||
use jj_cli::ui::Ui;
|
||||
|
||||
#[derive(clap::Parser, Clone, Debug)]
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
|
||||
use std::io::Write as _;
|
||||
|
||||
use jj_cli::cli_util::{CliRunner, CommandError};
|
||||
use jj_cli::cli_util::CliRunner;
|
||||
use jj_cli::command_error::CommandError;
|
||||
use jj_cli::ui::Ui;
|
||||
|
||||
#[derive(clap::Args, Clone, Debug)]
|
||||
|
|
|
@ -17,7 +17,8 @@ use std::path::{Path, PathBuf};
|
|||
use std::sync::Arc;
|
||||
|
||||
use itertools::Itertools;
|
||||
use jj_cli::cli_util::{CliRunner, CommandError, CommandHelper};
|
||||
use jj_cli::cli_util::{CliRunner, CommandHelper};
|
||||
use jj_cli::command_error::CommandError;
|
||||
use jj_cli::ui::Ui;
|
||||
use jj_lib::backend::{Backend, MergedTreeId};
|
||||
use jj_lib::commit::Commit;
|
||||
|
|
|
@ -31,9 +31,8 @@ use clap::builder::{NonEmptyStringValueParser, TypedValueParser, ValueParserFact
|
|||
use clap::{Arg, ArgAction, ArgMatches, Command, FromArgMatches};
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use itertools::Itertools;
|
||||
use jj_lib::backend::{BackendError, ChangeId, CommitId, MergedTreeId};
|
||||
use jj_lib::backend::{ChangeId, CommitId, MergedTreeId};
|
||||
use jj_lib::commit::Commit;
|
||||
use jj_lib::git::{GitConfigParseError, GitExportError, GitImportError, GitRemoteManagementError};
|
||||
use jj_lib::git_backend::GitBackend;
|
||||
use jj_lib::gitignore::{GitIgnoreError, GitIgnoreFile};
|
||||
use jj_lib::hex_util::to_reverse_hex;
|
||||
|
@ -41,43 +40,42 @@ use jj_lib::id_prefix::IdPrefixContext;
|
|||
use jj_lib::matchers::{EverythingMatcher, Matcher, PrefixMatcher};
|
||||
use jj_lib::merged_tree::MergedTree;
|
||||
use jj_lib::object_id::ObjectId;
|
||||
use jj_lib::op_heads_store::{self, OpHeadResolutionError};
|
||||
use jj_lib::op_store::{OpStoreError, OperationId, WorkspaceId};
|
||||
use jj_lib::op_walk::OpsetEvaluationError;
|
||||
use jj_lib::operation::Operation;
|
||||
use jj_lib::repo::{
|
||||
CheckOutCommitError, EditCommitError, MutableRepo, ReadonlyRepo, Repo, RepoLoader,
|
||||
RepoLoaderError, RewriteRootCommit, StoreFactories, StoreLoadError,
|
||||
StoreFactories, StoreLoadError,
|
||||
};
|
||||
use jj_lib::repo_path::{FsPathParseError, RepoPath, RepoPathBuf};
|
||||
use jj_lib::revset::{
|
||||
DefaultSymbolResolver, Revset, RevsetAliasesMap, RevsetCommitRef, RevsetEvaluationError,
|
||||
RevsetExpression, RevsetFilterPredicate, RevsetIteratorExt, RevsetParseContext,
|
||||
RevsetParseError, RevsetParseErrorKind, RevsetResolutionError, RevsetWorkspaceContext,
|
||||
DefaultSymbolResolver, Revset, RevsetAliasesMap, RevsetCommitRef, RevsetExpression,
|
||||
RevsetFilterPredicate, RevsetIteratorExt, RevsetParseContext, RevsetParseError,
|
||||
RevsetWorkspaceContext,
|
||||
};
|
||||
use jj_lib::rewrite::restore_tree;
|
||||
use jj_lib::settings::{ConfigResultExt as _, UserSettings};
|
||||
use jj_lib::signing::SignInitError;
|
||||
use jj_lib::str_util::{StringPattern, StringPatternParseError};
|
||||
use jj_lib::transaction::Transaction;
|
||||
use jj_lib::tree::TreeMergeError;
|
||||
use jj_lib::view::View;
|
||||
use jj_lib::working_copy::{
|
||||
CheckoutStats, LockedWorkingCopy, ResetError, SnapshotError, SnapshotOptions, WorkingCopy,
|
||||
WorkingCopyFactory, WorkingCopyStateError,
|
||||
CheckoutStats, LockedWorkingCopy, SnapshotOptions, WorkingCopy, WorkingCopyFactory,
|
||||
};
|
||||
use jj_lib::workspace::{
|
||||
default_working_copy_factories, LockedWorkspace, Workspace, WorkspaceInitError,
|
||||
WorkspaceLoadError, WorkspaceLoader,
|
||||
default_working_copy_factories, LockedWorkspace, Workspace, WorkspaceLoadError, WorkspaceLoader,
|
||||
};
|
||||
use jj_lib::{dag_walk, file_util, git, op_walk, revset};
|
||||
use jj_lib::{dag_walk, file_util, git, op_heads_store, op_walk, revset};
|
||||
use once_cell::unsync::OnceCell;
|
||||
use thiserror::Error;
|
||||
use toml_edit;
|
||||
use tracing::instrument;
|
||||
use tracing_chrome::ChromeLayerBuilder;
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
use crate::command_error::{
|
||||
internal_error, internal_error_with_message, user_error, user_error_with_hint,
|
||||
user_error_with_message, CommandError,
|
||||
};
|
||||
use crate::commit_templater::CommitTemplateLanguageExtension;
|
||||
use crate::config::{
|
||||
new_config_path, AnnotatedValue, CommandNameAndArgs, ConfigSource, LayeredConfigs,
|
||||
|
@ -86,110 +84,12 @@ use crate::formatter::{FormatRecorder, Formatter, PlainTextFormatter};
|
|||
use crate::git_util::{
|
||||
is_colocated_git_workspace, print_failed_git_export, print_git_import_stats,
|
||||
};
|
||||
use crate::merge_tools::{
|
||||
ConflictResolveError, DiffEditError, DiffEditor, DiffGenerateError, MergeEditor,
|
||||
MergeToolConfigError,
|
||||
};
|
||||
use crate::template_parser::{TemplateAliasesMap, TemplateParseError, TemplateParseErrorKind};
|
||||
use crate::merge_tools::{DiffEditor, MergeEditor, MergeToolConfigError};
|
||||
use crate::template_parser::TemplateAliasesMap;
|
||||
use crate::templater::Template;
|
||||
use crate::ui::{ColorChoice, Ui};
|
||||
use crate::{commit_templater, text_util};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CommandError {
|
||||
UserError {
|
||||
err: Arc<dyn std::error::Error + Send + Sync>,
|
||||
hint: Option<String>,
|
||||
},
|
||||
ConfigError(String),
|
||||
/// Invalid command line
|
||||
CliError(String),
|
||||
/// Invalid command line detected by clap
|
||||
ClapCliError(Arc<clap::Error>),
|
||||
BrokenPipe,
|
||||
InternalError(Arc<dyn std::error::Error + Send + Sync>),
|
||||
}
|
||||
|
||||
/// Wraps error with user-visible message.
|
||||
#[derive(Debug, Error)]
|
||||
#[error("{message}")]
|
||||
struct ErrorWithMessage {
|
||||
message: String,
|
||||
source: Box<dyn std::error::Error + Send + Sync>,
|
||||
}
|
||||
|
||||
impl ErrorWithMessage {
|
||||
fn new(
|
||||
message: impl Into<String>,
|
||||
source: impl Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
) -> Self {
|
||||
ErrorWithMessage {
|
||||
message: message.into(),
|
||||
source: source.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
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 {
|
||||
err: Arc::from(err.into()),
|
||||
hint,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn internal_error(err: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> CommandError {
|
||||
CommandError::InternalError(Arc::from(err.into()))
|
||||
}
|
||||
|
||||
pub fn internal_error_with_message(
|
||||
message: impl Into<String>,
|
||||
source: impl Into<Box<dyn std::error::Error + Send + Sync>>,
|
||||
) -> CommandError {
|
||||
CommandError::InternalError(Arc::new(ErrorWithMessage::new(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}?"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_error_sources(ui: &Ui, source: Option<&dyn std::error::Error>) -> io::Result<()> {
|
||||
let Some(err) = source else {
|
||||
return Ok(());
|
||||
|
@ -205,306 +105,6 @@ fn print_error_sources(ui: &Ui, source: Option<&dyn std::error::Error>) -> io::R
|
|||
Ok(())
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for CommandError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
if err.kind() == std::io::ErrorKind::BrokenPipe {
|
||||
CommandError::BrokenPipe
|
||||
} else {
|
||||
user_error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<config::ConfigError> for CommandError {
|
||||
fn from(err: config::ConfigError) -> Self {
|
||||
CommandError::ConfigError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::config::ConfigError> for CommandError {
|
||||
fn from(err: crate::config::ConfigError) -> Self {
|
||||
CommandError::ConfigError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
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<BackendError> for CommandError {
|
||||
fn from(err: BackendError) -> Self {
|
||||
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) => user_error(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 { .. } => 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TreeMergeError> for CommandError {
|
||||
fn from(err: TreeMergeError) -> Self {
|
||||
internal_error_with_message("Merge failed", 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<DiffGenerateError> for CommandError {
|
||||
fn from(err: DiffGenerateError) -> Self {
|
||||
user_error_with_message("Failed to generate diff", err)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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 message = format!("Failed to import refs from underlying Git repo: {err}");
|
||||
let hint = match &err {
|
||||
GitImportError::MissingHeadTarget { .. }
|
||||
| GitImportError::MissingRefAncestor { .. } => Some(
|
||||
"\
|
||||
Is this Git repository a shallow or partial clone (cloned with the --depth or --filter \
|
||||
argument)?
|
||||
jj currently does not support shallow/partial clones. To use jj with this \
|
||||
repository, try
|
||||
unshallowing the repository (https://stackoverflow.com/q/6802145) or 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,
|
||||
};
|
||||
user_error_with_hint_opt(message, hint)
|
||||
}
|
||||
}
|
||||
|
||||
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<RevsetParseError> for CommandError {
|
||||
fn from(err: RevsetParseError) -> Self {
|
||||
let err_chain = iter::successors(Some(&err), |e| e.origin());
|
||||
let message = err_chain.clone().join("\n");
|
||||
// Only for the bottom error, which is usually the root cause
|
||||
let hint = match err_chain.last().unwrap().kind() {
|
||||
RevsetParseErrorKind::NotPrefixOperator {
|
||||
op: _,
|
||||
similar_op,
|
||||
description,
|
||||
}
|
||||
| RevsetParseErrorKind::NotPostfixOperator {
|
||||
op: _,
|
||||
similar_op,
|
||||
description,
|
||||
}
|
||||
| RevsetParseErrorKind::NotInfixOperator {
|
||||
op: _,
|
||||
similar_op,
|
||||
description,
|
||||
} => Some(format!("Did you mean '{similar_op}' for {description}?")),
|
||||
RevsetParseErrorKind::NoSuchFunction {
|
||||
name: _,
|
||||
candidates,
|
||||
} => format_similarity_hint(candidates),
|
||||
_ => None,
|
||||
};
|
||||
user_error_with_hint_opt(format!("Failed to parse revset: {message}"), hint)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RevsetResolutionError> for CommandError {
|
||||
fn from(err: RevsetResolutionError) -> Self {
|
||||
let hint = match &err {
|
||||
RevsetResolutionError::NoSuchRevision {
|
||||
name: _,
|
||||
candidates,
|
||||
} => format_similarity_hint(candidates),
|
||||
RevsetResolutionError::EmptyString
|
||||
| RevsetResolutionError::WorkspaceMissingWorkingCopy { .. }
|
||||
| RevsetResolutionError::AmbiguousCommitIdPrefix(_)
|
||||
| RevsetResolutionError::AmbiguousChangeIdPrefix(_)
|
||||
| RevsetResolutionError::StoreError(_) => None,
|
||||
};
|
||||
user_error_with_hint_opt(err, hint)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TemplateParseError> for CommandError {
|
||||
fn from(err: TemplateParseError) -> Self {
|
||||
let err_chain = iter::successors(Some(&err), |e| e.origin());
|
||||
let message = err_chain.clone().join("\n");
|
||||
// Only for the bottom error, which is usually the root cause
|
||||
let hint = match err_chain.last().unwrap().kind() {
|
||||
TemplateParseErrorKind::NoSuchKeyword { candidates, .. }
|
||||
| TemplateParseErrorKind::NoSuchFunction { candidates, .. }
|
||||
| TemplateParseErrorKind::NoSuchMethod { candidates, .. } => {
|
||||
format_similarity_hint(candidates)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
user_error_with_hint_opt(format!("Failed to parse template: {message}"), hint)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FsPathParseError> for CommandError {
|
||||
fn from(err: FsPathParseError) -> Self {
|
||||
user_error(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<clap::Error> for CommandError {
|
||||
fn from(err: clap::Error) -> Self {
|
||||
CommandError::ClapCliError(Arc::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GitConfigParseError> for CommandError {
|
||||
fn from(err: GitConfigParseError) -> Self {
|
||||
internal_error_with_message("Failed to parse Git config", err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WorkingCopyStateError> for CommandError {
|
||||
fn from(err: WorkingCopyStateError) -> Self {
|
||||
internal_error_with_message("Failed to access working copy state", err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GitIgnoreError> for CommandError {
|
||||
fn from(err: GitIgnoreError) -> Self {
|
||||
user_error_with_message("Failed to process .gitignore.", err)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ChromeTracingFlushGuard {
|
||||
_inner: Option<Rc<tracing_chrome::FlushGuard>>,
|
||||
|
|
434
cli/src/command_error.rs
Normal file
434
cli/src/command_error.rs
Normal file
|
@ -0,0 +1,434 @@
|
|||
// 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::sync::Arc;
|
||||
use std::{error, io, iter, str};
|
||||
|
||||
use itertools::Itertools as _;
|
||||
use jj_lib::backend::BackendError;
|
||||
use jj_lib::git::{GitConfigParseError, GitExportError, GitImportError, 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::repo::{CheckOutCommitError, EditCommitError, RepoLoaderError, RewriteRootCommit};
|
||||
use jj_lib::repo_path::FsPathParseError;
|
||||
use jj_lib::revset::{
|
||||
RevsetEvaluationError, RevsetParseError, RevsetParseErrorKind, RevsetResolutionError,
|
||||
};
|
||||
use jj_lib::signing::SignInitError;
|
||||
use jj_lib::tree::TreeMergeError;
|
||||
use jj_lib::working_copy::{ResetError, SnapshotError, WorkingCopyStateError};
|
||||
use jj_lib::workspace::WorkspaceInitError;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::merge_tools::{
|
||||
ConflictResolveError, DiffEditError, DiffGenerateError, MergeToolConfigError,
|
||||
};
|
||||
use crate::template_parser::{TemplateParseError, TemplateParseErrorKind};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CommandError {
|
||||
UserError {
|
||||
err: Arc<dyn error::Error + Send + Sync>,
|
||||
hint: Option<String>,
|
||||
},
|
||||
ConfigError(String),
|
||||
/// Invalid command line
|
||||
CliError(String),
|
||||
/// Invalid command line detected by clap
|
||||
ClapCliError(Arc<clap::Error>),
|
||||
BrokenPipe,
|
||||
InternalError(Arc<dyn error::Error + Send + Sync>),
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
user_error_with_hint_opt(err, None)
|
||||
}
|
||||
|
||||
pub fn user_error_with_hint(
|
||||
err: impl Into<Box<dyn 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 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 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 error::Error + Send + Sync>>,
|
||||
hint: Option<String>,
|
||||
) -> CommandError {
|
||||
CommandError::UserError {
|
||||
err: Arc::from(err.into()),
|
||||
hint,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn internal_error(err: impl Into<Box<dyn error::Error + Send + Sync>>) -> CommandError {
|
||||
CommandError::InternalError(Arc::from(err.into()))
|
||||
}
|
||||
|
||||
pub fn internal_error_with_message(
|
||||
message: impl Into<String>,
|
||||
source: impl Into<Box<dyn error::Error + Send + Sync>>,
|
||||
) -> CommandError {
|
||||
CommandError::InternalError(Arc::new(ErrorWithMessage::new(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 {
|
||||
if err.kind() == io::ErrorKind::BrokenPipe {
|
||||
CommandError::BrokenPipe
|
||||
} else {
|
||||
user_error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<config::ConfigError> for CommandError {
|
||||
fn from(err: config::ConfigError) -> Self {
|
||||
CommandError::ConfigError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::config::ConfigError> for CommandError {
|
||||
fn from(err: crate::config::ConfigError) -> Self {
|
||||
CommandError::ConfigError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
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<BackendError> for CommandError {
|
||||
fn from(err: BackendError) -> Self {
|
||||
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) => user_error(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 { .. } => 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TreeMergeError> for CommandError {
|
||||
fn from(err: TreeMergeError) -> Self {
|
||||
internal_error_with_message("Merge failed", 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<DiffGenerateError> for CommandError {
|
||||
fn from(err: DiffGenerateError) -> Self {
|
||||
user_error_with_message("Failed to generate diff", err)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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 message = format!("Failed to import refs from underlying Git repo: {err}");
|
||||
let hint = match &err {
|
||||
GitImportError::MissingHeadTarget { .. }
|
||||
| GitImportError::MissingRefAncestor { .. } => Some(
|
||||
"\
|
||||
Is this Git repository a shallow or partial clone (cloned with the --depth or --filter \
|
||||
argument)?
|
||||
jj currently does not support shallow/partial clones. To use jj with this \
|
||||
repository, try
|
||||
unshallowing the repository (https://stackoverflow.com/q/6802145) or 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,
|
||||
};
|
||||
user_error_with_hint_opt(message, hint)
|
||||
}
|
||||
}
|
||||
|
||||
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<RevsetParseError> for CommandError {
|
||||
fn from(err: RevsetParseError) -> Self {
|
||||
let err_chain = iter::successors(Some(&err), |e| e.origin());
|
||||
let message = err_chain.clone().join("\n");
|
||||
// Only for the bottom error, which is usually the root cause
|
||||
let hint = match err_chain.last().unwrap().kind() {
|
||||
RevsetParseErrorKind::NotPrefixOperator {
|
||||
op: _,
|
||||
similar_op,
|
||||
description,
|
||||
}
|
||||
| RevsetParseErrorKind::NotPostfixOperator {
|
||||
op: _,
|
||||
similar_op,
|
||||
description,
|
||||
}
|
||||
| RevsetParseErrorKind::NotInfixOperator {
|
||||
op: _,
|
||||
similar_op,
|
||||
description,
|
||||
} => Some(format!("Did you mean '{similar_op}' for {description}?")),
|
||||
RevsetParseErrorKind::NoSuchFunction {
|
||||
name: _,
|
||||
candidates,
|
||||
} => format_similarity_hint(candidates),
|
||||
_ => None,
|
||||
};
|
||||
user_error_with_hint_opt(format!("Failed to parse revset: {message}"), hint)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RevsetResolutionError> for CommandError {
|
||||
fn from(err: RevsetResolutionError) -> Self {
|
||||
let hint = match &err {
|
||||
RevsetResolutionError::NoSuchRevision {
|
||||
name: _,
|
||||
candidates,
|
||||
} => format_similarity_hint(candidates),
|
||||
RevsetResolutionError::EmptyString
|
||||
| RevsetResolutionError::WorkspaceMissingWorkingCopy { .. }
|
||||
| RevsetResolutionError::AmbiguousCommitIdPrefix(_)
|
||||
| RevsetResolutionError::AmbiguousChangeIdPrefix(_)
|
||||
| RevsetResolutionError::StoreError(_) => None,
|
||||
};
|
||||
user_error_with_hint_opt(err, hint)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TemplateParseError> for CommandError {
|
||||
fn from(err: TemplateParseError) -> Self {
|
||||
let err_chain = iter::successors(Some(&err), |e| e.origin());
|
||||
let message = err_chain.clone().join("\n");
|
||||
// Only for the bottom error, which is usually the root cause
|
||||
let hint = match err_chain.last().unwrap().kind() {
|
||||
TemplateParseErrorKind::NoSuchKeyword { candidates, .. }
|
||||
| TemplateParseErrorKind::NoSuchFunction { candidates, .. }
|
||||
| TemplateParseErrorKind::NoSuchMethod { candidates, .. } => {
|
||||
format_similarity_hint(candidates)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
user_error_with_hint_opt(format!("Failed to parse template: {message}"), hint)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FsPathParseError> for CommandError {
|
||||
fn from(err: FsPathParseError) -> Self {
|
||||
user_error(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<clap::Error> for CommandError {
|
||||
fn from(err: clap::Error) -> Self {
|
||||
CommandError::ClapCliError(Arc::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GitConfigParseError> for CommandError {
|
||||
fn from(err: GitConfigParseError) -> Self {
|
||||
internal_error_with_message("Failed to parse Git config", err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WorkingCopyStateError> for CommandError {
|
||||
fn from(err: WorkingCopyStateError) -> Self {
|
||||
internal_error_with_message("Failed to access working copy state", err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GitIgnoreError> for CommandError {
|
||||
fn from(err: GitIgnoreError) -> Self {
|
||||
user_error_with_message("Failed to process .gitignore.", err)
|
||||
}
|
||||
}
|
|
@ -17,9 +17,8 @@ use std::io::Write;
|
|||
use jj_lib::object_id::ObjectId;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{
|
||||
resolve_multiple_nonempty_revsets, CommandError, CommandHelper, RevisionArg,
|
||||
};
|
||||
use crate::cli_util::{resolve_multiple_nonempty_revsets, CommandHelper, RevisionArg};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Abandon a revision
|
||||
|
|
|
@ -16,7 +16,8 @@ use jj_lib::object_id::ObjectId;
|
|||
use jj_lib::rewrite::back_out_commit;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Apply the reverse of a revision on top of another revision
|
||||
|
|
|
@ -23,7 +23,8 @@ use criterion::{BatchSize, BenchmarkGroup, BenchmarkId, Criterion};
|
|||
use jj_lib::object_id::HexPrefix;
|
||||
use jj_lib::repo::Repo;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper, WorkspaceCommandHelper};
|
||||
use crate::cli_util::{CommandHelper, WorkspaceCommandHelper};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Commands for benchmarking internal operations
|
||||
|
|
|
@ -28,9 +28,9 @@ use jj_lib::str_util::StringPattern;
|
|||
use jj_lib::view::View;
|
||||
|
||||
use crate::cli_util::{
|
||||
parse_string_pattern, user_error, user_error_with_hint, CommandError, CommandHelper,
|
||||
RemoteBranchName, RemoteBranchNamePattern, RevisionArg,
|
||||
parse_string_pattern, CommandHelper, RemoteBranchName, RemoteBranchNamePattern, RevisionArg,
|
||||
};
|
||||
use crate::command_error::{user_error, user_error_with_hint, CommandError};
|
||||
use crate::formatter::Formatter;
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ use jj_lib::repo::Repo;
|
|||
use pollster::FutureExt;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{user_error, CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Print contents of a file in a revision
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
use jj_lib::object_id::ObjectId;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{join_message_paragraphs, CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{join_message_paragraphs, CommandHelper, RevisionArg};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Create a new, empty change and edit it in the working copy
|
||||
|
|
|
@ -18,7 +18,8 @@ use jj_lib::merged_tree::MergedTreeBuilder;
|
|||
use jj_lib::object_id::ObjectId;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{user_error, CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)]
|
||||
|
|
|
@ -17,7 +17,8 @@ use jj_lib::repo::Repo;
|
|||
use jj_lib::rewrite::merge_commit_trees;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{join_message_paragraphs, user_error, CommandError, CommandHelper};
|
||||
use crate::cli_util::{join_message_paragraphs, CommandHelper};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::description_util::{description_template_for_commit, edit_description};
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -19,9 +19,10 @@ use itertools::Itertools;
|
|||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{
|
||||
get_new_config_file_path, run_ui_editor, serialize_config_value, user_error,
|
||||
write_config_value_to_file, CommandError, CommandHelper,
|
||||
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::config::{AnnotatedValue, ConfigSource};
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ use jj_lib::object_id::ObjectId;
|
|||
use jj_lib::working_copy::WorkingCopy;
|
||||
use jj_lib::{op_walk, revset};
|
||||
|
||||
use crate::cli_util::{internal_error, user_error, CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::{internal_error, user_error, CommandError};
|
||||
use crate::template_parser;
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@ use std::io::{self, Read, Write};
|
|||
use jj_lib::object_id::ObjectId;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{join_message_paragraphs, CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{join_message_paragraphs, CommandHelper, RevisionArg};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::description_util::{description_template_for_describe, edit_description};
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
use jj_lib::rewrite::merge_commit_trees;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::diff_util::{diff_formats_for, show_diff, DiffFormatArgs};
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ use jj_lib::object_id::ObjectId;
|
|||
use jj_lib::rewrite::merge_commit_trees;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Touch up the content changes in a revision with a diff editor
|
||||
|
|
|
@ -20,9 +20,9 @@ use jj_lib::repo::Repo;
|
|||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{
|
||||
resolve_multiple_nonempty_revsets, short_commit_hash, user_error, CommandError, CommandHelper,
|
||||
RevisionArg,
|
||||
resolve_multiple_nonempty_revsets, short_commit_hash, CommandHelper, RevisionArg,
|
||||
};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Create a new change with the same content as an existing one
|
||||
|
|
|
@ -17,7 +17,8 @@ use std::io::Write;
|
|||
use jj_lib::object_id::ObjectId;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Edit a commit in the working copy
|
||||
|
|
|
@ -16,7 +16,8 @@ use std::io::Write;
|
|||
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// List files in a revision
|
||||
|
|
|
@ -42,10 +42,13 @@ use maplit::hashset;
|
|||
|
||||
use crate::cli_util::{
|
||||
parse_string_pattern, print_trackable_remote_branches, resolve_multiple_nonempty_revsets,
|
||||
short_change_hash, short_commit_hash, start_repo_transaction, user_error, user_error_with_hint,
|
||||
user_error_with_hint_opt, user_error_with_message, CommandError, CommandHelper, RevisionArg,
|
||||
short_change_hash, short_commit_hash, start_repo_transaction, CommandHelper, RevisionArg,
|
||||
WorkspaceCommandHelper,
|
||||
};
|
||||
use crate::command_error::{
|
||||
user_error, user_error_with_hint, user_error_with_hint_opt, user_error_with_message,
|
||||
CommandError,
|
||||
};
|
||||
use crate::git_util::{
|
||||
get_git_repo, is_colocated_git_workspace, print_failed_git_export, print_git_import_stats,
|
||||
with_remote_git_callbacks,
|
||||
|
|
|
@ -20,7 +20,8 @@ use jj_lib::workspace::Workspace;
|
|||
use tracing::instrument;
|
||||
|
||||
use super::git;
|
||||
use crate::cli_util::{user_error_with_hint, user_error_with_message, CommandError, CommandHelper};
|
||||
use crate::cli_util::CommandHelper;
|
||||
use crate::command_error::{user_error_with_hint, user_error_with_message, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Create a new repo in the given directory
|
||||
|
|
|
@ -16,7 +16,8 @@ use clap::ArgGroup;
|
|||
use jj_lib::rewrite::rebase_to_dest_parent;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::diff_util::{self, DiffFormatArgs};
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ use jj_lib::revset_graph::{
|
|||
};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper, LogContentFormat, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, LogContentFormat, RevisionArg};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::diff_util::{self, DiffFormatArgs};
|
||||
use crate::graphlog::{get_graphlog, Edge};
|
||||
use crate::ui::Ui;
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
use tracing::instrument;
|
||||
|
||||
use super::new;
|
||||
use crate::cli_util::{CommandError, CommandHelper};
|
||||
use crate::cli_util::CommandHelper;
|
||||
use crate::command_error::CommandError;
|
||||
use crate::ui::Ui;
|
||||
|
||||
#[instrument(skip_all)]
|
||||
|
|
|
@ -62,7 +62,8 @@ use std::fmt::Debug;
|
|||
use clap::{CommandFactory, FromArgMatches, Subcommand};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{user_error_with_hint, Args, CommandError, CommandHelper};
|
||||
use crate::cli_util::{Args, CommandHelper};
|
||||
use crate::command_error::{user_error_with_hint, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
#[derive(clap::Parser, Clone, Debug)]
|
||||
|
|
|
@ -18,7 +18,8 @@ use jj_lib::repo::Repo;
|
|||
use jj_lib::rewrite::merge_commit_trees;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{user_error, CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::description_util::combine_messages;
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -22,9 +22,8 @@ use jj_lib::revset::{RevsetExpression, RevsetIteratorExt};
|
|||
use jj_lib::rewrite::{merge_commit_trees, rebase_commit};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{
|
||||
self, short_commit_hash, user_error, CommandError, CommandHelper, RevisionArg,
|
||||
};
|
||||
use crate::cli_util::{self, short_commit_hash, CommandHelper, RevisionArg};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Create a new, empty change and (by default) edit it in the working copy
|
||||
|
|
|
@ -19,9 +19,8 @@ use jj_lib::commit::Commit;
|
|||
use jj_lib::repo::Repo;
|
||||
use jj_lib::revset::{RevsetExpression, RevsetIteratorExt};
|
||||
|
||||
use crate::cli_util::{
|
||||
short_commit_hash, user_error, CommandError, CommandHelper, WorkspaceCommandHelper,
|
||||
};
|
||||
use crate::cli_util::{short_commit_hash, CommandHelper, WorkspaceCommandHelper};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Move the current working copy commit to the next child revision in the
|
||||
|
|
|
@ -18,9 +18,8 @@ use jj_lib::matchers::EverythingMatcher;
|
|||
use jj_lib::rewrite::rebase_to_dest_parent;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{
|
||||
CommandError, CommandHelper, LogContentFormat, RevisionArg, WorkspaceCommandHelper,
|
||||
};
|
||||
use crate::cli_util::{CommandHelper, LogContentFormat, RevisionArg, WorkspaceCommandHelper};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::diff_util::{self, DiffFormat, DiffFormatArgs};
|
||||
use crate::formatter::Formatter;
|
||||
use crate::graphlog::{get_graphlog, Edge};
|
||||
|
|
|
@ -23,10 +23,8 @@ use jj_lib::op_walk;
|
|||
use jj_lib::operation::Operation;
|
||||
use jj_lib::repo::Repo;
|
||||
|
||||
use crate::cli_util::{
|
||||
short_operation_hash, user_error, user_error_with_hint, CommandError, CommandHelper,
|
||||
LogContentFormat,
|
||||
};
|
||||
use crate::cli_util::{short_operation_hash, CommandHelper, LogContentFormat};
|
||||
use crate::command_error::{user_error, user_error_with_hint, CommandError};
|
||||
use crate::graphlog::{get_graphlog, Edge};
|
||||
use crate::operation_templater;
|
||||
use crate::templater::Template as _;
|
||||
|
|
|
@ -16,7 +16,8 @@ use itertools::Itertools;
|
|||
use jj_lib::repo::Repo;
|
||||
use jj_lib::revset::{RevsetExpression, RevsetIteratorExt};
|
||||
|
||||
use crate::cli_util::{short_commit_hash, user_error, CommandError, CommandHelper};
|
||||
use crate::cli_util::{short_commit_hash, CommandHelper};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::commands::next::choose_commit;
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -29,9 +29,10 @@ use jj_lib::settings::UserSettings;
|
|||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{
|
||||
self, resolve_multiple_nonempty_revsets_default_single, short_commit_hash, user_error,
|
||||
CommandError, CommandHelper, RevisionArg, WorkspaceCommandHelper,
|
||||
self, resolve_multiple_nonempty_revsets_default_single, short_commit_hash, CommandHelper,
|
||||
RevisionArg, WorkspaceCommandHelper,
|
||||
};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Move revisions to different parent(s)
|
||||
|
|
|
@ -22,7 +22,8 @@ use jj_lib::object_id::ObjectId;
|
|||
use jj_lib::repo_path::RepoPathBuf;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper, WorkspaceCommandHelper};
|
||||
use crate::cli_util::{CommandHelper, WorkspaceCommandHelper};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::formatter::Formatter;
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@ use jj_lib::object_id::ObjectId;
|
|||
use jj_lib::rewrite::{merge_commit_trees, restore_tree};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{user_error, CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Restore paths from another revision
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper};
|
||||
use crate::cli_util::CommandHelper;
|
||||
use crate::command_error::CommandError;
|
||||
use crate::commands::workspace;
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -14,9 +14,8 @@
|
|||
|
||||
//! This file contains the internal implementation of `run`.
|
||||
|
||||
use crate::cli_util::{
|
||||
resolve_multiple_nonempty_revsets, user_error, CommandError, CommandHelper, RevisionArg,
|
||||
};
|
||||
use crate::cli_util::{resolve_multiple_nonempty_revsets, CommandHelper, RevisionArg};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Run a command across a set of revisions.
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
use jj_lib::matchers::EverythingMatcher;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::diff_util::{self, DiffFormatArgs};
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -24,9 +24,8 @@ use jj_lib::repo_path::RepoPathBuf;
|
|||
use jj_lib::settings::UserSettings;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{
|
||||
edit_temp_file, internal_error_with_message, print_checkout_stats, CommandError, CommandHelper,
|
||||
};
|
||||
use crate::cli_util::{edit_temp_file, print_checkout_stats, CommandHelper};
|
||||
use crate::command_error::{internal_error_with_message, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Manage which paths from the working-copy commit are present in the working
|
||||
|
|
|
@ -18,7 +18,8 @@ use jj_lib::repo::Repo;
|
|||
use jj_lib::rewrite::merge_commit_trees;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::description_util::{description_template_for_commit, edit_description};
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@ use jj_lib::object_id::ObjectId;
|
|||
use jj_lib::revset;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{self, user_error, CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{self, CommandHelper, RevisionArg};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::description_util::combine_messages;
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ use jj_lib::rewrite::merge_commit_trees;
|
|||
use tracing::instrument;
|
||||
|
||||
use super::resolve;
|
||||
use crate::cli_util::{CommandError, CommandHelper};
|
||||
use crate::cli_util::CommandHelper;
|
||||
use crate::command_error::CommandError;
|
||||
use crate::diff_util;
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
|
||||
use jj_lib::str_util::StringPattern;
|
||||
|
||||
use crate::cli_util::{parse_string_pattern, CommandError, CommandHelper};
|
||||
use crate::cli_util::{parse_string_pattern, CommandHelper};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Manage tags.
|
||||
|
|
|
@ -17,7 +17,8 @@ use jj_lib::object_id::ObjectId;
|
|||
use jj_lib::rewrite::merge_commit_trees;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{user_error, CommandError, CommandHelper, RevisionArg};
|
||||
use crate::cli_util::{CommandHelper, RevisionArg};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::description_util::combine_messages;
|
||||
use crate::ui::Ui;
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ use jj_lib::repo::Repo;
|
|||
use jj_lib::working_copy::SnapshotOptions;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{user_error_with_hint, CommandError, CommandHelper};
|
||||
use crate::cli_util::CommandHelper;
|
||||
use crate::command_error::{user_error_with_hint, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Stop tracking specified paths in the working copy
|
||||
|
|
|
@ -20,7 +20,8 @@ use clap::{Command, Subcommand};
|
|||
use jj_lib::repo::Repo;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{user_error, CommandError, CommandHelper};
|
||||
use crate::cli_util::CommandHelper;
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Infrequently used commands such as for generating shell completions
|
||||
|
|
|
@ -16,7 +16,8 @@ use std::io::Write;
|
|||
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{CommandError, CommandHelper};
|
||||
use crate::cli_util::CommandHelper;
|
||||
use crate::command_error::CommandError;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Display version information
|
||||
|
|
|
@ -29,10 +29,10 @@ use jj_lib::workspace::Workspace;
|
|||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::{
|
||||
self, check_stale_working_copy, internal_error_with_message, print_checkout_stats,
|
||||
short_commit_hash, user_error, CommandError, CommandHelper, RevisionArg, WorkingCopyFreshness,
|
||||
WorkspaceCommandHelper,
|
||||
self, check_stale_working_copy, print_checkout_stats, short_commit_hash, CommandHelper,
|
||||
RevisionArg, WorkingCopyFreshness, WorkspaceCommandHelper,
|
||||
};
|
||||
use crate::command_error::{internal_error_with_message, user_error, CommandError};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Commands for working with workspaces
|
||||
|
|
|
@ -5,7 +5,8 @@ use jj_lib::merged_tree::MergedTree;
|
|||
use jj_lib::repo::ReadonlyRepo;
|
||||
use jj_lib::settings::UserSettings;
|
||||
|
||||
use crate::cli_util::{edit_temp_file, CommandError, WorkspaceCommandHelper};
|
||||
use crate::cli_util::{edit_temp_file, WorkspaceCommandHelper};
|
||||
use crate::command_error::CommandError;
|
||||
use crate::diff_util::{self, DiffFormat};
|
||||
use crate::formatter::PlainTextFormatter;
|
||||
use crate::text_util;
|
||||
|
|
|
@ -37,7 +37,8 @@ use pollster::FutureExt;
|
|||
use tracing::instrument;
|
||||
use unicode_width::UnicodeWidthStr as _;
|
||||
|
||||
use crate::cli_util::{CommandError, WorkspaceCommandHelper};
|
||||
use crate::cli_util::WorkspaceCommandHelper;
|
||||
use crate::command_error::CommandError;
|
||||
use crate::config::CommandNameAndArgs;
|
||||
use crate::formatter::Formatter;
|
||||
use crate::merge_tools::{self, ExternalMergeTool};
|
||||
|
|
|
@ -30,7 +30,7 @@ use jj_lib::store::Store;
|
|||
use jj_lib::workspace::Workspace;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::cli_util::{user_error, CommandError};
|
||||
use crate::command_error::{user_error, CommandError};
|
||||
use crate::formatter::Formatter;
|
||||
use crate::progress::Progress;
|
||||
use crate::ui::Ui;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
pub mod cleanup_guard;
|
||||
pub mod cli_util;
|
||||
pub mod command_error;
|
||||
pub mod commands;
|
||||
pub mod commit_templater;
|
||||
pub mod config;
|
||||
|
|
|
@ -21,7 +21,7 @@ use std::{env, fmt, io, mem};
|
|||
use minus::Pager as MinusPager;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::CommandError;
|
||||
use crate::command_error::CommandError;
|
||||
use crate::config::CommandNameAndArgs;
|
||||
use crate::formatter::{Formatter, FormatterFactory, LabeledWriter};
|
||||
|
||||
|
|
Loading…
Reference in a new issue