Factor out RevisionJson from ChangeJson

ChangeJson has grow in size and became very hard to read. This commit is
a first step at modularizing the logic by factoring out RevisionJson.

It makes the concept of lazyloading purely internal to
{Change,Revision}Json by removing the parameter and deriving the
parameter based on the provided options only.

Change-Id: Ie04ec27723d145518277c84970462ab0e6c01979
This commit is contained in:
Patrick Hiesel
2018-10-09 09:25:05 +02:00
parent 021e6f9c13
commit ed56ba1370
10 changed files with 438 additions and 328 deletions

View File

@@ -16,29 +16,23 @@ package com.google.gerrit.server.change;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.extensions.client.ListChangesOption.ALL_COMMITS; import static com.google.gerrit.extensions.client.ListChangesOption.ALL_COMMITS;
import static com.google.gerrit.extensions.client.ListChangesOption.ALL_FILES;
import static com.google.gerrit.extensions.client.ListChangesOption.ALL_REVISIONS; import static com.google.gerrit.extensions.client.ListChangesOption.ALL_REVISIONS;
import static com.google.gerrit.extensions.client.ListChangesOption.CHANGE_ACTIONS; import static com.google.gerrit.extensions.client.ListChangesOption.CHANGE_ACTIONS;
import static com.google.gerrit.extensions.client.ListChangesOption.CHECK; import static com.google.gerrit.extensions.client.ListChangesOption.CHECK;
import static com.google.gerrit.extensions.client.ListChangesOption.COMMIT_FOOTERS; import static com.google.gerrit.extensions.client.ListChangesOption.COMMIT_FOOTERS;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_ACTIONS; import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_ACTIONS;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_COMMIT; import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_COMMIT;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_FILES;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_REVISION; import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_REVISION;
import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_ACCOUNTS; import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_ACCOUNTS;
import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_LABELS; import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_LABELS;
import static com.google.gerrit.extensions.client.ListChangesOption.DOWNLOAD_COMMANDS;
import static com.google.gerrit.extensions.client.ListChangesOption.LABELS; import static com.google.gerrit.extensions.client.ListChangesOption.LABELS;
import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES; import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES;
import static com.google.gerrit.extensions.client.ListChangesOption.PUSH_CERTIFICATES;
import static com.google.gerrit.extensions.client.ListChangesOption.REVIEWED; import static com.google.gerrit.extensions.client.ListChangesOption.REVIEWED;
import static com.google.gerrit.extensions.client.ListChangesOption.REVIEWER_UPDATES; import static com.google.gerrit.extensions.client.ListChangesOption.REVIEWER_UPDATES;
import static com.google.gerrit.extensions.client.ListChangesOption.SKIP_MERGEABLE; import static com.google.gerrit.extensions.client.ListChangesOption.SKIP_MERGEABLE;
import static com.google.gerrit.extensions.client.ListChangesOption.SUBMITTABLE; import static com.google.gerrit.extensions.client.ListChangesOption.SUBMITTABLE;
import static com.google.gerrit.extensions.client.ListChangesOption.TRACKING_IDS; import static com.google.gerrit.extensions.client.ListChangesOption.TRACKING_IDS;
import static com.google.gerrit.extensions.client.ListChangesOption.WEB_LINKS;
import static com.google.gerrit.server.ChangeMessagesUtil.createChangeMessageInfo; import static com.google.gerrit.server.ChangeMessagesUtil.createChangeMessageInfo;
import static com.google.gerrit.server.CommonConverters.toGitPerson;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
import com.google.auto.value.AutoValue; import com.google.auto.value.AutoValue;
@@ -74,22 +68,13 @@ import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ApprovalInfo; import com.google.gerrit.extensions.common.ApprovalInfo;
import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ChangeMessageInfo; import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.common.FetchInfo;
import com.google.gerrit.extensions.common.LabelInfo; import com.google.gerrit.extensions.common.LabelInfo;
import com.google.gerrit.extensions.common.ProblemInfo; import com.google.gerrit.extensions.common.ProblemInfo;
import com.google.gerrit.extensions.common.PushCertificateInfo;
import com.google.gerrit.extensions.common.ReviewerUpdateInfo; import com.google.gerrit.extensions.common.ReviewerUpdateInfo;
import com.google.gerrit.extensions.common.RevisionInfo; import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.common.SubmitRequirementInfo; import com.google.gerrit.extensions.common.SubmitRequirementInfo;
import com.google.gerrit.extensions.common.TrackingIdInfo; import com.google.gerrit.extensions.common.TrackingIdInfo;
import com.google.gerrit.extensions.common.VotingRangeInfo; import com.google.gerrit.extensions.common.VotingRangeInfo;
import com.google.gerrit.extensions.common.WebLinkInfo;
import com.google.gerrit.extensions.config.DownloadCommand;
import com.google.gerrit.extensions.config.DownloadScheme;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.Url; import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.index.query.QueryResult; import com.google.gerrit.index.query.QueryResult;
import com.google.gerrit.mail.Address; import com.google.gerrit.mail.Address;
@@ -100,30 +85,23 @@ import com.google.gerrit.metrics.Timer0;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.ChangeMessage; 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.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval; import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.ApprovalsUtil; import com.google.gerrit.server.ApprovalsUtil;
import com.google.gerrit.server.ChangeMessagesUtil; import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.FanOutExecutor; import com.google.gerrit.server.FanOutExecutor;
import com.google.gerrit.server.GpgException; import com.google.gerrit.server.GpgException;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.ReviewerByEmailSet; import com.google.gerrit.server.ReviewerByEmailSet;
import com.google.gerrit.server.ReviewerSet; import com.google.gerrit.server.ReviewerSet;
import com.google.gerrit.server.ReviewerStatusUpdate; import com.google.gerrit.server.ReviewerStatusUpdate;
import com.google.gerrit.server.StarredChangesUtil; import com.google.gerrit.server.StarredChangesUtil;
import com.google.gerrit.server.WebLinks;
import com.google.gerrit.server.account.AccountInfoComparator; import com.google.gerrit.server.account.AccountInfoComparator;
import com.google.gerrit.server.account.AccountLoader; import com.google.gerrit.server.account.AccountLoader;
import com.google.gerrit.server.account.GpgApiAdapter;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.TrackingFooters; import com.google.gerrit.server.config.TrackingFooters;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MergeUtil;
import com.google.gerrit.server.index.change.ChangeField; import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.notedb.ChangeNotes; import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ReviewerStateInternal; import com.google.gerrit.server.notedb.ReviewerStateInternal;
@@ -132,8 +110,6 @@ import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.LabelPermission; import com.google.gerrit.server.permissions.LabelPermission;
import com.google.gerrit.server.permissions.PermissionBackend; import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException; import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.project.RemoveReviewerControl; import com.google.gerrit.server.project.RemoveReviewerControl;
import com.google.gerrit.server.project.SubmitRuleOptions; import com.google.gerrit.server.project.SubmitRuleOptions;
import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.ChangeData;
@@ -163,11 +139,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
/** /**
* Produces {@link ChangeInfo} (which is serialized to JSON afterwards) from {@link ChangeData}. * Produces {@link ChangeInfo} (which is serialized to JSON afterwards) from {@link ChangeData}.
@@ -184,7 +155,7 @@ public class ChangeJson {
public static final SubmitRuleOptions SUBMIT_RULE_OPTIONS_STRICT = public static final SubmitRuleOptions SUBMIT_RULE_OPTIONS_STRICT =
ChangeField.SUBMIT_RULE_OPTIONS_STRICT.toBuilder().build(); ChangeField.SUBMIT_RULE_OPTIONS_STRICT.toBuilder().build();
public static final ImmutableSet<ListChangesOption> REQUIRE_LAZY_LOAD = static final ImmutableSet<ListChangesOption> REQUIRE_LAZY_LOAD =
ImmutableSet.of( ImmutableSet.of(
ALL_COMMITS, ALL_COMMITS,
ALL_REVISIONS, ALL_REVISIONS,
@@ -252,34 +223,24 @@ public class ChangeJson {
private final Provider<ReviewDb> db; private final Provider<ReviewDb> db;
private final Provider<CurrentUser> userProvider; private final Provider<CurrentUser> userProvider;
private final AnonymousUser anonymous;
private final PermissionBackend permissionBackend; private final PermissionBackend permissionBackend;
private final GitRepositoryManager repoManager;
private final ProjectCache projectCache;
private final MergeUtil.Factory mergeUtilFactory;
private final IdentifiedUser.GenericFactory userFactory;
private final ChangeData.Factory changeDataFactory; private final ChangeData.Factory changeDataFactory;
private final FileInfoJson fileInfoJson;
private final AccountLoader.Factory accountLoaderFactory; private final AccountLoader.Factory accountLoaderFactory;
private final DynamicMap<DownloadScheme> downloadSchemes;
private final DynamicMap<DownloadCommand> downloadCommands;
private final WebLinks webLinks;
private final ImmutableSet<ListChangesOption> options; private final ImmutableSet<ListChangesOption> options;
private final ChangeMessagesUtil cmUtil; private final ChangeMessagesUtil cmUtil;
private final Provider<ConsistencyChecker> checkerProvider; private final Provider<ConsistencyChecker> checkerProvider;
private final ActionJson actionJson; private final ActionJson actionJson;
private final GpgApiAdapter gpgApi;
private final ChangeNotes.Factory notesFactory; private final ChangeNotes.Factory notesFactory;
private final ChangeResource.Factory changeResourceFactory;
private final ChangeKindCache changeKindCache;
private final ApprovalsUtil approvalsUtil; private final ApprovalsUtil approvalsUtil;
private final RemoveReviewerControl removeReviewerControl; private final RemoveReviewerControl removeReviewerControl;
private final TrackingFooters trackingFooters; private final TrackingFooters trackingFooters;
private final Metrics metrics; private final Metrics metrics;
private final RevisionJson revisionJson;
private final boolean enableParallelFormatting; private final boolean enableParallelFormatting;
private final ExecutorService fanOutExecutor; private final ExecutorService fanOutExecutor;
private final boolean lazyLoad;
private boolean lazyLoad = true;
private AccountLoader accountLoader; private AccountLoader accountLoader;
private FixInput fix; private FixInput fix;
private PluginDefinedAttributesFactory pluginDefinedAttributesFactory; private PluginDefinedAttributesFactory pluginDefinedAttributesFactory;
@@ -288,72 +249,42 @@ public class ChangeJson {
ChangeJson( ChangeJson(
Provider<ReviewDb> db, Provider<ReviewDb> db,
Provider<CurrentUser> user, Provider<CurrentUser> user,
AnonymousUser au,
PermissionBackend permissionBackend, PermissionBackend permissionBackend,
GitRepositoryManager repoManager,
ProjectCache projectCache,
MergeUtil.Factory mergeUtilFactory,
IdentifiedUser.GenericFactory uf,
ChangeData.Factory cdf, ChangeData.Factory cdf,
FileInfoJson fileInfoJson,
AccountLoader.Factory ailf, AccountLoader.Factory ailf,
DynamicMap<DownloadScheme> downloadSchemes,
DynamicMap<DownloadCommand> downloadCommands,
WebLinks webLinks,
ChangeMessagesUtil cmUtil, ChangeMessagesUtil cmUtil,
Provider<ConsistencyChecker> checkerProvider, Provider<ConsistencyChecker> checkerProvider,
ActionJson actionJson, ActionJson actionJson,
GpgApiAdapter gpgApi,
ChangeNotes.Factory notesFactory, ChangeNotes.Factory notesFactory,
ChangeResource.Factory changeResourceFactory,
ChangeKindCache changeKindCache,
ApprovalsUtil approvalsUtil, ApprovalsUtil approvalsUtil,
RemoveReviewerControl removeReviewerControl, RemoveReviewerControl removeReviewerControl,
TrackingFooters trackingFooters, TrackingFooters trackingFooters,
Metrics metrics, Metrics metrics,
RevisionJson.Factory revisionJsonFactory,
@GerritServerConfig Config config, @GerritServerConfig Config config,
@FanOutExecutor ExecutorService fanOutExecutor, @FanOutExecutor ExecutorService fanOutExecutor,
@Assisted Iterable<ListChangesOption> options) { @Assisted Iterable<ListChangesOption> options) {
this.db = db; this.db = db;
this.userProvider = user; this.userProvider = user;
this.anonymous = au;
this.changeDataFactory = cdf; this.changeDataFactory = cdf;
this.permissionBackend = permissionBackend; this.permissionBackend = permissionBackend;
this.repoManager = repoManager;
this.userFactory = uf;
this.projectCache = projectCache;
this.mergeUtilFactory = mergeUtilFactory;
this.fileInfoJson = fileInfoJson;
this.accountLoaderFactory = ailf; this.accountLoaderFactory = ailf;
this.downloadSchemes = downloadSchemes;
this.downloadCommands = downloadCommands;
this.webLinks = webLinks;
this.cmUtil = cmUtil; this.cmUtil = cmUtil;
this.checkerProvider = checkerProvider; this.checkerProvider = checkerProvider;
this.actionJson = actionJson; this.actionJson = actionJson;
this.gpgApi = gpgApi;
this.notesFactory = notesFactory; this.notesFactory = notesFactory;
this.changeResourceFactory = changeResourceFactory;
this.changeKindCache = changeKindCache;
this.approvalsUtil = approvalsUtil; this.approvalsUtil = approvalsUtil;
this.removeReviewerControl = removeReviewerControl; this.removeReviewerControl = removeReviewerControl;
this.trackingFooters = trackingFooters; this.trackingFooters = trackingFooters;
this.metrics = metrics; this.metrics = metrics;
this.revisionJson = revisionJsonFactory.create(options);
this.enableParallelFormatting = config.getBoolean("change", "enableParallelFormatting", false); this.enableParallelFormatting = config.getBoolean("change", "enableParallelFormatting", false);
this.fanOutExecutor = fanOutExecutor; this.fanOutExecutor = fanOutExecutor;
this.options = Sets.immutableEnumSet(options); this.options = Sets.immutableEnumSet(options);
this.lazyLoad = containsAnyOf(this.options, REQUIRE_LAZY_LOAD);
logger.atFine().log("options = %s", options); logger.atFine().log("options = %s", options);
} }
/**
* See {@link ChangeData#setLazyLoad(boolean)}. If lazyLoad is set, converting data from
* index-backed {@link ChangeData} will fail with an exception.
*/
public ChangeJson lazyLoad(boolean load) {
lazyLoad = load;
return this;
}
public ChangeJson fix(FixInput fix) { public ChangeJson fix(FixInput fix) {
this.fix = fix; this.fix = fix;
return this; return this;
@@ -719,7 +650,7 @@ public class ChangeJson {
// This block must come after the ChangeInfo is mostly populated, since // This block must come after the ChangeInfo is mostly populated, since
// it will be passed to ActionVisitors as-is. // it will be passed to ActionVisitors as-is.
if (needRevisions) { if (needRevisions) {
out.revisions = revisions(cd, src, limitToPsId, out); out.revisions = revisionJson.getRevisions(accountLoader, cd, src, limitToPsId, out);
if (out.revisions != null) { if (out.revisions != null) {
for (Map.Entry<String, RevisionInfo> entry : out.revisions.entrySet()) { for (Map.Entry<String, RevisionInfo> entry : out.revisions.entrySet()) {
if (entry.getValue().isCurrent) { if (entry.getValue().isCurrent) {
@@ -1305,47 +1236,6 @@ public class ChangeJson {
.collect(toList()); .collect(toList());
} }
@Nullable
private Repository openRepoIfNecessary(Project.NameKey project) throws IOException {
if (has(ALL_COMMITS) || has(CURRENT_COMMIT) || has(COMMIT_FOOTERS)) {
return repoManager.openRepository(project);
}
return null;
}
@Nullable
private RevWalk newRevWalk(@Nullable Repository repo) {
return repo != null ? new RevWalk(repo) : null;
}
private Map<String, RevisionInfo> revisions(
ChangeData cd,
Map<PatchSet.Id, PatchSet> map,
Optional<PatchSet.Id> limitToPsId,
ChangeInfo changeInfo)
throws PatchListNotAvailableException, GpgException, OrmException, IOException,
PermissionBackendException {
Map<String, RevisionInfo> res = new LinkedHashMap<>();
try (Repository repo = openRepoIfNecessary(cd.project());
RevWalk rw = newRevWalk(repo)) {
for (PatchSet in : map.values()) {
PatchSet.Id id = in.getId();
boolean want;
if (has(ALL_REVISIONS)) {
want = true;
} else if (limitToPsId.isPresent()) {
want = id.equals(limitToPsId.get());
} else {
want = id.equals(cd.change().currentPatchSetId());
}
if (want) {
res.put(in.getRevision().get(), toRevisionInfo(cd, in, repo, rw, false, changeInfo));
}
}
return res;
}
}
private Map<PatchSet.Id, PatchSet> loadPatchSets(ChangeData cd, Optional<PatchSet.Id> limitToPsId) private Map<PatchSet.Id, PatchSet> loadPatchSets(ChangeData cd, Optional<PatchSet.Id> limitToPsId)
throws OrmException { throws OrmException {
Collection<PatchSet> src; Collection<PatchSet> src;
@@ -1373,174 +1263,6 @@ public class ChangeJson {
return map; return map;
} }
public RevisionInfo getRevisionInfo(ChangeData cd, PatchSet in)
throws PatchListNotAvailableException, GpgException, OrmException, IOException,
PermissionBackendException {
accountLoader = accountLoaderFactory.create(has(DETAILED_ACCOUNTS));
try (Repository repo = openRepoIfNecessary(cd.project());
RevWalk rw = newRevWalk(repo)) {
RevisionInfo rev = toRevisionInfo(cd, in, repo, rw, true, null);
accountLoader.fill();
return rev;
}
}
private RevisionInfo toRevisionInfo(
ChangeData cd,
PatchSet in,
@Nullable Repository repo,
@Nullable RevWalk rw,
boolean fillCommit,
@Nullable ChangeInfo changeInfo)
throws PatchListNotAvailableException, GpgException, OrmException, IOException,
PermissionBackendException {
Change c = cd.change();
RevisionInfo out = new RevisionInfo();
out.isCurrent = in.getId().equals(c.currentPatchSetId());
out._number = in.getId().get();
out.ref = in.getRefName();
out.created = in.getCreatedOn();
out.uploader = accountLoader.get(in.getUploader());
out.fetch = makeFetchMap(cd, in);
out.kind = changeKindCache.getChangeKind(rw, repo != null ? repo.getConfig() : null, cd, in);
out.description = in.getDescription();
boolean setCommit = has(ALL_COMMITS) || (out.isCurrent && has(CURRENT_COMMIT));
boolean addFooters = out.isCurrent && has(COMMIT_FOOTERS);
if (setCommit || addFooters) {
checkState(rw != null);
checkState(repo != null);
Project.NameKey project = c.getProject();
String rev = in.getRevision().get();
RevCommit commit = rw.parseCommit(ObjectId.fromString(rev));
rw.parseBody(commit);
if (setCommit) {
out.commit = toCommit(project, rw, commit, has(WEB_LINKS), fillCommit);
}
if (addFooters) {
Ref ref = repo.exactRef(cd.change().getDest().get());
RevCommit mergeTip = null;
if (ref != null) {
mergeTip = rw.parseCommit(ref.getObjectId());
rw.parseBody(mergeTip);
}
out.commitWithFooters =
mergeUtilFactory
.create(projectCache.get(project))
.createCommitMessageOnSubmit(commit, mergeTip, cd.notes(), in.getId());
}
}
if (has(ALL_FILES) || (out.isCurrent && has(CURRENT_FILES))) {
out.files = fileInfoJson.toFileInfoMap(c, in);
out.files.remove(Patch.COMMIT_MSG);
out.files.remove(Patch.MERGE_LIST);
}
if (out.isCurrent && has(CURRENT_ACTIONS) && userProvider.get().isIdentifiedUser()) {
actionJson.addRevisionActions(
changeInfo,
out,
new RevisionResource(changeResourceFactory.create(cd.notes(), userProvider.get()), in));
}
if (gpgApi.isEnabled() && has(PUSH_CERTIFICATES)) {
if (in.getPushCertificate() != null) {
out.pushCertificate =
gpgApi.checkPushCertificate(
in.getPushCertificate(), userFactory.create(in.getUploader()));
} else {
out.pushCertificate = new PushCertificateInfo();
}
}
return out;
}
public CommitInfo toCommit(
Project.NameKey project, RevWalk rw, RevCommit commit, boolean addLinks, boolean fillCommit)
throws IOException {
CommitInfo info = new CommitInfo();
if (fillCommit) {
info.commit = commit.name();
}
info.parents = new ArrayList<>(commit.getParentCount());
info.author = toGitPerson(commit.getAuthorIdent());
info.committer = toGitPerson(commit.getCommitterIdent());
info.subject = commit.getShortMessage();
info.message = commit.getFullMessage();
if (addLinks) {
List<WebLinkInfo> links = webLinks.getPatchSetLinks(project, commit.name());
info.webLinks = links.isEmpty() ? null : links;
}
for (RevCommit parent : commit.getParents()) {
rw.parseBody(parent);
CommitInfo i = new CommitInfo();
i.commit = parent.name();
i.subject = parent.getShortMessage();
if (addLinks) {
List<WebLinkInfo> parentLinks = webLinks.getParentLinks(project, parent.name());
i.webLinks = parentLinks.isEmpty() ? null : parentLinks;
}
info.parents.add(i);
}
return info;
}
private Map<String, FetchInfo> makeFetchMap(ChangeData cd, PatchSet in)
throws PermissionBackendException, OrmException, IOException {
Map<String, FetchInfo> r = new LinkedHashMap<>();
for (Extension<DownloadScheme> e : downloadSchemes) {
String schemeName = e.getExportName();
DownloadScheme scheme = e.getProvider().get();
if (!scheme.isEnabled()
|| (scheme.isAuthRequired() && !userProvider.get().isIdentifiedUser())) {
continue;
}
if (!scheme.isAuthSupported() && !isWorldReadable(cd)) {
continue;
}
String projectName = cd.project().get();
String url = scheme.getUrl(projectName);
String refName = in.getRefName();
FetchInfo fetchInfo = new FetchInfo(url, refName);
r.put(schemeName, fetchInfo);
if (has(DOWNLOAD_COMMANDS)) {
populateFetchMap(scheme, downloadCommands, projectName, refName, fetchInfo);
}
}
return r;
}
public static void populateFetchMap(
DownloadScheme scheme,
DynamicMap<DownloadCommand> commands,
String projectName,
String refName,
FetchInfo fetchInfo) {
for (Extension<DownloadCommand> e2 : commands) {
String commandName = e2.getExportName();
DownloadCommand command = e2.getProvider().get();
String c = command.getCommand(scheme, projectName, refName);
if (c != null) {
addCommand(fetchInfo, commandName, c);
}
}
}
private static void addCommand(FetchInfo fetchInfo, String commandName, String c) {
if (fetchInfo.commands == null) {
fetchInfo.commands = new TreeMap<>();
}
fetchInfo.commands.put(commandName, c);
}
static void finish(ChangeInfo info) { static void finish(ChangeInfo info) {
info.id = info.id =
Joiner.on('~') Joiner.on('~')
@@ -1576,19 +1298,9 @@ public class ChangeJson {
: withUser.indexedChange(cd, notesFactory.createFromIndexedChange(cd.change())); : withUser.indexedChange(cd, notesFactory.createFromIndexedChange(cd.change()));
} }
private boolean isWorldReadable(ChangeData cd) private static boolean containsAnyOf(
throws OrmException, PermissionBackendException, IOException { ImmutableSet<ListChangesOption> set, ImmutableSet<ListChangesOption> toFind) {
try { return !Sets.intersection(toFind, set).isEmpty();
permissionBackendForChange(anonymous, cd).check(ChangePermission.READ);
} catch (AuthException ae) {
return false;
}
ProjectState projectState = projectCache.checkedGet(cd.project());
if (projectState == null) {
logger.atSevere().log("project state for project %s is null", cd.project());
return false;
}
return projectState.statePermitsRead();
} }
@AutoValue @AutoValue

View File

@@ -0,0 +1,402 @@
// Copyright (C) 2018 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.server.change;
import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.extensions.client.ListChangesOption.ALL_COMMITS;
import static com.google.gerrit.extensions.client.ListChangesOption.ALL_FILES;
import static com.google.gerrit.extensions.client.ListChangesOption.ALL_REVISIONS;
import static com.google.gerrit.extensions.client.ListChangesOption.COMMIT_FOOTERS;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_ACTIONS;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_COMMIT;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_FILES;
import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_ACCOUNTS;
import static com.google.gerrit.extensions.client.ListChangesOption.DOWNLOAD_COMMANDS;
import static com.google.gerrit.extensions.client.ListChangesOption.PUSH_CERTIFICATES;
import static com.google.gerrit.extensions.client.ListChangesOption.WEB_LINKS;
import static com.google.gerrit.server.CommonConverters.toGitPerson;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.common.FetchInfo;
import com.google.gerrit.extensions.common.PushCertificateInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.common.WebLinkInfo;
import com.google.gerrit.extensions.config.DownloadCommand;
import com.google.gerrit.extensions.config.DownloadScheme;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSet.Id;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.GpgException;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.WebLinks;
import com.google.gerrit.server.account.AccountLoader;
import com.google.gerrit.server.account.GpgApiAdapter;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MergeUtil;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
public class RevisionJson {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
public interface Factory {
RevisionJson create(Iterable<ListChangesOption> options);
}
private final MergeUtil.Factory mergeUtilFactory;
private final IdentifiedUser.GenericFactory userFactory;
private final FileInfoJson fileInfoJson;
private final GpgApiAdapter gpgApi;
private final ChangeResource.Factory changeResourceFactory;
private final ChangeKindCache changeKindCache;
private final ActionJson actionJson;
private final DynamicMap<DownloadScheme> downloadSchemes;
private final DynamicMap<DownloadCommand> downloadCommands;
private final WebLinks webLinks;
private final Provider<CurrentUser> userProvider;
private final ProjectCache projectCache;
private final ImmutableSet<ListChangesOption> options;
private final AccountLoader.Factory accountLoaderFactory;
private final AnonymousUser anonymous;
private final GitRepositoryManager repoManager;
private final PermissionBackend permissionBackend;
private final ChangeNotes.Factory notesFactory;
private final boolean lazyLoad;
@Inject
RevisionJson(
Provider<CurrentUser> userProvider,
AnonymousUser anonymous,
ProjectCache projectCache,
IdentifiedUser.GenericFactory userFactory,
MergeUtil.Factory mergeUtilFactory,
FileInfoJson fileInfoJson,
AccountLoader.Factory accountLoaderFactory,
DynamicMap<DownloadScheme> downloadSchemes,
DynamicMap<DownloadCommand> downloadCommands,
WebLinks webLinks,
ActionJson actionJson,
GpgApiAdapter gpgApi,
ChangeResource.Factory changeResourceFactory,
ChangeKindCache changeKindCache,
GitRepositoryManager repoManager,
PermissionBackend permissionBackend,
ChangeNotes.Factory notesFactory,
@Assisted Iterable<ListChangesOption> options) {
this.userProvider = userProvider;
this.anonymous = anonymous;
this.projectCache = projectCache;
this.userFactory = userFactory;
this.mergeUtilFactory = mergeUtilFactory;
this.fileInfoJson = fileInfoJson;
this.accountLoaderFactory = accountLoaderFactory;
this.downloadSchemes = downloadSchemes;
this.downloadCommands = downloadCommands;
this.webLinks = webLinks;
this.actionJson = actionJson;
this.gpgApi = gpgApi;
this.changeResourceFactory = changeResourceFactory;
this.changeKindCache = changeKindCache;
this.permissionBackend = permissionBackend;
this.notesFactory = notesFactory;
this.repoManager = repoManager;
this.options = ImmutableSet.copyOf(options);
this.lazyLoad = containsAnyOf(this.options, ChangeJson.REQUIRE_LAZY_LOAD);
}
public static void populateFetchMap(
DownloadScheme scheme,
DynamicMap<DownloadCommand> commands,
String projectName,
String refName,
FetchInfo fetchInfo) {
for (Extension<DownloadCommand> e2 : commands) {
String commandName = e2.getExportName();
DownloadCommand command = e2.getProvider().get();
String c = command.getCommand(scheme, projectName, refName);
if (c != null) {
addCommand(fetchInfo, commandName, c);
}
}
}
public RevisionInfo getRevisionInfo(ChangeData cd, PatchSet in)
throws PatchListNotAvailableException, GpgException, OrmException, IOException,
PermissionBackendException {
AccountLoader accountLoader = accountLoaderFactory.create(has(DETAILED_ACCOUNTS));
try (Repository repo = openRepoIfNecessary(cd.project());
RevWalk rw = newRevWalk(repo)) {
RevisionInfo rev = toRevisionInfo(accountLoader, cd, in, repo, rw, true, null);
accountLoader.fill();
return rev;
}
}
public CommitInfo toCommit(
Project.NameKey project, RevWalk rw, RevCommit commit, boolean addLinks, boolean fillCommit)
throws IOException {
CommitInfo info = new CommitInfo();
if (fillCommit) {
info.commit = commit.name();
}
info.parents = new ArrayList<>(commit.getParentCount());
info.author = toGitPerson(commit.getAuthorIdent());
info.committer = toGitPerson(commit.getCommitterIdent());
info.subject = commit.getShortMessage();
info.message = commit.getFullMessage();
if (addLinks) {
List<WebLinkInfo> links = webLinks.getPatchSetLinks(project, commit.name());
info.webLinks = links.isEmpty() ? null : links;
}
for (RevCommit parent : commit.getParents()) {
rw.parseBody(parent);
CommitInfo i = new CommitInfo();
i.commit = parent.name();
i.subject = parent.getShortMessage();
if (addLinks) {
List<WebLinkInfo> parentLinks = webLinks.getParentLinks(project, parent.name());
i.webLinks = parentLinks.isEmpty() ? null : parentLinks;
}
info.parents.add(i);
}
return info;
}
Map<String, RevisionInfo> getRevisions(
AccountLoader accountLoader,
ChangeData cd,
Map<PatchSet.Id, PatchSet> map,
Optional<Id> limitToPsId,
ChangeInfo changeInfo)
throws PatchListNotAvailableException, GpgException, OrmException, IOException,
PermissionBackendException {
Map<String, RevisionInfo> res = new LinkedHashMap<>();
try (Repository repo = openRepoIfNecessary(cd.project());
RevWalk rw = newRevWalk(repo)) {
for (PatchSet in : map.values()) {
PatchSet.Id id = in.getId();
boolean want;
if (has(ALL_REVISIONS)) {
want = true;
} else if (limitToPsId.isPresent()) {
want = id.equals(limitToPsId.get());
} else {
want = id.equals(cd.change().currentPatchSetId());
}
if (want) {
res.put(
in.getRevision().get(),
toRevisionInfo(accountLoader, cd, in, repo, rw, false, changeInfo));
}
}
return res;
}
}
private static void addCommand(FetchInfo fetchInfo, String commandName, String c) {
if (fetchInfo.commands == null) {
fetchInfo.commands = new TreeMap<>();
}
fetchInfo.commands.put(commandName, c);
}
private Map<String, FetchInfo> makeFetchMap(ChangeData cd, PatchSet in)
throws PermissionBackendException, OrmException, IOException {
Map<String, FetchInfo> r = new LinkedHashMap<>();
for (Extension<DownloadScheme> e : downloadSchemes) {
String schemeName = e.getExportName();
DownloadScheme scheme = e.getProvider().get();
if (!scheme.isEnabled()
|| (scheme.isAuthRequired() && !userProvider.get().isIdentifiedUser())) {
continue;
}
if (!scheme.isAuthSupported() && !isWorldReadable(cd)) {
continue;
}
String projectName = cd.project().get();
String url = scheme.getUrl(projectName);
String refName = in.getRefName();
FetchInfo fetchInfo = new FetchInfo(url, refName);
r.put(schemeName, fetchInfo);
if (has(DOWNLOAD_COMMANDS)) {
populateFetchMap(scheme, downloadCommands, projectName, refName, fetchInfo);
}
}
return r;
}
private RevisionInfo toRevisionInfo(
AccountLoader accountLoader,
ChangeData cd,
PatchSet in,
@Nullable Repository repo,
@Nullable RevWalk rw,
boolean fillCommit,
@Nullable ChangeInfo changeInfo)
throws PatchListNotAvailableException, GpgException, OrmException, IOException,
PermissionBackendException {
Change c = cd.change();
RevisionInfo out = new RevisionInfo();
out.isCurrent = in.getId().equals(c.currentPatchSetId());
out._number = in.getId().get();
out.ref = in.getRefName();
out.created = in.getCreatedOn();
out.uploader = accountLoader.get(in.getUploader());
out.fetch = makeFetchMap(cd, in);
out.kind = changeKindCache.getChangeKind(rw, repo != null ? repo.getConfig() : null, cd, in);
out.description = in.getDescription();
boolean setCommit = has(ALL_COMMITS) || (out.isCurrent && has(CURRENT_COMMIT));
boolean addFooters = out.isCurrent && has(COMMIT_FOOTERS);
if (setCommit || addFooters) {
checkState(rw != null);
checkState(repo != null);
Project.NameKey project = c.getProject();
String rev = in.getRevision().get();
RevCommit commit = rw.parseCommit(ObjectId.fromString(rev));
rw.parseBody(commit);
if (setCommit) {
out.commit = toCommit(project, rw, commit, has(WEB_LINKS), fillCommit);
}
if (addFooters) {
Ref ref = repo.exactRef(cd.change().getDest().get());
RevCommit mergeTip = null;
if (ref != null) {
mergeTip = rw.parseCommit(ref.getObjectId());
rw.parseBody(mergeTip);
}
out.commitWithFooters =
mergeUtilFactory
.create(projectCache.get(project))
.createCommitMessageOnSubmit(commit, mergeTip, cd.notes(), in.getId());
}
}
if (has(ALL_FILES) || (out.isCurrent && has(CURRENT_FILES))) {
out.files = fileInfoJson.toFileInfoMap(c, in);
out.files.remove(Patch.COMMIT_MSG);
out.files.remove(Patch.MERGE_LIST);
}
if (out.isCurrent && has(CURRENT_ACTIONS) && userProvider.get().isIdentifiedUser()) {
actionJson.addRevisionActions(
changeInfo,
out,
new RevisionResource(changeResourceFactory.create(cd.notes(), userProvider.get()), in));
}
if (gpgApi.isEnabled() && has(PUSH_CERTIFICATES)) {
if (in.getPushCertificate() != null) {
out.pushCertificate =
gpgApi.checkPushCertificate(
in.getPushCertificate(), userFactory.create(in.getUploader()));
} else {
out.pushCertificate = new PushCertificateInfo();
}
}
return out;
}
private boolean has(ListChangesOption option) {
return options.contains(option);
}
/**
* @return {@link com.google.gerrit.server.permissions.PermissionBackend.ForChange} constructed
* from either an index-backed or a database-backed {@link ChangeData} depending on {@code
* lazyload}.
*/
private PermissionBackend.ForChange permissionBackendForChange(
PermissionBackend.WithUser withUser, ChangeData cd) throws OrmException {
return lazyLoad
? withUser.change(cd)
: withUser.indexedChange(cd, notesFactory.createFromIndexedChange(cd.change()));
}
private boolean isWorldReadable(ChangeData cd)
throws OrmException, PermissionBackendException, IOException {
try {
permissionBackendForChange(permissionBackend.user(anonymous), cd)
.check(ChangePermission.READ);
} catch (AuthException ae) {
return false;
}
ProjectState projectState = projectCache.checkedGet(cd.project());
if (projectState == null) {
logger.atSevere().log("project state for project %s is null", cd.project());
return false;
}
return projectState.statePermitsRead();
}
@Nullable
private Repository openRepoIfNecessary(Project.NameKey project) throws IOException {
if (has(ALL_COMMITS) || has(CURRENT_COMMIT) || has(COMMIT_FOOTERS)) {
return repoManager.openRepository(project);
}
return null;
}
@Nullable
private RevWalk newRevWalk(@Nullable Repository repo) {
return repo != null ? new RevWalk(repo) : null;
}
private static boolean containsAnyOf(
ImmutableSet<ListChangesOption> set, ImmutableSet<ListChangesOption> toFind) {
return !Sets.intersection(toFind, set).isEmpty();
}
}

View File

@@ -103,6 +103,7 @@ import com.google.gerrit.server.change.ChangeJson;
import com.google.gerrit.server.change.ChangeKindCacheImpl; import com.google.gerrit.server.change.ChangeKindCacheImpl;
import com.google.gerrit.server.change.MergeabilityCacheImpl; import com.google.gerrit.server.change.MergeabilityCacheImpl;
import com.google.gerrit.server.change.ReviewerSuggestion; import com.google.gerrit.server.change.ReviewerSuggestion;
import com.google.gerrit.server.change.RevisionJson;
import com.google.gerrit.server.events.EventFactory; import com.google.gerrit.server.events.EventFactory;
import com.google.gerrit.server.events.EventListener; import com.google.gerrit.server.events.EventListener;
import com.google.gerrit.server.events.EventsMetrics; import com.google.gerrit.server.events.EventsMetrics;
@@ -266,6 +267,7 @@ public class GerritGlobalModule extends FactoryModule {
factory(ProjectState.Factory.class); factory(ProjectState.Factory.class);
factory(RegisterNewEmailSender.Factory.class); factory(RegisterNewEmailSender.Factory.class);
factory(ReplacePatchSetSender.Factory.class); factory(ReplacePatchSetSender.Factory.class);
factory(RevisionJson.Factory.class);
factory(SetAssigneeSender.Factory.class); factory(SetAssigneeSender.Factory.class);
factory(InboundEmailRejectionSender.Factory.class); factory(InboundEmailRejectionSender.Factory.class);
bind(PermissionCollection.Factory.class); bind(PermissionCollection.Factory.class);

View File

@@ -23,7 +23,7 @@ import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.registration.Extension; import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.server.CommonConverters; import com.google.gerrit.server.CommonConverters;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.change.ChangeJson; import com.google.gerrit.server.change.RevisionJson;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
@@ -97,7 +97,7 @@ public class ChangeEditJson {
FetchInfo fetchInfo = new FetchInfo(scheme.getUrl(projectName), refName); FetchInfo fetchInfo = new FetchInfo(scheme.getUrl(projectName), refName);
r.put(schemeName, fetchInfo); r.put(schemeName, fetchInfo);
ChangeJson.populateFetchMap(scheme, downloadCommands, projectName, refName, fetchInfo); RevisionJson.populateFetchMap(scheme, downloadCommands, projectName, refName, fetchInfo);
} }
return r; return r;

View File

@@ -29,6 +29,7 @@ import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GpgException; import com.google.gerrit.server.GpgException;
import com.google.gerrit.server.account.AccountState; import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.change.ChangeJson; import com.google.gerrit.server.change.ChangeJson;
import com.google.gerrit.server.change.RevisionJson;
import com.google.gerrit.server.patch.PatchListNotAvailableException; import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.permissions.PermissionBackendException; import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.ChangeData;
@@ -64,15 +65,18 @@ public class EventUtil {
private final ChangeData.Factory changeDataFactory; private final ChangeData.Factory changeDataFactory;
private final Provider<ReviewDb> db; private final Provider<ReviewDb> db;
private final ChangeJson.Factory changeJsonFactory; private final ChangeJson.Factory changeJsonFactory;
private final RevisionJson.Factory revisionJsonFactory;
@Inject @Inject
EventUtil( EventUtil(
ChangeJson.Factory changeJsonFactory, ChangeJson.Factory changeJsonFactory,
RevisionJson.Factory revisionJsonFactory,
ChangeData.Factory changeDataFactory, ChangeData.Factory changeDataFactory,
Provider<ReviewDb> db) { Provider<ReviewDb> db) {
this.changeDataFactory = changeDataFactory; this.changeDataFactory = changeDataFactory;
this.db = db; this.db = db;
this.changeJsonFactory = changeJsonFactory; this.changeJsonFactory = changeJsonFactory;
this.revisionJsonFactory = revisionJsonFactory;
} }
public ChangeInfo changeInfo(Change change) throws OrmException { public ChangeInfo changeInfo(Change change) throws OrmException {
@@ -89,7 +93,7 @@ public class EventUtil {
throws OrmException, PatchListNotAvailableException, GpgException, IOException, throws OrmException, PatchListNotAvailableException, GpgException, IOException,
PermissionBackendException { PermissionBackendException {
ChangeData cd = changeDataFactory.create(db.get(), project, ps.getId().getParentKey()); ChangeData cd = changeDataFactory.create(db.get(), project, ps.getId().getParentKey());
return changeJsonFactory.create(CHANGE_OPTIONS).getRevisionInfo(cd, ps); return revisionJsonFactory.create(CHANGE_OPTIONS).getRevisionInfo(cd, ps);
} }
public AccountInfo accountInfo(AccountState accountState) { public AccountInfo accountInfo(AccountState accountState) {

View File

@@ -14,12 +14,13 @@
package com.google.gerrit.server.restapi.change; package com.google.gerrit.server.restapi.change;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.extensions.common.CommitInfo; import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.restapi.CacheControl; import com.google.gerrit.extensions.restapi.CacheControl;
import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView; import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.change.ChangeJson; import com.google.gerrit.server.change.RevisionJson;
import com.google.gerrit.server.change.RevisionResource; import com.google.gerrit.server.change.RevisionResource;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -33,12 +34,12 @@ import org.kohsuke.args4j.Option;
public class GetCommit implements RestReadView<RevisionResource> { public class GetCommit implements RestReadView<RevisionResource> {
private final GitRepositoryManager repoManager; private final GitRepositoryManager repoManager;
private final ChangeJson.Factory json; private final RevisionJson.Factory json;
private boolean addLinks; private boolean addLinks;
@Inject @Inject
GetCommit(GitRepositoryManager repoManager, ChangeJson.Factory json) { GetCommit(GitRepositoryManager repoManager, RevisionJson.Factory json) {
this.repoManager = repoManager; this.repoManager = repoManager;
this.json = json; this.json = json;
} }
@@ -57,7 +58,8 @@ public class GetCommit implements RestReadView<RevisionResource> {
String rev = rsrc.getPatchSet().getRevision().get(); String rev = rsrc.getPatchSet().getRevision().get();
RevCommit commit = rw.parseCommit(ObjectId.fromString(rev)); RevCommit commit = rw.parseCommit(ObjectId.fromString(rev));
rw.parseBody(commit); rw.parseBody(commit);
CommitInfo info = json.noOptions().toCommit(rsrc.getProject(), rw, commit, addLinks, true); CommitInfo info =
json.create(ImmutableSet.of()).toCommit(rsrc.getProject(), rw, commit, addLinks, true);
Response<CommitInfo> r = Response.ok(info); Response<CommitInfo> r = Response.ok(info);
if (rsrc.isCacheable()) { if (rsrc.isCacheable()) {
r.caching(CacheControl.PRIVATE(7, TimeUnit.DAYS)); r.caching(CacheControl.PRIVATE(7, TimeUnit.DAYS));

View File

@@ -15,13 +15,14 @@
package com.google.gerrit.server.restapi.change; package com.google.gerrit.server.restapi.change;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.extensions.common.CommitInfo; import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.restapi.BadRequestException; import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.CacheControl; import com.google.gerrit.extensions.restapi.CacheControl;
import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView; import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.change.ChangeJson; import com.google.gerrit.server.change.RevisionJson;
import com.google.gerrit.server.change.RevisionResource; import com.google.gerrit.server.change.RevisionResource;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.patch.MergeListBuilder; import com.google.gerrit.server.patch.MergeListBuilder;
@@ -38,7 +39,7 @@ import org.kohsuke.args4j.Option;
public class GetMergeList implements RestReadView<RevisionResource> { public class GetMergeList implements RestReadView<RevisionResource> {
private final GitRepositoryManager repoManager; private final GitRepositoryManager repoManager;
private final ChangeJson.Factory json; private final RevisionJson.Factory json;
@Option(name = "--parent", usage = "Uninteresting parent (1-based, default = 1)") @Option(name = "--parent", usage = "Uninteresting parent (1-based, default = 1)")
private int uninterestingParent = 1; private int uninterestingParent = 1;
@@ -47,7 +48,7 @@ public class GetMergeList implements RestReadView<RevisionResource> {
private boolean addLinks; private boolean addLinks;
@Inject @Inject
GetMergeList(GitRepositoryManager repoManager, ChangeJson.Factory json) { GetMergeList(GitRepositoryManager repoManager, RevisionJson.Factory json) {
this.repoManager = repoManager; this.repoManager = repoManager;
this.json = json; this.json = json;
} }
@@ -80,7 +81,7 @@ public class GetMergeList implements RestReadView<RevisionResource> {
List<RevCommit> commits = MergeListBuilder.build(rw, commit, uninterestingParent); List<RevCommit> commits = MergeListBuilder.build(rw, commit, uninterestingParent);
List<CommitInfo> result = new ArrayList<>(commits.size()); List<CommitInfo> result = new ArrayList<>(commits.size());
ChangeJson changeJson = json.noOptions(); RevisionJson changeJson = json.create(ImmutableSet.of());
for (RevCommit c : commits) { for (RevCommit c : commits) {
result.add(changeJson.toCommit(rsrc.getProject(), rw, c, addLinks, true)); result.add(changeJson.toCommit(rsrc.getProject(), rw, c, addLinks, true));
} }

View File

@@ -14,9 +14,7 @@
package com.google.gerrit.server.restapi.change; package com.google.gerrit.server.restapi.change;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.flogger.FluentLogger; import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.client.ListChangesOption; import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.common.ChangeInfo;
@@ -136,10 +134,7 @@ public class QueryChanges implements RestReadView<TopLevelResource> {
ChangeJson cjson = json.create(options); ChangeJson cjson = json.create(options);
cjson.setPluginDefinedAttributesFactory(this.imp); cjson.setPluginDefinedAttributesFactory(this.imp);
List<List<ChangeInfo>> res = List<List<ChangeInfo>> res = cjson.formatQueryResults(results);
cjson
.lazyLoad(containsAnyOf(options, ChangeJson.REQUIRE_LAZY_LOAD))
.formatQueryResults(results);
for (int n = 0; n < cnt; n++) { for (int n = 0; n < cnt; n++) {
List<ChangeInfo> info = res.get(n); List<ChangeInfo> info = res.get(n);
@@ -149,9 +144,4 @@ public class QueryChanges implements RestReadView<TopLevelResource> {
} }
return res; return res;
} }
private static boolean containsAnyOf(
EnumSet<ListChangesOption> set, ImmutableSet<ListChangesOption> toFind) {
return !Sets.intersection(toFind, set).isEmpty();
}
} }

View File

@@ -67,14 +67,11 @@ public class SubmittedTogether implements RestReadView<ChangeResource> {
private final Provider<MergeSuperSet> mergeSuperSet; private final Provider<MergeSuperSet> mergeSuperSet;
private final Provider<WalkSorter> sorter; private final Provider<WalkSorter> sorter;
private boolean lazyLoad = false;
@Option(name = "-o", usage = "Output options") @Option(name = "-o", usage = "Output options")
void addOption(String option) { void addOption(String option) {
for (ListChangesOption o : ListChangesOption.values()) { for (ListChangesOption o : ListChangesOption.values()) {
if (o.name().equalsIgnoreCase(option)) { if (o.name().equalsIgnoreCase(option)) {
jsonOpt.add(o); jsonOpt.add(o);
lazyLoad |= ChangeJson.REQUIRE_LAZY_LOAD.contains(o);
return; return;
} }
} }
@@ -150,7 +147,7 @@ public class SubmittedTogether implements RestReadView<ChangeResource> {
cds = sort(cds, hidden); cds = sort(cds, hidden);
SubmittedTogetherInfo info = new SubmittedTogetherInfo(); SubmittedTogetherInfo info = new SubmittedTogetherInfo();
info.changes = json.create(jsonOpt).lazyLoad(lazyLoad).formatChangeDatas(cds); info.changes = json.create(jsonOpt).formatChangeDatas(cds);
info.nonVisibleChanges = hidden; info.nonVisibleChanges = hidden;
return info; return info;
} catch (OrmException | IOException e) { } catch (OrmException | IOException e) {

View File

@@ -35,7 +35,7 @@ import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.registration.RegistrationHandle; import com.google.gerrit.extensions.registration.RegistrationHandle;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.change.ChangeJson; import com.google.gerrit.server.change.RevisionJson;
import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.testing.ConfigSuite; import com.google.gerrit.testing.ConfigSuite;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -54,7 +54,7 @@ public class ActionsIT extends AbstractDaemonTest {
return submitWholeTopicEnabledConfig(); return submitWholeTopicEnabledConfig();
} }
@Inject private ChangeJson.Factory changeJsonFactory; @Inject private RevisionJson.Factory revisionJsonFactory;
@Inject private DynamicSet<ActionVisitor> actionVisitors; @Inject private DynamicSet<ActionVisitor> actionVisitors;
@@ -394,7 +394,7 @@ public class ActionsIT extends AbstractDaemonTest {
// ...via ChangeJson directly. // ...via ChangeJson directly.
ChangeData cd = changeDataFactory.create(db, project, changeId); ChangeData cd = changeDataFactory.create(db, project, changeId);
changeJsonFactory.create(opts).getRevisionInfo(cd, cd.patchSet(new PatchSet.Id(changeId, 1))); revisionJsonFactory.create(opts).getRevisionInfo(cd, cd.patchSet(new PatchSet.Id(changeId, 1)));
} }
private void visitedCurrentRevisionActionsAssertions( private void visitedCurrentRevisionActionsAssertions(