Simplify patch display to a single RPC
A long time ago I thought it might make sense to make the RPCs for patch display two parts. The first part was a static patchScript that only returns the file content, and thus could be infinitely cacheable on edge proxies because the content never changes. The second part was supposed to be a dynamic comment list, showing the current comments in the file. This didn't really work out. The static patchScript code actually had to know what comments existed at display time, in order to ensure sufficient context lines were packaged for the client. I also never got around to teaching gwtjsonrpc how to perform cached GET requests. Even if we did, access control rules within a project could change the READ permission from being public readable to being private, which would mean edge proxies might still had that private data. As it turns out, we can simplify the entire code base by putting the two together as a single RPC. We no longer need to perform an RPC join in order to display the result in PatchScreen, and we can cut in half the number of database queries required, as we used to be doing the comment loading work twice per screen display. Change-Id: Ic1a129ff507da0bbe97ca03ce31c566981ed3855 Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
parent
3c7c33d01a
commit
31e7c6d4d8
|
@ -14,7 +14,6 @@
|
|||
|
||||
package com.google.gerrit.common.data;
|
||||
|
||||
import com.google.gerrit.reviewdb.Patch;
|
||||
import com.google.gerrit.reviewdb.PatchLineComment;
|
||||
import com.google.gerrit.reviewdb.PatchSet;
|
||||
|
||||
|
@ -25,9 +24,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
public class CommentDetail {
|
||||
protected List<PatchLineComment> commentsA;
|
||||
protected List<PatchLineComment> commentsB;
|
||||
protected List<Patch> history;
|
||||
protected List<PatchLineComment> a;
|
||||
protected List<PatchLineComment> b;
|
||||
protected AccountInfoCache accounts;
|
||||
|
||||
private transient PatchSet.Id idA;
|
||||
|
@ -35,12 +33,11 @@ public class CommentDetail {
|
|||
private transient Map<Integer, List<PatchLineComment>> forA;
|
||||
private transient Map<Integer, List<PatchLineComment>> forB;
|
||||
|
||||
public CommentDetail(final PatchSet.Id a, final PatchSet.Id b) {
|
||||
commentsA = new ArrayList<PatchLineComment>();
|
||||
commentsB = new ArrayList<PatchLineComment>();
|
||||
|
||||
idA = a;
|
||||
idB = b;
|
||||
public CommentDetail(final PatchSet.Id idA, final PatchSet.Id idB) {
|
||||
this.a = new ArrayList<PatchLineComment>();
|
||||
this.b = new ArrayList<PatchLineComment>();
|
||||
this.idA = idA;
|
||||
this.idB = idB;
|
||||
}
|
||||
|
||||
protected CommentDetail() {
|
||||
|
@ -51,19 +48,19 @@ public class CommentDetail {
|
|||
switch (p.getSide()) {
|
||||
case 0:
|
||||
if (idA == null && idB.equals(psId)) {
|
||||
commentsA.add(p);
|
||||
a.add(p);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (idA != null && idA.equals(psId)) {
|
||||
commentsA.add(p);
|
||||
a.add(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (idB.equals(psId)) {
|
||||
commentsB.add(p);
|
||||
b.add(p);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -75,28 +72,20 @@ public class CommentDetail {
|
|||
accounts = a;
|
||||
}
|
||||
|
||||
public void setHistory(final List<Patch> h) {
|
||||
history = h;
|
||||
}
|
||||
|
||||
public AccountInfoCache getAccounts() {
|
||||
return accounts;
|
||||
}
|
||||
|
||||
public List<Patch> getHistory() {
|
||||
return history;
|
||||
}
|
||||
|
||||
public List<PatchLineComment> getCommentsA() {
|
||||
return commentsA;
|
||||
return a;
|
||||
}
|
||||
|
||||
public List<PatchLineComment> getCommentsB() {
|
||||
return commentsB;
|
||||
return b;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return commentsA.isEmpty() && commentsB.isEmpty();
|
||||
return a.isEmpty() && b.isEmpty();
|
||||
}
|
||||
|
||||
public List<PatchLineComment> getForA(final int lineNbr) {
|
||||
|
@ -104,7 +93,7 @@ public class CommentDetail {
|
|||
return Collections.emptyList();
|
||||
}
|
||||
if (forA == null) {
|
||||
forA = index(commentsA);
|
||||
forA = index(a);
|
||||
}
|
||||
return get(forA, lineNbr);
|
||||
}
|
||||
|
@ -114,7 +103,7 @@ public class CommentDetail {
|
|||
return Collections.emptyList();
|
||||
}
|
||||
if (forB == null) {
|
||||
forB = index(commentsB);
|
||||
forB = index(b);
|
||||
}
|
||||
return get(forB, lineNbr);
|
||||
}
|
||||
|
|
|
@ -36,9 +36,6 @@ public interface PatchDetailService extends RemoteJsonService {
|
|||
void patchScript(Patch.Key key, PatchSet.Id a, PatchSet.Id b,
|
||||
PatchScriptSettings settings, AsyncCallback<PatchScript> callback);
|
||||
|
||||
void patchComments(Patch.Key key, PatchSet.Id a, PatchSet.Id b,
|
||||
AsyncCallback<CommentDetail> callback);
|
||||
|
||||
@SignInRequired
|
||||
void saveDraft(PatchLineComment comment,
|
||||
AsyncCallback<PatchLineComment> callback);
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.google.gerrit.prettify.common.PrettySettings;
|
|||
import com.google.gerrit.prettify.common.SparseFileContent;
|
||||
import com.google.gerrit.prettify.common.SparseHtmlFile;
|
||||
import com.google.gerrit.reviewdb.Change;
|
||||
import com.google.gerrit.reviewdb.Patch;
|
||||
|
||||
import org.eclipse.jgit.diff.Edit;
|
||||
|
||||
|
@ -40,11 +41,13 @@ public class PatchScript {
|
|||
protected List<Edit> edits;
|
||||
protected DisplayMethod displayMethodA;
|
||||
protected DisplayMethod displayMethodB;
|
||||
protected CommentDetail comments;
|
||||
protected List<Patch> history;
|
||||
|
||||
public PatchScript(final Change.Key ck, final List<String> h,
|
||||
final PatchScriptSettings s, final SparseFileContent ca,
|
||||
final SparseFileContent cb, final List<Edit> e, final DisplayMethod ma,
|
||||
final DisplayMethod mb) {
|
||||
final DisplayMethod mb, final CommentDetail cd, final List<Patch> hist) {
|
||||
changeId = ck;
|
||||
header = h;
|
||||
settings = s;
|
||||
|
@ -53,6 +56,8 @@ public class PatchScript {
|
|||
edits = e;
|
||||
displayMethodA = ma;
|
||||
displayMethodB = mb;
|
||||
comments = cd;
|
||||
history = hist;
|
||||
}
|
||||
|
||||
protected PatchScript() {
|
||||
|
@ -74,6 +79,14 @@ public class PatchScript {
|
|||
return header;
|
||||
}
|
||||
|
||||
public CommentDetail getCommentDetail() {
|
||||
return comments;
|
||||
}
|
||||
|
||||
public List<Patch> getHistory() {
|
||||
return history;
|
||||
}
|
||||
|
||||
public int getContext() {
|
||||
return settings.getContext();
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@ import com.google.gerrit.client.changes.ChangeScreen;
|
|||
import com.google.gerrit.client.changes.PatchTable;
|
||||
import com.google.gerrit.client.changes.Util;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.client.rpc.ScreenLoadCallback;
|
||||
import com.google.gerrit.client.ui.ChangeLink;
|
||||
import com.google.gerrit.client.ui.InlineHyperlink;
|
||||
import com.google.gerrit.client.ui.Screen;
|
||||
import com.google.gerrit.common.PageLinks;
|
||||
import com.google.gerrit.common.data.CommentDetail;
|
||||
import com.google.gerrit.common.data.PatchScript;
|
||||
import com.google.gerrit.common.data.PatchScriptSettings;
|
||||
import com.google.gerrit.common.data.PatchSetDetail;
|
||||
|
@ -138,8 +138,6 @@ public abstract class PatchScreen extends Screen {
|
|||
private AbstractPatchContentTable contentTable;
|
||||
|
||||
private int rpcSequence;
|
||||
private PatchScript script;
|
||||
private CommentDetail comments;
|
||||
|
||||
/** The index of the file we are currently looking at among the fileList */
|
||||
private int patchIndex;
|
||||
|
@ -405,15 +403,12 @@ public abstract class PatchScreen extends Screen {
|
|||
|
||||
protected void refresh(final boolean isFirst) {
|
||||
final int rpcseq = ++rpcSequence;
|
||||
script = null;
|
||||
comments = null;
|
||||
|
||||
PatchUtil.DETAIL_SVC.patchScript(patchKey, idSideA, idSideB,
|
||||
scriptSettings, new GerritCallback<PatchScript>() {
|
||||
public void onSuccess(final PatchScript result) {
|
||||
scriptSettings, new ScreenLoadCallback<PatchScript>(this) {
|
||||
@Override
|
||||
protected void preDisplay(final PatchScript result) {
|
||||
if (rpcSequence == rpcseq) {
|
||||
script = result;
|
||||
onResult(isFirst);
|
||||
onResult(result, isFirst);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -424,83 +419,54 @@ public abstract class PatchScreen extends Screen {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
PatchUtil.DETAIL_SVC.patchComments(patchKey, idSideA, idSideB,
|
||||
new GerritCallback<CommentDetail>() {
|
||||
public void onSuccess(final CommentDetail result) {
|
||||
if (rpcSequence == rpcseq) {
|
||||
comments = result;
|
||||
onResult(isFirst);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
// Ignore no such entity, the patch script RPC above would
|
||||
// also notice the problem and report it.
|
||||
//
|
||||
if (!isNoSuchEntity(caught) && rpcSequence == rpcseq) {
|
||||
super.onFailure(caught);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onResult(final boolean isFirst) {
|
||||
if (script != null && comments != null) {
|
||||
final Change.Key cid = script.getChangeId();
|
||||
final String path = patchKey.get();
|
||||
String fileName = path;
|
||||
final int last = fileName.lastIndexOf('/');
|
||||
if (last >= 0) {
|
||||
fileName = fileName.substring(last + 1);
|
||||
}
|
||||
private void onResult(final PatchScript script, final boolean isFirst) {
|
||||
final Change.Key cid = script.getChangeId();
|
||||
final String path = patchKey.get();
|
||||
String fileName = path;
|
||||
final int last = fileName.lastIndexOf('/');
|
||||
if (last >= 0) {
|
||||
fileName = fileName.substring(last + 1);
|
||||
}
|
||||
|
||||
setWindowTitle(PatchUtil.M.patchWindowTitle(cid.abbreviate(), fileName));
|
||||
setPageTitle(PatchUtil.M.patchPageTitle(cid.abbreviate(), path));
|
||||
setWindowTitle(PatchUtil.M.patchWindowTitle(cid.abbreviate(), fileName));
|
||||
setPageTitle(PatchUtil.M.patchPageTitle(cid.abbreviate(), path));
|
||||
|
||||
historyTable.display(comments.getHistory());
|
||||
historyPanel.setVisible(true);
|
||||
historyTable.display(script.getHistory());
|
||||
historyPanel.setVisible(true);
|
||||
|
||||
// True if there are differences between the two patch sets
|
||||
boolean hasEdits = !script.getEdits().isEmpty();
|
||||
// True if this change is a mode change or a pure rename/copy
|
||||
boolean hasMeta = !script.getPatchHeader().isEmpty();
|
||||
// True if there are differences between the two patch sets
|
||||
boolean hasEdits = !script.getEdits().isEmpty();
|
||||
// True if this change is a mode change or a pure rename/copy
|
||||
boolean hasMeta = !script.getPatchHeader().isEmpty();
|
||||
|
||||
boolean hasDifferences = hasEdits || hasMeta;
|
||||
boolean pureMetaChange = !hasEdits && hasMeta;
|
||||
boolean hasDifferences = hasEdits || hasMeta;
|
||||
boolean pureMetaChange = !hasEdits && hasMeta;
|
||||
|
||||
if (contentTable instanceof SideBySideTable && pureMetaChange) {
|
||||
// User asked for SideBySide (or a link guessed, wrong) and we can't
|
||||
// show a binary or pure-rename change there accurately. Switch to
|
||||
// the unified view instead.
|
||||
//
|
||||
contentTable.removeFromParent();
|
||||
contentTable = new UnifiedDiffTable();
|
||||
contentTable.fileList = fileList;
|
||||
contentPanel.add(contentTable);
|
||||
setToken(Dispatcher.toPatchUnified(patchKey));
|
||||
}
|
||||
if (contentTable instanceof SideBySideTable && pureMetaChange) {
|
||||
// User asked for SideBySide (or a link guessed, wrong) and we can't
|
||||
// show a binary or pure-rename change there accurately. Switch to
|
||||
// the unified view instead.
|
||||
//
|
||||
contentTable.removeFromParent();
|
||||
contentTable = new UnifiedDiffTable();
|
||||
contentTable.fileList = fileList;
|
||||
contentPanel.add(contentTable);
|
||||
setToken(Dispatcher.toPatchUnified(patchKey));
|
||||
}
|
||||
|
||||
if (hasDifferences) {
|
||||
contentTable.display(patchKey, idSideA, idSideB, script);
|
||||
contentTable.display(comments);
|
||||
contentTable.finishDisplay();
|
||||
}
|
||||
showPatch(hasDifferences);
|
||||
if (hasDifferences) {
|
||||
contentTable.display(patchKey, idSideA, idSideB, script);
|
||||
contentTable.display(script.getCommentDetail());
|
||||
contentTable.finishDisplay();
|
||||
}
|
||||
showPatch(hasDifferences);
|
||||
|
||||
script = null;
|
||||
comments = null;
|
||||
|
||||
// Mark this file reviewed as soon we display the diff screen
|
||||
if (Gerrit.isSignedIn() && isFirst) {
|
||||
reviewedFlag.setValue(true);
|
||||
setReviewedByCurrentUser(true /* reviewed */);
|
||||
}
|
||||
|
||||
if (!isCurrentView()) {
|
||||
display();
|
||||
}
|
||||
// Mark this file reviewed as soon we display the diff screen
|
||||
if (Gerrit.isSignedIn() && isFirst) {
|
||||
reviewedFlag.setValue(true);
|
||||
setReviewedByCurrentUser(true /* reviewed */);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
// Copyright (C) 2009 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.httpd.rpc.patch;
|
||||
|
||||
import com.google.gerrit.common.data.CommentDetail;
|
||||
import com.google.gerrit.httpd.rpc.Handler;
|
||||
import com.google.gerrit.reviewdb.Account;
|
||||
import com.google.gerrit.reviewdb.Change;
|
||||
import com.google.gerrit.reviewdb.Patch;
|
||||
import com.google.gerrit.reviewdb.PatchLineComment;
|
||||
import com.google.gerrit.reviewdb.PatchSet;
|
||||
import com.google.gerrit.reviewdb.ReviewDb;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.AccountInfoCacheFactory;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gwtorm.client.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
class CommentDetailFactory extends Handler<CommentDetail> {
|
||||
interface Factory {
|
||||
CommentDetailFactory create(Patch.Key patchKey,
|
||||
@Assisted("patchSetA") PatchSet.Id patchSetA,
|
||||
@Assisted("patchSetB") PatchSet.Id patchSetB);
|
||||
}
|
||||
|
||||
private final ReviewDb db;
|
||||
private final ChangeControl.Factory changeControlFactory;
|
||||
private final AccountInfoCacheFactory aic;
|
||||
|
||||
private final Patch.Key patchKey;
|
||||
private final PatchSet.Id psa;
|
||||
private final PatchSet.Id psb;
|
||||
|
||||
private final PatchSet.Id patchSetId;
|
||||
private final Change.Id changeId;
|
||||
|
||||
@Inject
|
||||
CommentDetailFactory(final ReviewDb db,
|
||||
final ChangeControl.Factory changeControlFactory,
|
||||
final AccountInfoCacheFactory.Factory accountInfoCacheFactory,
|
||||
@Assisted final Patch.Key patchKey,
|
||||
@Assisted("patchSetA") @Nullable final PatchSet.Id patchSetA,
|
||||
@Assisted("patchSetB") final PatchSet.Id patchSetB) {
|
||||
this.db = db;
|
||||
this.changeControlFactory = changeControlFactory;
|
||||
this.aic = accountInfoCacheFactory.create();
|
||||
|
||||
this.patchKey = patchKey;
|
||||
this.psa = patchSetA;
|
||||
this.psb = patchSetB;
|
||||
|
||||
patchSetId = patchKey.getParentKey();
|
||||
changeId = patchSetId.getParentKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommentDetail call() throws OrmException, NoSuchChangeException {
|
||||
validatePatchSetId(psa);
|
||||
validatePatchSetId(psb);
|
||||
|
||||
final ChangeControl control = changeControlFactory.validateFor(changeId);
|
||||
final String pn = patchKey.getFileName();
|
||||
final CommentDetail r = new CommentDetail(psa, psb);
|
||||
|
||||
final List<Patch> historyList = new ArrayList<Patch>();
|
||||
final Map<PatchSet.Id, Patch> bySet = new HashMap<PatchSet.Id, Patch>();
|
||||
for (final PatchSet ps : db.patchSets().byChange(changeId)) {
|
||||
final Patch p = new Patch(new Patch.Key(ps.getId(), pn));
|
||||
historyList.add(p);
|
||||
bySet.put(ps.getId(), p);
|
||||
}
|
||||
|
||||
for (PatchLineComment c : db.patchComments().published(changeId, pn)) {
|
||||
if (r.include(c)) {
|
||||
aic.want(c.getAuthor());
|
||||
}
|
||||
final PatchSet.Id psId = c.getKey().getParentKey().getParentKey();
|
||||
final Patch patch = bySet.get(psId);
|
||||
if (patch != null) {
|
||||
patch.setCommentCount(patch.getCommentCount() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
final CurrentUser user = control.getCurrentUser();
|
||||
if (user instanceof IdentifiedUser) {
|
||||
final Account.Id me = ((IdentifiedUser) user).getAccountId();
|
||||
for (PatchLineComment c : db.patchComments().draft(changeId, pn, me)) {
|
||||
if (r.include(c)) {
|
||||
aic.want(me);
|
||||
}
|
||||
final PatchSet.Id psId = c.getKey().getParentKey().getParentKey();
|
||||
final Patch patch = bySet.get(psId);
|
||||
if (patch != null) {
|
||||
patch.setDraftCount(patch.getDraftCount() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r.setHistory(historyList);
|
||||
r.setAccountInfoCache(aic.create());
|
||||
return r;
|
||||
}
|
||||
|
||||
private void validatePatchSetId(final PatchSet.Id psId)
|
||||
throws NoSuchChangeException {
|
||||
if (psId == null) { // OK, means use base;
|
||||
} else if (changeId.equals(psId.getParentKey())) { // OK, same change;
|
||||
} else {
|
||||
throw new NoSuchChangeException(changeId);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@ import com.google.gerrit.common.data.AddReviewerResult;
|
|||
import com.google.gerrit.common.data.ApprovalSummary;
|
||||
import com.google.gerrit.common.data.ApprovalSummarySet;
|
||||
import com.google.gerrit.common.data.ApprovalTypes;
|
||||
import com.google.gerrit.common.data.CommentDetail;
|
||||
import com.google.gerrit.common.data.PatchDetailService;
|
||||
import com.google.gerrit.common.data.PatchScript;
|
||||
import com.google.gerrit.common.data.PatchScriptSettings;
|
||||
|
@ -61,7 +60,6 @@ class PatchDetailServiceImpl extends BaseServiceImplementation implements
|
|||
private final AccountInfoCacheFactory.Factory accountInfoCacheFactory;
|
||||
private final AddReviewer.Factory addReviewerFactory;
|
||||
private final ChangeControl.Factory changeControlFactory;
|
||||
private final CommentDetailFactory.Factory commentDetailFactory;
|
||||
private final FunctionState.Factory functionStateFactory;
|
||||
private final PublishComments.Factory publishCommentsFactory;
|
||||
private final PatchScriptFactory.Factory patchScriptFactoryFactory;
|
||||
|
@ -74,7 +72,6 @@ class PatchDetailServiceImpl extends BaseServiceImplementation implements
|
|||
final AccountInfoCacheFactory.Factory accountInfoCacheFactory,
|
||||
final AddReviewer.Factory addReviewerFactory,
|
||||
final ChangeControl.Factory changeControlFactory,
|
||||
final CommentDetailFactory.Factory commentDetailFactory,
|
||||
final FunctionState.Factory functionStateFactory,
|
||||
final PatchScriptFactory.Factory patchScriptFactoryFactory,
|
||||
final PublishComments.Factory publishCommentsFactory,
|
||||
|
@ -85,7 +82,6 @@ class PatchDetailServiceImpl extends BaseServiceImplementation implements
|
|||
this.accountInfoCacheFactory = accountInfoCacheFactory;
|
||||
this.addReviewerFactory = addReviewerFactory;
|
||||
this.changeControlFactory = changeControlFactory;
|
||||
this.commentDetailFactory = commentDetailFactory;
|
||||
this.functionStateFactory = functionStateFactory;
|
||||
this.patchScriptFactoryFactory = patchScriptFactoryFactory;
|
||||
this.publishCommentsFactory = publishCommentsFactory;
|
||||
|
@ -102,15 +98,6 @@ class PatchDetailServiceImpl extends BaseServiceImplementation implements
|
|||
patchScriptFactoryFactory.create(patchKey, psa, psb, s).to(callback);
|
||||
}
|
||||
|
||||
public void patchComments(final Patch.Key patchKey, final PatchSet.Id psa,
|
||||
final PatchSet.Id psb, final AsyncCallback<CommentDetail> callback) {
|
||||
if (psb == null) {
|
||||
callback.onFailure(new NoSuchEntityException());
|
||||
return;
|
||||
}
|
||||
commentDetailFactory.create(patchKey, psa, psb).to(callback);
|
||||
}
|
||||
|
||||
public void saveDraft(final PatchLineComment comment,
|
||||
final AsyncCallback<PatchLineComment> callback) {
|
||||
saveDraftFactory.create(comment).to(callback);
|
||||
|
|
|
@ -29,7 +29,6 @@ public class PatchModule extends RpcServletModule {
|
|||
@Override
|
||||
protected void configure() {
|
||||
factory(AddReviewer.Factory.class);
|
||||
factory(CommentDetailFactory.Factory.class);
|
||||
factory(PatchScriptFactory.Factory.class);
|
||||
factory(SaveDraft.Factory.class);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.google.gerrit.common.data.PatchScriptSettings.Whitespace;
|
|||
import com.google.gerrit.prettify.common.EditList;
|
||||
import com.google.gerrit.prettify.common.SparseFileContent;
|
||||
import com.google.gerrit.reviewdb.Change;
|
||||
import com.google.gerrit.reviewdb.Patch;
|
||||
import com.google.gerrit.reviewdb.PatchLineComment;
|
||||
import com.google.gerrit.reviewdb.Patch.PatchType;
|
||||
import com.google.gerrit.server.FileTypeRegistry;
|
||||
|
@ -103,14 +104,15 @@ class PatchScriptBuilder {
|
|||
}
|
||||
|
||||
PatchScript toPatchScript(final PatchListEntry content,
|
||||
final CommentDetail comments) throws IOException {
|
||||
final CommentDetail comments, final List<Patch> history)
|
||||
throws IOException {
|
||||
if (content.getPatchType() == PatchType.N_WAY) {
|
||||
// For a diff --cc format we don't support converting it into
|
||||
// a patch script. Instead treat everything as a file header.
|
||||
//
|
||||
return new PatchScript(change.getKey(), content.getHeaderLines(),
|
||||
settings, a.dst, b.dst, Collections.<Edit> emptyList(),
|
||||
a.displayMethod, b.displayMethod);
|
||||
a.displayMethod, b.displayMethod, comments, history);
|
||||
}
|
||||
|
||||
a.path = oldName(content);
|
||||
|
@ -157,7 +159,7 @@ class PatchScriptBuilder {
|
|||
}
|
||||
|
||||
return new PatchScript(change.getKey(), header, settings, a.dst, b.dst,
|
||||
edits, a.displayMethod, b.displayMethod);
|
||||
edits, a.displayMethod, b.displayMethod, comments, history);
|
||||
}
|
||||
|
||||
private static String oldName(final PatchListEntry entry) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.google.gerrit.common.data.PatchScript;
|
|||
import com.google.gerrit.common.data.PatchScriptSettings;
|
||||
import com.google.gerrit.common.data.PatchScriptSettings.Whitespace;
|
||||
import com.google.gerrit.httpd.rpc.Handler;
|
||||
import com.google.gerrit.reviewdb.Account;
|
||||
import com.google.gerrit.reviewdb.AccountGeneralPreferences;
|
||||
import com.google.gerrit.reviewdb.Change;
|
||||
import com.google.gerrit.reviewdb.Patch;
|
||||
|
@ -26,7 +27,9 @@ import com.google.gerrit.reviewdb.PatchLineComment;
|
|||
import com.google.gerrit.reviewdb.PatchSet;
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.reviewdb.ReviewDb;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.AccountInfoCacheFactory;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.patch.PatchList;
|
||||
import com.google.gerrit.server.patch.PatchListCache;
|
||||
|
@ -47,6 +50,10 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
@ -67,6 +74,7 @@ class PatchScriptFactory extends Handler<PatchScript> {
|
|||
private final PatchListCache patchListCache;
|
||||
private final SchemaFactory<ReviewDb> schemaFactory;
|
||||
private final ChangeControl.Factory changeControlFactory;
|
||||
private final AccountInfoCacheFactory.Factory aicFactory;
|
||||
|
||||
private final Patch.Key patchKey;
|
||||
@Nullable
|
||||
|
@ -80,19 +88,18 @@ class PatchScriptFactory extends Handler<PatchScript> {
|
|||
private Change change;
|
||||
private PatchSet patchSet;
|
||||
private Project.NameKey projectKey;
|
||||
private Repository git;
|
||||
|
||||
private ChangeControl control;
|
||||
|
||||
private ObjectId aId;
|
||||
|
||||
private ObjectId bId;
|
||||
private List<Patch> history;
|
||||
private CommentDetail comments;
|
||||
|
||||
@Inject
|
||||
PatchScriptFactory(final GitRepositoryManager grm,
|
||||
Provider<PatchScriptBuilder> builderFactory,
|
||||
final PatchListCache patchListCache, final SchemaFactory<ReviewDb> sf,
|
||||
final ChangeControl.Factory changeControlFactory,
|
||||
final AccountInfoCacheFactory.Factory aicFactory,
|
||||
@Assisted final Patch.Key patchKey,
|
||||
@Assisted("patchSetA") @Nullable final PatchSet.Id patchSetA,
|
||||
@Assisted("patchSetB") final PatchSet.Id patchSetB,
|
||||
|
@ -102,6 +109,7 @@ class PatchScriptFactory extends Handler<PatchScript> {
|
|||
this.patchListCache = patchListCache;
|
||||
this.schemaFactory = sf;
|
||||
this.changeControlFactory = changeControlFactory;
|
||||
this.aicFactory = aicFactory;
|
||||
|
||||
this.patchKey = patchKey;
|
||||
this.psa = patchSetA;
|
||||
|
@ -119,21 +127,21 @@ class PatchScriptFactory extends Handler<PatchScript> {
|
|||
|
||||
control = changeControlFactory.validateFor(changeId);
|
||||
change = control.getChange();
|
||||
final CommentDetail comments = allComments();
|
||||
loadMetaData();
|
||||
|
||||
final Repository git;
|
||||
try {
|
||||
git = repoManager.openRepository(projectKey.get());
|
||||
} catch (RepositoryNotFoundException e) {
|
||||
log.error("Repository " + projectKey + " not found", e);
|
||||
throw new NoSuchChangeException(changeId, e);
|
||||
}
|
||||
|
||||
final String fileName = patchKey.getFileName();
|
||||
try {
|
||||
final PatchList list = listFor(keyFor(settings.getWhitespace()));
|
||||
final PatchScriptBuilder b = newBuilder(list);
|
||||
final PatchListEntry content = list.get(fileName);
|
||||
final PatchScriptBuilder b = newBuilder(list, git);
|
||||
final PatchListEntry content = list.get(patchKey.getFileName());
|
||||
try {
|
||||
return b.toPatchScript(content, comments);
|
||||
return b.toPatchScript(content, comments, history);
|
||||
} catch (IOException e) {
|
||||
log.error("File content unavailable", e);
|
||||
throw new NoSuchChangeException(changeId, e);
|
||||
|
@ -151,7 +159,7 @@ class PatchScriptFactory extends Handler<PatchScript> {
|
|||
return patchListCache.get(key);
|
||||
}
|
||||
|
||||
private PatchScriptBuilder newBuilder(final PatchList list)
|
||||
private PatchScriptBuilder newBuilder(final PatchList list, Repository git)
|
||||
throws NoSuchChangeException {
|
||||
final PatchScriptSettings s = new PatchScriptSettings(settings);
|
||||
|
||||
|
@ -200,11 +208,9 @@ class PatchScriptFactory extends Handler<PatchScript> {
|
|||
}
|
||||
}
|
||||
|
||||
private CommentDetail allComments()
|
||||
throws OrmException, NoSuchChangeException {
|
||||
ReviewDb db = schemaFactory.open();
|
||||
private void loadMetaData() throws OrmException, NoSuchChangeException {
|
||||
final ReviewDb db = schemaFactory.open();
|
||||
try {
|
||||
final CommentDetail r = new CommentDetail(psa, psb);
|
||||
patchSet = db.patchSets().get(patchSetId);
|
||||
if (patchSet == null) {
|
||||
throw new NoSuchChangeException(changeId);
|
||||
|
@ -213,18 +219,47 @@ class PatchScriptFactory extends Handler<PatchScript> {
|
|||
projectKey = change.getProject();
|
||||
aId = psa != null ? toObjectId(db, psa) : null;
|
||||
bId = toObjectId(db, psb);
|
||||
final String pn = patchKey.get();
|
||||
for (PatchLineComment p : db.patchComments().published(changeId, pn)) {
|
||||
r.include(p);
|
||||
history = new ArrayList<Patch>();
|
||||
comments = new CommentDetail(psa, psb);
|
||||
|
||||
final String file = patchKey.get();
|
||||
final Map<PatchSet.Id, Patch> bySet = new HashMap<PatchSet.Id, Patch>();
|
||||
for (final PatchSet ps : db.patchSets().byChange(changeId)) {
|
||||
final Patch p = new Patch(new Patch.Key(ps.getId(), file));
|
||||
history.add(p);
|
||||
bySet.put(ps.getId(), p);
|
||||
}
|
||||
|
||||
if (control.getCurrentUser() instanceof IdentifiedUser) {
|
||||
for (PatchLineComment p : db.patchComments().draft(changeId, pn,
|
||||
((IdentifiedUser) control.getCurrentUser()).getAccountId())) {
|
||||
r.include(p);
|
||||
final AccountInfoCacheFactory aic = aicFactory.create();
|
||||
for (PatchLineComment c : db.patchComments().published(changeId, file)) {
|
||||
if (comments.include(c)) {
|
||||
aic.want(c.getAuthor());
|
||||
}
|
||||
|
||||
final PatchSet.Id psId = c.getKey().getParentKey().getParentKey();
|
||||
final Patch p = bySet.get(psId);
|
||||
if (p != null) {
|
||||
p.setCommentCount(p.getCommentCount() + 1);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
|
||||
final CurrentUser user = control.getCurrentUser();
|
||||
if (user instanceof IdentifiedUser) {
|
||||
final Account.Id me = ((IdentifiedUser) user).getAccountId();
|
||||
for (PatchLineComment c : db.patchComments().draft(changeId, file, me)) {
|
||||
if (comments.include(c)) {
|
||||
aic.want(me);
|
||||
}
|
||||
|
||||
final PatchSet.Id psId = c.getKey().getParentKey().getParentKey();
|
||||
final Patch p = bySet.get(psId);
|
||||
if (p != null) {
|
||||
p.setDraftCount(p.getDraftCount() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
comments.setAccountInfoCache(aic.create());
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue