Files
gerrit/java/com/google/gerrit/server/change/FileInfoJson.java
Edwin Kempin 1f834ad6f0 Do not fail with 500 ISE if base of merge change cannot be computed due to NoMergeBaseException
If the repository content doesn't allow us to compute an auto-merge
commit for the base of a merge change because JGit cannot find a merge
base (e.g. due to CONFLICTS_DURING_MERGE_BASE_CALCULATION), we now
return '409 Conflict' for the ListFiles and change-edit-related REST
endpoints. If the files were supposed to be included into a ChangeInfo /
RevisionInfo we ignore the failure and just do not populate the file
list (but we log a warning). Letting the request succeed in this case is
better, as the caller can at least get the rest of the change and
revision information.

Treating NoMergeBaseException as '409 Conflict' is consistent with how
we treat this exception in other places (e.g. in the CreateChange REST
endpoint).

Change-Id: I78b4636c23635048eedf2a1e4b1075eb87ecb262
2020-01-15 15:24:37 +01:00

124 lines
4.7 KiB
Java

// Copyright (C) 2013 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 com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Patch;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import com.google.gerrit.extensions.common.FileInfo;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.patch.PatchListEntry;
import com.google.gerrit.server.patch.PatchListKey;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;
import org.eclipse.jgit.errors.NoMergeBaseException;
import org.eclipse.jgit.lib.ObjectId;
@Singleton
public class FileInfoJson {
private final PatchListCache patchListCache;
@Inject
FileInfoJson(PatchListCache patchListCache) {
this.patchListCache = patchListCache;
}
public Map<String, FileInfo> toFileInfoMap(Change change, PatchSet patchSet)
throws ResourceConflictException, PatchListNotAvailableException {
return toFileInfoMap(change, patchSet.commitId(), null);
}
public Map<String, FileInfo> toFileInfoMap(
Change change, ObjectId objectId, @Nullable PatchSet base)
throws ResourceConflictException, PatchListNotAvailableException {
ObjectId a = base != null ? base.commitId() : null;
return toFileInfoMap(change, PatchListKey.againstCommit(a, objectId, Whitespace.IGNORE_NONE));
}
public Map<String, FileInfo> toFileInfoMap(Change change, ObjectId objectId, int parent)
throws ResourceConflictException, PatchListNotAvailableException {
return toFileInfoMap(
change, PatchListKey.againstParentNum(parent + 1, objectId, Whitespace.IGNORE_NONE));
}
private Map<String, FileInfo> toFileInfoMap(Change change, PatchListKey key)
throws ResourceConflictException, PatchListNotAvailableException {
return toFileInfoMap(change.getProject(), key);
}
public Map<String, FileInfo> toFileInfoMap(Project.NameKey project, PatchListKey key)
throws ResourceConflictException, PatchListNotAvailableException {
PatchList list;
try {
list = patchListCache.get(key, project);
} catch (PatchListNotAvailableException e) {
Throwable cause = e.getCause();
if (cause instanceof ExecutionException) {
cause = cause.getCause();
}
if (cause instanceof NoMergeBaseException) {
throw new ResourceConflictException(
String.format("Cannot create auto merge commit: %s", e.getMessage()), e);
}
throw e;
}
Map<String, FileInfo> files = new TreeMap<>();
for (PatchListEntry e : list.getPatches()) {
FileInfo d = new FileInfo();
d.status =
e.getChangeType() != Patch.ChangeType.MODIFIED ? e.getChangeType().getCode() : null;
d.oldPath = e.getOldName();
d.sizeDelta = e.getSizeDelta();
d.size = e.getSize();
if (e.getPatchType() == Patch.PatchType.BINARY) {
d.binary = true;
} else {
d.linesInserted = e.getInsertions() > 0 ? e.getInsertions() : null;
d.linesDeleted = e.getDeletions() > 0 ? e.getDeletions() : null;
}
FileInfo o = files.put(e.getNewName(), d);
if (o != null) {
// This should only happen on a delete-add break created by JGit
// when the file was rewritten and too little content survived. Write
// a single record with data from both sides.
d.status = Patch.ChangeType.REWRITE.getCode();
d.sizeDelta = o.sizeDelta;
d.size = o.size;
if (o.binary != null && o.binary) {
d.binary = true;
}
if (o.linesInserted != null) {
d.linesInserted = o.linesInserted;
}
if (o.linesDeleted != null) {
d.linesDeleted = o.linesDeleted;
}
}
}
return files;
}
}