mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-18 18:27:38 +00:00
revset: insert StringPattern enum to add support for other kind of matching
This commit is contained in:
parent
313670d3c2
commit
5b3c73dfc4
3 changed files with 236 additions and 126 deletions
|
@ -86,17 +86,17 @@ revsets (expressions) as arguments.
|
||||||
* `all()`: All visible commits in the repo.
|
* `all()`: All visible commits in the repo.
|
||||||
* `none()`: No commits. This function is rarely useful; it is provided for
|
* `none()`: No commits. This function is rarely useful; it is provided for
|
||||||
completeness.
|
completeness.
|
||||||
* `branches([needle])`: All local branch targets. If `needle` is specified,
|
* `branches([pattern])`: All local branch targets. If `pattern` is specified,
|
||||||
branches whose name contains the given string are selected. For example,
|
branches whose name contains the given string are selected. For example,
|
||||||
`branches(push)` would match the branches `push-123` and `repushed` but not
|
`branches(push)` would match the branches `push-123` and `repushed` but not
|
||||||
the branch `main`. If a branch is in a conflicted state, all its possible
|
the branch `main`. If a branch is in a conflicted state, all its possible
|
||||||
targets are included.
|
targets are included.
|
||||||
* `remote_branches([branch_needle[, [remote=]remote_needle]])`: All remote
|
* `remote_branches([branch_pattern[, [remote=]remote_pattern]])`: All remote
|
||||||
branch targets across all remotes. If just the `branch_needle` is specified,
|
branch targets across all remotes. If just the `branch_pattern` is specified,
|
||||||
branches whose name contains the given string across all remotes are
|
branches whose name contains the given string across all remotes are
|
||||||
selected. If both `branch_needle` and `remote_needle` are specified, the
|
selected. If both `branch_pattern` and `remote_pattern` are specified, the
|
||||||
selection is further restricted to just the remotes whose name contains
|
selection is further restricted to just the remotes whose name contains
|
||||||
`remote_needle`. For example, `remote_branches(push, ri)` would match the
|
`remote_pattern`. For example, `remote_branches(push, ri)` would match the
|
||||||
branches `push-123@origin` and `repushed@private` but not `push-123@upstream`
|
branches `push-123@origin` and `repushed@private` but not `push-123@upstream`
|
||||||
or `main@origin` or `main@upstream`. If a branch is in a conflicted state,
|
or `main@origin` or `main@upstream`. If a branch is in a conflicted state,
|
||||||
all its possible targets are included.
|
all its possible targets are included.
|
||||||
|
@ -118,13 +118,13 @@ revsets (expressions) as arguments.
|
||||||
* `latest(x[, count])`: Latest `count` commits in `x`, based on committer
|
* `latest(x[, count])`: Latest `count` commits in `x`, based on committer
|
||||||
timestamp. The default `count` is 1.
|
timestamp. The default `count` is 1.
|
||||||
* `merges()`: Merge commits.
|
* `merges()`: Merge commits.
|
||||||
* `description(needle)`: Commits with the given string in their
|
* `description(pattern)`: Commits with the given string in their
|
||||||
description.
|
description.
|
||||||
* `author(needle)`: Commits with the given string in the author's name or
|
* `author(pattern)`: Commits with the given string in the author's name or
|
||||||
email.
|
email.
|
||||||
* `mine()`: Commits where the author's email matches the email of the current
|
* `mine()`: Commits where the author's email matches the email of the current
|
||||||
user.
|
user.
|
||||||
* `committer(needle)`: Commits with the given string in the committer's
|
* `committer(pattern)`: Commits with the given string in the committer's
|
||||||
name or email.
|
name or email.
|
||||||
* `empty()`: Commits modifying no files. This also includes `merges()` without
|
* `empty()`: Commits modifying no files. This also includes `merges()` without
|
||||||
user modifications and `root`.
|
user modifications and `root`.
|
||||||
|
|
|
@ -831,33 +831,29 @@ fn build_predicate_fn<'index>(
|
||||||
let parent_count_range = parent_count_range.clone();
|
let parent_count_range = parent_count_range.clone();
|
||||||
pure_predicate_fn(move |entry| parent_count_range.contains(&entry.num_parents()))
|
pure_predicate_fn(move |entry| parent_count_range.contains(&entry.num_parents()))
|
||||||
}
|
}
|
||||||
RevsetFilterPredicate::Description(needle) => {
|
RevsetFilterPredicate::Description(pattern) => {
|
||||||
let needle = needle.clone();
|
let pattern = pattern.clone();
|
||||||
pure_predicate_fn(move |entry| {
|
pure_predicate_fn(move |entry| {
|
||||||
store
|
let commit = store.get_commit(&entry.commit_id()).unwrap();
|
||||||
.get_commit(&entry.commit_id())
|
pattern.matches(commit.description())
|
||||||
.unwrap()
|
|
||||||
.description()
|
|
||||||
.contains(needle.as_str())
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
RevsetFilterPredicate::Author(needle) => {
|
RevsetFilterPredicate::Author(pattern) => {
|
||||||
let needle = needle.clone();
|
let pattern = pattern.clone();
|
||||||
// TODO: Make these functions that take a needle to search for accept some
|
// TODO: Make these functions that take a needle to search for accept some
|
||||||
// syntax for specifying whether it's a regex and whether it's
|
// syntax for specifying whether it's a regex and whether it's
|
||||||
// case-sensitive.
|
// case-sensitive.
|
||||||
pure_predicate_fn(move |entry| {
|
pure_predicate_fn(move |entry| {
|
||||||
let commit = store.get_commit(&entry.commit_id()).unwrap();
|
let commit = store.get_commit(&entry.commit_id()).unwrap();
|
||||||
commit.author().name.contains(needle.as_str())
|
pattern.matches(&commit.author().name) || pattern.matches(&commit.author().email)
|
||||||
|| commit.author().email.contains(needle.as_str())
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
RevsetFilterPredicate::Committer(needle) => {
|
RevsetFilterPredicate::Committer(pattern) => {
|
||||||
let needle = needle.clone();
|
let pattern = pattern.clone();
|
||||||
pure_predicate_fn(move |entry| {
|
pure_predicate_fn(move |entry| {
|
||||||
let commit = store.get_commit(&entry.commit_id()).unwrap();
|
let commit = store.get_commit(&entry.commit_id()).unwrap();
|
||||||
commit.committer().name.contains(needle.as_str())
|
pattern.matches(&commit.committer().name)
|
||||||
|| commit.committer().email.contains(needle.as_str())
|
|| pattern.matches(&commit.committer().email)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
RevsetFilterPredicate::File(paths) => {
|
RevsetFilterPredicate::File(paths) => {
|
||||||
|
|
|
@ -208,15 +208,37 @@ impl error::Error for RevsetParseError {
|
||||||
pub const GENERATION_RANGE_FULL: Range<u64> = 0..u64::MAX;
|
pub const GENERATION_RANGE_FULL: Range<u64> = 0..u64::MAX;
|
||||||
pub const GENERATION_RANGE_EMPTY: Range<u64> = 0..0;
|
pub const GENERATION_RANGE_EMPTY: Range<u64> = 0..0;
|
||||||
|
|
||||||
|
/// Pattern to be tested against string property like commit description or
|
||||||
|
/// branch name.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum StringPattern {
|
||||||
|
/// Matches strings that contain `substring`.
|
||||||
|
Substring(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StringPattern {
|
||||||
|
/// Pattern that matches any string.
|
||||||
|
pub fn everything() -> Self {
|
||||||
|
StringPattern::Substring(String::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if this pattern matches the `haystack`.
|
||||||
|
pub fn matches(&self, haystack: &str) -> bool {
|
||||||
|
match self {
|
||||||
|
StringPattern::Substring(needle) => haystack.contains(needle),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Symbol or function to be resolved to `CommitId`s.
|
/// Symbol or function to be resolved to `CommitId`s.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum RevsetCommitRef {
|
pub enum RevsetCommitRef {
|
||||||
Symbol(String),
|
Symbol(String),
|
||||||
VisibleHeads,
|
VisibleHeads,
|
||||||
Branches(String),
|
Branches(StringPattern),
|
||||||
RemoteBranches {
|
RemoteBranches {
|
||||||
branch_needle: String,
|
branch_pattern: StringPattern,
|
||||||
remote_needle: String,
|
remote_pattern: StringPattern,
|
||||||
},
|
},
|
||||||
Tags,
|
Tags,
|
||||||
GitRefs,
|
GitRefs,
|
||||||
|
@ -228,11 +250,11 @@ pub enum RevsetFilterPredicate {
|
||||||
/// Commits with number of parents in the range.
|
/// Commits with number of parents in the range.
|
||||||
ParentCount(Range<u32>),
|
ParentCount(Range<u32>),
|
||||||
/// Commits with description containing the needle.
|
/// Commits with description containing the needle.
|
||||||
Description(String),
|
Description(StringPattern),
|
||||||
/// Commits with author's name or email containing the needle.
|
/// Commits with author's name or email containing the needle.
|
||||||
Author(String),
|
Author(StringPattern),
|
||||||
/// Commits with committer's name or email containing the needle.
|
/// Commits with committer's name or email containing the needle.
|
||||||
Committer(String),
|
Committer(StringPattern),
|
||||||
/// Commits modifying the paths specified by the pattern.
|
/// Commits modifying the paths specified by the pattern.
|
||||||
File(Option<Vec<RepoPath>>), // TODO: embed matcher expression?
|
File(Option<Vec<RepoPath>>), // TODO: embed matcher expression?
|
||||||
/// Commits with conflicts
|
/// Commits with conflicts
|
||||||
|
@ -309,17 +331,20 @@ impl RevsetExpression {
|
||||||
Rc::new(RevsetExpression::CommitRef(RevsetCommitRef::VisibleHeads))
|
Rc::new(RevsetExpression::CommitRef(RevsetCommitRef::VisibleHeads))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn branches(needle: String) -> Rc<RevsetExpression> {
|
pub fn branches(pattern: StringPattern) -> Rc<RevsetExpression> {
|
||||||
Rc::new(RevsetExpression::CommitRef(RevsetCommitRef::Branches(
|
Rc::new(RevsetExpression::CommitRef(RevsetCommitRef::Branches(
|
||||||
needle,
|
pattern,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remote_branches(branch_needle: String, remote_needle: String) -> Rc<RevsetExpression> {
|
pub fn remote_branches(
|
||||||
|
branch_pattern: StringPattern,
|
||||||
|
remote_pattern: StringPattern,
|
||||||
|
) -> Rc<RevsetExpression> {
|
||||||
Rc::new(RevsetExpression::CommitRef(
|
Rc::new(RevsetExpression::CommitRef(
|
||||||
RevsetCommitRef::RemoteBranches {
|
RevsetCommitRef::RemoteBranches {
|
||||||
branch_needle,
|
branch_pattern,
|
||||||
remote_needle,
|
remote_pattern,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -986,29 +1011,29 @@ static BUILTIN_FUNCTION_MAP: Lazy<HashMap<&'static str, RevsetFunction>> = Lazy:
|
||||||
});
|
});
|
||||||
map.insert("branches", |name, arguments_pair, state| {
|
map.insert("branches", |name, arguments_pair, state| {
|
||||||
let ([], [opt_arg]) = expect_arguments(name, arguments_pair)?;
|
let ([], [opt_arg]) = expect_arguments(name, arguments_pair)?;
|
||||||
let needle = if let Some(arg) = opt_arg {
|
let pattern = if let Some(arg) = opt_arg {
|
||||||
parse_function_argument_to_string(name, arg, state)?
|
parse_function_argument_to_string_pattern(name, arg, state)?
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
StringPattern::everything()
|
||||||
};
|
};
|
||||||
Ok(RevsetExpression::branches(needle))
|
Ok(RevsetExpression::branches(pattern))
|
||||||
});
|
});
|
||||||
map.insert("remote_branches", |name, arguments_pair, state| {
|
map.insert("remote_branches", |name, arguments_pair, state| {
|
||||||
let ([], [branch_opt_arg, remote_opt_arg]) =
|
let ([], [branch_opt_arg, remote_opt_arg]) =
|
||||||
expect_named_arguments(name, &["", "remote"], arguments_pair)?;
|
expect_named_arguments(name, &["", "remote"], arguments_pair)?;
|
||||||
let branch_needle = if let Some(branch_arg) = branch_opt_arg {
|
let branch_pattern = if let Some(branch_arg) = branch_opt_arg {
|
||||||
parse_function_argument_to_string(name, branch_arg, state)?
|
parse_function_argument_to_string_pattern(name, branch_arg, state)?
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
StringPattern::everything()
|
||||||
};
|
};
|
||||||
let remote_needle = if let Some(remote_arg) = remote_opt_arg {
|
let remote_pattern = if let Some(remote_arg) = remote_opt_arg {
|
||||||
parse_function_argument_to_string(name, remote_arg, state)?
|
parse_function_argument_to_string_pattern(name, remote_arg, state)?
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
StringPattern::everything()
|
||||||
};
|
};
|
||||||
Ok(RevsetExpression::remote_branches(
|
Ok(RevsetExpression::remote_branches(
|
||||||
branch_needle,
|
branch_pattern,
|
||||||
remote_needle,
|
remote_pattern,
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
map.insert("tags", |name, arguments_pair, _state| {
|
map.insert("tags", |name, arguments_pair, _state| {
|
||||||
|
@ -1041,29 +1066,30 @@ static BUILTIN_FUNCTION_MAP: Lazy<HashMap<&'static str, RevsetFunction>> = Lazy:
|
||||||
});
|
});
|
||||||
map.insert("description", |name, arguments_pair, state| {
|
map.insert("description", |name, arguments_pair, state| {
|
||||||
let arg = expect_one_argument(name, arguments_pair)?;
|
let arg = expect_one_argument(name, arguments_pair)?;
|
||||||
let needle = parse_function_argument_to_string(name, arg, state)?;
|
let pattern = parse_function_argument_to_string_pattern(name, arg, state)?;
|
||||||
Ok(RevsetExpression::filter(
|
Ok(RevsetExpression::filter(
|
||||||
RevsetFilterPredicate::Description(needle),
|
RevsetFilterPredicate::Description(pattern),
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
map.insert("author", |name, arguments_pair, state| {
|
map.insert("author", |name, arguments_pair, state| {
|
||||||
let arg = expect_one_argument(name, arguments_pair)?;
|
let arg = expect_one_argument(name, arguments_pair)?;
|
||||||
let needle = parse_function_argument_to_string(name, arg, state)?;
|
let pattern = parse_function_argument_to_string_pattern(name, arg, state)?;
|
||||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::Author(
|
Ok(RevsetExpression::filter(RevsetFilterPredicate::Author(
|
||||||
needle,
|
pattern,
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
map.insert("mine", |name, arguments_pair, state| {
|
map.insert("mine", |name, arguments_pair, state| {
|
||||||
expect_no_arguments(name, arguments_pair)?;
|
expect_no_arguments(name, arguments_pair)?;
|
||||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::Author(
|
Ok(RevsetExpression::filter(RevsetFilterPredicate::Author(
|
||||||
state.user_email.to_owned(),
|
// TODO: use exact match
|
||||||
|
StringPattern::Substring(state.user_email.to_owned()),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
map.insert("committer", |name, arguments_pair, state| {
|
map.insert("committer", |name, arguments_pair, state| {
|
||||||
let arg = expect_one_argument(name, arguments_pair)?;
|
let arg = expect_one_argument(name, arguments_pair)?;
|
||||||
let needle = parse_function_argument_to_string(name, arg, state)?;
|
let pattern = parse_function_argument_to_string_pattern(name, arg, state)?;
|
||||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::Committer(
|
Ok(RevsetExpression::filter(RevsetFilterPredicate::Committer(
|
||||||
needle,
|
pattern,
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
map.insert("empty", |name, arguments_pair, _state| {
|
map.insert("empty", |name, arguments_pair, _state| {
|
||||||
|
@ -1249,6 +1275,15 @@ fn parse_function_argument_to_string(
|
||||||
parse_function_argument_as_literal("string", name, pair, state)
|
parse_function_argument_as_literal("string", name, pair, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_function_argument_to_string_pattern(
|
||||||
|
name: &str,
|
||||||
|
pair: Pair<Rule>,
|
||||||
|
state: ParseState,
|
||||||
|
) -> Result<StringPattern, RevsetParseError> {
|
||||||
|
let needle = parse_function_argument_as_literal("string", name, pair, state)?;
|
||||||
|
Ok(StringPattern::Substring(needle))
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_function_argument_as_literal<T: FromStr>(
|
fn parse_function_argument_as_literal<T: FromStr>(
|
||||||
type_name: &str,
|
type_name: &str,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
@ -1941,10 +1976,10 @@ fn resolve_commit_ref(
|
||||||
match commit_ref {
|
match commit_ref {
|
||||||
RevsetCommitRef::Symbol(symbol) => symbol_resolver.resolve_symbol(symbol),
|
RevsetCommitRef::Symbol(symbol) => symbol_resolver.resolve_symbol(symbol),
|
||||||
RevsetCommitRef::VisibleHeads => Ok(repo.view().heads().iter().cloned().collect_vec()),
|
RevsetCommitRef::VisibleHeads => Ok(repo.view().heads().iter().cloned().collect_vec()),
|
||||||
RevsetCommitRef::Branches(needle) => {
|
RevsetCommitRef::Branches(pattern) => {
|
||||||
let mut commit_ids = vec![];
|
let mut commit_ids = vec![];
|
||||||
for (branch_name, branch_target) in repo.view().branches() {
|
for (branch_name, branch_target) in repo.view().branches() {
|
||||||
if !branch_name.contains(needle) {
|
if !pattern.matches(branch_name) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
commit_ids.extend(branch_target.local_target.added_ids().cloned());
|
commit_ids.extend(branch_target.local_target.added_ids().cloned());
|
||||||
|
@ -1952,16 +1987,16 @@ fn resolve_commit_ref(
|
||||||
Ok(commit_ids)
|
Ok(commit_ids)
|
||||||
}
|
}
|
||||||
RevsetCommitRef::RemoteBranches {
|
RevsetCommitRef::RemoteBranches {
|
||||||
branch_needle,
|
branch_pattern,
|
||||||
remote_needle,
|
remote_pattern,
|
||||||
} => {
|
} => {
|
||||||
let mut commit_ids = vec![];
|
let mut commit_ids = vec![];
|
||||||
for (branch_name, branch_target) in repo.view().branches() {
|
for (branch_name, branch_target) in repo.view().branches() {
|
||||||
if !branch_name.contains(branch_needle) {
|
if !branch_pattern.matches(branch_name) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (remote_name, remote_target) in branch_target.remote_targets.iter() {
|
for (remote_name, remote_target) in branch_target.remote_targets.iter() {
|
||||||
if remote_name.contains(remote_needle) {
|
if remote_pattern.matches(remote_name) {
|
||||||
commit_ids.extend(remote_target.added_ids().cloned());
|
commit_ids.extend(remote_target.added_ids().cloned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2544,16 +2579,16 @@ mod tests {
|
||||||
// Space is allowed around infix operators and function arguments
|
// Space is allowed around infix operators and function arguments
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(" description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) "),
|
parse(" description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) "),
|
||||||
Ok(
|
Ok(RevsetExpression::filter(RevsetFilterPredicate::Description(
|
||||||
RevsetExpression::filter(RevsetFilterPredicate::Description("arg1".to_string()))
|
StringPattern::Substring("arg1".to_string())
|
||||||
.minus(&RevsetExpression::filter(RevsetFilterPredicate::File(
|
))
|
||||||
Some(vec![
|
.minus(&RevsetExpression::filter(RevsetFilterPredicate::File(
|
||||||
RepoPath::from_internal_string("arg1"),
|
Some(vec![
|
||||||
RepoPath::from_internal_string("arg2"),
|
RepoPath::from_internal_string("arg1"),
|
||||||
])
|
RepoPath::from_internal_string("arg2"),
|
||||||
)))
|
])
|
||||||
.minus(&RevsetExpression::visible_heads())
|
)))
|
||||||
)
|
.minus(&RevsetExpression::visible_heads()))
|
||||||
);
|
);
|
||||||
// Space is allowed around keyword arguments
|
// Space is allowed around keyword arguments
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -2695,13 +2730,13 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(r#"description("")"#),
|
parse(r#"description("")"#),
|
||||||
Ok(RevsetExpression::filter(
|
Ok(RevsetExpression::filter(
|
||||||
RevsetFilterPredicate::Description("".to_string())
|
RevsetFilterPredicate::Description(StringPattern::Substring("".to_string()))
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse("description(foo)"),
|
parse("description(foo)"),
|
||||||
Ok(RevsetExpression::filter(
|
Ok(RevsetExpression::filter(
|
||||||
RevsetFilterPredicate::Description("foo".to_string())
|
RevsetFilterPredicate::Description(StringPattern::Substring("foo".to_string()))
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -2714,20 +2749,20 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse("description((foo))"),
|
parse("description((foo))"),
|
||||||
Ok(RevsetExpression::filter(
|
Ok(RevsetExpression::filter(
|
||||||
RevsetFilterPredicate::Description("foo".to_string())
|
RevsetFilterPredicate::Description(StringPattern::Substring("foo".to_string()))
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse("description(\"(foo)\")"),
|
parse("description(\"(foo)\")"),
|
||||||
Ok(RevsetExpression::filter(
|
Ok(RevsetExpression::filter(
|
||||||
RevsetFilterPredicate::Description("(foo)".to_string())
|
RevsetFilterPredicate::Description(StringPattern::Substring("(foo)".to_string()))
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
assert!(parse("mine(foo)").is_err());
|
assert!(parse("mine(foo)").is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse("mine()"),
|
parse("mine()"),
|
||||||
Ok(RevsetExpression::filter(RevsetFilterPredicate::Author(
|
Ok(RevsetExpression::filter(RevsetFilterPredicate::Author(
|
||||||
"test.user@example.com".to_string()
|
StringPattern::Substring("test.user@example.com".to_string())
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -2960,42 +2995,44 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("parents(branches() & all())").unwrap()),
|
optimize(parse("parents(branches() & all())").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).parents()
|
RevsetExpression::branches(StringPattern::everything()).parents()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("children(branches() & all())").unwrap()),
|
optimize(parse("children(branches() & all())").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).children()
|
RevsetExpression::branches(StringPattern::everything()).children()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("ancestors(branches() & all())").unwrap()),
|
optimize(parse("ancestors(branches() & all())").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).ancestors()
|
RevsetExpression::branches(StringPattern::everything()).ancestors()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("descendants(branches() & all())").unwrap()),
|
optimize(parse("descendants(branches() & all())").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).descendants()
|
RevsetExpression::branches(StringPattern::everything()).descendants()
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("(branches() & all())..(all() & tags())").unwrap()),
|
optimize(parse("(branches() & all())..(all() & tags())").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).range(&RevsetExpression::tags())
|
RevsetExpression::branches(StringPattern::everything())
|
||||||
|
.range(&RevsetExpression::tags())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("(branches() & all()):(all() & tags())").unwrap()),
|
optimize(parse("(branches() & all()):(all() & tags())").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).dag_range_to(&RevsetExpression::tags())
|
RevsetExpression::branches(StringPattern::everything())
|
||||||
|
.dag_range_to(&RevsetExpression::tags())
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("heads(branches() & all())").unwrap()),
|
optimize(parse("heads(branches() & all())").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).heads()
|
RevsetExpression::branches(StringPattern::everything()).heads()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("roots(branches() & all())").unwrap()),
|
optimize(parse("roots(branches() & all())").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).roots()
|
RevsetExpression::branches(StringPattern::everything()).roots()
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("latest(branches() & all(), 2)").unwrap()),
|
optimize(parse("latest(branches() & all(), 2)").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).latest(2)
|
RevsetExpression::branches(StringPattern::everything()).latest(2)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -3008,25 +3045,28 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("present(branches() & all())").unwrap()),
|
optimize(parse("present(branches() & all())").unwrap()),
|
||||||
Rc::new(RevsetExpression::Present(RevsetExpression::branches(
|
Rc::new(RevsetExpression::Present(RevsetExpression::branches(
|
||||||
"".to_owned()
|
StringPattern::everything()
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("~branches() & all()").unwrap()),
|
optimize(parse("~branches() & all()").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).negated()
|
RevsetExpression::branches(StringPattern::everything()).negated()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("(branches() & all()) | (all() & tags())").unwrap()),
|
optimize(parse("(branches() & all()) | (all() & tags())").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).union(&RevsetExpression::tags())
|
RevsetExpression::branches(StringPattern::everything())
|
||||||
|
.union(&RevsetExpression::tags())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("(branches() & all()) & (all() & tags())").unwrap()),
|
optimize(parse("(branches() & all()) & (all() & tags())").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).intersection(&RevsetExpression::tags())
|
RevsetExpression::branches(StringPattern::everything())
|
||||||
|
.intersection(&RevsetExpression::tags())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
optimize(parse("(branches() & all()) ~ (all() & tags())").unwrap()),
|
optimize(parse("(branches() & all()) ~ (all() & tags())").unwrap()),
|
||||||
RevsetExpression::branches("".to_owned()).minus(&RevsetExpression::tags())
|
RevsetExpression::branches(StringPattern::everything())
|
||||||
|
.minus(&RevsetExpression::tags())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3059,7 +3099,7 @@ mod tests {
|
||||||
let optimized = optimize(parsed.clone());
|
let optimized = optimize(parsed.clone());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
unwrap_union(&optimized).0.as_ref(),
|
unwrap_union(&optimized).0.as_ref(),
|
||||||
&RevsetExpression::CommitRef(RevsetCommitRef::Branches("".to_owned()))
|
&RevsetExpression::CommitRef(RevsetCommitRef::Branches(StringPattern::everything()))
|
||||||
);
|
);
|
||||||
assert!(Rc::ptr_eq(
|
assert!(Rc::ptr_eq(
|
||||||
unwrap_union(&parsed).1,
|
unwrap_union(&parsed).1,
|
||||||
|
@ -3336,7 +3376,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"foo",
|
Substring(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3355,7 +3397,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"bar",
|
Substring(
|
||||||
|
"bar",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3374,7 +3418,9 @@ mod tests {
|
||||||
Union(
|
Union(
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"bar",
|
Substring(
|
||||||
|
"bar",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
CommitRef(
|
CommitRef(
|
||||||
|
@ -3400,7 +3446,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"foo",
|
Substring(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3412,7 +3460,9 @@ mod tests {
|
||||||
insta::assert_debug_snapshot!(optimize(parse("author(foo)").unwrap()), @r###"
|
insta::assert_debug_snapshot!(optimize(parse("author(foo)").unwrap()), @r###"
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"foo",
|
Substring(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
"###);
|
"###);
|
||||||
|
@ -3426,7 +3476,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Description(
|
Description(
|
||||||
"bar",
|
Substring(
|
||||||
|
"bar",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3440,7 +3492,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"foo",
|
Substring(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3450,12 +3504,16 @@ mod tests {
|
||||||
Intersection(
|
Intersection(
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"foo",
|
Substring(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Committer(
|
Committer(
|
||||||
"bar",
|
Substring(
|
||||||
|
"bar",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3472,13 +3530,17 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Description(
|
Description(
|
||||||
"bar",
|
Substring(
|
||||||
|
"bar",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"baz",
|
Substring(
|
||||||
|
"baz",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3494,13 +3556,17 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Committer(
|
Committer(
|
||||||
"foo",
|
Substring(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"baz",
|
Substring(
|
||||||
|
"baz",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3516,7 +3582,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Committer(
|
Committer(
|
||||||
"foo",
|
Substring(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -3537,7 +3605,9 @@ mod tests {
|
||||||
Intersection(
|
Intersection(
|
||||||
Filter(
|
Filter(
|
||||||
Committer(
|
Committer(
|
||||||
"foo",
|
Substring(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
|
@ -3552,7 +3622,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"baz",
|
Substring(
|
||||||
|
"baz",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3601,13 +3673,17 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Description(
|
Description(
|
||||||
"bar",
|
Substring(
|
||||||
|
"bar",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"baz",
|
Substring(
|
||||||
|
"baz",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3625,7 +3701,9 @@ mod tests {
|
||||||
Ancestors {
|
Ancestors {
|
||||||
heads: Filter(
|
heads: Filter(
|
||||||
Author(
|
Author(
|
||||||
"baz",
|
Substring(
|
||||||
|
"baz",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
generation: 1..2,
|
generation: 1..2,
|
||||||
|
@ -3640,7 +3718,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Description(
|
Description(
|
||||||
"bar",
|
Substring(
|
||||||
|
"bar",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3663,7 +3743,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"baz",
|
Substring(
|
||||||
|
"baz",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -3673,7 +3755,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Description(
|
Description(
|
||||||
"bar",
|
Substring(
|
||||||
|
"bar",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3706,19 +3790,25 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"A",
|
Substring(
|
||||||
|
"A",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"B",
|
Substring(
|
||||||
|
"B",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"C",
|
Substring(
|
||||||
|
"C",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3757,19 +3847,25 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"A",
|
Substring(
|
||||||
|
"A",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"B",
|
Substring(
|
||||||
|
"B",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"C",
|
Substring(
|
||||||
|
"C",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3788,13 +3884,17 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Description(
|
Description(
|
||||||
"bar",
|
Substring(
|
||||||
|
"bar",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"baz",
|
Substring(
|
||||||
|
"baz",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3815,7 +3915,9 @@ mod tests {
|
||||||
Union(
|
Union(
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"foo",
|
Substring(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
CommitRef(
|
CommitRef(
|
||||||
|
@ -3846,7 +3948,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Committer(
|
Committer(
|
||||||
"bar",
|
Substring(
|
||||||
|
"bar",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -3854,7 +3958,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Description(
|
Description(
|
||||||
"baz",
|
Substring(
|
||||||
|
"baz",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3882,7 +3988,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"foo",
|
Substring(
|
||||||
|
"foo",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -3931,7 +4039,9 @@ mod tests {
|
||||||
Union(
|
Union(
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"A",
|
Substring(
|
||||||
|
"A",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
CommitRef(
|
CommitRef(
|
||||||
|
@ -3946,7 +4056,9 @@ mod tests {
|
||||||
Union(
|
Union(
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"B",
|
Substring(
|
||||||
|
"B",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
CommitRef(
|
CommitRef(
|
||||||
|
@ -3961,7 +4073,9 @@ mod tests {
|
||||||
Union(
|
Union(
|
||||||
Filter(
|
Filter(
|
||||||
Author(
|
Author(
|
||||||
"C",
|
Substring(
|
||||||
|
"C",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
CommitRef(
|
CommitRef(
|
||||||
|
|
Loading…
Reference in a new issue