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:
@@ -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",
|
||||
],
|
||||
)
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user