// 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. #![allow(missing_docs)] use std::any::Any;use std::collections::hash_map;use std::collections::HashMap;use std::convert::Infallible;use std::fmt;use std::ops::Range;use std::rc::Rc;use std::sync::Arc; use itertools::Itertools as _;use once_cell::sync::Lazy;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::dsl_util::AliasExpandError as _;use crate::fileset;use crate::fileset::FilesetDiagnostics;use crate::fileset::FilesetExpression;use crate::graph::GraphNode;use crate::hex_util::to_forward_hex;use crate::id_prefix::IdPrefixContext;use crate::id_prefix::IdPrefixIndex;use crate::object_id::HexPrefix;use crate::object_id::PrefixResolution;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::expect_literal;pub use crate::revset_parser::parse_program;pub use crate::revset_parser::parse_symbol;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;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("Unexpected error from store")] StoreError(#[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 store")] StoreError(#[from] BackendError), #[error(transparent)] Other(Box<dyn std::error::Error + Send + Sync>),} impl RevsetEvaluationError { pub fn expect_backend_error(self) -> BackendError { match self { Self::StoreError(err) => err, Self::Other(err) => panic!("Unexpected revset error: {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; /// 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), 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 { fn as_any(&self) -> &dyn Any; /// Returns true iff this filter matches the specified commit. fn matches_commit(&self, commit: &Commit) -> bool;} #[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, /// Custom predicates provided by extensions Extension(Rc<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, Root, Commits(Vec<CommitId>), CommitRef(St::CommitRef), Ancestors { heads: Rc<Self>, generation: Range<u64>, }, Descendants { roots: Rc<Self>, generation: Range<u64>, }, // Commits that are ancestors of "heads" but not ancestors of "roots" Range { roots: Rc<Self>, heads: Rc<Self>, generation: Range<u64>, }, // Commits that are descendants of "roots" and ancestors of "heads" DagRange { roots: Rc<Self>, heads: Rc<Self>, // TODO: maybe add generation_from_roots/heads? }, // Commits reachable from "sources" within "domain" Reachable { sources: Rc<Self>, domain: Rc<Self>, }, Heads(Rc<Self>), Roots(Rc<Self>), ForkPoint(Rc<Self>), Latest { candidates: Rc<Self>, count: usize, }, Filter(RevsetFilterPredicate), /// Marker for subtree that should be intersected as filter. AsFilter(Rc<Self>), /// Resolves symbols and visibility at the specified operation. AtOperation { operation: St::Operation, candidates: Rc<Self>, }, /// Resolves visibility within the specified repo state. WithinVisibility { candidates: Rc<Self>, /// Copy of `repo.view().heads()` at the operation. visible_heads: Vec<CommitId>, }, Coalesce(Rc<Self>, Rc<Self>), Present(Rc<Self>), NotIn(Rc<Self>), Union(Rc<Self>, Rc<Self>), Intersection(Rc<Self>, Rc<Self>), Difference(Rc<Self>, Rc<Self>),} // Leaf expression that never contains unresolved commit refs, which can be// either user or resolved expressionimpl<St: ExpressionState> RevsetExpression<St> { pub fn none() -> Rc<Self> { Rc::new(Self::None) } pub fn all() -> Rc<Self> { Rc::new(Self::All) } pub fn visible_heads() -> Rc<Self> { Rc::new(Self::VisibleHeads) } pub fn root() -> Rc<Self> { Rc::new(Self::Root) } pub fn commit(commit_id: CommitId) -> Rc<Self> { Self::commits(vec![commit_id]) } pub fn commits(commit_ids: Vec<CommitId>) -> Rc<Self> { Rc::new(Self::Commits(commit_ids)) } pub fn filter(predicate: RevsetFilterPredicate) -> Rc<Self> { Rc::new(Self::Filter(predicate)) } /// Find any empty commits. pub fn is_empty() -> Rc<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) -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::WorkingCopy(name))) } pub fn working_copies() -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::WorkingCopies)) } pub fn symbol(value: String) -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::Symbol(value))) } pub fn remote_symbol(value: RemoteRefSymbolBuf) -> Rc<Self> { let commit_ref = RevsetCommitRef::RemoteSymbol(value); Rc::new(Self::CommitRef(commit_ref)) } pub fn bookmarks(pattern: StringPattern) -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::Bookmarks(pattern))) } pub fn remote_bookmarks( bookmark_pattern: StringPattern, remote_pattern: StringPattern, remote_ref_state: Option<RemoteRefState>, ) -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::RemoteBookmarks { bookmark_pattern, remote_pattern, remote_ref_state, })) } pub fn tags(pattern: StringPattern) -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::Tags(pattern))) } pub fn git_refs() -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::GitRefs)) } pub fn git_head() -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::GitHead)) }} // Compound expressionimpl<St: ExpressionState> RevsetExpression<St> { pub fn latest(self: &Rc<Self>, count: usize) -> Rc<Self> { Rc::new(Self::Latest { candidates: self.clone(), count, }) } /// Commits in `self` that don't have descendants in `self`. pub fn heads(self: &Rc<Self>) -> Rc<Self> { Rc::new(Self::Heads(self.clone())) } /// Commits in `self` that don't have ancestors in `self`. pub fn roots(self: &Rc<Self>) -> Rc<Self> { Rc::new(Self::Roots(self.clone())) } /// Parents of `self`. pub fn parents(self: &Rc<Self>) -> Rc<Self> { self.ancestors_at(1) } /// Ancestors of `self`, including `self`. pub fn ancestors(self: &Rc<Self>) -> Rc<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: &Rc<Self>, generation: u64) -> Rc<Self> { self.ancestors_range(generation..(generation + 1)) } /// Ancestors of `self` in the given range. pub fn ancestors_range(self: &Rc<Self>, generation_range: Range<u64>) -> Rc<Self> { Rc::new(Self::Ancestors { heads: self.clone(), generation: generation_range, }) } /// Children of `self`. pub fn children(self: &Rc<Self>) -> Rc<Self> { self.descendants_at(1) } /// Descendants of `self`, including `self`. pub fn descendants(self: &Rc<Self>) -> Rc<Self> { self.descendants_range(GENERATION_RANGE_FULL) } /// Descendants of `self` at an offset of `generation` ahead of `self`. /// The `generation` offset is zero-based starting from `self`. pub fn descendants_at(self: &Rc<Self>, generation: u64) -> Rc<Self> { self.descendants_range(generation..(generation + 1)) } /// Descendants of `self` in the given range. pub fn descendants_range(self: &Rc<Self>, generation_range: Range<u64>) -> Rc<Self> { Rc::new(Self::Descendants { roots: self.clone(), generation: generation_range, }) } /// Fork point (best common ancestors) of `self`. pub fn fork_point(self: &Rc<Self>) -> Rc<Self> { Rc::new(Self::ForkPoint(self.clone())) } /// Filter all commits by `predicate` in `self`. pub fn filtered(self: &Rc<Self>, predicate: RevsetFilterPredicate) -> Rc<Self> { self.intersection(&Self::filter(predicate)) } /// Commits that are descendants of `self` and ancestors of `heads`, both /// inclusive. pub fn dag_range_to(self: &Rc<Self>, heads: &Rc<Self>) -> Rc<Self> { Rc::new(Self::DagRange { roots: self.clone(), heads: heads.clone(), }) } /// Connects any ancestors and descendants in the set by adding the commits /// between them. pub fn connected(self: &Rc<Self>) -> Rc<Self> { self.dag_range_to(self) } /// All commits within `domain` reachable from this set of commits, by /// traversing either parent or child edges. pub fn reachable(self: &Rc<Self>, domain: &Rc<Self>) -> Rc<Self> { Rc::new(Self::Reachable { sources: self.clone(), domain: domain.clone(), }) } /// Commits reachable from `heads` but not from `self`. pub fn range(self: &Rc<Self>, heads: &Rc<Self>) -> Rc<Self> { Rc::new(Self::Range { roots: self.clone(), heads: heads.clone(), generation: GENERATION_RANGE_FULL, }) } /// Suppresses name resolution error within `self`. pub fn present(self: &Rc<Self>) -> Rc<Self> { Rc::new(Self::Present(self.clone())) } /// Commits that are not in `self`, i.e. the complement of `self`. pub fn negated(self: &Rc<Self>) -> Rc<Self> { Rc::new(Self::NotIn(self.clone())) } /// Commits that are in `self` or in `other` (or both). pub fn union(self: &Rc<Self>, other: &Rc<Self>) -> Rc<Self> { Rc::new(Self::Union(self.clone(), other.clone())) } /// Commits that are in any of the `expressions`. pub fn union_all(expressions: &[Rc<Self>]) -> Rc<Self> { match expressions { [] => Self::none(),Lines 1–500 of 4319. Load more
// 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. #![allow(missing_docs)] use std::any::Any; use std::collections::hash_map; use std::collections::HashMap; use std::convert::Infallible; use std::fmt; use std::ops::Range; use std::rc::Rc; use std::sync::Arc; use itertools::Itertools as _; use once_cell::sync::Lazy; 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::dsl_util::AliasExpandError as _; use crate::fileset; use crate::fileset::FilesetDiagnostics; use crate::fileset::FilesetExpression; use crate::graph::GraphNode; use crate::hex_util::to_forward_hex; use crate::id_prefix::IdPrefixContext; use crate::id_prefix::IdPrefixIndex; use crate::object_id::HexPrefix; use crate::object_id::PrefixResolution; 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::expect_literal; pub use crate::revset_parser::parse_program; pub use crate::revset_parser::parse_symbol; 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; 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("Unexpected error from store")] StoreError(#[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 store")] StoreError(#[from] BackendError), #[error(transparent)] Other(Box<dyn std::error::Error + Send + Sync>), } impl RevsetEvaluationError { pub fn expect_backend_error(self) -> BackendError { match self { Self::StoreError(err) => err, Self::Other(err) => panic!("Unexpected revset error: {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; /// 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), 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 { fn as_any(&self) -> &dyn Any; /// Returns true iff this filter matches the specified commit. fn matches_commit(&self, commit: &Commit) -> bool; } #[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, /// Custom predicates provided by extensions Extension(Rc<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, Root, Commits(Vec<CommitId>), CommitRef(St::CommitRef), Ancestors { heads: Rc<Self>, generation: Range<u64>, }, Descendants { roots: Rc<Self>, generation: Range<u64>, }, // Commits that are ancestors of "heads" but not ancestors of "roots" Range { roots: Rc<Self>, heads: Rc<Self>, generation: Range<u64>, }, // Commits that are descendants of "roots" and ancestors of "heads" DagRange { roots: Rc<Self>, heads: Rc<Self>, // TODO: maybe add generation_from_roots/heads? }, // Commits reachable from "sources" within "domain" Reachable { sources: Rc<Self>, domain: Rc<Self>, }, Heads(Rc<Self>), Roots(Rc<Self>), ForkPoint(Rc<Self>), Latest { candidates: Rc<Self>, count: usize, }, Filter(RevsetFilterPredicate), /// Marker for subtree that should be intersected as filter. AsFilter(Rc<Self>), /// Resolves symbols and visibility at the specified operation. AtOperation { operation: St::Operation, candidates: Rc<Self>, }, /// Resolves visibility within the specified repo state. WithinVisibility { candidates: Rc<Self>, /// Copy of `repo.view().heads()` at the operation. visible_heads: Vec<CommitId>, }, Coalesce(Rc<Self>, Rc<Self>), Present(Rc<Self>), NotIn(Rc<Self>), Union(Rc<Self>, Rc<Self>), Intersection(Rc<Self>, Rc<Self>), Difference(Rc<Self>, Rc<Self>), } // Leaf expression that never contains unresolved commit refs, which can be // either user or resolved expression impl<St: ExpressionState> RevsetExpression<St> { pub fn none() -> Rc<Self> { Rc::new(Self::None) } pub fn all() -> Rc<Self> { Rc::new(Self::All) } pub fn visible_heads() -> Rc<Self> { Rc::new(Self::VisibleHeads) } pub fn root() -> Rc<Self> { Rc::new(Self::Root) } pub fn commit(commit_id: CommitId) -> Rc<Self> { Self::commits(vec![commit_id]) } pub fn commits(commit_ids: Vec<CommitId>) -> Rc<Self> { Rc::new(Self::Commits(commit_ids)) } pub fn filter(predicate: RevsetFilterPredicate) -> Rc<Self> { Rc::new(Self::Filter(predicate)) } /// Find any empty commits. pub fn is_empty() -> Rc<Self> { Self::filter(RevsetFilterPredicate::File(FilesetExpression::all())).negated() } } // Leaf expression that represents unresolved commit refs impl<St: ExpressionState<CommitRef = RevsetCommitRef>> RevsetExpression<St> { pub fn working_copy(name: WorkspaceNameBuf) -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::WorkingCopy(name))) } pub fn working_copies() -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::WorkingCopies)) } pub fn symbol(value: String) -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::Symbol(value))) } pub fn remote_symbol(value: RemoteRefSymbolBuf) -> Rc<Self> { let commit_ref = RevsetCommitRef::RemoteSymbol(value); Rc::new(Self::CommitRef(commit_ref)) } pub fn bookmarks(pattern: StringPattern) -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::Bookmarks(pattern))) } pub fn remote_bookmarks( bookmark_pattern: StringPattern, remote_pattern: StringPattern, remote_ref_state: Option<RemoteRefState>, ) -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::RemoteBookmarks { bookmark_pattern, remote_pattern, remote_ref_state, })) } pub fn tags(pattern: StringPattern) -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::Tags(pattern))) } pub fn git_refs() -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::GitRefs)) } pub fn git_head() -> Rc<Self> { Rc::new(Self::CommitRef(RevsetCommitRef::GitHead)) } } // Compound expression impl<St: ExpressionState> RevsetExpression<St> { pub fn latest(self: &Rc<Self>, count: usize) -> Rc<Self> { Rc::new(Self::Latest { candidates: self.clone(), count, }) } /// Commits in `self` that don't have descendants in `self`. pub fn heads(self: &Rc<Self>) -> Rc<Self> { Rc::new(Self::Heads(self.clone())) } /// Commits in `self` that don't have ancestors in `self`. pub fn roots(self: &Rc<Self>) -> Rc<Self> { Rc::new(Self::Roots(self.clone())) } /// Parents of `self`. pub fn parents(self: &Rc<Self>) -> Rc<Self> { self.ancestors_at(1) } /// Ancestors of `self`, including `self`. pub fn ancestors(self: &Rc<Self>) -> Rc<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: &Rc<Self>, generation: u64) -> Rc<Self> { self.ancestors_range(generation..(generation + 1)) } /// Ancestors of `self` in the given range. pub fn ancestors_range(self: &Rc<Self>, generation_range: Range<u64>) -> Rc<Self> { Rc::new(Self::Ancestors { heads: self.clone(), generation: generation_range, }) } /// Children of `self`. pub fn children(self: &Rc<Self>) -> Rc<Self> { self.descendants_at(1) } /// Descendants of `self`, including `self`. pub fn descendants(self: &Rc<Self>) -> Rc<Self> { self.descendants_range(GENERATION_RANGE_FULL) } /// Descendants of `self` at an offset of `generation` ahead of `self`. /// The `generation` offset is zero-based starting from `self`. pub fn descendants_at(self: &Rc<Self>, generation: u64) -> Rc<Self> { self.descendants_range(generation..(generation + 1)) } /// Descendants of `self` in the given range. pub fn descendants_range(self: &Rc<Self>, generation_range: Range<u64>) -> Rc<Self> { Rc::new(Self::Descendants { roots: self.clone(), generation: generation_range, }) } /// Fork point (best common ancestors) of `self`. pub fn fork_point(self: &Rc<Self>) -> Rc<Self> { Rc::new(Self::ForkPoint(self.clone())) } /// Filter all commits by `predicate` in `self`. pub fn filtered(self: &Rc<Self>, predicate: RevsetFilterPredicate) -> Rc<Self> { self.intersection(&Self::filter(predicate)) } /// Commits that are descendants of `self` and ancestors of `heads`, both /// inclusive. pub fn dag_range_to(self: &Rc<Self>, heads: &Rc<Self>) -> Rc<Self> { Rc::new(Self::DagRange { roots: self.clone(), heads: heads.clone(), }) } /// Connects any ancestors and descendants in the set by adding the commits /// between them. pub fn connected(self: &Rc<Self>) -> Rc<Self> { self.dag_range_to(self) } /// All commits within `domain` reachable from this set of commits, by /// traversing either parent or child edges. pub fn reachable(self: &Rc<Self>, domain: &Rc<Self>) -> Rc<Self> { Rc::new(Self::Reachable { sources: self.clone(), domain: domain.clone(), }) } /// Commits reachable from `heads` but not from `self`. pub fn range(self: &Rc<Self>, heads: &Rc<Self>) -> Rc<Self> { Rc::new(Self::Range { roots: self.clone(), heads: heads.clone(), generation: GENERATION_RANGE_FULL, }) } /// Suppresses name resolution error within `self`. pub fn present(self: &Rc<Self>) -> Rc<Self> { Rc::new(Self::Present(self.clone())) } /// Commits that are not in `self`, i.e. the complement of `self`. pub fn negated(self: &Rc<Self>) -> Rc<Self> { Rc::new(Self::NotIn(self.clone())) } /// Commits that are in `self` or in `other` (or both). pub fn union(self: &Rc<Self>, other: &Rc<Self>) -> Rc<Self> { Rc::new(Self::Union(self.clone(), other.clone())) } /// Commits that are in any of the `expressions`. pub fn union_all(expressions: &[Rc<Self>]) -> Rc<Self> { match expressions { [] => Self::none(),