// Copyright (C) 2012 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.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.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.extensions.common.ListChangesOption; import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Branch; import com.google.gerrit.reviewdb.client.Change; 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.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 NewGerritCallback extends com.google.gerrit.client.rpc.GerritCallback<ChangeInfo> { @Override public void onSuccess(ChangeInfo detail) { setChangeDetail(reverse(detail)); } } public static class IgnoreErrorCallback implements AsyncCallback<ChangeDetail> { @Override public void onSuccess(ChangeDetail info) { setChangeDetail(info); } @Override public void onFailure(Throwable caught) { } } 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(rev.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(info.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<>(); 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<>(); 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<>(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); StarredChanges.fireChangeStarEvent(chgId, detail.isStarred()); } private final Change.Id changeId; public ChangeDetailCache(final Change.Id chg) { changeId = chg; } public void refresh() { RestApi call = ChangeApi.detail(changeId.get()); ChangeList.addOptions(call, EnumSet.of( ListChangesOption.CURRENT_ACTIONS, ListChangesOption.ALL_REVISIONS, ListChangesOption.ALL_COMMITS)); call.get(new NewGerritCallback()); } }