Merge branch 'stable-3.6'
* stable-3.6: Prepare 3.6.2-SNAPSHOT builds JGit v3.6.1.201501031845-r Trim author/committer name and email in commit header Rename detection should canonicalize line endings PathMatcher should respect "assumeDirectory" flag Change-Id: Idd48c6d94cf1ab09abc07f70d50890b1b78e1833 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
commit
79dacba922
|
@ -83,7 +83,7 @@ public void testIndexingLargeObject() throws IOException,
|
|||
+ "B\n" //
|
||||
+ "B\n").getBytes("UTF-8");
|
||||
SimilarityIndex si = new SimilarityIndex();
|
||||
si.hash(new ByteArrayInputStream(in), in.length);
|
||||
si.hash(new ByteArrayInputStream(in), in.length, false);
|
||||
assertEquals(2, si.size());
|
||||
}
|
||||
|
||||
|
@ -103,6 +103,48 @@ public void testCommonScore_SameFiles() throws TableFullException {
|
|||
assertEquals(100, dst.score(src, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommonScore_SameFiles_CR_canonicalization()
|
||||
throws TableFullException {
|
||||
String text = "" //
|
||||
+ "A\r\n" //
|
||||
+ "B\r\n" //
|
||||
+ "D\r\n" //
|
||||
+ "B\r\n";
|
||||
SimilarityIndex src = hash(text);
|
||||
SimilarityIndex dst = hash(text.replace("\r", ""));
|
||||
assertEquals(8, src.common(dst));
|
||||
assertEquals(8, dst.common(src));
|
||||
|
||||
assertEquals(100, src.score(dst, 100));
|
||||
assertEquals(100, dst.score(src, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommonScoreLargeObject_SameFiles_CR_canonicalization()
|
||||
throws TableFullException, IOException {
|
||||
String text = "" //
|
||||
+ "A\r\n" //
|
||||
+ "B\r\n" //
|
||||
+ "D\r\n" //
|
||||
+ "B\r\n";
|
||||
SimilarityIndex src = new SimilarityIndex();
|
||||
byte[] bytes1 = text.getBytes("UTF-8");
|
||||
src.hash(new ByteArrayInputStream(bytes1), bytes1.length, true);
|
||||
src.sort();
|
||||
|
||||
SimilarityIndex dst = new SimilarityIndex();
|
||||
byte[] bytes2 = text.replace("\r", "").getBytes("UTF-8");
|
||||
dst.hash(new ByteArrayInputStream(bytes2), bytes2.length, true);
|
||||
dst.sort();
|
||||
|
||||
assertEquals(8, src.common(dst));
|
||||
assertEquals(8, dst.common(src));
|
||||
|
||||
assertEquals(100, src.score(dst, 100));
|
||||
assertEquals(100, dst.score(src, 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommonScore_EmptyFiles() throws TableFullException {
|
||||
SimilarityIndex src = hash("");
|
||||
|
@ -132,24 +174,8 @@ public void testCommonScore_SimiliarBy75() throws TableFullException {
|
|||
}
|
||||
|
||||
private static SimilarityIndex hash(String text) throws TableFullException {
|
||||
SimilarityIndex src = new SimilarityIndex() {
|
||||
@Override
|
||||
void hash(byte[] raw, int ptr, final int end)
|
||||
throws TableFullException {
|
||||
while (ptr < end) {
|
||||
int hash = raw[ptr] & 0xff;
|
||||
int start = ptr;
|
||||
do {
|
||||
int c = raw[ptr++] & 0xff;
|
||||
if (c == '\n')
|
||||
break;
|
||||
} while (ptr < end && ptr - start < 64);
|
||||
add(hash, ptr - start);
|
||||
}
|
||||
}
|
||||
};
|
||||
SimilarityIndex src = new SimilarityIndex();
|
||||
byte[] raw = Constants.encode(text);
|
||||
src.setFileSize(raw.length);
|
||||
src.hash(raw, 0, raw.length);
|
||||
src.sort();
|
||||
return src;
|
||||
|
|
|
@ -44,9 +44,12 @@
|
|||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jgit.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
@ -236,16 +239,62 @@ public void testParentDirectoryGitIgnores() {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testTrailingSlash() {
|
||||
public void testDirModeAndNoRegex() {
|
||||
String pattern = "/src/";
|
||||
assertMatched(pattern, "/src/");
|
||||
assertMatched(pattern, "/src/new");
|
||||
assertMatched(pattern, "/src/new/a.c");
|
||||
assertMatched(pattern, "/src/a.c");
|
||||
// no match as a "file" pattern, because rule is for directories only
|
||||
assertNotMatched(pattern, "/src");
|
||||
assertNotMatched(pattern, "/srcA/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirModeAndRegex1() {
|
||||
// IgnoreRule was buggy for some cases below, therefore using "Assume"
|
||||
Boolean assume = useOldRule;
|
||||
|
||||
String pattern = "a/*/src/";
|
||||
assertMatched(pattern, "a/b/src/");
|
||||
assertMatched(pattern, "a/b/src/new");
|
||||
assertMatched(pattern, "a/b/src/new/a.c");
|
||||
assertMatched(pattern, "a/b/src/a.c");
|
||||
// no match as a "file" pattern, because rule is for directories only
|
||||
assertNotMatched(pattern, "a/b/src", assume);
|
||||
assertNotMatched(pattern, "a/b/srcA/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirModeAndRegex2() {
|
||||
// IgnoreRule was buggy for some cases below, therefore using "Assume"
|
||||
Boolean assume = useOldRule;
|
||||
|
||||
String pattern = "a/[a-b]/src/";
|
||||
assertMatched(pattern, "a/b/src/");
|
||||
assertMatched(pattern, "a/b/src/new");
|
||||
assertMatched(pattern, "a/b/src/new/a.c");
|
||||
assertMatched(pattern, "a/b/src/a.c");
|
||||
// no match as a "file" pattern, because rule is for directories only
|
||||
assertNotMatched(pattern, "a/b/src", assume);
|
||||
assertNotMatched(pattern, "a/b/srcA/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirModeAndRegex3() {
|
||||
// IgnoreRule was buggy for some cases below, therefore using "Assume"
|
||||
Boolean assume = useOldRule;
|
||||
|
||||
String pattern = "**/src/";
|
||||
assertMatched(pattern, "a/b/src/", assume);
|
||||
assertMatched(pattern, "a/b/src/new", assume);
|
||||
assertMatched(pattern, "a/b/src/new/a.c", assume);
|
||||
assertMatched(pattern, "a/b/src/a.c", assume);
|
||||
// no match as a "file" pattern, because rule is for directories only
|
||||
assertNotMatched(pattern, "a/b/src", assume);
|
||||
assertNotMatched(pattern, "a/b/srcA/", assume);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNameOnlyMatches() {
|
||||
/*
|
||||
|
@ -321,11 +370,16 @@ public void testNegation() {
|
|||
* Pattern as it would appear in a .gitignore file
|
||||
* @param target
|
||||
* Target file path relative to repository's GIT_DIR
|
||||
* @param assume
|
||||
*/
|
||||
public void assertMatched(String pattern, String target) {
|
||||
public void assertMatched(String pattern, String target, Boolean... assume) {
|
||||
boolean value = match(pattern, target);
|
||||
assertTrue("Expected a match for: " + pattern + " with: " + target,
|
||||
value);
|
||||
if (assume.length == 0 || !assume[0].booleanValue())
|
||||
assertTrue("Expected a match for: " + pattern + " with: " + target,
|
||||
value);
|
||||
else
|
||||
assumeTrue("Expected a match for: " + pattern + " with: " + target,
|
||||
value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -336,11 +390,17 @@ public void assertMatched(String pattern, String target) {
|
|||
* Pattern as it would appear in a .gitignore file
|
||||
* @param target
|
||||
* Target file path relative to repository's GIT_DIR
|
||||
* @param assume
|
||||
*/
|
||||
public void assertNotMatched(String pattern, String target) {
|
||||
public void assertNotMatched(String pattern, String target,
|
||||
Boolean... assume) {
|
||||
boolean value = match(pattern, target);
|
||||
assertFalse("Expected no match for: " + pattern + " with: " + target,
|
||||
value);
|
||||
if (assume.length == 0 || !assume[0].booleanValue())
|
||||
assertFalse("Expected no match for: " + pattern + " with: "
|
||||
+ target, value);
|
||||
else
|
||||
assumeFalse("Expected no match for: " + pattern + " with: "
|
||||
+ target, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -355,16 +415,43 @@ public void assertNotMatched(String pattern, String target) {
|
|||
*/
|
||||
private boolean match(String pattern, String target) {
|
||||
boolean isDirectory = target.endsWith("/");
|
||||
boolean match;
|
||||
if (useOldRule.booleanValue()) {
|
||||
IgnoreRule r = new IgnoreRule(pattern);
|
||||
// If speed of this test is ever an issue, we can use a presetRule
|
||||
// field
|
||||
// to avoid recompiling a pattern each time.
|
||||
return r.isMatch(target, isDirectory);
|
||||
match = r.isMatch(target, isDirectory);
|
||||
} else {
|
||||
FastIgnoreRule r = new FastIgnoreRule(pattern);
|
||||
match = r.isMatch(target, isDirectory);
|
||||
}
|
||||
|
||||
if (isDirectory) {
|
||||
boolean noTrailingSlash = matchAsDir(pattern,
|
||||
target.substring(0, target.length() - 1));
|
||||
if (match != noTrailingSlash) {
|
||||
String message = "Difference in result for directory pattern: "
|
||||
+ pattern + " with: " + target
|
||||
+ " if target is given without trailing slash";
|
||||
Assert.assertEquals(message, match, noTrailingSlash);
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* must not ends with a slash!
|
||||
* @param pattern
|
||||
* same as {@link #match(String, String)}
|
||||
* @return same as {@link #match(String, String)}
|
||||
*/
|
||||
private boolean matchAsDir(String pattern, String target) {
|
||||
assertFalse(target.endsWith("/"));
|
||||
if (useOldRule.booleanValue()) {
|
||||
IgnoreRule r = new IgnoreRule(pattern);
|
||||
return r.isMatch(target, true);
|
||||
}
|
||||
FastIgnoreRule r = new FastIgnoreRule(pattern);
|
||||
// If speed of this test is ever an issue, we can use a presetRule field
|
||||
// to avoid recompiling a pattern each time.
|
||||
return r.isMatch(target, isDirectory);
|
||||
return r.isMatch(target, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
package org.eclipse.jgit.lib;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
@ -83,4 +84,15 @@ public void nullForNameShouldThrowIllegalArgumentException() {
|
|||
public void nullForEmailShouldThrowIllegalArgumentException() {
|
||||
new PersonIdent("A U Thor", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToExternalStringTrimsNameAndEmail() throws Exception {
|
||||
PersonIdent personIdent = new PersonIdent(" A U Thor ",
|
||||
" author@example.com ");
|
||||
|
||||
String externalString = personIdent.toExternalString();
|
||||
|
||||
assertTrue(externalString.startsWith("A U Thor <author@example.com>"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -79,8 +79,11 @@ class SimilarityIndex {
|
|||
/** Maximum value of the count field, also mask to extract the count. */
|
||||
private static final long MAX_COUNT = (1L << KEY_SHIFT) - 1;
|
||||
|
||||
/** Total size of the file we hashed into the structure. */
|
||||
private long fileSize;
|
||||
/**
|
||||
* Total amount of bytes hashed into the structure, including \n. This is
|
||||
* usually the size of the file minus number of CRLF encounters.
|
||||
*/
|
||||
private long hashedCnt;
|
||||
|
||||
/** Number of non-zero entries in {@link #idHash}. */
|
||||
private int idSize;
|
||||
|
@ -108,48 +111,59 @@ class SimilarityIndex {
|
|||
idGrowAt = growAt(idHashBits);
|
||||
}
|
||||
|
||||
long getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
void setFileSize(long size) {
|
||||
fileSize = size;
|
||||
}
|
||||
|
||||
void hash(ObjectLoader obj) throws MissingObjectException, IOException,
|
||||
TableFullException {
|
||||
if (obj.isLarge()) {
|
||||
ObjectStream in = obj.openStream();
|
||||
try {
|
||||
setFileSize(in.getSize());
|
||||
hash(in, fileSize);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
hashLargeObject(obj);
|
||||
} else {
|
||||
byte[] raw = obj.getCachedBytes();
|
||||
setFileSize(raw.length);
|
||||
hash(raw, 0, raw.length);
|
||||
}
|
||||
}
|
||||
|
||||
private void hashLargeObject(ObjectLoader obj) throws IOException,
|
||||
TableFullException {
|
||||
ObjectStream in1 = obj.openStream();
|
||||
boolean text;
|
||||
try {
|
||||
text = !RawText.isBinary(in1);
|
||||
} finally {
|
||||
in1.close();
|
||||
}
|
||||
|
||||
ObjectStream in2 = obj.openStream();
|
||||
try {
|
||||
hash(in2, in2.getSize(), text);
|
||||
} finally {
|
||||
in2.close();
|
||||
}
|
||||
}
|
||||
|
||||
void hash(byte[] raw, int ptr, final int end) throws TableFullException {
|
||||
final boolean text = !RawText.isBinary(raw);
|
||||
hashedCnt = 0;
|
||||
while (ptr < end) {
|
||||
int hash = 5381;
|
||||
int blockHashedCnt = 0;
|
||||
int start = ptr;
|
||||
|
||||
// Hash one line, or one block, whichever occurs first.
|
||||
do {
|
||||
int c = raw[ptr++] & 0xff;
|
||||
// Ignore CR in CRLF sequence if text
|
||||
if (text && c == '\r' && ptr < end && raw[ptr] == '\n')
|
||||
continue;
|
||||
blockHashedCnt++;
|
||||
if (c == '\n')
|
||||
break;
|
||||
hash = (hash << 5) + hash + c;
|
||||
} while (ptr < end && ptr - start < 64);
|
||||
add(hash, ptr - start);
|
||||
hashedCnt += blockHashedCnt;
|
||||
add(hash, blockHashedCnt);
|
||||
}
|
||||
}
|
||||
|
||||
void hash(InputStream in, long remaining) throws IOException,
|
||||
void hash(InputStream in, long remaining, boolean text) throws IOException,
|
||||
TableFullException {
|
||||
byte[] buf = new byte[4096];
|
||||
int ptr = 0;
|
||||
|
@ -157,6 +171,7 @@ void hash(InputStream in, long remaining) throws IOException,
|
|||
|
||||
while (0 < remaining) {
|
||||
int hash = 5381;
|
||||
int blockHashedCnt = 0;
|
||||
|
||||
// Hash one line, or one block, whichever occurs first.
|
||||
int n = 0;
|
||||
|
@ -170,11 +185,16 @@ void hash(InputStream in, long remaining) throws IOException,
|
|||
|
||||
n++;
|
||||
int c = buf[ptr++] & 0xff;
|
||||
// Ignore CR in CRLF sequence if text
|
||||
if (text && c == '\r' && ptr < cnt && buf[ptr] == '\n')
|
||||
continue;
|
||||
blockHashedCnt++;
|
||||
if (c == '\n')
|
||||
break;
|
||||
hash = (hash << 5) + hash + c;
|
||||
} while (n < 64 && n < remaining);
|
||||
add(hash, n);
|
||||
hashedCnt += blockHashedCnt;
|
||||
add(hash, blockHashedCnt);
|
||||
remaining -= n;
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +213,7 @@ void sort() {
|
|||
}
|
||||
|
||||
int score(SimilarityIndex dst, int maxScore) {
|
||||
long max = Math.max(fileSize, dst.fileSize);
|
||||
long max = Math.max(hashedCnt, dst.hashedCnt);
|
||||
if (max == 0)
|
||||
return maxScore;
|
||||
return (int) ((common(dst) * maxScore) / max);
|
||||
|
|
|
@ -217,7 +217,8 @@ boolean iterate(final String path, final int startIncl, final int endExcl,
|
|||
matcher++;
|
||||
match = matches(matcher, path, left, endExcl,
|
||||
assumeDirectory);
|
||||
} else if (dirOnly)
|
||||
} else if (dirOnly && !assumeDirectory)
|
||||
// Directory expectations not met
|
||||
return false;
|
||||
}
|
||||
return match && matcher + 1 == matchers.size();
|
||||
|
|
|
@ -254,9 +254,9 @@ && getEmailAddress().equals(p.getEmailAddress())
|
|||
*/
|
||||
public String toExternalString() {
|
||||
final StringBuilder r = new StringBuilder();
|
||||
r.append(getName());
|
||||
r.append(getName().trim());
|
||||
r.append(" <"); //$NON-NLS-1$
|
||||
r.append(getEmailAddress());
|
||||
r.append(getEmailAddress().trim());
|
||||
r.append("> "); //$NON-NLS-1$
|
||||
r.append(when / 1000);
|
||||
r.append(' ');
|
||||
|
|
Loading…
Reference in New Issue