Remove old changeDetail RPC

Convert the new RPC data into the old data, just enough to keep the
old UI alive against a newer server.  This will allow us to build a
final version of the old UI code and run it for quite some time
against a modern REST API.

Users who refuse to upgrade to ChangeScreen2 can run this frozen old
UI build until it no longer works.

Change-Id: Ieef15c39e97673f6bcdeb03567fc48ddbd289a6e
This commit is contained in:
Shawn Pearce
2013-12-05 21:00:52 -08:00
parent dd5f4ca82a
commit adb91286f8
13 changed files with 493 additions and 529 deletions

View File

@@ -52,6 +52,10 @@ public class AccountInfo {
return id;
}
public void setFullName(String n) {
fullName = n;
}
/** @return the full name of the account holder; null if not supplied */
public String getFullName() {
return fullName;

View File

@@ -17,7 +17,6 @@ package com.google.gerrit.common.data;
import com.google.gerrit.common.audit.Audit;
import com.google.gerrit.common.auth.SignInRequired;
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwtjsonrpc.common.AsyncCallback;
import com.google.gwtjsonrpc.common.RemoteJsonService;
@@ -26,12 +25,6 @@ import com.google.gwtjsonrpc.common.RpcImpl.Version;
@RpcImpl(version = Version.V2_0)
public interface ChangeDetailService extends RemoteJsonService {
@Audit
void changeDetail(Change.Id id, AsyncCallback<ChangeDetail> callback);
@Audit
void includedInDetail(Change.Id id, AsyncCallback<IncludedInDetail> callback);
@Audit
void patchSetDetail(PatchSet.Id key, AsyncCallback<PatchSetDetail> callback);

View File

@@ -35,10 +35,14 @@ public class ChangeInfo {
protected PatchSet.Id patchSetId;
protected boolean latest;
protected ChangeInfo() {
public ChangeInfo() {
}
public ChangeInfo(final Change c, final PatchSet.Id patchId) {
set(c, patchId);
}
public void set(final Change c, final PatchSet.Id patchId) {
id = c.getId();
key = c.getKey();
owner = c.getOwner();

View File

@@ -39,7 +39,7 @@ import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
class RelatedChanges extends TabPanel {
public class RelatedChanges extends TabPanel {
private enum Tab {
RELATED_CHANGES(Resources.C.relatedChanges(),
Resources.C.relatedChangesTooltip()) {
@@ -284,19 +284,19 @@ class RelatedChanges extends TabPanel {
}
}
private static class RelatedInfo extends JavaScriptObject {
final native JsArray<ChangeAndCommit> changes() /*-{ return this.changes }-*/;
public static class RelatedInfo extends JavaScriptObject {
public final native JsArray<ChangeAndCommit> changes() /*-{ return this.changes }-*/;
protected RelatedInfo() {
}
}
static class ChangeAndCommit extends JavaScriptObject {
public static class ChangeAndCommit extends JavaScriptObject {
static ChangeAndCommit create() {
return (ChangeAndCommit) createObject();
}
final native String id() /*-{ return this.change_id }-*/;
final native CommitInfo commit() /*-{ return this.commit }-*/;
public final native String id() /*-{ return this.change_id }-*/;
public final native CommitInfo commit() /*-{ return this.commit }-*/;
final native String branch() /*-{ return this.branch }-*/;
final native void set_id(String i)
@@ -308,11 +308,11 @@ class RelatedChanges extends TabPanel {
final native void set_branch(String b)
/*-{ if(b)this.branch=b; }-*/;
final Change.Id legacy_id() {
public final Change.Id legacy_id() {
return has_change_number() ? new Change.Id(_change_number()) : null;
}
final PatchSet.Id patch_set_id() {
public final PatchSet.Id patch_set_id() {
return has_change_number() && has_revision_number()
? new PatchSet.Id(legacy_id(), _revision_number())
: null;

View File

@@ -14,15 +14,54 @@
package com.google.gerrit.client.changes;
import com.google.gerrit.client.actions.ActionInfo;
import com.google.gerrit.client.changes.ChangeInfo.CommitInfo;
import com.google.gerrit.client.changes.ChangeInfo.GitPerson;
import com.google.gerrit.client.changes.ChangeInfo.MessageInfo;
import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
import com.google.gerrit.client.rpc.NativeMap;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.rpc.RestApi;
import com.google.gerrit.client.ui.ListenableValue;
import com.google.gerrit.common.changes.ListChangesOption;
import com.google.gerrit.common.data.AccountInfo;
import com.google.gerrit.common.data.AccountInfoCache;
import com.google.gerrit.common.data.ChangeDetail;
import com.google.gerrit.common.data.PatchSetDetail;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.common.data.SubmitTypeRecord;
import com.google.gerrit.common.data.UiCommandDetail;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gwtjsonrpc.common.AsyncCallback;
import com.google.gerrit.reviewdb.client.ChangeMessage;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetInfo;
import com.google.gerrit.reviewdb.client.PatchSetInfo.ParentInfo;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.client.UserIdentity;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwtjsonrpc.common.AsyncCallback;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
public class ChangeDetailCache extends ListenableValue<ChangeDetail> {
public static class GerritCallback extends
public static class NewGerritCallback extends
com.google.gerrit.client.rpc.GerritCallback<ChangeInfo> {
@Override
public void onSuccess(ChangeInfo detail) {
setChangeDetail(reverse(detail));
}
}
public static class OldGerritCallback extends
com.google.gerrit.client.rpc.GerritCallback<ChangeDetail> {
@Override
public void onSuccess(ChangeDetail detail) {
@@ -37,7 +76,7 @@ public class ChangeDetailCache extends ListenableValue<ChangeDetail> {
*
* It is up to the caller to handle the original disabling of the Widget.
*/
public static class GerritWidgetCallback extends GerritCallback {
public static class GerritWidgetCallback extends OldGerritCallback {
private FocusWidget widget;
public GerritWidgetCallback(FocusWidget widget) {
@@ -53,8 +92,8 @@ public class ChangeDetailCache extends ListenableValue<ChangeDetail> {
public static class IgnoreErrorCallback implements AsyncCallback<ChangeDetail> {
@Override
public void onSuccess(ChangeDetail detail) {
setChangeDetail(detail);
public void onSuccess(ChangeDetail info) {
setChangeDetail(info);
}
@Override
@@ -62,6 +101,173 @@ public class ChangeDetailCache extends ListenableValue<ChangeDetail> {
}
}
public static ChangeDetail reverse(ChangeInfo info) {
info.revisions().copyKeysIntoChildren("name");
RevisionInfo rev = current(info);
ChangeDetail r = new ChangeDetail();
r.setAllowsAnonymous(rev.has_fetch() && rev.fetch().containsKey("http"));
r.setCanAbandon(can(info.actions(), "abandon"));
r.setCanEditCommitMessage(can(info.actions(), "message"));
r.setCanCherryPick(can(rev.actions(), "cherrypick"));
r.setCanPublish(can(rev.actions(), "publish"));
r.setCanRebase(can(rev.actions(), "rebase"));
r.setCanRestore(can(info.actions(), "restore"));
r.setCanRevert(can(info.actions(), "revert"));
r.setCanDeleteDraft(can(rev.actions(), "/"));
r.setCanEditTopicName(can(info.actions(), "topic"));
r.setCanSubmit(can(rev.actions(), "submit"));
r.setCanEdit(true);
r.setChange(toChange(info));
r.setStarred(info.starred());
r.setPatchSets(toPatchSets(info));
r.setMessages(toMessages(info));
r.setAccounts(users(info));
r.setCurrentPatchSetId(new PatchSet.Id(info.legacy_id(), rev._number()));
r.setCurrentPatchSetDetail(toPatchSetDetail(info));
r.setSubmitRecords(new ArrayList<SubmitRecord>());
// Obtained later in ChangeScreen.
r.setSubmitTypeRecord(new SubmitTypeRecord());
r.getSubmitTypeRecord().status = SubmitTypeRecord.Status.RULE_ERROR;
r.setPatchSetsWithDraftComments(new HashSet<PatchSet.Id>());
r.setDependsOn(new ArrayList<com.google.gerrit.common.data.ChangeInfo>());
r.setNeededBy(new ArrayList<com.google.gerrit.common.data.ChangeInfo>());
return r;
}
private static PatchSetDetail toPatchSetDetail(ChangeInfo info) {
RevisionInfo rev = current(info);
PatchSetDetail p = new PatchSetDetail();
p.setPatchSet(toPatchSet(info, rev));
p.setProject(info.project_name_key());
p.setInfo(new PatchSetInfo(p.getPatchSet().getId()));
p.getInfo().setRevId(rev.name());
p.getInfo().setParents(new ArrayList<ParentInfo>());
p.getInfo().setAuthor(toUser(rev.commit().author()));
p.getInfo().setCommitter(toUser(rev.commit().committer()));
p.getInfo().setSubject(rev.commit().subject());
p.getInfo().setMessage(rev.commit().message());
if (rev.commit().parents() != null) {
for (CommitInfo c : Natives.asList(rev.commit().parents())) {
p.getInfo().getParents().add(new ParentInfo(
new RevId(c.commit()),
c.subject()));
}
}
p.setPatches(new ArrayList<Patch>());
p.setCommands(new ArrayList<UiCommandDetail>());
rev.files();
return p;
}
private static UserIdentity toUser(GitPerson p) {
UserIdentity u = new UserIdentity();
u.setName(p.name());
u.setEmail(p.email());
u.setDate(p.date());
return u;
}
public static AccountInfoCache users(ChangeInfo info) {
Map<Integer, AccountInfo> r = new HashMap<Integer, AccountInfo>();
add(r, info.owner());
if (info.messages() != null) {
for (MessageInfo m : Natives.asList(info.messages())) {
add(r, m.author());
}
}
return new AccountInfoCache(r.values());
}
private static void add(Map<Integer, AccountInfo> r,
com.google.gerrit.client.account.AccountInfo user) {
if (user != null && !r.containsKey(user._account_id())) {
AccountInfo a = new AccountInfo(new Account.Id(user._account_id()));
a.setPreferredEmail(user.email());
a.setFullName(user.name());
r.put(user._account_id(), a);
}
}
private static boolean can(NativeMap<ActionInfo> m, String n) {
return m != null && m.containsKey(n) && m.get(n).enabled();
}
private static List<ChangeMessage> toMessages(ChangeInfo info) {
List<ChangeMessage> msgs = new ArrayList<ChangeMessage>();
for (MessageInfo m : Natives.asList(info.messages())) {
ChangeMessage o = new ChangeMessage(
new ChangeMessage.Key(
info.legacy_id(),
m.date().toString()),
m.author() != null
? new Account.Id(m.author()._account_id())
: null,
m.date(),
m._revisionNumber() > 0
? new PatchSet.Id(info.legacy_id(), m._revisionNumber())
: null);
o.setMessage(m.message());
msgs.add(o);
}
return msgs;
}
private static List<PatchSet> toPatchSets(ChangeInfo info) {
JsArray<RevisionInfo> all = info.revisions().values();
RevisionInfo.sortRevisionInfoByNumber(all);
List<PatchSet> r = new ArrayList<PatchSet>(all.length());
for (RevisionInfo rev : Natives.asList(all)) {
r.add(toPatchSet(info, rev));
}
return r;
}
private static PatchSet toPatchSet(ChangeInfo info, RevisionInfo rev) {
PatchSet p = new PatchSet(
new PatchSet.Id(info.legacy_id(), rev._number()));
p.setCreatedOn(rev.commit().committer().date());
p.setDraft(rev.draft());
p.setRevision(new RevId(rev.name()));
return p;
}
public static Change toChange(ChangeInfo info) {
RevisionInfo rev = current(info);
PatchSetInfo p = new PatchSetInfo(
new PatchSet.Id(
info.legacy_id(),
rev._number()));
p.setSubject(info.subject());
Change c = new Change(
new Change.Key(info.change_id()),
info.legacy_id(),
new Account.Id(info.owner()._account_id()),
new Branch.NameKey(
info.project_name_key(),
info.branch()),
info.created());
c.setTopic(info.topic());
c.setStatus(info.status());
c.setCurrentPatchSet(p);
c.setLastUpdatedOn(info.updated());
c.setMergeable(info.mergeable());
return c;
}
private static RevisionInfo current(ChangeInfo info) {
RevisionInfo rev = info.revision(info.current_revision());
if (rev == null) {
JsArray<RevisionInfo> all = info.revisions().values();
RevisionInfo.sortRevisionInfoByNumber(all);
rev = all.get(all.length() - 1);
}
return rev;
}
public static void setChangeDetail(ChangeDetail detail) {
Change.Id chgId = detail.getChange().getId();
ChangeCache.get(chgId).getChangeDetailCache().set(detail);
@@ -75,6 +281,11 @@ public class ChangeDetailCache extends ListenableValue<ChangeDetail> {
}
public void refresh() {
Util.DETAIL_SVC.changeDetail(changeId, new GerritCallback());
RestApi call = ChangeApi.detail(changeId.get());
ChangeList.addOptions(call, EnumSet.of(
ListChangesOption.CURRENT_ACTIONS,
ListChangesOption.ALL_REVISIONS,
ListChangesOption.ALL_COMMITS));
call.get(new NewGerritCallback());
}
}

View File

@@ -18,9 +18,18 @@ import com.google.gerrit.client.Dispatcher;
import com.google.gerrit.client.FormatUtil;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.account.AccountInfo;
import com.google.gerrit.client.change.RelatedChanges;
import com.google.gerrit.client.change.RelatedChanges.ChangeAndCommit;
import com.google.gerrit.client.changes.ChangeInfo.CommitInfo;
import com.google.gerrit.client.diff.DiffApi;
import com.google.gerrit.client.diff.FileInfo;
import com.google.gerrit.client.projects.ConfigInfoCache;
import com.google.gerrit.client.rpc.CallbackGroup;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.NativeMap;
import com.google.gerrit.client.rpc.NativeString;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.rpc.RestApi;
import com.google.gerrit.client.ui.CommentLinkProcessor;
import com.google.gerrit.client.ui.CommentPanel;
import com.google.gerrit.client.ui.ComplexDisclosurePanel;
@@ -28,14 +37,22 @@ import com.google.gerrit.client.ui.ExpandAllCommand;
import com.google.gerrit.client.ui.LinkMenuBar;
import com.google.gerrit.client.ui.NeedsSignInKeyCommand;
import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.changes.ListChangesOption;
import com.google.gerrit.common.data.AccountInfoCache;
import com.google.gerrit.common.data.ChangeDetail;
import com.google.gerrit.common.data.ChangeInfo;
import com.google.gerrit.common.data.SubmitTypeRecord;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.CommentVisibilityStrategy;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Change.Status;
import com.google.gerrit.reviewdb.client.ChangeMessage;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.Patch.ChangeType;
import com.google.gerrit.reviewdb.client.Patch.PatchType;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -45,6 +62,7 @@ import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.FlowPanel;
@@ -59,7 +77,13 @@ import com.google.gwtexpui.globalkey.client.KeyCommand;
import com.google.gwtexpui.globalkey.client.KeyCommandSet;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class ChangeScreen extends Screen
@@ -273,10 +297,209 @@ public class ChangeScreen extends Screen
// happen sequentially after the ChangeDetail lookup, because we can't
// start an async get at the source of every call that might trigger a
// value change.
CallbackGroup cbs = new CallbackGroup();
CallbackGroup cbs1 = new CallbackGroup();
final CallbackGroup cbs2 = new CallbackGroup();
final PatchSet.Id psId = event.getValue().getCurrentPatchSet().getId();
final Map<String, Patch> patches = new HashMap<String, Patch>();
String revId =
event.getValue().getCurrentPatchSetDetail().getInfo().getRevId();
if (event.getValue().getChange().getStatus().isOpen()) {
ChangeApi.revision(changeId.get(), "current")
.view("submit_type")
.get(cbs1.add(new GerritCallback<NativeString>() {
@Override
public void onSuccess(NativeString result) {
event.getValue().setSubmitTypeRecord(SubmitTypeRecord.OK(
Project.SubmitType.valueOf(result.asString())));
}
public void onFailure(Throwable caught) {}
}));
}
if (Gerrit.isSignedIn()) {
ChangeApi.revision(changeId.get(), "" + psId.get())
.view("related")
.get(cbs1.add(new AsyncCallback<RelatedChanges.RelatedInfo>() {
@Override
public void onSuccess(RelatedChanges.RelatedInfo info) {
if (info.changes() != null) {
dependsOn(info);
neededBy(info);
}
}
private void dependsOn(RelatedChanges.RelatedInfo info) {
ChangeAndCommit self = null;
Map<String, ChangeAndCommit> m = new HashMap<String, ChangeAndCommit>();
for (int i = 0; i < info.changes().length(); i++) {
ChangeAndCommit c = info.changes().get(i);
if (changeId.equals(c.legacy_id())) {
self = c;
}
if (c.commit() != null && c.commit().commit() != null) {
m.put(c.commit().commit(), c);
}
}
if (self != null && self.commit() != null
&& self.commit().parents() != null) {
List<ChangeInfo> d = new ArrayList<ChangeInfo>();
for (CommitInfo p : Natives.asList(self.commit().parents())) {
ChangeAndCommit pc = m.get(p.commit());
if (pc != null) {
ChangeInfo i = new ChangeInfo();
load(pc, i);
d.add(i);
}
}
event.getValue().setDependsOn(d);
}
}
private void neededBy(RelatedChanges.RelatedInfo info) {
Set<String> mine = new HashSet<String>();
for (PatchSet ps : event.getValue().getPatchSets()) {
mine.add(ps.getRevision().get());
}
List<ChangeInfo> n = new ArrayList<ChangeInfo>();
for (int i = 0; i < info.changes().length(); i++) {
ChangeAndCommit c = info.changes().get(i);
if (c.commit() != null && c.commit().parents() != null) {
for (int j = 0; j < c.commit().parents().length(); j++) {
CommitInfo p = c.commit().parents().get(j);
if (mine.contains(p.commit())) {
ChangeInfo u = new ChangeInfo();
load(c, u);
n.add(u);
break;
}
}
}
}
event.getValue().setNeededBy(n);
}
private void load(final ChangeAndCommit pc, final ChangeInfo i) {
RestApi call = ChangeApi.change(pc.legacy_id().get());
ChangeList.addOptions(call, EnumSet.of(
ListChangesOption.DETAILED_ACCOUNTS,
ListChangesOption.CURRENT_REVISION));
call.get(cbs2.add(new AsyncCallback<
com.google.gerrit.client.changes.ChangeInfo>() {
public void onFailure(Throwable caught) {}
public void onSuccess(
com.google.gerrit.client.changes.ChangeInfo result) {
i.set(ChangeDetailCache.toChange(result),
pc.patch_set_id());
i.setStarred(result.starred());
event.getValue().getAccounts()
.merge(ChangeDetailCache.users(result));
}}));
}
public void onFailure(Throwable caught) {}
}));
ChangeApi.revision(changeId.get(), revId)
.view("files")
.addParameterTrue("reviewed")
.get(cbs1.add(new AsyncCallback<JsArrayString>() {
@Override
public void onSuccess(JsArrayString result) {
for(int i = 0; i < result.length(); i++) {
String path = result.get(i);
Patch p = patches.get(path);
if (p == null) {
p = new Patch(new Patch.Key(psId, path));
patches.put(path, p);
}
p.setReviewedByCurrentUser(true);
}
}
public void onFailure(Throwable caught) {}
}));
final Set<PatchSet.Id> withDrafts = new HashSet<PatchSet.Id>();
event.getValue().setPatchSetsWithDraftComments(withDrafts);
for (PatchSet ps : event.getValue().getPatchSets()) {
if (!ps.getId().equals(psId)) {
final PatchSet.Id id = ps.getId();
ChangeApi.revision(changeId.get(), "" + id.get())
.view("drafts")
.get(cbs1.add(new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
@Override
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
if (!result.isEmpty()) {
withDrafts.add(id);
}
}
public void onFailure(Throwable caught) {}
}));
}
}
ChangeApi.revision(changeId.get(), "" + psId.get())
.view("drafts")
.get(cbs1.add(new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
@Override
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
for (String path : result.keySet()) {
Patch p = patches.get(path);
if (p == null) {
p = new Patch(new Patch.Key(psId, path));
patches.put(path, p);
}
p.setDraftCount(result.get(path).length());
}
if (!result.isEmpty()) {
withDrafts.add(psId);
}
}
public void onFailure(Throwable caught) {}
}));
}
ChangeApi.revision(changeId.get(), revId)
.view("comments")
.get(cbs1.add(new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
@Override
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
for (String path : result.keySet()) {
Patch p = patches.get(path);
if (p == null) {
p = new Patch(new Patch.Key(psId, path));
patches.put(path, p);
}
p.setCommentCount(result.get(path).length());
}
}
public void onFailure(Throwable caught) {}
}));
DiffApi.list(changeId.get(), null, revId,
new AsyncCallback<NativeMap<FileInfo>>() {
@Override
public void onSuccess(NativeMap<FileInfo> result) {
JsArray<FileInfo> fileInfos = result.values();
FileInfo.sortFileInfoByPath(fileInfos);
List<Patch> list = new ArrayList<Patch>(fileInfos.length());
for (FileInfo f : Natives.asList(fileInfos)) {
Patch p = patches.get(f.path());
if (p == null) {
p = new Patch(new Patch.Key(psId, f.path()));
patches.put(f.path(), p);
}
p.setInsertions(f.lines_inserted());
p.setDeletions(f.lines_deleted());
p.setPatchType(f.binary() ? PatchType.BINARY : PatchType.UNIFIED);
if (f.status() == null) {
p.setChangeType(ChangeType.MODIFIED);
} else {
p.setChangeType(ChangeType.forCode(f.status().charAt(0)));
}
list.add(p);
}
event.getValue().getCurrentPatchSetDetail().setPatches(list);
}
public void onFailure(Throwable caught) {}
});
ConfigInfoCache.get(
event.getValue().getChange().getProject(),
cbs.add(new GerritCallback<ConfigInfoCache.Entry>() {
cbs1.add(new GerritCallback<ConfigInfoCache.Entry>() {
@Override
public void onSuccess(ConfigInfoCache.Entry result) {
commentLinkProcessor = result.getCommentLinkProcessor();
@@ -288,13 +511,19 @@ public class ChangeScreen extends Screen
// Handled by last callback's onFailure.
}
}));
ChangeApi.detail(event.getValue().getChange().getId().get(), cbs.addFinal(
ChangeApi.detail(changeId.get(), cbs1.addFinal(
new GerritCallback<com.google.gerrit.client.changes.ChangeInfo>() {
@Override
public void onSuccess(
com.google.gerrit.client.changes.ChangeInfo result) {
changeInfo = result;
display(event.getValue());
cbs2.addFinal(new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
display(event.getValue());
}
public void onFailure(Throwable caught) {}
}).onSuccess(null);
}
}));
}

View File

@@ -15,9 +15,11 @@
package com.google.gerrit.client.changes;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.changes.ChangeInfo.IncludedInInfo;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.common.data.IncludedInDetail;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.user.client.ui.Composite;
@@ -25,6 +27,9 @@ import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import java.util.ArrayList;
import java.util.List;
/** Displays a table of Branches and Tags containing the change record. */
public class IncludedInTable extends Composite implements
@@ -73,13 +78,26 @@ public class IncludedInTable extends Composite implements
@Override
public void onOpen(OpenEvent<DisclosurePanel> event) {
if (!loaded) {
Util.DETAIL_SVC.includedInDetail(changeId,
new GerritCallback<IncludedInDetail>() {
@Override
public void onSuccess(final IncludedInDetail result) {
loadTable(result);
ChangeApi.includedIn(changeId.get(),
new GerritCallback<IncludedInInfo>() {
@Override
public void onSuccess(IncludedInInfo r) {
IncludedInDetail result = new IncludedInDetail();
result.setBranches(toList(r.branches()));
result.setTags(toList(r.tags()));
loadTable(result);
}
private List<String> toList(JsArrayString in) {
List<String> r = new ArrayList<String>();
if (in != null) {
for (int i = 0; i < in.length(); i++) {
r.add(in.get(i));
}
});
}
return r;
}
});
}
}
}

View File

@@ -20,7 +20,6 @@ import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.GitwebLink;
import com.google.gerrit.client.change.DraftActions;
import com.google.gerrit.client.download.DownloadPanel;
import com.google.gerrit.client.patches.PatchUtil;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.NativeString;
import com.google.gerrit.client.rpc.RestApi;

View File

@@ -1,377 +0,0 @@
// Copyright (C) 2008 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.changedetail;
import com.google.gerrit.common.data.ChangeDetail;
import com.google.gerrit.common.data.ChangeInfo;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.common.errors.NoSuchEntityException;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.ChangeMessage;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetAncestor;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.ProjectUtil;
import com.google.gerrit.server.account.AccountInfoCacheFactory;
import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.change.Mergeable;
import com.google.gerrit.server.change.RevisionResource;
import com.google.gerrit.server.changedetail.RebaseChange;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.ResultSet;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Creates a {@link ChangeDetail} from a {@link Change}. */
public class ChangeDetailFactory extends Handler<ChangeDetail> {
private static final Logger log = LoggerFactory
.getLogger(ChangeDetailFactory.class);
public interface Factory {
ChangeDetailFactory create(Change.Id id);
}
private final ChangeControl.Factory changeControlFactory;
private final PatchSetDetailFactory.Factory patchSetDetail;
private final AccountInfoCacheFactory aic;
private final AnonymousUser anonymousUser;
private final ReviewDb db;
private final GitRepositoryManager repoManager;
private final Change.Id changeId;
private ChangeDetail detail;
private ChangeControl control;
private Map<PatchSet.Id, PatchSet> patchsetsById;
private final Mergeable mergeable;
private List<PatchSetAncestor> currentPatchSetAncestors;
private List<PatchSet> currentDepPatchSets;
private List<Change> currentDepChanges;
@Inject
ChangeDetailFactory(
final PatchSetDetailFactory.Factory patchSetDetail, final ReviewDb db,
final GitRepositoryManager repoManager,
final ChangeControl.Factory changeControlFactory,
final AccountInfoCacheFactory.Factory accountInfoCacheFactory,
final AnonymousUser anonymousUser,
final Mergeable mergeable,
@GerritServerConfig final Config cfg,
@Assisted final Change.Id id) {
this.patchSetDetail = patchSetDetail;
this.db = db;
this.repoManager = repoManager;
this.changeControlFactory = changeControlFactory;
this.anonymousUser = anonymousUser;
this.aic = accountInfoCacheFactory.create();
this.mergeable = mergeable;
this.changeId = id;
}
@Override
public ChangeDetail call() throws OrmException, NoSuchEntityException,
PatchSetInfoNotAvailableException, NoSuchChangeException,
RepositoryNotFoundException, IOException, NoSuchProjectException {
control = changeControlFactory.validateFor(changeId);
final Change change = control.getChange();
final PatchSet patch = db.patchSets().get(change.currentPatchSetId());
if (patch == null) {
throw new NoSuchEntityException();
}
aic.want(change.getOwner());
detail = new ChangeDetail();
detail.setChange(change);
detail.setAllowsAnonymous(control.forUser(anonymousUser).isVisible(db));
detail.setCanAbandon(change.getStatus() != Change.Status.DRAFT && change.getStatus().isOpen() && control.canAbandon());
detail.setCanPublish(control.canPublish(db));
detail.setCanRestore(change.getStatus() == Change.Status.ABANDONED
&& control.canRestore()
&& ProjectUtil.branchExists(repoManager, change.getDest()));
detail.setCanDeleteDraft(control.canDeleteDraft(db));
detail.setStarred(control.getCurrentUser().getStarredChanges().contains(
changeId));
detail.setCanRevert(change.getStatus() == Change.Status.MERGED && control.canAddPatchSet());
detail.setCanCherryPick(control.getProjectControl().canUpload());
detail.setCanEdit(control.getRefControl().canWrite());
detail.setCanEditCommitMessage(change.getStatus().isOpen() && control.canAddPatchSet());
detail.setCanEditTopicName(control.canEditTopicName());
List<SubmitRecord> submitRecords = control.getSubmitRecords(db, patch);
for (SubmitRecord rec : submitRecords) {
if (rec.labels != null) {
for (SubmitRecord.Label lbl : rec.labels) {
aic.want(lbl.appliedBy);
}
}
if (detail.getChange().getStatus().isOpen()
&& rec.status == SubmitRecord.Status.OK
&& control.getRefControl().canSubmit()
&& ProjectUtil.branchExists(repoManager, change.getDest())) {
detail.setCanSubmit(true);
}
}
detail.setSubmitRecords(submitRecords);
detail.setSubmitTypeRecord(control.getSubmitTypeRecord(db, patch));
patchsetsById = new HashMap<PatchSet.Id, PatchSet>();
loadPatchSets();
loadMessages();
if (change.currentPatchSetId() != null) {
loadCurrentPatchSet();
}
load();
detail.setCanRebase(detail.getChange().getStatus().isOpen() &&
control.canRebase() &&
RebaseChange.canDoRebase(db, change, repoManager,
currentPatchSetAncestors, currentDepPatchSets, currentDepChanges));
detail.setAccounts(aic.create());
return detail;
}
private void loadPatchSets() throws OrmException {
ResultSet<PatchSet> source = db.patchSets().byChange(changeId);
List<PatchSet> patches = new ArrayList<PatchSet>();
Set<PatchSet.Id> patchesWithDraftComments = new HashSet<PatchSet.Id>();
final CurrentUser user = control.getCurrentUser();
final Account.Id me =
user.isIdentifiedUser() ? ((IdentifiedUser) user).getAccountId()
: null;
for (PatchSet ps : source) {
final PatchSet.Id psId = ps.getId();
if (control.isPatchVisible(ps, db)) {
patches.add(ps);
if (me != null
&& db.patchComments().draftByPatchSetAuthor(psId, me)
.iterator().hasNext()) {
patchesWithDraftComments.add(psId);
}
}
patchsetsById.put(psId, ps);
}
detail.setPatchSets(patches);
detail.setPatchSetsWithDraftComments(patchesWithDraftComments);
}
private void loadMessages() throws OrmException {
ResultSet<ChangeMessage> source = db.changeMessages().byChange(changeId);
List<ChangeMessage> msgList = new ArrayList<ChangeMessage>();
for (ChangeMessage msg : source) {
PatchSet.Id id = msg.getPatchSetId();
if (id != null) {
PatchSet ps = patchsetsById.get(msg.getPatchSetId());
if (ps != null && control.isPatchVisible(ps, db)) {
msgList.add(msg);
}
} else {
// Not guaranteed to have a non-null patchset id, so just display it.
msgList.add(msg);
}
}
detail.setMessages(msgList);
for (final ChangeMessage m : detail.getMessages()) {
aic.want(m.getAuthor());
}
}
private void load() throws OrmException, NoSuchChangeException,
NoSuchProjectException {
final Change.Status status = detail.getChange().getStatus();
if ((status.equals(Change.Status.NEW) || status.equals(Change.Status.DRAFT))) {
try {
detail.getChange().setMergeable(mergeable.apply(new RevisionResource(
new ChangeResource(control),
detail.getCurrentPatchSet())).mergeable);
} catch (RepositoryNotFoundException e) {
log.warn("Cannot check mergeable", e);
} catch (ResourceConflictException e) {
log.warn("Cannot check mergeable", e);
} catch (BadRequestException e) {
log.warn("Cannot check mergeable", e);
} catch (AuthException e) {
log.warn("Cannot check mergeable", e);
} catch (IOException e) {
log.warn("Cannot check mergeable", e);
}
}
}
private boolean isReviewer(Change change) {
// Return true if the currently logged in user is a reviewer of the change.
try {
return control.isReviewer(db, new ChangeData(change));
} catch (OrmException e) {
return false;
}
}
private void loadCurrentPatchSet() throws OrmException,
NoSuchEntityException, PatchSetInfoNotAvailableException,
NoSuchChangeException {
currentDepPatchSets = new ArrayList<PatchSet>();
currentDepChanges = new ArrayList<Change>();
final PatchSet currentPatch = findCurrentOrLatestPatchSet();
final PatchSet.Id psId = currentPatch.getId();
final PatchSetDetailFactory loader = patchSetDetail.create(null, psId, null);
loader.patchSet = currentPatch;
loader.control = control;
detail.setCurrentPatchSetDetail(loader.call());
detail.setCurrentPatchSetId(psId);
final HashSet<Change.Id> changesToGet = new HashSet<Change.Id>();
final HashMap<Change.Id,PatchSet.Id> ancestorPatchIds =
new HashMap<Change.Id,PatchSet.Id>();
final List<Change.Id> ancestorOrder = new ArrayList<Change.Id>();
currentPatchSetAncestors = db.patchSetAncestors().ancestorsOf(psId).toList();
for (PatchSetAncestor a : currentPatchSetAncestors) {
for (PatchSet p : db.patchSets().byRevision(a.getAncestorRevision())) {
currentDepPatchSets.add(p);
final Change.Id ck = p.getId().getParentKey();
if (changesToGet.add(ck)) {
ancestorPatchIds.put(ck, p.getId());
ancestorOrder.add(ck);
}
}
}
final Set<PatchSet.Id> descendants = new HashSet<PatchSet.Id>();
RevId cprev;
for (PatchSet p : detail.getPatchSets()) {
cprev = p.getRevision();
if (cprev != null) {
for (PatchSetAncestor a : db.patchSetAncestors().descendantsOf(cprev)) {
if (descendants.add(a.getPatchSet())) {
changesToGet.add(a.getPatchSet().getParentKey());
}
}
}
}
final Map<Change.Id, Change> m =
db.changes().toMap(db.changes().get(changesToGet));
final CurrentUser currentUser = control.getCurrentUser();
Account.Id currentUserId = null;
if (currentUser.isIdentifiedUser()) {
currentUserId = ((IdentifiedUser) currentUser).getAccountId();
}
final ArrayList<ChangeInfo> dependsOn = new ArrayList<ChangeInfo>();
for (final Change.Id a : ancestorOrder) {
final Change ac = m.get(a);
if (ac != null && ac.getProject().equals(detail.getChange().getProject())) {
currentDepChanges.add(ac);
if (ac.getStatus().getCode() != Change.STATUS_DRAFT
|| ac.getOwner().equals(currentUserId)
|| isReviewer(ac)) {
dependsOn.add(newChangeInfo(ac, ancestorPatchIds));
}
}
}
final ArrayList<ChangeInfo> neededBy = new ArrayList<ChangeInfo>();
for (final PatchSet.Id a : descendants) {
final Change ac = m.get(a.getParentKey());
if (ac != null && ac.currentPatchSetId().equals(a)) {
if (ac.getStatus().getCode() != Change.STATUS_DRAFT
|| ac.getOwner().equals(currentUserId)
|| isReviewer(ac)) {
neededBy.add(newChangeInfo(ac, null));
}
}
}
Collections.sort(neededBy, new Comparator<ChangeInfo>() {
public int compare(final ChangeInfo o1, final ChangeInfo o2) {
return o1.getId().get() - o2.getId().get();
}
});
detail.setDependsOn(dependsOn);
detail.setNeededBy(neededBy);
}
private PatchSet findCurrentOrLatestPatchSet() {
PatchSet currentPatch = detail.getCurrentPatchSet();
// If the current patch set is a draft and user can't see it, set the
// current patch set to whatever the latest one is
if (currentPatch == null) {
List<PatchSet> patchSets = detail.getPatchSets();
if (!detail.getPatchSets().isEmpty()) {
currentPatch = patchSets.get(patchSets.size() - 1);
} else {
// Shouldn't happen, change shouldn't be visible if all the patchsets
// are drafts
}
}
return currentPatch;
}
private ChangeInfo newChangeInfo(final Change ac,
Map<Change.Id,PatchSet.Id> ancestorPatchIds) {
aic.want(ac.getOwner());
ChangeInfo ci;
if (ancestorPatchIds == null) {
ci = new ChangeInfo(ac);
} else {
ci = new ChangeInfo(ac, ancestorPatchIds.get(ac.getId()));
}
ci.setStarred(isStarred(ac));
return ci;
}
private boolean isStarred(final Change ac) {
return control.getCurrentUser().getStarredChanges().contains(ac.getId());
}
}

View File

@@ -14,44 +14,26 @@
package com.google.gerrit.httpd.rpc.changedetail;
import com.google.gerrit.common.data.ChangeDetail;
import com.google.gerrit.common.data.ChangeDetailService;
import com.google.gerrit.common.data.IncludedInDetail;
import com.google.gerrit.common.data.PatchSetDetail;
import com.google.gerrit.common.data.PatchSetPublishDetail;
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwtjsonrpc.common.AsyncCallback;
import com.google.inject.Inject;
class ChangeDetailServiceImpl implements ChangeDetailService {
private final ChangeDetailFactory.Factory changeDetail;
private final IncludedInDetailFactory.Factory includedInDetail;
private final PatchSetDetailFactory.Factory patchSetDetail;
private final PatchSetPublishDetailFactory.Factory patchSetPublishDetail;
@Inject
ChangeDetailServiceImpl(final ChangeDetailFactory.Factory changeDetail,
final IncludedInDetailFactory.Factory includedInDetail,
ChangeDetailServiceImpl(
final PatchSetDetailFactory.Factory patchSetDetail,
final PatchSetPublishDetailFactory.Factory patchSetPublishDetail) {
this.changeDetail = changeDetail;
this.includedInDetail = includedInDetail;
this.patchSetDetail = patchSetDetail;
this.patchSetPublishDetail = patchSetPublishDetail;
}
public void changeDetail(final Change.Id id,
final AsyncCallback<ChangeDetail> callback) {
changeDetail.create(id).to(callback);
}
public void includedInDetail(final Change.Id id,
final AsyncCallback<IncludedInDetail> callback) {
includedInDetail.create(id).to(callback);
}
public void patchSetDetail(PatchSet.Id id,
AsyncCallback<PatchSetDetail> callback) {
patchSetDetail2(null, id, null, callback);

View File

@@ -28,8 +28,6 @@ public class ChangeModule extends RpcServletModule {
install(new FactoryModule() {
@Override
protected void configure() {
factory(ChangeDetailFactory.Factory.class);
factory(IncludedInDetailFactory.Factory.class);
factory(PatchSetDetailFactory.Factory.class);
factory(PatchSetPublishDetailFactory.Factory.class);
}

View File

@@ -1,95 +0,0 @@
// Copyright (C) 2010 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.changedetail;
import com.google.gerrit.common.data.IncludedInDetail;
import com.google.gerrit.common.errors.InvalidRevisionException;
import com.google.gerrit.httpd.rpc.Handler;
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.change.IncludedInResolver;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import java.io.IOException;
/** Creates a {@link IncludedInDetail} of a {@link Change}. */
class IncludedInDetailFactory extends Handler<IncludedInDetail> {
interface Factory {
IncludedInDetailFactory create(Change.Id id);
}
private final ReviewDb db;
private final ChangeControl.Factory changeControlFactory;
private final GitRepositoryManager repoManager;
private final Change.Id changeId;
private ChangeControl control;
@Inject
IncludedInDetailFactory(final ReviewDb db,
final ChangeControl.Factory changeControlFactory,
final GitRepositoryManager repoManager, @Assisted final Change.Id changeId) {
this.changeControlFactory = changeControlFactory;
this.repoManager = repoManager;
this.changeId = changeId;
this.db = db;
}
@Override
public IncludedInDetail call() throws OrmException, NoSuchChangeException,
IOException, InvalidRevisionException {
control = changeControlFactory.validateFor(changeId);
final PatchSet patch =
db.patchSets().get(control.getChange().currentPatchSetId());
final Repository repo =
repoManager.openRepository(control.getProject().getNameKey());
try {
final RevWalk rw = new RevWalk(repo);
try {
rw.setRetainBody(false);
final RevCommit rev;
try {
rev = rw.parseCommit(ObjectId.fromString(patch.getRevision().get()));
} catch (IncorrectObjectTypeException err) {
throw new InvalidRevisionException();
} catch (MissingObjectException err) {
throw new InvalidRevisionException();
}
return IncludedInResolver.resolve(repo, rw, rev);
} finally {
rw.release();
}
} finally {
repo.close();
}
}
}

View File

@@ -19,7 +19,6 @@ import com.google.gerrit.common.data.PatchScript;
import com.google.gerrit.common.errors.NoSuchEntityException;
import com.google.gerrit.httpd.rpc.BaseServiceImplementation;
import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.httpd.rpc.changedetail.ChangeDetailFactory;
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Patch;
@@ -48,7 +47,6 @@ class PatchDetailServiceImpl extends BaseServiceImplementation implements
final Provider<CurrentUser> currentUser,
final PatchScriptFactory.Factory patchScriptFactoryFactory,
final SaveDraft.Factory saveDraftFactory,
final ChangeDetailFactory.Factory changeDetailFactory,
final ChangeControl.Factory changeControlFactory) {
super(schema, currentUser);