diff options
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java')
-rw-r--r-- | gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java | 568 |
1 files changed, 0 insertions, 568 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java deleted file mode 100644 index 6f3e05594c..0000000000 --- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java +++ /dev/null @@ -1,568 +0,0 @@ -// Copyright (C) 2009 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.patch; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.google.common.collect.ImmutableSet; -import com.google.gerrit.common.data.CommentDetail; -import com.google.gerrit.common.data.PatchScript; -import com.google.gerrit.common.data.PatchScript.DisplayMethod; -import com.google.gerrit.extensions.client.DiffPreferencesInfo; -import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace; -import com.google.gerrit.prettify.common.EditList; -import com.google.gerrit.prettify.common.SparseFileContent; -import com.google.gerrit.reviewdb.client.Change; -import com.google.gerrit.reviewdb.client.Comment; -import com.google.gerrit.reviewdb.client.Patch; -import com.google.gerrit.reviewdb.client.Project; -import com.google.gerrit.server.mime.FileTypeRegistry; -import com.google.inject.Inject; -import eu.medsea.mimeutil.MimeType; -import eu.medsea.mimeutil.MimeUtil2; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import org.eclipse.jgit.diff.Edit; -import org.eclipse.jgit.errors.CorruptObjectException; -import org.eclipse.jgit.errors.IncorrectObjectTypeException; -import org.eclipse.jgit.errors.MissingObjectException; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.FileMode; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectReader; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.revwalk.RevTree; -import org.eclipse.jgit.revwalk.RevWalk; -import org.eclipse.jgit.treewalk.TreeWalk; - -class PatchScriptBuilder { - static final int MAX_CONTEXT = 5000000; - static final int BIG_FILE = 9000; - - private static final Comparator<Edit> EDIT_SORT = - new Comparator<Edit>() { - @Override - public int compare(Edit o1, Edit o2) { - return o1.getBeginA() - o2.getBeginA(); - } - }; - - private Repository db; - private Project.NameKey projectKey; - private ObjectReader reader; - private Change change; - private DiffPreferencesInfo diffPrefs; - private ComparisonType comparisonType; - private ObjectId aId; - private ObjectId bId; - - private final Side a; - private final Side b; - - private List<Edit> edits; - private final FileTypeRegistry registry; - private final PatchListCache patchListCache; - private int context; - - @Inject - PatchScriptBuilder(FileTypeRegistry ftr, PatchListCache plc) { - a = new Side(); - b = new Side(); - registry = ftr; - patchListCache = plc; - } - - void setRepository(Repository r, Project.NameKey projectKey) { - this.db = r; - this.projectKey = projectKey; - } - - void setChange(Change c) { - this.change = c; - } - - void setDiffPrefs(DiffPreferencesInfo dp) { - diffPrefs = dp; - - context = diffPrefs.context; - if (context == DiffPreferencesInfo.WHOLE_FILE_CONTEXT) { - context = MAX_CONTEXT; - } else if (context > MAX_CONTEXT) { - context = MAX_CONTEXT; - } - } - - void setTrees(ComparisonType ct, ObjectId a, ObjectId b) { - comparisonType = ct; - aId = a; - bId = b; - } - - PatchScript toPatchScript(PatchListEntry content, CommentDetail comments, List<Patch> history) - throws IOException { - reader = db.newObjectReader(); - try { - return build(content, comments, history); - } finally { - reader.close(); - } - } - - private PatchScript build(PatchListEntry content, CommentDetail comments, List<Patch> history) - throws IOException { - boolean intralineDifferenceIsPossible = true; - boolean intralineFailure = false; - boolean intralineTimeout = false; - - a.path = oldName(content); - b.path = newName(content); - - a.resolve(null, aId); - b.resolve(a, bId); - - edits = new ArrayList<>(content.getEdits()); - ImmutableSet<Edit> editsDueToRebase = content.getEditsDueToRebase(); - - if (!isModify(content)) { - intralineDifferenceIsPossible = false; - } else if (diffPrefs.intralineDifference) { - IntraLineDiff d = - patchListCache.getIntraLineDiff( - IntraLineDiffKey.create(a.id, b.id, diffPrefs.ignoreWhitespace), - IntraLineDiffArgs.create( - a.src, b.src, edits, editsDueToRebase, projectKey, bId, b.path)); - if (d != null) { - switch (d.getStatus()) { - case EDIT_LIST: - edits = new ArrayList<>(d.getEdits()); - break; - - case DISABLED: - intralineDifferenceIsPossible = false; - break; - - case ERROR: - intralineDifferenceIsPossible = false; - intralineFailure = true; - break; - - case TIMEOUT: - intralineDifferenceIsPossible = false; - intralineTimeout = true; - break; - } - } else { - intralineDifferenceIsPossible = false; - intralineFailure = true; - } - } - - if (comments != null) { - ensureCommentsVisible(comments); - } - - boolean hugeFile = false; - if (a.src == b.src && a.size() <= context && content.getEdits().isEmpty()) { - // Odd special case; the files are identical (100% rename or copy) - // and the user has asked for context that is larger than the file. - // Send them the entire file, with an empty edit after the last line. - // - for (int i = 0; i < a.size(); i++) { - a.addLine(i); - } - edits = new ArrayList<>(1); - edits.add(new Edit(a.size(), a.size())); - - } else { - if (BIG_FILE < Math.max(a.size(), b.size())) { - // IF the file is really large, we disable things to avoid choking - // the browser client. - // - hugeFile = true; - } - - // In order to expand the skipped common lines or syntax highlight the - // file properly we need to give the client the complete file contents. - // So force our context temporarily to the complete file size. - // - context = MAX_CONTEXT; - - packContent(diffPrefs.ignoreWhitespace != Whitespace.IGNORE_NONE); - } - - return new PatchScript( - change.getKey(), - content.getChangeType(), - content.getOldName(), - content.getNewName(), - a.fileMode, - b.fileMode, - content.getHeaderLines(), - diffPrefs, - a.dst, - b.dst, - edits, - editsDueToRebase, - a.displayMethod, - b.displayMethod, - a.mimeType.toString(), - b.mimeType.toString(), - comments, - history, - hugeFile, - intralineDifferenceIsPossible, - intralineFailure, - intralineTimeout, - content.getPatchType() == Patch.PatchType.BINARY, - aId == null ? null : aId.getName(), - bId == null ? null : bId.getName()); - } - - private static boolean isModify(PatchListEntry content) { - switch (content.getChangeType()) { - case MODIFIED: - case COPIED: - case RENAMED: - case REWRITE: - return true; - - case ADDED: - case DELETED: - default: - return false; - } - } - - private static String oldName(PatchListEntry entry) { - switch (entry.getChangeType()) { - case ADDED: - return null; - case DELETED: - case MODIFIED: - case REWRITE: - return entry.getNewName(); - case COPIED: - case RENAMED: - default: - return entry.getOldName(); - } - } - - private static String newName(PatchListEntry entry) { - switch (entry.getChangeType()) { - case DELETED: - return null; - case ADDED: - case MODIFIED: - case COPIED: - case RENAMED: - case REWRITE: - default: - return entry.getNewName(); - } - } - - private void ensureCommentsVisible(CommentDetail comments) { - if (comments.getCommentsA().isEmpty() && comments.getCommentsB().isEmpty()) { - // No comments, no additional dummy edits are required. - // - return; - } - - // Construct empty Edit blocks around each location where a comment is. - // This will force the later packContent method to include the regions - // containing comments, potentially combining those regions together if - // they have overlapping contexts. UI renders will also be able to make - // correct hunks from this, but because the Edit is empty they will not - // style it specially. - // - final List<Edit> empty = new ArrayList<>(); - int lastLine; - - lastLine = -1; - for (Comment c : comments.getCommentsA()) { - final int a = c.lineNbr; - if (lastLine != a) { - final int b = mapA2B(a - 1); - if (0 <= b) { - safeAdd(empty, new Edit(a - 1, b)); - } - lastLine = a; - } - } - - lastLine = -1; - for (Comment c : comments.getCommentsB()) { - int b = c.lineNbr; - if (lastLine != b) { - final int a = mapB2A(b - 1); - if (0 <= a) { - safeAdd(empty, new Edit(a, b - 1)); - } - lastLine = b; - } - } - - // Sort the final list by the index in A, so packContent can combine - // them correctly later. - // - edits.addAll(empty); - Collections.sort(edits, EDIT_SORT); - } - - private void safeAdd(List<Edit> empty, Edit toAdd) { - final int a = toAdd.getBeginA(); - final int b = toAdd.getBeginB(); - for (Edit e : edits) { - if (e.getBeginA() <= a && a <= e.getEndA()) { - return; - } - if (e.getBeginB() <= b && b <= e.getEndB()) { - return; - } - } - empty.add(toAdd); - } - - private int mapA2B(int a) { - if (edits.isEmpty()) { - // Magic special case of an unmodified file. - // - return a; - } - - for (int i = 0; i < edits.size(); i++) { - final Edit e = edits.get(i); - if (a < e.getBeginA()) { - if (i == 0) { - // Special case of context at start of file. - // - return a; - } - return e.getBeginB() - (e.getBeginA() - a); - } - if (e.getBeginA() <= a && a <= e.getEndA()) { - return -1; - } - } - - final Edit last = edits.get(edits.size() - 1); - return last.getEndB() + (a - last.getEndA()); - } - - private int mapB2A(int b) { - if (edits.isEmpty()) { - // Magic special case of an unmodified file. - // - return b; - } - - for (int i = 0; i < edits.size(); i++) { - final Edit e = edits.get(i); - if (b < e.getBeginB()) { - if (i == 0) { - // Special case of context at start of file. - // - return b; - } - return e.getBeginA() - (e.getBeginB() - b); - } - if (e.getBeginB() <= b && b <= e.getEndB()) { - return -1; - } - } - - final Edit last = edits.get(edits.size() - 1); - return last.getEndA() + (b - last.getEndB()); - } - - private void packContent(boolean ignoredWhitespace) { - EditList list = new EditList(edits, context, a.size(), b.size()); - for (EditList.Hunk hunk : list.getHunks()) { - while (hunk.next()) { - if (hunk.isContextLine()) { - final String lineA = a.src.getString(hunk.getCurA()); - a.dst.addLine(hunk.getCurA(), lineA); - - if (ignoredWhitespace) { - // If we ignored whitespace in some form, also get the line - // from b when it does not exactly match the line from a. - // - final String lineB = b.src.getString(hunk.getCurB()); - if (!lineA.equals(lineB)) { - b.dst.addLine(hunk.getCurB(), lineB); - } - } - hunk.incBoth(); - continue; - } - - if (hunk.isDeletedA()) { - a.addLine(hunk.getCurA()); - hunk.incA(); - } - - if (hunk.isInsertedB()) { - b.addLine(hunk.getCurB()); - hunk.incB(); - } - } - } - } - - private class Side { - String path; - ObjectId id; - FileMode mode; - byte[] srcContent; - Text src; - MimeType mimeType = MimeUtil2.UNKNOWN_MIME_TYPE; - DisplayMethod displayMethod = DisplayMethod.DIFF; - PatchScript.FileMode fileMode = PatchScript.FileMode.FILE; - final SparseFileContent dst = new SparseFileContent(); - - int size() { - return src != null ? src.size() : 0; - } - - void addLine(int line) { - dst.addLine(line, src.getString(line)); - } - - void resolve(Side other, ObjectId within) throws IOException { - try { - final boolean reuse; - if (Patch.COMMIT_MSG.equals(path)) { - if (comparisonType.isAgainstParentOrAutoMerge() - && (aId == within || within.equals(aId))) { - id = ObjectId.zeroId(); - src = Text.EMPTY; - srcContent = Text.NO_BYTES; - mode = FileMode.MISSING; - displayMethod = DisplayMethod.NONE; - } else { - id = within; - src = Text.forCommit(reader, within); - srcContent = src.getContent(); - if (src == Text.EMPTY) { - mode = FileMode.MISSING; - displayMethod = DisplayMethod.NONE; - } else { - mode = FileMode.REGULAR_FILE; - } - } - reuse = false; - } else if (Patch.MERGE_LIST.equals(path)) { - if (comparisonType.isAgainstParentOrAutoMerge() - && (aId == within || within.equals(aId))) { - id = ObjectId.zeroId(); - src = Text.EMPTY; - srcContent = Text.NO_BYTES; - mode = FileMode.MISSING; - displayMethod = DisplayMethod.NONE; - } else { - id = within; - src = Text.forMergeList(comparisonType, reader, within); - srcContent = src.getContent(); - if (src == Text.EMPTY) { - mode = FileMode.MISSING; - displayMethod = DisplayMethod.NONE; - } else { - mode = FileMode.REGULAR_FILE; - } - } - reuse = false; - } else { - final TreeWalk tw = find(within); - - id = tw != null ? tw.getObjectId(0) : ObjectId.zeroId(); - mode = tw != null ? tw.getFileMode(0) : FileMode.MISSING; - reuse = - other != null - && other.id.equals(id) - && (other.mode == mode || isBothFile(other.mode, mode)); - - if (reuse) { - srcContent = other.srcContent; - - } else if (mode.getObjectType() == Constants.OBJ_BLOB) { - srcContent = Text.asByteArray(db.open(id, Constants.OBJ_BLOB)); - - } else if (mode.getObjectType() == Constants.OBJ_COMMIT) { - String strContent = "Subproject commit " + ObjectId.toString(id); - srcContent = strContent.getBytes(UTF_8); - - } else { - srcContent = Text.NO_BYTES; - } - - if (reuse) { - mimeType = other.mimeType; - displayMethod = other.displayMethod; - src = other.src; - - } else if (srcContent.length > 0 && FileMode.SYMLINK != mode) { - mimeType = registry.getMimeType(path, srcContent); - if ("image".equals(mimeType.getMediaType()) && registry.isSafeInline(mimeType)) { - displayMethod = DisplayMethod.IMG; - } - } - } - - if (mode == FileMode.MISSING) { - displayMethod = DisplayMethod.NONE; - } - - if (!reuse) { - if (srcContent == Text.NO_BYTES) { - src = Text.EMPTY; - } else { - src = new Text(srcContent); - } - } - - dst.setSize(size()); - - if (mode == FileMode.SYMLINK) { - fileMode = PatchScript.FileMode.SYMLINK; - } else if (mode == FileMode.GITLINK) { - fileMode = PatchScript.FileMode.GITLINK; - } - } catch (IOException err) { - throw new IOException("Cannot read " + within.name() + ":" + path, err); - } - } - - private TreeWalk find(ObjectId within) - throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException, - IOException { - if (path == null || within == null) { - return null; - } - try (RevWalk rw = new RevWalk(reader)) { - final RevTree tree = rw.parseTree(within); - return TreeWalk.forPath(reader, path, tree); - } - } - } - - private static boolean isBothFile(FileMode a, FileMode b) { - return (a.getBits() & FileMode.TYPE_FILE) == FileMode.TYPE_FILE - && (b.getBits() & FileMode.TYPE_FILE) == FileMode.TYPE_FILE; - } -} |