summaryrefslogtreecommitdiffstats
path: root/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java')
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java248
1 files changed, 176 insertions, 72 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
index a975f1b85b..a2fa7fe34c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
@@ -14,17 +14,20 @@
package com.google.gerrit.server.query.change;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.events.ChangeAttribute;
import com.google.gerrit.server.events.EventFactory;
+import com.google.gerrit.server.events.PatchSetAttribute;
import com.google.gerrit.server.events.QueryStats;
+import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.query.Predicate;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gson.Gson;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -64,12 +67,17 @@ public class QueryProcessor {
private final ChangeQueryBuilder queryBuilder;
private final ChangeQueryRewriter queryRewriter;
private final Provider<ReviewDb> db;
+ private final GitRepositoryManager repoManager;
+ private final int maxLimit;
- private int defaultLimit = 500;
private OutputFormat outputFormat = OutputFormat.TEXT;
private boolean includePatchSets;
private boolean includeCurrentPatchSet;
private boolean includeApprovals;
+ private boolean includeComments;
+ private boolean includeFiles;
+ private boolean includeCommitMessage;
+ private boolean includeDependencies;
private OutputStream outputStream = DisabledOutputStream.INSTANCE;
private PrintWriter out;
@@ -77,87 +85,147 @@ public class QueryProcessor {
@Inject
QueryProcessor(EventFactory eventFactory,
ChangeQueryBuilder.Factory queryBuilder, CurrentUser currentUser,
- ChangeQueryRewriter queryRewriter, Provider<ReviewDb> db) {
+ ChangeQueryRewriter queryRewriter, Provider<ReviewDb> db,
+ GitRepositoryManager repoManager) {
this.eventFactory = eventFactory;
this.queryBuilder = queryBuilder.create(currentUser);
this.queryRewriter = queryRewriter;
this.db = db;
+ this.repoManager = repoManager;
+ this.maxLimit = currentUser.getCapabilities()
+ .getRange(GlobalCapability.QUERY_LIMIT)
+ .getMax();
}
public void setIncludePatchSets(boolean on) {
includePatchSets = on;
}
+ public boolean getIncludePatchSets() {
+ return includePatchSets;
+ }
+
public void setIncludeCurrentPatchSet(boolean on) {
includeCurrentPatchSet = on;
}
+ public boolean getIncludeCurrentPatchSet() {
+ return includeCurrentPatchSet;
+ }
+
public void setIncludeApprovals(boolean on) {
includeApprovals = on;
}
+ public void setIncludeComments(boolean on) {
+ includeComments = on;
+ }
+
+ public void setIncludeFiles(boolean on) {
+ includeFiles = on;
+ }
+
+ public boolean getIncludeFiles() {
+ return includeFiles;
+ }
+
+ public void setIncludeDependencies(boolean on) {
+ includeDependencies = on;
+ }
+
+ public boolean getIncludeDependencies() {
+ return includeDependencies;
+ }
+
+ public void setIncludeCommitMessage(boolean on) {
+ includeCommitMessage = on;
+ }
+
public void setOutput(OutputStream out, OutputFormat fmt) {
this.outputStream = out;
this.outputFormat = fmt;
}
+ public List<ChangeData> queryChanges(final String queryString)
+ throws OrmException, QueryParseException {
+ final Predicate<ChangeData> visibleToMe = queryBuilder.is_visible();
+ Predicate<ChangeData> s = compileQuery(queryString, visibleToMe);
+ List<ChangeData> results = new ArrayList<ChangeData>();
+ HashSet<Change.Id> want = new HashSet<Change.Id>();
+ for (ChangeData d : ((ChangeDataSource) s).read()) {
+ if (d.hasChange()) {
+ // Checking visibleToMe here should be unnecessary, the
+ // query should have already performed it. But we don't
+ // want to trust the query rewriter that much yet.
+ //
+ if (visibleToMe.match(d)) {
+ results.add(d);
+ }
+ } else {
+ want.add(d.getId());
+ }
+ }
+
+ if (!want.isEmpty()) {
+ for (Change c : db.get().changes().get(want)) {
+ ChangeData d = new ChangeData(c);
+ if (visibleToMe.match(d)) {
+ results.add(d);
+ }
+ }
+ }
+
+ Collections.sort(results, new Comparator<ChangeData>() {
+ @Override
+ public int compare(ChangeData a, ChangeData b) {
+ return b.getChange().getSortKey().compareTo(
+ a.getChange().getSortKey());
+ }
+ });
+
+ int limit = limit(s);
+ if (limit < results.size()) {
+ results = results.subList(0, limit);
+ }
+
+ return results;
+ }
+
public void query(String queryString) throws IOException {
out = new PrintWriter( //
new BufferedWriter( //
new OutputStreamWriter(outputStream, "UTF-8")));
try {
+ if (maxLimit <= 0) {
+ ErrorMessage m = new ErrorMessage();
+ m.message = "query disabled";
+ show(m);
+ return;
+ }
+
try {
final QueryStats stats = new QueryStats();
stats.runTimeMilliseconds = System.currentTimeMillis();
- final Predicate<ChangeData> visibleToMe = queryBuilder.is_visible();
- Predicate<ChangeData> s = compileQuery(queryString, visibleToMe);
- List<ChangeData> results = new ArrayList<ChangeData>();
- HashSet<Change.Id> want = new HashSet<Change.Id>();
- for (ChangeData d : ((ChangeDataSource) s).read()) {
- if (d.hasChange()) {
- // Checking visibleToMe here should be unnecessary, the
- // query should have already performed it. But we don't
- // want to trust the query rewriter that much yet.
- //
- if (visibleToMe.match(d)) {
- results.add(d);
- }
- } else {
- want.add(d.getId());
- }
- }
-
- if (!want.isEmpty()) {
- for (Change c : db.get().changes().get(want)) {
- ChangeData d = new ChangeData(c);
- if (visibleToMe.match(d)) {
- results.add(d);
- }
- }
- }
-
- Collections.sort(results, new Comparator<ChangeData>() {
- @Override
- public int compare(ChangeData a, ChangeData b) {
- return b.getChange().getSortKey().compareTo(
- a.getChange().getSortKey());
- }
- });
-
- int limit = limit(s);
- if (limit < results.size()) {
- results = results.subList(0, limit);
- }
-
+ List<ChangeData> results = queryChanges(queryString);
for (ChangeData d : results) {
ChangeAttribute c = eventFactory.asChangeAttribute(d.getChange());
eventFactory.extend(c, d.getChange());
eventFactory.addTrackingIds(c, d.trackingIds(db));
+ if (includeCommitMessage) {
+ eventFactory.addCommitMessage(c, d.commitMessage(repoManager, db));
+ }
+
if (includePatchSets) {
- eventFactory.addPatchSets(c, d.patches(db),
- includeApprovals ? d.approvalsMap(db) : null);
+ if (includeFiles) {
+ eventFactory.addPatchSets(c, d.patches(db),
+ includeApprovals ? d.approvalsMap(db) : null,
+ includeFiles, d.change(db));
+ } else {
+ eventFactory.addPatchSets(c, d.patches(db),
+ includeApprovals ? d.approvalsMap(db) : null);
+ }
}
if (includeCurrentPatchSet) {
@@ -166,9 +234,27 @@ public class QueryProcessor {
c.currentPatchSet = eventFactory.asPatchSetAttribute(current);
eventFactory.addApprovals(c.currentPatchSet, //
d.approvalsFor(db, current.getId()));
+
+ if (includeFiles) {
+ eventFactory.addPatchSetFileNames(c.currentPatchSet,
+ d.change(db), d.currentPatchSet(db));
+ }
}
}
+ if (includeComments) {
+ eventFactory.addComments(c, d.messages(db));
+ if (includePatchSets) {
+ for (PatchSetAttribute attribute : c.patchSets) {
+ eventFactory.addPatchSetComments(attribute, d.comments(db));
+ }
+ }
+ }
+
+ if (includeDependencies) {
+ eventFactory.addDependencies(c, d.getChange());
+ }
+
show(c);
}
@@ -198,7 +284,7 @@ public class QueryProcessor {
}
private int limit(Predicate<ChangeData> s) {
- return queryBuilder.hasLimit(s) ? queryBuilder.getLimit(s) : defaultLimit;
+ return queryBuilder.hasLimit(s) ? queryBuilder.getLimit(s) : maxLimit;
}
@SuppressWarnings("unchecked")
@@ -206,13 +292,10 @@ public class QueryProcessor {
final Predicate<ChangeData> visibleToMe) throws QueryParseException {
Predicate<ChangeData> q = queryBuilder.parse(queryString);
- if (!queryBuilder.hasLimit(q)) {
- q = Predicate.and(q, queryBuilder.limit(defaultLimit));
- }
if (!queryBuilder.hasSortKey(q)) {
q = Predicate.and(q, queryBuilder.sortkey_before("z"));
}
- q = Predicate.and(q, visibleToMe);
+ q = Predicate.and(q, queryBuilder.limit(maxLimit), visibleToMe);
Predicate<ChangeData> s = queryRewriter.rewrite(q);
if (!(s instanceof ChangeDataSource)) {
@@ -262,42 +345,61 @@ public class QueryProcessor {
continue;
}
- indent(depth);
- out.print(f.getName());
- out.print(":");
-
- if (val instanceof Long && isDateField(f.getName())) {
- out.print(' ');
- out.print(sdf.format(new Date(((Long) val) * 1000L)));
- out.print('\n');
- } else {
- showTextValue(val, depth);
- }
+ showField(f.getName(), val, depth);
}
}
- private void indent(int depth) {
- for (int i = 0; i < depth; i++) {
- out.print(" ");
+ private String indent(int spaces) {
+ if (spaces == 0) {
+ return "";
+ } else {
+ return String.format("%" + spaces + "s", " ");
}
}
- private void showTextValue(Object value, int depth) {
- if (isPrimitive(value)) {
+ private void showField(String field, Object value, int depth) {
+ final int spacesDepthRatio = 2;
+ String indent = indent(depth * spacesDepthRatio);
+ out.print(indent);
+ out.print(field);
+ out.print(':');
+ if (value instanceof String && ((String) value).contains("\n")) {
+ out.print(' ');
+ // Idention for multi-line text is
+ // current depth indetion + length of field + length of ": "
+ indent = indent(indent.length() + field.length() + spacesDepthRatio);
+ out.print(((String) value).replaceAll("\n", "\n" + indent).trim());
+ out.print('\n');
+ } else if (value instanceof Long && isDateField(field)) {
+ out.print(' ');
+ out.print(sdf.format(new Date(((Long) value) * 1000L)));
+ out.print('\n');
+ } else if (isPrimitive(value)) {
out.print(' ');
out.print(value);
out.print('\n');
-
} else if (value instanceof Collection) {
out.print('\n');
+ boolean firstElement = true;
for (Object thing : ((Collection<?>) value)) {
+ // The name of the collection was initially printed at the beginning
+ // of this routine. Beginning at the second sub-element, reprint
+ // the collection name so humans can separate individual elements
+ // with less strain and error.
+ //
+ if (firstElement) {
+ firstElement = false;
+ } else {
+ out.print(indent);
+ out.print(field);
+ out.print(":\n");
+ }
if (isPrimitive(thing)) {
out.print(' ');
out.print(value);
out.print('\n');
} else {
showText(thing, depth + 1);
- out.print('\n');
}
}
} else {
@@ -315,7 +417,9 @@ public class QueryProcessor {
private static boolean isDateField(String name) {
return "lastUpdated".equals(name) //
- || "grantedOn".equals(name);
+ || "grantedOn".equals(name) //
+ || "timestamp".equals(name) //
+ || "createdOn".equals(name);
}
private List<Field> fieldsOf(Class<?> type) {