6169 lines · 227.7 KB · Rust
RawDownload
// Copyright 2021 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. #![expect(missing_docs)] use std::any::Any;use std::collections::HashMap;use std::collections::hash_map;use std::convert::Infallible;use std::fmt;use std::ops::ControlFlow;use std::ops::Range;use std::sync::Arc;use std::sync::LazyLock; use itertools::Itertools as _;use thiserror::Error; use crate::backend::BackendError;use crate::backend::ChangeId;use crate::backend::CommitId;use crate::commit::Commit;use crate::dsl_util;use crate::dsl_util::collect_similar;use crate::fileset;use crate::fileset::FilesetDiagnostics;use crate::fileset::FilesetExpression;use crate::graph::GraphNode;use crate::id_prefix::IdPrefixContext;use crate::id_prefix::IdPrefixIndex;use crate::object_id::HexPrefix;use crate::object_id::PrefixResolution;use crate::op_store::RefTarget;use crate::op_store::RemoteRefState;use crate::op_walk;use crate::ref_name::RemoteRefSymbol;use crate::ref_name::RemoteRefSymbolBuf;use crate::ref_name::WorkspaceName;use crate::ref_name::WorkspaceNameBuf;use crate::repo::ReadonlyRepo;use crate::repo::Repo;use crate::repo::RepoLoaderError;use crate::repo_path::RepoPathUiConverter;use crate::revset_parser;pub use crate::revset_parser::BinaryOp;pub use crate::revset_parser::ExpressionKind;pub use crate::revset_parser::ExpressionNode;pub use crate::revset_parser::FunctionCallNode;pub use crate::revset_parser::RevsetAliasesMap;pub use crate::revset_parser::RevsetDiagnostics;pub use crate::revset_parser::RevsetParseError;pub use crate::revset_parser::RevsetParseErrorKind;pub use crate::revset_parser::UnaryOp;pub use crate::revset_parser::expect_literal;pub use crate::revset_parser::parse_program;pub use crate::revset_parser::parse_symbol;use crate::store::Store;use crate::str_util::StringPattern;use crate::time_util::DatePattern;use crate::time_util::DatePatternContext; /// Error occurred during symbol resolution.#[derive(Debug, Error)]pub enum RevsetResolutionError {    #[error("Revision `{name}` doesn't exist")]    NoSuchRevision {        name: String,        candidates: Vec<String>,    },    #[error("Workspace `{}` doesn't have a working-copy commit", name.as_symbol())]    WorkspaceMissingWorkingCopy { name: WorkspaceNameBuf },    #[error("An empty string is not a valid revision")]    EmptyString,    #[error("Commit ID prefix `{0}` is ambiguous")]    AmbiguousCommitIdPrefix(String),    #[error("Change ID prefix `{0}` is ambiguous")]    AmbiguousChangeIdPrefix(String),    #[error("Change ID `{symbol}` is divergent")]    DivergentChangeId {        symbol: String,        targets: Vec<CommitId>,    },    #[error("Name `{symbol}` is conflicted")]    ConflictedRef {        kind: &'static str,        symbol: String,        targets: Vec<CommitId>,    },    #[error("Unexpected error from commit backend")]    Backend(#[source] BackendError),    #[error(transparent)]    Other(#[from] Box<dyn std::error::Error + Send + Sync>),} /// Error occurred during revset evaluation.#[derive(Debug, Error)]pub enum RevsetEvaluationError {    #[error("Unexpected error from commit backend")]    Backend(#[from] BackendError),    #[error(transparent)]    Other(Box<dyn std::error::Error + Send + Sync>),} impl RevsetEvaluationError {    // TODO: Create a higher-level error instead of putting non-BackendErrors in a    // BackendError    pub fn into_backend_error(self) -> BackendError {        match self {            Self::Backend(err) => err,            Self::Other(err) => BackendError::Other(err),        }    }} // assumes index has less than u64::MAX entries.pub const GENERATION_RANGE_FULL: Range<u64> = 0..u64::MAX;pub const GENERATION_RANGE_EMPTY: Range<u64> = 0..0; pub const PARENTS_RANGE_FULL: Range<u32> = 0..u32::MAX; /// Global flag applied to the entire expression.////// The core revset engine doesn't use this value. It's up to caller to/// interpret it to change the evaluation behavior.#[derive(Clone, Copy, Debug, Eq, PartialEq)]pub enum RevsetModifier {    /// Expression can be evaluated to multiple revisions even if a single    /// revision is expected by default.    All,} /// Symbol or function to be resolved to `CommitId`s.#[derive(Clone, Debug)]pub enum RevsetCommitRef {    WorkingCopy(WorkspaceNameBuf),    WorkingCopies,    Symbol(String),    RemoteSymbol(RemoteRefSymbolBuf),    ChangeId(HexPrefix),    CommitId(HexPrefix),    Bookmarks(StringPattern),    RemoteBookmarks {        bookmark_pattern: StringPattern,        remote_pattern: StringPattern,        remote_ref_state: Option<RemoteRefState>,    },    Tags(StringPattern),    GitRefs,    GitHead,} /// A custom revset filter expression, defined by an extension.pub trait RevsetFilterExtension: std::fmt::Debug + Any + Send + Sync {    /// Returns true iff this filter matches the specified commit.    fn matches_commit(&self, commit: &Commit) -> bool;} impl dyn RevsetFilterExtension {    /// Returns reference of the implementation type.    pub fn downcast_ref<T: RevsetFilterExtension>(&self) -> Option<&T> {        (self as &dyn Any).downcast_ref()    }} #[derive(Clone, Debug)]pub enum RevsetFilterPredicate {    /// Commits with number of parents in the range.    ParentCount(Range<u32>),    /// Commits with description matching the pattern.    Description(StringPattern),    /// Commits with first line of the description matching the pattern.    Subject(StringPattern),    /// Commits with author name matching the pattern.    AuthorName(StringPattern),    /// Commits with author email matching the pattern.    AuthorEmail(StringPattern),    /// Commits with author dates matching the given date pattern.    AuthorDate(DatePattern),    /// Commits with committer name matching the pattern.    CommitterName(StringPattern),    /// Commits with committer email matching the pattern.    CommitterEmail(StringPattern),    /// Commits with committer dates matching the given date pattern.    CommitterDate(DatePattern),    /// Commits modifying the paths specified by the fileset.    File(FilesetExpression),    /// Commits containing diffs matching the `text` pattern within the `files`.    DiffContains {        text: StringPattern,        files: FilesetExpression,    },    /// Commits with conflicts    HasConflict,    /// Commits that are cryptographically signed.    Signed,    /// Custom predicates provided by extensions    Extension(Arc<dyn RevsetFilterExtension>),} mod private {    /// Defines [`RevsetExpression`] variants depending on resolution state.    pub trait ExpressionState {        type CommitRef: Clone;        type Operation: Clone;    }     // Not constructible because these state types just define associated types.    #[derive(Debug)]    pub enum UserExpressionState {}    #[derive(Debug)]    pub enum ResolvedExpressionState {}} use private::ExpressionState;use private::ResolvedExpressionState;use private::UserExpressionState; impl ExpressionState for UserExpressionState {    type CommitRef = RevsetCommitRef;    type Operation = String;} impl ExpressionState for ResolvedExpressionState {    type CommitRef = Infallible;    type Operation = Infallible;} /// [`RevsetExpression`] that may contain unresolved commit refs.pub type UserRevsetExpression = RevsetExpression<UserExpressionState>;/// [`RevsetExpression`] that never contains unresolved commit refs.pub type ResolvedRevsetExpression = RevsetExpression<ResolvedExpressionState>; /// Tree of revset expressions describing DAG operations.////// Use [`UserRevsetExpression`] or [`ResolvedRevsetExpression`] to construct/// expression of that state.#[derive(Clone, Debug)]pub enum RevsetExpression<St: ExpressionState> {    None,    All,    VisibleHeads,    /// Visible heads and all referenced commits within the current expression    /// scope. Used as the default of `Range`/`DagRange` heads.    VisibleHeadsOrReferenced,    Root,    Commits(Vec<CommitId>),    CommitRef(St::CommitRef),    Ancestors {        heads: Arc<Self>,        generation: Range<u64>,        parents_range: Range<u32>,    },    Descendants {        roots: Arc<Self>,        generation: Range<u64>,    },    // Commits that are ancestors of "heads" but not ancestors of "roots"    Range {        roots: Arc<Self>,        heads: Arc<Self>,        generation: Range<u64>,        // Parents range is only used for traversing heads, not roots        parents_range: Range<u32>,    },    // Commits that are descendants of "roots" and ancestors of "heads"    DagRange {        roots: Arc<Self>,        heads: Arc<Self>,        // TODO: maybe add generation_from_roots/heads?    },    // Commits reachable from "sources" within "domain"    Reachable {        sources: Arc<Self>,        domain: Arc<Self>,    },    Heads(Arc<Self>),    /// Heads of the set of commits which are ancestors of `heads` but are not    /// ancestors of `roots`, and which also are contained in `filter`.    HeadsRange {        roots: Arc<Self>,        heads: Arc<Self>,        parents_range: Range<u32>,        filter: Arc<Self>,    },    Roots(Arc<Self>),    ForkPoint(Arc<Self>),    Bisect(Arc<Self>),    HasSize {        candidates: Arc<Self>,        count: usize,    },    Latest {        candidates: Arc<Self>,        count: usize,    },    Filter(RevsetFilterPredicate),    /// Marker for subtree that should be intersected as filter.    AsFilter(Arc<Self>),    /// Resolves symbols and visibility at the specified operation.    AtOperation {        operation: St::Operation,        candidates: Arc<Self>,    },    /// Makes `All` include the commits and their ancestors in addition to the    /// visible heads.    WithinReference {        candidates: Arc<Self>,        /// Commits explicitly referenced within the scope.        commits: Vec<CommitId>,    },    /// Resolves visibility within the specified repo state.    WithinVisibility {        candidates: Arc<Self>,        /// Copy of `repo.view().heads()` at the operation.        visible_heads: Vec<CommitId>,    },    Coalesce(Arc<Self>, Arc<Self>),    Present(Arc<Self>),    NotIn(Arc<Self>),    Union(Arc<Self>, Arc<Self>),    Intersection(Arc<Self>, Arc<Self>),    Difference(Arc<Self>, Arc<Self>),} // Leaf expression that never contains unresolved commit refs, which can be// either user or resolved expressionimpl<St: ExpressionState> RevsetExpression<St> {    pub fn none() -> Arc<Self> {        Arc::new(Self::None)    }     /// Ancestors of visible heads and all referenced commits within the current    /// expression scope, which may include hidden commits.    pub fn all() -> Arc<Self> {        Arc::new(Self::All)    }     pub fn visible_heads() -> Arc<Self> {        Arc::new(Self::VisibleHeads)    }     fn visible_heads_or_referenced() -> Arc<Self> {        Arc::new(Self::VisibleHeadsOrReferenced)    }     pub fn root() -> Arc<Self> {        Arc::new(Self::Root)    }     pub fn commit(commit_id: CommitId) -> Arc<Self> {        Self::commits(vec![commit_id])    }     pub fn commits(commit_ids: Vec<CommitId>) -> Arc<Self> {        Arc::new(Self::Commits(commit_ids))    }     pub fn filter(predicate: RevsetFilterPredicate) -> Arc<Self> {        Arc::new(Self::Filter(predicate))    }     /// Find any empty commits.    pub fn is_empty() -> Arc<Self> {        Self::filter(RevsetFilterPredicate::File(FilesetExpression::all())).negated()    }} // Leaf expression that represents unresolved commit refsimpl<St: ExpressionState<CommitRef = RevsetCommitRef>> RevsetExpression<St> {    pub fn working_copy(name: WorkspaceNameBuf) -> Arc<Self> {        Arc::new(Self::CommitRef(RevsetCommitRef::WorkingCopy(name)))    }     pub fn working_copies() -> Arc<Self> {        Arc::new(Self::CommitRef(RevsetCommitRef::WorkingCopies))    }     pub fn symbol(value: String) -> Arc<Self> {        Arc::new(Self::CommitRef(RevsetCommitRef::Symbol(value)))    }     pub fn remote_symbol(value: RemoteRefSymbolBuf) -> Arc<Self> {        let commit_ref = RevsetCommitRef::RemoteSymbol(value);        Arc::new(Self::CommitRef(commit_ref))    }     pub fn change_id_prefix(prefix: HexPrefix) -> Arc<Self> {        let commit_ref = RevsetCommitRef::ChangeId(prefix);        Arc::new(Self::CommitRef(commit_ref))    }     pub fn commit_id_prefix(prefix: HexPrefix) -> Arc<Self> {        let commit_ref = RevsetCommitRef::CommitId(prefix);        Arc::new(Self::CommitRef(commit_ref))    }     pub fn bookmarks(pattern: StringPattern) -> Arc<Self> {        Arc::new(Self::CommitRef(RevsetCommitRef::Bookmarks(pattern)))    }     pub fn remote_bookmarks(        bookmark_pattern: StringPattern,        remote_pattern: StringPattern,        remote_ref_state: Option<RemoteRefState>,    ) -> Arc<Self> {        Arc::new(Self::CommitRef(RevsetCommitRef::RemoteBookmarks {            bookmark_pattern,            remote_pattern,            remote_ref_state,        }))    }     pub fn tags(pattern: StringPattern) -> Arc<Self> {        Arc::new(Self::CommitRef(RevsetCommitRef::Tags(pattern)))    }     pub fn git_refs() -> Arc<Self> {        Arc::new(Self::CommitRef(RevsetCommitRef::GitRefs))    }     pub fn git_head() -> Arc<Self> {        Arc::new(Self::CommitRef(RevsetCommitRef::GitHead))    }} // Compound expressionimpl<St: ExpressionState> RevsetExpression<St> {    pub fn latest(self: &Arc<Self>, count: usize) -> Arc<Self> {        Arc::new(Self::Latest {            candidates: self.clone(),            count,        })    }     /// Commits in `self` that don't have descendants in `self`.    pub fn heads(self: &Arc<Self>) -> Arc<Self> {        Arc::new(Self::Heads(self.clone()))    }     /// Commits in `self` that don't have ancestors in `self`.    pub fn roots(self: &Arc<Self>) -> Arc<Self> {        Arc::new(Self::Roots(self.clone()))    }     /// Parents of `self`.    pub fn parents(self: &Arc<Self>) -> Arc<Self> {        self.ancestors_at(1)    }     /// Ancestors of `self`, including `self`.    pub fn ancestors(self: &Arc<Self>) -> Arc<Self> {        self.ancestors_range(GENERATION_RANGE_FULL)    }     /// Ancestors of `self` at an offset of `generation` behind `self`.    /// The `generation` offset is zero-based starting from `self`.    pub fn ancestors_at(self: &Arc<Self>, generation: u64) -> Arc<Self> {        self.ancestors_range(generation..generation.saturating_add(1))    }     /// Ancestors of `self` in the given range.    pub fn ancestors_range(self: &Arc<Self>, generation_range: Range<u64>) -> Arc<Self> {        Arc::new(Self::Ancestors {            heads: self.clone(),            generation: generation_range,            parents_range: PARENTS_RANGE_FULL,        })    }     /// First-parent ancestors of `self`, including `self`.    pub fn first_ancestors(self: &Arc<Self>) -> Arc<Self> {        self.first_ancestors_range(GENERATION_RANGE_FULL)    }     /// First-parent ancestors of `self` at an offset of `generation` behind    /// `self`. The `generation` offset is zero-based starting from `self`.    pub fn first_ancestors_at(self: &Arc<Self>, generation: u64) -> Arc<Self> {        self.first_ancestors_range(generation..generation.saturating_add(1))    }     /// First-parent ancestors of `self` in the given range.    pub fn first_ancestors_range(self: &Arc<Self>, generation_range: Range<u64>) -> Arc<Self> {        Arc::new(Self::Ancestors {            heads: self.clone(),            generation: generation_range,            parents_range: 0..1,        })    } 

Lines 1–500 of 6169.