Revert "Split off library classes from server/patch/ into diff/"

This reverts commit 0d157b3561.

Reason for revert: full class name goes into H2 keys and values,
and possibly in other data structures in other deployments
(eg. at google), causing cache misses, warnings and/or more
cache dysfunction.

See also https://bugs.chromium.org/p/gerrit/issues/detail?id=7784&desc=2

Change-Id: I03851b8f783b93929e7dc27548fb75882b6bfe05
This commit is contained in:
Han-Wen Nienhuys
2017-11-17 09:21:05 +00:00
parent 6a70aea137
commit a2743969b3
75 changed files with 150 additions and 264 deletions

View File

@@ -1,19 +0,0 @@
java_library(
name = "diff",
srcs = glob(["**/*.java"]),
visibility = ["//visibility:public"],
deps = [
"//java/com/google/gerrit/common:annotations",
"//java/com/google/gerrit/common:server",
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/reviewdb:server",
"//java/com/google/gerrit/server/ioutil",
"//java/org/eclipse/jgit:server",
"//lib:guava",
"//lib:gwtorm",
"//lib:juniversalchardet",
"//lib/auto:auto-value",
"//lib/jgit/org.eclipse.jgit:jgit",
"//lib/log:api",
],
)

View File

@@ -1,47 +0,0 @@
// Copyright (C) 2010 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.diff;
import org.eclipse.jgit.diff.Sequence;
public class CharText extends Sequence {
private final String content;
public CharText(Text text, int s, int e) {
content = text.getString(s, e, false /* keep LF */);
}
public char charAt(int idx) {
return content.charAt(idx);
}
public boolean isLineStart(int b) {
return b == 0 || charAt(b - 1) == '\n';
}
public boolean contains(int b, int e, char c) {
for (; b < e; b++) {
if (charAt(b) == c) {
return true;
}
}
return false;
}
@Override
public int size() {
return content.length();
}
}

View File

@@ -1,29 +0,0 @@
// Copyright (C) 2010 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.diff;
import org.eclipse.jgit.diff.SequenceComparator;
public class CharTextComparator extends SequenceComparator<CharText> {
@Override
public boolean equals(CharText a, int ai, CharText b, int bi) {
return a.charAt(ai) == b.charAt(bi);
}
@Override
public int hash(CharText seq, int ptr) {
return seq.charAt(ptr);
}
}

View File

@@ -1,77 +0,0 @@
// Copyright (C) 2016 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.diff;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class ComparisonType {
/** 1-based parent */
private final Integer parentNum;
private final boolean autoMerge;
public static ComparisonType againstOtherPatchSet() {
return new ComparisonType(null, false);
}
public static ComparisonType againstParent(int parentNum) {
return new ComparisonType(parentNum, false);
}
public static ComparisonType againstAutoMerge() {
return new ComparisonType(null, true);
}
private ComparisonType(Integer parentNum, boolean autoMerge) {
this.parentNum = parentNum;
this.autoMerge = autoMerge;
}
public boolean isAgainstParentOrAutoMerge() {
return isAgainstParent() || isAgainstAutoMerge();
}
public boolean isAgainstParent() {
return parentNum != null;
}
public boolean isAgainstAutoMerge() {
return autoMerge;
}
public int getParentNum() {
checkNotNull(parentNum);
return parentNum;
}
void writeTo(OutputStream out) throws IOException {
writeVarInt32(out, parentNum != null ? parentNum : 0);
writeVarInt32(out, autoMerge ? 1 : 0);
}
static ComparisonType readFrom(InputStream in) throws IOException {
int p = readVarInt32(in);
Integer parentNum = p > 0 ? p : null;
boolean autoMerge = readVarInt32(in) != 0;
return new ComparisonType(parentNum, autoMerge);
}
}

View File

@@ -1,84 +0,0 @@
// Copyright (C) 2016 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.diff;
import static com.google.gerrit.server.ioutil.BasicSerialization.readString;
import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeString;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
public class DiffSummary implements Serializable {
private static final long serialVersionUID = DiffSummaryKey.serialVersionUID;
private transient String[] paths;
private transient int insertions;
private transient int deletions;
public DiffSummary(String[] paths, int insertions, int deletions) {
this.paths = paths;
this.insertions = insertions;
this.deletions = deletions;
}
public List<String> getPaths() {
return Collections.unmodifiableList(Arrays.asList(paths));
}
public ChangedLines getChangedLines() {
return new ChangedLines(insertions, deletions);
}
private void writeObject(ObjectOutputStream output) throws IOException {
writeVarInt32(output, insertions);
writeVarInt32(output, deletions);
writeVarInt32(output, paths.length);
try (DeflaterOutputStream out = new DeflaterOutputStream(output)) {
for (String p : paths) {
writeString(out, p);
}
}
}
private void readObject(ObjectInputStream input) throws IOException {
insertions = readVarInt32(input);
deletions = readVarInt32(input);
paths = new String[readVarInt32(input)];
try (InflaterInputStream in = new InflaterInputStream(input)) {
for (int i = 0; i < paths.length; i++) {
paths[i] = readString(in);
}
}
}
public static class ChangedLines {
public final int insertions;
public final int deletions;
public ChangedLines(int insertions, int deletions) {
this.insertions = insertions;
this.deletions = deletions;
}
}
}

View File

@@ -1,117 +0,0 @@
// Copyright (C) 2016 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.diff;
import static org.eclipse.jgit.lib.ObjectIdSerialization.readCanBeNull;
import static org.eclipse.jgit.lib.ObjectIdSerialization.readNotNull;
import static org.eclipse.jgit.lib.ObjectIdSerialization.writeCanBeNull;
import static org.eclipse.jgit.lib.ObjectIdSerialization.writeNotNull;
import com.google.common.base.Preconditions;
import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Objects;
import org.eclipse.jgit.lib.ObjectId;
public class DiffSummaryKey implements Serializable {
public static final long serialVersionUID = 1L;
/** see PatchListKey#oldId */
private transient ObjectId oldId;
/** see PatchListKey#parentNum */
private transient Integer parentNum;
private transient ObjectId newId;
private transient Whitespace whitespace;
public static DiffSummaryKey fromPatchListKey(PatchListKey plk) {
Preconditions.checkArgument(plk.getAlgorithm() == PatchListKey.Algorithm.OPTIMIZED_DIFF);
return new DiffSummaryKey(
plk.getOldId(), plk.getParentNum(), plk.getNewId(), plk.getWhitespace());
}
private DiffSummaryKey(ObjectId oldId, Integer parentNum, ObjectId newId, Whitespace whitespace) {
this.oldId = oldId;
this.parentNum = parentNum;
this.newId = newId;
this.whitespace = whitespace;
}
public PatchListKey toPatchListKey() {
return new PatchListKey(
oldId, parentNum, newId, whitespace, PatchListKey.Algorithm.OPTIMIZED_DIFF);
}
@Override
public int hashCode() {
return Objects.hash(oldId, parentNum, newId, whitespace);
}
@Override
public boolean equals(Object o) {
if (o instanceof DiffSummaryKey) {
DiffSummaryKey k = (DiffSummaryKey) o;
return Objects.equals(oldId, k.oldId)
&& Objects.equals(parentNum, k.parentNum)
&& Objects.equals(newId, k.newId)
&& whitespace == k.whitespace;
}
return false;
}
@Override
public String toString() {
StringBuilder n = new StringBuilder();
n.append("DiffSummaryKey[");
n.append(oldId != null ? oldId.name() : "BASE");
n.append("..");
n.append(newId.name());
n.append(" ");
if (parentNum != null) {
n.append(parentNum);
n.append(" ");
}
n.append(whitespace.name());
n.append("]");
return n.toString();
}
private void writeObject(ObjectOutputStream out) throws IOException {
writeCanBeNull(out, oldId);
out.writeInt(parentNum == null ? 0 : parentNum);
writeNotNull(out, newId);
Character c = PatchListKey.WHITESPACE_TYPES.get(whitespace);
if (c == null) {
throw new IOException("Invalid whitespace type: " + whitespace);
}
out.writeChar(c);
}
private void readObject(ObjectInputStream in) throws IOException {
oldId = readCanBeNull(in);
int n = in.readInt();
parentNum = n == 0 ? null : Integer.valueOf(n);
newId = readNotNull(in);
char t = in.readChar();
whitespace = PatchListKey.WHITESPACE_TYPES.inverse().get(t);
if (whitespace == null) {
throw new IOException("Invalid whitespace type code: " + t);
}
}
}

View File

@@ -1,154 +0,0 @@
// Copyright (C) 2010 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.diff;
import static com.google.gerrit.server.ioutil.BasicSerialization.readEnum;
import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeEnum;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.reviewdb.client.CodedEnum;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.diff.ReplaceEdit;
public class IntraLineDiff implements Serializable {
static final long serialVersionUID = IntraLineDiffKey.serialVersionUID;
public enum Status implements CodedEnum {
EDIT_LIST('e'),
DISABLED('D'),
TIMEOUT('T'),
ERROR('E');
private final char code;
Status(char code) {
this.code = code;
}
@Override
public char getCode() {
return code;
}
}
private transient Status status;
private transient ImmutableList<Edit> edits;
public IntraLineDiff(Status status) {
this.status = status;
this.edits = ImmutableList.of();
}
public IntraLineDiff(List<Edit> edits) {
this.status = Status.EDIT_LIST;
this.edits = ImmutableList.copyOf(edits);
}
public Status getStatus() {
return status;
}
public ImmutableList<Edit> getEdits() {
// Edits are mutable objects. As we serialize IntraLineDiff asynchronously in H2CacheImpl, we
// must ensure that its state isn't modified until it was properly stored in the cache.
return deepCopyEdits(edits);
}
private void writeObject(ObjectOutputStream out) throws IOException {
writeEnum(out, status);
writeVarInt32(out, edits.size());
for (Edit e : edits) {
writeEdit(out, e);
if (e instanceof ReplaceEdit) {
ReplaceEdit r = (ReplaceEdit) e;
writeVarInt32(out, r.getInternalEdits().size());
for (Edit i : r.getInternalEdits()) {
writeEdit(out, i);
}
} else {
writeVarInt32(out, 0);
}
}
}
private void readObject(ObjectInputStream in) throws IOException {
status = readEnum(in, Status.values());
int editCount = readVarInt32(in);
Edit[] editArray = new Edit[editCount];
for (int i = 0; i < editCount; i++) {
editArray[i] = readEdit(in);
int innerCount = readVarInt32(in);
if (0 < innerCount) {
Edit[] inner = new Edit[innerCount];
for (int j = 0; j < innerCount; j++) {
inner[j] = readEdit(in);
}
editArray[i] = new ReplaceEdit(editArray[i], toList(inner));
}
}
edits = ImmutableList.copyOf(editArray);
}
private static ImmutableList<Edit> deepCopyEdits(List<Edit> edits) {
return edits.stream().map(IntraLineDiff::copy).collect(ImmutableList.toImmutableList());
}
private static Edit copy(Edit edit) {
if (edit instanceof ReplaceEdit) {
return copy((ReplaceEdit) edit);
}
return new Edit(edit.getBeginA(), edit.getEndA(), edit.getBeginB(), edit.getEndB());
}
private static ReplaceEdit copy(ReplaceEdit edit) {
List<Edit> internalEdits =
edit.getInternalEdits().stream().map(IntraLineDiff::copy).collect(Collectors.toList());
return new ReplaceEdit(
edit.getBeginA(), edit.getEndA(), edit.getBeginB(), edit.getEndB(), internalEdits);
}
private static void writeEdit(OutputStream out, Edit e) throws IOException {
writeVarInt32(out, e.getBeginA());
writeVarInt32(out, e.getEndA());
writeVarInt32(out, e.getBeginB());
writeVarInt32(out, e.getEndB());
}
private static Edit readEdit(InputStream in) throws IOException {
int beginA = readVarInt32(in);
int endA = readVarInt32(in);
int beginB = readVarInt32(in);
int endB = readVarInt32(in);
return new Edit(beginA, endA, beginB, endB);
}
private static List<Edit> toList(Edit[] l) {
return Collections.unmodifiableList(Arrays.asList(l));
}
}

