1945 lines · 70.7 KB · Rust
RawDownload
// Copyright 2020 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. #![allow(missing_docs)] use std::collections::hash_map::Entry;use std::collections::HashMap;use std::collections::HashSet;use std::fmt::Debug;use std::fmt::Formatter;use std::fs;use std::path::Path;use std::slice;use std::sync::Arc; use itertools::Itertools as _;use once_cell::sync::OnceCell;use thiserror::Error;use tracing::instrument; use self::dirty_cell::DirtyCell;use crate::backend::Backend;use crate::backend::BackendError;use crate::backend::BackendInitError;use crate::backend::BackendLoadError;use crate::backend::BackendResult;use crate::backend::ChangeId;use crate::backend::CommitId;use crate::backend::MergedTreeId;use crate::commit::Commit;use crate::commit::CommitByCommitterTimestamp;use crate::commit_builder::CommitBuilder;use crate::commit_builder::DetachedCommitBuilder;use crate::dag_walk;use crate::default_index::DefaultIndexStore;use crate::default_index::DefaultMutableIndex;use crate::default_submodule_store::DefaultSubmoduleStore;use crate::file_util::IoResultExt as _;use crate::file_util::PathError;use crate::index::ChangeIdIndex;use crate::index::Index;use crate::index::IndexReadError;use crate::index::IndexStore;use crate::index::MutableIndex;use crate::index::ReadonlyIndex;use crate::merge::MergeBuilder;use crate::object_id::HexPrefix;use crate::object_id::ObjectId as _;use crate::object_id::PrefixResolution;use crate::op_heads_store;use crate::op_heads_store::OpHeadResolutionError;use crate::op_heads_store::OpHeadsStore;use crate::op_heads_store::OpHeadsStoreError;use crate::op_store;use crate::op_store::OpStore;use crate::op_store::OpStoreError;use crate::op_store::OpStoreResult;use crate::op_store::OperationId;use crate::op_store::RefTarget;use crate::op_store::RemoteRef;use crate::op_store::RemoteRefState;use crate::op_store::RootOperationData;use crate::operation::Operation;use crate::ref_name::GitRefName;use crate::ref_name::RefName;use crate::ref_name::RemoteName;use crate::ref_name::RemoteRefSymbol;use crate::ref_name::WorkspaceName;use crate::ref_name::WorkspaceNameBuf;use crate::refs::diff_named_ref_targets;use crate::refs::diff_named_remote_refs;use crate::refs::merge_ref_targets;use crate::refs::merge_remote_refs;use crate::revset;use crate::revset::RevsetExpression;use crate::revset::RevsetIteratorExt as _;use crate::rewrite::merge_commit_trees;use crate::rewrite::rebase_commit_with_options;use crate::rewrite::CommitRewriter;use crate::rewrite::RebaseOptions;use crate::rewrite::RebasedCommit;use crate::rewrite::RewriteRefsOptions;use crate::settings::UserSettings;use crate::signing::SignInitError;use crate::signing::Signer;use crate::simple_backend::SimpleBackend;use crate::simple_op_heads_store::SimpleOpHeadsStore;use crate::simple_op_store::SimpleOpStore;use crate::store::Store;use crate::submodule_store::SubmoduleStore;use crate::transaction::Transaction;use crate::view::RenameWorkspaceError;use crate::view::View; pub trait Repo {    /// Base repository that contains all committed data. Returns `self` if this    /// is a `ReadonlyRepo`,    fn base_repo(&self) -> &ReadonlyRepo;     fn store(&self) -> &Arc<Store>;     fn op_store(&self) -> &Arc<dyn OpStore>;     fn index(&self) -> &dyn Index;     fn view(&self) -> &View;     fn submodule_store(&self) -> &Arc<dyn SubmoduleStore>;     fn resolve_change_id(&self, change_id: &ChangeId) -> Option<Vec<CommitId>> {        // Replace this if we added more efficient lookup method.        let prefix = HexPrefix::from_bytes(change_id.as_bytes());        match self.resolve_change_id_prefix(&prefix) {            PrefixResolution::NoMatch => None,            PrefixResolution::SingleMatch(entries) => Some(entries),            PrefixResolution::AmbiguousMatch => panic!("complete change_id should be unambiguous"),        }    }     fn resolve_change_id_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<Vec<CommitId>>;     fn shortest_unique_change_id_prefix_len(&self, target_id_bytes: &ChangeId) -> usize;} pub struct ReadonlyRepo {    loader: RepoLoader,    operation: Operation,    index: Box<dyn ReadonlyIndex>,    change_id_index: OnceCell<Box<dyn ChangeIdIndex>>,    // TODO: This should eventually become part of the index and not be stored fully in memory.    view: View,} impl Debug for ReadonlyRepo {    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {        f.debug_struct("ReadonlyRepo")            .field("store", &self.loader.store)            .finish_non_exhaustive()    }} #[derive(Error, Debug)]pub enum RepoInitError {    #[error(transparent)]    Backend(#[from] BackendInitError),    #[error(transparent)]    OpHeadsStore(#[from] OpHeadsStoreError),    #[error(transparent)]    Path(#[from] PathError),} impl ReadonlyRepo {    pub fn default_op_store_initializer() -> &'static OpStoreInitializer<'static> {        &|_settings, store_path, root_data| {            Ok(Box::new(SimpleOpStore::init(store_path, root_data)?))        }    }     pub fn default_op_heads_store_initializer() -> &'static OpHeadsStoreInitializer<'static> {        &|_settings, store_path| Ok(Box::new(SimpleOpHeadsStore::init(store_path)?))    }     pub fn default_index_store_initializer() -> &'static IndexStoreInitializer<'static> {        &|_settings, store_path| Ok(Box::new(DefaultIndexStore::init(store_path)?))    }     pub fn default_submodule_store_initializer() -> &'static SubmoduleStoreInitializer<'static> {        &|_settings, store_path| Ok(Box::new(DefaultSubmoduleStore::init(store_path)))    }     #[expect(clippy::too_many_arguments)]    pub fn init(        settings: &UserSettings,        repo_path: &Path,        backend_initializer: &BackendInitializer,        signer: Signer,        op_store_initializer: &OpStoreInitializer,        op_heads_store_initializer: &OpHeadsStoreInitializer,        index_store_initializer: &IndexStoreInitializer,        submodule_store_initializer: &SubmoduleStoreInitializer,    ) -> Result<Arc<ReadonlyRepo>, RepoInitError> {        let repo_path = dunce::canonicalize(repo_path).context(repo_path)?;         let store_path = repo_path.join("store");        fs::create_dir(&store_path).context(&store_path)?;        let backend = backend_initializer(settings, &store_path)?;        let backend_path = store_path.join("type");        fs::write(&backend_path, backend.name()).context(&backend_path)?;        let store = Store::new(backend, signer);         let op_store_path = repo_path.join("op_store");        fs::create_dir(&op_store_path).context(&op_store_path)?;        let root_op_data = RootOperationData {            root_commit_id: store.root_commit_id().clone(),        };        let op_store = op_store_initializer(settings, &op_store_path, root_op_data)?;        let op_store_type_path = op_store_path.join("type");        fs::write(&op_store_type_path, op_store.name()).context(&op_store_type_path)?;        let op_store: Arc<dyn OpStore> = Arc::from(op_store);         let op_heads_path = repo_path.join("op_heads");        fs::create_dir(&op_heads_path).context(&op_heads_path)?;        let op_heads_store = op_heads_store_initializer(settings, &op_heads_path)?;        let op_heads_type_path = op_heads_path.join("type");        fs::write(&op_heads_type_path, op_heads_store.name()).context(&op_heads_type_path)?;        op_heads_store.update_op_heads(&[], op_store.root_operation_id())?;        let op_heads_store: Arc<dyn OpHeadsStore> = Arc::from(op_heads_store);         let index_path = repo_path.join("index");        fs::create_dir(&index_path).context(&index_path)?;        let index_store = index_store_initializer(settings, &index_path)?;        let index_type_path = index_path.join("type");        fs::write(&index_type_path, index_store.name()).context(&index_type_path)?;        let index_store: Arc<dyn IndexStore> = Arc::from(index_store);         let submodule_store_path = repo_path.join("submodule_store");        fs::create_dir(&submodule_store_path).context(&submodule_store_path)?;        let submodule_store = submodule_store_initializer(settings, &submodule_store_path)?;        let submodule_store_type_path = submodule_store_path.join("type");        fs::write(&submodule_store_type_path, submodule_store.name())            .context(&submodule_store_type_path)?;        let submodule_store = Arc::from(submodule_store);         let loader = RepoLoader {            settings: settings.clone(),            store,            op_store,            op_heads_store,            index_store,            submodule_store,        };         let root_operation = loader.root_operation();        let root_view = root_operation.view().expect("failed to read root view");        assert!(!root_view.heads().is_empty());        let index = loader            .index_store            .get_index_at_op(&root_operation, &loader.store)            // If the root op index couldn't be read, the index backend wouldn't            // be initialized properly.            .map_err(|err| BackendInitError(err.into()))?;        Ok(Arc::new(ReadonlyRepo {            loader,            operation: root_operation,            index,            change_id_index: OnceCell::new(),            view: root_view,        }))    }     pub fn loader(&self) -> &RepoLoader {        &self.loader    }     pub fn op_id(&self) -> &OperationId {        self.operation.id()    }     pub fn operation(&self) -> &Operation {        &self.operation    }     pub fn view(&self) -> &View {        &self.view    }     pub fn readonly_index(&self) -> &dyn ReadonlyIndex {        self.index.as_ref()    }     fn change_id_index(&self) -> &dyn ChangeIdIndex {        self.change_id_index            .get_or_init(|| {                self.readonly_index()                    .change_id_index(&mut self.view().heads().iter())            })            .as_ref()    }     pub fn op_heads_store(&self) -> &Arc<dyn OpHeadsStore> {        self.loader.op_heads_store()    }     pub fn index_store(&self) -> &Arc<dyn IndexStore> {        self.loader.index_store()    }     pub fn settings(&self) -> &UserSettings {        self.loader.settings()    }     pub fn start_transaction(self: &Arc<ReadonlyRepo>) -> Transaction {        let mut_repo = MutableRepo::new(self.clone(), self.readonly_index(), &self.view);        Transaction::new(mut_repo, self.settings())    }     pub fn reload_at_head(&self) -> Result<Arc<ReadonlyRepo>, RepoLoaderError> {        self.loader().load_at_head()    }     #[instrument]    pub fn reload_at(&self, operation: &Operation) -> Result<Arc<ReadonlyRepo>, RepoLoaderError> {        self.loader().load_at(operation)    }} impl Repo for ReadonlyRepo {    fn base_repo(&self) -> &ReadonlyRepo {        self    }     fn store(&self) -> &Arc<Store> {        self.loader.store()    }     fn op_store(&self) -> &Arc<dyn OpStore> {        self.loader.op_store()    }     fn index(&self) -> &dyn Index {        self.readonly_index().as_index()    }     fn view(&self) -> &View {        &self.view    }     fn submodule_store(&self) -> &Arc<dyn SubmoduleStore> {        self.loader.submodule_store()    }     fn resolve_change_id_prefix(&self, prefix: &HexPrefix) -> PrefixResolution<Vec<CommitId>> {        self.change_id_index().resolve_prefix(prefix)    }     fn shortest_unique_change_id_prefix_len(&self, target_id: &ChangeId) -> usize {        self.change_id_index().shortest_unique_prefix_len(target_id)    }} pub type BackendInitializer<'a> =    dyn Fn(&UserSettings, &Path) -> Result<Box<dyn Backend>, BackendInitError> + 'a;#[rustfmt::skip] // auto-formatted line would exceed the maximum widthpub type OpStoreInitializer<'a> =    dyn Fn(&UserSettings, &Path, RootOperationData) -> Result<Box<dyn OpStore>, BackendInitError>    + 'a;pub type OpHeadsStoreInitializer<'a> =    dyn Fn(&UserSettings, &Path) -> Result<Box<dyn OpHeadsStore>, BackendInitError> + 'a;pub type IndexStoreInitializer<'a> =    dyn Fn(&UserSettings, &Path) -> Result<Box<dyn IndexStore>, BackendInitError> + 'a;pub type SubmoduleStoreInitializer<'a> =    dyn Fn(&UserSettings, &Path) -> Result<Box<dyn SubmoduleStore>, BackendInitError> + 'a; type BackendFactory =    Box<dyn Fn(&UserSettings, &Path) -> Result<Box<dyn Backend>, BackendLoadError>>;type OpStoreFactory = Box<    dyn Fn(&UserSettings, &Path, RootOperationData) -> Result<Box<dyn OpStore>, BackendLoadError>,>;type OpHeadsStoreFactory =    Box<dyn Fn(&UserSettings, &Path) -> Result<Box<dyn OpHeadsStore>, BackendLoadError>>;type IndexStoreFactory =    Box<dyn Fn(&UserSettings, &Path) -> Result<Box<dyn IndexStore>, BackendLoadError>>;type SubmoduleStoreFactory =    Box<dyn Fn(&UserSettings, &Path) -> Result<Box<dyn SubmoduleStore>, BackendLoadError>>; pub fn merge_factories_map<F>(base: &mut HashMap<String, F>, ext: HashMap<String, F>) {    for (name, factory) in ext {        match base.entry(name) {            Entry::Vacant(v) => {                v.insert(factory);            }            Entry::Occupied(o) => {                panic!("Conflicting factory definitions for '{}' factory", o.key())            }        }    }} pub struct StoreFactories {    backend_factories: HashMap<String, BackendFactory>,    op_store_factories: HashMap<String, OpStoreFactory>,    op_heads_store_factories: HashMap<String, OpHeadsStoreFactory>,    index_store_factories: HashMap<String, IndexStoreFactory>,    submodule_store_factories: HashMap<String, SubmoduleStoreFactory>,} impl Default for StoreFactories {    fn default() -> Self {        let mut factories = StoreFactories::empty();         // Backends        factories.add_backend(            SimpleBackend::name(),            Box::new(|_settings, store_path| Ok(Box::new(SimpleBackend::load(store_path)))),        );        #[cfg(feature = "git")]        factories.add_backend(            crate::git_backend::GitBackend::name(),            Box::new(|settings, store_path| {                Ok(Box::new(crate::git_backend::GitBackend::load(                    settings, store_path,                )?))            }),        );        #[cfg(feature = "testing")]        factories.add_backend(            crate::secret_backend::SecretBackend::name(),            Box::new(|settings, store_path| {                Ok(Box::new(crate::secret_backend::SecretBackend::load(                    settings, store_path,                )?))            }),        );         // OpStores        factories.add_op_store(            SimpleOpStore::name(),            Box::new(|_settings, store_path, root_data| {                Ok(Box::new(SimpleOpStore::load(store_path, root_data)))            }),        );         // OpHeadsStores        factories.add_op_heads_store(            SimpleOpHeadsStore::name(),            Box::new(|_settings, store_path| Ok(Box::new(SimpleOpHeadsStore::load(store_path)))),        );         // Index        factories.add_index_store(            DefaultIndexStore::name(),            Box::new(|_settings, store_path| Ok(Box::new(DefaultIndexStore::load(store_path)))),        );         // SubmoduleStores        factories.add_submodule_store(            DefaultSubmoduleStore::name(),            Box::new(|_settings, store_path| Ok(Box::new(DefaultSubmoduleStore::load(store_path)))),        );         factories    }} #[derive(Debug, Error)]pub enum StoreLoadError {    #[error("Unsupported {store} backend type '{store_type}'")]    UnsupportedType {        store: &'static str,        store_type: String,    },    #[error("Failed to read {store} backend type")]    ReadError {        store: &'static str,        source: PathError,    },    #[error(transparent)]    Backend(#[from] BackendLoadError),    #[error(transparent)]    Signing(#[from] SignInitError),} impl StoreFactories {    pub fn empty() -> Self {        StoreFactories {            backend_factories: HashMap::new(),            op_store_factories: HashMap::new(),            op_heads_store_factories: HashMap::new(),            index_store_factories: HashMap::new(),            submodule_store_factories: HashMap::new(),        }    }     pub fn merge(&mut self, ext: StoreFactories) {        let StoreFactories {            backend_factories,            op_store_factories,            op_heads_store_factories,            index_store_factories,            submodule_store_factories,        } = ext;         merge_factories_map(&mut self.backend_factories, backend_factories);        merge_factories_map(&mut self.op_store_factories, op_store_factories);        merge_factories_map(&mut self.op_heads_store_factories, op_heads_store_factories);        merge_factories_map(&mut self.index_store_factories, index_store_factories);        merge_factories_map(            &mut self.submodule_store_factories,            submodule_store_factories,

Lines 1–500 of 1945.