Browse Source

Take core.autocrlf into account for blame annotations

Blaming with core.autocrlf set to 'true' - even for freshly checked out
files - showed all lines as being locally modified. For autocrlf = true
the line breaks of the local file will be converted to LF for blaming.
This results in useful diffs and therefor in the desired blame
annotations.

For autocrlf = input no conversion takes place to cope with CRLF line
breaks in the repository, in addition to the usual LF. For autocrlf =
true CRLF line breaks in the repo can't be supported without additional
effort. In that case the whole local file will be blamed as being
locally modified.

Change-Id: If020dcca54d16b2fb79210a070b8480aec82e58e
Signed-off-by: Konrad Kügler <swamblumat-eclipsebugs@yahoo.de>
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
stable-3.4
Konrad Kügler 11 years ago committed by Robin Rosenberg
parent
commit
efd91ef8a7
  1. 61
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java
  2. 58
      org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java

61
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java

@ -45,9 +45,15 @@ package org.eclipse.jgit.api;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import java.io.File;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.blame.BlameResult; import org.eclipse.jgit.blame.BlameResult;
import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.junit.Test; import org.junit.Test;
/** /**
@ -325,4 +331,59 @@ public class BlameCommandTest extends RepositoryTestCase {
assertEquals(commit3, lines.getSourceCommit(1)); assertEquals(commit3, lines.getSourceCommit(1));
assertEquals(commit3, lines.getSourceCommit(2)); assertEquals(commit3, lines.getSourceCommit(2));
} }
@Test
public void testCoreAutoCrlf1() throws Exception {
testCoreAutoCrlf(AutoCRLF.INPUT, AutoCRLF.FALSE);
}
@Test
public void testCoreAutoCrlf2() throws Exception {
testCoreAutoCrlf(AutoCRLF.FALSE, AutoCRLF.FALSE);
}
@Test
public void testCoreAutoCrlf3() throws Exception {
testCoreAutoCrlf(AutoCRLF.INPUT, AutoCRLF.INPUT);
}
@Test
public void testCoreAutoCrlf4() throws Exception {
testCoreAutoCrlf(AutoCRLF.FALSE, AutoCRLF.INPUT);
}
@Test
public void testCoreAutoCrlf5() throws Exception {
testCoreAutoCrlf(AutoCRLF.INPUT, AutoCRLF.TRUE);
}
private void testCoreAutoCrlf(AutoCRLF modeForCommitting,
AutoCRLF modeForReset) throws Exception {
Git git = new Git(db);
FileBasedConfig config = db.getConfig();
config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_AUTOCRLF, modeForCommitting);
config.save();
String joinedCrlf = "a\r\nb\r\nc\r\n";
File trashFile = writeTrashFile("file.txt", joinedCrlf);
git.add().addFilepattern("file.txt").call();
RevCommit commit = git.commit().setMessage("create file").call();
// re-create file from the repo
trashFile.delete();
config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_AUTOCRLF, modeForReset);
config.save();
git.reset().setMode(ResetType.HARD).call();
BlameCommand command = new BlameCommand(db);
command.setFilePath("file.txt");
BlameResult lines = command.call();
assertEquals(3, lines.getResultContents().size());
assertEquals(commit, lines.getSourceCommit(0));
assertEquals(commit, lines.getSourceCommit(1));
assertEquals(commit, lines.getSourceCommit(2));
}
} }

58
org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java

@ -43,7 +43,10 @@
package org.eclipse.jgit.api; package org.eclipse.jgit.api;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -60,6 +63,10 @@ import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
import org.eclipse.jgit.treewalk.WorkingTreeOptions;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.io.EolCanonicalizingInputStream;
/** /**
* Blame command for building a {@link BlameResult} for a file path. * Blame command for building a {@link BlameResult} for a file path.
@ -215,8 +222,10 @@ public class BlameCommand extends GitCommand<BlameResult> {
gen.push(null, dc.getEntry(entry).getObjectId()); gen.push(null, dc.getEntry(entry).getObjectId());
File inTree = new File(repo.getWorkTree(), path); File inTree = new File(repo.getWorkTree(), path);
if (repo.getFS().isFile(inTree)) if (repo.getFS().isFile(inTree)) {
gen.push(null, new RawText(inTree)); RawText rawText = getRawText(inTree);
gen.push(null, rawText);
}
} }
} }
return gen.computeBlameResult(); return gen.computeBlameResult();
@ -226,4 +235,49 @@ public class BlameCommand extends GitCommand<BlameResult> {
gen.release(); gen.release();
} }
} }
private RawText getRawText(File inTree) throws IOException,
FileNotFoundException {
RawText rawText;
WorkingTreeOptions workingTreeOptions = getRepository().getConfig()
.get(WorkingTreeOptions.KEY);
AutoCRLF autoCRLF = workingTreeOptions.getAutoCRLF();
switch (autoCRLF) {
case FALSE:
case INPUT:
// Git used the repo format on checkout, but other tools
// may change the format to CRLF. We ignore that here.
rawText = new RawText(inTree);
break;
case TRUE:
EolCanonicalizingInputStream in = new EolCanonicalizingInputStream(
new FileInputStream(inTree), true);
// Canonicalization should lead to same or shorter length
// (CRLF to LF), so the file size on disk is an upper size bound
rawText = new RawText(toByteArray(in, (int) inTree.length()));
break;
default:
throw new IllegalArgumentException(
"Unknown autocrlf option " + autoCRLF); //$NON-NLS-1$
}
return rawText;
}
private static byte[] toByteArray(InputStream source, int upperSizeLimit)
throws IOException {
byte[] buffer = new byte[upperSizeLimit];
try {
int read = IO.readFully(source, buffer, 0);
if (read == upperSizeLimit)
return buffer;
else {
byte[] copy = new byte[read];
System.arraycopy(buffer, 0, copy, 0, read);
return copy;
}
} finally {
source.close();
}
}
} }

Loading…
Cancel
Save