diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt index 51dc38e5ff..d596730452 100644 --- a/Documentation/user-search.txt +++ b/Documentation/user-search.txt @@ -317,6 +317,10 @@ E.g. a change that touches a file in the directory 'a/b/c' matches for 'a/b/c', + Slash ('/') is used path separator. Leading and trailing slashes are allowed but are not mandatory. ++ +If 'DIR' starts with `^` it matches directories and directory segments by +regular expression. The link:http://www.brics.dk/automaton/[dk.brics.automaton +library] is used for evaluation of such patterns. [[footer]] footer:'FOOTER':: diff --git a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java index 33e1575767..b62a1d71b4 100644 --- a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java +++ b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java @@ -781,6 +781,10 @@ public class ChangeQueryBuilder extends QueryBuilder { @Operator public Predicate directory(String directory) throws QueryParseException { if (args.getSchema().hasField(ChangeField.DIRECTORY)) { + if (directory.startsWith("^")) { + return new RegexDirectoryPredicate(directory); + } + return new DirectoryPredicate(directory); } throw new QueryParseException("'directory' operator is not supported by change index version"); diff --git a/java/com/google/gerrit/server/query/change/RegexDirectoryPredicate.java b/java/com/google/gerrit/server/query/change/RegexDirectoryPredicate.java new file mode 100644 index 0000000000..1d49f1e113 --- /dev/null +++ b/java/com/google/gerrit/server/query/change/RegexDirectoryPredicate.java @@ -0,0 +1,48 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// 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 +// +// http://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. + +package com.google.gerrit.server.query.change; + +import com.google.gerrit.server.index.change.ChangeField; +import com.google.gwtorm.server.OrmException; +import dk.brics.automaton.RegExp; +import dk.brics.automaton.RunAutomaton; + +public class RegexDirectoryPredicate extends ChangeRegexPredicate { + protected final RunAutomaton pattern; + + public RegexDirectoryPredicate(String re) { + super(ChangeField.DIRECTORY, re); + + if (re.startsWith("^")) { + re = re.substring(1); + } + + if (re.endsWith("$") && !re.endsWith("\\$")) { + re = re.substring(0, re.length() - 1); + } + + this.pattern = new RunAutomaton(new RegExp(re).toAutomaton()); + } + + @Override + public boolean match(ChangeData cd) throws OrmException { + return ChangeField.getDirectories(cd).stream().anyMatch(pattern::run); + } + + @Override + public int getCost() { + return 1; + } +} diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java index 06deb9da52..7872a82784 100644 --- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java +++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java @@ -1581,6 +1581,11 @@ public abstract class AbstractQueryChangesTest extends GerritServerTests { assertQuery("directory:/b/c", change5); assertQuery("directory:/b/c/", change5); assertQuery("directory:b/c/", change5); + + // match by regexp + assertQuery("directory:^.*va.*", change2); + assertQuery("directory:^documentation/.*/slides", change3); + assertQuery("directory:^train.*", change3); } @Test