From: Konrad Kügler Date: Sun, 12 Jan 2014 12:39:18 +0000 (+0100) Subject: Take core.autocrlf into account for blame annotations X-Git-Tag: v3.4.0.201405051725-m7~54 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=refs%2Fchanges%2F43%2F20543%2F4;p=jgit.git 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 Signed-off-by: Robin Rosenberg --- diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java index 7b2e85f003..20e93f88c4 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java +++ b/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.assertNotNull; +import java.io.File; + +import org.eclipse.jgit.api.ResetCommand.ResetType; import org.eclipse.jgit.blame.BlameResult; 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.storage.file.FileBasedConfig; import org.junit.Test; /** @@ -325,4 +331,59 @@ public class BlameCommandTest extends RepositoryTestCase { assertEquals(commit3, lines.getSourceCommit(1)); 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)); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java index 29726146c3..f7ce835d51 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java @@ -43,7 +43,10 @@ package org.eclipse.jgit.api; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; 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.ObjectId; 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. @@ -215,8 +222,10 @@ public class BlameCommand extends GitCommand { gen.push(null, dc.getEntry(entry).getObjectId()); File inTree = new File(repo.getWorkTree(), path); - if (repo.getFS().isFile(inTree)) - gen.push(null, new RawText(inTree)); + if (repo.getFS().isFile(inTree)) { + RawText rawText = getRawText(inTree); + gen.push(null, rawText); + } } } return gen.computeBlameResult(); @@ -226,4 +235,49 @@ public class BlameCommand extends GitCommand { 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(); + } + } }