View File

@@ -1,56 +0,0 @@
// Copyright (C) 2015 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.diff;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.reviewdb.client.Project;
import java.util.List;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.lib.ObjectId;
@AutoValue
public abstract class IntraLineDiffArgs {
public static IntraLineDiffArgs create(
Text aText,
Text bText,
List<Edit> edits,
Project.NameKey project,
ObjectId commit,
String path) {
return new AutoValue_IntraLineDiffArgs(
aText, bText, deepCopyEdits(edits), project, commit, path);
}
private static ImmutableList<Edit> deepCopyEdits(List<Edit> edits) {
return edits.stream().map(IntraLineDiffArgs::copy).collect(ImmutableList.toImmutableList());
}
private static Edit copy(Edit edit) {
return new Edit(edit.getBeginA(), edit.getEndA(), edit.getBeginB(), edit.getEndB());
}
public abstract Text aText();
public abstract Text bText();
public abstract ImmutableList<Edit> edits();
public abstract Project.NameKey project();
public abstract ObjectId commit();
public abstract String path();
}

View File

@@ -1,35 +0,0 @@
// Copyright (C) 2010 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.diff;
import com.google.auto.value.AutoValue;
import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import java.io.Serializable;
import org.eclipse.jgit.lib.ObjectId;
@AutoValue
public abstract class IntraLineDiffKey implements Serializable {
public static final long serialVersionUID = 8L;
public static IntraLineDiffKey create(ObjectId aId, ObjectId bId, Whitespace whitespace) {
return new AutoValue_IntraLineDiffKey(aId, bId, whitespace);
}
public abstract ObjectId getBlobA();
public abstract ObjectId getBlobB();
public abstract Whitespace getWhitespace();
}

View File

@@ -1,50 +0,0 @@
// Copyright (C) 2016 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.diff;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
public class MergeListBuilder {
public static List<RevCommit> build(RevWalk rw, RevCommit merge, int uninterestingParent)
throws IOException {
rw.reset();
rw.parseBody(merge);
if (merge.getParentCount() < 2) {
return ImmutableList.of();
}
for (int parent = 0; parent < merge.getParentCount(); parent++) {
RevCommit parentCommit = merge.getParent(parent);
rw.parseBody(parentCommit);
if (parent == uninterestingParent - 1) {
rw.markUninteresting(parentCommit);
} else {
rw.markStart(parentCommit);
}
}
List<RevCommit> result = new ArrayList<>();
RevCommit c;
while ((c = rw.next()) != null) {
result.add(c);
}
return result;
}
}

View File

@@ -1,164 +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.diff;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.gerrit.common.errors.NoSuchEntityException;
import com.google.gerrit.reviewdb.client.Patch;
import java.io.IOException;
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.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
/** State supporting processing of a single {@link Patch} instance. */
public class PatchFile {
private final Repository repo;
private final PatchListEntry entry;
private final RevTree aTree;
private final RevTree bTree;
private Text a;
private Text b;
public PatchFile(Repository repo, PatchList patchList, String fileName)
throws MissingObjectException, IncorrectObjectTypeException, IOException {
this.repo = repo;
this.entry = patchList.get(fileName);
try (ObjectReader reader = repo.newObjectReader();
RevWalk rw = new RevWalk(reader)) {
final RevCommit bCommit = rw.parseCommit(patchList.getNewId());
if (Patch.COMMIT_MSG.equals(fileName)) {
if (patchList.getComparisonType().isAgainstParentOrAutoMerge()) {
a = Text.EMPTY;
} else {
// For the initial commit, we have an empty tree on Side A
RevObject object = rw.parseAny(patchList.getOldId());
a = object instanceof RevCommit ? Text.forCommit(reader, object) : Text.EMPTY;
}
b = Text.forCommit(reader, bCommit);
aTree = null;
bTree = null;
} else if (Patch.MERGE_LIST.equals(fileName)) {
// For the initial commit, we have an empty tree on Side A
RevObject object = rw.parseAny(patchList.getOldId());
a =
object instanceof RevCommit
? Text.forMergeList(patchList.getComparisonType(), reader, object)
: Text.EMPTY;
b = Text.forMergeList(patchList.getComparisonType(), reader, bCommit);
aTree = null;
bTree = null;
} else {
if (patchList.getOldId() != null) {
aTree = rw.parseTree(patchList.getOldId());
} else {
final RevCommit p = bCommit.getParent(0);
rw.parseHeaders(p);
aTree = p.getTree();
}
bTree = bCommit.getTree();
}
}
}
/**
* Extract a line from the file, as a string.
*
* @param file the file index to extract.
* @param line the line number to extract (1 based; 1 is the first line).
* @return the string version of the file line.
* @throws IOException the patch or complete file content cannot be read.
* @throws NoSuchEntityException
*/
public String getLine(int file, int line) throws IOException, NoSuchEntityException {
switch (file) {
case 0:
if (a == null) {
a = load(aTree, entry.getOldName());
}
return a.getString(line - 1);
case 1:
if (b == null) {
b = load(bTree, entry.getNewName());
}
return b.getString(line - 1);
default:
throw new NoSuchEntityException();
}
}
/**
* Return number of lines in file.
*
* @param file the file index to extract.
* @return number of lines in file.
* @throws IOException the patch or complete file content cannot be read.
* @throws NoSuchEntityException the file is not exist.
*/
public int getLineCount(int file) throws IOException, NoSuchEntityException {
switch (file) {
case 0:
if (a == null) {
a = load(aTree, entry.getOldName());
}
return a.size();
case 1:
if (b == null) {
b = load(bTree, entry.getNewName());
}
return b.size();
default:
throw new NoSuchEntityException();
}
}
private Text load(ObjectId tree, String path)
throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException,
IOException {
if (path == null) {
return Text.EMPTY;
}
final TreeWalk tw = TreeWalk.forPath(repo, path, tree);
if (tw == null) {
return Text.EMPTY;
}
if (tw.getFileMode(0).getObjectType() == Constants.OBJ_BLOB) {
return new Text(repo.open(tw.getObjectId(0), Constants.OBJ_BLOB));
} else if (tw.getFileMode(0).getObjectType() == Constants.OBJ_COMMIT) {
String str = "Subproject commit " + ObjectId.toString(tw.getObjectId(0));
return new Text(str.getBytes(UTF_8));
} else {
return Text.EMPTY;
}
}
}

View File

@@ -1,207 +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.diff;
import static com.google.gerrit.server.ioutil.BasicSerialization.readBytes;
import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeBytes;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
import static org.eclipse.jgit.lib.ObjectIdSerialization.readCanBeNull;
import static org.eclipse.jgit.lib.ObjectIdSerialization.readNotNull;
import static org.eclipse.jgit.lib.ObjectIdSerialization.writeCanBeNull;
import static org.eclipse.jgit.lib.ObjectIdSerialization.writeNotNull;
import com.google.common.annotations.VisibleForTesting;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
public class PatchList implements Serializable {
private static final long serialVersionUID = PatchListKey.serialVersionUID;
private static final Comparator<PatchListEntry> PATCH_CMP =
new Comparator<PatchListEntry>() {
@Override
public int compare(PatchListEntry a, PatchListEntry b) {
return comparePaths(a.getNewName(), b.getNewName());
}
};
@VisibleForTesting
static int comparePaths(String a, String b) {
int m1 = Patch.isMagic(a) ? (a.equals(Patch.MERGE_LIST) ? 2 : 1) : 3;
int m2 = Patch.isMagic(b) ? (b.equals(Patch.MERGE_LIST) ? 2 : 1) : 3;
if (m1 != m2) {
return m1 - m2;
} else if (m1 < 3) {
return 0;
}
// m1 == m2 == 3: normal names.
return a.compareTo(b);
}
@Nullable private transient ObjectId oldId;
private transient ObjectId newId;
private transient boolean isMerge;
private transient ComparisonType comparisonType;
private transient int insertions;
private transient int deletions;
private transient PatchListEntry[] patches;
public PatchList(
@Nullable AnyObjectId oldId,
AnyObjectId newId,
boolean isMerge,
ComparisonType comparisonType,
PatchListEntry[] patches) {
this.oldId = oldId != null ? oldId.copy() : null;
this.newId = newId.copy();
this.isMerge = isMerge;
this.comparisonType = comparisonType;
Arrays.sort(patches, 0, patches.length, PATCH_CMP);
// Skip magic files
int i = 0;
for (; i < patches.length; i++) {
if (!Patch.isMagic(patches[i].getNewName())) {
break;
}
}
for (; i < patches.length; i++) {
insertions += patches[i].getInsertions();
deletions += patches[i].getDeletions();
}
this.patches = patches;
}
/** Old side tree or commit; null only if this is a combined diff. */
@Nullable
public ObjectId getOldId() {
return oldId;
}
/** New side commit. */
public ObjectId getNewId() {
return newId;
}
/** Get a sorted, unmodifiable list of all files in this list. */
public List<PatchListEntry> getPatches() {
return Collections.unmodifiableList(Arrays.asList(patches));
}
/** @return the comparison type */
public ComparisonType getComparisonType() {
return comparisonType;
}
/** @return total number of new lines added. */
public int getInsertions() {
return insertions;
}
/** @return total number of lines removed. */
public int getDeletions() {
return deletions;
}
/**
* Get a sorted, modifiable list of all files in this list.
*
* <p>The returned list items do not populate:
*
* <ul>
* <li>{@link Patch#getCommentCount()}
* <li>{@link Patch#getDraftCount()}
* <li>{@link Patch#isReviewedByCurrentUser()}
* </ul>
*
* @param setId the patch set identity these patches belong to. This really should not need to be
* specified, but is a current legacy artifact of how the cache is keyed versus how the
* database is keyed.
*/
public List<Patch> toPatchList(PatchSet.Id setId) {
final ArrayList<Patch> r = new ArrayList<>(patches.length);
for (PatchListEntry e : patches) {
r.add(e.toPatch(setId));
}
return r;
}
/** Find an entry by name, returning an empty entry if not present. */
public PatchListEntry get(String fileName) {
final int index = search(fileName);
return 0 <= index ? patches[index] : PatchListEntry.empty(fileName);
}
private int search(String fileName) {
PatchListEntry want = PatchListEntry.empty(fileName);
return Arrays.binarySearch(patches, 0, patches.length, want, PATCH_CMP);
}
private void writeObject(ObjectOutputStream output) throws IOException {
final ByteArrayOutputStream buf = new ByteArrayOutputStream();
try (DeflaterOutputStream out = new DeflaterOutputStream(buf)) {
writeCanBeNull(out, oldId);
writeNotNull(out, newId);
writeVarInt32(out, isMerge ? 1 : 0);
comparisonType.writeTo(out);
writeVarInt32(out, insertions);
writeVarInt32(out, deletions);
writeVarInt32(out, patches.length);
for (PatchListEntry p : patches) {
p.writeTo(out);
}
}
writeBytes(output, buf.toByteArray());
}
private void readObject(ObjectInputStream input) throws IOException {
final ByteArrayInputStream buf = new ByteArrayInputStream(readBytes(input));
try (InflaterInputStream in = new InflaterInputStream(buf)) {
oldId = readCanBeNull(in);
newId = readNotNull(in);
isMerge = readVarInt32(in) != 0;
comparisonType = ComparisonType.readFrom(in);
insertions = readVarInt32(in);
deletions = readVarInt32(in);
final int cnt = readVarInt32(in);
final PatchListEntry[] all = new PatchListEntry[cnt];
for (int i = 0; i < all.length; i++) {
all[i] = PatchListEntry.readFrom(in);
}
patches = all;
}
}
}

View File

@@ -1,35 +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.diff;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import org.eclipse.jgit.lib.ObjectId;
/** Provides a cached list of {@link PatchListEntry}. */
public interface PatchListCache {
PatchList get(PatchListKey key, Project.NameKey project) throws PatchListNotAvailableException;
PatchList get(Change change, PatchSet patchSet) throws PatchListNotAvailableException;
ObjectId getOldId(Change change, PatchSet patchSet, Integer parentNum)
throws PatchListNotAvailableException;
IntraLineDiff getIntraLineDiff(IntraLineDiffKey key, IntraLineDiffArgs args);
DiffSummary getDiffSummary(DiffSummaryKey key, Project.NameKey project)
throws PatchListNotAvailableException;
}

View File

@@ -1,373 +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.diff;
import static com.google.gerrit.server.ioutil.BasicSerialization.readBytes;
import static com.google.gerrit.server.ioutil.BasicSerialization.readEnum;
import static com.google.gerrit.server.ioutil.BasicSerialization.readFixInt64;
import static com.google.gerrit.server.ioutil.BasicSerialization.readString;
import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeBytes;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeEnum;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeFixInt64;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeString;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.Patch.ChangeType;
import com.google.gerrit.reviewdb.client.Patch.PatchType;
import com.google.gerrit.reviewdb.client.PatchSet;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.patch.CombinedFileHeader;
import org.eclipse.jgit.patch.FileHeader;
import org.eclipse.jgit.util.IntList;
import org.eclipse.jgit.util.RawParseUtils;
public class PatchListEntry {
private static final byte[] EMPTY_HEADER = {};
public static PatchListEntry empty(String fileName) {
return new PatchListEntry(
ChangeType.MODIFIED,
PatchType.UNIFIED,
null,
fileName,
EMPTY_HEADER,
ImmutableList.of(),
ImmutableSet.of(),
0,
0,
0,
0);
}
private final ChangeType changeType;
private final PatchType patchType;
private final String oldName;
private final String newName;
private final byte[] header;
private final ImmutableList<Edit> edits;
private final ImmutableSet<Edit> editsDueToRebase;
private final int insertions;
private final int deletions;
private final long size;
private final long sizeDelta;
// Note: When adding new fields, the serialVersionUID in PatchListKey must be
// incremented so that entries from the cache are automatically invalidated.
public PatchListEntry(
FileHeader hdr, List<Edit> editList, Set<Edit> editsDueToRebase, long size, long sizeDelta) {
changeType = toChangeType(hdr);
patchType = toPatchType(hdr);
switch (changeType) {
case DELETED:
oldName = null;
newName = hdr.getOldPath();
break;
case ADDED:
case MODIFIED:
case REWRITE:
oldName = null;
newName = hdr.getNewPath();
break;
case COPIED:
case RENAMED:
oldName = hdr.getOldPath();
newName = hdr.getNewPath();
break;
default:
throw new IllegalArgumentException("Unsupported type " + changeType);
}
header = compact(hdr);
if (hdr instanceof CombinedFileHeader || hdr.getHunks().isEmpty()) {
edits = ImmutableList.of();
} else {
edits = ImmutableList.copyOf(editList);
}
this.editsDueToRebase = ImmutableSet.copyOf(editsDueToRebase);
int ins = 0;
int del = 0;
for (Edit e : editList) {
if (!editsDueToRebase.contains(e)) {
del += e.getEndA() - e.getBeginA();
ins += e.getEndB() - e.getBeginB();
}
}
insertions = ins;
deletions = del;
this.size = size;
this.sizeDelta = sizeDelta;
}
private PatchListEntry(
ChangeType changeType,
PatchType patchType,
String oldName,
String newName,
byte[] header,
ImmutableList<Edit> edits,
ImmutableSet<Edit> editsDueToRebase,
int insertions,
int deletions,
long size,
long sizeDelta) {
this.changeType = changeType;
this.patchType = patchType;
this.oldName = oldName;
this.newName = newName;
this.header = header;
this.edits = edits;
this.editsDueToRebase = editsDueToRebase;
this.insertions = insertions;
this.deletions = deletions;
this.size = size;
this.sizeDelta = sizeDelta;
}
public int weigh() {
int size = 16 + 6 * 8 + 2 * 4 + 20 + 16 + 8 + 4 + 20;
size += stringSize(oldName);
size += stringSize(newName);
size += header.length;
size += (8 + 16 + 4 * 4) * edits.size();
size += (8 + 16 + 4 * 4) * editsDueToRebase.size();
return size;
}
private static int stringSize(String str) {
if (str != null) {
return 16 + 3 * 4 + 16 + str.length() * 2;
}
return 0;
}
public ChangeType getChangeType() {
return changeType;
}
public PatchType getPatchType() {
return patchType;
}
public String getOldName() {
return oldName;
}
public String getNewName() {
return newName;
}
public ImmutableList<Edit> getEdits() {
return edits;
}
public ImmutableSet<Edit> getEditsDueToRebase() {
return editsDueToRebase;
}
public int getInsertions() {
return insertions;
}
public int getDeletions() {
return deletions;
}
public long getSize() {
return size;
}
public long getSizeDelta() {
return sizeDelta;
}
public List<String> getHeaderLines() {
final IntList m = RawParseUtils.lineMap(header, 0, header.length);
final List<String> headerLines = new ArrayList<>(m.size() - 1);
for (int i = 1; i < m.size() - 1; i++) {
final int b = m.get(i);
int e = m.get(i + 1);
if (header[e - 1] == '\n') {
e--;
}
headerLines.add(RawParseUtils.decode(Constants.CHARSET, header, b, e));
}
return headerLines;
}
Patch toPatch(PatchSet.Id setId) {
final Patch p = new Patch(new Patch.Key(setId, getNewName()));
p.setChangeType(getChangeType());
p.setPatchType(getPatchType());
p.setSourceFileName(getOldName());
p.setInsertions(insertions);
p.setDeletions(deletions);
return p;
}
void writeTo(OutputStream out) throws IOException {
writeEnum(out, changeType);
writeEnum(out, patchType);
writeString(out, oldName);
writeString(out, newName);
writeBytes(out, header);
writeVarInt32(out, insertions);
writeVarInt32(out, deletions);
writeFixInt64(out, size);
writeFixInt64(out, sizeDelta);
writeEditArray(out, edits);
writeEditArray(out, editsDueToRebase);
}
private static void writeEditArray(OutputStream out, Collection<Edit> edits) throws IOException {
writeVarInt32(out, edits.size());
for (Edit edit : edits) {
writeVarInt32(out, edit.getBeginA());
writeVarInt32(out, edit.getEndA());
writeVarInt32(out, edit.getBeginB());
writeVarInt32(out, edit.getEndB());
}
}
static PatchListEntry readFrom(InputStream in) throws IOException {
ChangeType changeType = readEnum(in, ChangeType.values());
PatchType patchType = readEnum(in, PatchType.values());
String oldName = readString(in);
String newName = readString(in);
byte[] hdr = readBytes(in);
int ins = readVarInt32(in);
int del = readVarInt32(in);
long size = readFixInt64(in);
long sizeDelta = readFixInt64(in);
Edit[] editArray = readEditArray(in);
Edit[] editsDueToRebase = readEditArray(in);
return new PatchListEntry(
changeType,
patchType,
oldName,
newName,
hdr,
ImmutableList.copyOf(editArray),
ImmutableSet.copyOf(editsDueToRebase),
ins,
del,
size,
sizeDelta);
}
private static Edit[] readEditArray(InputStream in) throws IOException {
int numEdits = readVarInt32(in);
Edit[] edits = new Edit[numEdits];
for (int i = 0; i < numEdits; i++) {
int beginA = readVarInt32(in);
int endA = readVarInt32(in);
int beginB = readVarInt32(in);
int endB = readVarInt32(in);
edits[i] = new Edit(beginA, endA, beginB, endB);
}
return edits;
}
private static byte[] compact(FileHeader h) {
final int end = end(h);
if (h.getStartOffset() == 0 && end == h.getBuffer().length) {
return h.getBuffer();
}
final byte[] buf = new byte[end - h.getStartOffset()];
System.arraycopy(h.getBuffer(), h.getStartOffset(), buf, 0, buf.length);
return buf;
}
private static int end(FileHeader h) {
if (h instanceof CombinedFileHeader) {
return h.getEndOffset();
}
if (!h.getHunks().isEmpty()) {
return h.getHunks().get(0).getStartOffset();
}
return h.getEndOffset();
}
private static ChangeType toChangeType(FileHeader hdr) {
switch (hdr.getChangeType()) {
case ADD:
return ChangeType.ADDED;
case MODIFY:
return ChangeType.MODIFIED;
case DELETE:
return ChangeType.DELETED;
case RENAME:
return ChangeType.RENAMED;
case COPY:
return ChangeType.COPIED;
default:
throw new IllegalArgumentException("Unsupported type " + hdr.getChangeType());
}
}
private static PatchType toPatchType(FileHeader hdr) {
PatchType pt;
switch (hdr.getPatchType()) {
case UNIFIED:
pt = PatchType.UNIFIED;
break;
case GIT_BINARY:
case BINARY:
pt = PatchType.BINARY;
break;
default:
throw new IllegalArgumentException("Unsupported type " + hdr.getPatchType());
}
if (pt != PatchType.BINARY) {
final byte[] buf = hdr.getBuffer();
for (int ptr = hdr.getStartOffset(); ptr < hdr.getEndOffset(); ptr++) {
if (buf[ptr] == '\0') {
// Its really binary, but Git couldn't see the nul early enough
// to realize its binary, and instead produced the diff.
//
// Force it to be a binary; it really should have been that.
//
pt = PatchType.BINARY;
break;
}
}
}
return pt;
}
}

View File

@@ -1,213 +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.diff;
import static com.google.common.base.Preconditions.checkState;
import static org.eclipse.jgit.lib.ObjectIdSerialization.readCanBeNull;
import static org.eclipse.jgit.lib.ObjectIdSerialization.readNotNull;
import static org.eclipse.jgit.lib.ObjectIdSerialization.writeCanBeNull;
import static org.eclipse.jgit.lib.ObjectIdSerialization.writeNotNull;
import com.google.common.collect.ImmutableBiMap;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Objects;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
public class PatchListKey implements Serializable {
public static final long serialVersionUID = 28L;
// TODO(aliceks): Get rid of this enum and the parameter in the PatchListKey as we only use one of
// its values.
public enum Algorithm {
PURE_TREE_DIFF,
OPTIMIZED_DIFF
}
private static final ImmutableBiMap<Algorithm, Character> ALGORITHM_TYPES =
ImmutableBiMap.of(
Algorithm.PURE_TREE_DIFF, 'T',
Algorithm.OPTIMIZED_DIFF, 'O');
public static final ImmutableBiMap<Whitespace, Character> WHITESPACE_TYPES =
ImmutableBiMap.of(
Whitespace.IGNORE_NONE, 'N',
Whitespace.IGNORE_TRAILING, 'E',
Whitespace.IGNORE_LEADING_AND_TRAILING, 'S',
Whitespace.IGNORE_ALL, 'A');
static {
checkState(WHITESPACE_TYPES.size() == Whitespace.values().length);
checkState(ALGORITHM_TYPES.size() == Algorithm.values().length);
}
public static PatchListKey againstDefaultBase(AnyObjectId newId, Whitespace ws) {
return new PatchListKey(null, newId, ws, Algorithm.OPTIMIZED_DIFF);
}
public static PatchListKey againstParentNum(int parentNum, AnyObjectId newId, Whitespace ws) {
return new PatchListKey(parentNum, newId, ws, Algorithm.OPTIMIZED_DIFF);
}
public static PatchListKey againstCommit(
AnyObjectId otherCommitId, AnyObjectId newId, Whitespace whitespace) {
return new PatchListKey(otherCommitId, newId, whitespace, Algorithm.OPTIMIZED_DIFF);
}
/**
* Old patch-set ID
*
* <p>When null, it represents the Base of the newId for a non-merge commit.
*
* <p>When newId is a merge commit, null value of the oldId represents either the auto-merge
* commit of the newId or a parent commit of the newId. These two cases are distinguished by the
* parentNum.
*/
private transient ObjectId oldId;
/**
* 1-based parent number when newId is a merge commit
*
* <p>For the auto-merge case this field is null.
*
* <p>Used only when oldId is null and newId is a merge commit
*/
private transient Integer parentNum;
private transient ObjectId newId;
private transient Whitespace whitespace;
private transient Algorithm algorithm;
private PatchListKey(AnyObjectId a, AnyObjectId b, Whitespace ws, Algorithm algorithm) {
oldId = a != null ? a.copy() : null;
newId = b.copy();
whitespace = ws;
this.algorithm = algorithm;
}
private PatchListKey(int parentNum, AnyObjectId b, Whitespace ws, Algorithm algorithm) {
this.parentNum = Integer.valueOf(parentNum);
newId = b.copy();
whitespace = ws;
this.algorithm = algorithm;
}
/** For use only by DiffSummaryKey. */
PatchListKey(
ObjectId oldId,
Integer parentNum,
ObjectId newId,
Whitespace whitespace,
Algorithm algorithm) {
this.oldId = oldId;
this.parentNum = parentNum;
this.newId = newId;
this.whitespace = whitespace;
this.algorithm = algorithm;
}
/** Old side commit, or null to assume ancestor or combined merge. */
@Nullable
public ObjectId getOldId() {
return oldId;
}
/** Parent number (old side) of the new side (merge) commit */
@Nullable
public Integer getParentNum() {
return parentNum;
}
/** New side commit name. */
public ObjectId getNewId() {
return newId;
}
public Whitespace getWhitespace() {
return whitespace;
}
public Algorithm getAlgorithm() {
return algorithm;
}
@Override
public int hashCode() {
return Objects.hash(oldId, parentNum, newId, whitespace, algorithm);
}
@Override
public boolean equals(Object o) {
if (o instanceof PatchListKey) {
PatchListKey k = (PatchListKey) o;
return Objects.equals(oldId, k.oldId)
&& Objects.equals(parentNum, k.parentNum)
&& Objects.equals(newId, k.newId)
&& whitespace == k.whitespace
&& algorithm == k.algorithm;
}
return false;
}
@Override
public String toString() {
StringBuilder n = new StringBuilder();
n.append("PatchListKey[");
n.append(oldId != null ? oldId.name() : "BASE");
n.append("..");
n.append(newId.name());
n.append(" ");
if (parentNum != null) {
n.append(parentNum);
n.append(" ");
}
n.append(whitespace.name());
n.append(" ");
n.append(algorithm.name());
n.append("]");
return n.toString();
}
private void writeObject(ObjectOutputStream out) throws IOException {
writeCanBeNull(out, oldId);
out.writeInt(parentNum == null ? 0 : parentNum);
writeNotNull(out, newId);
Character c = WHITESPACE_TYPES.get(whitespace);
if (c == null) {
throw new IOException("Invalid whitespace type: " + whitespace);
}
out.writeChar(c);
out.writeChar(ALGORITHM_TYPES.get(algorithm));
}
private void readObject(ObjectInputStream in) throws IOException {
oldId = readCanBeNull(in);
int n = in.readInt();
parentNum = n == 0 ? null : Integer.valueOf(n);
newId = readNotNull(in);
char t = in.readChar();
whitespace = WHITESPACE_TYPES.inverse().get(t);
if (whitespace == null) {
throw new IOException("Invalid whitespace type code: " + t);
}
char algorithmCharacter = in.readChar();
algorithm = ALGORITHM_TYPES.inverse().get(algorithmCharacter);
}
}

