]> source.dussan.org Git - jgit.git/commitdiff
Take core.autocrlf into account for blame annotations 43/20543/4
authorKonrad Kügler <swamblumat-eclipsebugs@yahoo.de>
Sun, 12 Jan 2014 12:39:18 +0000 (13:39 +0100)
committerRobin Rosenberg <robin.rosenberg@dewire.com>
Mon, 10 Mar 2014 11:22:57 +0000 (12:22 +0100)
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>
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java
org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java

index 7b2e85f0032218c3cf4581ac419853337c2af979..20e93f88c4faa855a3b5860b428b457ee346164f 100644 (file)
@@ -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));
+       }
 }
index 29726146c364b40c4d396e4d22b0ed8c0ca26ef1..f7ce835d51fa00010b47f9c2fa9a873ef7c2635b 100644 (file)
 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<BlameResult> {
                                                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<BlameResult> {
                        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();
+               }
+       }
 }