diff options
23 files changed, 662 insertions, 106 deletions
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml index a4ff8a4b1d..a8f6ab73b0 100644 --- a/org.eclipse.jgit.packaging/pom.xml +++ b/org.eclipse.jgit.packaging/pom.xml @@ -62,7 +62,7 @@ <tycho-version>0.16.0</tycho-version> <jetty-version>7.6.0.v20120127</jetty-version> <args4j-version>2.0.12</args4j-version> - <jsch-version>0.1.44-1</jsch-version> + <jsch-version>0.1.46</jsch-version> <eclipse-site>http://download.eclipse.org/releases/indigo</eclipse-site> <orbit-site>http://download.eclipse.org/tools/orbit/downloads/drops/R20120526062928/repository/</orbit-site> </properties> diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/NL1.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/NL1.patch new file mode 100644 index 0000000000..ba5a4fc25d --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/NL1.patch @@ -0,0 +1,10 @@ +diff --git a/NL1 b/NL1 +index 68abad7..b14088c 100644 +--- a/NL1 ++++ b/NL1 +@@ -1,4 +1,4 @@ + a
+-b
++d
+ c
+
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/NL1_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/NL1_PostImage new file mode 100644 index 0000000000..b14088c045 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/NL1_PostImage @@ -0,0 +1,4 @@ +a
+d
+c
+
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/NL1_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/NL1_PreImage new file mode 100644 index 0000000000..68abad7d93 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/NL1_PreImage @@ -0,0 +1,4 @@ +a
+b
+c
+
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java index 5513b44603..a0a4ddcbf7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java @@ -178,6 +178,16 @@ public class ApplyCommandTest extends RepositoryTestCase { b.getString(0, b.size(), false)); } + @Test + public void testModifyNL1() throws Exception { + ApplyResult result = init("NL1"); + assertEquals(1, result.getUpdatedFiles().size()); + assertEquals(new File(db.getWorkTree(), "NL1"), result + .getUpdatedFiles().get(0)); + checkFile(new File(db.getWorkTree(), "NL1"), + b.getString(0, b.size(), false)); + } + private static byte[] readFile(final String patchFile) throws IOException { final InputStream in = DiffFormatterReflowTest.class .getResourceAsStream(patchFile); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java index ba97e905b3..fbaef76e1c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java @@ -1059,7 +1059,6 @@ public class RebaseCommandTest extends RepositoryTestCase { } @Test - @SuppressWarnings("null") public void testRebaseWithUnstagedTopicChange() throws Exception { // create file1, add and commit writeTrashFile(FILE1, "file1"); @@ -1084,19 +1083,14 @@ public class RebaseCommandTest extends RepositoryTestCase { writeTrashFile("file2", "unstaged file2"); // rebase - JGitInternalException exception = null; - try { - git.rebase().setUpstream("refs/heads/master").call(); - } catch (JGitInternalException e) { - exception = e; - } - assertNotNull(exception); - assertEquals("Checkout conflict with files: \nfile2", - exception.getMessage()); + RebaseResult result = git.rebase().setUpstream("refs/heads/master") + .call(); + assertEquals(Status.CONFLICTS, result.getStatus()); + assertEquals(1, result.getConflicts().size()); + assertEquals("file2", result.getConflicts().get(0)); } @Test - @SuppressWarnings("null") public void testRebaseWithUncommittedTopicChange() throws Exception { // create file1, add and commit writeTrashFile(FILE1, "file1"); @@ -1122,23 +1116,17 @@ public class RebaseCommandTest extends RepositoryTestCase { git.add().addFilepattern("file2").call(); // do not commit - // rebase - JGitInternalException exception = null; - try { - git.rebase().setUpstream("refs/heads/master").call(); - } catch (JGitInternalException e) { - exception = e; - } - assertNotNull(exception); - assertEquals("Checkout conflict with files: \nfile2", - exception.getMessage()); + RebaseResult result = git.rebase().setUpstream("refs/heads/master") + .call(); + assertEquals(Status.CONFLICTS, result.getStatus()); + assertEquals(1, result.getConflicts().size()); + assertEquals("file2", result.getConflicts().get(0)); checkFile(uncommittedFile, "uncommitted file2"); assertEquals(RepositoryState.SAFE, git.getRepository().getRepositoryState()); } @Test - @SuppressWarnings("null") public void testRebaseWithUnstagedMasterChange() throws Exception { // create file1, add and commit writeTrashFile(FILE1, "file1"); @@ -1163,19 +1151,14 @@ public class RebaseCommandTest extends RepositoryTestCase { writeTrashFile(FILE1, "unstaged modified file1"); // rebase - JGitInternalException exception = null; - try { - git.rebase().setUpstream("refs/heads/master").call(); - } catch (JGitInternalException e) { - exception = e; - } - assertNotNull(exception); - assertEquals("Checkout conflict with files: \nfile1", - exception.getMessage()); + RebaseResult result = git.rebase().setUpstream("refs/heads/master") + .call(); + assertEquals(Status.CONFLICTS, result.getStatus()); + assertEquals(1, result.getConflicts().size()); + assertEquals(FILE1, result.getConflicts().get(0)); } @Test - @SuppressWarnings("null") public void testRebaseWithUncommittedMasterChange() throws Exception { // create file1, add and commit writeTrashFile(FILE1, "file1"); @@ -1202,15 +1185,11 @@ public class RebaseCommandTest extends RepositoryTestCase { // do not commit // rebase - JGitInternalException exception = null; - try { - git.rebase().setUpstream("refs/heads/master").call(); - } catch (JGitInternalException e) { - exception = e; - } - assertNotNull(exception); - assertEquals("Checkout conflict with files: \nfile1", - exception.getMessage()); + RebaseResult result = git.rebase().setUpstream("refs/heads/master") + .call(); + assertEquals(Status.CONFLICTS, result.getStatus()); + assertEquals(1, result.getConflicts().size()); + assertEquals(FILE1, result.getConflicts().get(0)); } @Test @@ -1496,14 +1475,13 @@ public class RebaseCommandTest extends RepositoryTestCase { File theFile = writeTrashFile(FILE1, "dirty the file"); // and attempt to rebase - try { - RebaseResult rebaseResult = git.rebase() + RebaseResult rebaseResult = git.rebase() .setUpstream("refs/heads/master").call(); - fail("Checkout with conflict should have occured, not " - + rebaseResult.getStatus()); - } catch (JGitInternalException e) { - checkFile(theFile, "dirty the file"); - } + assertEquals(Status.CONFLICTS, rebaseResult.getStatus()); + assertEquals(1, rebaseResult.getConflicts().size()); + assertEquals(FILE1, rebaseResult.getConflicts().get(0)); + + checkFile(theFile, "dirty the file"); assertEquals(RepositoryState.SAFE, git.getRepository() .getRepositoryState()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java index cb7cad8340..4c9c54f214 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, Dariusz Luksza <dariusz@luksza.org> + * Copyright (C) 2011, 2013 Dariusz Luksza <dariusz@luksza.org> * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -47,6 +47,7 @@ import static org.eclipse.jgit.util.FileUtils.delete; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -65,6 +66,8 @@ import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.treewalk.EmptyTreeIterator; import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.filter.PathFilterGroup; +import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.eclipse.jgit.util.FileUtils; import org.junit.Test; @@ -265,6 +268,71 @@ public class DiffEntryTest extends RepositoryTestCase { assertThat(entry.getNewPath(), is("b.txt")); } + @Test + public void shouldMarkEntriesWhenGivenMarkTreeFilter() throws Exception { + // given + Git git = new Git(db); + RevCommit c1 = git.commit().setMessage("initial commit").call(); + FileUtils.mkdir(new File(db.getWorkTree(), "b")); + writeTrashFile("a.txt", "a"); + writeTrashFile("b/1.txt", "b1"); + writeTrashFile("b/2.txt", "b2"); + writeTrashFile("c.txt", "c"); + git.add().addFilepattern("a.txt").addFilepattern("b") + .addFilepattern("c.txt").call(); + RevCommit c2 = git.commit().setMessage("second commit").call(); + TreeFilter filterA = PathFilterGroup.createFromStrings("a.txt"); + TreeFilter filterB = PathFilterGroup.createFromStrings("b"); + TreeFilter filterB2 = PathFilterGroup.createFromStrings("b/2.txt"); + + // when + TreeWalk walk = new TreeWalk(db); + walk.addTree(c1.getTree()); + walk.addTree(c2.getTree()); + List<DiffEntry> result = DiffEntry.scan(walk, true, new TreeFilter[] { + filterA, filterB, filterB2 }); + + // then + assertThat(result, notNullValue()); + assertEquals(5, result.size()); + + DiffEntry entryA = result.get(0); + DiffEntry entryB = result.get(1); + DiffEntry entryB1 = result.get(2); + DiffEntry entryB2 = result.get(3); + DiffEntry entryC = result.get(4); + + assertThat(entryA.getNewPath(), is("a.txt")); + assertTrue(entryA.isMarked(0)); + assertFalse(entryA.isMarked(1)); + assertFalse(entryA.isMarked(2)); + assertEquals(1, entryA.getTreeFilterMarks()); + + assertThat(entryB.getNewPath(), is("b")); + assertFalse(entryB.isMarked(0)); + assertTrue(entryB.isMarked(1)); + assertTrue(entryB.isMarked(2)); + assertEquals(6, entryB.getTreeFilterMarks()); + + assertThat(entryB1.getNewPath(), is("b/1.txt")); + assertFalse(entryB1.isMarked(0)); + assertTrue(entryB1.isMarked(1)); + assertFalse(entryB1.isMarked(2)); + assertEquals(2, entryB1.getTreeFilterMarks()); + + assertThat(entryB2.getNewPath(), is("b/2.txt")); + assertFalse(entryB2.isMarked(0)); + assertTrue(entryB2.isMarked(1)); + assertTrue(entryB2.isMarked(2)); + assertEquals(6, entryB2.getTreeFilterMarks()); + + assertThat(entryC.getNewPath(), is("c.txt")); + assertFalse(entryC.isMarked(0)); + assertFalse(entryC.isMarked(1)); + assertFalse(entryC.isMarked(2)); + assertEquals(0, entryC.getTreeFilterMarks()); + } + @Test(expected = IllegalArgumentException.class) public void shouldThrowIAEWhenTreeWalkHasLessThanTwoTrees() throws Exception { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java index 73fb838f0b..88ace76eb7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java @@ -185,4 +185,46 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase { String message = formatter.format(Arrays.asList(a), head); assertEquals("Merge branch 'a'", message); } + + @Test + public void testFormatWithConflictsNoFooter() { + String originalMessage = "Header Line\n\nCommit body\n"; + String message = formatter.formatWithConflicts(originalMessage, + Arrays.asList(new String[] { "path1" })); + assertEquals("Header Line\n\nCommit body\n\nConflicts:\n\tpath1\n", + message); + } + + @Test + public void testFormatWithConflictsNoFooterNoLineBreak() { + String originalMessage = "Header Line\n\nCommit body"; + String message = formatter.formatWithConflicts(originalMessage, + Arrays.asList(new String[] { "path1" })); + assertEquals("Header Line\n\nCommit body\n\nConflicts:\n\tpath1\n", + message); + } + + @Test + public void testFormatWithConflictsWithFooters() { + String originalMessage = "Header Line\n\nCommit body\n\nChangeId:" + + " I123456789123456789123456789123456789\nBug:1234567\n"; + String message = formatter.formatWithConflicts(originalMessage, + Arrays.asList(new String[] { "path1" })); + assertEquals( + "Header Line\n\nCommit body\n\nConflicts:\n\tpath1\n\n" + + "ChangeId: I123456789123456789123456789123456789\nBug:1234567\n", + message); + } + + @Test + public void testFormatWithConflictsWithFooterlikeLineInBody() { + String originalMessage = "Header Line\n\nCommit body\nBug:1234567\nMore Body\n\nChangeId:" + + " I123456789123456789123456789123456789\nBug:1234567\n"; + String message = formatter.formatWithConflicts(originalMessage, + Arrays.asList(new String[] { "path1" })); + assertEquals( + "Header Line\n\nCommit body\nBug:1234567\nMore Body\n\nConflicts:\n\tpath1\n\n" + + "ChangeId: I123456789123456789123456789123456789\nBug:1234567\n", + message); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java index 4cdc02ac55..54f3114c6d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java @@ -123,15 +123,65 @@ public class ChangeIdUtilTest { @Test public void testHasChangeid() throws Exception { assertEquals( - "has changeid\n\nBug: 33\nmore text\nSigned-off-by: me@you.too\nChange-Id: I0123456789012345678901234567890123456789\nAnd then some\n", - call("has changeid\n\nBug: 33\nmore text\nSigned-off-by: me@you.too\nChange-Id: I0123456789012345678901234567890123456789\nAnd then some\n")); + "has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789\n", + call("has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789\n")); } @Test public void testHasChangeidWithReplacement() throws Exception { assertEquals( - "has changeid\n\nBug: 33\nmore text\nSigned-off-by: me@you.too\nChange-Id: I988d2d7a6f2c0578fccabd4ebd3cec0768bc7f9f\nAnd then some\n", - call("has changeid\n\nBug: 33\nmore text\nSigned-off-by: me@you.too\nChange-Id: I0123456789012345678901234567890123456789\nAnd then some\n", + "has changeid\nmore text\n\nSigned-off-by: me@you.too\n" + + "Change-Id: I2178563fada5edb2c99a8d8c0d619471b050ec24\nBug: 33\n", + call("has changeid\nmore text\n\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789\nBug: 33\n", + true)); + } + + @Test + public void testHasChangeidWithReplacementInLastLine() throws Exception { + assertEquals( + "has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I1d6578f4c96e3db4dd707705fe3d17bf658c4758\n", + call("has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789\n", + true)); + } + + @Test + public void testHasChangeidWithReplacementInLastLineNoLineBreak() + throws Exception { + assertEquals( + "has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I1d6578f4c96e3db4dd707705fe3d17bf658c4758", + call("has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789", + true)); + } + + @Test + public void testHasChangeidWithSpacesBeforeId() throws Exception { + assertEquals( + "has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: Ie7575eaf450fdd0002df2e642426faf251de3ad9\n", + call("has changeid\nmore text\n\nBug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789\n", + true)); + } + + @Test + public void testHasChangeidWithReplacementWithChangeIdInCommitMessage() + throws Exception { + assertEquals( + "has changeid\nmore text\n" + + "Change-Id: I0123456789012345678901234567890123456789\n\n" + + "Bug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: Ie48d10d59ef67995ca89688ac0171b88f10dd520\n", + call("has changeid\nmore text\n" + + "Change-Id: I0123456789012345678901234567890123456789\n\n" + + "Bug: 33\nSigned-off-by: me@you.too\n" + + "Change-Id: I0123456789012345678901234567890123456789\n", true)); } @@ -587,6 +637,34 @@ public class ChangeIdUtilTest { "git://example.com/ fixes this\n")); } + @Test + public void testIndexOfChangeId() { + assertEquals(3, ChangeIdUtil.indexOfChangeId("x\n" + "\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n", + "\n")); + assertEquals(5, ChangeIdUtil.indexOfChangeId("x\r\n" + "\r\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\r\n", + "\r\n")); + assertEquals(3, ChangeIdUtil.indexOfChangeId("x\r" + "\r" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\r", + "\r")); + assertEquals(8, ChangeIdUtil.indexOfChangeId("x\ny\n\nz\n" + "\n" + + "Change-Id: I3b7e4e16b503ce00f07ba6ad01d97a356dad7701\n", + "\n")); + } + + @Test + public void testIndexOfFirstFooterLine() { + assertEquals( + 2, + ChangeIdUtil.indexOfFirstFooterLine(new String[] { "a", "", + "Bug: 42", "Signed-Off-By: j.developer@a.com" })); + assertEquals( + 3, + ChangeIdUtil.indexOfFirstFooterLine(new String[] { "a", + "Bug: 42", "", "Signed-Off-By: j.developer@a.com" })); + } + private void hookDoesNotModify(final String in) throws Exception { assertEquals(in, call(in)); } diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index 48cb487543..6673a8cd4e 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -477,6 +477,7 @@ transportProtoLocal=Local Git Repository transportProtoSFTP=SFTP transportProtoSSH=SSH treeEntryAlreadyExists=Tree entry "{0}" already exists. +treeFilterMarkerTooManyFilters=Too many markTreeFilters passed, maximum number is {0} (passed {1}) treeIteratorDoesNotSupportRemove=TreeIterator does not support remove() treeWalkMustHaveExactlyTwoTrees=TreeWalk should have exactly two trees. truncatedHunkLinesMissingForAncestor=Truncated hunk, at least {0} lines missing for ancestor {1} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java index 2147a2e5c4..6a945e4d39 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java @@ -238,13 +238,10 @@ public class ApplyCommand extends GitCommand<ApplyResult> { if (!isChanged(oldLines, newLines)) return; // don't touch the file StringBuilder sb = new StringBuilder(); - final String eol = rt.size() == 0 - || (rt.size() == 1 && rt.isMissingNewlineAtEnd()) ? "\n" : rt //$NON-NLS-1$ - .getLineDelimiter(); for (String l : newLines) { - sb.append(l); - if (eol != null) - sb.append(eol); + // don't bother handling line endings - if it was windows, the \r is + // still there! + sb.append(l).append('\n'); } sb.deleteCharAt(sb.length() - 1); FileWriter fw = new FileWriter(f); @@ -252,7 +249,7 @@ public class ApplyCommand extends GitCommand<ApplyResult> { fw.close(); } - private boolean isChanged(List<String> ol, List<String> nl) { + private static boolean isChanged(List<String> ol, List<String> nl) { if (ol.size() != nl.size()) return true; for (int i = 0; i < ol.size(); i++) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java index 1c930ebeb3..82272168aa 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java @@ -45,6 +45,7 @@ package org.eclipse.jgit.api; import java.text.MessageFormat; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.eclipse.jgit.internal.JGitText; @@ -177,6 +178,21 @@ public class MergeResult { public boolean isSuccessful() { return false; } + }, + /** + * Status representing a checkout conflict, meaning that nothing could + * be merged, as the pre-scan for the trees already failed for certain + * files (i.e. local modifications prevent checkout of files). + */ + CHECKOUT_CONFLICT { + public String toString() { + return "Checkout Conflict"; + } + + @Override + public boolean isSuccessful() { + return false; + } }; /** @@ -201,6 +217,8 @@ public class MergeResult { private Map<String, MergeFailureReason> failingPaths; + private List<String> checkoutConflicts; + /** * @param newHead * the object the head points at after the merge @@ -295,6 +313,18 @@ public class MergeResult { } /** + * Creates a new result that represents a checkout conflict before the + * operation even started for real. + * + * @param checkoutConflicts + * the conflicting files + */ + public MergeResult(List<String> checkoutConflicts) { + this.checkoutConflicts = checkoutConflicts; + this.mergeStatus = MergeStatus.CHECKOUT_CONFLICT; + } + + /** * @return the object the head points at after the merge */ public ObjectId getNewHead() { @@ -450,4 +480,14 @@ public class MergeResult { public Map<String, MergeFailureReason> getFailingPaths() { return failingPaths; } + + /** + * Returns a list of paths that cause a checkout conflict. These paths + * prevent the operation from even starting. + * + * @return the list of files that caused the checkout conflict. + */ + public List<String> getCheckoutConflicts() { + return checkoutConflicts; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java index 3f7feb936f..5158c8533b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java @@ -355,6 +355,8 @@ public class RebaseCommand extends GitCommand<RebaseResult> { return RebaseResult.OK_RESULT; } return RebaseResult.FAST_FORWARD_RESULT; + } catch (CheckoutConflictException cce) { + return new RebaseResult(cce.getConflictingPaths()); } catch (IOException ioe) { throw new JGitInternalException(ioe.getMessage(), ioe); } @@ -880,13 +882,18 @@ public class RebaseCommand extends GitCommand<RebaseResult> { return RawParseUtils.decode(content, 0, end); } - private boolean checkoutCommit(RevCommit commit) throws IOException { + private boolean checkoutCommit(RevCommit commit) throws IOException, + CheckoutConflictException { try { RevCommit head = walk.parseCommit(repo.resolve(Constants.HEAD)); DirCacheCheckout dco = new DirCacheCheckout(repo, head.getTree(), repo.lockDirCache(), commit.getTree()); dco.setFailOnConflict(true); - dco.checkout(); + try { + dco.checkout(); + } catch (org.eclipse.jgit.errors.CheckoutConflictException cce) { + throw new CheckoutConflictException(dco.getConflicts(), cce); + } // update the HEAD RefUpdate refUpdate = repo.updateRef(Constants.HEAD, true); refUpdate.setExpectedOldObjectId(head); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java index a09f8c28af..59655570c0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java @@ -42,6 +42,7 @@ */ package org.eclipse.jgit.api; +import java.util.List; import java.util.Map; import org.eclipse.jgit.merge.ResolveMerger; @@ -93,6 +94,15 @@ public class RebaseResult { } }, /** + * Conflicts: checkout of target HEAD failed + */ + CONFLICTS { + @Override + public boolean isSuccessful() { + return false; + } + }, + /** * Already up-to-date */ UP_TO_DATE { @@ -148,6 +158,8 @@ public class RebaseResult { private Map<String, MergeFailureReason> failingPaths; + private List<String> conflicts; + private RebaseResult(Status status) { this.status = status; currentCommit = null; @@ -177,6 +189,18 @@ public class RebaseResult { } /** + * Create <code>RebaseResult</code> with status {@link Status#CONFLICTS} + * + * @param conflicts + * the list of conflicting paths + */ + RebaseResult(List<String> conflicts) { + status = Status.CONFLICTS; + currentCommit = null; + this.conflicts = conflicts; + } + + /** * @return the overall status */ public Status getStatus() { @@ -199,4 +223,11 @@ public class RebaseResult { public Map<String, MergeFailureReason> getFailingPaths() { return failingPaths; } + + /** + * @return the list of conflicts if status is {@link Status#CONFLICTS} + */ + public List<String> getConflicts() { + return conflicts; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java index cc8d285d95..a3d4e09d70 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2010, Google Inc. + * Copyright (C) 2008-2013, Google Inc. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -55,6 +55,8 @@ import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.MutableObjectId; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.filter.TreeFilter; +import org.eclipse.jgit.treewalk.filter.TreeFilterMarker; /** A value class representing a change to a file */ public class DiffEntry { @@ -123,7 +125,7 @@ public class DiffEntry { * when {@code includeTrees} parameter is {@code true} it can't * be recursive. * @param includeTrees - * include tree object's. + * include tree objects. * @return headers describing the changed files. * @throws IOException * the repository cannot be accessed. @@ -134,6 +136,36 @@ public class DiffEntry { */ public static List<DiffEntry> scan(TreeWalk walk, boolean includeTrees) throws IOException { + return scan(walk, includeTrees, null); + } + + /** + * Convert the TreeWalk into DiffEntry headers, depending on + * {@code includeTrees} it will add tree objects into result or not. + * + * @param walk + * the TreeWalk to walk through. Must have exactly two trees and + * when {@code includeTrees} parameter is {@code true} it can't + * be recursive. + * @param includeTrees + * include tree objects. + * @param markTreeFilters + * array of tree filters which will be tested for each entry. If + * an entry matches, the entry will later return true when + * queried through {{@link #isMarked(int)} (with the index from + * this passed array). + * @return headers describing the changed files. + * @throws IOException + * the repository cannot be accessed. + * @throws IllegalArgumentException + * when {@code includeTrees} is true and given TreeWalk is + * recursive. Or when given TreeWalk doesn't have exactly two + * trees + * @since 2.3 + */ + public static List<DiffEntry> scan(TreeWalk walk, boolean includeTrees, + TreeFilter[] markTreeFilters) + throws IOException { if (walk.getTreeCount() != 2) throw new IllegalArgumentException( JGitText.get().treeWalkMustHaveExactlyTwoTrees); @@ -141,6 +173,12 @@ public class DiffEntry { throw new IllegalArgumentException( JGitText.get().cannotBeRecursiveWhenTreesAreIncluded); + TreeFilterMarker treeFilterMarker; + if (markTreeFilters != null && markTreeFilters.length > 0) + treeFilterMarker = new TreeFilterMarker(markTreeFilters); + else + treeFilterMarker = null; + List<DiffEntry> r = new ArrayList<DiffEntry>(); MutableObjectId idBuf = new MutableObjectId(); while (walk.next()) { @@ -156,6 +194,9 @@ public class DiffEntry { entry.newMode = walk.getFileMode(1); entry.newPath = entry.oldPath = walk.getPathString(); + if (treeFilterMarker != null) + entry.treeFilterMarks = treeFilterMarker.getMarks(walk); + if (entry.oldMode == FileMode.MISSING) { entry.oldPath = DiffEntry.DEV_NULL; entry.changeType = ChangeType.ADD; @@ -295,6 +336,12 @@ public class DiffEntry { protected AbbreviatedObjectId newId; /** + * Bitset for marked flags of tree filters passed to + * {@link #scan(TreeWalk, boolean, TreeFilter...)} + */ + private int treeFilterMarks = 0; + + /** * Get the old name associated with this file. * <p> * The meaning of the old name can differ depending on the semantic meaning @@ -397,6 +444,48 @@ public class DiffEntry { } /** + * Whether the mark tree filter with the specified index matched during scan + * or not, see {@link #scan(TreeWalk, boolean, TreeFilter...)}. Example: + * <p> + * + * <pre> + * TreeFilter filterA = ...; + * TreeFilter filterB = ...; + * List<DiffEntry> entries = DiffEntry.scan(walk, false, filterA, filterB); + * DiffEntry entry = entries.get(0); + * boolean filterAMatched = entry.isMarked(0); + * boolean filterBMatched = entry.isMarked(1); + * </pre> + * <p> + * Note that 0 corresponds to filterA because it was the first filter that + * was passed to scan. + * <p> + * To query more than one flag at once, see {@link #getTreeFilterMarks()}. + * + * @param index + * the index of the tree filter to check for (must be between 0 + * and {@link Integer#SIZE}). + * + * @return true, if the tree filter matched; false if not + * @since 2.3 + */ + public boolean isMarked(int index) { + return (treeFilterMarks & (1L << index)) != 0; + } + + /** + * Get the raw tree filter marks, as set during + * {@link #scan(TreeWalk, boolean, TreeFilter...)}. See + * {@link #isMarked(int)} to query each mark individually. + * + * @return the bitset of tree filter marks + * @since 2.3 + */ + public int getTreeFilterMarks() { + return treeFilterMarks; + } + + /** * Get the object id. * * @param side diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index 2876843926..d402f139ff 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, Sasa Zivkov <sasa.zivkov@sap.com> + * Copyright (C) 2010, 2013 Sasa Zivkov <sasa.zivkov@sap.com> * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -538,6 +538,7 @@ public class JGitText extends TranslationBundle { /***/ public String transportProtoSFTP; /***/ public String transportProtoSSH; /***/ public String treeEntryAlreadyExists; + /***/ public String treeFilterMarkerTooManyFilters; /***/ public String treeIteratorDoesNotSupportRemove; /***/ public String treeWalkMustHaveExactlyTwoTrees; /***/ public String truncatedHunkLinesMissingForAncestor; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java index 29fa8d65ad..d94e7280c1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java @@ -48,6 +48,7 @@ import java.util.List; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.util.ChangeIdUtil; import org.eclipse.jgit.util.StringUtils; /** @@ -133,14 +134,26 @@ public class MergeMessageFormatter { */ public String formatWithConflicts(String message, List<String> conflictingPaths) { - StringBuilder sb = new StringBuilder(message); - if (!message.endsWith("\n") && message.length() != 0) //$NON-NLS-1$ - sb.append("\n"); //$NON-NLS-1$ - sb.append("\n"); //$NON-NLS-1$ - sb.append("Conflicts:\n"); + StringBuilder sb = new StringBuilder(); + String[] lines = message.split("\n"); //$NON-NLS-1$ + int firstFooterLine = ChangeIdUtil.indexOfFirstFooterLine(lines); + for (int i = 0; i < firstFooterLine; i++) + sb.append(lines[i]).append('\n'); + if (firstFooterLine == lines.length && message.length() != 0) + sb.append('\n'); + addConflictsMessage(conflictingPaths, sb); + if (firstFooterLine < lines.length) + sb.append('\n'); + for (int i = firstFooterLine; i < lines.length; i++) + sb.append(lines[i]).append('\n'); + return sb.toString(); + } + + private static void addConflictsMessage(List<String> conflictingPaths, + StringBuilder sb) { + sb.append("Conflicts:\n"); //$NON-NLS-1$ for (String conflictingPath : conflictingPaths) sb.append('\t').append(conflictingPath).append('\n'); - return sb.toString(); } private static String joinNames(List<String> names, String singular, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsOutputStream.java index 9a2aff4fae..2070d80157 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsOutputStream.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, Google Inc. + * Copyright (C) 2011, 2012 Google Inc. and others. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -47,10 +47,12 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; +import org.eclipse.jgit.storage.pack.PackExt; + /** * Output stream to create a file on the DFS. * - * @see DfsObjDatabase#writeFile(DfsPackDescription, String) + * @see DfsObjDatabase#writeFile(DfsPackDescription, PackExt) */ public abstract class DfsOutputStream extends OutputStream { /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsPackDescription.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsPackDescription.java index 3d3d80de93..a793d3c820 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsPackDescription.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/dfs/DfsPackDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, Google Inc. + * Copyright (C) 2011, 2013 Google Inc., and others. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -84,7 +84,7 @@ public class DfsPackDescription implements Comparable<DfsPackDescription> { * <p> * The corresponding index file is assumed to exist. If this is not true * implementors must extend the class and override - * {@link #getFileName(String)}. + * {@link #getFileName(PackExt)}. * <p> * Callers should also try to fill in other fields if they are reasonably * free to access at the time this instance is being initialized. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilterMarker.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilterMarker.java new file mode 100644 index 0000000000..59515dca52 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/TreeFilterMarker.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2013, Robin Stocker <robin@nibor.org> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.treewalk.filter; + +import java.io.IOException; +import java.text.MessageFormat; + +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.errors.StopWalkException; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.treewalk.TreeWalk; + +/** + * For testing an array of {@link TreeFilter} during a {@link TreeWalk} for each + * entry and returning the result as a bitmask. + * + * @since 2.3 + */ +public class TreeFilterMarker { + + private final TreeFilter[] filters; + + /** + * Construct a TreeFilterMarker. Note that it is stateful and can only be + * used for one walk loop. + * + * @param markTreeFilters + * the filters to use for marking, must not have more elements + * than {@link Integer#SIZE}. + * @throws IllegalArgumentException + * if more tree filters are passed than possible + */ + public TreeFilterMarker(TreeFilter[] markTreeFilters) { + if (markTreeFilters.length > Integer.SIZE) { + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().treeFilterMarkerTooManyFilters, + Integer.valueOf(Integer.SIZE), + Integer.valueOf(markTreeFilters.length))); + } + filters = new TreeFilter[markTreeFilters.length]; + System.arraycopy(markTreeFilters, 0, filters, 0, markTreeFilters.length); + } + + /** + * Test the filters against the walk. Returns a bitmask where each bit + * represents the result of a call to {@link TreeFilter#include(TreeWalk)}, + * ordered by the index for which the tree filters were passed in the + * constructor. + * + * @param walk + * the walk from which to test the current entry + * @return the marks bitmask + * @throws MissingObjectException + * as thrown by {@link TreeFilter#include(TreeWalk)} + * @throws IncorrectObjectTypeException + * as thrown by {@link TreeFilter#include(TreeWalk)} + * @throws IOException + * as thrown by {@link TreeFilter#include(TreeWalk)} + */ + public int getMarks(TreeWalk walk) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + int marks = 0; + for (int index = 0; index < filters.length; index++) { + TreeFilter filter = filters[index]; + if (filter != null) { + try { + boolean marked = filter.include(walk); + if (marked) + marks |= (1L << index); + } catch (StopWalkException e) { + // Don't check tree filter anymore, it will no longer + // match + filters[index] = null; + } + } + } + return marks; + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java index a869b2beac..41bb4cc7eb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java @@ -161,36 +161,26 @@ public class ChangeIdUtil { */ public static String insertId(String message, ObjectId changeId, boolean replaceExisting) { - if (message.indexOf(CHANGE_ID) > 0) { - if (replaceExisting) { - int i = message.indexOf(CHANGE_ID) + 10; - while (message.charAt(i) == ' ') - i++; - String oldId = message.length() == (i + 40) ? - message.substring(i) : message.substring(i, i + 41); - message = message.replace(oldId, "I" + changeId.getName()); //$NON-NLS-1$ + int indexOfChangeId = indexOfChangeId(message, "\n"); //$NON-NLS-1$ + if (indexOfChangeId > 0) { + if (!replaceExisting) + return message; + else { + StringBuilder ret = new StringBuilder(message.substring(0, + indexOfChangeId)); + ret.append(CHANGE_ID); + ret.append(" I"); //$NON-NLS-1$ + ret.append(ObjectId.toString(changeId)); + int indexOfNextLineBreak = message.indexOf("\n", //$NON-NLS-1$ + indexOfChangeId); + if (indexOfNextLineBreak > 0) + ret.append(message.substring(indexOfNextLineBreak)); + return ret.toString(); } - return message; } String[] lines = message.split("\n"); //$NON-NLS-1$ - int footerFirstLine = lines.length; - for (int i = lines.length - 1; i > 1; --i) { - if (footerPattern.matcher(lines[i]).matches()) { - footerFirstLine = i; - continue; - } - if (footerFirstLine != lines.length && lines[i].length() == 0) { - break; - } - if (footerFirstLine != lines.length - && includeInFooterPattern.matcher(lines[i]).matches()) { - footerFirstLine = i + 1; - continue; - } - footerFirstLine = lines.length; - break; - } + int footerFirstLine = indexOfFirstFooterLine(lines); int insertAfter = footerFirstLine; for (int i = footerFirstLine; i < lines.length; ++i) { if (issuePattern.matcher(lines[i]).matches()) { @@ -217,4 +207,57 @@ public class ChangeIdUtil { } return ret.toString(); } + + /** + * Find the index in the String {@code} message} where the Change-Id entry + * begins + * + * @param message + * @param delimiter + * the line delimiter, like "\n" or "\r\n", needed to find the + * footer + * @return the index of the ChangeId footer in the message, or -1 if no + * ChangeId footer available + */ + public static int indexOfChangeId(String message, String delimiter) { + String[] lines = message.split(delimiter); + int footerFirstLine = indexOfFirstFooterLine(lines); + if (footerFirstLine == lines.length) + return -1; + + int indexOfFooter = 0; + for (int i = 0; i < footerFirstLine; ++i) + indexOfFooter += lines[i].length() + delimiter.length(); + return message.indexOf(CHANGE_ID, indexOfFooter); + } + + /** + * Find the index of the first line of the footer paragraph in an array of + * the lines, or lines.length if no footer is available + * + * @param lines + * the commit message split into lines and the line delimiters + * stripped off + * @return the index of the first line of the footer paragraph, or + * lines.length if no footer is available + */ + public static int indexOfFirstFooterLine(String[] lines) { + int footerFirstLine = lines.length; + for (int i = lines.length - 1; i > 1; --i) { + if (footerPattern.matcher(lines[i]).matches()) { + footerFirstLine = i; + continue; + } + if (footerFirstLine != lines.length && lines[i].length() == 0) + break; + if (footerFirstLine != lines.length + && includeInFooterPattern.matcher(lines[i]).matches()) { + footerFirstLine = i + 1; + continue; + } + footerFirstLine = lines.length; + break; + } + return footerFirstLine; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java index ce62628e85..73f9161ca3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java @@ -90,7 +90,7 @@ class FS_Win32 extends FS { String path = SystemReader.getInstance().getenv("PATH"); //$NON-NLS-1$ File gitExe = searchPath(path, "git.exe", "git.cmd"); //$NON-NLS-1$ //$NON-NLS-2$ if (gitExe != null) - return gitExe.getParentFile().getParentFile(); + return resolveGrandparentFile(gitExe); // This isn't likely to work, if bash is in $PATH, git should // also be in $PATH. But its worth trying. @@ -102,7 +102,16 @@ class FS_Win32 extends FS { // The path may be in cygwin/msys notation so resolve it right away gitExe = resolve(null, w); if (gitExe != null) - return gitExe.getParentFile().getParentFile(); + return resolveGrandparentFile(gitExe); + } + return null; + } + + private static File resolveGrandparentFile(File grandchild) { + if (grandchild != null) { + File parent = grandchild.getParentFile(); + if (parent != null) + return parent.getParentFile(); } return null; } @@ -115,7 +124,8 @@ class FS_Win32 extends FS { String homeDrive = SystemReader.getInstance().getenv("HOMEDRIVE"); //$NON-NLS-1$ if (homeDrive != null) { String homePath = SystemReader.getInstance().getenv("HOMEPATH"); //$NON-NLS-1$ - return new File(homeDrive, homePath); + if (homePath != null) + return new File(homeDrive, homePath); } String homeShare = SystemReader.getInstance().getenv("HOMESHARE"); //$NON-NLS-1$ @@ -73,6 +73,12 @@ <name>Christian Halstrick</name> </developer> <developer> + <name>Colby Ranger</name> + </developer> + <developer> + <name>Dave Borowitz</name> + </developer> + <developer> <name>Gunnar Wagenknecht</name> </developer> <developer> @@ -170,7 +176,7 @@ <bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest> <jgit-last-release-version>2.1.0.201209190230-r</jgit-last-release-version> - <jsch-version>0.1.44-1</jsch-version> + <jsch-version>0.1.46</jsch-version> <junit-version>4.5</junit-version> <args4j-version>2.0.12</args4j-version> <commons-compress-version>1.3</commons-compress-version> |