View File

@@ -1,31 +0,0 @@
// 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.server.diff;
public class PatchListNotAvailableException extends Exception {
private static final long serialVersionUID = 1L;
public PatchListNotAvailableException(String message) {
super(message);
}
public PatchListNotAvailableException(String message, Throwable cause) {
super(message, cause);
}
public PatchListNotAvailableException(Throwable cause) {
super(cause);
}
}

View File

@@ -1,37 +0,0 @@
// 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.server.diff;
import com.google.common.cache.Weigher;
/** Approximates memory usage for PatchList in bytes of memory used. */
public class PatchListWeigher implements Weigher<PatchListKey, PatchList> {
@Override
public int weigh(PatchListKey key, PatchList value) {
int size =
16
+ 4 * 8
+ 2 * 36
+ 8 // Size of PatchListKey, 64 bit JVM
+ 16
+ 3 * 8
+ 3 * 4
+ 20; // Size of PatchList, 64 bit JVM
for (PatchListEntry e : value.getPatches()) {
size += e.weigh();
}
return size;
}
}

View File

@@ -1,190 +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.diff;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.text.SimpleDateFormat;
import org.eclipse.jgit.diff.RawText;
import org.eclipse.jgit.errors.LargeObjectException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.util.RawParseUtils;
import org.mozilla.universalchardet.UniversalDetector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Text extends RawText {
private static final Logger log = LoggerFactory.getLogger(Text.class);
private static final int bigFileThreshold = PackConfig.DEFAULT_BIG_FILE_THRESHOLD;
public static final byte[] NO_BYTES = {};
public static final Text EMPTY = new Text(NO_BYTES);
public static Text forCommit(ObjectReader reader, AnyObjectId commitId) throws IOException {
try (RevWalk rw = new RevWalk(reader)) {
RevCommit c;
if (commitId instanceof RevCommit) {
c = (RevCommit) commitId;
} else {
c = rw.parseCommit(commitId);
}
StringBuilder b = new StringBuilder();
switch (c.getParentCount()) {
case 0:
break;
case 1:
{
RevCommit p = c.getParent(0);
rw.parseBody(p);
b.append("Parent: ");
b.append(reader.abbreviate(p, 8).name());
b.append(" (");
b.append(p.getShortMessage());
b.append(")\n");
break;
}
default:
for (int i = 0; i < c.getParentCount(); i++) {
RevCommit p = c.getParent(i);
rw.parseBody(p);
b.append(i == 0 ? "Merge Of: " : " ");
b.append(reader.abbreviate(p, 8).name());
b.append(" (");
b.append(p.getShortMessage());
b.append(")\n");
}
}
appendPersonIdent(b, "Author", c.getAuthorIdent());
appendPersonIdent(b, "Commit", c.getCommitterIdent());
b.append("\n");
b.append(c.getFullMessage());
return new Text(b.toString().getBytes(UTF_8));
}
}
public static Text forMergeList(
ComparisonType comparisonType, ObjectReader reader, AnyObjectId commitId) throws IOException {
try (RevWalk rw = new RevWalk(reader)) {
RevCommit c = rw.parseCommit(commitId);
StringBuilder b = new StringBuilder();
switch (c.getParentCount()) {
case 0:
break;
case 1:
{
break;
}
default:
int uniterestingParent =
comparisonType.isAgainstParent() ? comparisonType.getParentNum() : 1;
b.append("Merge List:\n\n");
for (RevCommit commit : MergeListBuilder.build(rw, c, uniterestingParent)) {
b.append("* ");
b.append(reader.abbreviate(commit, 8).name());
b.append(" ");
b.append(commit.getShortMessage());
b.append("\n");
}
}
return new Text(b.toString().getBytes(UTF_8));
}
}
private static void appendPersonIdent(StringBuilder b, String field, PersonIdent person) {
if (person != null) {
b.append(field).append(": ");
if (person.getName() != null) {
b.append(" ");
b.append(person.getName());
}
if (person.getEmailAddress() != null) {
b.append(" <");
b.append(person.getEmailAddress());
b.append(">");
}
b.append("\n");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ZZZ");
sdf.setTimeZone(person.getTimeZone());
b.append(field).append("Date: ");
b.append(sdf.format(person.getWhen()));
b.append("\n");
}
}
public static byte[] asByteArray(ObjectLoader ldr)
throws MissingObjectException, LargeObjectException, IOException {
return ldr.getCachedBytes(bigFileThreshold);
}
private static Charset charset(byte[] content, String encoding) {
if (encoding == null) {
UniversalDetector d = new UniversalDetector(null);
d.handleData(content, 0, content.length);
d.dataEnd();
encoding = d.getDetectedCharset();
}
if (encoding == null) {
return ISO_8859_1;
}
try {
return Charset.forName(encoding);
} catch (IllegalCharsetNameException err) {
log.error("Invalid detected charset name '" + encoding + "': " + err);
return ISO_8859_1;
} catch (UnsupportedCharsetException err) {
log.error("Detected charset '" + encoding + "' not supported: " + err);
return ISO_8859_1;
}
}
private Charset charset;
public Text(byte[] r) {
super(r);
}
public Text(ObjectLoader ldr) throws MissingObjectException, LargeObjectException, IOException {
this(asByteArray(ldr));
}
public byte[] getContent() {
return content;
}
@Override
protected String decode(int s, int e) {
if (charset == null) {
charset = charset(content, null);
}
return RawParseUtils.decode(charset, content, s, e);
}
}