mirror of
https://github.com/martinvonz/jj.git
synced 2025-02-01 00:50:57 +00:00
cli: make CommandHelper
cheaply cloneable
This wraps all the fields in `CommandHelper` in an `Rc` so `CommandHelper` itself becomes cheap to clone (thanks to @yuja for the idea). I'll use that next to avoid some cloning in `WorkspaceCommandHelper`.
This commit is contained in:
parent
da7b1e9e18
commit
34425a2501
1 changed files with 57 additions and 34 deletions
|
@ -255,7 +255,12 @@ impl TracingSubscription {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct CommandHelper {
|
pub struct CommandHelper {
|
||||||
|
data: Rc<CommandHelperData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CommandHelperData {
|
||||||
app: Command,
|
app: Command,
|
||||||
cwd: PathBuf,
|
cwd: PathBuf,
|
||||||
string_args: Vec<String>,
|
string_args: Vec<String>,
|
||||||
|
@ -273,7 +278,7 @@ pub struct CommandHelper {
|
||||||
|
|
||||||
impl CommandHelper {
|
impl CommandHelper {
|
||||||
pub fn app(&self) -> &Command {
|
pub fn app(&self) -> &Command {
|
||||||
&self.app
|
&self.data.app
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Canonical form of the current working directory path.
|
/// Canonical form of the current working directory path.
|
||||||
|
@ -281,34 +286,34 @@ impl CommandHelper {
|
||||||
/// A loaded `Workspace::workspace_root()` also returns a canonical path, so
|
/// A loaded `Workspace::workspace_root()` also returns a canonical path, so
|
||||||
/// relative paths can be easily computed from these paths.
|
/// relative paths can be easily computed from these paths.
|
||||||
pub fn cwd(&self) -> &Path {
|
pub fn cwd(&self) -> &Path {
|
||||||
&self.cwd
|
&self.data.cwd
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn string_args(&self) -> &Vec<String> {
|
pub fn string_args(&self) -> &Vec<String> {
|
||||||
&self.string_args
|
&self.data.string_args
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches(&self) -> &ArgMatches {
|
pub fn matches(&self) -> &ArgMatches {
|
||||||
&self.matches
|
&self.data.matches
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn global_args(&self) -> &GlobalArgs {
|
pub fn global_args(&self) -> &GlobalArgs {
|
||||||
&self.global_args
|
&self.data.global_args
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn settings(&self) -> &UserSettings {
|
pub fn settings(&self) -> &UserSettings {
|
||||||
&self.settings
|
&self.data.settings
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolved_config_values(
|
pub fn resolved_config_values(
|
||||||
&self,
|
&self,
|
||||||
prefix: &ConfigNamePathBuf,
|
prefix: &ConfigNamePathBuf,
|
||||||
) -> Result<Vec<AnnotatedValue>, crate::config::ConfigError> {
|
) -> Result<Vec<AnnotatedValue>, crate::config::ConfigError> {
|
||||||
self.layered_configs.resolved_config_values(prefix)
|
self.data.layered_configs.resolved_config_values(prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn revset_extensions(&self) -> &Arc<RevsetExtensions> {
|
pub fn revset_extensions(&self) -> &Arc<RevsetExtensions> {
|
||||||
&self.revset_extensions
|
&self.data.revset_extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads template aliases from the configs.
|
/// Loads template aliases from the configs.
|
||||||
|
@ -316,7 +321,7 @@ impl CommandHelper {
|
||||||
/// For most commands that depend on a loaded repo, you should use
|
/// For most commands that depend on a loaded repo, you should use
|
||||||
/// `WorkspaceCommandHelper::template_aliases_map()` instead.
|
/// `WorkspaceCommandHelper::template_aliases_map()` instead.
|
||||||
fn load_template_aliases(&self, ui: &Ui) -> Result<TemplateAliasesMap, CommandError> {
|
fn load_template_aliases(&self, ui: &Ui) -> Result<TemplateAliasesMap, CommandError> {
|
||||||
load_template_aliases(ui, &self.layered_configs)
|
load_template_aliases(ui, &self.data.layered_configs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses template of the given language into evaluation tree.
|
/// Parses template of the given language into evaluation tree.
|
||||||
|
@ -341,11 +346,14 @@ impl CommandHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn operation_template_extensions(&self) -> &[Arc<dyn OperationTemplateLanguageExtension>] {
|
pub fn operation_template_extensions(&self) -> &[Arc<dyn OperationTemplateLanguageExtension>] {
|
||||||
&self.operation_template_extensions
|
&self.data.operation_template_extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn workspace_loader(&self) -> Result<&dyn WorkspaceLoader, CommandError> {
|
pub fn workspace_loader(&self) -> Result<&dyn WorkspaceLoader, CommandError> {
|
||||||
self.maybe_workspace_loader.as_deref().map_err(Clone::clone)
|
self.data
|
||||||
|
.maybe_workspace_loader
|
||||||
|
.as_deref()
|
||||||
|
.map_err(Clone::clone)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads workspace and repo, then snapshots the working copy if allowed.
|
/// Loads workspace and repo, then snapshots the working copy if allowed.
|
||||||
|
@ -374,9 +382,11 @@ impl CommandHelper {
|
||||||
|
|
||||||
// We convert StoreLoadError -> WorkspaceLoadError -> CommandError
|
// We convert StoreLoadError -> WorkspaceLoadError -> CommandError
|
||||||
let factory: Result<_, WorkspaceLoadError> =
|
let factory: Result<_, WorkspaceLoadError> =
|
||||||
get_working_copy_factory(loader, &self.working_copy_factories).map_err(|e| e.into());
|
get_working_copy_factory(loader, &self.data.working_copy_factories)
|
||||||
let factory = factory
|
.map_err(|e| e.into());
|
||||||
.map_err(|err| map_workspace_load_error(err, self.global_args.repository.as_deref()))?;
|
let factory = factory.map_err(|err| {
|
||||||
|
map_workspace_load_error(err, self.data.global_args.repository.as_deref())
|
||||||
|
})?;
|
||||||
Ok(factory)
|
Ok(factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,24 +395,29 @@ impl CommandHelper {
|
||||||
let loader = self.workspace_loader()?;
|
let loader = self.workspace_loader()?;
|
||||||
loader
|
loader
|
||||||
.load(
|
.load(
|
||||||
&self.settings,
|
&self.data.settings,
|
||||||
&self.store_factories,
|
&self.data.store_factories,
|
||||||
&self.working_copy_factories,
|
&self.data.working_copy_factories,
|
||||||
)
|
)
|
||||||
.map_err(|err| map_workspace_load_error(err, self.global_args.repository.as_deref()))
|
.map_err(|err| {
|
||||||
|
map_workspace_load_error(err, self.data.global_args.repository.as_deref())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the working copy to be loaded is writable, and therefore
|
/// Returns true if the working copy to be loaded is writable, and therefore
|
||||||
/// should usually be snapshotted.
|
/// should usually be snapshotted.
|
||||||
pub fn is_working_copy_writable(&self) -> bool {
|
pub fn is_working_copy_writable(&self) -> bool {
|
||||||
self.is_at_head_operation() && !self.global_args.ignore_working_copy
|
self.is_at_head_operation() && !self.data.global_args.ignore_working_copy
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the current operation is considered to be the head.
|
/// Returns true if the current operation is considered to be the head.
|
||||||
pub fn is_at_head_operation(&self) -> bool {
|
pub fn is_at_head_operation(&self) -> bool {
|
||||||
// TODO: should we accept --at-op=<head_id> as the head op? or should we
|
// TODO: should we accept --at-op=<head_id> as the head op? or should we
|
||||||
// make --at-op=@ imply --ignore-workign-copy (i.e. not at the head.)
|
// make --at-op=@ imply --ignore-workign-copy (i.e. not at the head.)
|
||||||
matches!(self.global_args.at_operation.as_deref(), None | Some("@"))
|
matches!(
|
||||||
|
self.data.global_args.at_operation.as_deref(),
|
||||||
|
None | Some("@")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves the current operation from the command-line argument.
|
/// Resolves the current operation from the command-line argument.
|
||||||
|
@ -415,7 +430,7 @@ impl CommandHelper {
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
repo_loader: &RepoLoader,
|
repo_loader: &RepoLoader,
|
||||||
) -> Result<Operation, CommandError> {
|
) -> Result<Operation, CommandError> {
|
||||||
if let Some(op_str) = &self.global_args.at_operation {
|
if let Some(op_str) = &self.data.global_args.at_operation {
|
||||||
Ok(op_walk::resolve_op_for_load(repo_loader, op_str)?)
|
Ok(op_walk::resolve_op_for_load(repo_loader, op_str)?)
|
||||||
} else {
|
} else {
|
||||||
op_heads_store::resolve_op_heads(
|
op_heads_store::resolve_op_heads(
|
||||||
|
@ -428,11 +443,14 @@ impl CommandHelper {
|
||||||
)?;
|
)?;
|
||||||
let base_repo = repo_loader.load_at(&op_heads[0])?;
|
let base_repo = repo_loader.load_at(&op_heads[0])?;
|
||||||
// TODO: It may be helpful to print each operation we're merging here
|
// TODO: It may be helpful to print each operation we're merging here
|
||||||
let mut tx =
|
let mut tx = start_repo_transaction(
|
||||||
start_repo_transaction(&base_repo, &self.settings, &self.string_args);
|
&base_repo,
|
||||||
|
&self.data.settings,
|
||||||
|
&self.data.string_args,
|
||||||
|
);
|
||||||
for other_op_head in op_heads.into_iter().skip(1) {
|
for other_op_head in op_heads.into_iter().skip(1) {
|
||||||
tx.merge_operation(other_op_head)?;
|
tx.merge_operation(other_op_head)?;
|
||||||
let num_rebased = tx.mut_repo().rebase_descendants(&self.settings)?;
|
let num_rebased = tx.mut_repo().rebase_descendants(&self.data.settings)?;
|
||||||
if num_rebased > 0 {
|
if num_rebased > 0 {
|
||||||
writeln!(
|
writeln!(
|
||||||
ui.status(),
|
ui.status(),
|
||||||
|
@ -598,26 +616,28 @@ impl WorkspaceCommandHelper {
|
||||||
repo: Arc<ReadonlyRepo>,
|
repo: Arc<ReadonlyRepo>,
|
||||||
loaded_at_head: bool,
|
loaded_at_head: bool,
|
||||||
) -> Result<Self, CommandError> {
|
) -> Result<Self, CommandError> {
|
||||||
let settings = command.settings.clone();
|
let settings = command.data.settings.clone();
|
||||||
let commit_summary_template_text =
|
let commit_summary_template_text =
|
||||||
settings.config().get_string("templates.commit_summary")?;
|
settings.config().get_string("templates.commit_summary")?;
|
||||||
let revset_aliases_map = revset_util::load_revset_aliases(ui, &command.layered_configs)?;
|
let revset_aliases_map =
|
||||||
|
revset_util::load_revset_aliases(ui, &command.data.layered_configs)?;
|
||||||
let template_aliases_map = command.load_template_aliases(ui)?;
|
let template_aliases_map = command.load_template_aliases(ui)?;
|
||||||
let may_update_working_copy = loaded_at_head && !command.global_args.ignore_working_copy;
|
let may_update_working_copy =
|
||||||
|
loaded_at_head && !command.data.global_args.ignore_working_copy;
|
||||||
let working_copy_shared_with_git = is_colocated_git_workspace(&workspace, &repo);
|
let working_copy_shared_with_git = is_colocated_git_workspace(&workspace, &repo);
|
||||||
let path_converter = RepoPathUiConverter::Fs {
|
let path_converter = RepoPathUiConverter::Fs {
|
||||||
cwd: command.cwd.clone(),
|
cwd: command.data.cwd.clone(),
|
||||||
base: workspace.workspace_root().clone(),
|
base: workspace.workspace_root().clone(),
|
||||||
};
|
};
|
||||||
let helper = Self {
|
let helper = Self {
|
||||||
string_args: command.string_args.clone(),
|
string_args: command.data.string_args.clone(),
|
||||||
global_args: command.global_args.clone(),
|
global_args: command.data.global_args.clone(),
|
||||||
settings,
|
settings,
|
||||||
workspace,
|
workspace,
|
||||||
user_repo: ReadonlyUserRepo::new(repo),
|
user_repo: ReadonlyUserRepo::new(repo),
|
||||||
revset_extensions: command.revset_extensions.clone(),
|
revset_extensions: command.data.revset_extensions.clone(),
|
||||||
commit_summary_template_text,
|
commit_summary_template_text,
|
||||||
commit_template_extensions: command.commit_template_extensions.clone(),
|
commit_template_extensions: command.data.commit_template_extensions.clone(),
|
||||||
revset_aliases_map,
|
revset_aliases_map,
|
||||||
template_aliases_map,
|
template_aliases_map,
|
||||||
may_update_working_copy,
|
may_update_working_copy,
|
||||||
|
@ -1333,7 +1353,7 @@ See https://github.com/martinvonz/jj/blob/main/docs/working-copy.md#stale-workin
|
||||||
"Run `jj workspace update-stale` to recover.
|
"Run `jj workspace update-stale` to recover.
|
||||||
See https://github.com/martinvonz/jj/blob/main/docs/working-copy.md#stale-working-copy \
|
See https://github.com/martinvonz/jj/blob/main/docs/working-copy.md#stale-working-copy \
|
||||||
for more information.",
|
for more information.",
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.into()),
|
||||||
};
|
};
|
||||||
|
@ -3065,7 +3085,7 @@ impl CliRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let settings = UserSettings::from_config(config);
|
let settings = UserSettings::from_config(config);
|
||||||
let command_helper = CommandHelper {
|
let command_helper_data = CommandHelperData {
|
||||||
app: self.app,
|
app: self.app,
|
||||||
cwd,
|
cwd,
|
||||||
string_args,
|
string_args,
|
||||||
|
@ -3080,6 +3100,9 @@ impl CliRunner {
|
||||||
store_factories: self.store_factories,
|
store_factories: self.store_factories,
|
||||||
working_copy_factories: self.working_copy_factories,
|
working_copy_factories: self.working_copy_factories,
|
||||||
};
|
};
|
||||||
|
let command_helper = CommandHelper {
|
||||||
|
data: Rc::new(command_helper_data),
|
||||||
|
};
|
||||||
for start_hook_fn in self.start_hook_fns {
|
for start_hook_fn in self.start_hook_fns {
|
||||||
start_hook_fn(ui, &command_helper)?;
|
start_hook_fn(ui, &command_helper)?;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue