mirror of
https://github.com/jj-vcs/jj.git
synced 2025-12-23 06:01:01 +00:00
working_copy: move freshness calculation into lib for sharing
This is to facilitate automatic update-stale in extensions and in the CommandHelper layer.
This commit is contained in:
parent
c656fd30af
commit
afe25464fe
3 changed files with 63 additions and 55 deletions
|
|
@ -54,7 +54,6 @@ use jj_lib::backend::CommitId;
|
|||
use jj_lib::backend::MergedTreeId;
|
||||
use jj_lib::backend::TreeValue;
|
||||
use jj_lib::commit::Commit;
|
||||
use jj_lib::dag_walk;
|
||||
use jj_lib::file_util;
|
||||
use jj_lib::fileset;
|
||||
use jj_lib::fileset::FilesetDiagnostics;
|
||||
|
|
@ -111,10 +110,10 @@ use jj_lib::str_util::StringPattern;
|
|||
use jj_lib::transaction::Transaction;
|
||||
use jj_lib::view::View;
|
||||
use jj_lib::working_copy::CheckoutStats;
|
||||
use jj_lib::working_copy::LockedWorkingCopy;
|
||||
use jj_lib::working_copy::SnapshotOptions;
|
||||
use jj_lib::working_copy::WorkingCopy;
|
||||
use jj_lib::working_copy::WorkingCopyFactory;
|
||||
use jj_lib::working_copy::WorkingCopyFreshness;
|
||||
use jj_lib::workspace::default_working_copy_factories;
|
||||
use jj_lib::workspace::get_working_copy_factory;
|
||||
use jj_lib::workspace::DefaultWorkspaceLoaderFactory;
|
||||
|
|
@ -1558,7 +1557,7 @@ impl WorkspaceCommandHelper {
|
|||
let mut locked_ws = self.workspace.start_working_copy_mutation()?;
|
||||
let old_op_id = locked_ws.locked_wc().old_operation_id().clone();
|
||||
let (repo, wc_commit) =
|
||||
match check_stale_working_copy(locked_ws.locked_wc(), &wc_commit, &repo) {
|
||||
match WorkingCopyFreshness::check_stale(locked_ws.locked_wc(), &wc_commit, &repo) {
|
||||
Ok(WorkingCopyFreshness::Fresh) => (repo, wc_commit),
|
||||
Ok(WorkingCopyFreshness::Updated(wc_operation)) => {
|
||||
let repo = repo.reload_at(&wc_operation)?;
|
||||
|
|
@ -2214,55 +2213,6 @@ pub fn start_repo_transaction(
|
|||
tx
|
||||
}
|
||||
|
||||
/// Whether the working copy is stale or not.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum WorkingCopyFreshness {
|
||||
/// The working copy isn't stale, and no need to reload the repo.
|
||||
Fresh,
|
||||
/// The working copy was updated since we loaded the repo. The repo must be
|
||||
/// reloaded at the working copy's operation.
|
||||
Updated(Box<Operation>),
|
||||
/// The working copy is behind the latest operation.
|
||||
WorkingCopyStale,
|
||||
/// The working copy is a sibling of the latest operation.
|
||||
SiblingOperation,
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub fn check_stale_working_copy(
|
||||
locked_wc: &dyn LockedWorkingCopy,
|
||||
wc_commit: &Commit,
|
||||
repo: &ReadonlyRepo,
|
||||
) -> Result<WorkingCopyFreshness, OpStoreError> {
|
||||
// Check if the working copy's tree matches the repo's view
|
||||
let wc_tree_id = locked_wc.old_tree_id();
|
||||
if wc_commit.tree_id() == wc_tree_id {
|
||||
// The working copy isn't stale, and no need to reload the repo.
|
||||
Ok(WorkingCopyFreshness::Fresh)
|
||||
} else {
|
||||
let wc_operation = repo.loader().load_operation(locked_wc.old_operation_id())?;
|
||||
let repo_operation = repo.operation();
|
||||
let ancestor_op = dag_walk::closest_common_node_ok(
|
||||
[Ok(wc_operation.clone())],
|
||||
[Ok(repo_operation.clone())],
|
||||
|op: &Operation| op.id().clone(),
|
||||
|op: &Operation| op.parents().collect_vec(),
|
||||
)?
|
||||
.expect("unrelated operations");
|
||||
if ancestor_op.id() == repo_operation.id() {
|
||||
// The working copy was updated since we loaded the repo. The repo must be
|
||||
// reloaded at the working copy's operation.
|
||||
Ok(WorkingCopyFreshness::Updated(Box::new(wc_operation)))
|
||||
} else if ancestor_op.id() == wc_operation.id() {
|
||||
// The working copy was not updated when some repo operation committed,
|
||||
// meaning that it's stale compared to the repo view.
|
||||
Ok(WorkingCopyFreshness::WorkingCopyStale)
|
||||
} else {
|
||||
Ok(WorkingCopyFreshness::SiblingOperation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub fn print_conflicted_paths(
|
||||
conflicts: &[(RepoPathBuf, MergedTreeValue)],
|
||||
|
|
|
|||
|
|
@ -18,13 +18,12 @@ use jj_lib::object_id::ObjectId;
|
|||
use jj_lib::op_store::OpStoreError;
|
||||
use jj_lib::repo::ReadonlyRepo;
|
||||
use jj_lib::repo::Repo;
|
||||
use jj_lib::working_copy::WorkingCopyFreshness;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::cli_util::check_stale_working_copy;
|
||||
use crate::cli_util::print_checkout_stats;
|
||||
use crate::cli_util::short_commit_hash;
|
||||
use crate::cli_util::CommandHelper;
|
||||
use crate::cli_util::WorkingCopyFreshness;
|
||||
use crate::cli_util::WorkspaceCommandHelper;
|
||||
use crate::command_error::internal_error_with_message;
|
||||
use crate::command_error::user_error;
|
||||
|
|
@ -67,7 +66,7 @@ pub fn cmd_workspace_update_stale(
|
|||
let repo = workspace_command.repo().clone();
|
||||
let (mut locked_ws, desired_wc_commit) =
|
||||
workspace_command.unchecked_start_working_copy_mutation()?;
|
||||
match check_stale_working_copy(locked_ws.locked_wc(), &desired_wc_commit, &repo)? {
|
||||
match WorkingCopyFreshness::check_stale(locked_ws.locked_wc(), &desired_wc_commit, &repo)? {
|
||||
WorkingCopyFreshness::Fresh | WorkingCopyFreshness::Updated(_) => {
|
||||
writeln!(
|
||||
ui.status(),
|
||||
|
|
|
|||
|
|
@ -20,18 +20,24 @@ use std::ffi::OsString;
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use itertools::Itertools;
|
||||
use thiserror::Error;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::backend::BackendError;
|
||||
use crate::backend::MergedTreeId;
|
||||
use crate::commit::Commit;
|
||||
use crate::dag_walk;
|
||||
use crate::fsmonitor::FsmonitorSettings;
|
||||
use crate::gitignore::GitIgnoreError;
|
||||
use crate::gitignore::GitIgnoreFile;
|
||||
use crate::matchers::EverythingMatcher;
|
||||
use crate::matchers::Matcher;
|
||||
use crate::op_store::OpStoreError;
|
||||
use crate::op_store::OperationId;
|
||||
use crate::op_store::WorkspaceId;
|
||||
use crate::operation::Operation;
|
||||
use crate::repo::ReadonlyRepo;
|
||||
use crate::repo_path::InvalidRepoPathError;
|
||||
use crate::repo_path::RepoPath;
|
||||
use crate::repo_path::RepoPathBuf;
|
||||
|
|
@ -310,6 +316,59 @@ pub enum ResetError {
|
|||
},
|
||||
}
|
||||
|
||||
/// Whether the working copy is stale or not.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum WorkingCopyFreshness {
|
||||
/// The working copy isn't stale, and no need to reload the repo.
|
||||
Fresh,
|
||||
/// The working copy was updated since we loaded the repo. The repo must be
|
||||
/// reloaded at the working copy's operation.
|
||||
Updated(Box<Operation>),
|
||||
/// The working copy is behind the latest operation.
|
||||
WorkingCopyStale,
|
||||
/// The working copy is a sibling of the latest operation.
|
||||
SiblingOperation,
|
||||
}
|
||||
|
||||
impl WorkingCopyFreshness {
|
||||
/// Determine the freshness of the provided working copy relative to the
|
||||
/// target commit.
|
||||
#[instrument(skip_all)]
|
||||
pub fn check_stale(
|
||||
locked_wc: &dyn LockedWorkingCopy,
|
||||
wc_commit: &Commit,
|
||||
repo: &ReadonlyRepo,
|
||||
) -> Result<Self, OpStoreError> {
|
||||
// Check if the working copy's tree matches the repo's view
|
||||
let wc_tree_id = locked_wc.old_tree_id();
|
||||
if wc_commit.tree_id() == wc_tree_id {
|
||||
// The working copy isn't stale, and no need to reload the repo.
|
||||
Ok(Self::Fresh)
|
||||
} else {
|
||||
let wc_operation = repo.loader().load_operation(locked_wc.old_operation_id())?;
|
||||
let repo_operation = repo.operation();
|
||||
let ancestor_op = dag_walk::closest_common_node_ok(
|
||||
[Ok(wc_operation.clone())],
|
||||
[Ok(repo_operation.clone())],
|
||||
|op: &Operation| op.id().clone(),
|
||||
|op: &Operation| op.parents().collect_vec(),
|
||||
)?
|
||||
.expect("unrelated operations");
|
||||
if ancestor_op.id() == repo_operation.id() {
|
||||
// The working copy was updated since we loaded the repo. The repo must be
|
||||
// reloaded at the working copy's operation.
|
||||
Ok(Self::Updated(Box::new(wc_operation)))
|
||||
} else if ancestor_op.id() == wc_operation.id() {
|
||||
// The working copy was not updated when some repo operation committed,
|
||||
// meaning that it's stale compared to the repo view.
|
||||
Ok(Self::WorkingCopyStale)
|
||||
} else {
|
||||
Ok(Self::SiblingOperation)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error while reading the working copy state.
|
||||
#[derive(Debug, Error)]
|
||||
#[error("{message}")]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue