1#![expect(missing_docs)]
16
17use std::collections::BTreeMap;
18use std::collections::HashMap;
19use std::collections::HashSet;
20use std::collections::hash_map::Entry;
21use std::fmt::Debug;
22use std::fmt::Formatter;
23use std::fs;
24use std::path::Path;
25use std::slice;
26use std::sync::Arc;
27
28use futures::StreamExt as _;
29use futures::TryStreamExt as _;
30use futures::future::try_join_all;
31use futures::stream;
32use itertools::Itertools as _;
33use once_cell::sync::OnceCell;
34use thiserror::Error;
35use tracing::instrument;
36
37use self::dirty_cell::DirtyCell;
38use crate::backend::Backend;
39use crate::backend::BackendError;
40use crate::backend::BackendInitError;
41use crate::backend::BackendLoadError;
42use crate::backend::BackendResult;
43use crate::backend::ChangeId;
44use crate::backend::CommitId;
45use crate::commit::Commit;
46use crate::commit::CommitByCommitterTimestamp;
47use crate::commit_builder::CommitBuilder;
48use crate::commit_builder::DetachedCommitBuilder;
49use crate::dag_walk;
50use crate::dag_walk_async;
51use crate::default_index::DefaultIndexStore;
52use crate::default_index::DefaultMutableIndex;
53use crate::default_submodule_store::DefaultSubmoduleStore;
54use crate::file_util::IoResultExt as _;
55use crate::file_util::PathError;
56use crate::index::ChangeIdIndex;
57use crate::index::Index;
58use crate::index::IndexError;
59use crate::index::IndexResult;
60use crate::index::IndexStore;
61use crate::index::IndexStoreError;
62use crate::index::MutableIndex;
63use crate::index::ReadonlyIndex;
64use crate::index::ResolvedChangeTargets;
65use crate::merge::MergeBuilder;
66use crate::merge::SameChange;
67use crate::merge::trivial_merge;
68use crate::merged_tree::MergedTree;
69use crate::object_id::HexPrefix;
70use crate::object_id::PrefixResolution;
71use crate::op_heads_store;
72use crate::op_heads_store::OpHeadsStore;
73use crate::op_heads_store::OpHeadsStoreError;
74use crate::op_store;
75use crate::op_store::OpStore;
76use crate::op_store::OpStoreError;
77use crate::op_store::OpStoreResult;
78use crate::op_store::OperationId;
79use crate::op_store::RefTarget;
80use crate::op_store::RemoteRef;
81use crate::op_store::RemoteRefState;
82use crate::op_store::RootOperationData;
83use crate::operation::Operation;
84use crate::ref_name::GitRefName;
85use crate::ref_name::RefName;
86use crate::ref_name::RemoteName;
87use crate::ref_name::RemoteRefSymbol;
88use crate::ref_name::WorkspaceName;
89use crate::ref_name::WorkspaceNameBuf;
90use crate::refs::diff_named_commit_ids;
91use crate::refs::diff_named_ref_targets;
92use crate::refs::diff_named_remote_refs;
93use crate::refs::merge_ref_targets;
94use crate::refs::merge_remote_refs;
95use crate::revset;
96use crate::revset::ResolvedRevsetExpression;
97use crate::revset::RevsetEvaluationError;
98use crate::revset::RevsetExpression;
99use crate::revset::RevsetStreamExt as _;
100use crate::rewrite::CommitRewriter;
101use crate::rewrite::RebaseOptions;
102use crate::rewrite::RebasedCommit;
103use crate::rewrite::RewriteRefsOptions;
104use crate::rewrite::merge_commit_trees;
105use crate::rewrite::rebase_commit_with_options;
106use crate::settings::UserSettings;
107use crate::signing::SignInitError;
108use crate::signing::Signer;
109use crate::simple_backend::SimpleBackend;
110use crate::simple_op_heads_store::SimpleOpHeadsStore;
111use crate::simple_op_store::SimpleOpStore;
112use crate::store::Store;
113use crate::submodule_store::SubmoduleStore;
114use crate::transaction::Transaction;
115use crate::transaction::TransactionCommitError;
116use crate::tree_merge::MergeOptions;
117use crate::view::RenameWorkspaceError;
118use crate::view::View;
119
120pub trait Repo {
121 fn base_repo(&self) -> &ReadonlyRepo;
124
125 fn store(&self) -> &Arc<Store>;
126
127 fn op_store(&self) -> &Arc<dyn OpStore>;
128
129 fn index(&self) -> &dyn Index;
130
131 fn view(&self) -> &View;
132
133 fn submodule_store(&self) -> &Arc<dyn SubmoduleStore>;
134
135 fn resolve_change_id(
136 &self,
137 change_id: &ChangeId,
138 ) -> IndexResult<Option<ResolvedChangeTargets>> {
139 let prefix = HexPrefix::from_id(change_id);
141 match self.resolve_change_id_prefix(&prefix)? {
142 PrefixResolution::NoMatch => Ok(None),
143 PrefixResolution::SingleMatch(entries) => Ok(Some(entries)),
144 PrefixResolution::AmbiguousMatch => panic!("complete change_id should be unambiguous"),
145 }
146 }
147
148 fn resolve_change_id_prefix(
149 &self,
150 prefix: &HexPrefix,
151 ) -> IndexResult<PrefixResolution<ResolvedChangeTargets>>;
152
153 fn shortest_unique_change_id_prefix_len(
154 &self,
155 target_id_bytes: &ChangeId,
156 ) -> IndexResult<usize>;
157}
158
159pub struct ReadonlyRepo {
160 loader: RepoLoader,
161 operation: Operation,
162 index: Box<dyn ReadonlyIndex>,
163 change_id_index: OnceCell<Box<dyn ChangeIdIndex>>,
164 view: View,
166}
167
168impl Debug for ReadonlyRepo {
169 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
170 f.debug_struct("ReadonlyRepo")
171 .field("store", &self.loader.store)
172 .finish_non_exhaustive()
173 }
174}
175
176#[derive(Error, Debug)]
177pub enum RepoInitError {
178 #[error(transparent)]
179 Backend(#[from] BackendInitError),
180 #[error(transparent)]
181 OpHeadsStore(#[from] OpHeadsStoreError),
182 #[error(transparent)]
183 Path(#[from] PathError),
184}
185
186impl ReadonlyRepo {
187 pub fn default_op_store_initializer() -> &'static OpStoreInitializer<'static> {
188 &|_settings, store_path, root_data| {
189 Ok(Box::new(SimpleOpStore::init(store_path, root_data)?))
190 }
191 }
192
193 pub fn default_op_heads_store_initializer() -> &'static OpHeadsStoreInitializer<'static> {
194 &|_settings, store_path, root_op_id| {
195 Ok(Box::new(SimpleOpHeadsStore::init(store_path, root_op_id)?))
196 }
197 }
198
199 pub fn default_index_store_initializer() -> &'static IndexStoreInitializer<'static> {
200 &|_settings, store_path| Ok(Box::new(DefaultIndexStore::init(store_path)?))
201 }
202
203 pub fn default_submodule_store_initializer() -> &'static SubmoduleStoreInitializer<'static> {
204 &|_settings, store_path| Ok(Box::new(DefaultSubmoduleStore::init(store_path)))
205 }
206
207 #[expect(clippy::too_many_arguments)]
208 pub async fn init(
209 settings: &UserSettings,
210 repo_path: &Path,
211 backend_initializer: &BackendInitializer<'_>,
212 signer: Signer,
213 op_store_initializer: &OpStoreInitializer<'_>,
214 op_heads_store_initializer: &OpHeadsStoreInitializer<'_>,
215 index_store_initializer: &IndexStoreInitializer<'_>,
216 submodule_store_initializer: &SubmoduleStoreInitializer<'_>,
217 ) -> Result<Arc<Self>, RepoInitError> {
218 let repo_path = dunce::canonicalize(repo_path).context(repo_path)?;
219
220 let store_path = repo_path.join("store");
221 fs::create_dir(&store_path).context(&store_path)?;
222 let backend = backend_initializer(settings, &store_path)?;
223 let backend_path = store_path.join("type");
224 fs::write(&backend_path, backend.name()).context(&backend_path)?;
225 let merge_options =
226 MergeOptions::from_settings(settings).map_err(|err| BackendInitError(err.into()))?;
227 let store = Store::new(backend, signer, merge_options);
228
229 let op_store_path = repo_path.join("op_store");
230 fs::create_dir(&op_store_path).context(&op_store_path)?;
231 let root_op_data = RootOperationData {
232 root_commit_id: store.root_commit_id().clone(),
233 };
234 let op_store = op_store_initializer(settings, &op_store_path, root_op_data)?;
235 let op_store_type_path = op_store_path.join("type");
236 fs::write(&op_store_type_path, op_store.name()).context(&op_store_type_path)?;
237 let op_store: Arc<dyn OpStore> = Arc::from(op_store);
238
239 let op_heads_path = repo_path.join("op_heads");
240 fs::create_dir(&op_heads_path).context(&op_heads_path)?;
241 let op_heads_store =
242 op_heads_store_initializer(settings, &op_heads_path, op_store.root_operation_id())?;
243 let op_heads_type_path = op_heads_path.join("type");
244 fs::write(&op_heads_type_path, op_heads_store.name()).context(&op_heads_type_path)?;
245 let op_heads_store: Arc<dyn OpHeadsStore> = Arc::from(op_heads_store);
246
247 let index_path = repo_path.join("index");
248 fs::create_dir(&index_path).context(&index_path)?;
249 let index_store = index_store_initializer(settings, &index_path)?;
250 let index_type_path = index_path.join("type");
251 fs::write(&index_type_path, index_store.name()).context(&index_type_path)?;
252 let index_store: Arc<dyn IndexStore> = Arc::from(index_store);
253
254 let submodule_store_path = repo_path.join("submodule_store");
255 fs::create_dir(&submodule_store_path).context(&submodule_store_path)?;
256 let submodule_store = submodule_store_initializer(settings, &submodule_store_path)?;
257 let submodule_store_type_path = submodule_store_path.join("type");
258 fs::write(&submodule_store_type_path, submodule_store.name())
259 .context(&submodule_store_type_path)?;
260 let submodule_store = Arc::from(submodule_store);
261
262 let loader = RepoLoader {
263 settings: settings.clone(),
264 store,
265 op_store,
266 op_heads_store,
267 index_store,
268 submodule_store,
269 };
270
271 let root_operation = loader.root_operation().await;
272 let root_view = root_operation
273 .view()
274 .await
275 .expect("failed to read root view");
276 assert!(!root_view.heads().is_empty());
277 let index = loader
278 .index_store
279 .get_index_at_op(&root_operation, &loader.store)
280 .await
281 .map_err(|err| BackendInitError(err.into()))?;
284 Ok(Arc::new(Self {
285 loader,
286 operation: root_operation,
287 index,
288 change_id_index: OnceCell::new(),
289 view: root_view,
290 }))
291 }
292
293 pub fn loader(&self) -> &RepoLoader {
294 &self.loader
295 }
296
297 pub fn op_id(&self) -> &OperationId {
298 self.operation.id()
299 }
300
301 pub fn operation(&self) -> &Operation {
302 &self.operation
303 }
304
305 pub fn view(&self) -> &View {
306 &self.view
307 }
308
309 pub fn readonly_index(&self) -> &dyn ReadonlyIndex {
310 self.index.as_ref()
311 }
312
313 fn change_id_index(&self) -> &dyn ChangeIdIndex {
314 self.change_id_index
315 .get_or_init(|| {
316 self.readonly_index()
317 .change_id_index(&mut self.view().heads().iter())
318 })
319 .as_ref()
320 }
321
322 pub fn op_heads_store(&self) -> &Arc<dyn OpHeadsStore> {
323 self.loader.op_heads_store()
324 }
325
326 pub fn index_store(&self) -> &Arc<dyn IndexStore> {
327 self.loader.index_store()
328 }
329
330 pub fn settings(&self) -> &UserSettings {
331 self.loader.settings()
332 }
333
334 pub fn start_transaction(self: &Arc<Self>) -> Transaction {
335 let mut_repo = MutableRepo::new(self.clone(), self.readonly_index(), &self.view);
336 Transaction::new(mut_repo, self.settings())
337 }
338
339 pub async fn reload_at_head(&self) -> Result<Arc<Self>, RepoLoaderError> {
340 self.loader().load_at_head().await
341 }
342
343 #[instrument]
344 pub async fn reload_at(&self, operation: &Operation) -> Result<Arc<Self>, RepoLoaderError> {
345 self.loader().load_at(operation).await
346 }
347}
348
349impl Repo for ReadonlyRepo {
350 fn base_repo(&self) -> &ReadonlyRepo {
351 self
352 }
353
354 fn store(&self) -> &Arc<Store> {
355 self.loader.store()
356 }
357
358 fn op_store(&self) -> &Arc<dyn OpStore> {
359 self.loader.op_store()
360 }
361
362 fn index(&self) -> &dyn Index {
363 self.readonly_index().as_index()
364 }
365
366 fn view(&self) -> &View {
367 &self.view
368 }
369
370 fn submodule_store(&self) -> &Arc<dyn SubmoduleStore> {
371 self.loader.submodule_store()
372 }
373
374 fn resolve_change_id_prefix(
375 &self,
376 prefix: &HexPrefix,
377 ) -> IndexResult<PrefixResolution<ResolvedChangeTargets>> {
378 self.change_id_index().resolve_prefix(prefix)
379 }
380
381 fn shortest_unique_change_id_prefix_len(&self, target_id: &ChangeId) -> IndexResult<usize> {
382 self.change_id_index().shortest_unique_prefix_len(target_id)
383 }
384}
385
386pub type BackendInitializer<'a> =
387 dyn Fn(&UserSettings, &Path) -> Result<Box<dyn Backend>, BackendInitError> + 'a;
388#[rustfmt::skip] pub type OpStoreInitializer<'a> =
390 dyn Fn(&UserSettings, &Path, RootOperationData) -> Result<Box<dyn OpStore>, BackendInitError>
391 + 'a;
392#[rustfmt::skip] pub type OpHeadsStoreInitializer<'a> =
394 dyn Fn(&UserSettings, &Path, &OperationId)
395 -> Result<Box<dyn OpHeadsStore>, BackendInitError>
396 + 'a;
397pub type IndexStoreInitializer<'a> =
398 dyn Fn(&UserSettings, &Path) -> Result<Box<dyn IndexStore>, BackendInitError> + 'a;
399pub type SubmoduleStoreInitializer<'a> =
400 dyn Fn(&UserSettings, &Path) -> Result<Box<dyn SubmoduleStore>, BackendInitError> + 'a;
401
402type BackendFactory =
403 Box<dyn Fn(&UserSettings, &Path) -> Result<Box<dyn Backend>, BackendLoadError>>;
404type OpStoreFactory = Box<
405 dyn Fn(&UserSettings, &Path, RootOperationData) -> Result<Box<dyn OpStore>, BackendLoadError>,
406>;
407type OpHeadsStoreFactory =
408 Box<dyn Fn(&UserSettings, &Path) -> Result<Box<dyn OpHeadsStore>, BackendLoadError>>;
409type IndexStoreFactory =
410 Box<dyn Fn(&UserSettings, &Path) -> Result<Box<dyn IndexStore>, BackendLoadError>>;
411type SubmoduleStoreFactory =
412 Box<dyn Fn(&UserSettings, &Path) -> Result<Box<dyn SubmoduleStore>, BackendLoadError>>;
413
414pub fn merge_factories_map<F>(base: &mut HashMap<String, F>, ext: HashMap<String, F>) {
415 for (name, factory) in ext {
416 match base.entry(name) {
417 Entry::Vacant(v) => {
418 v.insert(factory);
419 }
420 Entry::Occupied(o) => {
421 panic!("Conflicting factory definitions for '{}' factory", o.key())
422 }
423 }
424 }
425}
426
427pub struct StoreFactories {
428 backend_factories: HashMap<String, BackendFactory>,
429 op_store_factories: HashMap<String, OpStoreFactory>,
430 op_heads_store_factories: HashMap<String, OpHeadsStoreFactory>,
431 index_store_factories: HashMap<String, IndexStoreFactory>,
432 submodule_store_factories: HashMap<String, SubmoduleStoreFactory>,
433}
434
435impl Default for StoreFactories {
436 fn default() -> Self {
437 let mut factories = Self::empty();
438
439 factories.add_backend(
441 SimpleBackend::name(),
442 Box::new(|_settings, store_path| Ok(Box::new(SimpleBackend::load(store_path)))),
443 );
444 #[cfg(feature = "git")]
445 factories.add_backend(
446 crate::git_backend::GitBackend::name(),
447 Box::new(|settings, store_path| {
448 Ok(Box::new(crate::git_backend::GitBackend::load(
449 settings, store_path,
450 )?))
451 }),
452 );
453 #[cfg(feature = "testing")]
454 factories.add_backend(
455 crate::secret_backend::SecretBackend::name(),
456 Box::new(|settings, store_path| {
457 Ok(Box::new(crate::secret_backend::SecretBackend::load(
458 settings, store_path,
459 )?))
460 }),
461 );
462
463 factories.add_op_store(
465 SimpleOpStore::name(),
466 Box::new(|_settings, store_path, root_data| {
467 Ok(Box::new(SimpleOpStore::load(store_path, root_data)))
468 }),
469 );
470
471 factories.add_op_heads_store(
473 SimpleOpHeadsStore::name(),
474 Box::new(|_settings, store_path| Ok(Box::new(SimpleOpHeadsStore::load(store_path)))),
475 );
476
477 factories.add_index_store(
479 DefaultIndexStore::name(),
480 Box::new(|_settings, store_path| Ok(Box::new(DefaultIndexStore::load(store_path)))),
481 );
482
483 factories.add_submodule_store(
485 DefaultSubmoduleStore::name(),
486 Box::new(|_settings, store_path| Ok(Box::new(DefaultSubmoduleStore::load(store_path)))),
487 );
488
489 factories
490 }
491}
492
493#[derive(Debug, Error)]
494pub enum StoreLoadError {
495 #[error("Unsupported {store} backend type '{store_type}'")]
496 UnsupportedType {
497 store: &'static str,
498 store_type: String,
499 },
500 #[error("Failed to read {store} backend type")]
501 ReadError {
502 store: &'static str,
503 source: PathError,
504 },
505 #[error(transparent)]
506 Backend(#[from] BackendLoadError),
507 #[error(transparent)]
508 Signing(#[from] SignInitError),
509}
510
511impl StoreFactories {
512 pub fn empty() -> Self {
513 Self {
514 backend_factories: HashMap::new(),
515 op_store_factories: HashMap::new(),
516 op_heads_store_factories: HashMap::new(),
517 index_store_factories: HashMap::new(),
518 submodule_store_factories: HashMap::new(),
519 }
520 }
521
522 pub fn merge(&mut self, ext: Self) {
523 let Self {
524 backend_factories,
525 op_store_factories,
526 op_heads_store_factories,
527 index_store_factories,
528 submodule_store_factories,
529 } = ext;
530
531 merge_factories_map(&mut self.backend_factories, backend_factories);
532 merge_factories_map(&mut self.op_store_factories, op_store_factories);
533 merge_factories_map(&mut self.op_heads_store_factories, op_heads_store_factories);
534 merge_factories_map(&mut self.index_store_factories, index_store_factories);
535 merge_factories_map(
536 &mut self.submodule_store_factories,
537 submodule_store_factories,
538 );
539 }
540
541 pub fn add_backend(&mut self, name: &str, factory: BackendFactory) {
542 self.backend_factories.insert(name.to_string(), factory);
543 }
544
545 pub fn load_backend(
546 &self,
547 settings: &UserSettings,
548 store_path: &Path,
549 ) -> Result<Box<dyn Backend>, StoreLoadError> {
550 let backend_type = read_store_type("commit", store_path.join("type"))?;
551 let backend_factory = self.backend_factories.get(&backend_type).ok_or_else(|| {
552 StoreLoadError::UnsupportedType {
553 store: "commit",
554 store_type: backend_type.clone(),
555 }
556 })?;
557 Ok(backend_factory(settings, store_path)?)
558 }
559
560 pub fn add_op_store(&mut self, name: &str, factory: OpStoreFactory) {
561 self.op_store_factories.insert(name.to_string(), factory);
562 }
563
564 pub fn load_op_store(
565 &self,
566 settings: &UserSettings,
567 store_path: &Path,
568 root_data: RootOperationData,
569 ) -> Result<Box<dyn OpStore>, StoreLoadError> {
570 let op_store_type = read_store_type("operation", store_path.join("type"))?;
571 let op_store_factory = self.op_store_factories.get(&op_store_type).ok_or_else(|| {
572 StoreLoadError::UnsupportedType {
573 store: "operation",
574 store_type: op_store_type.clone(),
575 }
576 })?;
577 Ok(op_store_factory(settings, store_path, root_data)?)
578 }
579
580 pub fn add_op_heads_store(&mut self, name: &str, factory: OpHeadsStoreFactory) {
581 self.op_heads_store_factories
582 .insert(name.to_string(), factory);
583 }
584
585 pub fn load_op_heads_store(
586 &self,
587 settings: &UserSettings,
588 store_path: &Path,
589 ) -> Result<Box<dyn OpHeadsStore>, StoreLoadError> {
590 let op_heads_store_type = read_store_type("operation heads", store_path.join("type"))?;
591 let op_heads_store_factory = self
592 .op_heads_store_factories
593 .get(&op_heads_store_type)
594 .ok_or_else(|| StoreLoadError::UnsupportedType {
595 store: "operation heads",
596 store_type: op_heads_store_type.clone(),
597 })?;
598 Ok(op_heads_store_factory(settings, store_path)?)
599 }
600
601 pub fn add_index_store(&mut self, name: &str, factory: IndexStoreFactory) {
602 self.index_store_factories.insert(name.to_string(), factory);
603 }
604
605 pub fn load_index_store(
606 &self,
607 settings: &UserSettings,
608 store_path: &Path,
609 ) -> Result<Box<dyn IndexStore>, StoreLoadError> {
610 let index_store_type = read_store_type("index", store_path.join("type"))?;
611 let index_store_factory = self
612 .index_store_factories
613 .get(&index_store_type)
614 .ok_or_else(|| StoreLoadError::UnsupportedType {
615 store: "index",
616 store_type: index_store_type.clone(),
617 })?;
618 Ok(index_store_factory(settings, store_path)?)
619 }
620
621 pub fn add_submodule_store(&mut self, name: &str, factory: SubmoduleStoreFactory) {
622 self.submodule_store_factories
623 .insert(name.to_string(), factory);
624 }
625
626 pub fn load_submodule_store(
627 &self,
628 settings: &UserSettings,
629 store_path: &Path,
630 ) -> Result<Box<dyn SubmoduleStore>, StoreLoadError> {
631 let submodule_store_type = read_store_type("submodule_store", store_path.join("type"))?;
632 let submodule_store_factory = self
633 .submodule_store_factories
634 .get(&submodule_store_type)
635 .ok_or_else(|| StoreLoadError::UnsupportedType {
636 store: "submodule_store",
637 store_type: submodule_store_type.clone(),
638 })?;
639
640 Ok(submodule_store_factory(settings, store_path)?)
641 }
642}
643
644pub fn read_store_type(
645 store: &'static str,
646 path: impl AsRef<Path>,
647) -> Result<String, StoreLoadError> {
648 let path = path.as_ref();
649 fs::read_to_string(path)
650 .context(path)
651 .map_err(|source| StoreLoadError::ReadError { store, source })
652}
653
654#[derive(Debug, Error)]
655pub enum RepoLoaderError {
656 #[error(transparent)]
657 Backend(#[from] BackendError),
658 #[error(transparent)]
659 Index(#[from] IndexError),
660 #[error(transparent)]
661 IndexStore(#[from] IndexStoreError),
662 #[error(transparent)]
663 OpHeadsStoreError(#[from] OpHeadsStoreError),
664 #[error(transparent)]
665 OpStore(#[from] OpStoreError),
666 #[error(transparent)]
667 TransactionCommit(#[from] TransactionCommitError),
668}
669
670#[derive(Clone)]
673pub struct RepoLoader {
674 settings: UserSettings,
675 store: Arc<Store>,
676 op_store: Arc<dyn OpStore>,
677 op_heads_store: Arc<dyn OpHeadsStore>,
678 index_store: Arc<dyn IndexStore>,
679 submodule_store: Arc<dyn SubmoduleStore>,
680}
681
682impl RepoLoader {
683 pub fn new(
684 settings: UserSettings,
685 store: Arc<Store>,
686 op_store: Arc<dyn OpStore>,
687 op_heads_store: Arc<dyn OpHeadsStore>,
688 index_store: Arc<dyn IndexStore>,
689 submodule_store: Arc<dyn SubmoduleStore>,
690 ) -> Self {
691 Self {
692 settings,
693 store,
694 op_store,
695 op_heads_store,
696 index_store,
697 submodule_store,
698 }
699 }
700
701 pub fn init_from_file_system(
705 settings: &UserSettings,
706 repo_path: &Path,
707 store_factories: &StoreFactories,
708 ) -> Result<Self, StoreLoadError> {
709 let merge_options =
710 MergeOptions::from_settings(settings).map_err(|err| BackendLoadError(err.into()))?;
711 let store = Store::new(
712 store_factories.load_backend(settings, &repo_path.join("store"))?,
713 Signer::from_settings(settings)?,
714 merge_options,
715 );
716 let root_op_data = RootOperationData {
717 root_commit_id: store.root_commit_id().clone(),
718 };
719 let op_store = Arc::from(store_factories.load_op_store(
720 settings,
721 &repo_path.join("op_store"),
722 root_op_data,
723 )?);
724 let op_heads_store =
725 Arc::from(store_factories.load_op_heads_store(settings, &repo_path.join("op_heads"))?);
726 let index_store =
727 Arc::from(store_factories.load_index_store(settings, &repo_path.join("index"))?);
728 let submodule_store = Arc::from(
729 store_factories.load_submodule_store(settings, &repo_path.join("submodule_store"))?,
730 );
731 Ok(Self {
732 settings: settings.clone(),
733 store,
734 op_store,
735 op_heads_store,
736 index_store,
737 submodule_store,
738 })
739 }
740
741 pub fn settings(&self) -> &UserSettings {
742 &self.settings
743 }
744
745 pub fn store(&self) -> &Arc<Store> {
746 &self.store
747 }
748
749 pub fn index_store(&self) -> &Arc<dyn IndexStore> {
750 &self.index_store
751 }
752
753 pub fn op_store(&self) -> &Arc<dyn OpStore> {
754 &self.op_store
755 }
756
757 pub fn op_heads_store(&self) -> &Arc<dyn OpHeadsStore> {
758 &self.op_heads_store
759 }
760
761 pub fn submodule_store(&self) -> &Arc<dyn SubmoduleStore> {
762 &self.submodule_store
763 }
764
765 pub async fn load_at_head(&self) -> Result<Arc<ReadonlyRepo>, RepoLoaderError> {
766 let op = op_heads_store::resolve_op_heads(
767 self.op_heads_store.as_ref(),
768 &self.op_store,
769 async |op_heads| {
770 assert!(!op_heads.is_empty());
771 self.merge_operations(op_heads, Some("reconcile divergent operations"))
772 .await
773 },
774 )
775 .await?;
776 let view = op.view().await?;
777 self.finish_load(op, view).await
778 }
779
780 #[instrument(skip(self))]
781 pub async fn load_at(&self, op: &Operation) -> Result<Arc<ReadonlyRepo>, RepoLoaderError> {
782 let view = op.view().await?;
783 self.finish_load(op.clone(), view).await
784 }
785
786 pub fn create_from(
787 &self,
788 operation: Operation,
789 view: View,
790 index: Box<dyn ReadonlyIndex>,
791 ) -> Arc<ReadonlyRepo> {
792 let repo = ReadonlyRepo {
793 loader: self.clone(),
794 operation,
795 index,
796 change_id_index: OnceCell::new(),
797 view,
798 };
799 Arc::new(repo)
800 }
801
802 pub async fn root_operation(&self) -> Operation {
807 self.load_operation(self.op_store.root_operation_id())
808 .await
809 .expect("failed to read root operation")
810 }
811
812 pub async fn load_operation(&self, id: &OperationId) -> OpStoreResult<Operation> {
814 let data = self.op_store.read_operation(id).await?;
815 Ok(Operation::new(self.op_store.clone(), id.clone(), data))
816 }
817
818 pub async fn merge_operations(
821 &self,
822 operations: Vec<Operation>,
823 tx_description: Option<&str>,
824 ) -> Result<Operation, RepoLoaderError> {
825 let num_operations = operations.len();
826 let mut operations = operations.into_iter();
827 let Some(base_op) = operations.next() else {
828 return Ok(self.root_operation().await);
829 };
830 let final_op = if num_operations > 1 {
831 let base_repo = self.load_at(&base_op).await?;
832 let mut tx = base_repo.start_transaction();
833 for other_op in operations {
834 tx.merge_operation(other_op).await?;
835 tx.repo_mut().rebase_descendants().await?;
836 }
837 let tx_description = tx_description.map_or_else(
838 || format!("merge {num_operations} operations"),
839 |tx_description| tx_description.to_string(),
840 );
841 let merged_repo = tx.write(tx_description).await?.leave_unpublished();
842 merged_repo.operation().clone()
843 } else {
844 base_op
845 };
846
847 Ok(final_op)
848 }
849
850 async fn finish_load(
851 &self,
852 operation: Operation,
853 view: View,
854 ) -> Result<Arc<ReadonlyRepo>, RepoLoaderError> {
855 let index = self
856 .index_store
857 .get_index_at_op(&operation, &self.store)
858 .await?;
859 let repo = ReadonlyRepo {
860 loader: self.clone(),
861 operation,
862 index,
863 change_id_index: OnceCell::new(),
864 view,
865 };
866 Ok(Arc::new(repo))
867 }
868}
869
870#[derive(Clone, Debug, PartialEq, Eq)]
871enum Rewrite {
872 Rewritten(CommitId),
875 Divergent(Vec<CommitId>),
878 Abandoned(Vec<CommitId>),
881}
882
883impl Rewrite {
884 fn new_parent_ids(&self) -> &[CommitId] {
885 match self {
886 Self::Rewritten(new_parent_id) => std::slice::from_ref(new_parent_id),
887 Self::Divergent(new_parent_ids) => new_parent_ids.as_slice(),
888 Self::Abandoned(new_parent_ids) => new_parent_ids.as_slice(),
889 }
890 }
891}
892
893pub struct MutableRepo {
894 base_repo: Arc<ReadonlyRepo>,
895 index: Box<dyn MutableIndex>,
896 view: DirtyCell<View>,
897 commit_predecessors: BTreeMap<CommitId, Vec<CommitId>>,
902 parent_mapping: HashMap<CommitId, Rewrite>,
911}
912
913impl MutableRepo {
914 pub fn new(base_repo: Arc<ReadonlyRepo>, index: &dyn ReadonlyIndex, view: &View) -> Self {
915 let mut_view = view.clone();
916 let mut_index = index.start_modification();
917 Self {
918 base_repo,
919 index: mut_index,
920 view: DirtyCell::with_clean(mut_view),
921 commit_predecessors: Default::default(),
922 parent_mapping: Default::default(),
923 }
924 }
925
926 pub fn base_repo(&self) -> &Arc<ReadonlyRepo> {
927 &self.base_repo
928 }
929
930 fn view_mut(&mut self) -> &mut View {
931 self.view.get_mut()
932 }
933
934 pub fn mutable_index(&self) -> &dyn MutableIndex {
935 self.index.as_ref()
936 }
937
938 pub(crate) fn is_backed_by_default_index(&self) -> bool {
939 self.index.downcast_ref::<DefaultMutableIndex>().is_some()
940 }
941
942 pub fn has_changes(&self) -> bool {
943 self.view.ensure_clean(|v| self.enforce_view_invariants(v));
944 !(self.commit_predecessors.is_empty()
945 && self.parent_mapping.is_empty()
946 && self.view() == &self.base_repo.view)
947 }
948
949 pub(crate) fn consume(
950 self,
951 ) -> (
952 Box<dyn MutableIndex>,
953 View,
954 BTreeMap<CommitId, Vec<CommitId>>,
955 ) {
956 self.view.ensure_clean(|v| self.enforce_view_invariants(v));
957 (self.index, self.view.into_inner(), self.commit_predecessors)
958 }
959
960 pub fn new_commit(&mut self, parents: Vec<CommitId>, tree: MergedTree) -> CommitBuilder<'_> {
962 let settings = self.base_repo.settings();
963 DetachedCommitBuilder::for_new_commit(self, settings, parents, tree).attach(self)
964 }
965
966 pub fn rewrite_commit(&mut self, predecessor: &Commit) -> CommitBuilder<'_> {
968 let settings = self.base_repo.settings();
969 DetachedCommitBuilder::for_rewrite_from(self, settings, predecessor).attach(self)
970 }
973
974 pub(crate) fn set_predecessors(&mut self, id: CommitId, predecessors: Vec<CommitId>) {
975 self.commit_predecessors.insert(id, predecessors);
976 }
977
978 pub fn set_rewritten_commit(&mut self, old_id: CommitId, new_id: CommitId) {
985 assert_ne!(old_id, *self.store().root_commit_id());
986 self.parent_mapping
987 .insert(old_id, Rewrite::Rewritten(new_id));
988 }
989
990 pub fn set_divergent_rewrite(
998 &mut self,
999 old_id: CommitId,
1000 new_ids: impl IntoIterator<Item = CommitId>,
1001 ) {
1002 assert_ne!(old_id, *self.store().root_commit_id());
1003 self.parent_mapping.insert(
1004 old_id.clone(),
1005 Rewrite::Divergent(new_ids.into_iter().collect()),
1006 );
1007 }
1008
1009 pub fn record_abandoned_commit(&mut self, old_commit: &Commit) {
1019 assert_ne!(old_commit.id(), self.store().root_commit_id());
1020 self.record_abandoned_commit_with_parents(
1022 old_commit.id().clone(),
1023 old_commit.parent_ids().iter().cloned(),
1024 );
1025 }
1026
1027 pub fn record_abandoned_commit_with_parents(
1033 &mut self,
1034 old_id: CommitId,
1035 new_parent_ids: impl IntoIterator<Item = CommitId>,
1036 ) {
1037 assert_ne!(old_id, *self.store().root_commit_id());
1038 self.parent_mapping.insert(
1039 old_id,
1040 Rewrite::Abandoned(new_parent_ids.into_iter().collect()),
1041 );
1042 }
1043
1044 pub fn has_rewrites(&self) -> bool {
1045 !self.parent_mapping.is_empty()
1046 }
1047
1048 pub fn new_parents(&self, old_ids: &[CommitId]) -> Vec<CommitId> {
1055 self.rewritten_ids_with(old_ids, |rewrite| !matches!(rewrite, Rewrite::Divergent(_)))
1056 }
1057
1058 fn rewritten_ids_with(
1059 &self,
1060 old_ids: &[CommitId],
1061 mut predicate: impl FnMut(&Rewrite) -> bool,
1062 ) -> Vec<CommitId> {
1063 assert!(!old_ids.is_empty());
1064 let mut new_ids = Vec::with_capacity(old_ids.len());
1065 let mut to_visit = old_ids.iter().rev().collect_vec();
1066 let mut visited = HashSet::new();
1067 while let Some(id) = to_visit.pop() {
1068 if !visited.insert(id) {
1069 continue;
1070 }
1071 match self.parent_mapping.get(id).filter(|&v| predicate(v)) {
1072 None => {
1073 new_ids.push(id.clone());
1074 }
1075 Some(rewrite) => {
1076 let replacements = rewrite.new_parent_ids();
1077 assert!(
1078 !replacements.is_empty(),
1083 "Found empty value for key {id:?} in the parent mapping",
1084 );
1085 to_visit.extend(replacements.iter().rev());
1086 }
1087 }
1088 }
1089 assert!(
1090 !new_ids.is_empty(),
1091 "new ids become empty because of cycle in the parent mapping"
1092 );
1093 debug_assert!(new_ids.iter().all_unique());
1094 new_ids
1095 }
1096
1097 fn resolve_rewrite_mapping_with(
1101 &self,
1102 mut predicate: impl FnMut(&Rewrite) -> bool,
1103 ) -> BackendResult<HashMap<CommitId, Vec<CommitId>>> {
1104 let sorted_ids = dag_walk::topo_order_forward(
1105 self.parent_mapping.keys(),
1106 |&id| id,
1107 |&id| match self.parent_mapping.get(id).filter(|&v| predicate(v)) {
1108 None => &[],
1109 Some(rewrite) => rewrite.new_parent_ids(),
1110 },
1111 |id| {
1112 BackendError::Other(
1113 format!("Cycle between rewritten commits involving commit {id}").into(),
1114 )
1115 },
1116 )?;
1117 let mut new_mapping: HashMap<CommitId, Vec<CommitId>> = HashMap::new();
1118 for old_id in sorted_ids {
1119 let Some(rewrite) = self.parent_mapping.get(old_id).filter(|&v| predicate(v)) else {
1120 continue;
1121 };
1122 let lookup = |id| new_mapping.get(id).map_or(slice::from_ref(id), |ids| ids);
1123 let new_ids = match rewrite.new_parent_ids() {
1124 [id] => lookup(id).to_vec(), ids => ids.iter().flat_map(lookup).unique().cloned().collect(),
1126 };
1127 debug_assert_eq!(
1128 new_ids,
1129 self.rewritten_ids_with(slice::from_ref(old_id), &mut predicate)
1130 );
1131 new_mapping.insert(old_id.clone(), new_ids);
1132 }
1133 Ok(new_mapping)
1134 }
1135
1136 pub async fn update_rewritten_references(
1139 &mut self,
1140 options: &RewriteRefsOptions,
1141 ) -> BackendResult<()> {
1142 self.update_all_references(options).await?;
1143 self.update_heads()
1144 .await
1145 .map_err(|err| err.into_backend_error())?;
1146 Ok(())
1147 }
1148
1149 async fn update_all_references(&mut self, options: &RewriteRefsOptions) -> BackendResult<()> {
1150 let rewrite_mapping = self.resolve_rewrite_mapping_with(|_| true)?;
1151 self.update_local_bookmarks(&rewrite_mapping, options)
1152 .map_err(|err| BackendError::Other(err.into()))?;
1154 self.update_wc_commits(&rewrite_mapping).await?;
1155 Ok(())
1156 }
1157
1158 fn update_local_bookmarks(
1159 &mut self,
1160 rewrite_mapping: &HashMap<CommitId, Vec<CommitId>>,
1161 options: &RewriteRefsOptions,
1162 ) -> IndexResult<()> {
1163 let changed_branches = self
1164 .view()
1165 .local_bookmarks()
1166 .flat_map(|(name, target)| {
1167 target.added_ids().filter_map(|id| {
1168 let change = rewrite_mapping.get_key_value(id)?;
1169 Some((name.to_owned(), change))
1170 })
1171 })
1172 .collect_vec();
1173 for (bookmark_name, (old_commit_id, new_commit_ids)) in changed_branches {
1174 let should_delete = options.delete_abandoned_bookmarks
1175 && matches!(
1176 self.parent_mapping.get(old_commit_id),
1177 Some(Rewrite::Abandoned(_))
1178 );
1179 let old_target = RefTarget::normal(old_commit_id.clone());
1180 let new_target = if should_delete {
1181 RefTarget::absent()
1182 } else {
1183 let ids = itertools::intersperse(new_commit_ids, old_commit_id)
1184 .map(|id| Some(id.clone()));
1185 RefTarget::from_merge(MergeBuilder::from_iter(ids).build())
1186 };
1187
1188 self.merge_local_bookmark(&bookmark_name, &old_target, &new_target)?;
1189 }
1190 Ok(())
1191 }
1192
1193 async fn update_wc_commits(
1194 &mut self,
1195 rewrite_mapping: &HashMap<CommitId, Vec<CommitId>>,
1196 ) -> BackendResult<()> {
1197 let changed_wc_commits = self
1198 .view()
1199 .wc_commit_ids()
1200 .iter()
1201 .filter_map(|(name, commit_id)| {
1202 let change = rewrite_mapping.get_key_value(commit_id)?;
1203 Some((name.to_owned(), change))
1204 })
1205 .collect_vec();
1206 let mut recreated_wc_commits: HashMap<&CommitId, Commit> = HashMap::new();
1207 for (name, (old_commit_id, new_commit_ids)) in changed_wc_commits {
1208 let abandoned_old_commit = matches!(
1209 self.parent_mapping.get(old_commit_id),
1210 Some(Rewrite::Abandoned(_))
1211 );
1212 let new_wc_commit = if !abandoned_old_commit {
1213 self.store().get_commit_async(&new_commit_ids[0]).await?
1215 } else if let Some(commit) = recreated_wc_commits.get(old_commit_id) {
1216 commit.clone()
1217 } else {
1218 let new_commit_futures = new_commit_ids
1219 .iter()
1220 .map(async |id| self.store().get_commit_async(id).await);
1221 let new_commits = try_join_all(new_commit_futures).await?;
1222 let merged_parents_tree = merge_commit_trees(self, &new_commits).await?;
1223 let commit = self
1224 .new_commit(new_commit_ids.clone(), merged_parents_tree)
1225 .write()
1226 .await?;
1227 recreated_wc_commits.insert(old_commit_id, commit.clone());
1228 commit
1229 };
1230 self.edit(name, &new_wc_commit)
1231 .await
1232 .map_err(|err| match err {
1233 EditCommitError::BackendError(backend_error) => backend_error,
1234 EditCommitError::WorkingCopyCommitNotFound(_)
1235 | EditCommitError::RewriteRootCommit(_) => panic!("unexpected error: {err:?}"),
1236 })?;
1237 }
1238 Ok(())
1239 }
1240
1241 async fn update_heads(&mut self) -> Result<(), RevsetEvaluationError> {
1242 let old_commits_expression =
1243 RevsetExpression::commits(self.parent_mapping.keys().cloned().collect())
1244 .intersection(&RevsetExpression::visible_heads().ancestors());
1245 let heads_to_add_expression = old_commits_expression
1246 .parents()
1247 .minus(&old_commits_expression);
1248 let heads_to_add: Vec<_> = heads_to_add_expression
1249 .evaluate(self)?
1250 .stream()
1251 .try_collect()
1252 .await?;
1253
1254 let mut view = self.view().store_view().clone();
1255 for commit_id in self.parent_mapping.keys() {
1256 view.head_ids.remove(commit_id);
1257 }
1258 view.head_ids.extend(heads_to_add);
1259 self.set_view(view);
1260 Ok(())
1261 }
1262
1263 pub async fn find_descendants_for_rebase(
1266 &self,
1267 roots: Vec<CommitId>,
1268 immutable: &Arc<ResolvedRevsetExpression>,
1269 ) -> BackendResult<Vec<Commit>> {
1270 let to_visit_revset = RevsetExpression::commits(roots)
1271 .descendants()
1272 .minus(immutable)
1273 .minus(&RevsetExpression::commits(
1274 self.parent_mapping.keys().cloned().collect(),
1275 ))
1276 .evaluate(self)
1277 .map_err(|err| err.into_backend_error())?;
1278 let to_visit = to_visit_revset
1279 .stream()
1280 .commits(self.store())
1281 .try_collect()
1282 .await
1283 .map_err(|err| err.into_backend_error())?;
1284 Ok(to_visit)
1285 }
1286
1287 async fn order_commits_for_rebase(
1290 &self,
1291 to_visit: Vec<Commit>,
1292 new_parents_map: &HashMap<CommitId, Vec<CommitId>>,
1293 ) -> BackendResult<Vec<Commit>> {
1294 let to_visit_set: HashSet<CommitId> =
1295 to_visit.iter().map(|commit| commit.id().clone()).collect();
1296 let mut visited = HashSet::new();
1297 let store = self.store();
1300 dag_walk_async::topo_order_reverse(
1301 to_visit.into_iter().map(Ok),
1302 |commit| commit.id().clone(),
1303 async |commit| -> Vec<BackendResult<Commit>> {
1304 visited.insert(commit.id().clone());
1305 let mut dependents = vec![];
1306 let parent_ids = new_parents_map
1307 .get(commit.id())
1308 .map_or(commit.parent_ids(), |parent_ids| parent_ids);
1309 for parent_id in parent_ids {
1310 let parent = store.get_commit_async(parent_id).await;
1311 let Ok(parent) = parent else {
1312 dependents.push(parent);
1313 continue;
1314 };
1315 if let Some(rewrite) = self.parent_mapping.get(parent.id()) {
1316 for target in rewrite.new_parent_ids() {
1317 if to_visit_set.contains(target) && !visited.contains(target) {
1318 dependents.push(store.get_commit_async(target).await);
1319 }
1320 }
1321 }
1322 if to_visit_set.contains(parent.id()) {
1323 dependents.push(Ok(parent));
1324 }
1325 }
1326 dependents
1327 },
1328 |_| panic!("graph has cycle"),
1329 )
1330 .await
1331 }
1332
1333 pub async fn transform_descendants(
1345 &mut self,
1346 roots: Vec<CommitId>,
1347 callback: impl AsyncFnMut(CommitRewriter) -> BackendResult<()>,
1348 ) -> BackendResult<()> {
1349 self.transform_descendants_with_options(
1350 roots,
1351 &RevsetExpression::none(),
1352 &HashMap::new(),
1353 &RewriteRefsOptions::default(),
1354 callback,
1355 )
1356 .await
1357 }
1358
1359 pub async fn transform_descendants_with_options(
1369 &mut self,
1370 roots: Vec<CommitId>,
1371 immutable: &Arc<ResolvedRevsetExpression>,
1372 new_parents_map: &HashMap<CommitId, Vec<CommitId>>,
1373 options: &RewriteRefsOptions,
1374 callback: impl AsyncFnMut(CommitRewriter) -> BackendResult<()>,
1375 ) -> BackendResult<()> {
1376 let descendants = self.find_descendants_for_rebase(roots, immutable).await?;
1377 self.transform_commits(descendants, new_parents_map, options, callback)
1378 .await
1379 }
1380
1381 pub async fn transform_commits(
1387 &mut self,
1388 commits: Vec<Commit>,
1389 new_parents_map: &HashMap<CommitId, Vec<CommitId>>,
1390 options: &RewriteRefsOptions,
1391 mut callback: impl AsyncFnMut(CommitRewriter) -> BackendResult<()>,
1392 ) -> BackendResult<()> {
1393 let mut to_visit = self
1394 .order_commits_for_rebase(commits, new_parents_map)
1395 .await?;
1396 while let Some(old_commit) = to_visit.pop() {
1397 let parent_ids = new_parents_map
1398 .get(old_commit.id())
1399 .map_or(old_commit.parent_ids(), |parent_ids| parent_ids);
1400 let new_parent_ids = self.new_parents(parent_ids);
1401 let rewriter = CommitRewriter::new(self, old_commit, new_parent_ids);
1402 callback(rewriter).await?;
1403 }
1404 self.update_rewritten_references(options).await?;
1405 Ok(())
1415 }
1416
1417 pub async fn rebase_descendants_with_options(
1435 &mut self,
1436 immutable: &Arc<ResolvedRevsetExpression>,
1437 options: &RebaseOptions,
1438 mut progress: impl FnMut(Commit, RebasedCommit),
1439 ) -> BackendResult<()> {
1440 let roots = self.parent_mapping.keys().cloned().collect();
1441 self.transform_descendants_with_options(
1442 roots,
1443 immutable,
1444 &HashMap::new(),
1445 &options.rewrite_refs,
1446 async |rewriter| {
1447 if rewriter.parents_changed() {
1448 let old_commit = rewriter.old_commit().clone();
1449 let rebased_commit = rebase_commit_with_options(rewriter, options).await?;
1450 progress(old_commit, rebased_commit);
1451 }
1452 Ok(())
1453 },
1454 )
1455 .await?;
1456 self.parent_mapping.clear();
1457 Ok(())
1458 }
1459
1460 pub async fn rebase_descendants(&mut self) -> BackendResult<usize> {
1470 let mut num_rebased = 0;
1471 self.rebase_descendants_with_options(
1472 &RevsetExpression::none(),
1473 &RebaseOptions::default(),
1474 |_old_commit, _rebased_commit| {
1475 num_rebased += 1;
1476 },
1477 )
1478 .await?;
1479 Ok(num_rebased)
1480 }
1481
1482 pub async fn reparent_descendants(&mut self) -> BackendResult<usize> {
1489 let roots = self.parent_mapping.keys().cloned().collect_vec();
1490 let mut num_reparented = 0;
1491 self.transform_descendants(roots, async |rewriter| {
1492 if rewriter.parents_changed() {
1493 let builder = rewriter.reparent();
1494 builder.write().await?;
1495 num_reparented += 1;
1496 }
1497 Ok(())
1498 })
1499 .await?;
1500 self.parent_mapping.clear();
1501 Ok(num_reparented)
1502 }
1503
1504 pub fn set_wc_commit(
1505 &mut self,
1506 name: WorkspaceNameBuf,
1507 commit_id: CommitId,
1508 ) -> Result<(), RewriteRootCommit> {
1509 if &commit_id == self.store().root_commit_id() {
1510 return Err(RewriteRootCommit);
1511 }
1512 self.view_mut().set_wc_commit(name, commit_id);
1513 Ok(())
1514 }
1515
1516 pub async fn remove_wc_commit(&mut self, name: &WorkspaceName) -> Result<(), EditCommitError> {
1517 self.maybe_abandon_wc_commit(name).await?;
1518 self.view_mut().remove_wc_commit(name);
1519 Ok(())
1520 }
1521
1522 fn merge_wc_commit(
1525 &mut self,
1526 name: &WorkspaceName,
1527 base_id: Option<&CommitId>,
1528 other_id: Option<&CommitId>,
1529 ) {
1530 let view = self.view.get_mut();
1531 let self_id = view.get_wc_commit_id(name);
1532 let new_id = if let Some(resolved) =
1536 trivial_merge(&[self_id, base_id, other_id], SameChange::Accept)
1537 {
1538 resolved.cloned()
1539 } else if self_id.is_none() || other_id.is_none() {
1540 None
1543 } else {
1544 self_id.cloned()
1545 };
1546 match new_id {
1547 Some(id) => view.set_wc_commit(name.to_owned(), id),
1548 None => view.remove_wc_commit(name),
1549 }
1550 }
1551
1552 pub fn rename_workspace(
1553 &mut self,
1554 old_name: &WorkspaceName,
1555 new_name: WorkspaceNameBuf,
1556 ) -> Result<(), RenameWorkspaceError> {
1557 self.view_mut().rename_workspace(old_name, new_name)
1558 }
1559
1560 pub async fn check_out(
1561 &mut self,
1562 name: WorkspaceNameBuf,
1563 commit: &Commit,
1564 ) -> Result<Commit, CheckOutCommitError> {
1565 let wc_commit = self
1566 .new_commit(vec![commit.id().clone()], commit.tree())
1567 .write()
1568 .await?;
1569 self.edit(name, &wc_commit).await?;
1570 Ok(wc_commit)
1571 }
1572
1573 pub async fn edit(
1574 &mut self,
1575 name: WorkspaceNameBuf,
1576 commit: &Commit,
1577 ) -> Result<(), EditCommitError> {
1578 self.maybe_abandon_wc_commit(&name).await?;
1579 self.add_head(commit).await?;
1580 Ok(self.set_wc_commit(name, commit.id().clone())?)
1581 }
1582
1583 async fn maybe_abandon_wc_commit(
1584 &mut self,
1585 workspace_name: &WorkspaceName,
1586 ) -> Result<(), EditCommitError> {
1587 let is_commit_referenced = |view: &View, commit_id: &CommitId| -> bool {
1588 itertools::chain!(
1589 view.wc_commit_ids()
1590 .iter()
1591 .filter(|&(name, _)| name != workspace_name)
1592 .map(|(_, wc_id)| wc_id),
1593 view.local_bookmarks()
1594 .flat_map(|(_, target)| target.added_ids()),
1595 view.local_tags().flat_map(|(_, target)| target.added_ids()),
1596 )
1597 .any(|id| id == commit_id)
1598 };
1599
1600 let maybe_wc_commit_id = self
1601 .view
1602 .with_ref(|v| v.get_wc_commit_id(workspace_name).cloned());
1603 if let Some(wc_commit_id) = maybe_wc_commit_id {
1604 let wc_commit = self
1605 .store()
1606 .get_commit_async(&wc_commit_id)
1607 .await
1608 .map_err(EditCommitError::WorkingCopyCommitNotFound)?;
1609 if wc_commit.is_discardable(self).await?
1610 && self
1611 .view
1612 .with_ref(|v| !is_commit_referenced(v, wc_commit.id()))
1613 && self.view().heads().contains(wc_commit.id())
1614 {
1615 self.record_abandoned_commit(&wc_commit);
1619 }
1620 }
1621
1622 Ok(())
1623 }
1624
1625 fn enforce_view_invariants(&self, view: &mut View) {
1626 let view = view.store_view_mut();
1627 let root_commit_id = self.store().root_commit_id();
1628 if view.head_ids.is_empty() {
1629 view.head_ids.insert(root_commit_id.clone());
1630 } else if view.head_ids.len() > 1 {
1631 view.head_ids.remove(root_commit_id);
1634 view.head_ids = self
1638 .index()
1639 .heads(&mut view.head_ids.iter())
1640 .unwrap()
1641 .into_iter()
1642 .collect();
1643 }
1644 assert!(!view.head_ids.is_empty());
1645 }
1646
1647 pub async fn add_head(&mut self, head: &Commit) -> BackendResult<()> {
1650 self.add_heads(slice::from_ref(head)).await
1651 }
1652
1653 pub async fn add_heads(&mut self, heads: &[Commit]) -> BackendResult<()> {
1660 let current_heads = self.view.get_mut().heads();
1661 match heads {
1665 [] => {}
1666 [head]
1667 if head
1668 .parent_ids()
1669 .iter()
1670 .all(|parent_id| current_heads.contains(parent_id)) =>
1671 {
1672 self.index
1673 .add_commit(head)
1674 .await
1675 .map_err(|err| BackendError::Other(err.into()))?;
1677 self.view.get_mut().add_head(head.id());
1678 for parent_id in head.parent_ids() {
1679 self.view.get_mut().remove_head(parent_id);
1680 }
1681 }
1682 _ => {
1683 self.index_commits(heads).await?;
1684 for head in heads {
1685 self.view.get_mut().add_head(head.id());
1686 }
1687 self.view.mark_dirty();
1688 }
1689 }
1690 Ok(())
1691 }
1692
1693 pub fn remove_head(&mut self, head: &CommitId) {
1694 self.view_mut().remove_head(head);
1695 self.view.mark_dirty();
1696 }
1697
1698 pub async fn index_commits(&mut self, heads: &[Commit]) -> BackendResult<Vec<Commit>> {
1701 let missing_commits = dag_walk_async::topo_order_reverse_ord(
1702 heads
1703 .iter()
1704 .filter_map(|commit| match self.index().has_id(commit.id()) {
1705 Ok(false) => Some(Ok(CommitByCommitterTimestamp(commit.clone()))),
1706 Ok(true) => None,
1707 Err(err) => Some(Err(BackendError::Other(err.into()))),
1709 }),
1710 |CommitByCommitterTimestamp(commit)| commit.id().clone(),
1711 async |CommitByCommitterTimestamp(commit)| {
1712 stream::iter(commit.parent_ids())
1713 .filter_map(async |id| match self.index().has_id(id) {
1714 Ok(false) => Some(
1715 self.store()
1716 .get_commit_async(id)
1717 .await
1718 .map(CommitByCommitterTimestamp),
1719 ),
1720 Ok(true) => None,
1721 Err(err) => Some(Err(BackendError::Other(err.into()))),
1723 })
1724 .collect::<Vec<_>>()
1725 .await
1726 },
1727 |_| panic!("graph has cycle"),
1728 )
1729 .await?;
1730 for CommitByCommitterTimestamp(missing_commit) in missing_commits.iter().rev() {
1731 self.index
1732 .add_commit(missing_commit)
1733 .await
1734 .map_err(|err| BackendError::Other(err.into()))?;
1736 }
1737 let indexed_commits = missing_commits
1738 .into_iter()
1739 .map(|CommitByCommitterTimestamp(commit)| commit)
1740 .collect();
1741 Ok(indexed_commits)
1742 }
1743
1744 pub fn get_local_bookmark(&self, name: &RefName) -> RefTarget {
1745 self.view.with_ref(|v| v.get_local_bookmark(name).clone())
1746 }
1747
1748 pub fn set_local_bookmark_target(&mut self, name: &RefName, target: RefTarget) {
1749 let view = self.view_mut();
1750 for id in target.added_ids() {
1751 view.add_head(id);
1752 }
1753 view.set_local_bookmark_target(name, target);
1754 self.view.mark_dirty();
1755 }
1756
1757 pub fn merge_local_bookmark(
1758 &mut self,
1759 name: &RefName,
1760 base_target: &RefTarget,
1761 other_target: &RefTarget,
1762 ) -> IndexResult<()> {
1763 let view = self.view.get_mut();
1764 let index = self.index.as_index();
1765 let self_target = view.get_local_bookmark(name);
1766 let new_target = merge_ref_targets(index, self_target, base_target, other_target)?;
1767 self.set_local_bookmark_target(name, new_target);
1768 Ok(())
1769 }
1770
1771 pub fn get_remote_bookmark(&self, symbol: RemoteRefSymbol<'_>) -> RemoteRef {
1772 self.view
1773 .with_ref(|v| v.get_remote_bookmark(symbol).clone())
1774 }
1775
1776 pub fn set_remote_bookmark(&mut self, symbol: RemoteRefSymbol<'_>, remote_ref: RemoteRef) {
1777 self.view_mut().set_remote_bookmark(symbol, remote_ref);
1778 }
1779
1780 fn merge_remote_bookmark(
1781 &mut self,
1782 symbol: RemoteRefSymbol<'_>,
1783 base_ref: &RemoteRef,
1784 other_ref: &RemoteRef,
1785 ) -> IndexResult<()> {
1786 let view = self.view.get_mut();
1787 let index = self.index.as_index();
1788 let self_ref = view.get_remote_bookmark(symbol);
1789 let new_ref = merge_remote_refs(index, self_ref, base_ref, other_ref)?;
1790 view.set_remote_bookmark(symbol, new_ref);
1791 Ok(())
1792 }
1793
1794 pub fn track_remote_bookmark(&mut self, symbol: RemoteRefSymbol<'_>) -> IndexResult<()> {
1797 let mut remote_ref = self.get_remote_bookmark(symbol);
1798 let base_target = remote_ref.tracked_target();
1799 self.merge_local_bookmark(symbol.name, base_target, &remote_ref.target)?;
1800 remote_ref.state = RemoteRefState::Tracked;
1801 self.set_remote_bookmark(symbol, remote_ref);
1802 Ok(())
1803 }
1804
1805 pub fn untrack_remote_bookmark(&mut self, symbol: RemoteRefSymbol<'_>) {
1807 let mut remote_ref = self.get_remote_bookmark(symbol);
1808 remote_ref.state = RemoteRefState::New;
1809 self.set_remote_bookmark(symbol, remote_ref);
1810 }
1811
1812 pub fn ensure_remote(&mut self, remote_name: &RemoteName) {
1813 self.view_mut().ensure_remote(remote_name);
1814 }
1815
1816 pub fn remove_remote(&mut self, remote_name: &RemoteName) {
1817 self.view_mut().remove_remote(remote_name);
1818 }
1819
1820 pub fn rename_remote(&mut self, old: &RemoteName, new: &RemoteName) {
1821 self.view_mut().rename_remote(old, new);
1822 }
1823
1824 pub fn get_local_tag(&self, name: &RefName) -> RefTarget {
1825 self.view.with_ref(|v| v.get_local_tag(name).clone())
1826 }
1827
1828 pub fn set_local_tag_target(&mut self, name: &RefName, target: RefTarget) {
1829 self.view_mut().set_local_tag_target(name, target);
1830 }
1831
1832 pub fn merge_local_tag(
1833 &mut self,
1834 name: &RefName,
1835 base_target: &RefTarget,
1836 other_target: &RefTarget,
1837 ) -> IndexResult<()> {
1838 let view = self.view.get_mut();
1839 let index = self.index.as_index();
1840 let self_target = view.get_local_tag(name);
1841 let new_target = merge_ref_targets(index, self_target, base_target, other_target)?;
1842 view.set_local_tag_target(name, new_target);
1843 Ok(())
1844 }
1845
1846 pub fn get_remote_tag(&self, symbol: RemoteRefSymbol<'_>) -> RemoteRef {
1847 self.view.with_ref(|v| v.get_remote_tag(symbol).clone())
1848 }
1849
1850 pub fn set_remote_tag(&mut self, symbol: RemoteRefSymbol<'_>, remote_ref: RemoteRef) {
1851 self.view_mut().set_remote_tag(symbol, remote_ref);
1852 }
1853
1854 fn merge_remote_tag(
1855 &mut self,
1856 symbol: RemoteRefSymbol<'_>,
1857 base_ref: &RemoteRef,
1858 other_ref: &RemoteRef,
1859 ) -> IndexResult<()> {
1860 let view = self.view.get_mut();
1861 let index = self.index.as_index();
1862 let self_ref = view.get_remote_tag(symbol);
1863 let new_ref = merge_remote_refs(index, self_ref, base_ref, other_ref)?;
1864 view.set_remote_tag(symbol, new_ref);
1865 Ok(())
1866 }
1867
1868 pub fn get_git_ref(&self, name: &GitRefName) -> RefTarget {
1869 self.view.with_ref(|v| v.get_git_ref(name).clone())
1870 }
1871
1872 pub fn set_git_ref_target(&mut self, name: &GitRefName, target: RefTarget) {
1873 self.view_mut().set_git_ref_target(name, target);
1874 }
1875
1876 fn merge_git_ref(
1877 &mut self,
1878 name: &GitRefName,
1879 base_target: &RefTarget,
1880 other_target: &RefTarget,
1881 ) -> IndexResult<()> {
1882 let view = self.view.get_mut();
1883 let index = self.index.as_index();
1884 let self_target = view.get_git_ref(name);
1885 let new_target = merge_ref_targets(index, self_target, base_target, other_target)?;
1886 view.set_git_ref_target(name, new_target);
1887 Ok(())
1888 }
1889
1890 pub fn git_head(&self) -> RefTarget {
1891 self.view.with_ref(|v| v.git_head().clone())
1892 }
1893
1894 pub fn set_git_head_target(&mut self, target: RefTarget) {
1895 self.view_mut().set_git_head_target(target);
1896 }
1897
1898 pub fn set_view(&mut self, data: op_store::View) {
1899 self.view_mut().set_view(data);
1900 self.view.mark_dirty();
1901 }
1902
1903 pub async fn merge(
1904 &mut self,
1905 base_repo: &ReadonlyRepo,
1906 other_repo: &ReadonlyRepo,
1907 ) -> Result<(), RepoLoaderError> {
1908 self.index.merge_in(base_repo.readonly_index())?;
1913 self.index.merge_in(other_repo.readonly_index())?;
1914
1915 self.view.ensure_clean(|v| self.enforce_view_invariants(v));
1916 self.merge_view(&base_repo.view, &other_repo.view).await?;
1917 self.view.mark_dirty();
1918 Ok(())
1919 }
1920
1921 pub fn merge_index(&mut self, other_repo: &ReadonlyRepo) -> IndexResult<()> {
1922 self.index.merge_in(other_repo.readonly_index())
1923 }
1924
1925 async fn merge_view(&mut self, base: &View, other: &View) -> Result<(), RepoLoaderError> {
1926 let changed_wc_commits = diff_named_commit_ids(base.wc_commit_ids(), other.wc_commit_ids());
1927 for (name, (base_id, other_id)) in changed_wc_commits {
1928 self.merge_wc_commit(name, base_id, other_id);
1929 }
1930
1931 let base_heads = base.heads().iter().cloned().collect_vec();
1932 let own_heads = self.view().heads().iter().cloned().collect_vec();
1933 let other_heads = other.heads().iter().cloned().collect_vec();
1934
1935 if self.is_backed_by_default_index() {
1942 self.record_rewrites(&base_heads, &own_heads).await?;
1943 self.record_rewrites(&base_heads, &other_heads).await?;
1944 } else {
1947 for removed_head in base.heads().difference(other.heads()) {
1948 self.view_mut().remove_head(removed_head);
1949 }
1950 }
1951 for added_head in other.heads().difference(base.heads()) {
1952 self.view_mut().add_head(added_head);
1953 }
1954
1955 let changed_local_bookmarks =
1956 diff_named_ref_targets(base.local_bookmarks(), other.local_bookmarks());
1957 for (name, (base_target, other_target)) in changed_local_bookmarks {
1958 self.merge_local_bookmark(name, base_target, other_target)?;
1959 }
1960
1961 let changed_local_tags = diff_named_ref_targets(base.local_tags(), other.local_tags());
1962 for (name, (base_target, other_target)) in changed_local_tags {
1963 self.merge_local_tag(name, base_target, other_target)?;
1964 }
1965
1966 let changed_git_refs = diff_named_ref_targets(base.git_refs(), other.git_refs());
1967 for (name, (base_target, other_target)) in changed_git_refs {
1968 self.merge_git_ref(name, base_target, other_target)?;
1969 }
1970
1971 let changed_remote_bookmarks =
1972 diff_named_remote_refs(base.all_remote_bookmarks(), other.all_remote_bookmarks());
1973 for (symbol, (base_ref, other_ref)) in changed_remote_bookmarks {
1974 self.merge_remote_bookmark(symbol, base_ref, other_ref)?;
1975 }
1976
1977 let changed_remote_tags =
1978 diff_named_remote_refs(base.all_remote_tags(), other.all_remote_tags());
1979 for (symbol, (base_ref, other_ref)) in changed_remote_tags {
1980 self.merge_remote_tag(symbol, base_ref, other_ref)?;
1981 }
1982
1983 let new_git_head_target = merge_ref_targets(
1984 self.index(),
1985 self.view().git_head(),
1986 base.git_head(),
1987 other.git_head(),
1988 )?;
1989 self.set_git_head_target(new_git_head_target);
1990
1991 Ok(())
1992 }
1993
1994 async fn record_rewrites(
1997 &mut self,
1998 old_heads: &[CommitId],
1999 new_heads: &[CommitId],
2000 ) -> BackendResult<()> {
2001 let mut removed_changes: HashMap<ChangeId, Vec<CommitId>> = HashMap::new();
2002 {
2003 let mut stream = revset::walk_revs(self, old_heads, new_heads)
2004 .map_err(|err| err.into_backend_error())?
2005 .commit_change_ids();
2006 while let Some((commit_id, change_id)) = stream
2007 .try_next()
2008 .await
2009 .map_err(|err| err.into_backend_error())?
2010 {
2011 removed_changes
2012 .entry(change_id)
2013 .or_default()
2014 .push(commit_id);
2015 }
2016 }
2017 if removed_changes.is_empty() {
2018 return Ok(());
2019 }
2020
2021 let mut rewritten_changes = HashSet::new();
2022 let mut rewritten_commits: HashMap<CommitId, Vec<CommitId>> = HashMap::new();
2023 {
2024 let mut stream = revset::walk_revs(self, new_heads, old_heads)
2025 .map_err(|err| err.into_backend_error())?
2026 .commit_change_ids();
2027 while let Some((commit_id, change_id)) = stream
2028 .try_next()
2029 .await
2030 .map_err(|err| err.into_backend_error())?
2031 {
2032 if let Some(old_commits) = removed_changes.get(&change_id) {
2033 for old_commit in old_commits {
2034 rewritten_commits
2035 .entry(old_commit.clone())
2036 .or_default()
2037 .push(commit_id.clone());
2038 }
2039 }
2040 rewritten_changes.insert(change_id);
2041 }
2042 }
2043 for (old_commit, new_commits) in rewritten_commits {
2044 if new_commits.len() == 1 {
2045 self.set_rewritten_commit(
2046 old_commit.clone(),
2047 new_commits.into_iter().next().unwrap(),
2048 );
2049 } else {
2050 self.set_divergent_rewrite(old_commit.clone(), new_commits);
2051 }
2052 }
2053
2054 for (change_id, removed_commit_ids) in &removed_changes {
2055 if !rewritten_changes.contains(change_id) {
2056 for id in removed_commit_ids {
2057 let commit = self.store().get_commit_async(id).await?;
2058 self.record_abandoned_commit(&commit);
2059 }
2060 }
2061 }
2062
2063 Ok(())
2064 }
2065}
2066
2067impl Repo for MutableRepo {
2068 fn base_repo(&self) -> &ReadonlyRepo {
2069 &self.base_repo
2070 }
2071
2072 fn store(&self) -> &Arc<Store> {
2073 self.base_repo.store()
2074 }
2075
2076 fn op_store(&self) -> &Arc<dyn OpStore> {
2077 self.base_repo.op_store()
2078 }
2079
2080 fn index(&self) -> &dyn Index {
2081 self.index.as_index()
2082 }
2083
2084 fn view(&self) -> &View {
2085 self.view
2086 .get_or_ensure_clean(|v| self.enforce_view_invariants(v))
2087 }
2088
2089 fn submodule_store(&self) -> &Arc<dyn SubmoduleStore> {
2090 self.base_repo.submodule_store()
2091 }
2092
2093 fn resolve_change_id_prefix(
2094 &self,
2095 prefix: &HexPrefix,
2096 ) -> IndexResult<PrefixResolution<ResolvedChangeTargets>> {
2097 let change_id_index = self.index.change_id_index(&mut self.view().heads().iter());
2098 change_id_index.resolve_prefix(prefix)
2099 }
2100
2101 fn shortest_unique_change_id_prefix_len(&self, target_id: &ChangeId) -> IndexResult<usize> {
2102 let change_id_index = self.index.change_id_index(&mut self.view().heads().iter());
2103 change_id_index.shortest_unique_prefix_len(target_id)
2104 }
2105}
2106
2107#[derive(Debug, Error)]
2109#[error("Cannot rewrite the root commit")]
2110pub struct RewriteRootCommit;
2111
2112#[derive(Debug, Error)]
2114pub enum EditCommitError {
2115 #[error("Current working-copy commit not found")]
2116 WorkingCopyCommitNotFound(#[source] BackendError),
2117 #[error(transparent)]
2118 RewriteRootCommit(#[from] RewriteRootCommit),
2119 #[error(transparent)]
2120 BackendError(#[from] BackendError),
2121}
2122
2123#[derive(Debug, Error)]
2125pub enum CheckOutCommitError {
2126 #[error("Failed to create new working-copy commit")]
2127 CreateCommit(#[from] BackendError),
2128 #[error("Failed to edit commit")]
2129 EditCommit(#[from] EditCommitError),
2130}
2131
2132mod dirty_cell {
2133 use std::cell::OnceCell;
2134 use std::cell::RefCell;
2135
2136 #[derive(Clone, Debug)]
2140 pub struct DirtyCell<T> {
2141 clean: OnceCell<Box<T>>,
2144 dirty: RefCell<Option<Box<T>>>,
2145 }
2146
2147 impl<T> DirtyCell<T> {
2148 pub fn with_clean(value: T) -> Self {
2149 Self {
2150 clean: OnceCell::from(Box::new(value)),
2151 dirty: RefCell::new(None),
2152 }
2153 }
2154
2155 pub fn get_or_ensure_clean(&self, f: impl FnOnce(&mut T)) -> &T {
2156 self.clean.get_or_init(|| {
2157 let mut value = self.dirty.borrow_mut().take().unwrap();
2159 f(&mut value);
2160 value
2161 })
2162 }
2163
2164 pub fn ensure_clean(&self, f: impl FnOnce(&mut T)) {
2165 self.get_or_ensure_clean(f);
2166 }
2167
2168 pub fn into_inner(self) -> T {
2169 *self
2170 .clean
2171 .into_inner()
2172 .or_else(|| self.dirty.into_inner())
2173 .unwrap()
2174 }
2175
2176 pub fn with_ref<R>(&self, f: impl FnOnce(&T) -> R) -> R {
2177 if let Some(value) = self.clean.get() {
2178 f(value)
2179 } else {
2180 f(self.dirty.borrow().as_ref().unwrap())
2181 }
2182 }
2183
2184 pub fn get_mut(&mut self) -> &mut T {
2185 self.clean
2186 .get_mut()
2187 .or_else(|| self.dirty.get_mut().as_mut())
2188 .unwrap()
2189 }
2190
2191 pub fn mark_dirty(&mut self) {
2192 if let Some(value) = self.clean.take() {
2193 *self.dirty.get_mut() = Some(value);
2194 }
2195 }
2196 }
2197}