Merge "Allow plugins to define change search operators."
This commit is contained in:
commit
9f9e624038
@ -586,6 +586,48 @@ $ ssh -p 29418 review.example.com sh ls
|
||||
$ ssh -p 29418 review.example.com sh ps
|
||||
----
|
||||
|
||||
[[search_operators]]
|
||||
=== Search Operators ===
|
||||
|
||||
Plugins can define new search operators to extend change searching by
|
||||
implementing the `ChangeQueryBuilder.ChangeOperatorFactory` interface
|
||||
and registering it to an operator name in the plugin module's
|
||||
`configure()` method. The search operator name is defined during
|
||||
registration via the DynamicMap annotation mechanism. The plugin
|
||||
name will get appended to the annotated name, with an underscore
|
||||
in between, leading to the final operator name. An example
|
||||
registration looks like this:
|
||||
|
||||
bind(ChangeOperatorFactory.class)
|
||||
.annotatedWith(Exports.named("sample"))
|
||||
.to(SampleOperator.class);
|
||||
|
||||
If this is registered in the `myplugin` plugin, then the resulting
|
||||
operator will be named `sample_myplugin`.
|
||||
|
||||
The search operator itself is implemented by ensuring that the
|
||||
`create()` method of the class implementing the
|
||||
`ChangeQueryBuilder.ChangeOperatorFactory` interface returns a
|
||||
`Predicate<ChangeData>`. Here is a sample operator factory
|
||||
defintion which creates a `MyPredicate`:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Singleton
|
||||
public class SampleOperator
|
||||
implements ChangeQueryBuilder.ChangeOperatorFactory {
|
||||
public static class MyPredicate extends OperatorPredicate<ChangeData> {
|
||||
...
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<ChangeData> create(ChangeQueryBuilder builder, String value)
|
||||
throws QueryParseException {
|
||||
return new MyPredicate(value);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
[[simple-configuration]]
|
||||
== Simple Configuration in `gerrit.config`
|
||||
|
||||
|
@ -125,6 +125,7 @@ import com.google.gerrit.server.project.ProjectNode;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.project.SectionSortCache;
|
||||
import com.google.gerrit.server.query.change.ChangeData;
|
||||
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
|
||||
import com.google.gerrit.server.query.change.ConflictsCacheImpl;
|
||||
import com.google.gerrit.server.ssh.SshAddressesModule;
|
||||
import com.google.gerrit.server.tools.ToolsCatalog;
|
||||
@ -299,6 +300,8 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
factory(UploadValidators.Factory.class);
|
||||
DynamicSet.setOf(binder(), UploadValidationListener.class);
|
||||
|
||||
DynamicMap.mapOf(binder(), ChangeQueryBuilder.ChangeOperatorFactory.class);
|
||||
|
||||
bind(AnonymousUser.class);
|
||||
|
||||
factory(CommitValidators.Factory.class);
|
||||
|
@ -73,6 +73,11 @@ import java.util.Map;
|
||||
* @param <T> type of object the predicates can evaluate in memory.
|
||||
*/
|
||||
public abstract class QueryBuilder<T> {
|
||||
/** Converts a value string passed to an operator into a {@link Predicate}. */
|
||||
public interface OperatorFactory<T, Q extends QueryBuilder<T>> {
|
||||
Predicate<T> create(Q builder, String value) throws QueryParseException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the operators known by a QueryBuilder.
|
||||
*
|
||||
@ -162,7 +167,7 @@ public abstract class QueryBuilder<T> {
|
||||
protected final Definition<T, ? extends QueryBuilder<T>> builderDef;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final Map<String, OperatorFactory> opFactories;
|
||||
protected final Map<String, OperatorFactory> opFactories;
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
protected QueryBuilder(Definition<T, ? extends QueryBuilder<T>> def) {
|
||||
@ -323,11 +328,6 @@ public abstract class QueryBuilder<T> {
|
||||
return new QueryParseException(msg, why);
|
||||
}
|
||||
|
||||
/** Converts a value string passed to an operator into a {@link Predicate}. */
|
||||
protected interface OperatorFactory<T, Q extends QueryBuilder<T>> {
|
||||
Predicate<T> create(Q builder, String value) throws QueryParseException;
|
||||
}
|
||||
|
||||
/** Denotes a method which is a query operator. */
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
|
@ -21,6 +21,7 @@ import com.google.common.base.Optional;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.errors.NotSignedInException;
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.client.Branch;
|
||||
@ -55,6 +56,7 @@ import com.google.gerrit.server.project.ListChildProjects;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.query.Predicate;
|
||||
import com.google.gerrit.server.query.QueryBuilder;
|
||||
import com.google.gerrit.server.query.QueryBuilder.OperatorFactory;
|
||||
import com.google.gerrit.server.query.QueryParseException;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
@ -70,6 +72,7 @@ import org.eclipse.jgit.lib.Repository;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -80,6 +83,10 @@ import java.util.regex.Pattern;
|
||||
* Parses a query string meant to be applied to change objects.
|
||||
*/
|
||||
public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
public interface ChangeOperatorFactory
|
||||
extends OperatorFactory<ChangeData, ChangeQueryBuilder> {
|
||||
}
|
||||
|
||||
private static final Pattern PAT_LEGACY_ID = Pattern.compile("^[1-9][0-9]*$");
|
||||
private static final Pattern PAT_CHANGE_ID =
|
||||
Pattern.compile("^[iI][0-9a-f]{4,}.*$");
|
||||
@ -145,6 +152,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
final Provider<ReviewDb> db;
|
||||
final Provider<InternalChangeQuery> queryProvider;
|
||||
final IndexRewriter rewriter;
|
||||
final DynamicMap<ChangeOperatorFactory> opFactories;
|
||||
final IdentifiedUser.GenericFactory userFactory;
|
||||
final CapabilityControl.Factory capabilityControlFactory;
|
||||
final ChangeControl.GenericFactory changeControlGenericFactory;
|
||||
@ -172,6 +180,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
public Arguments(Provider<ReviewDb> db,
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
IndexRewriter rewriter,
|
||||
DynamicMap<ChangeOperatorFactory> opFactories,
|
||||
IdentifiedUser.GenericFactory userFactory,
|
||||
Provider<CurrentUser> self,
|
||||
CapabilityControl.Factory capabilityControlFactory,
|
||||
@ -192,7 +201,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
ConflictsCache conflictsCache,
|
||||
TrackingFooters trackingFooters,
|
||||
@GerritServerConfig Config cfg) {
|
||||
this(db, queryProvider, rewriter, userFactory, self,
|
||||
this(db, queryProvider, rewriter, opFactories, userFactory, self,
|
||||
capabilityControlFactory, changeControlGenericFactory,
|
||||
changeDataFactory, fillArgs, plcUtil, accountResolver, groupBackend,
|
||||
allProjectsName, allUsersName, patchListCache, repoManager,
|
||||
@ -206,6 +215,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
Provider<ReviewDb> db,
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
IndexRewriter rewriter,
|
||||
DynamicMap<ChangeOperatorFactory> opFactories,
|
||||
IdentifiedUser.GenericFactory userFactory,
|
||||
Provider<CurrentUser> self,
|
||||
CapabilityControl.Factory capabilityControlFactory,
|
||||
@ -229,6 +239,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
this.db = db;
|
||||
this.queryProvider = queryProvider;
|
||||
this.rewriter = rewriter;
|
||||
this.opFactories = opFactories;
|
||||
this.userFactory = userFactory;
|
||||
this.self = self;
|
||||
this.capabilityControlFactory = capabilityControlFactory;
|
||||
@ -252,7 +263,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
}
|
||||
|
||||
Arguments asUser(CurrentUser otherUser) {
|
||||
return new Arguments(db, queryProvider, rewriter, userFactory,
|
||||
return new Arguments(db, queryProvider, rewriter, opFactories, userFactory,
|
||||
Providers.of(otherUser),
|
||||
capabilityControlFactory, changeControlGenericFactory,
|
||||
changeDataFactory, fillArgs, plcUtil, accountResolver, groupBackend,
|
||||
@ -304,6 +315,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
ChangeQueryBuilder(Arguments args) {
|
||||
super(mydef);
|
||||
this.args = args;
|
||||
setupDynamicOperators();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@ -314,6 +326,13 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
private void setupDynamicOperators() {
|
||||
for (DynamicMap.Entry<ChangeOperatorFactory> e : args.opFactories) {
|
||||
String name = e.getExportName() + "_" + e.getPluginName();
|
||||
opFactories.put(name, e.getProvider().get());
|
||||
}
|
||||
}
|
||||
|
||||
public ChangeQueryBuilder asUser(CurrentUser user) {
|
||||
return new ChangeQueryBuilder(builderDef, args.asUser(user));
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ public class FakeQueryBuilder extends ChangeQueryBuilder {
|
||||
FakeQueryBuilder.class),
|
||||
new ChangeQueryBuilder.Arguments(null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, indexes, null, null, null, null));
|
||||
null, null, indexes, null, null, null, null));
|
||||
}
|
||||
|
||||
@Operator
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 2efae2e9ade87f5c4fc303db64e0ea643d17367d
|
||||
Subproject commit 1b41f7a615ea4eca37878f9945ec820f95885755
|
Loading…
Reference in New Issue
Block a user