diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a5bcf0ca..77c6834dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Older binaries may not warn user when attempting to `git push` commits with such signatures. +* In revsets, the working-copy symbols (such as `@` and `workspace_id@`) can + no longer be quoted and will not be resolved as a revset aliases or revset + function parameter. For example, `author(foo@)` is now an error, and + a revset alias `'revset-aliases.foo@' = '@'` will be ignored. ### New features diff --git a/cli/src/cli_util.rs b/cli/src/cli_util.rs index 5bc984dc0..01837bf14 100644 --- a/cli/src/cli_util.rs +++ b/cli/src/cli_util.rs @@ -328,6 +328,7 @@ impl From for CommandError { candidates, } => format_similarity_hint(candidates), RevsetResolutionError::EmptyString + | RevsetResolutionError::WorkspaceMissingWorkingCopy { .. } | RevsetResolutionError::AmbiguousCommitIdPrefix(_) | RevsetResolutionError::AmbiguousChangeIdPrefix(_) | RevsetResolutionError::StoreError(_) => None, @@ -1142,7 +1143,7 @@ impl WorkspaceCommandHelper { Box::new(|repo, prefix| id_prefix_context.resolve_commit_prefix(repo, prefix)); let change_id_resolver: revset::PrefixResolver> = Box::new(|repo, prefix| id_prefix_context.resolve_change_prefix(repo, prefix)); - DefaultSymbolResolver::new(self.repo().as_ref(), Some(self.workspace_id())) + DefaultSymbolResolver::new(self.repo().as_ref()) .with_commit_id_resolver(commit_id_resolver) .with_change_id_resolver(change_id_resolver) } @@ -1157,8 +1158,7 @@ impl WorkspaceCommandHelper { .unwrap_or_else(|_| self.settings.default_revset()); if !revset_string.is_empty() { let disambiguation_revset = self.parse_revset(&revset_string, None).unwrap(); - context = context - .disambiguate_within(disambiguation_revset, Some(self.workspace_id().clone())); + context = context.disambiguate_within(disambiguation_revset); } context }) diff --git a/cli/src/commands/mod.rs b/cli/src/commands/mod.rs index 328ae074f..0f575281a 100644 --- a/cli/src/commands/mod.rs +++ b/cli/src/commands/mod.rs @@ -1728,7 +1728,7 @@ fn cmd_log(ui: &mut Ui, command: &CommandHelper, args: &LogArgs) -> Result<(), C only_path, &RevsetAliasesMap::new(), &command.settings().user_email(), - None, + Some(&workspace_command.revset_context()), ) .is_ok() { @@ -2523,7 +2523,7 @@ from the source will be moved into the parent. only_path, &RevsetAliasesMap::new(), &command.settings().user_email(), - None, + Some(&tx.base_workspace_helper().revset_context()), ) .is_ok() { diff --git a/cli/tests/test_workspaces.rs b/cli/tests/test_workspaces.rs index 33cdcb570..921ddc57a 100644 --- a/cli/tests/test_workspaces.rs +++ b/cli/tests/test_workspaces.rs @@ -323,7 +323,7 @@ fn test_workspaces_forget() { // Revision "@" cannot be used let stderr = test_env.jj_cmd_failure(&main_path, &["log", "-r", "@"]); insta::assert_snapshot!(stderr, @r###" - Error: Revision "@" doesn't exist + Error: Workspace "default" doesn't have a working copy "###); // Try to add back the workspace diff --git a/lib/src/id_prefix.rs b/lib/src/id_prefix.rs index 17042d0d8..938f7ad49 100644 --- a/lib/src/id_prefix.rs +++ b/lib/src/id_prefix.rs @@ -23,7 +23,6 @@ use once_cell::unsync::OnceCell; use crate::backend::{self, ChangeId, CommitId, ObjectId}; use crate::index::{HexPrefix, PrefixResolution}; -use crate::op_store::WorkspaceId; use crate::repo::Repo; use crate::revset::{DefaultSymbolResolver, RevsetExpression}; @@ -31,7 +30,6 @@ struct PrefixDisambiguationError; struct DisambiguationData { expression: Rc, - workspace_id: Option, indexes: OnceCell, } @@ -44,7 +42,7 @@ struct Indexes { impl DisambiguationData { fn indexes(&self, repo: &dyn Repo) -> Result<&Indexes, PrefixDisambiguationError> { self.indexes.get_or_try_init(|| { - let symbol_resolver = DefaultSymbolResolver::new(repo, self.workspace_id.as_ref()); + let symbol_resolver = DefaultSymbolResolver::new(repo); let resolved_expression = self .expression .clone() @@ -99,13 +97,8 @@ pub struct IdPrefixContext { } impl IdPrefixContext { - pub fn disambiguate_within( - mut self, - expression: Rc, - workspace_id: Option, - ) -> Self { + pub fn disambiguate_within(mut self, expression: Rc) -> Self { self.disambiguation = Some(DisambiguationData { - workspace_id, expression, indexes: OnceCell::new(), }); diff --git a/lib/src/revset.rs b/lib/src/revset.rs index 698dd2e4b..b239ea76d 100644 --- a/lib/src/revset.rs +++ b/lib/src/revset.rs @@ -51,6 +51,8 @@ pub enum RevsetResolutionError { name: String, candidates: Vec, }, + #[error("Workspace \"{name}\" doesn't have a working copy")] + WorkspaceMissingWorkingCopy { name: String }, #[error("An empty string is not a valid revision")] EmptyString, #[error("Commit ID prefix \"{0}\" is ambiguous")] @@ -108,6 +110,8 @@ pub enum RevsetParseErrorKind { FsPathParseError(#[source] FsPathParseError), #[error("Cannot resolve file pattern without workspace")] FsPathWithoutWorkspace, + #[error(r#"Cannot resolve "@" without workspace"#)] + WorkingCopyWithoutWorkspace, #[error("Redefinition of function parameter")] RedefinedFunctionParameter, #[error(r#"Alias "{0}" cannot be expanded"#)] @@ -245,6 +249,7 @@ impl StringPattern { /// Symbol or function to be resolved to `CommitId`s. #[derive(Clone, Debug, Eq, PartialEq)] pub enum RevsetCommitRef { + WorkingCopy(WorkspaceId), Symbol(String), VisibleHeads, Branches(StringPattern), @@ -327,6 +332,12 @@ impl RevsetExpression { Rc::new(RevsetExpression::All) } + pub fn working_copy(workspace_id: WorkspaceId) -> Rc { + Rc::new(RevsetExpression::CommitRef(RevsetCommitRef::WorkingCopy( + workspace_id, + ))) + } + pub fn symbol(value: String) -> Rc { Rc::new(RevsetExpression::CommitRef(RevsetCommitRef::Symbol(value))) } @@ -883,7 +894,20 @@ fn parse_symbol_rule( match first.as_rule() { Rule::identifier => { let name = first.as_str(); - if let Some(expr) = state.locals.get(name) { + if name.ends_with('@') { + let workspace_id = if name == "@" { + if let Some(ctx) = state.workspace_ctx { + ctx.workspace_id.clone() + } else { + return Err(RevsetParseError::new( + RevsetParseErrorKind::WorkingCopyWithoutWorkspace, + )); + } + } else { + WorkspaceId::new(name.strip_suffix('@').unwrap().to_string()) + }; + Ok(RevsetExpression::working_copy(workspace_id)) + } else if let Some(expr) = state.locals.get(name) { Ok(expr.clone()) } else if let Some((id, defn)) = state.aliases_map.get_symbol(name) { let locals = HashMap::new(); // Don't spill out the current scope @@ -1903,20 +1927,18 @@ impl SymbolResolver for FailingSymbolResolver { pub type PrefixResolver<'a, T> = Box PrefixResolution + 'a>; -/// Resolves the "root" and "@" symbols, branches, remote branches, tags, git +/// Resolves the "root" symbol, branches, remote branches, tags, git /// refs, and full and abbreviated commit and change ids. pub struct DefaultSymbolResolver<'a> { repo: &'a dyn Repo, - workspace_id: Option<&'a WorkspaceId>, commit_id_resolver: PrefixResolver<'a, CommitId>, change_id_resolver: PrefixResolver<'a, Vec>, } impl<'a> DefaultSymbolResolver<'a> { - pub fn new(repo: &'a dyn Repo, workspace_id: Option<&'a WorkspaceId>) -> Self { + pub fn new(repo: &'a dyn Repo) -> Self { DefaultSymbolResolver { repo, - workspace_id, commit_id_resolver: Box::new(|repo, prefix| repo.index().resolve_prefix(prefix)), change_id_resolver: Box::new(|repo, prefix| repo.resolve_change_id_prefix(prefix)), } @@ -1941,28 +1963,7 @@ impl<'a> DefaultSymbolResolver<'a> { impl SymbolResolver for DefaultSymbolResolver<'_> { fn resolve_symbol(&self, symbol: &str) -> Result, RevsetResolutionError> { - if symbol.ends_with('@') { - let target_workspace = if symbol == "@" { - if let Some(workspace_id) = self.workspace_id { - workspace_id.clone() - } else { - return Err(RevsetResolutionError::NoSuchRevision { - name: symbol.to_owned(), - candidates: Default::default(), - }); - } - } else { - WorkspaceId::new(symbol.strip_suffix('@').unwrap().to_string()) - }; - if let Some(commit_id) = self.repo.view().get_wc_commit_id(&target_workspace) { - Ok(vec![commit_id.clone()]) - } else { - Err(RevsetResolutionError::NoSuchRevision { - name: symbol.to_owned(), - candidates: Default::default(), - }) - } - } else if symbol == "root" { + if symbol == "root" { Ok(vec![self.repo.store().root_commit_id().clone()]) } else if symbol.is_empty() { Err(RevsetResolutionError::EmptyString) @@ -2042,6 +2043,15 @@ fn resolve_commit_ref( ) -> Result, RevsetResolutionError> { match commit_ref { RevsetCommitRef::Symbol(symbol) => symbol_resolver.resolve_symbol(symbol), + RevsetCommitRef::WorkingCopy(workspace_id) => { + if let Some(commit_id) = repo.view().get_wc_commit_id(workspace_id) { + Ok(vec![commit_id.clone()]) + } else { + Err(RevsetResolutionError::WorkspaceMissingWorkingCopy { + name: workspace_id.as_str().to_string(), + }) + } + } RevsetCommitRef::VisibleHeads => Ok(repo.view().heads().iter().cloned().collect_vec()), RevsetCommitRef::Branches(pattern) => { let view = repo.view(); @@ -2098,7 +2108,8 @@ fn resolve_symbols( RevsetResolutionError::NoSuchRevision { .. } => { Ok(RevsetExpression::none()) } - RevsetResolutionError::EmptyString + RevsetResolutionError::WorkspaceMissingWorkingCopy { .. } + | RevsetResolutionError::EmptyString | RevsetResolutionError::AmbiguousCommitIdPrefix(_) | RevsetResolutionError::AmbiguousChangeIdPrefix(_) | RevsetResolutionError::StoreError(_) => Err(err), @@ -2379,7 +2390,7 @@ impl Iterator for ReverseRevsetIterator { } } -/// Workspace information needed to evaluate revset expression. +/// Workspace information needed to parse revset expression. #[derive(Clone, Debug)] pub struct RevsetWorkspaceContext<'a> { pub cwd: &'a Path, @@ -2395,6 +2406,13 @@ mod tests { parse_with_aliases(revset_str, [] as [(&str, &str); 0]) } + fn parse_with_workspace( + revset_str: &str, + workspace_id: &WorkspaceId, + ) -> Result, RevsetParseErrorKind> { + parse_with_aliases_and_workspace(revset_str, [] as [(&str, &str); 0], workspace_id) + } + fn parse_with_aliases( revset_str: &str, aliases: impl IntoIterator, impl Into)>, @@ -2403,12 +2421,25 @@ mod tests { for (decl, defn) in aliases { aliases_map.insert(decl, defn).unwrap(); } - // Set up pseudo context to resolve file(path) + // Map error to comparable object + super::parse(revset_str, &aliases_map, "test.user@example.com", None).map_err(|e| e.kind) + } + + fn parse_with_aliases_and_workspace( + revset_str: &str, + aliases: impl IntoIterator, impl Into)>, + workspace_id: &WorkspaceId, + ) -> Result, RevsetParseErrorKind> { + // Set up pseudo context to resolve `workspace_id@` and `file(path)` let workspace_ctx = RevsetWorkspaceContext { cwd: Path::new("/"), - workspace_id: &WorkspaceId::default(), + workspace_id, workspace_root: Path::new("/"), }; + let mut aliases_map = RevsetAliasesMap::new(); + for (decl, defn) in aliases { + aliases_map.insert(decl, defn).unwrap(); + } // Map error to comparable object super::parse( revset_str, @@ -2422,36 +2453,36 @@ mod tests { #[test] #[allow(clippy::redundant_clone)] // allow symbol.clone() fn test_revset_expression_building() { - let wc_symbol = RevsetExpression::symbol("@".to_string()); + let current_wc = RevsetExpression::working_copy(WorkspaceId::default()); let foo_symbol = RevsetExpression::symbol("foo".to_string()); let bar_symbol = RevsetExpression::symbol("bar".to_string()); let baz_symbol = RevsetExpression::symbol("baz".to_string()); assert_eq!( - wc_symbol, - Rc::new(RevsetExpression::CommitRef(RevsetCommitRef::Symbol( - "@".to_string() + current_wc, + Rc::new(RevsetExpression::CommitRef(RevsetCommitRef::WorkingCopy( + WorkspaceId::default() ))), ); assert_eq!( - wc_symbol.heads(), - Rc::new(RevsetExpression::Heads(wc_symbol.clone())) + current_wc.heads(), + Rc::new(RevsetExpression::Heads(current_wc.clone())) ); assert_eq!( - wc_symbol.roots(), - Rc::new(RevsetExpression::Roots(wc_symbol.clone())) + current_wc.roots(), + Rc::new(RevsetExpression::Roots(current_wc.clone())) ); assert_eq!( - wc_symbol.parents(), + current_wc.parents(), Rc::new(RevsetExpression::Ancestors { - heads: wc_symbol.clone(), + heads: current_wc.clone(), generation: 1..2, is_legacy: false, }) ); assert_eq!( - wc_symbol.ancestors(), + current_wc.ancestors(), Rc::new(RevsetExpression::Ancestors { - heads: wc_symbol.clone(), + heads: current_wc.clone(), generation: GENERATION_RANGE_FULL, is_legacy: false, }) @@ -2473,10 +2504,10 @@ mod tests { }) ); assert_eq!( - foo_symbol.dag_range_to(&wc_symbol), + foo_symbol.dag_range_to(¤t_wc), Rc::new(RevsetExpression::DagRange { roots: foo_symbol.clone(), - heads: wc_symbol.clone(), + heads: current_wc.clone(), is_legacy: false, }) ); @@ -2489,10 +2520,10 @@ mod tests { }) ); assert_eq!( - foo_symbol.range(&wc_symbol), + foo_symbol.range(¤t_wc), Rc::new(RevsetExpression::Range { roots: foo_symbol.clone(), - heads: wc_symbol.clone(), + heads: current_wc.clone(), generation: GENERATION_RANGE_FULL, }) ); @@ -2501,32 +2532,35 @@ mod tests { Rc::new(RevsetExpression::NotIn(foo_symbol.clone())) ); assert_eq!( - foo_symbol.union(&wc_symbol), + foo_symbol.union(¤t_wc), Rc::new(RevsetExpression::Union( foo_symbol.clone(), - wc_symbol.clone() + current_wc.clone() )) ); assert_eq!( RevsetExpression::union_all(&[]), Rc::new(RevsetExpression::None) ); - assert_eq!(RevsetExpression::union_all(&[wc_symbol.clone()]), wc_symbol); assert_eq!( - RevsetExpression::union_all(&[wc_symbol.clone(), foo_symbol.clone()]), + RevsetExpression::union_all(&[current_wc.clone()]), + current_wc + ); + assert_eq!( + RevsetExpression::union_all(&[current_wc.clone(), foo_symbol.clone()]), Rc::new(RevsetExpression::Union( - wc_symbol.clone(), + current_wc.clone(), foo_symbol.clone(), )) ); assert_eq!( RevsetExpression::union_all(&[ - wc_symbol.clone(), + current_wc.clone(), foo_symbol.clone(), bar_symbol.clone(), ]), Rc::new(RevsetExpression::Union( - wc_symbol.clone(), + current_wc.clone(), Rc::new(RevsetExpression::Union( foo_symbol.clone(), bar_symbol.clone(), @@ -2535,14 +2569,14 @@ mod tests { ); assert_eq!( RevsetExpression::union_all(&[ - wc_symbol.clone(), + current_wc.clone(), foo_symbol.clone(), bar_symbol.clone(), baz_symbol.clone(), ]), Rc::new(RevsetExpression::Union( Rc::new(RevsetExpression::Union( - wc_symbol.clone(), + current_wc.clone(), foo_symbol.clone(), )), Rc::new(RevsetExpression::Union( @@ -2552,25 +2586,58 @@ mod tests { )) ); assert_eq!( - foo_symbol.intersection(&wc_symbol), + foo_symbol.intersection(¤t_wc), Rc::new(RevsetExpression::Intersection( foo_symbol.clone(), - wc_symbol.clone() + current_wc.clone() )) ); assert_eq!( - foo_symbol.minus(&wc_symbol), - Rc::new(RevsetExpression::Difference(foo_symbol, wc_symbol.clone())) + foo_symbol.minus(¤t_wc), + Rc::new(RevsetExpression::Difference(foo_symbol, current_wc.clone())) ); } #[test] fn test_parse_revset() { - let wc_symbol = RevsetExpression::symbol("@".to_string()); + let main_workspace_id = WorkspaceId::new("main".to_string()); + let other_workspace_id = WorkspaceId::new("other".to_string()); + let main_wc = RevsetExpression::working_copy(main_workspace_id.clone()); let foo_symbol = RevsetExpression::symbol("foo".to_string()); let bar_symbol = RevsetExpression::symbol("bar".to_string()); - // Parse a single symbol (specifically the "checkout" symbol) - assert_eq!(parse("@"), Ok(wc_symbol.clone())); + // Parse "@" (the current working copy) + assert_eq!( + parse("@"), + Err(RevsetParseErrorKind::WorkingCopyWithoutWorkspace) + ); + assert_eq!(parse("main@"), Ok(main_wc.clone())); + assert_eq!( + parse_with_workspace("@", &main_workspace_id), + Ok(main_wc.clone()) + ); + assert_eq!( + parse_with_workspace("main@", &other_workspace_id), + Ok(main_wc) + ); + // Quoted "@" is not interpreted as a working copy + assert_eq!( + parse(r#""@""#), + Ok(RevsetExpression::symbol("@".to_string())) + ); + // "@" in function argument must be quoted + assert_eq!( + parse("author(foo@)"), + Err(RevsetParseErrorKind::InvalidFunctionArguments { + name: "author".to_string(), + message: "Expected function argument of string pattern".to_string(), + }) + ); + assert_eq!( + parse(r#"author("foo@")"#), + Ok(RevsetExpression::filter(RevsetFilterPredicate::Author( + StringPattern::Substring("foo@".to_string()), + ))) + ); // Parse a single symbol assert_eq!(parse("foo"), Ok(foo_symbol.clone())); // Internal '.', '-', and '+' are allowed @@ -2601,20 +2668,20 @@ mod tests { // Parse a quoted symbol assert_eq!(parse("\"foo\""), Ok(foo_symbol.clone())); // Parse the "parents" operator - assert_eq!(parse("@-"), Ok(wc_symbol.parents())); + assert_eq!(parse("foo-"), Ok(foo_symbol.parents())); // Parse the "children" operator - assert_eq!(parse("@+"), Ok(wc_symbol.children())); + assert_eq!(parse("foo+"), Ok(foo_symbol.children())); // Parse the "ancestors" operator - assert_eq!(parse("::@"), Ok(wc_symbol.ancestors())); + assert_eq!(parse("::foo"), Ok(foo_symbol.ancestors())); // Parse the "descendants" operator - assert_eq!(parse("@::"), Ok(wc_symbol.descendants())); + assert_eq!(parse("foo::"), Ok(foo_symbol.descendants())); // Parse the "dag range" operator assert_eq!(parse("foo::bar"), Ok(foo_symbol.dag_range_to(&bar_symbol))); // Parse the "range" prefix operator - assert_eq!(parse("..@"), Ok(wc_symbol.ancestors())); + assert_eq!(parse("..foo"), Ok(foo_symbol.ancestors())); assert_eq!( - parse("@.."), - Ok(wc_symbol.range(&RevsetExpression::visible_heads())) + parse("foo.."), + Ok(foo_symbol.range(&RevsetExpression::visible_heads())) ); assert_eq!(parse("foo..bar"), Ok(foo_symbol.range(&bar_symbol))); // Parse the "negate" operator @@ -2630,17 +2697,20 @@ mod tests { // Parse the "difference" operator assert_eq!(parse("foo ~ bar"), Ok(foo_symbol.minus(&bar_symbol))); // Parentheses are allowed before suffix operators - assert_eq!(parse("(@)-"), Ok(wc_symbol.parents())); + assert_eq!(parse("(foo)-"), Ok(foo_symbol.parents())); // Space is allowed around expressions - assert_eq!(parse(" ::@ "), Ok(wc_symbol.ancestors())); - assert_eq!(parse("( ::@ )"), Ok(wc_symbol.ancestors())); + assert_eq!(parse(" ::foo "), Ok(foo_symbol.ancestors())); + assert_eq!(parse("( ::foo )"), Ok(foo_symbol.ancestors())); // Space is not allowed around prefix operators - assert_eq!(parse(" :: @ "), Err(RevsetParseErrorKind::SyntaxError)); + assert_eq!(parse(" :: foo "), Err(RevsetParseErrorKind::SyntaxError)); // Incomplete parse assert_eq!(parse("foo | -"), Err(RevsetParseErrorKind::SyntaxError)); // Space is allowed around infix operators and function arguments assert_eq!( - parse(" description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) "), + parse_with_workspace( + " description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) ", + &main_workspace_id + ), Ok(RevsetExpression::filter(RevsetFilterPredicate::Description( StringPattern::Substring("arg1".to_string()) )) @@ -2666,8 +2736,8 @@ mod tests { assert!(parse("branches(,a)").is_err()); assert!(parse("branches(a,,)").is_err()); assert!(parse("branches(a , , )").is_err()); - assert!(parse("file(a,b,)").is_ok()); - assert!(parse("file(a,,b)").is_err()); + assert!(parse_with_workspace("file(a,b,)", &main_workspace_id).is_ok()); + assert!(parse_with_workspace("file(a,,b)", &main_workspace_id).is_err()); assert!(parse("remote_branches(a,remote=b , )").is_ok()); assert!(parse("remote_branches(a,,remote=b)").is_err()); } @@ -2815,17 +2885,17 @@ mod tests { #[test] fn test_parse_revset_function() { - let wc_symbol = RevsetExpression::symbol("@".to_string()); - assert_eq!(parse("parents(@)"), Ok(wc_symbol.parents())); - assert_eq!(parse("parents((@))"), Ok(wc_symbol.parents())); - assert_eq!(parse("parents(\"@\")"), Ok(wc_symbol.parents())); + let foo_symbol = RevsetExpression::symbol("foo".to_string()); + assert_eq!(parse("parents(foo)"), Ok(foo_symbol.parents())); + assert_eq!(parse("parents((foo))"), Ok(foo_symbol.parents())); + assert_eq!(parse("parents(\"foo\")"), Ok(foo_symbol.parents())); assert_eq!( - parse("ancestors(parents(@))"), - Ok(wc_symbol.parents().ancestors()) + parse("ancestors(parents(foo))"), + Ok(foo_symbol.parents().ancestors()) ); - assert_eq!(parse("parents(@"), Err(RevsetParseErrorKind::SyntaxError)); + assert_eq!(parse("parents(foo"), Err(RevsetParseErrorKind::SyntaxError)); assert_eq!( - parse("parents(@,@)"), + parse("parents(foo,foo)"), Err(RevsetParseErrorKind::InvalidFunctionArguments { name: "parents".to_string(), message: "Expected 1 arguments".to_string() @@ -2870,19 +2940,19 @@ mod tests { ))) ); assert_eq!( - parse("empty()"), + parse_with_workspace("empty()", &WorkspaceId::default()), Ok(RevsetExpression::filter(RevsetFilterPredicate::File(None)).negated()) ); - assert!(parse("empty(foo)").is_err()); - assert!(parse("file()").is_err()); + assert!(parse_with_workspace("empty(foo)", &WorkspaceId::default()).is_err()); + assert!(parse_with_workspace("file()", &WorkspaceId::default()).is_err()); assert_eq!( - parse("file(foo)"), + parse_with_workspace("file(foo)", &WorkspaceId::default()), Ok(RevsetExpression::filter(RevsetFilterPredicate::File(Some( vec![RepoPath::from_internal_string("foo")] )))) ); assert_eq!( - parse("file(foo, bar, baz)"), + parse_with_workspace("file(foo, bar, baz)", &WorkspaceId::default()), Ok(RevsetExpression::filter(RevsetFilterPredicate::File(Some( vec![ RepoPath::from_internal_string("foo"), @@ -2959,11 +3029,18 @@ mod tests { parse_with_aliases(r#"A|"A""#, [("A", "a")]).unwrap(), parse("a|A").unwrap() ); + // Working copy symbol should not be substituted with alias. + // TODO: Make it an error instead of being ignored + assert_eq!( + parse_with_aliases(r#"a@"#, [("a@", "a")]).unwrap(), + parse("a@").unwrap() + ); // Alias can be substituted to string literal. assert_eq!( - parse_with_aliases("file(A)", [("A", "a")]).unwrap(), - parse("file(a)").unwrap() + parse_with_aliases_and_workspace("file(A)", [("A", "a")], &WorkspaceId::default()) + .unwrap(), + parse_with_workspace("file(a)", &WorkspaceId::default()).unwrap() ); // Alias can be substituted to string pattern. @@ -3034,6 +3111,13 @@ mod tests { parse("(x|(x|a))&y").unwrap() ); + // Working copy symbol cannot be used as parameter name + // TODO: Make it an error instead of being ignored + assert_eq!( + parse_with_aliases("F(x)", [("F(a@)", "a@|y")]).unwrap(), + parse("a@|y").unwrap() + ); + // Function parameter should precede the symbol alias. assert_eq!( parse_with_aliases("F(a)|X", [("F(X)", "X"), ("X", "x")]).unwrap(), @@ -3690,7 +3774,7 @@ mod tests { ) "###); insta::assert_debug_snapshot!( - optimize(parse("committer(foo) & file(bar) & baz").unwrap()), @r###" + optimize(parse_with_workspace("committer(foo) & file(bar) & baz", &WorkspaceId::default()).unwrap()), @r###" Intersection( Intersection( CommitRef( @@ -3718,7 +3802,7 @@ mod tests { ) "###); insta::assert_debug_snapshot!( - optimize(parse("committer(foo) & file(bar) & author(baz)").unwrap()), @r###" + optimize(parse_with_workspace("committer(foo) & file(bar) & author(baz)", &WorkspaceId::default()).unwrap()), @r###" Intersection( Intersection( Filter( @@ -3747,7 +3831,7 @@ mod tests { ), ) "###); - insta::assert_debug_snapshot!(optimize(parse("foo & file(bar) & baz").unwrap()), @r###" + insta::assert_debug_snapshot!(optimize(parse_with_workspace("foo & file(bar) & baz", &WorkspaceId::default()).unwrap()), @r###" Intersection( Intersection( CommitRef( diff --git a/lib/tests/test_id_prefix.rs b/lib/tests/test_id_prefix.rs index cf4f62508..fe9062c9a 100644 --- a/lib/tests/test_id_prefix.rs +++ b/lib/tests/test_id_prefix.rs @@ -184,7 +184,7 @@ fn test_id_prefix() { // --------------------------------------------------------------------------------------------- let expression = RevsetExpression::commits(vec![commits[0].id().clone(), commits[2].id().clone()]); - let c = c.disambiguate_within(expression, None); + let c = c.disambiguate_within(expression); // The prefix is now shorter assert_eq!( c.shortest_commit_prefix_len(repo.as_ref(), commits[2].id()), @@ -213,7 +213,7 @@ fn test_id_prefix() { // needed. // --------------------------------------------------------------------------------------------- let expression = RevsetExpression::commit(root_commit_id.clone()); - let c = c.disambiguate_within(expression, None); + let c = c.disambiguate_within(expression); assert_eq!( c.shortest_commit_prefix_len(repo.as_ref(), root_commit_id), 1 @@ -243,7 +243,7 @@ fn test_id_prefix() { // --------------------------------------------------------------------------------------------- // TODO: Should be an error let expression = RevsetExpression::symbol("nonexistent".to_string()); - let context = c.disambiguate_within(expression, None); + let context = c.disambiguate_within(expression); assert_eq!( context.shortest_commit_prefix_len(repo.as_ref(), commits[2].id()), 2 diff --git a/lib/tests/test_revset.rs b/lib/tests/test_revset.rs index a02b0a87a..c1f5d9a64 100644 --- a/lib/tests/test_revset.rs +++ b/lib/tests/test_revset.rs @@ -42,19 +42,15 @@ use testutils::{ create_random_commit, write_random_commit, CommitGraphBuilder, TestRepo, TestWorkspace, }; -fn resolve_symbol( - repo: &dyn Repo, - symbol: &str, - workspace_id: Option<&WorkspaceId>, -) -> Result, RevsetResolutionError> { - DefaultSymbolResolver::new(repo, workspace_id).resolve_symbol(symbol) +fn resolve_symbol(repo: &dyn Repo, symbol: &str) -> Result, RevsetResolutionError> { + DefaultSymbolResolver::new(repo).resolve_symbol(symbol) } fn revset_for_commits<'index>( repo: &'index dyn Repo, commits: &[&Commit], ) -> Box + 'index> { - let symbol_resolver = DefaultSymbolResolver::new(repo, None); + let symbol_resolver = DefaultSymbolResolver::new(repo); RevsetExpression::commits(commits.iter().map(|commit| commit.id().clone()).collect()) .resolve_user_expression(repo, &symbol_resolver) .unwrap() @@ -69,7 +65,7 @@ fn test_resolve_symbol_root(use_git: bool) { let repo = &test_repo.repo; assert_matches!( - resolve_symbol(repo.as_ref(), "root", None), + resolve_symbol(repo.as_ref(), "root"), Ok(v) if v == vec![repo.store().root_commit_id().clone()] ); } @@ -80,7 +76,7 @@ fn test_resolve_symbol_empty_string() { let repo = &test_repo.repo; assert_matches!( - resolve_symbol(repo.as_ref(), "", None), + resolve_symbol(repo.as_ref(), ""), Err(RevsetResolutionError::EmptyString) ); } @@ -141,56 +137,41 @@ fn test_resolve_symbol_commit_id() { // Test lookup by full commit id assert_eq!( - resolve_symbol( - repo.as_ref(), - "0454de3cae04c46cda37ba2e8873b4c17ff51dcb", - None - ) - .unwrap(), + resolve_symbol(repo.as_ref(), "0454de3cae04c46cda37ba2e8873b4c17ff51dcb",).unwrap(), vec![commits[0].id().clone()] ); assert_eq!( - resolve_symbol( - repo.as_ref(), - "045f56cd1b17e8abde86771e2705395dcde6a957", - None - ) - .unwrap(), + resolve_symbol(repo.as_ref(), "045f56cd1b17e8abde86771e2705395dcde6a957",).unwrap(), vec![commits[1].id().clone()] ); assert_eq!( - resolve_symbol( - repo.as_ref(), - "0468f7da8de2ce442f512aacf83411d26cd2e0cf", - None - ) - .unwrap(), + resolve_symbol(repo.as_ref(), "0468f7da8de2ce442f512aacf83411d26cd2e0cf",).unwrap(), vec![commits[2].id().clone()] ); // Test commit id prefix assert_eq!( - resolve_symbol(repo.as_ref(), "046", None).unwrap(), + resolve_symbol(repo.as_ref(), "046").unwrap(), vec![commits[2].id().clone()] ); assert_matches!( - resolve_symbol(repo.as_ref(), "04", None), + resolve_symbol(repo.as_ref(), "04"), Err(RevsetResolutionError::AmbiguousCommitIdPrefix(s)) if s == "04" ); assert_matches!( - resolve_symbol(repo.as_ref(), "040", None), + resolve_symbol(repo.as_ref(), "040"), Err(RevsetResolutionError::NoSuchRevision{name, candidates}) if name == "040" && candidates.is_empty() ); // Test non-hex string assert_matches!( - resolve_symbol(repo.as_ref(), "foo", None), + resolve_symbol(repo.as_ref(), "foo"), Err(RevsetResolutionError::NoSuchRevision{name, candidates}) if name == "foo" && candidates.is_empty() ); // Test present() suppresses only NoSuchRevision error assert_eq!(resolve_commit_ids(repo.as_ref(), "present(foo)"), []); - let symbol_resolver = DefaultSymbolResolver::new(repo.as_ref(), None); + let symbol_resolver = DefaultSymbolResolver::new(repo.as_ref()); assert_matches!( optimize(parse("present(04)", &RevsetAliasesMap::new(), &settings.user_email(), None).unwrap()).resolve_user_expression(repo.as_ref(), &symbol_resolver), Err(RevsetResolutionError::AmbiguousCommitIdPrefix(s)) if s == "04" @@ -281,19 +262,19 @@ fn test_resolve_symbol_change_id(readonly: bool) { // Test lookup by full change id assert_eq!( - resolve_symbol(repo, "zvlyxpuvtsoopsqzlkorrpqrszrqvlnx", None).unwrap(), + resolve_symbol(repo, "zvlyxpuvtsoopsqzlkorrpqrszrqvlnx").unwrap(), vec![CommitId::from_hex( "8fd68d104372910e19511df709e5dde62a548720" )] ); assert_eq!( - resolve_symbol(repo, "zvzowopwpuymrlmonvnuruunomzqmlsy", None).unwrap(), + resolve_symbol(repo, "zvzowopwpuymrlmonvnuruunomzqmlsy").unwrap(), vec![CommitId::from_hex( "5339432b8e7b90bd3aa1a323db71b8a5c5dcd020" )] ); assert_eq!( - resolve_symbol(repo, "zvlynszrxlvlwvkwkwsymrpypvtsszor", None).unwrap(), + resolve_symbol(repo, "zvlynszrxlvlwvkwkwsymrpypvtsszor").unwrap(), vec![CommitId::from_hex( "e2ad9d861d0ee625851b8ecfcf2c727410e38720" )] @@ -301,36 +282,36 @@ fn test_resolve_symbol_change_id(readonly: bool) { // Test change id prefix assert_eq!( - resolve_symbol(repo, "zvlyx", None).unwrap(), + resolve_symbol(repo, "zvlyx").unwrap(), vec![CommitId::from_hex( "8fd68d104372910e19511df709e5dde62a548720" )] ); assert_eq!( - resolve_symbol(repo, "zvlyn", None).unwrap(), + resolve_symbol(repo, "zvlyn").unwrap(), vec![CommitId::from_hex( "e2ad9d861d0ee625851b8ecfcf2c727410e38720" )] ); assert_matches!( - resolve_symbol(repo, "zvly", None), + resolve_symbol(repo, "zvly"), Err(RevsetResolutionError::AmbiguousChangeIdPrefix(s)) if s == "zvly" ); assert_matches!( - resolve_symbol(repo, "zvlyw", None), + resolve_symbol(repo, "zvlyw"), Err(RevsetResolutionError::NoSuchRevision{name, candidates}) if name == "zvlyw" && candidates.is_empty() ); // Test that commit and changed id don't conflict ("040" and "zvz" are the // same). assert_eq!( - resolve_symbol(repo, "040", None).unwrap(), + resolve_symbol(repo, "040").unwrap(), vec![CommitId::from_hex( "040031cb4ad0cbc3287914f1d205dabf4a7eb889" )] ); assert_eq!( - resolve_symbol(repo, "zvz", None).unwrap(), + resolve_symbol(repo, "zvz").unwrap(), vec![CommitId::from_hex( "5339432b8e7b90bd3aa1a323db71b8a5c5dcd020" )] @@ -338,7 +319,7 @@ fn test_resolve_symbol_change_id(readonly: bool) { // Test non-hex string assert_matches!( - resolve_symbol(repo, "foo", None), + resolve_symbol(repo, "foo"), Err(RevsetResolutionError::NoSuchRevision{ name, candidates @@ -348,7 +329,7 @@ fn test_resolve_symbol_change_id(readonly: bool) { #[test_case(false ; "local backend")] #[test_case(true ; "git backend")] -fn test_resolve_symbol_checkout(use_git: bool) { +fn test_resolve_working_copy(use_git: bool) { let settings = testutils::user_settings(); let test_repo = TestRepo::init(use_git); let repo = &test_repo.repo; @@ -362,52 +343,33 @@ fn test_resolve_symbol_checkout(use_git: bool) { let ws1 = WorkspaceId::new("ws1".to_string()); let ws2 = WorkspaceId::new("ws2".to_string()); - // With no workspaces, no variation can be resolved + // Cannot resolve a working-copy commit for an unknown workspace assert_matches!( - resolve_symbol(mut_repo, "@", None), - Err(RevsetResolutionError::NoSuchRevision{ - name, - candidates, - }) if name == "@" && candidates.is_empty() - ); - assert_matches!( - resolve_symbol(mut_repo, "@", Some(&ws1)), - Err(RevsetResolutionError::NoSuchRevision{ - name, - candidates, - }) if name == "@" && candidates.is_empty() - ); - assert_matches!( - resolve_symbol(mut_repo, "ws1@", Some(&ws1)), - Err(RevsetResolutionError::NoSuchRevision{ - name, - candidates, - }) if name == "ws1@" && candidates.is_empty() + RevsetExpression::working_copy(ws1.clone()).resolve(mut_repo), + Err(RevsetResolutionError::WorkspaceMissingWorkingCopy { name }) if name == "ws1" ); // Add some workspaces mut_repo .set_wc_commit(ws1.clone(), commit1.id().clone()) .unwrap(); - mut_repo.set_wc_commit(ws2, commit2.id().clone()).unwrap(); - // @ cannot be resolved without a default workspace ID - assert_matches!( - resolve_symbol(mut_repo, "@", None), - Err(RevsetResolutionError::NoSuchRevision{ - name, - candidates, - }) if name == "@" && candidates.is_empty() - ); + mut_repo + .set_wc_commit(ws2.clone(), commit2.id().clone()) + .unwrap(); + let resolve = |ws_id: WorkspaceId| -> Vec { + RevsetExpression::working_copy(ws_id) + .resolve(mut_repo) + .unwrap() + .evaluate(mut_repo) + .unwrap() + .iter() + .collect() + }; + // Can resolve "@" shorthand with a default workspace ID - assert_eq!( - resolve_symbol(mut_repo, "@", Some(&ws1)).unwrap(), - vec![commit1.id().clone()] - ); + assert_eq!(resolve(ws1), vec![commit1.id().clone()]); // Can resolve an explicit checkout - assert_eq!( - resolve_symbol(mut_repo, "ws2@", Some(&ws1)).unwrap(), - vec![commit2.id().clone()] - ); + assert_eq!(resolve(ws2), vec![commit2.id().clone()]); } #[test] @@ -461,11 +423,11 @@ fn test_resolve_symbol_branches() { // Local only assert_eq!( - resolve_symbol(mut_repo, "local", None).unwrap(), + resolve_symbol(mut_repo, "local").unwrap(), vec![commit1.id().clone()], ); insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "local@origin", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "local@origin").unwrap_err(), @r###" NoSuchRevision { name: "local@origin", candidates: [ @@ -479,7 +441,7 @@ fn test_resolve_symbol_branches() { // Remote only (or locally deleted) insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "remote", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "remote").unwrap_err(), @r###" NoSuchRevision { name: "remote", candidates: [ @@ -490,35 +452,35 @@ fn test_resolve_symbol_branches() { } "###); assert_eq!( - resolve_symbol(mut_repo, "remote@origin", None).unwrap(), + resolve_symbol(mut_repo, "remote@origin").unwrap(), vec![commit2.id().clone()], ); // Local/remote/git assert_eq!( - resolve_symbol(mut_repo, "local-remote", None).unwrap(), + resolve_symbol(mut_repo, "local-remote").unwrap(), vec![commit3.id().clone()], ); assert_eq!( - resolve_symbol(mut_repo, "local-remote@origin", None).unwrap(), + resolve_symbol(mut_repo, "local-remote@origin").unwrap(), vec![commit4.id().clone()], ); assert_eq!( - resolve_symbol(mut_repo, "local-remote@mirror", None).unwrap(), + resolve_symbol(mut_repo, "local-remote@mirror").unwrap(), vec![commit3.id().clone()], ); assert_eq!( - resolve_symbol(mut_repo, "local-remote@git", None).unwrap(), + resolve_symbol(mut_repo, "local-remote@git").unwrap(), vec![commit3.id().clone()], ); // Conflicted assert_eq!( - resolve_symbol(mut_repo, "local-conflicted", None).unwrap(), + resolve_symbol(mut_repo, "local-conflicted").unwrap(), vec![commit3.id().clone(), commit2.id().clone()], ); assert_eq!( - resolve_symbol(mut_repo, "remote-conflicted@origin", None).unwrap(), + resolve_symbol(mut_repo, "remote-conflicted@origin").unwrap(), vec![commit5.id().clone(), commit4.id().clone()], ); @@ -526,7 +488,7 @@ fn test_resolve_symbol_branches() { // For "local-emote" (without @remote part), "local-remote@mirror"/"@git" aren't // suggested since they point to the same target as "local-remote". insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "local-emote", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "local-emote").unwrap_err(), @r###" NoSuchRevision { name: "local-emote", candidates: [ @@ -538,7 +500,7 @@ fn test_resolve_symbol_branches() { } "###); insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "local-emote@origin", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "local-emote@origin").unwrap_err(), @r###" NoSuchRevision { name: "local-emote@origin", candidates: [ @@ -553,7 +515,7 @@ fn test_resolve_symbol_branches() { } "###); insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "local-remote@origine", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "local-remote@origine").unwrap_err(), @r###" NoSuchRevision { name: "local-remote@origine", candidates: [ @@ -570,7 +532,7 @@ fn test_resolve_symbol_branches() { // "local-remote@mirror" shouldn't be omitted just because it points to the same // target as "local-remote". insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "remote@mirror", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "remote@mirror").unwrap_err(), @r###" NoSuchRevision { name: "remote@mirror", candidates: [ @@ -582,7 +544,7 @@ fn test_resolve_symbol_branches() { // Typo of remote-only branch name insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "emote", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "emote").unwrap_err(), @r###" NoSuchRevision { name: "emote", candidates: [ @@ -592,7 +554,7 @@ fn test_resolve_symbol_branches() { } "###); insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "emote@origin", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "emote@origin").unwrap_err(), @r###" NoSuchRevision { name: "emote@origin", candidates: [ @@ -602,7 +564,7 @@ fn test_resolve_symbol_branches() { } "###); insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "remote@origine", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "remote@origine").unwrap_err(), @r###" NoSuchRevision { name: "remote@origine", candidates: [ @@ -627,14 +589,14 @@ fn test_resolve_symbol_git_head() { // Without HEAD@git insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "HEAD", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "HEAD").unwrap_err(), @r###" NoSuchRevision { name: "HEAD", candidates: [], } "###); insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "HEAD@git", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "HEAD@git").unwrap_err(), @r###" NoSuchRevision { name: "HEAD@git", candidates: [], @@ -644,7 +606,7 @@ fn test_resolve_symbol_git_head() { // With HEAD@git mut_repo.set_git_head_target(RefTarget::normal(commit1.id().clone())); insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "HEAD", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "HEAD").unwrap_err(), @r###" NoSuchRevision { name: "HEAD", candidates: [ @@ -653,7 +615,7 @@ fn test_resolve_symbol_git_head() { } "###); assert_eq!( - resolve_symbol(mut_repo, "HEAD@git", None).unwrap(), + resolve_symbol(mut_repo, "HEAD@git").unwrap(), vec![commit1.id().clone()], ); } @@ -696,7 +658,7 @@ fn test_resolve_symbol_git_refs() { // Nonexistent ref assert_matches!( - resolve_symbol(mut_repo, "nonexistent", None), + resolve_symbol(mut_repo, "nonexistent"), Err(RevsetResolutionError::NoSuchRevision{name, candidates}) if name == "nonexistent" && candidates.is_empty() ); @@ -704,7 +666,7 @@ fn test_resolve_symbol_git_refs() { // Full ref mut_repo.set_git_ref_target("refs/heads/branch", RefTarget::normal(commit4.id().clone())); assert_eq!( - resolve_symbol(mut_repo, "refs/heads/branch", None).unwrap(), + resolve_symbol(mut_repo, "refs/heads/branch").unwrap(), vec![commit4.id().clone()] ); @@ -712,7 +674,7 @@ fn test_resolve_symbol_git_refs() { mut_repo.set_git_ref_target("refs/heads/branch", RefTarget::normal(commit5.id().clone())); // branch alone is not recognized insta::assert_debug_snapshot!( - resolve_symbol(mut_repo, "branch", None).unwrap_err(), @r###" + resolve_symbol(mut_repo, "branch").unwrap_err(), @r###" NoSuchRevision { name: "branch", candidates: [ @@ -725,19 +687,19 @@ fn test_resolve_symbol_git_refs() { mut_repo.set_git_ref_target("refs/tags/branch", RefTarget::normal(commit4.id().clone())); // The *tag* branch is recognized assert_eq!( - resolve_symbol(mut_repo, "branch", None).unwrap(), + resolve_symbol(mut_repo, "branch").unwrap(), vec![commit4.id().clone()] ); // heads/branch does get resolved to the git ref refs/heads/branch assert_eq!( - resolve_symbol(mut_repo, "heads/branch", None).unwrap(), + resolve_symbol(mut_repo, "heads/branch").unwrap(), vec![commit5.id().clone()] ); // Unqualified tag name mut_repo.set_git_ref_target("refs/tags/tag", RefTarget::normal(commit4.id().clone())); assert_eq!( - resolve_symbol(mut_repo, "tag", None).unwrap(), + resolve_symbol(mut_repo, "tag").unwrap(), vec![commit4.id().clone()] ); @@ -747,11 +709,11 @@ fn test_resolve_symbol_git_refs() { RefTarget::normal(commit2.id().clone()), ); assert_eq!( - resolve_symbol(mut_repo, "origin/remote-branch", None).unwrap(), + resolve_symbol(mut_repo, "origin/remote-branch").unwrap(), vec![commit2.id().clone()] ); - // Cannot shadow checkout ("@") or root symbols + // Cannot shadow root symbols let ws_id = WorkspaceId::default(); mut_repo .set_wc_commit(ws_id.clone(), commit1.id().clone()) @@ -759,17 +721,13 @@ fn test_resolve_symbol_git_refs() { mut_repo.set_git_ref_target("@", RefTarget::normal(commit2.id().clone())); mut_repo.set_git_ref_target("root", RefTarget::normal(commit3.id().clone())); assert_eq!( - resolve_symbol(mut_repo, "@", Some(&ws_id)).unwrap(), - vec![mut_repo.view().get_wc_commit_id(&ws_id).unwrap().clone()] - ); - assert_eq!( - resolve_symbol(mut_repo, "root", None).unwrap(), + resolve_symbol(mut_repo, "root").unwrap(), vec![mut_repo.store().root_commit().id().clone()] ); // Conflicted ref resolves to its "adds" assert_eq!( - resolve_symbol(mut_repo, "refs/heads/conflicted", None).unwrap(), + resolve_symbol(mut_repo, "refs/heads/conflicted").unwrap(), vec![commit1.id().clone(), commit3.id().clone()] ); } @@ -785,7 +743,7 @@ fn resolve_commit_ids(repo: &dyn Repo, revset_str: &str) -> Vec { ) .unwrap(), ); - let symbol_resolver = DefaultSymbolResolver::new(repo, None); + let symbol_resolver = DefaultSymbolResolver::new(repo); let expression = expression .resolve_user_expression(repo, &symbol_resolver) .unwrap(); @@ -813,7 +771,7 @@ fn resolve_commit_ids_in_workspace( ) .unwrap(), ); - let symbol_resolver = DefaultSymbolResolver::new(repo, Some(workspace_ctx.workspace_id)); + let symbol_resolver = DefaultSymbolResolver::new(repo); let expression = expression .resolve_user_expression(repo, &symbol_resolver) .unwrap(); @@ -2860,9 +2818,9 @@ fn test_no_such_revision_suggestion() { ); } - assert_matches!(resolve_symbol(mut_repo, "bar", None), Ok(_)); + assert_matches!(resolve_symbol(mut_repo, "bar"), Ok(_)); assert_matches!( - resolve_symbol(mut_repo, "bax", None), + resolve_symbol(mut_repo, "bax"), Err(RevsetResolutionError::NoSuchRevision { name, candidates }) if name == "bax" && candidates == vec!["bar".to_string(), "baz".to_string()] );