Line data Source code
1 : // Copyright (C) 2021 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.change; 16 : 17 : import com.google.gerrit.common.Nullable; 18 : import com.google.gerrit.entities.Change; 19 : import com.google.gerrit.entities.Patch; 20 : import com.google.gerrit.entities.PatchSet; 21 : import com.google.gerrit.entities.Project; 22 : import com.google.gerrit.extensions.common.FileInfo; 23 : import com.google.gerrit.extensions.restapi.ResourceConflictException; 24 : import com.google.gerrit.server.patch.DiffNotAvailableException; 25 : import com.google.gerrit.server.patch.DiffOperations; 26 : import com.google.gerrit.server.patch.DiffOptions; 27 : import com.google.gerrit.server.patch.FilePathAdapter; 28 : import com.google.gerrit.server.patch.PatchListNotAvailableException; 29 : import com.google.gerrit.server.patch.filediff.FileDiffOutput; 30 : import com.google.inject.Inject; 31 : import java.util.HashMap; 32 : import java.util.Map; 33 : import org.eclipse.jgit.errors.NoMergeBaseException; 34 : import org.eclipse.jgit.lib.ObjectId; 35 : 36 : /** Implementation of {@link FileInfoJson} using {@link DiffOperations}. */ 37 : public class FileInfoJsonImpl implements FileInfoJson { 38 : private final DiffOperations diffs; 39 : 40 : @Inject 41 103 : FileInfoJsonImpl(DiffOperations diffOperations) { 42 103 : this.diffs = diffOperations; 43 103 : } 44 : 45 : @Nullable 46 : @Override 47 : public Map<String, FileInfo> getFileInfoMap( 48 : Change change, ObjectId objectId, @Nullable PatchSet base) 49 : throws ResourceConflictException, PatchListNotAvailableException { 50 : try { 51 103 : if (base == null) { 52 : // Setting parentNum=0 requests the default parent, which is the only parent for 53 : // single-parent commits, or the auto-merge otherwise 54 103 : return asFileInfo( 55 103 : diffs.listModifiedFilesAgainstParent( 56 103 : change.getProject(), objectId, /* parentNum= */ 0, DiffOptions.DEFAULTS)); 57 : } 58 4 : return asFileInfo( 59 4 : diffs.listModifiedFiles( 60 4 : change.getProject(), base.commitId(), objectId, DiffOptions.DEFAULTS)); 61 0 : } catch (DiffNotAvailableException e) { 62 0 : convertException(e); 63 0 : return null; // unreachable. handleAndThrow will throw an exception anyway 64 : } 65 : } 66 : 67 : @Nullable 68 : @Override 69 : public Map<String, FileInfo> getFileInfoMap( 70 : Project.NameKey project, ObjectId objectId, int parent) 71 : throws ResourceConflictException, PatchListNotAvailableException { 72 : try { 73 7 : Map<String, FileDiffOutput> modifiedFiles = 74 7 : diffs.listModifiedFilesAgainstParent(project, objectId, parent, DiffOptions.DEFAULTS); 75 7 : return asFileInfo(modifiedFiles); 76 0 : } catch (DiffNotAvailableException e) { 77 0 : convertException(e); 78 0 : return null; // unreachable. handleAndThrow will throw an exception anyway 79 : } 80 : } 81 : 82 : private void convertException(DiffNotAvailableException e) 83 : throws ResourceConflictException, PatchListNotAvailableException { 84 0 : Throwable cause = e.getCause(); 85 0 : if (cause != null && !(cause instanceof NoMergeBaseException)) { 86 0 : cause = cause.getCause(); 87 : } 88 0 : if (cause instanceof NoMergeBaseException) { 89 0 : throw new ResourceConflictException( 90 0 : String.format("Cannot create auto merge commit: %s", e.getMessage()), e); 91 : } 92 0 : throw new PatchListNotAvailableException(e); 93 : } 94 : 95 : private Map<String, FileInfo> asFileInfo(Map<String, FileDiffOutput> fileDiffs) { 96 103 : Map<String, FileInfo> result = new HashMap<>(); 97 103 : for (String path : fileDiffs.keySet()) { 98 103 : FileDiffOutput fileDiff = fileDiffs.get(path); 99 103 : FileInfo fileInfo = new FileInfo(); 100 103 : fileInfo.status = 101 103 : fileDiff.changeType() != Patch.ChangeType.MODIFIED 102 103 : ? fileDiff.changeType().getCode() 103 103 : : null; 104 103 : fileInfo.oldPath = FilePathAdapter.getOldPath(fileDiff.oldPath(), fileDiff.changeType()); 105 103 : fileInfo.sizeDelta = fileDiff.sizeDelta(); 106 103 : fileInfo.size = fileDiff.size(); 107 103 : fileInfo.oldMode = 108 103 : fileDiff.oldMode().isPresent() && !fileDiff.oldMode().get().equals(Patch.FileMode.MISSING) 109 50 : ? fileDiff.oldMode().get().getMode() 110 103 : : null; 111 103 : fileInfo.newMode = 112 103 : fileDiff.newMode().isPresent() && !fileDiff.newMode().get().equals(Patch.FileMode.MISSING) 113 89 : ? fileDiff.newMode().get().getMode() 114 103 : : null; 115 103 : if (fileDiff.patchType().get() == Patch.PatchType.BINARY) { 116 2 : fileInfo.binary = true; 117 : } else { 118 103 : fileInfo.linesInserted = fileDiff.insertions() > 0 ? fileDiff.insertions() : null; 119 103 : fileInfo.linesDeleted = fileDiff.deletions() > 0 ? fileDiff.deletions() : null; 120 : } 121 103 : result.put(path, fileInfo); 122 103 : } 123 103 : return result; 124 : } 125 : }