Browse Source

Merge branch 'master' into stable-4.2

Change-Id: Ia92c91e1226da7d6455ab14f1e255a1546f8f357
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
stable-4.2
Matthias Sohn 9 years ago
parent
commit
edec10dc39
  1. 4
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
  2. 4
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
  3. 4
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
  4. 18
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
  5. 11
      org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
  6. 5
      org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
  7. 1
      org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
  8. 24
      org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
  9. 6
      org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
  10. 6
      org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java7).launch
  11. 1
      org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java8).launch
  12. 3
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
  13. 159
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RemoteTest.java
  14. 8
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java
  15. 5
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java
  16. 1
      org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
  17. 5
      org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
  18. 10
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
  19. 3
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
  20. 10
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
  21. 4
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
  22. 197
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java
  23. 18
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
  24. 7
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
  25. 5
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
  26. 7
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
  27. 3
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
  28. 1
      org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 7).launch
  29. 1
      org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 8).launch
  30. 96
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AbstractRemoteCommandTest.java
  31. 188
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
  32. 136
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
  33. 6
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
  34. 54
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
  35. 4
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NameRevCommandTest.java
  36. 8
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
  37. 81
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteAddCommandTest.java
  38. 68
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java
  39. 68
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteListCommandTest.java
  40. 100
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java
  41. 6
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
  42. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java
  43. 102
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java
  44. 20
      org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
  45. 29
      org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java
  46. 55
      org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java
  47. 866
      org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java
  48. 31
      org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java
  49. 4
      org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
  50. 38
      org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
  51. 49
      org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
  52. 8
      org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java
  53. 40
      org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
  54. 13
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
  55. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java
  56. 24
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
  57. 48
      org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java
  58. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
  59. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SquashMessageFormatterTest.java
  60. 200
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java
  61. 143
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
  62. 12
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java
  63. 15
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
  64. 29
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java
  65. 41
      org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java
  66. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java
  67. 1
      org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java
  68. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java
  69. 1
      org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java
  70. 21
      org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java
  71. 65
      org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java
  72. 30
      org.eclipse.jgit/.settings/.api_filters
  73. 2
      org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
  74. 52
      org.eclipse.jgit/META-INF/MANIFEST.MF
  75. 7
      org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
  76. 69
      org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java
  77. 41
      org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java
  78. 7
      org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
  79. 6
      org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
  80. 6
      org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
  81. 44
      org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
  82. 27
      org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
  83. 14
      org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
  84. 133
      org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java
  85. 91
      org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java
  86. 110
      org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
  87. 155
      org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
  88. 5
      org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
  89. 144
      org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java
  90. 16
      org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java
  91. 202
      org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java
  92. 12
      org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java
  93. 81
      org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java
  94. 55
      org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java
  95. 19
      org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java
  96. 4
      org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
  97. 38
      org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
  98. 81
      org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java
  99. 125
      org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
  100. 31
      org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
  101. Some files were not shown because too many files have changed in this diff Show More

4
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java

@ -209,7 +209,7 @@ public class DumbClientDumbServerTest extends HttpTestCase {
} }
assertTrue(dst.hasObject(A_txt)); assertTrue(dst.hasObject(A_txt));
assertEquals(B, dst.getRef(master).getObjectId()); assertEquals(B, dst.exactRef(master).getObjectId());
fsck(dst, B); fsck(dst, B);
List<AccessEvent> loose = getRequests(loose(remoteURI, A_txt)); List<AccessEvent> loose = getRequests(loose(remoteURI, A_txt));
@ -234,7 +234,7 @@ public class DumbClientDumbServerTest extends HttpTestCase {
} }
assertTrue(dst.hasObject(A_txt)); assertTrue(dst.hasObject(A_txt));
assertEquals(B, dst.getRef(master).getObjectId()); assertEquals(B, dst.exactRef(master).getObjectId());
fsck(dst, B); fsck(dst, B);
List<AccessEvent> req; List<AccessEvent> req;

4
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java

@ -225,7 +225,7 @@ public class DumbClientSmartServerTest extends HttpTestCase {
} }
assertTrue(dst.hasObject(A_txt)); assertTrue(dst.hasObject(A_txt));
assertEquals(B, dst.getRef(master).getObjectId()); assertEquals(B, dst.exactRef(master).getObjectId());
fsck(dst, B); fsck(dst, B);
List<AccessEvent> loose = getRequests(loose(remoteURI, A_txt)); List<AccessEvent> loose = getRequests(loose(remoteURI, A_txt));
@ -253,7 +253,7 @@ public class DumbClientSmartServerTest extends HttpTestCase {
} }
assertTrue(dst.hasObject(A_txt)); assertTrue(dst.hasObject(A_txt));
assertEquals(B, dst.getRef(master).getObjectId()); assertEquals(B, dst.exactRef(master).getObjectId());
fsck(dst, B); fsck(dst, B);
List<AccessEvent> req; List<AccessEvent> req;

4
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java

@ -164,8 +164,8 @@ public class HookMessageTest extends HttpTestCase {
} }
assertTrue(remoteRepository.hasObject(Q_txt)); assertTrue(remoteRepository.hasObject(Q_txt));
assertNotNull("has " + dstName, remoteRepository.getRef(dstName)); assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
assertEquals(Q, remoteRepository.getRef(dstName).getObjectId()); assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
fsck(remoteRepository, Q); fsck(remoteRepository, Q);
List<AccessEvent> requests = getRequests(); List<AccessEvent> requests = getRequests();

18
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java

@ -296,7 +296,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
} }
assertTrue(dst.hasObject(A_txt)); assertTrue(dst.hasObject(A_txt));
assertEquals(B, dst.getRef(master).getObjectId()); assertEquals(B, dst.exactRef(master).getObjectId());
fsck(dst, B); fsck(dst, B);
List<AccessEvent> requests = getRequests(); List<AccessEvent> requests = getRequests();
@ -337,7 +337,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
} finally { } finally {
t.close(); t.close();
} }
assertEquals(B, dst.getRepository().getRef(master).getObjectId()); assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
List<AccessEvent> cloneRequests = getRequests(); List<AccessEvent> cloneRequests = getRequests();
// Only create a few new commits. // Only create a few new commits.
@ -358,7 +358,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
} finally { } finally {
t.close(); t.close();
} }
assertEquals(Z, dst.getRepository().getRef(master).getObjectId()); assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
List<AccessEvent> requests = getRequests(); List<AccessEvent> requests = getRequests();
requests.removeAll(cloneRequests); requests.removeAll(cloneRequests);
@ -400,7 +400,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
} finally { } finally {
t.close(); t.close();
} }
assertEquals(B, dst.getRepository().getRef(master).getObjectId()); assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
List<AccessEvent> cloneRequests = getRequests(); List<AccessEvent> cloneRequests = getRequests();
// Force enough into the local client that enumeration will // Force enough into the local client that enumeration will
@ -424,7 +424,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
} finally { } finally {
t.close(); t.close();
} }
assertEquals(Z, dst.getRepository().getRef(master).getObjectId()); assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
List<AccessEvent> requests = getRequests(); List<AccessEvent> requests = getRequests();
requests.removeAll(cloneRequests); requests.removeAll(cloneRequests);
@ -579,8 +579,8 @@ public class SmartClientSmartServerTest extends HttpTestCase {
} }
assertTrue(remoteRepository.hasObject(Q_txt)); assertTrue(remoteRepository.hasObject(Q_txt));
assertNotNull("has " + dstName, remoteRepository.getRef(dstName)); assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
assertEquals(Q, remoteRepository.getRef(dstName).getObjectId()); assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
fsck(remoteRepository, Q); fsck(remoteRepository, Q);
final ReflogReader log = remoteRepository.getReflogReader(dstName); final ReflogReader log = remoteRepository.getReflogReader(dstName);
@ -657,8 +657,8 @@ public class SmartClientSmartServerTest extends HttpTestCase {
} }
assertTrue(remoteRepository.hasObject(Q_bin)); assertTrue(remoteRepository.hasObject(Q_bin));
assertNotNull("has " + dstName, remoteRepository.getRef(dstName)); assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
assertEquals(Q, remoteRepository.getRef(dstName).getObjectId()); assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
fsck(remoteRepository, Q); fsck(remoteRepository, Q);
List<AccessEvent> requests = getRequests(); List<AccessEvent> requests = getRequests();

11
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java

@ -241,6 +241,17 @@ public abstract class JGitTestUtil {
FileUtils.delete(path); FileUtils.delete(path);
} }
/**
* @param db
* the repository
* @param link
* the path of the symbolic link to create
* @param target
* the target of the symbolic link
* @return the path to the symbolic link
* @throws Exception
* @since 4.2
*/
public static Path writeLink(Repository db, String link, public static Path writeLink(Repository db, String link,
String target) throws Exception { String target) throws Exception {
return FileUtils.createSymLink(new File(db.getWorkTree(), link), return FileUtils.createSymLink(new File(db.getWorkTree(), link),

5
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java

@ -91,7 +91,10 @@ public abstract class LocalDiskRepositoryTestCase {
/** A fake (but stable) identity for committer fields in the test. */ /** A fake (but stable) identity for committer fields in the test. */
protected PersonIdent committer; protected PersonIdent committer;
/** A {@link SystemReader} used to coordinate time, envars, etc. */ /**
* A {@link SystemReader} used to coordinate time, envars, etc.
* @since 4.2
*/
protected MockSystemReader mockSystemReader; protected MockSystemReader mockSystemReader;
private final List<Repository> toClose = new ArrayList<Repository>(); private final List<Repository> toClose = new ArrayList<Repository>();

1
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java

@ -151,6 +151,7 @@ public class MockSystemReader extends SystemReader {
* *
* @param secDelta * @param secDelta
* number of seconds to add to the current time. * number of seconds to add to the current time.
* @since 4.2
*/ */
public void tick(final int secDelta) { public void tick(final int secDelta) {
now += secDelta * 1000L; now += secDelta * 1000L;

24
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java

@ -108,6 +108,17 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
return JGitTestUtil.writeTrashFile(db, name, data); return JGitTestUtil.writeTrashFile(db, name, data);
} }
/**
* Create a symbolic link
*
* @param link
* the path of the symbolic link to create
* @param target
* the target of the symbolic link
* @return the path to the symbolic link
* @throws Exception
* @since 4.2
*/
protected Path writeLink(final String link, final String target) protected Path writeLink(final String link, final String target)
throws Exception { throws Exception {
return JGitTestUtil.writeLink(db, link, target); return JGitTestUtil.writeLink(db, link, target);
@ -271,6 +282,19 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
return name; return name;
} }
/**
* Replaces '\' by '/'
*
* @param str
* the string in which backslashes should be replaced
* @return the resulting string with slashes
* @since 4.2
*/
public static String slashify(String str) {
str = str.replace('\\', '/');
return str;
}
/** /**
* Waits until it is guaranteed that a subsequent file modification has a * Waits until it is guaranteed that a subsequent file modification has a
* younger modification timestamp than the modification timestamp of the * younger modification timestamp than the modification timestamp of the

6
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java

@ -175,6 +175,7 @@ public class TestRepository<R extends Repository> {
* the MockSystemReader to use for clock and other system * the MockSystemReader to use for clock and other system
* operations. * operations.
* @throws IOException * @throws IOException
* @since 4.2
*/ */
public TestRepository(R db, RevWalk rw, MockSystemReader reader) public TestRepository(R db, RevWalk rw, MockSystemReader reader)
throws IOException { throws IOException {
@ -203,7 +204,10 @@ public class TestRepository<R extends Repository> {
return git; return git;
} }
/** @return current date. */ /**
* @return current date.
* @since 4.2
*/
public Date getDate() { public Date getDate() {
return new Date(mockSystemReader.getCurrentTime()); return new Date(mockSystemReader.getCurrentTime());
} }

6
org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java7).launch

@ -15,12 +15,6 @@
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/> <booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/> <stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/> <stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;org.eclipse.jgit.pgm.test&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;org.eclipse.jgit.java7&quot; type=&quot;1&quot;/&gt;&#10;"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/> <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/> <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.pgm.test"/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.pgm.test"/>

1
org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java8).launch

@ -19,7 +19,6 @@
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH"> <listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;org.eclipse.jgit.pgm.test&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;org.eclipse.jgit.pgm.test&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;org.eclipse.jgit.java7&quot; type=&quot;1&quot;/&gt;&#10;"/>
</listAttribute> </listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>

3
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java

@ -198,7 +198,8 @@ public class CheckoutTest extends CLIRepositoryTestCase {
assertStringArrayEquals("Switched to a new branch 'new_branch'", assertStringArrayEquals("Switched to a new branch 'new_branch'",
execute("git checkout --orphan new_branch")); execute("git checkout --orphan new_branch"));
assertEquals("refs/heads/new_branch", db.getRef("HEAD").getTarget().getName()); assertEquals("refs/heads/new_branch",
db.exactRef("HEAD").getTarget().getName());
RevCommit commit = git.commit().setMessage("orphan commit").call(); RevCommit commit = git.commit().setMessage("orphan commit").call();
assertEquals(0, commit.getParentCount()); assertEquals(0, commit.getParentCount());
} }

159
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RemoteTest.java

@ -0,0 +1,159 @@
/*
* Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* 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.pgm;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.List;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import org.junit.Before;
import org.junit.Test;
public class RemoteTest extends CLIRepositoryTestCase {
private StoredConfig config;
private RemoteConfig remote;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
// create another repository
Repository remoteRepository = createWorkRepository();
// set it up as a remote to this repository
config = db.getConfig();
remote = new RemoteConfig(config, "test");
remote.addFetchRefSpec(
new RefSpec("+refs/heads/*:refs/remotes/test/*"));
URIish uri = new URIish(
remoteRepository.getDirectory().toURI().toURL());
remote.addURI(uri);
remote.update(config);
config.save();
Git.wrap(remoteRepository).commit().setMessage("initial commit").call();
}
@Test
public void testList() throws Exception {
assertArrayEquals(new String[] { remote.getName(), "" },
execute("git remote"));
}
@Test
public void testVerboseList() throws Exception {
assertArrayEquals(
new String[] {
String.format("%s\t%s (fetch)", remote.getName(),
remote.getURIs().get(0)),
String.format("%s\t%s (push)", remote.getName(),
remote.getURIs().get(0)),
"" },
execute("git remote -v"));
}
@Test
public void testAdd() throws Exception {
assertArrayEquals(new String[] { "" },
execute("git remote add second git://test.com/second"));
List<RemoteConfig> remotes = RemoteConfig.getAllRemoteConfigs(config);
assertEquals(2, remotes.size());
assertEquals("second", remotes.get(0).getName());
assertEquals("test", remotes.get(1).getName());
}
@Test
public void testRemove() throws Exception {
assertArrayEquals(new String[] { "" },
execute("git remote remove test"));
assertTrue(RemoteConfig.getAllRemoteConfigs(config).isEmpty());
}
@Test
public void testSetUrl() throws Exception {
assertArrayEquals(new String[] { "" },
execute("git remote set-url test git://test.com/test"));
RemoteConfig result = new RemoteConfig(config, "test");
assertEquals("test", result.getName());
assertArrayEquals(new URIish[] { new URIish("git://test.com/test") },
result.getURIs().toArray());
assertTrue(result.getPushURIs().isEmpty());
}
@Test
public void testSetUrlPush() throws Exception {
assertArrayEquals(new String[] { "" },
execute("git remote set-url --push test git://test.com/test"));
RemoteConfig result = new RemoteConfig(config, "test");
assertEquals("test", result.getName());
assertEquals(remote.getURIs(), result.getURIs());
assertArrayEquals(new URIish[] { new URIish("git://test.com/test") },
result.getPushURIs().toArray());
}
@Test
public void testUpdate() throws Exception {
assertArrayEquals(new String[] {
"From " + remote.getURIs().get(0).toString(),
" * [new branch] master -> test/master", "", "" },
execute("git remote update test"));
}
}

8
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java

@ -67,7 +67,7 @@ public class ResetTest extends CLIRepositoryTestCase {
assertStringArrayEquals("", assertStringArrayEquals("",
execute("git reset --hard " + commit.getId().name())); execute("git reset --hard " + commit.getId().name()));
assertEquals(commit.getId(), assertEquals(commit.getId(),
git.getRepository().getRef("HEAD").getObjectId()); git.getRepository().exactRef("HEAD").getObjectId());
} }
@Test @Test
@ -77,7 +77,7 @@ public class ResetTest extends CLIRepositoryTestCase {
assertStringArrayEquals("", assertStringArrayEquals("",
execute("git reset --hard " + commit.getId().name())); execute("git reset --hard " + commit.getId().name()));
assertEquals(commit.getId(), assertEquals(commit.getId(),
git.getRepository().getRef("HEAD").getObjectId()); git.getRepository().exactRef("HEAD").getObjectId());
} }
@Test @Test
@ -86,7 +86,7 @@ public class ResetTest extends CLIRepositoryTestCase {
assertStringArrayEquals("", assertStringArrayEquals("",
execute("git reset --hard " + commit.getId().name() + " --")); execute("git reset --hard " + commit.getId().name() + " --"));
assertEquals(commit.getId(), assertEquals(commit.getId(),
git.getRepository().getRef("HEAD").getObjectId()); git.getRepository().exactRef("HEAD").getObjectId());
} }
@Test @Test
@ -119,7 +119,7 @@ public class ResetTest extends CLIRepositoryTestCase {
(useDoubleDash) ? " --" : ""); (useDoubleDash) ? " --" : "");
assertStringArrayEquals("", execute(cmd)); assertStringArrayEquals("", execute(cmd));
assertEquals(commit.getId(), assertEquals(commit.getId(),
git.getRepository().getRef("HEAD").getObjectId()); git.getRepository().exactRef("HEAD").getObjectId());
org.eclipse.jgit.api.Status status = git.status().call(); org.eclipse.jgit.api.Status status = git.status().call();
// assert that file a is unstaged // assert that file a is unstaged

5
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java

@ -42,13 +42,14 @@
*/ */
package org.eclipse.jgit.pgm; package org.eclipse.jgit.pgm;
import static org.eclipse.jgit.lib.Constants.MASTER;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
import java.io.IOException; import java.io.IOException;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Test; import org.junit.Test;
@ -254,7 +255,7 @@ public class StatusTest extends CLIRepositoryTestCase {
} }
private void detachHead(Git git) throws IOException, GitAPIException { private void detachHead(Git git) throws IOException, GitAPIException {
String commitId = db.getRef(Constants.MASTER).getObjectId().name(); String commitId = db.exactRef(R_HEADS + MASTER).getObjectId().name();
git.checkout().setName(commitId).call(); git.checkout().setName(commitId).call();
} }

1
org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin

@ -24,6 +24,7 @@ org.eclipse.jgit.pgm.MergeBase
org.eclipse.jgit.pgm.Push org.eclipse.jgit.pgm.Push
org.eclipse.jgit.pgm.ReceivePack org.eclipse.jgit.pgm.ReceivePack
org.eclipse.jgit.pgm.Reflog org.eclipse.jgit.pgm.Reflog
org.eclipse.jgit.pgm.Remote
org.eclipse.jgit.pgm.Repo org.eclipse.jgit.pgm.Repo
org.eclipse.jgit.pgm.Reset org.eclipse.jgit.pgm.Reset
org.eclipse.jgit.pgm.RevList org.eclipse.jgit.pgm.RevList

5
org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties

@ -128,6 +128,7 @@ metaVar_user=USER
metaVar_version=VERSION metaVar_version=VERSION
mostCommonlyUsedCommandsAre=The most commonly used commands are: mostCommonlyUsedCommandsAre=The most commonly used commands are:
needApprovalToDestroyCurrentRepository=Need approval to destroy current repository needApprovalToDestroyCurrentRepository=Need approval to destroy current repository
needSingleRevision=Needed a single revision
noGitRepositoryConfigured=No Git repository configured. noGitRepositoryConfigured=No Git repository configured.
noNamesFound=No names found, cannot describe anything. noNamesFound=No names found, cannot describe anything.
noSuchFile=no such file: {0} noSuchFile=no such file: {0}
@ -142,6 +143,7 @@ notAJgitCommand={0} is not a jgit command
notARevision=Not a revision: {0} notARevision=Not a revision: {0}
notATree={0} is not a tree notATree={0} is not a tree
notAValidRefName={0} is not a valid ref name notAValidRefName={0} is not a valid ref name
notAValidCommitName={0} is not a valid commit name
notAnIndexFile={0} is not an index file notAnIndexFile={0} is not an index file
notAnObject={0} is not an object notAnObject={0} is not an object
notFound=!! NOT FOUND !! notFound=!! NOT FOUND !!
@ -186,6 +188,7 @@ treeIsRequired=argument tree is required
tooManyRefsGiven=Too many refs given tooManyRefsGiven=Too many refs given
unknownIoErrorStdout=An unknown I/O error occurred on standard output unknownIoErrorStdout=An unknown I/O error occurred on standard output
unknownMergeStrategy=unknown merge strategy {0} specified unknownMergeStrategy=unknown merge strategy {0} specified
unknownSubcommand=Unknown subcommand: {0}
unmergedPaths=Unmerged paths: unmergedPaths=Unmerged paths:
unsupportedOperation=Unsupported operation: {0} unsupportedOperation=Unsupported operation: {0}
untrackedFiles=Untracked files: untrackedFiles=Untracked files:
@ -220,6 +223,7 @@ usage_MergeBase=Find as good common ancestors as possible for a merge
usage_MergesTwoDevelopmentHistories=Merges two development histories usage_MergesTwoDevelopmentHistories=Merges two development histories
usage_ReadDirCache= Read the DirCache 100 times usage_ReadDirCache= Read the DirCache 100 times
usage_RebuildCommitGraph=Recreate a repository from another one's commit graph usage_RebuildCommitGraph=Recreate a repository from another one's commit graph
usage_Remote=Manage set of tracked repositories
usage_RepositoryToReadFrom=Repository to read from usage_RepositoryToReadFrom=Repository to read from
usage_RepositoryToReceiveInto=Repository to receive into usage_RepositoryToReceiveInto=Repository to receive into
usage_RevList=List commit objects in reverse chronological order usage_RevList=List commit objects in reverse chronological order
@ -327,6 +331,7 @@ usage_performFsckStyleChecksOnReceive=perform fsck style checks on receive
usage_portNumberToListenOn=port number to listen on usage_portNumberToListenOn=port number to listen on
usage_printOnlyBranchesThatContainTheCommit=print only branches that contain the commit usage_printOnlyBranchesThatContainTheCommit=print only branches that contain the commit
usage_pruneStaleTrackingRefs=prune stale tracking refs usage_pruneStaleTrackingRefs=prune stale tracking refs
usage_pushUrls=push URLs are manipulated
usage_quiet=don't show progress messages usage_quiet=don't show progress messages
usage_recordChangesToRepository=Record changes to the repository usage_recordChangesToRepository=Record changes to the repository
usage_recurseIntoSubtrees=recurse into subtrees usage_recurseIntoSubtrees=recurse into subtrees

10
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java

@ -154,10 +154,14 @@ class Branch extends TextBuiltin {
startBranch = Constants.HEAD; startBranch = Constants.HEAD;
Ref startRef = db.getRef(startBranch); Ref startRef = db.getRef(startBranch);
ObjectId startAt = db.resolve(startBranch + "^0"); //$NON-NLS-1$ ObjectId startAt = db.resolve(startBranch + "^0"); //$NON-NLS-1$
if (startRef != null) if (startRef != null) {
startBranch = startRef.getName(); startBranch = startRef.getName();
else } else if (startAt != null) {
startBranch = startAt.name(); startBranch = startAt.name();
} else {
throw die(MessageFormat.format(
CLIText.get().notAValidCommitName, startBranch));
}
startBranch = Repository.shortenRefName(startBranch); startBranch = Repository.shortenRefName(startBranch);
String newRefName = newHead; String newRefName = newHead;
if (!newRefName.startsWith(Constants.R_HEADS)) if (!newRefName.startsWith(Constants.R_HEADS))
@ -249,7 +253,7 @@ class Branch extends TextBuiltin {
String current = db.getBranch(); String current = db.getBranch();
ObjectId head = db.resolve(Constants.HEAD); ObjectId head = db.resolve(Constants.HEAD);
for (String branch : branches) { for (String branch : branches) {
if (current.equals(branch)) { if (branch.equals(current)) {
throw die(MessageFormat.format(CLIText.get().cannotDeleteTheBranchWhichYouAreCurrentlyOn, branch)); throw die(MessageFormat.format(CLIText.get().cannotDeleteTheBranchWhichYouAreCurrentlyOn, branch));
} }
RefUpdate update = db.updateRef((remote ? Constants.R_REMOTES RefUpdate update = db.updateRef((remote ? Constants.R_REMOTES

3
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java

@ -96,6 +96,9 @@ class Commit extends TextBuiltin {
commitCmd.setAmend(amend); commitCmd.setAmend(amend);
commitCmd.setAll(all); commitCmd.setAll(all);
Ref head = db.getRef(Constants.HEAD); Ref head = db.getRef(Constants.HEAD);
if (head == null) {
throw die(CLIText.get().onBranchToBeBorn);
}
RevCommit commit; RevCommit commit;
try { try {
commit = commitCmd.call(); commit = commitCmd.call();

10
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java

@ -120,7 +120,7 @@ class Merge extends TextBuiltin {
throw die(MessageFormat.format( throw die(MessageFormat.format(
CLIText.get().refDoesNotExistOrNoCommit, ref)); CLIText.get().refDoesNotExistOrNoCommit, ref));
Ref oldHead = db.getRef(Constants.HEAD); Ref oldHead = getOldHead();
MergeResult result; MergeResult result;
try (Git git = new Git(db)) { try (Git git = new Git(db)) {
MergeCommand mergeCmd = git.merge().setStrategy(mergeStrategy) MergeCommand mergeCmd = git.merge().setStrategy(mergeStrategy)
@ -205,6 +205,14 @@ class Merge extends TextBuiltin {
} }
} }
private Ref getOldHead() throws IOException {
Ref oldHead = db.getRef(Constants.HEAD);
if (oldHead == null) {
throw die(CLIText.get().onBranchToBeBorn);
}
return oldHead;
}
private boolean isMergedInto(Ref oldHead, AnyObjectId src) private boolean isMergedInto(Ref oldHead, AnyObjectId src)
throws IOException { throws IOException {
try (RevWalk revWalk = new RevWalk(db)) { try (RevWalk revWalk = new RevWalk(db)) {

4
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java

@ -82,6 +82,9 @@ class Push extends TextBuiltin {
@Option(name = "--all") @Option(name = "--all")
private boolean all; private boolean all;
@Option(name = "--atomic")
private boolean atomic;
@Option(name = "--tags") @Option(name = "--tags")
private boolean tags; private boolean tags;
@ -122,6 +125,7 @@ class Push extends TextBuiltin {
push.setPushTags(); push.setPushTags();
push.setRemote(remote); push.setRemote(remote);
push.setThin(thin); push.setThin(thin);
push.setAtomic(atomic);
push.setTimeout(timeout); push.setTimeout(timeout);
Iterable<PushResult> results = push.call(); Iterable<PushResult> results = push.call();
for (PushResult result : results) { for (PushResult result : results) {

197
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java

@ -0,0 +1,197 @@
/*
* Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* 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.pgm;
import java.io.IOException;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.RemoteAddCommand;
import org.eclipse.jgit.api.RemoteListCommand;
import org.eclipse.jgit.api.RemoteRemoveCommand;
import org.eclipse.jgit.api.RemoteSetUrlCommand;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.pgm.opt.CmdLineParser;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.io.ThrowingPrintWriter;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
@Command(common = false, usage = "usage_Remote")
class Remote extends TextBuiltin {
@Option(name = "--verbose", aliases = { "-v" }, usage = "usage_beVerbose")
private boolean verbose = false;
@Option(name = "--prune", aliases = {
"-p" }, usage = "usage_pruneStaleTrackingRefs")
private boolean prune;
@Option(name = "--push", usage = "usage_pushUrls")
private boolean push;
@Argument(index = 0, metaVar = "metaVar_command")
private String command;
@Argument(index = 1, metaVar = "metaVar_remoteName")
private String name;
@Argument(index = 2, metaVar = "metaVar_uriish")
private String uri;
@Override
protected void run() throws Exception {
try (Git git = new Git(db)) {
if (command == null) {
RemoteListCommand cmd = git.remoteList();
List<RemoteConfig> remotes = cmd.call();
print(remotes);
} else if ("add".equals(command)) { //$NON-NLS-1$
RemoteAddCommand cmd = git.remoteAdd();
cmd.setName(name);
cmd.setUri(new URIish(uri));
cmd.call();
} else if ("remove".equals(command) || "rm".equals(command)) { //$NON-NLS-1$ //$NON-NLS-2$
RemoteRemoveCommand cmd = git.remoteRemove();
cmd.setName(name);
cmd.call();
} else if ("set-url".equals(command)) { //$NON-NLS-1$
RemoteSetUrlCommand cmd = git.remoteSetUrl();
cmd.setName(name);
cmd.setUri(new URIish(uri));
cmd.setPush(push);
cmd.call();
} else if ("update".equals(command)) { //$NON-NLS-1$
// reuse fetch command for basic implementation of remote update
Fetch fetch = new Fetch();
fetch.init(db, gitdir);
// redirect the output stream
StringWriter osw = new StringWriter();
fetch.outw = new ThrowingPrintWriter(osw);
// redirect the error stream
StringWriter esw = new StringWriter();
fetch.errw = new ThrowingPrintWriter(esw);
List<String> fetchArgs = new ArrayList<>();
if (verbose) {
fetchArgs.add("--verbose"); //$NON-NLS-1$
}
if (prune) {
fetchArgs.add("--prune"); //$NON-NLS-1$
}
if (name != null) {
fetchArgs.add(name);
}
fetch.execute(fetchArgs.toArray(new String[fetchArgs.size()]));
// flush the streams
fetch.outw.flush();
fetch.errw.flush();
outw.println(osw.toString());
errw.println(esw.toString());
} else {
throw new JGitInternalException(MessageFormat
.format(CLIText.get().unknownSubcommand, command));
}
}
}
@Override
public void printUsageAndExit(final String message, final CmdLineParser clp)
throws IOException {
errw.println(message);
errw.println("jgit remote [--verbose (-v)] [--help (-h)]"); //$NON-NLS-1$
errw.println("jgit remote add name uri-ish [--help (-h)]"); //$NON-NLS-1$
errw.println("jgit remote remove name [--help (-h)]"); //$NON-NLS-1$
errw.println("jgit remote rm name [--help (-h)]"); //$NON-NLS-1$
errw.println(
"jgit remote [--verbose (-v)] update [name] [--prune (-p)] [--help (-h)]"); //$NON-NLS-1$
errw.println("jgit remote set-url name uri-ish [--push] [--help (-h)]"); //$NON-NLS-1$
errw.println();
clp.printUsage(errw, getResourceBundle());
errw.println();
errw.flush();
throw die(true);
}
private void print(List<RemoteConfig> remotes) throws IOException {
for (RemoteConfig remote : remotes) {
String remoteName = remote.getName();
if (verbose) {
List<URIish> fetchURIs = remote.getURIs();
List<URIish> pushURIs = remote.getPushURIs();
String fetchURI = ""; //$NON-NLS-1$
if (!fetchURIs.isEmpty()) {
fetchURI = fetchURIs.get(0).toString();
} else if (!pushURIs.isEmpty()) {
fetchURI = pushURIs.get(0).toString();
}
String pushURI = ""; //$NON-NLS-1$
if (!pushURIs.isEmpty()) {
pushURI = pushURIs.get(0).toString();
} else if (!fetchURIs.isEmpty()) {
pushURI = fetchURIs.get(0).toString();
}
outw.println(
String.format("%s\t%s (fetch)", remoteName, fetchURI)); //$NON-NLS-1$
outw.println(
String.format("%s\t%s (push)", remoteName, pushURI)); //$NON-NLS-1$
} else {
outw.println(remoteName);
}
}
}
}

18
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java

@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2009, Daniel Cheng (aka SDiZ) <git@sdiz.net> * Copyright (C) 2009, Daniel Cheng (aka SDiZ) <git@sdiz.net>
* Copyright (C) 2009, Daniel Cheng (aka SDiZ) <j16sdiz+freenet@gmail.com> * Copyright (C) 2009, Daniel Cheng (aka SDiZ) <j16sdiz+freenet@gmail.com>
* Copyright (C) 2015 Thomas Meyer <thomas@m3y3r.de>
* and other copyright owners as documented in the project's IP log. * and other copyright owners as documented in the project's IP log.
* *
* This program and the accompanying materials are made available * This program and the accompanying materials are made available
@ -51,14 +52,19 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.Option; import org.kohsuke.args4j.Option;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.pgm.internal.CLIText;;
@Command(usage = "usage_RevParse") @Command(usage = "usage_RevParse")
class RevParse extends TextBuiltin { class RevParse extends TextBuiltin {
@Option(name = "--all", usage = "usage_RevParseAll") @Option(name = "--all", usage = "usage_RevParseAll")
boolean all = false; boolean all;
@Option(name = "--verify", usage = "usage_RevParseVerify")
boolean verify;
@Argument(index = 0, metaVar = "metaVar_commitish") @Argument(index = 0, metaVar = "metaVar_commitish")
private final List<ObjectId> commits = new ArrayList<ObjectId>(); private final List<ObjectId> commits = new ArrayList<ObjectId>();
@ -67,11 +73,17 @@ class RevParse extends TextBuiltin {
protected void run() throws Exception { protected void run() throws Exception {
if (all) { if (all) {
Map<String, Ref> allRefs = db.getRefDatabase().getRefs(ALL); Map<String, Ref> allRefs = db.getRefDatabase().getRefs(ALL);
for (final Ref r : allRefs.values()) for (final Ref r : allRefs.values()) {
outw.println(r.getObjectId().name()); outw.println(r.getObjectId().name());
}
} else { } else {
for (final ObjectId o : commits) if (verify && commits.size() > 1) {
throw new CmdLineException(CLIText.get().needSingleRevision);
}
for (final ObjectId o : commits) {
outw.println(o.name()); outw.println(o.name());
} }
} }
}
} }

7
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java

@ -242,9 +242,10 @@ class DiffAlgorithms extends TextBuiltin {
} }
}); });
if (db.getDirectory() != null) { File directory = db.getDirectory();
String name = db.getDirectory().getName(); if (directory != null) {
File parent = db.getDirectory().getParentFile(); String name = directory.getName();
File parent = directory.getParentFile();
if (name.equals(Constants.DOT_GIT) && parent != null) if (name.equals(Constants.DOT_GIT) && parent != null)
name = parent.getName(); name = parent.getName();
outw.println(name + ": start at " + startId.name()); outw.println(name + ": start at " + startId.name());

5
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java

@ -117,9 +117,12 @@ class RebuildCommitGraph extends TextBuiltin {
@Override @Override
protected void run() throws Exception { protected void run() throws Exception {
if (!really && !db.getRefDatabase().getRefs(ALL).isEmpty()) { if (!really && !db.getRefDatabase().getRefs(ALL).isEmpty()) {
File directory = db.getDirectory();
String absolutePath = directory == null ? "null" //$NON-NLS-1$
: directory.getAbsolutePath();
errw.println( errw.println(
MessageFormat.format(CLIText.get().fatalThisProgramWillDestroyTheRepository MessageFormat.format(CLIText.get().fatalThisProgramWillDestroyTheRepository
, db.getDirectory().getAbsolutePath(), REALLY)); , absolutePath, REALLY));
throw die(CLIText.get().needApprovalToDestroyCurrentRepository); throw die(CLIText.get().needApprovalToDestroyCurrentRepository);
} }
if (!refList.isFile()) if (!refList.isFile())

7
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java

@ -341,9 +341,10 @@ class TextHashFunctions extends TextBuiltin {
} }
} }
if (db.getDirectory() != null) { File directory = db.getDirectory();
String name = db.getDirectory().getName(); if (directory != null) {
File parent = db.getDirectory().getParentFile(); String name = directory.getName();
File parent = directory.getParentFile();
if (name.equals(Constants.DOT_GIT) && parent != null) if (name.equals(Constants.DOT_GIT) && parent != null)
name = parent.getName(); name = parent.getName();
outw.println(name + ":"); //$NON-NLS-1$ outw.println(name + ":"); //$NON-NLS-1$

3
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java

@ -187,6 +187,7 @@ public class CLIText extends TranslationBundle {
/***/ public String metaVar_version; /***/ public String metaVar_version;
/***/ public String mostCommonlyUsedCommandsAre; /***/ public String mostCommonlyUsedCommandsAre;
/***/ public String needApprovalToDestroyCurrentRepository; /***/ public String needApprovalToDestroyCurrentRepository;
/***/ public String needSingleRevision;
/***/ public String noGitRepositoryConfigured; /***/ public String noGitRepositoryConfigured;
/***/ public String noNamesFound; /***/ public String noNamesFound;
/***/ public String noSuchFile; /***/ public String noSuchFile;
@ -201,6 +202,7 @@ public class CLIText extends TranslationBundle {
/***/ public String notARevision; /***/ public String notARevision;
/***/ public String notATree; /***/ public String notATree;
/***/ public String notAValidRefName; /***/ public String notAValidRefName;
/***/ public String notAValidCommitName;
/***/ public String notAnIndexFile; /***/ public String notAnIndexFile;
/***/ public String notAnObject; /***/ public String notAnObject;
/***/ public String notFound; /***/ public String notFound;
@ -245,6 +247,7 @@ public class CLIText extends TranslationBundle {
/***/ public String treeIsRequired; /***/ public String treeIsRequired;
/***/ public char[] unknownIoErrorStdout; /***/ public char[] unknownIoErrorStdout;
/***/ public String unknownMergeStrategy; /***/ public String unknownMergeStrategy;
/***/ public String unknownSubcommand;
/***/ public String unmergedPaths; /***/ public String unmergedPaths;
/***/ public String unsupportedOperation; /***/ public String unsupportedOperation;
/***/ public String untrackedFiles; /***/ public String untrackedFiles;

1
org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 7).launch

@ -18,7 +18,6 @@
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH"> <listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;org.eclipse.jgit.test&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;org.eclipse.jgit.test&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;org.eclipse.jgit.java7&quot; type=&quot;1&quot;/&gt;&#10;"/>
</listAttribute> </listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/> <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>

1
org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 8).launch

@ -19,7 +19,6 @@
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH"> <listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;org.eclipse.jgit.test&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;org.eclipse.jgit.test&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;org.eclipse.jgit.java7&quot; type=&quot;1&quot;/&gt;&#10;"/>
</listAttribute> </listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>

96
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AbstractRemoteCommandTest.java

@ -0,0 +1,96 @@
/*
* Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* 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.api;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.net.URISyntaxException;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
public class AbstractRemoteCommandTest extends RepositoryTestCase {
protected static final String REMOTE_NAME = "test";
protected RemoteConfig setupRemote()
throws IOException, URISyntaxException {
// create another repository
Repository remoteRepository = createWorkRepository();
// set it up as a remote to this repository
final StoredConfig config = db.getConfig();
RemoteConfig remoteConfig = new RemoteConfig(config, REMOTE_NAME);
RefSpec refSpec = new RefSpec();
refSpec = refSpec.setForceUpdate(true);
refSpec = refSpec.setSourceDestination(Constants.R_HEADS + "*",
Constants.R_REMOTES + REMOTE_NAME + "/*");
remoteConfig.addFetchRefSpec(refSpec);
URIish uri = new URIish(
remoteRepository.getDirectory().toURI().toURL());
remoteConfig.addURI(uri);
remoteConfig.update(config);
config.save();
return remoteConfig;
}
protected void assertRemoteConfigEquals(RemoteConfig expected,
RemoteConfig actual) {
assertEquals(expected.getName(), actual.getName());
assertEquals(expected.getURIs(), actual.getURIs());
assertEquals(expected.getPushURIs(), actual.getPushURIs());
assertEquals(expected.getFetchRefSpecs(), actual.getFetchRefSpecs());
assertEquals(expected.getPushRefSpecs(), actual.getPushRefSpecs());
}
}

188
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java

@ -45,6 +45,7 @@ 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 static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.io.File; import java.io.File;
@ -52,11 +53,13 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import org.eclipse.jgit.api.errors.FilterFailedException;
import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.NoFilepatternException; import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
@ -111,6 +114,191 @@ public class AddCommandTest extends RepositoryTestCase {
indexState(CONTENT)); indexState(CONTENT));
} }
@Test
public void testCleanFilter() throws IOException,
GitAPIException {
writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
writeTrashFile("src/a.tmp", "foo");
// Caution: we need a trailing '\n' since sed on mac always appends
// linefeeds if missing
writeTrashFile("src/a.txt", "foo\n");
File script = writeTempFile("sed s/o/e/g");
Git git = new Git(db);
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "tstFilter", "clean",
"sh " + slashify(script.getPath()));
config.save();
git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp")
.call();
assertEquals(
"[src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:fee\n]",
indexState(CONTENT));
}
@Test
public void testCleanFilterEnvironment()
throws IOException, GitAPIException {
writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
writeTrashFile("src/a.txt", "foo");
File script = writeTempFile("echo $GIT_DIR; echo 1 >xyz");
Git git = new Git(db);
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "tstFilter", "clean",
"sh " + slashify(script.getPath()));
config.save();
git.add().addFilepattern("src/a.txt").call();
String gitDir = db.getDirectory().getAbsolutePath();
assertEquals("[src/a.txt, mode:100644, content:" + gitDir
+ "\n]", indexState(CONTENT));
assertTrue(new File(db.getWorkTree(), "xyz").exists());
}
@Test
public void testMultipleCleanFilter() throws IOException, GitAPIException {
writeTrashFile(".gitattributes",
"*.txt filter=tstFilter\n*.tmp filter=tstFilter2");
// Caution: we need a trailing '\n' since sed on mac always appends
// linefeeds if missing
writeTrashFile("src/a.tmp", "foo\n");
writeTrashFile("src/a.txt", "foo\n");
File script = writeTempFile("sed s/o/e/g");
File script2 = writeTempFile("sed s/f/x/g");
Git git = new Git(db);
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "tstFilter", "clean",
"sh " + slashify(script.getPath()));
config.setString("filter", "tstFilter2", "clean",
"sh " + slashify(script2.getPath()));
config.save();
git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp")
.call();
assertEquals(
"[src/a.tmp, mode:100644, content:xoo\n][src/a.txt, mode:100644, content:fee\n]",
indexState(CONTENT));
// TODO: multiple clean filters for one file???
}
/**
* The path of an added file name contains ';' and afterwards malicious
* commands. Make sure when calling filter commands to properly escape the
* filenames
*
* @throws IOException
* @throws GitAPIException
*/
@Test
public void testCommandInjection() throws IOException, GitAPIException {
// Caution: we need a trailing '\n' since sed on mac always appends
// linefeeds if missing
writeTrashFile("; echo virus", "foo\n");
File script = writeTempFile("sed s/o/e/g");
Git git = new Git(db);
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "tstFilter", "clean",
"sh " + slashify(script.getPath()) + " %f");
writeTrashFile(".gitattributes", "* filter=tstFilter");
git.add().addFilepattern("; echo virus").call();
// Without proper escaping the content would be "feovirus". The sed
// command and the "echo virus" would contribute to the content
assertEquals("[; echo virus, mode:100644, content:fee\n]",
indexState(CONTENT));
}
@Test
public void testBadCleanFilter() throws IOException, GitAPIException {
writeTrashFile("a.txt", "foo");
File script = writeTempFile("sedfoo s/o/e/g");
Git git = new Git(db);
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "tstFilter", "clean",
"sh " + script.getPath());
config.save();
writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
try {
git.add().addFilepattern("a.txt").call();
fail("Didn't received the expected exception");
} catch (FilterFailedException e) {
assertEquals(127, e.getReturnCode());
}
}
@Test
public void testBadCleanFilter2() throws IOException, GitAPIException {
writeTrashFile("a.txt", "foo");
File script = writeTempFile("sed s/o/e/g");
Git git = new Git(db);
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "tstFilter", "clean",
"shfoo " + script.getPath());
config.save();
writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
try {
git.add().addFilepattern("a.txt").call();
fail("Didn't received the expected exception");
} catch (FilterFailedException e) {
assertEquals(127, e.getReturnCode());
}
}
@Test
public void testCleanFilterReturning12() throws IOException,
GitAPIException {
writeTrashFile("a.txt", "foo");
File script = writeTempFile("exit 12");
Git git = new Git(db);
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "tstFilter", "clean",
"sh " + slashify(script.getPath()));
config.save();
writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
try {
git.add().addFilepattern("a.txt").call();
fail("Didn't received the expected exception");
} catch (FilterFailedException e) {
assertEquals(12, e.getReturnCode());
}
}
@Test
public void testNotApplicableFilter() throws IOException, GitAPIException {
writeTrashFile("a.txt", "foo");
File script = writeTempFile("sed s/o/e/g");
Git git = new Git(db);
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "tstFilter", "something",
"sh " + script.getPath());
config.save();
writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
git.add().addFilepattern("a.txt").call();
assertEquals("[a.txt, mode:100644, content:foo]", indexState(CONTENT));
}
private File writeTempFile(String body) throws IOException {
File f = File.createTempFile("AddCommandTest_", "");
JGitTestUtil.write(f, body);
return f;
}
@Test @Test
public void testAddExistingSingleSmallFileWithNewLine() throws IOException, public void testAddExistingSingleSmallFileWithNewLine() throws IOException,
GitAPIException { GitAPIException {

136
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java

@ -43,6 +43,8 @@
*/ */
package org.eclipse.jgit.api; package org.eclipse.jgit.api;
import static org.eclipse.jgit.lib.Constants.MASTER;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -70,12 +72,14 @@ import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.api.errors.TransportException; import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.Sets;
import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.storage.file.FileBasedConfig;
@ -84,6 +88,7 @@ import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.FileUtils;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
public class CheckoutCommandTest extends RepositoryTestCase { public class CheckoutCommandTest extends RepositoryTestCase {
@ -134,7 +139,7 @@ public class CheckoutCommandTest extends RepositoryTestCase {
@Test @Test
public void testCreateBranchOnCheckout() throws Exception { public void testCreateBranchOnCheckout() throws Exception {
git.checkout().setCreateBranch(true).setName("test2").call(); git.checkout().setCreateBranch(true).setName("test2").call();
assertNotNull(db.getRef("test2")); assertNotNull(db.exactRef("refs/heads/test2"));
} }
@Test @Test
@ -237,8 +242,8 @@ public class CheckoutCommandTest extends RepositoryTestCase {
.setStartPoint("origin/test") .setStartPoint("origin/test")
.setUpstreamMode(SetupUpstreamMode.TRACK).call(); .setUpstreamMode(SetupUpstreamMode.TRACK).call();
assertEquals("refs/heads/test", db2.getRef(Constants.HEAD).getTarget() assertEquals("refs/heads/test",
.getName()); db2.exactRef(Constants.HEAD).getTarget().getName());
StoredConfig config = db2.getConfig(); StoredConfig config = db2.getConfig();
assertEquals("origin", config.getString( assertEquals("origin", config.getString(
ConfigConstants.CONFIG_BRANCH_SECTION, "test", ConfigConstants.CONFIG_BRANCH_SECTION, "test",
@ -345,7 +350,7 @@ public class CheckoutCommandTest extends RepositoryTestCase {
CheckoutCommand co = git.checkout(); CheckoutCommand co = git.checkout();
co.setName("master").call(); co.setName("master").call();
String commitId = db.getRef(Constants.MASTER).getObjectId().name(); String commitId = db.exactRef(R_HEADS + MASTER).getObjectId().name();
co = git.checkout(); co = git.checkout();
co.setName(commitId).call(); co.setName(commitId).call();
@ -443,7 +448,7 @@ public class CheckoutCommandTest extends RepositoryTestCase {
} }
private void assertHeadDetached() throws IOException { private void assertHeadDetached() throws IOException {
Ref head = db.getRef(Constants.HEAD); Ref head = db.exactRef(Constants.HEAD);
assertFalse(head.isSymbolic()); assertFalse(head.isSymbolic());
assertSame(head, head.getTarget()); assertSame(head, head.getTarget());
} }
@ -554,4 +559,125 @@ public class CheckoutCommandTest extends RepositoryTestCase {
} }
org.junit.Assume.assumeTrue(foundUnsmudged); org.junit.Assume.assumeTrue(foundUnsmudged);
} }
@Test
public void testSmudgeFilter_modifyExisting() throws IOException, GitAPIException {
File script = writeTempFile("sed s/o/e/g");
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "tstFilter", "smudge",
"sh " + slashify(script.getPath()));
config.save();
writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
git.add().addFilepattern(".gitattributes").call();
git.commit().setMessage("add filter").call();
writeTrashFile("src/a.tmp", "x");
// Caution: we need a trailing '\n' since sed on mac always appends
// linefeeds if missing
writeTrashFile("src/a.txt", "x\n");
git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
.call();
RevCommit content1 = git.commit().setMessage("add content").call();
writeTrashFile("src/a.tmp", "foo");
writeTrashFile("src/a.txt", "foo\n");
git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
.call();
RevCommit content2 = git.commit().setMessage("changed content").call();
git.checkout().setName(content1.getName()).call();
git.checkout().setName(content2.getName()).call();
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
indexState(CONTENT));
assertEquals(Sets.of("src/a.txt"), git.status().call().getModified());
assertEquals("foo", read("src/a.tmp"));
assertEquals("fee\n", read("src/a.txt"));
}
@Test
public void testSmudgeFilter_createNew()
throws IOException, GitAPIException {
File script = writeTempFile("sed s/o/e/g");
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "tstFilter", "smudge",
"sh " + slashify(script.getPath()));
config.save();
writeTrashFile("foo", "foo");
git.add().addFilepattern("foo").call();
RevCommit initial = git.commit().setMessage("initial").call();
writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
git.add().addFilepattern(".gitattributes").call();
git.commit().setMessage("add filter").call();
writeTrashFile("src/a.tmp", "foo");
// Caution: we need a trailing '\n' since sed on mac always appends
// linefeeds if missing
writeTrashFile("src/a.txt", "foo\n");
git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
.call();
RevCommit content = git.commit().setMessage("added content").call();
git.checkout().setName(initial.getName()).call();
git.checkout().setName(content.getName()).call();
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
indexState(CONTENT));
assertEquals("foo", read("src/a.tmp"));
assertEquals("fee\n", read("src/a.txt"));
}
@Test
@Ignore
public void testSmudgeAndClean() throws IOException, GitAPIException {
// @TODO: fix this test
File clean_filter = writeTempFile("sed s/V1/@version/g -");
File smudge_filter = writeTempFile("sed s/@version/V1/g -");
Git git = new Git(db);
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "tstFilter", "smudge",
"sh " + slashify(smudge_filter.getPath()));
config.setString("filter", "tstFilter", "clean",
"sh " + slashify(clean_filter.getPath()));
config.save();
writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
git.add().addFilepattern(".gitattributes").call();
git.commit().setMessage("add attributes").call();
writeTrashFile("filterTest.txt", "hello world, V1");
git.add().addFilepattern("filterTest.txt").call();
git.commit().setMessage("add filterText.txt").call();
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some other change][filterTest.txt, mode:100644, content:hello world, @version]",
indexState(CONTENT));
git.checkout().setCreateBranch(true).setName("test2").call();
writeTrashFile("filterTest.txt", "bon giorno world, V1");
git.add().addFilepattern("filterTest.txt").call();
git.commit().setMessage("modified filterText.txt").call();
assertTrue(git.status().call().isClean());
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some other change][filterTest.txt, mode:100644, content:bon giorno world, @version]",
indexState(CONTENT));
git.checkout().setName("refs/heads/test").call();
assertTrue(git.status().call().isClean());
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some other change][filterTest.txt, mode:100644, content:hello world, @version]",
indexState(CONTENT));
assertEquals("hello world, V1", read("filterTest.txt"));
}
private File writeTempFile(String body) throws IOException {
File f = File.createTempFile("AddCommandTest_", "");
JGitTestUtil.write(f, body);
return f;
}
} }

6
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java

@ -408,8 +408,10 @@ public class CommitCommandTest extends RepositoryTestCase {
checkoutBranch("refs/heads/master"); checkoutBranch("refs/heads/master");
MergeResult result = git.merge().include(db.getRef("branch1")) MergeResult result = git.merge()
.setSquash(true).call(); .include(db.exactRef("refs/heads/branch1"))
.setSquash(true)
.call();
assertTrue(new File(db.getWorkTree(), "file1").exists()); assertTrue(new File(db.getWorkTree(), "file1").exists());
assertTrue(new File(db.getWorkTree(), "file2").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists());

54
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java

@ -43,6 +43,8 @@
*/ */
package org.eclipse.jgit.api; package org.eclipse.jgit.api;
import static org.eclipse.jgit.lib.Constants.MASTER;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
@ -97,7 +99,7 @@ public class MergeCommandTest extends RepositoryTestCase {
Git git = new Git(db); Git git = new Git(db);
git.commit().setMessage("initial commit").call(); git.commit().setMessage("initial commit").call();
MergeResult result = git.merge().include(db.getRef(Constants.HEAD)).call(); MergeResult result = git.merge().include(db.exactRef(Constants.HEAD)).call();
assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus()); assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus());
// no reflog entry written by merge // no reflog entry written by merge
assertEquals("commit (initial): initial commit", assertEquals("commit (initial): initial commit",
@ -115,7 +117,7 @@ public class MergeCommandTest extends RepositoryTestCase {
createBranch(first, "refs/heads/branch1"); createBranch(first, "refs/heads/branch1");
RevCommit second = git.commit().setMessage("second commit").call(); RevCommit second = git.commit().setMessage("second commit").call();
MergeResult result = git.merge().include(db.getRef("refs/heads/branch1")).call(); MergeResult result = git.merge().include(db.exactRef("refs/heads/branch1")).call();
assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus()); assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus());
assertEquals(second, result.getNewHead()); assertEquals(second, result.getNewHead());
// no reflog entry written by merge // no reflog entry written by merge
@ -135,7 +137,7 @@ public class MergeCommandTest extends RepositoryTestCase {
checkoutBranch("refs/heads/branch1"); checkoutBranch("refs/heads/branch1");
MergeResult result = git.merge().include(db.getRef(Constants.MASTER)).call(); MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)).call();
assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus()); assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus());
assertEquals(second, result.getNewHead()); assertEquals(second, result.getNewHead());
@ -155,7 +157,7 @@ public class MergeCommandTest extends RepositoryTestCase {
checkoutBranch("refs/heads/branch1"); checkoutBranch("refs/heads/branch1");
MergeResult result = git.merge().include(db.getRef(Constants.MASTER)) MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER))
.setCommit(false).call(); .setCommit(false).call();
assertEquals(MergeResult.MergeStatus.FAST_FORWARD, assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
@ -186,7 +188,7 @@ public class MergeCommandTest extends RepositoryTestCase {
checkoutBranch("refs/heads/branch1"); checkoutBranch("refs/heads/branch1");
assertFalse(new File(db.getWorkTree(), "file2").exists()); assertFalse(new File(db.getWorkTree(), "file2").exists());
MergeResult result = git.merge().include(db.getRef(Constants.MASTER)).call(); MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)).call();
assertTrue(new File(db.getWorkTree(), "file1").exists()); assertTrue(new File(db.getWorkTree(), "file1").exists());
assertTrue(new File(db.getWorkTree(), "file2").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists());
@ -221,7 +223,7 @@ public class MergeCommandTest extends RepositoryTestCase {
MergeCommand merge = git.merge(); MergeCommand merge = git.merge();
merge.include(second.getId()); merge.include(second.getId());
merge.include(db.getRef(Constants.MASTER)); merge.include(db.exactRef(R_HEADS + MASTER));
try { try {
merge.call(); merge.call();
fail("Expected exception not thrown when merging multiple heads"); fail("Expected exception not thrown when merging multiple heads");
@ -248,7 +250,7 @@ public class MergeCommandTest extends RepositoryTestCase {
git.commit().setMessage("third").call(); git.commit().setMessage("third").call();
MergeResult result = git.merge().setStrategy(mergeStrategy) MergeResult result = git.merge().setStrategy(mergeStrategy)
.include(db.getRef(Constants.MASTER)).call(); .include(db.exactRef(R_HEADS + MASTER)).call();
assertEquals(MergeStatus.MERGED, result.getMergeStatus()); assertEquals(MergeStatus.MERGED, result.getMergeStatus());
assertEquals( assertEquals(
"merge refs/heads/master: Merge made by " "merge refs/heads/master: Merge made by "
@ -279,9 +281,9 @@ public class MergeCommandTest extends RepositoryTestCase {
MergeResult result = git.merge().setStrategy(mergeStrategy) MergeResult result = git.merge().setStrategy(mergeStrategy)
.setCommit(false) .setCommit(false)
.include(db.getRef(Constants.MASTER)).call(); .include(db.exactRef(R_HEADS + MASTER)).call();
assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
assertEquals(db.getRef(Constants.HEAD).getTarget().getObjectId(), assertEquals(db.exactRef(Constants.HEAD).getTarget().getObjectId(),
thirdCommit.getId()); thirdCommit.getId());
} }
@ -378,7 +380,7 @@ public class MergeCommandTest extends RepositoryTestCase {
git.add().addFilepattern("a").call(); git.add().addFilepattern("a").call();
git.commit().setMessage("main").call(); git.commit().setMessage("main").call();
Ref sideBranch = db.getRef("side"); Ref sideBranch = db.exactRef("refs/heads/side");
git.merge().include(sideBranch) git.merge().include(sideBranch)
.setStrategy(MergeStrategy.RESOLVE).call(); .setStrategy(MergeStrategy.RESOLVE).call();
@ -590,7 +592,7 @@ public class MergeCommandTest extends RepositoryTestCase {
.setCommit(false) .setCommit(false)
.setStrategy(MergeStrategy.RESOLVE).call(); .setStrategy(MergeStrategy.RESOLVE).call();
assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
assertEquals(db.getRef(Constants.HEAD).getTarget().getObjectId(), assertEquals(db.exactRef(Constants.HEAD).getTarget().getObjectId(),
thirdCommit.getId()); thirdCommit.getId());
assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(), assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
@ -1310,8 +1312,10 @@ public class MergeCommandTest extends RepositoryTestCase {
assertFalse(new File(db.getWorkTree(), "file2").exists()); assertFalse(new File(db.getWorkTree(), "file2").exists());
assertFalse(new File(db.getWorkTree(), "file3").exists()); assertFalse(new File(db.getWorkTree(), "file3").exists());
MergeResult result = git.merge().include(db.getRef("branch1")) MergeResult result = git.merge()
.setSquash(true).call(); .include(db.exactRef("refs/heads/branch1"))
.setSquash(true)
.call();
assertTrue(new File(db.getWorkTree(), "file1").exists()); assertTrue(new File(db.getWorkTree(), "file1").exists());
assertTrue(new File(db.getWorkTree(), "file2").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists());
@ -1375,8 +1379,10 @@ public class MergeCommandTest extends RepositoryTestCase {
assertTrue(new File(db.getWorkTree(), "file2").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists());
assertFalse(new File(db.getWorkTree(), "file3").exists()); assertFalse(new File(db.getWorkTree(), "file3").exists());
MergeResult result = git.merge().include(db.getRef("branch1")) MergeResult result = git.merge()
.setSquash(true).call(); .include(db.exactRef("refs/heads/branch1"))
.setSquash(true)
.call();
assertTrue(new File(db.getWorkTree(), "file1").exists()); assertTrue(new File(db.getWorkTree(), "file1").exists());
assertTrue(new File(db.getWorkTree(), "file2").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists());
@ -1430,8 +1436,10 @@ public class MergeCommandTest extends RepositoryTestCase {
assertTrue(new File(db.getWorkTree(), "file1").exists()); assertTrue(new File(db.getWorkTree(), "file1").exists());
assertTrue(new File(db.getWorkTree(), "file2").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists());
MergeResult result = git.merge().include(db.getRef("branch1")) MergeResult result = git.merge()
.setSquash(true).call(); .include(db.exactRef("refs/heads/branch1"))
.setSquash(true)
.call();
assertTrue(new File(db.getWorkTree(), "file1").exists()); assertTrue(new File(db.getWorkTree(), "file1").exists());
assertTrue(new File(db.getWorkTree(), "file2").exists()); assertTrue(new File(db.getWorkTree(), "file2").exists());
@ -1468,7 +1476,7 @@ public class MergeCommandTest extends RepositoryTestCase {
MergeCommand merge = git.merge(); MergeCommand merge = git.merge();
merge.setFastForward(FastForwardMode.FF_ONLY); merge.setFastForward(FastForwardMode.FF_ONLY);
merge.include(db.getRef(Constants.MASTER)); merge.include(db.exactRef(R_HEADS + MASTER));
MergeResult result = merge.call(); MergeResult result = merge.call();
assertEquals(MergeStatus.FAST_FORWARD, result.getMergeStatus()); assertEquals(MergeStatus.FAST_FORWARD, result.getMergeStatus());
@ -1485,7 +1493,7 @@ public class MergeCommandTest extends RepositoryTestCase {
MergeCommand merge = git.merge(); MergeCommand merge = git.merge();
merge.setFastForward(FastForwardMode.NO_FF); merge.setFastForward(FastForwardMode.NO_FF);
merge.include(db.getRef(Constants.MASTER)); merge.include(db.exactRef(R_HEADS + MASTER));
MergeResult result = merge.call(); MergeResult result = merge.call();
assertEquals(MergeStatus.MERGED, result.getMergeStatus()); assertEquals(MergeStatus.MERGED, result.getMergeStatus());
@ -1505,7 +1513,7 @@ public class MergeCommandTest extends RepositoryTestCase {
// when // when
MergeCommand merge = git.merge(); MergeCommand merge = git.merge();
merge.setFastForward(FastForwardMode.NO_FF); merge.setFastForward(FastForwardMode.NO_FF);
merge.include(db.getRef(Constants.MASTER)); merge.include(db.exactRef(R_HEADS + MASTER));
merge.setCommit(false); merge.setCommit(false);
MergeResult result = merge.call(); MergeResult result = merge.call();
@ -1531,7 +1539,7 @@ public class MergeCommandTest extends RepositoryTestCase {
git.commit().setMessage("second commit on branch1").call(); git.commit().setMessage("second commit on branch1").call();
MergeCommand merge = git.merge(); MergeCommand merge = git.merge();
merge.setFastForward(FastForwardMode.FF_ONLY); merge.setFastForward(FastForwardMode.FF_ONLY);
merge.include(db.getRef(Constants.MASTER)); merge.include(db.exactRef(R_HEADS + MASTER));
MergeResult result = merge.call(); MergeResult result = merge.call();
assertEquals(MergeStatus.ABORTED, result.getMergeStatus()); assertEquals(MergeStatus.ABORTED, result.getMergeStatus());
@ -1588,7 +1596,7 @@ public class MergeCommandTest extends RepositoryTestCase {
git.add().addFilepattern("c").call(); git.add().addFilepattern("c").call();
git.commit().setMessage("main").call(); git.commit().setMessage("main").call();
Ref sideBranch = db.getRef("side"); Ref sideBranch = db.exactRef("refs/heads/side");
git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
.setMessage("user message").call(); .setMessage("user message").call();
@ -1621,7 +1629,7 @@ public class MergeCommandTest extends RepositoryTestCase {
git.add().addFilepattern("a").call(); git.add().addFilepattern("a").call();
git.commit().setMessage("main").call(); git.commit().setMessage("main").call();
Ref sideBranch = db.getRef("side"); Ref sideBranch = db.exactRef("refs/heads/side");
git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
.setMessage("user message").call(); .setMessage("user message").call();

4
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NameRevCommandTest.java

@ -95,9 +95,9 @@ public class NameRevCommandTest extends RepositoryTestCase {
tr.update("refs/heads/master", c); tr.update("refs/heads/master", c);
tr.update("refs/tags/tag", c); tr.update("refs/tags/tag", c);
assertOneResult("master", assertOneResult("master",
git.nameRev().addRef(db.getRef("refs/heads/master")), c); git.nameRev().addRef(db.exactRef("refs/heads/master")), c);
assertOneResult("tag", assertOneResult("tag",
git.nameRev().addRef(db.getRef("refs/tags/tag")), c); git.nameRev().addRef(db.exactRef("refs/tags/tag")), c);
} }
@Test @Test

8
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java

@ -138,11 +138,9 @@ public class PushCommandTest extends RepositoryTestCase {
RefSpec spec = new RefSpec("refs/heads/master:refs/heads/x"); RefSpec spec = new RefSpec("refs/heads/master:refs/heads/x");
git1.push().setRemote("test").setRefSpecs(spec).call(); git1.push().setRemote("test").setRefSpecs(spec).call();
assertEquals( assertEquals("1:test, 2:" + uri + ", 3:\n" + "refs/heads/master "
"1:test, 2:file://" + db2.getDirectory().toPath() // + commit.getName() + " refs/heads/x "
+ "/, 3:\n" + "refs/heads/master " + commit.getName() + ObjectId.zeroId().name(), read(hookOutput));
+ " refs/heads/x " + ObjectId.zeroId().name(),
read(hookOutput));
} }
private File writeHookFile(final String name, final String data) private File writeHookFile(final String name, final String data)

81
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteAddCommandTest.java

@ -0,0 +1,81 @@
/*
* Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* 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.api;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import org.junit.Test;
public class RemoteAddCommandTest extends AbstractRemoteCommandTest {
@Test
public void testAdd() throws Exception {
// create another repository
Repository remoteRepository = createWorkRepository();
URIish uri = new URIish(
remoteRepository.getDirectory().toURI().toURL());
// execute the command to add a new remote
RemoteAddCommand cmd = Git.wrap(db).remoteAdd();
cmd.setName(REMOTE_NAME);
cmd.setUri(uri);
RemoteConfig remote = cmd.call();
// assert that the added remote represents the remote repository
assertEquals(REMOTE_NAME, remote.getName());
assertArrayEquals(new URIish[] { uri }, remote.getURIs().toArray());
assertEquals(1, remote.getFetchRefSpecs().size());
assertEquals(
String.format("+refs/heads/*:refs/remotes/%s/*", REMOTE_NAME),
remote.getFetchRefSpecs().get(0).toString());
// assert that the added remote is available in the git configuration
assertRemoteConfigEquals(remote,
new RemoteConfig(db.getConfig(), REMOTE_NAME));
}
}

68
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java

@ -0,0 +1,68 @@
/*
* Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* 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.api;
import static org.junit.Assert.assertTrue;
import org.eclipse.jgit.transport.RemoteConfig;
import org.junit.Test;
public class RemoteDeleteCommandTest extends AbstractRemoteCommandTest {
@Test
public void testDelete() throws Exception {
// setup an initial remote
RemoteConfig remoteConfig = setupRemote();
// execute the command to remove the remote
RemoteRemoveCommand cmd = Git.wrap(db).remoteRemove();
cmd.setName(REMOTE_NAME);
RemoteConfig remote = cmd.call();
// assert that the removed remote is the initial remote
assertRemoteConfigEquals(remoteConfig, remote);
// assert that there are no remotes left
assertTrue(RemoteConfig.getAllRemoteConfigs(db.getConfig()).isEmpty());
}
}

68
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteListCommandTest.java

@ -0,0 +1,68 @@
/*
* Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* 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.api;
import static org.junit.Assert.assertEquals;
import java.util.List;
import org.eclipse.jgit.transport.RemoteConfig;
import org.junit.Test;
public class RemoteListCommandTest extends AbstractRemoteCommandTest {
@Test
public void testList() throws Exception {
// setup an initial remote
RemoteConfig remoteConfig = setupRemote();
// execute the command to list the remotes
List<RemoteConfig> remotes = Git.wrap(db).remoteList().call();
// assert that there is only one remote
assertEquals(1, remotes.size());
// assert that the available remote is the initial remote
assertRemoteConfigEquals(remoteConfig, remotes.get(0));
}
}

100
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java

@ -0,0 +1,100 @@
/*
* Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* 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.api;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import org.junit.Test;
public class RemoteSetUrlCommandTest extends AbstractRemoteCommandTest {
@Test
public void testSetUrl() throws Exception {
// setup an initial remote
setupRemote();
// execute the command to change the fetch url
RemoteSetUrlCommand cmd = Git.wrap(db).remoteSetUrl();
cmd.setName(REMOTE_NAME);
URIish newUri = new URIish("git://test.com/test");
cmd.setUri(newUri);
RemoteConfig remote = cmd.call();
// assert that the changed remote has the new fetch url
assertEquals(REMOTE_NAME, remote.getName());
assertArrayEquals(new URIish[] { newUri }, remote.getURIs().toArray());
// assert that the changed remote is available in the git configuration
assertRemoteConfigEquals(remote,
new RemoteConfig(db.getConfig(), REMOTE_NAME));
}
@Test
public void testSetPushUrl() throws Exception {
// setup an initial remote
RemoteConfig remoteConfig = setupRemote();
// execute the command to change the push url
RemoteSetUrlCommand cmd = Git.wrap(db).remoteSetUrl();
cmd.setName(REMOTE_NAME);
URIish newUri = new URIish("git://test.com/test");
cmd.setUri(newUri);
cmd.setPush(true);
RemoteConfig remote = cmd.call();
// assert that the changed remote has the old fetch url and the new push
// url
assertEquals(REMOTE_NAME, remote.getName());
assertEquals(remoteConfig.getURIs(), remote.getURIs());
assertArrayEquals(new URIish[] { newUri },
remote.getPushURIs().toArray());
// assert that the changed remote is available in the git configuration
assertRemoteConfigEquals(remote,
new RemoteConfig(db.getConfig(), REMOTE_NAME));
}
}

6
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java

@ -477,8 +477,10 @@ public class ResetCommandTest extends RepositoryTestCase {
checkoutBranch("refs/heads/master"); checkoutBranch("refs/heads/master");
MergeResult result = g.merge().include(db.getRef("branch1")) MergeResult result = g.merge()
.setSquash(true).call(); .include(db.exactRef("refs/heads/branch1"))
.setSquash(true)
.call();
assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED, assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
result.getMergeStatus()); result.getMergeStatus());

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java

@ -110,7 +110,7 @@ public class StashCreateCommandTest extends RepositoryTestCase {
int parentCount) int parentCount)
throws IOException { throws IOException {
assertNotNull(commit); assertNotNull(commit);
Ref stashRef = db.getRef(Constants.R_STASH); Ref stashRef = db.exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(commit, stashRef.getObjectId()); assertEquals(commit, stashRef.getObjectId());
assertNotNull(commit.getAuthorIdent()); assertNotNull(commit.getAuthorIdent());

102
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java

@ -96,13 +96,13 @@ public class StashDropCommandTest extends RepositoryTestCase {
@Test @Test
public void dropWithInvalidLogIndex() throws Exception { public void dropWithInvalidLogIndex() throws Exception {
write(committedFile, "content2"); write(committedFile, "content2");
Ref stashRef = git.getRepository().getRef(Constants.R_STASH); Ref stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef); assertNull(stashRef);
RevCommit stashed = git.stashCreate().call(); RevCommit stashed = git.stashCreate().call();
assertNotNull(stashed); assertNotNull(stashed);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertEquals(stashed, git.getRepository().getRef(Constants.R_STASH) assertEquals(stashed,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
try { try {
assertNull(git.stashDrop().setStashRef(100).call()); assertNull(git.stashDrop().setStashRef(100).call());
fail("Exception not thrown"); fail("Exception not thrown");
@ -115,15 +115,15 @@ public class StashDropCommandTest extends RepositoryTestCase {
@Test @Test
public void dropSingleStashedCommit() throws Exception { public void dropSingleStashedCommit() throws Exception {
write(committedFile, "content2"); write(committedFile, "content2");
Ref stashRef = git.getRepository().getRef(Constants.R_STASH); Ref stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef); assertNull(stashRef);
RevCommit stashed = git.stashCreate().call(); RevCommit stashed = git.stashCreate().call();
assertNotNull(stashed); assertNotNull(stashed);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertEquals(stashed, git.getRepository().getRef(Constants.R_STASH) assertEquals(stashed,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
assertNull(git.stashDrop().call()); assertNull(git.stashDrop().call());
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef); assertNull(stashRef);
ReflogReader reader = git.getRepository().getReflogReader( ReflogReader reader = git.getRepository().getReflogReader(
@ -134,25 +134,25 @@ public class StashDropCommandTest extends RepositoryTestCase {
@Test @Test
public void dropAll() throws Exception { public void dropAll() throws Exception {
write(committedFile, "content2"); write(committedFile, "content2");
Ref stashRef = git.getRepository().getRef(Constants.R_STASH); Ref stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef); assertNull(stashRef);
RevCommit firstStash = git.stashCreate().call(); RevCommit firstStash = git.stashCreate().call();
assertNotNull(firstStash); assertNotNull(firstStash);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(firstStash, git.getRepository().getRef(Constants.R_STASH) assertEquals(firstStash,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content3"); write(committedFile, "content3");
RevCommit secondStash = git.stashCreate().call(); RevCommit secondStash = git.stashCreate().call();
assertNotNull(secondStash); assertNotNull(secondStash);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(secondStash, git.getRepository().getRef(Constants.R_STASH) assertEquals(secondStash,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
assertNull(git.stashDrop().setAll(true).call()); assertNull(git.stashDrop().setAll(true).call());
assertNull(git.getRepository().getRef(Constants.R_STASH)); assertNull(git.getRepository().exactRef(Constants.R_STASH));
ReflogReader reader = git.getRepository().getReflogReader( ReflogReader reader = git.getRepository().getReflogReader(
Constants.R_STASH); Constants.R_STASH);
@ -162,25 +162,25 @@ public class StashDropCommandTest extends RepositoryTestCase {
@Test @Test
public void dropFirstStashedCommit() throws Exception { public void dropFirstStashedCommit() throws Exception {
write(committedFile, "content2"); write(committedFile, "content2");
Ref stashRef = git.getRepository().getRef(Constants.R_STASH); Ref stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef); assertNull(stashRef);
RevCommit firstStash = git.stashCreate().call(); RevCommit firstStash = git.stashCreate().call();
assertNotNull(firstStash); assertNotNull(firstStash);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(firstStash, git.getRepository().getRef(Constants.R_STASH) assertEquals(firstStash,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content3"); write(committedFile, "content3");
RevCommit secondStash = git.stashCreate().call(); RevCommit secondStash = git.stashCreate().call();
assertNotNull(secondStash); assertNotNull(secondStash);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(secondStash, git.getRepository().getRef(Constants.R_STASH) assertEquals(secondStash,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
assertEquals(firstStash, git.stashDrop().call()); assertEquals(firstStash, git.stashDrop().call());
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(firstStash, stashRef.getObjectId()); assertEquals(firstStash, stashRef.getObjectId());
@ -196,33 +196,33 @@ public class StashDropCommandTest extends RepositoryTestCase {
@Test @Test
public void dropMiddleStashCommit() throws Exception { public void dropMiddleStashCommit() throws Exception {
write(committedFile, "content2"); write(committedFile, "content2");
Ref stashRef = git.getRepository().getRef(Constants.R_STASH); Ref stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef); assertNull(stashRef);
RevCommit firstStash = git.stashCreate().call(); RevCommit firstStash = git.stashCreate().call();
assertNotNull(firstStash); assertNotNull(firstStash);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(firstStash, git.getRepository().getRef(Constants.R_STASH) assertEquals(firstStash,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content3"); write(committedFile, "content3");
RevCommit secondStash = git.stashCreate().call(); RevCommit secondStash = git.stashCreate().call();
assertNotNull(secondStash); assertNotNull(secondStash);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(secondStash, git.getRepository().getRef(Constants.R_STASH) assertEquals(secondStash,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content4"); write(committedFile, "content4");
RevCommit thirdStash = git.stashCreate().call(); RevCommit thirdStash = git.stashCreate().call();
assertNotNull(thirdStash); assertNotNull(thirdStash);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(thirdStash, git.getRepository().getRef(Constants.R_STASH) assertEquals(thirdStash,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
assertEquals(thirdStash, git.stashDrop().setStashRef(1).call()); assertEquals(thirdStash, git.stashDrop().setStashRef(1).call());
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(thirdStash, stashRef.getObjectId()); assertEquals(thirdStash, stashRef.getObjectId());
@ -241,46 +241,46 @@ public class StashDropCommandTest extends RepositoryTestCase {
@Test @Test
public void dropBoundaryStashedCommits() throws Exception { public void dropBoundaryStashedCommits() throws Exception {
write(committedFile, "content2"); write(committedFile, "content2");
Ref stashRef = git.getRepository().getRef(Constants.R_STASH); Ref stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef); assertNull(stashRef);
RevCommit firstStash = git.stashCreate().call(); RevCommit firstStash = git.stashCreate().call();
assertNotNull(firstStash); assertNotNull(firstStash);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(firstStash, git.getRepository().getRef(Constants.R_STASH) assertEquals(firstStash,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content3"); write(committedFile, "content3");
RevCommit secondStash = git.stashCreate().call(); RevCommit secondStash = git.stashCreate().call();
assertNotNull(secondStash); assertNotNull(secondStash);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(secondStash, git.getRepository().getRef(Constants.R_STASH) assertEquals(secondStash,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content4"); write(committedFile, "content4");
RevCommit thirdStash = git.stashCreate().call(); RevCommit thirdStash = git.stashCreate().call();
assertNotNull(thirdStash); assertNotNull(thirdStash);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(thirdStash, git.getRepository().getRef(Constants.R_STASH) assertEquals(thirdStash,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content5"); write(committedFile, "content5");
RevCommit fourthStash = git.stashCreate().call(); RevCommit fourthStash = git.stashCreate().call();
assertNotNull(fourthStash); assertNotNull(fourthStash);
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(fourthStash, git.getRepository().getRef(Constants.R_STASH) assertEquals(fourthStash,
.getObjectId()); git.getRepository().exactRef(Constants.R_STASH).getObjectId());
assertEquals(thirdStash, git.stashDrop().call()); assertEquals(thirdStash, git.stashDrop().call());
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(thirdStash, stashRef.getObjectId()); assertEquals(thirdStash, stashRef.getObjectId());
assertEquals(thirdStash, git.stashDrop().setStashRef(2).call()); assertEquals(thirdStash, git.stashDrop().setStashRef(2).call());
stashRef = git.getRepository().getRef(Constants.R_STASH); stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef); assertNotNull(stashRef);
assertEquals(thirdStash, stashRef.getObjectId()); assertEquals(thirdStash, stashRef.getObjectId());

20
org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java

@ -52,9 +52,7 @@ import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.attributes.Attribute.State; import org.eclipse.jgit.attributes.Attribute.State;
@ -243,27 +241,29 @@ public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase {
DirCacheIterator itr = walk.getTree(0, DirCacheIterator.class); DirCacheIterator itr = walk.getTree(0, DirCacheIterator.class);
assertNotNull("has tree", itr); assertNotNull("has tree", itr);
AttributesNode attributeNode = itr.getEntryAttributesNode(db AttributesNode attributesNode = itr.getEntryAttributesNode(db
.newObjectReader()); .newObjectReader());
assertAttributeNode(pathName, attributeNode, nodeAttrs); assertAttributesNode(pathName, attributesNode, nodeAttrs);
if (D.equals(type)) if (D.equals(type))
walk.enterSubtree(); walk.enterSubtree();
} }
private void assertAttributeNode(String pathName, private void assertAttributesNode(String pathName,
AttributesNode attributeNode, List<Attribute> nodeAttrs) { AttributesNode attributesNode, List<Attribute> nodeAttrs) {
if (attributeNode == null) if (attributesNode == null)
assertTrue(nodeAttrs == null || nodeAttrs.isEmpty()); assertTrue(nodeAttrs == null || nodeAttrs.isEmpty());
else { else {
Map<String, Attribute> entryAttributes = new LinkedHashMap<String, Attribute>(); Attributes entryAttributes = new Attributes();
attributeNode.getAttributes(pathName, false, entryAttributes); attributesNode.getAttributes(pathName,
false, entryAttributes);
if (nodeAttrs != null && !nodeAttrs.isEmpty()) { if (nodeAttrs != null && !nodeAttrs.isEmpty()) {
for (Attribute attribute : nodeAttrs) { for (Attribute attribute : nodeAttrs) {
assertThat(entryAttributes.values(), hasItem(attribute)); assertThat(entryAttributes.getAll(),
hasItem(attribute));
} }
} else { } else {
assertTrue( assertTrue(

29
org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeNodeTest.java → org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java

@ -49,10 +49,6 @@ import static org.junit.Assert.assertEquals;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
@ -60,7 +56,7 @@ import org.junit.Test;
/** /**
* Test {@link AttributesNode} * Test {@link AttributesNode}
*/ */
public class AttributeNodeTest { public class AttributesNodeTest {
private static final Attribute A_SET_ATTR = new Attribute("A", SET); private static final Attribute A_SET_ATTR = new Attribute("A", SET);
@ -104,8 +100,8 @@ public class AttributeNodeTest {
is = new ByteArrayInputStream(attributeFileContent.getBytes()); is = new ByteArrayInputStream(attributeFileContent.getBytes());
AttributesNode node = new AttributesNode(); AttributesNode node = new AttributesNode();
node.parse(is); node.parse(is);
assertAttribute("file.type1", node, Collections.<Attribute> emptySet()); assertAttribute("file.type1", node, new Attributes());
assertAttribute("file.type2", node, Collections.<Attribute> emptySet()); assertAttribute("file.type2", node, new Attributes());
} }
@Test @Test
@ -115,7 +111,7 @@ public class AttributeNodeTest {
is = new ByteArrayInputStream(attributeFileContent.getBytes()); is = new ByteArrayInputStream(attributeFileContent.getBytes());
AttributesNode node = new AttributesNode(); AttributesNode node = new AttributesNode();
node.parse(is); node.parse(is);
assertAttribute("file.type1", node, Collections.<Attribute> emptySet()); assertAttribute("file.type1", node, new Attributes());
assertAttribute("file.type2", node, asSet(A_UNSET_ATTR)); assertAttribute("file.type2", node, asSet(A_UNSET_ATTR));
} }
@ -127,8 +123,8 @@ public class AttributeNodeTest {
is = new ByteArrayInputStream(attributeFileContent.getBytes()); is = new ByteArrayInputStream(attributeFileContent.getBytes());
AttributesNode node = new AttributesNode(); AttributesNode node = new AttributesNode();
node.parse(is); node.parse(is);
assertAttribute("file.type1", node, Collections.<Attribute> emptySet()); assertAttribute("file.type1", node, new Attributes());
assertAttribute("file.type2", node, Collections.<Attribute> emptySet()); assertAttribute("file.type2", node, new Attributes());
assertAttribute("file.type3", node, asSet(new Attribute("attr", ""))); assertAttribute("file.type3", node, asSet(new Attribute("attr", "")));
} }
@ -166,17 +162,14 @@ public class AttributeNodeTest {
} }
private void assertAttribute(String path, AttributesNode node, private void assertAttribute(String path, AttributesNode node,
Set<Attribute> attrs) { Attributes attrs) {
HashMap<String, Attribute> attributes = new HashMap<String, Attribute>(); Attributes attributes = new Attributes();
node.getAttributes(path, false, attributes); node.getAttributes(path, false, attributes);
assertEquals(attrs, new HashSet<Attribute>(attributes.values())); assertEquals(attrs, attributes);
} }
static Set<Attribute> asSet(Attribute... attrs) { static Attributes asSet(Attribute... attrs) {
Set<Attribute> result = new HashSet<Attribute>(); return new Attributes(attrs);
for (Attribute attr : attrs)
result.add(attr);
return result;
} }
} }

55
org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java

@ -53,9 +53,7 @@ import static org.junit.Assert.assertTrue;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.eclipse.jgit.attributes.Attribute.State; import org.eclipse.jgit.attributes.Attribute.State;
import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.CorruptObjectException;
@ -76,14 +74,10 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase {
private static final FileMode F = FileMode.REGULAR_FILE; private static final FileMode F = FileMode.REGULAR_FILE;
private static Attribute EOL_CRLF = new Attribute("eol", "crlf");
private static Attribute EOL_LF = new Attribute("eol", "lf"); private static Attribute EOL_LF = new Attribute("eol", "lf");
private static Attribute DELTA_UNSET = new Attribute("delta", State.UNSET); private static Attribute DELTA_UNSET = new Attribute("delta", State.UNSET);
private static Attribute CUSTOM_VALUE = new Attribute("custom", "value");
private TreeWalk walk; private TreeWalk walk;
@Test @Test
@ -112,25 +106,19 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase {
walk = beginWalk(); walk = beginWalk();
assertIteration(F, ".gitattributes"); assertIteration(F, ".gitattributes");
assertIteration(F, "global.txt", asList(EOL_LF), null, assertIteration(F, "global.txt", asList(EOL_LF));
asList(CUSTOM_VALUE)); assertIteration(F, "readme.txt", asList(EOL_LF));
assertIteration(F, "readme.txt", asList(EOL_LF), null,
asList(CUSTOM_VALUE));
assertIteration(D, "src"); assertIteration(D, "src");
assertIteration(D, "src/config"); assertIteration(D, "src/config");
assertIteration(F, "src/config/.gitattributes"); assertIteration(F, "src/config/.gitattributes");
assertIteration(F, "src/config/readme.txt", asList(DELTA_UNSET), null, assertIteration(F, "src/config/readme.txt", asList(DELTA_UNSET));
asList(CUSTOM_VALUE)); assertIteration(F, "src/config/windows.file", null);
assertIteration(F, "src/config/windows.file", null, asList(EOL_CRLF), assertIteration(F, "src/config/windows.txt", asList(DELTA_UNSET));
null);
assertIteration(F, "src/config/windows.txt", asList(DELTA_UNSET),
asList(EOL_CRLF), asList(CUSTOM_VALUE));
assertIteration(F, "windows.file", null, asList(EOL_CRLF), null); assertIteration(F, "windows.file", null);
assertIteration(F, "windows.txt", asList(EOL_LF), asList(EOL_CRLF), assertIteration(F, "windows.txt", asList(EOL_LF));
asList(CUSTOM_VALUE));
endWalk(); endWalk();
} }
@ -212,14 +200,11 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase {
private void assertIteration(FileMode type, String pathName) private void assertIteration(FileMode type, String pathName)
throws IOException { throws IOException {
assertIteration(type, pathName, Collections.<Attribute> emptyList(), assertIteration(type, pathName, Collections.<Attribute> emptyList());
Collections.<Attribute> emptyList(),
Collections.<Attribute> emptyList());
} }
private void assertIteration(FileMode type, String pathName, private void assertIteration(FileMode type, String pathName,
List<Attribute> nodeAttrs, List<Attribute> infoAttrs, List<Attribute> nodeAttrs)
List<Attribute> globalAttrs)
throws IOException { throws IOException {
assertTrue("walk has entry", walk.next()); assertTrue("walk has entry", walk.next());
assertEquals(pathName, walk.getPathString()); assertEquals(pathName, walk.getPathString());
@ -227,29 +212,27 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase {
WorkingTreeIterator itr = walk.getTree(0, WorkingTreeIterator.class); WorkingTreeIterator itr = walk.getTree(0, WorkingTreeIterator.class);
assertNotNull("has tree", itr); assertNotNull("has tree", itr);
AttributesNode attributeNode = itr.getEntryAttributesNode(); AttributesNode attributesNode = itr.getEntryAttributesNode();
assertAttributeNode(pathName, attributeNode, nodeAttrs); assertAttributesNode(pathName, attributesNode, nodeAttrs);
AttributesNode infoAttributeNode = itr.getInfoAttributesNode();
assertAttributeNode(pathName, infoAttributeNode, infoAttrs);
AttributesNode globalAttributeNode = itr.getGlobalAttributesNode();
assertAttributeNode(pathName, globalAttributeNode, globalAttrs);
if (D.equals(type)) if (D.equals(type))
walk.enterSubtree(); walk.enterSubtree();
} }
private void assertAttributeNode(String pathName, private void assertAttributesNode(String pathName,
AttributesNode attributeNode, List<Attribute> nodeAttrs) { AttributesNode attributesNode, List<Attribute> nodeAttrs) {
if (attributeNode == null) if (attributesNode == null)
assertTrue(nodeAttrs == null || nodeAttrs.isEmpty()); assertTrue(nodeAttrs == null || nodeAttrs.isEmpty());
else { else {
Map<String, Attribute> entryAttributes = new LinkedHashMap<String, Attribute>(); Attributes entryAttributes = new Attributes();
attributeNode.getAttributes(pathName, false, entryAttributes); attributesNode.getAttributes(pathName,
false, entryAttributes);
if (nodeAttrs != null && !nodeAttrs.isEmpty()) { if (nodeAttrs != null && !nodeAttrs.isEmpty()) {
for (Attribute attribute : nodeAttrs) { for (Attribute attribute : nodeAttrs) {
assertThat(entryAttributes.values(), hasItem(attribute)); assertThat(entryAttributes.getAll(),
hasItem(attribute));
} }
} else { } else {
assertTrue( assertTrue(

866
org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java

@ -0,0 +1,866 @@
/*
* Copyright (C) 2014, Obeo.
* 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.attributes;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.attributes.Attribute.State;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Tests the attributes are correctly computed in a {@link TreeWalk}.
*
* @see TreeWalk#getAttributes()
*/
public class TreeWalkAttributeTest extends RepositoryTestCase {
private static final FileMode M = FileMode.MISSING;
private static final FileMode D = FileMode.TREE;
private static final FileMode F = FileMode.REGULAR_FILE;
private static Attribute EOL_CRLF = new Attribute("eol", "crlf");
private static Attribute EOL_LF = new Attribute("eol", "lf");
private static Attribute TEXT_SET = new Attribute("text", State.SET);
private static Attribute TEXT_UNSET = new Attribute("text", State.UNSET);
private static Attribute DELTA_UNSET = new Attribute("delta", State.UNSET);
private static Attribute DELTA_SET = new Attribute("delta", State.SET);
private static Attribute CUSTOM_GLOBAL = new Attribute("custom", "global");
private static Attribute CUSTOM_INFO = new Attribute("custom", "info");
private static Attribute CUSTOM_ROOT = new Attribute("custom", "root");
private static Attribute CUSTOM_PARENT = new Attribute("custom", "parent");
private static Attribute CUSTOM_CURRENT = new Attribute("custom", "current");
private static Attribute CUSTOM2_UNSET = new Attribute("custom2",
State.UNSET);
private static Attribute CUSTOM2_SET = new Attribute("custom2", State.SET);
private TreeWalk walk;
private TreeWalk ci_walk;
private Git git;
private File customAttributeFile;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
git = new Git(db);
}
@Override
@After
public void tearDown() throws Exception {
super.tearDown();
if (customAttributeFile != null)
customAttributeFile.delete();
}
/**
* Checks that the attributes are computed correctly depending on the
* operation type.
* <p>
* In this test we changed the content of the attribute files in the working
* tree compared to the one in the index.
* </p>
*
* @throws IOException
* @throws NoFilepatternException
* @throws GitAPIException
*/
@Test
public void testCheckinCheckoutDifferences() throws IOException,
NoFilepatternException, GitAPIException {
writeGlobalAttributeFile("globalAttributesFile", "*.txt -custom2");
writeAttributesFile(".git/info/attributes", "*.txt eol=crlf");
writeAttributesFile(".gitattributes", "*.txt custom=root");
writeAttributesFile("level1/.gitattributes", "*.txt text");
writeAttributesFile("level1/level2/.gitattributes", "*.txt -delta");
writeTrashFile("l0.txt", "");
writeTrashFile("level1/l1.txt", "");
writeTrashFile("level1/level2/l2.txt", "");
git.add().addFilepattern(".").call();
beginWalk();
// Modify all attributes
writeGlobalAttributeFile("globalAttributesFile", "*.txt custom2");
writeAttributesFile(".git/info/attributes", "*.txt eol=lf");
writeAttributesFile(".gitattributes", "*.txt custom=info");
writeAttributesFile("level1/.gitattributes", "*.txt -text");
writeAttributesFile("level1/level2/.gitattributes", "*.txt delta");
assertEntry(F, ".gitattributes");
assertEntry(F, "l0.txt", asSet(EOL_LF, CUSTOM_INFO, CUSTOM2_SET),
asSet(EOL_LF, CUSTOM_ROOT, CUSTOM2_SET));
assertEntry(D, "level1");
assertEntry(F, "level1/.gitattributes");
assertEntry(F, "level1/l1.txt",
asSet(EOL_LF, CUSTOM_INFO, CUSTOM2_SET, TEXT_UNSET),
asSet(EOL_LF, CUSTOM_ROOT, CUSTOM2_SET, TEXT_SET));
assertEntry(D, "level1/level2");
assertEntry(F, "level1/level2/.gitattributes");
assertEntry(F, "level1/level2/l2.txt",
asSet(EOL_LF, CUSTOM_INFO, CUSTOM2_SET, TEXT_UNSET, DELTA_SET),
asSet(EOL_LF, CUSTOM_ROOT, CUSTOM2_SET, TEXT_SET, DELTA_UNSET));
endWalk();
}
/**
* Checks that the index is used as fallback when the git attributes file
* are missing in the working tree.
*
* @throws IOException
* @throws NoFilepatternException
* @throws GitAPIException
*/
@Test
public void testIndexOnly() throws IOException, NoFilepatternException,
GitAPIException {
List<File> attrFiles = new ArrayList<File>();
attrFiles.add(writeGlobalAttributeFile("globalAttributesFile",
"*.txt -custom2"));
attrFiles.add(writeAttributesFile(".git/info/attributes",
"*.txt eol=crlf"));
attrFiles
.add(writeAttributesFile(".gitattributes", "*.txt custom=root"));
attrFiles
.add(writeAttributesFile("level1/.gitattributes", "*.txt text"));
attrFiles.add(writeAttributesFile("level1/level2/.gitattributes",
"*.txt -delta"));
writeTrashFile("l0.txt", "");
writeTrashFile("level1/l1.txt", "");
writeTrashFile("level1/level2/l2.txt", "");
git.add().addFilepattern(".").call();
// Modify all attributes
for (File attrFile : attrFiles)
attrFile.delete();
beginWalk();
assertEntry(M, ".gitattributes");
assertEntry(F, "l0.txt", asSet(CUSTOM_ROOT));
assertEntry(D, "level1");
assertEntry(M, "level1/.gitattributes");
assertEntry(F, "level1/l1.txt",
asSet(CUSTOM_ROOT, TEXT_SET));
assertEntry(D, "level1/level2");
assertEntry(M, "level1/level2/.gitattributes");
assertEntry(F, "level1/level2/l2.txt",
asSet(CUSTOM_ROOT, TEXT_SET, DELTA_UNSET));
endWalk();
}
/**
* Check that we search in the working tree for attributes although the file
* we are currently inspecting does not exist anymore in the working tree.
*
* @throws IOException
* @throws NoFilepatternException
* @throws GitAPIException
*/
@Test
public void testIndexOnly2()
throws IOException, NoFilepatternException, GitAPIException {
File l2 = writeTrashFile("level1/level2/l2.txt", "");
writeTrashFile("level1/level2/l1.txt", "");
git.add().addFilepattern(".").call();
writeAttributesFile(".gitattributes", "*.txt custom=root");
assertTrue(l2.delete());
beginWalk();
assertEntry(F, ".gitattributes");
assertEntry(D, "level1");
assertEntry(D, "level1/level2");
assertEntry(F, "level1/level2/l1.txt", asSet(CUSTOM_ROOT));
assertEntry(M, "level1/level2/l2.txt", asSet(CUSTOM_ROOT));
endWalk();
}
/**
* Basic test for git attributes.
* <p>
* In this use case files are present in both the working tree and the index
* </p>
*
* @throws IOException
* @throws NoFilepatternException
* @throws GitAPIException
*/
@Test
public void testRules() throws IOException, NoFilepatternException,
GitAPIException {
writeAttributesFile(".git/info/attributes", "windows* eol=crlf");
writeAttributesFile(".gitattributes", "*.txt eol=lf");
writeTrashFile("windows.file", "");
writeTrashFile("windows.txt", "");
writeTrashFile("readme.txt", "");
writeAttributesFile("src/config/.gitattributes", "*.txt -delta");
writeTrashFile("src/config/readme.txt", "");
writeTrashFile("src/config/windows.file", "");
writeTrashFile("src/config/windows.txt", "");
beginWalk();
git.add().addFilepattern(".").call();
assertEntry(F, ".gitattributes");
assertEntry(F, "readme.txt", asSet(EOL_LF));
assertEntry(D, "src");
assertEntry(D, "src/config");
assertEntry(F, "src/config/.gitattributes");
assertEntry(F, "src/config/readme.txt", asSet(DELTA_UNSET, EOL_LF));
assertEntry(F, "src/config/windows.file", asSet(EOL_CRLF));
assertEntry(F, "src/config/windows.txt", asSet(DELTA_UNSET, EOL_CRLF));
assertEntry(F, "windows.file", asSet(EOL_CRLF));
assertEntry(F, "windows.txt", asSet(EOL_CRLF));
endWalk();
}
/**
* Checks that if there is no .gitattributes file in the repository
* everything still work fine.
*
* @throws IOException
*/
@Test
public void testNoAttributes() throws IOException {
writeTrashFile("l0.txt", "");
writeTrashFile("level1/l1.txt", "");
writeTrashFile("level1/level2/l2.txt", "");
beginWalk();
assertEntry(F, "l0.txt");
assertEntry(D, "level1");
assertEntry(F, "level1/l1.txt");
assertEntry(D, "level1/level2");
assertEntry(F, "level1/level2/l2.txt");
endWalk();
}
/**
* Checks that an empty .gitattribute file does not return incorrect value.
*
* @throws IOException
*/
@Test
public void testEmptyGitAttributeFile() throws IOException {
writeAttributesFile(".git/info/attributes", "");
writeTrashFile("l0.txt", "");
writeAttributesFile(".gitattributes", "");
writeTrashFile("level1/l1.txt", "");
writeTrashFile("level1/level2/l2.txt", "");
beginWalk();
assertEntry(F, ".gitattributes");
assertEntry(F, "l0.txt");
assertEntry(D, "level1");
assertEntry(F, "level1/l1.txt");
assertEntry(D, "level1/level2");
assertEntry(F, "level1/level2/l2.txt");
endWalk();
}
@Test
public void testNoMatchingAttributes() throws IOException {
writeAttributesFile(".git/info/attributes", "*.java delta");
writeAttributesFile(".gitattributes", "*.java -delta");
writeAttributesFile("levelA/.gitattributes", "*.java eol=lf");
writeAttributesFile("levelB/.gitattributes", "*.txt eol=lf");
writeTrashFile("levelA/lA.txt", "");
beginWalk();
assertEntry(F, ".gitattributes");
assertEntry(D, "levelA");
assertEntry(F, "levelA/.gitattributes");
assertEntry(F, "levelA/lA.txt");
assertEntry(D, "levelB");
assertEntry(F, "levelB/.gitattributes");
endWalk();
}
/**
* Checks that $GIT_DIR/info/attributes file has the highest precedence.
*
* @throws IOException
*/
@Test
public void testPrecedenceInfo() throws IOException {
writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global");
writeAttributesFile(".git/info/attributes", "*.txt custom=info");
writeAttributesFile(".gitattributes", "*.txt custom=root");
writeAttributesFile("level1/.gitattributes", "*.txt custom=parent");
writeAttributesFile("level1/level2/.gitattributes",
"*.txt custom=current");
writeTrashFile("level1/level2/file.txt", "");
beginWalk();
assertEntry(F, ".gitattributes");
assertEntry(D, "level1");
assertEntry(F, "level1/.gitattributes");
assertEntry(D, "level1/level2");
assertEntry(F, "level1/level2/.gitattributes");
assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_INFO));
endWalk();
}
/**
* Checks that a subfolder ".gitattributes" file has precedence over its
* parent.
*
* @throws IOException
*/
@Test
public void testPrecedenceCurrent() throws IOException {
writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global");
writeAttributesFile(".gitattributes", "*.txt custom=root");
writeAttributesFile("level1/.gitattributes", "*.txt custom=parent");
writeAttributesFile("level1/level2/.gitattributes",
"*.txt custom=current");
writeTrashFile("level1/level2/file.txt", "");
beginWalk();
assertEntry(F, ".gitattributes");
assertEntry(D, "level1");
assertEntry(F, "level1/.gitattributes");
assertEntry(D, "level1/level2");
assertEntry(F, "level1/level2/.gitattributes");
assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_CURRENT));
endWalk();
}
/**
* Checks that the parent ".gitattributes" file is used as fallback.
*
* @throws IOException
*/
@Test
public void testPrecedenceParent() throws IOException {
writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global");
writeAttributesFile(".gitattributes", "*.txt custom=root");
writeAttributesFile("level1/.gitattributes", "*.txt custom=parent");
writeTrashFile("level1/level2/file.txt", "");
beginWalk();
assertEntry(F, ".gitattributes");
assertEntry(D, "level1");
assertEntry(F, "level1/.gitattributes");
assertEntry(D, "level1/level2");
assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_PARENT));
endWalk();
}
/**
* Checks that the grand parent ".gitattributes" file is used as fallback.
*
* @throws IOException
*/
@Test
public void testPrecedenceRoot() throws IOException {
writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global");
writeAttributesFile(".gitattributes", "*.txt custom=root");
writeTrashFile("level1/level2/file.txt", "");
beginWalk();
assertEntry(F, ".gitattributes");
assertEntry(D, "level1");
assertEntry(D, "level1/level2");
assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_ROOT));
endWalk();
}
/**
* Checks that the global attribute file is used as fallback.
*
* @throws IOException
*/
@Test
public void testPrecedenceGlobal() throws IOException {
writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global");
writeTrashFile("level1/level2/file.txt", "");
beginWalk();
assertEntry(D, "level1");
assertEntry(D, "level1/level2");
assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_GLOBAL));
endWalk();
}
/**
* Checks the precedence on a hierarchy with multiple attributes.
* <p>
* In this test all file are present in both the working tree and the index.
* </p>
*
* @throws IOException
* @throws GitAPIException
* @throws NoFilepatternException
*/
@Test
public void testHierarchyBothIterator() throws IOException,
NoFilepatternException, GitAPIException {
writeAttributesFile(".git/info/attributes", "*.global eol=crlf");
writeAttributesFile(".gitattributes", "*.local eol=lf");
writeAttributesFile("level1/.gitattributes", "*.local text");
writeAttributesFile("level1/level2/.gitattributes", "*.local -text");
writeTrashFile("l0.global", "");
writeTrashFile("l0.local", "");
writeTrashFile("level1/l1.global", "");
writeTrashFile("level1/l1.local", "");
writeTrashFile("level1/level2/l2.global", "");
writeTrashFile("level1/level2/l2.local", "");
beginWalk();
git.add().addFilepattern(".").call();
assertEntry(F, ".gitattributes");
assertEntry(F, "l0.global", asSet(EOL_CRLF));
assertEntry(F, "l0.local", asSet(EOL_LF));
assertEntry(D, "level1");
assertEntry(F, "level1/.gitattributes");
assertEntry(F, "level1/l1.global", asSet(EOL_CRLF));
assertEntry(F, "level1/l1.local", asSet(EOL_LF, TEXT_SET));
assertEntry(D, "level1/level2");
assertEntry(F, "level1/level2/.gitattributes");
assertEntry(F, "level1/level2/l2.global", asSet(EOL_CRLF));
assertEntry(F, "level1/level2/l2.local", asSet(EOL_LF, TEXT_UNSET));
endWalk();
}
/**
* Checks the precedence on a hierarchy with multiple attributes.
* <p>
* In this test all file are present only in the working tree.
* </p>
*
* @throws IOException
* @throws GitAPIException
* @throws NoFilepatternException
*/
@Test
public void testHierarchyWorktreeOnly()
throws IOException, NoFilepatternException, GitAPIException {
writeAttributesFile(".git/info/attributes", "*.global eol=crlf");
writeAttributesFile(".gitattributes", "*.local eol=lf");
writeAttributesFile("level1/.gitattributes", "*.local text");
writeAttributesFile("level1/level2/.gitattributes", "*.local -text");
writeTrashFile("l0.global", "");
writeTrashFile("l0.local", "");
writeTrashFile("level1/l1.global", "");
writeTrashFile("level1/l1.local", "");
writeTrashFile("level1/level2/l2.global", "");
writeTrashFile("level1/level2/l2.local", "");
beginWalk();
assertEntry(F, ".gitattributes");
assertEntry(F, "l0.global", asSet(EOL_CRLF));
assertEntry(F, "l0.local", asSet(EOL_LF));
assertEntry(D, "level1");
assertEntry(F, "level1/.gitattributes");
assertEntry(F, "level1/l1.global", asSet(EOL_CRLF));
assertEntry(F, "level1/l1.local", asSet(EOL_LF, TEXT_SET));
assertEntry(D, "level1/level2");
assertEntry(F, "level1/level2/.gitattributes");
assertEntry(F, "level1/level2/l2.global", asSet(EOL_CRLF));
assertEntry(F, "level1/level2/l2.local", asSet(EOL_LF, TEXT_UNSET));
endWalk();
}
/**
* Checks that the list of attributes is an aggregation of all the
* attributes from the attributes files hierarchy.
*
* @throws IOException
*/
@Test
public void testAggregation() throws IOException {
writeGlobalAttributeFile("globalAttributesFile", "*.txt -custom2");
writeAttributesFile(".git/info/attributes", "*.txt eol=crlf");
writeAttributesFile(".gitattributes", "*.txt custom=root");
writeAttributesFile("level1/.gitattributes", "*.txt text");
writeAttributesFile("level1/level2/.gitattributes", "*.txt -delta");
writeTrashFile("l0.txt", "");
writeTrashFile("level1/l1.txt", "");
writeTrashFile("level1/level2/l2.txt", "");
beginWalk();
assertEntry(F, ".gitattributes");
assertEntry(F, "l0.txt", asSet(EOL_CRLF, CUSTOM_ROOT, CUSTOM2_UNSET));
assertEntry(D, "level1");
assertEntry(F, "level1/.gitattributes");
assertEntry(F, "level1/l1.txt",
asSet(EOL_CRLF, CUSTOM_ROOT, TEXT_SET, CUSTOM2_UNSET));
assertEntry(D, "level1/level2");
assertEntry(F, "level1/level2/.gitattributes");
assertEntry(
F,
"level1/level2/l2.txt",
asSet(EOL_CRLF, CUSTOM_ROOT, TEXT_SET, DELTA_UNSET,
CUSTOM2_UNSET));
endWalk();
}
/**
* Checks that the last entry in .gitattributes is used if 2 lines match the
* same attribute
*
* @throws IOException
*/
@Test
public void testOverriding() throws IOException {
writeAttributesFile(".git/info/attributes",//
//
"*.txt custom=current",//
"*.txt custom=parent",//
"*.txt custom=root",//
"*.txt custom=info",
//
"*.txt delta",//
"*.txt -delta",
//
"*.txt eol=lf",//
"*.txt eol=crlf",
//
"*.txt text",//
"*.txt -text");
writeTrashFile("l0.txt", "");
beginWalk();
assertEntry(F, "l0.txt",
asSet(TEXT_UNSET, EOL_CRLF, DELTA_UNSET, CUSTOM_INFO));
endWalk();
}
/**
* Checks that the last value of an attribute is used if in the same line an
* attribute is defined several time.
*
* @throws IOException
*/
@Test
public void testOverriding2() throws IOException {
writeAttributesFile(".git/info/attributes",
"*.txt custom=current custom=parent custom=root custom=info",//
"*.txt delta -delta",//
"*.txt eol=lf eol=crlf",//
"*.txt text -text");
writeTrashFile("l0.txt", "");
beginWalk();
assertEntry(F, "l0.txt",
asSet(TEXT_UNSET, EOL_CRLF, DELTA_UNSET, CUSTOM_INFO));
endWalk();
}
@Test
public void testRulesInherited() throws Exception {
writeAttributesFile(".gitattributes", "**/*.txt eol=lf");
writeTrashFile("src/config/readme.txt", "");
writeTrashFile("src/config/windows.file", "");
beginWalk();
assertEntry(F, ".gitattributes");
assertEntry(D, "src");
assertEntry(D, "src/config");
assertEntry(F, "src/config/readme.txt", asSet(EOL_LF));
assertEntry(F, "src/config/windows.file",
Collections.<Attribute> emptySet());
endWalk();
}
private void beginWalk() throws NoWorkTreeException, IOException {
walk = new TreeWalk(db);
walk.addTree(new FileTreeIterator(db));
walk.addTree(new DirCacheIterator(db.readDirCache()));
ci_walk = new TreeWalk(db);
ci_walk.setOperationType(OperationType.CHECKIN_OP);
ci_walk.addTree(new FileTreeIterator(db));
ci_walk.addTree(new DirCacheIterator(db.readDirCache()));
}
/**
* Assert an entry in which checkin and checkout attributes are expected to
* be the same.
*
* @param type
* @param pathName
* @param forBothOperaiton
* @throws IOException
*/
private void assertEntry(FileMode type, String pathName,
Set<Attribute> forBothOperaiton) throws IOException {
assertEntry(type, pathName, forBothOperaiton, forBothOperaiton);
}
/**
* Assert an entry with no attribute expected.
*
* @param type
* @param pathName
* @throws IOException
*/
private void assertEntry(FileMode type, String pathName) throws IOException {
assertEntry(type, pathName, Collections.<Attribute> emptySet(),
Collections.<Attribute> emptySet());
}
/**
* Assert that an entry;
* <ul>
* <li>Has the correct type</li>
* <li>Exist in the tree walk</li>
* <li>Has the expected attributes on a checkin operation</li>
* <li>Has the expected attributes on a checkout operation</li>
* </ul>
*
* @param type
* @param pathName
* @param checkinAttributes
* @param checkoutAttributes
* @throws IOException
*/
private void assertEntry(FileMode type, String pathName,
Set<Attribute> checkinAttributes, Set<Attribute> checkoutAttributes)
throws IOException {
assertTrue("walk has entry", walk.next());
assertTrue("walk has entry", ci_walk.next());
assertEquals(pathName, walk.getPathString());
assertEquals(type, walk.getFileMode(0));
assertEquals(checkinAttributes,
asSet(ci_walk.getAttributes().getAll()));
assertEquals(checkoutAttributes,
asSet(walk.getAttributes().getAll()));
if (D.equals(type)) {
walk.enterSubtree();
ci_walk.enterSubtree();
}
}
private static Set<Attribute> asSet(Collection<Attribute> attributes) {
Set<Attribute> ret = new HashSet<Attribute>();
for (Attribute a : attributes) {
ret.add(a);
}
return (ret);
}
private File writeAttributesFile(String name, String... rules)
throws IOException {
StringBuilder data = new StringBuilder();
for (String line : rules)
data.append(line + "\n");
return writeTrashFile(name, data.toString());
}
/**
* Creates an attributes file and set its location in the git configuration.
*
* @param fileName
* @param attributes
* @return The attribute file
* @throws IOException
* @see Repository#getConfig()
*/
private File writeGlobalAttributeFile(String fileName, String... attributes)
throws IOException {
customAttributeFile = File.createTempFile("tmp_", fileName, null);
customAttributeFile.deleteOnExit();
StringBuilder attributesFileContent = new StringBuilder();
for (String attr : attributes) {
attributesFileContent.append(attr).append("\n");
}
JGitTestUtil.write(customAttributeFile,
attributesFileContent.toString());
db.getConfig().setString("core", null, "attributesfile",
customAttributeFile.getAbsolutePath());
return customAttributeFile;
}
static Set<Attribute> asSet(Attribute... attrs) {
HashSet<Attribute> result = new HashSet<Attribute>();
for (Attribute attr : attrs)
result.add(attr);
return result;
}
private void endWalk() throws IOException {
assertFalse("Not all files tested", walk.next());
assertFalse("Not all files tested", ci_walk.next());
}
}

31
org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java

@ -48,6 +48,7 @@ import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.diff.DiffEntry.ChangeType;
@ -226,6 +227,19 @@ public class RenameDetectorTest extends RepositoryTestCase {
assertCopy(d, b, 100, entries.get(2)); assertCopy(d, b, 100, entries.get(2));
} }
@Test
public void testExactRename_UnstagedFile() throws Exception {
ObjectId aId = blob("foo");
DiffEntry a = DiffEntry.delete(PATH_A, aId);
DiffEntry b = DiffEntry.add(PATH_B, aId);
rd.addAll(Arrays.asList(a, b));
List<DiffEntry> entries = rd.compute();
assertEquals(1, entries.size());
assertRename(a, b, 100, entries.get(0));
}
@Test @Test
public void testInexactRename_OnePair() throws Exception { public void testInexactRename_OnePair() throws Exception {
ObjectId aId = blob("foo\nbar\nbaz\nblarg\n"); ObjectId aId = blob("foo\nbar\nbaz\nblarg\n");
@ -429,6 +443,23 @@ public class RenameDetectorTest extends RepositoryTestCase {
assertSame(b, entries.get(1)); assertSame(b, entries.get(1));
} }
@Test
public void testNoRenames_UntrackedFile() throws Exception {
ObjectId aId = blob("foo");
ObjectId bId = ObjectId
.fromString("3049eb6eee7e1318f4e78e799bf33f1e54af9cbf");
DiffEntry a = DiffEntry.delete(PATH_A, aId);
DiffEntry b = DiffEntry.add(PATH_B, bId);
rd.addAll(Arrays.asList(a, b));
List<DiffEntry> entries = rd.compute();
assertEquals(2, entries.size());
assertSame(a, entries.get(0));
assertSame(b, entries.get(1));
}
@Test @Test
public void testBreakModify_BreakAll() throws Exception { public void testBreakModify_BreakAll() throws Exception {
ObjectId aId = blob("foo"); ObjectId aId = blob("foo");

4
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java vendored

@ -69,9 +69,9 @@ public class DirCacheEntryTest {
assertFalse(isValidPath("a\u0000b")); assertFalse(isValidPath("a\u0000b"));
} }
private static boolean isValidPath(final String path) { private static boolean isValidPath(String path) {
try { try {
DirCacheCheckout.checkValidPath(path); new DirCacheEntry(path);
return true; return true;
} catch (InvalidPathException e) { } catch (InvalidPathException e) {
return false; return false;

38
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java

@ -77,7 +77,7 @@ public class GcPackRefsTest extends GcTestCase {
tr.lightweightTag("t", a); tr.lightweightTag("t", a);
gc.packRefs(); gc.packRefs();
assertSame(repo.getRef("t").getStorage(), Storage.PACKED); assertSame(repo.exactRef("refs/tags/t").getStorage(), Storage.PACKED);
} }
@Test @Test
@ -126,8 +126,8 @@ public class GcPackRefsTest extends GcTestCase {
refLock.unlock(); refLock.unlock();
} }
assertSame(repo.getRef("refs/tags/t1").getStorage(), Storage.LOOSE); assertSame(repo.exactRef("refs/tags/t1").getStorage(), Storage.LOOSE);
assertSame(repo.getRef("refs/tags/t2").getStorage(), Storage.PACKED); assertSame(repo.exactRef("refs/tags/t2").getStorage(), Storage.PACKED);
} }
@Test @Test
@ -146,7 +146,7 @@ public class GcPackRefsTest extends GcTestCase {
public Result call() throws Exception { public Result call() throws Exception {
RefUpdate update = new RefDirectoryUpdate( RefUpdate update = new RefDirectoryUpdate(
(RefDirectory) repo.getRefDatabase(), (RefDirectory) repo.getRefDatabase(),
repo.getRef("refs/tags/t")) { repo.exactRef("refs/tags/t")) {
@Override @Override
public boolean isForceUpdate() { public boolean isForceUpdate() {
try { try {
@ -182,7 +182,7 @@ public class GcPackRefsTest extends GcTestCase {
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
} }
assertEquals(repo.getRef("refs/tags/t").getObjectId(), b); assertEquals(repo.exactRef("refs/tags/t").getObjectId(), b);
} }
@Test @Test
@ -194,23 +194,23 @@ public class GcPackRefsTest extends GcTestCase {
// check for the unborn branch master. HEAD should point to master and // check for the unborn branch master. HEAD should point to master and
// master doesn't exist. // master doesn't exist.
assertEquals(repo.getRef("HEAD").getTarget().getName(), assertEquals(repo.exactRef("HEAD").getTarget().getName(),
"refs/heads/master"); "refs/heads/master");
assertNull(repo.getRef("HEAD").getTarget().getObjectId()); assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
gc.packRefs(); gc.packRefs();
assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE); assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
assertEquals(repo.getRef("HEAD").getTarget().getName(), assertEquals(repo.exactRef("HEAD").getTarget().getName(),
"refs/heads/master"); "refs/heads/master");
assertNull(repo.getRef("HEAD").getTarget().getObjectId()); assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
git.checkout().setName("refs/heads/side").call(); git.checkout().setName("refs/heads/side").call();
gc.packRefs(); gc.packRefs();
assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE); assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
// check for detached HEAD // check for detached HEAD
git.checkout().setName(first.getName()).call(); git.checkout().setName(first.getName()).call();
gc.packRefs(); gc.packRefs();
assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE); assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
} }
@Test @Test
@ -229,20 +229,20 @@ public class GcPackRefsTest extends GcTestCase {
// check for the unborn branch master. HEAD should point to master and // check for the unborn branch master. HEAD should point to master and
// master doesn't exist. // master doesn't exist.
assertEquals(repo.getRef("HEAD").getTarget().getName(), assertEquals(repo.exactRef("HEAD").getTarget().getName(),
"refs/heads/master"); "refs/heads/master");
assertNull(repo.getRef("HEAD").getTarget().getObjectId()); assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
gc.packRefs(); gc.packRefs();
assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE); assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
assertEquals(repo.getRef("HEAD").getTarget().getName(), assertEquals(repo.exactRef("HEAD").getTarget().getName(),
"refs/heads/master"); "refs/heads/master");
assertNull(repo.getRef("HEAD").getTarget().getObjectId()); assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
// check for non-detached HEAD // check for non-detached HEAD
repo.updateRef(Constants.HEAD).link("refs/heads/side"); repo.updateRef(Constants.HEAD).link("refs/heads/side");
gc.packRefs(); gc.packRefs();
assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE); assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
assertEquals(repo.getRef("HEAD").getTarget().getObjectId(), assertEquals(repo.exactRef("HEAD").getTarget().getObjectId(),
second.getId()); second.getId());
} }
} }

49
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java

@ -857,6 +857,36 @@ public class RefDirectoryTest extends LocalDiskRepositoryTestCase {
assertNull("mising 1 due to cycle", r); assertNull("mising 1 due to cycle", r);
} }
@Test
public void testGetRef_CycleInSymbolicRef() throws IOException {
Ref r;
writeLooseRef("refs/1", "ref: refs/2\n");
writeLooseRef("refs/2", "ref: refs/3\n");
writeLooseRef("refs/3", "ref: refs/4\n");
writeLooseRef("refs/4", "ref: refs/5\n");
writeLooseRef("refs/5", "ref: refs/end\n");
writeLooseRef("refs/end", A);
r = refdir.getRef("1");
assertEquals("refs/1", r.getName());
assertEquals(A, r.getObjectId());
assertTrue(r.isSymbolic());
writeLooseRef("refs/5", "ref: refs/6\n");
writeLooseRef("refs/6", "ref: refs/end\n");
r = refdir.getRef("1");
assertNull("missing 1 due to cycle", r);
writeLooseRef("refs/heads/1", B);
r = refdir.getRef("1");
assertEquals("refs/heads/1", r.getName());
assertEquals(B, r.getObjectId());
assertFalse(r.isSymbolic());
}
@Test @Test
public void testGetRefs_PackedNotPeeled_Sorted() throws IOException { public void testGetRefs_PackedNotPeeled_Sorted() throws IOException {
Map<String, Ref> all; Map<String, Ref> all;
@ -1024,6 +1054,25 @@ public class RefDirectoryTest extends LocalDiskRepositoryTestCase {
assertNull(refdir.getRef("v1.0")); assertNull(refdir.getRef("v1.0"));
} }
@Test
public void testExactRef_EmptyDatabase() throws IOException {
Ref r;
r = refdir.exactRef(HEAD);
assertTrue(r.isSymbolic());
assertSame(LOOSE, r.getStorage());
assertEquals("refs/heads/master", r.getTarget().getName());
assertSame(NEW, r.getTarget().getStorage());
assertNull(r.getTarget().getObjectId());
assertNull(refdir.exactRef("refs/heads/master"));
assertNull(refdir.exactRef("refs/tags/v1.0"));
assertNull(refdir.exactRef("FETCH_HEAD"));
assertNull(refdir.exactRef("NOT.A.REF.NAME"));
assertNull(refdir.exactRef("master"));
assertNull(refdir.exactRef("v1.0"));
}
@Test @Test
public void testGetRef_FetchHead() throws IOException { public void testGetRef_FetchHead() throws IOException {
// This is an odd special case where we need to make sure we read // This is an odd special case where we need to make sure we read

8
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java

@ -347,7 +347,7 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase {
Result update = updateRef.update(); Result update = updateRef.update();
assertEquals(Result.FORCED, update); assertEquals(Result.FORCED, update);
assertEquals(ppid, db.resolve("HEAD")); assertEquals(ppid, db.resolve("HEAD"));
Ref ref = db.getRef("HEAD"); Ref ref = db.exactRef("HEAD");
assertEquals("HEAD", ref.getName()); assertEquals("HEAD", ref.getName());
assertTrue("is detached", !ref.isSymbolic()); assertTrue("is detached", !ref.isSymbolic());
@ -377,7 +377,7 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase {
Result update = updateRef.update(); Result update = updateRef.update();
assertEquals(Result.NEW, update); assertEquals(Result.NEW, update);
assertEquals(ppid, db.resolve("HEAD")); assertEquals(ppid, db.resolve("HEAD"));
Ref ref = db.getRef("HEAD"); Ref ref = db.exactRef("HEAD");
assertEquals("HEAD", ref.getName()); assertEquals("HEAD", ref.getName());
assertTrue("is detached", !ref.isSymbolic()); assertTrue("is detached", !ref.isSymbolic());
@ -681,13 +681,13 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase {
public void testRenameBranchAlsoInPack() throws IOException { public void testRenameBranchAlsoInPack() throws IOException {
ObjectId rb = db.resolve("refs/heads/b"); ObjectId rb = db.resolve("refs/heads/b");
ObjectId rb2 = db.resolve("refs/heads/b~1"); ObjectId rb2 = db.resolve("refs/heads/b~1");
assertEquals(Ref.Storage.PACKED, db.getRef("refs/heads/b").getStorage()); assertEquals(Ref.Storage.PACKED, db.exactRef("refs/heads/b").getStorage());
RefUpdate updateRef = db.updateRef("refs/heads/b"); RefUpdate updateRef = db.updateRef("refs/heads/b");
updateRef.setNewObjectId(rb2); updateRef.setNewObjectId(rb2);
updateRef.setForceUpdate(true); updateRef.setForceUpdate(true);
Result update = updateRef.update(); Result update = updateRef.update();
assertEquals("internal check new ref is loose", Result.FORCED, update); assertEquals("internal check new ref is loose", Result.FORCED, update);
assertEquals(Ref.Storage.LOOSE, db.getRef("refs/heads/b").getStorage()); assertEquals(Ref.Storage.LOOSE, db.exactRef("refs/heads/b").getStorage());
writeReflog(db, rb, "Just a message", "refs/heads/b"); writeReflog(db, rb, "Just a message", "refs/heads/b");
assertTrue("log on old branch", new File(db.getDirectory(), assertTrue("log on old branch", new File(db.getDirectory(),
"logs/refs/heads/b").exists()); "logs/refs/heads/b").exists());

40
org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java

@ -127,25 +127,25 @@ public class TestRepositoryTest {
@Test @Test
public void resetFromSymref() throws Exception { public void resetFromSymref() throws Exception {
repo.updateRef("HEAD").link("refs/heads/master"); repo.updateRef("HEAD").link("refs/heads/master");
Ref head = repo.getRef("HEAD"); Ref head = repo.exactRef("HEAD");
RevCommit master = tr.branch("master").commit().create(); RevCommit master = tr.branch("master").commit().create();
RevCommit branch = tr.branch("branch").commit().create(); RevCommit branch = tr.branch("branch").commit().create();
RevCommit detached = tr.commit().create(); RevCommit detached = tr.commit().create();
assertTrue(head.isSymbolic()); assertTrue(head.isSymbolic());
assertEquals("refs/heads/master", head.getTarget().getName()); assertEquals("refs/heads/master", head.getTarget().getName());
assertEquals(master, repo.getRef("refs/heads/master").getObjectId()); assertEquals(master, repo.exactRef("refs/heads/master").getObjectId());
assertEquals(branch, repo.getRef("refs/heads/branch").getObjectId()); assertEquals(branch, repo.exactRef("refs/heads/branch").getObjectId());
// Reset to branches preserves symref. // Reset to branches preserves symref.
tr.reset("master"); tr.reset("master");
head = repo.getRef("HEAD"); head = repo.exactRef("HEAD");
assertEquals(master, head.getObjectId()); assertEquals(master, head.getObjectId());
assertTrue(head.isSymbolic()); assertTrue(head.isSymbolic());
assertEquals("refs/heads/master", head.getTarget().getName()); assertEquals("refs/heads/master", head.getTarget().getName());
tr.reset("branch"); tr.reset("branch");
head = repo.getRef("HEAD"); head = repo.exactRef("HEAD");
assertEquals(branch, head.getObjectId()); assertEquals(branch, head.getObjectId());
assertTrue(head.isSymbolic()); assertTrue(head.isSymbolic());
assertEquals("refs/heads/master", head.getTarget().getName()); assertEquals("refs/heads/master", head.getTarget().getName());
@ -153,50 +153,50 @@ public class TestRepositoryTest {
// Reset to a SHA-1 detaches. // Reset to a SHA-1 detaches.
tr.reset(detached); tr.reset(detached);
head = repo.getRef("HEAD"); head = repo.exactRef("HEAD");
assertEquals(detached, head.getObjectId()); assertEquals(detached, head.getObjectId());
assertFalse(head.isSymbolic()); assertFalse(head.isSymbolic());
tr.reset(detached.name()); tr.reset(detached.name());
head = repo.getRef("HEAD"); head = repo.exactRef("HEAD");
assertEquals(detached, head.getObjectId()); assertEquals(detached, head.getObjectId());
assertFalse(head.isSymbolic()); assertFalse(head.isSymbolic());
// Reset back to a branch remains detached. // Reset back to a branch remains detached.
tr.reset("master"); tr.reset("master");
head = repo.getRef("HEAD"); head = repo.exactRef("HEAD");
assertEquals(lastHeadBeforeDetach, head.getObjectId()); assertEquals(lastHeadBeforeDetach, head.getObjectId());
assertFalse(head.isSymbolic()); assertFalse(head.isSymbolic());
} }
@Test @Test
public void resetFromDetachedHead() throws Exception { public void resetFromDetachedHead() throws Exception {
Ref head = repo.getRef("HEAD"); Ref head = repo.exactRef("HEAD");
RevCommit master = tr.branch("master").commit().create(); RevCommit master = tr.branch("master").commit().create();
RevCommit branch = tr.branch("branch").commit().create(); RevCommit branch = tr.branch("branch").commit().create();
RevCommit detached = tr.commit().create(); RevCommit detached = tr.commit().create();
assertNull(head); assertNull(head);
assertEquals(master, repo.getRef("refs/heads/master").getObjectId()); assertEquals(master, repo.exactRef("refs/heads/master").getObjectId());
assertEquals(branch, repo.getRef("refs/heads/branch").getObjectId()); assertEquals(branch, repo.exactRef("refs/heads/branch").getObjectId());
tr.reset("master"); tr.reset("master");
head = repo.getRef("HEAD"); head = repo.exactRef("HEAD");
assertEquals(master, head.getObjectId()); assertEquals(master, head.getObjectId());
assertFalse(head.isSymbolic()); assertFalse(head.isSymbolic());
tr.reset("branch"); tr.reset("branch");
head = repo.getRef("HEAD"); head = repo.exactRef("HEAD");
assertEquals(branch, head.getObjectId()); assertEquals(branch, head.getObjectId());
assertFalse(head.isSymbolic()); assertFalse(head.isSymbolic());
tr.reset(detached); tr.reset(detached);
head = repo.getRef("HEAD"); head = repo.exactRef("HEAD");
assertEquals(detached, head.getObjectId()); assertEquals(detached, head.getObjectId());
assertFalse(head.isSymbolic()); assertFalse(head.isSymbolic());
tr.reset(detached.name()); tr.reset(detached.name());
head = repo.getRef("HEAD"); head = repo.exactRef("HEAD");
assertEquals(detached, head.getObjectId()); assertEquals(detached, head.getObjectId());
assertFalse(head.isSymbolic()); assertFalse(head.isSymbolic());
} }
@ -222,7 +222,7 @@ public class TestRepositoryTest {
.tick(3) .tick(3)
.add("bar", "fixed bar contents") .add("bar", "fixed bar contents")
.create(); .create();
assertEquals(amended, repo.getRef("refs/heads/master").getObjectId()); assertEquals(amended, repo.exactRef("refs/heads/master").getObjectId());
rw.parseBody(amended); rw.parseBody(amended);
assertEquals(1, amended.getParentCount()); assertEquals(1, amended.getParentCount());
@ -257,7 +257,7 @@ public class TestRepositoryTest {
.add("foo", "fixed foo contents") .add("foo", "fixed foo contents")
.create(); .create();
Ref head = repo.getRef(Constants.HEAD); Ref head = repo.exactRef(Constants.HEAD);
assertEquals(amended, head.getObjectId()); assertEquals(amended, head.getObjectId());
assertTrue(head.isSymbolic()); assertTrue(head.isSymbolic());
assertEquals("refs/heads/master", head.getTarget().getName()); assertEquals("refs/heads/master", head.getTarget().getName());
@ -291,7 +291,7 @@ public class TestRepositoryTest {
public void commitToUnbornHead() throws Exception { public void commitToUnbornHead() throws Exception {
repo.updateRef("HEAD").link("refs/heads/master"); repo.updateRef("HEAD").link("refs/heads/master");
RevCommit root = tr.branch("HEAD").commit().create(); RevCommit root = tr.branch("HEAD").commit().create();
Ref ref = repo.getRef(Constants.HEAD); Ref ref = repo.exactRef(Constants.HEAD);
assertEquals(root, ref.getObjectId()); assertEquals(root, ref.getObjectId());
assertTrue(ref.isSymbolic()); assertTrue(ref.isSymbolic());
assertEquals("refs/heads/master", ref.getTarget().getName()); assertEquals("refs/heads/master", ref.getTarget().getName());
@ -316,7 +316,7 @@ public class TestRepositoryTest {
RevCommit result = tr.cherryPick(toPick); RevCommit result = tr.cherryPick(toPick);
rw.parseBody(result); rw.parseBody(result);
Ref headRef = tr.getRepository().getRef("HEAD"); Ref headRef = tr.getRepository().exactRef("HEAD");
assertEquals(result, headRef.getObjectId()); assertEquals(result, headRef.getObjectId());
assertTrue(headRef.isSymbolic()); assertTrue(headRef.isSymbolic());
assertEquals("refs/heads/master", headRef.getLeaf().getName()); assertEquals("refs/heads/master", headRef.getLeaf().getName());
@ -371,7 +371,7 @@ public class TestRepositoryTest {
.create(); .create();
assertNotEquals(head, toPick); assertNotEquals(head, toPick);
assertNull(tr.cherryPick(toPick)); assertNull(tr.cherryPick(toPick));
assertEquals(head, repo.getRef("HEAD").getObjectId()); assertEquals(head, repo.exactRef("HEAD").getObjectId());
} }
private String blobAsString(AnyObjectId treeish, String path) private String blobAsString(AnyObjectId treeish, String path)

13
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java

@ -79,6 +79,7 @@ import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.FileUtils;
import org.junit.Assume;
import org.junit.Test; import org.junit.Test;
public class DirCacheCheckoutTest extends RepositoryTestCase { public class DirCacheCheckoutTest extends RepositoryTestCase {
@ -112,7 +113,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
return dco.getRemoved(); return dco.getRemoved();
} }
private Map<String, ObjectId> getUpdated() { private Map<String, String> getUpdated() {
return dco.getUpdated(); return dco.getUpdated();
} }
@ -267,8 +268,6 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
@Test @Test
public void testRules1thru3_NoIndexEntry() throws IOException { public void testRules1thru3_NoIndexEntry() throws IOException {
ObjectId head = buildTree(mk("foo")); ObjectId head = buildTree(mk("foo"));
TreeWalk tw = TreeWalk.forPath(db, "foo", head);
ObjectId objectId = tw.getObjectId(0);
ObjectId merge = db.newObjectInserter().insert(Constants.OBJ_TREE, ObjectId merge = db.newObjectInserter().insert(Constants.OBJ_TREE,
new byte[0]); new byte[0]);
@ -278,10 +277,9 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
prescanTwoTrees(merge, head); prescanTwoTrees(merge, head);
assertEquals(objectId, getUpdated().get("foo")); assertTrue(getUpdated().containsKey("foo"));
merge = buildTree(mkmap("foo", "a")); merge = buildTree(mkmap("foo", "a"));
tw = TreeWalk.forPath(db, "foo", merge);
prescanTwoTrees(head, merge); prescanTwoTrees(head, merge);
@ -925,6 +923,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
@Test @Test
public void testCheckoutChangeLinkToEmptyDir() throws Exception { public void testCheckoutChangeLinkToEmptyDir() throws Exception {
Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
String fname = "was_file"; String fname = "was_file";
Git git = Git.wrap(db); Git git = Git.wrap(db);
@ -961,6 +960,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
@Test @Test
public void testCheckoutChangeLinkToEmptyDirs() throws Exception { public void testCheckoutChangeLinkToEmptyDirs() throws Exception {
Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
String fname = "was_file"; String fname = "was_file";
Git git = Git.wrap(db); Git git = Git.wrap(db);
@ -999,6 +999,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
@Test @Test
public void testCheckoutChangeLinkToNonEmptyDirs() throws Exception { public void testCheckoutChangeLinkToNonEmptyDirs() throws Exception {
Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
String fname = "file"; String fname = "file";
Git git = Git.wrap(db); Git git = Git.wrap(db);
@ -1043,6 +1044,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
@Test @Test
public void testCheckoutChangeLinkToNonEmptyDirsAndNewIndexEntry() public void testCheckoutChangeLinkToNonEmptyDirsAndNewIndexEntry()
throws Exception { throws Exception {
Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
String fname = "file"; String fname = "file";
Git git = Git.wrap(db); Git git = Git.wrap(db);
@ -1364,6 +1366,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
@Test @Test
public void testOverwriteUntrackedLinkModeChange() public void testOverwriteUntrackedLinkModeChange()
throws Exception { throws Exception {
Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
String fname = "file.txt"; String fname = "file.txt";
Git git = Git.wrap(db); Git git = Git.wrap(db);

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java

@ -87,7 +87,7 @@ public class IndexDiffSubmoduleTest extends RepositoryTestCase {
.call(); .call();
submodule_db = (FileRepository) Git.wrap(db).submoduleAdd() submodule_db = (FileRepository) Git.wrap(db).submoduleAdd()
.setPath("submodule") .setPath("modules/submodule")
.setURI(submoduleStandalone.getDirectory().toURI().toString()) .setURI(submoduleStandalone.getDirectory().toURI().toString())
.call(); .call();
submoduleStandalone.close(); submoduleStandalone.close();

24
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java

@ -163,7 +163,7 @@ public class RefTest extends SampleDataRepositoryTestCase {
@Test @Test
public void testReadSymRefToPacked() throws IOException { public void testReadSymRefToPacked() throws IOException {
writeSymref("HEAD", "refs/heads/b"); writeSymref("HEAD", "refs/heads/b");
Ref ref = db.getRef("HEAD"); Ref ref = db.exactRef("HEAD");
assertEquals(Ref.Storage.LOOSE, ref.getStorage()); assertEquals(Ref.Storage.LOOSE, ref.getStorage());
assertTrue("is symref", ref.isSymbolic()); assertTrue("is symref", ref.isSymbolic());
ref = ref.getTarget(); ref = ref.getTarget();
@ -181,7 +181,7 @@ public class RefTest extends SampleDataRepositoryTestCase {
assertEquals(Result.FORCED, update); // internal assertEquals(Result.FORCED, update); // internal
writeSymref("HEAD", "refs/heads/master"); writeSymref("HEAD", "refs/heads/master");
Ref ref = db.getRef("HEAD"); Ref ref = db.exactRef("HEAD");
assertEquals(Ref.Storage.LOOSE, ref.getStorage()); assertEquals(Ref.Storage.LOOSE, ref.getStorage());
ref = ref.getTarget(); ref = ref.getTarget();
assertEquals("refs/heads/master", ref.getName()); assertEquals("refs/heads/master", ref.getName());
@ -194,13 +194,13 @@ public class RefTest extends SampleDataRepositoryTestCase {
updateRef.setNewObjectId(db.resolve("refs/heads/master")); updateRef.setNewObjectId(db.resolve("refs/heads/master"));
Result update = updateRef.update(); Result update = updateRef.update();
assertEquals(Result.NEW, update); assertEquals(Result.NEW, update);
Ref ref = db.getRef("ref/heads/new"); Ref ref = db.exactRef("ref/heads/new");
assertEquals(Storage.LOOSE, ref.getStorage()); assertEquals(Storage.LOOSE, ref.getStorage());
} }
@Test @Test
public void testGetShortRef() throws IOException { public void testGetShortRef() throws IOException {
Ref ref = db.getRef("master"); Ref ref = db.exactRef("refs/heads/master");
assertEquals("refs/heads/master", ref.getName()); assertEquals("refs/heads/master", ref.getName());
assertEquals(db.resolve("refs/heads/master"), ref.getObjectId()); assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
} }
@ -222,7 +222,7 @@ public class RefTest extends SampleDataRepositoryTestCase {
assertNull(db.getRefDatabase().exactRef("refs/foo/bar")); assertNull(db.getRefDatabase().exactRef("refs/foo/bar"));
Ref ref = db.getRef("refs/foo/bar"); Ref ref = db.findRef("refs/foo/bar");
assertEquals("refs/heads/refs/foo/bar", ref.getName()); assertEquals("refs/heads/refs/foo/bar", ref.getName());
assertEquals(db.resolve("refs/heads/master"), ref.getObjectId()); assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
} }
@ -237,7 +237,7 @@ public class RefTest extends SampleDataRepositoryTestCase {
assertEquals("refs/foo/bar", exactRef.getName()); assertEquals("refs/foo/bar", exactRef.getName());
assertEquals(masterId, exactRef.getObjectId()); assertEquals(masterId, exactRef.getObjectId());
Ref ref = db.getRef("refs/foo/bar"); Ref ref = db.findRef("refs/foo/bar");
assertEquals("refs/foo/bar", ref.getName()); assertEquals("refs/foo/bar", ref.getName());
assertEquals(masterId, ref.getObjectId()); assertEquals(masterId, ref.getObjectId());
} }
@ -251,7 +251,7 @@ public class RefTest extends SampleDataRepositoryTestCase {
@Test @Test
public void testReadLoosePackedRef() throws IOException, public void testReadLoosePackedRef() throws IOException,
InterruptedException { InterruptedException {
Ref ref = db.getRef("refs/heads/master"); Ref ref = db.exactRef("refs/heads/master");
assertEquals(Storage.PACKED, ref.getStorage()); assertEquals(Storage.PACKED, ref.getStorage());
FileOutputStream os = new FileOutputStream(new File(db.getDirectory(), FileOutputStream os = new FileOutputStream(new File(db.getDirectory(),
"refs/heads/master")); "refs/heads/master"));
@ -259,7 +259,7 @@ public class RefTest extends SampleDataRepositoryTestCase {
os.write('\n'); os.write('\n');
os.close(); os.close();
ref = db.getRef("refs/heads/master"); ref = db.exactRef("refs/heads/master");
assertEquals(Storage.LOOSE, ref.getStorage()); assertEquals(Storage.LOOSE, ref.getStorage());
} }
@ -271,7 +271,7 @@ public class RefTest extends SampleDataRepositoryTestCase {
*/ */
@Test @Test
public void testReadSimplePackedRefSameRepo() throws IOException { public void testReadSimplePackedRefSameRepo() throws IOException {
Ref ref = db.getRef("refs/heads/master"); Ref ref = db.exactRef("refs/heads/master");
ObjectId pid = db.resolve("refs/heads/master^"); ObjectId pid = db.resolve("refs/heads/master^");
assertEquals(Storage.PACKED, ref.getStorage()); assertEquals(Storage.PACKED, ref.getStorage());
RefUpdate updateRef = db.updateRef("refs/heads/master"); RefUpdate updateRef = db.updateRef("refs/heads/master");
@ -280,19 +280,19 @@ public class RefTest extends SampleDataRepositoryTestCase {
Result update = updateRef.update(); Result update = updateRef.update();
assertEquals(Result.FORCED, update); assertEquals(Result.FORCED, update);
ref = db.getRef("refs/heads/master"); ref = db.exactRef("refs/heads/master");
assertEquals(Storage.LOOSE, ref.getStorage()); assertEquals(Storage.LOOSE, ref.getStorage());
} }
@Test @Test
public void testResolvedNamesBranch() throws IOException { public void testResolvedNamesBranch() throws IOException {
Ref ref = db.getRef("a"); Ref ref = db.findRef("a");
assertEquals("refs/heads/a", ref.getName()); assertEquals("refs/heads/a", ref.getName());
} }
@Test @Test
public void testResolvedSymRef() throws IOException { public void testResolvedSymRef() throws IOException {
Ref ref = db.getRef(Constants.HEAD); Ref ref = db.exactRef(Constants.HEAD);
assertEquals(Constants.HEAD, ref.getName()); assertEquals(Constants.HEAD, ref.getName());
assertTrue("is symbolic ref", ref.isSymbolic()); assertTrue("is symbolic ref", ref.isSymbolic());
assertSame(Ref.Storage.LOOSE, ref.getStorage()); assertSame(Ref.Storage.LOOSE, ref.getStorage());

48
org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java

@ -84,44 +84,44 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase {
@Test @Test
public void testOneBranch() throws IOException { public void testOneBranch() throws IOException {
Ref a = db.getRef("refs/heads/a"); Ref a = db.exactRef("refs/heads/a");
Ref master = db.getRef("refs/heads/master"); Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(a), master); String message = formatter.format(Arrays.asList(a), master);
assertEquals("Merge branch 'a'", message); assertEquals("Merge branch 'a'", message);
} }
@Test @Test
public void testTwoBranches() throws IOException { public void testTwoBranches() throws IOException {
Ref a = db.getRef("refs/heads/a"); Ref a = db.exactRef("refs/heads/a");
Ref b = db.getRef("refs/heads/b"); Ref b = db.exactRef("refs/heads/b");
Ref master = db.getRef("refs/heads/master"); Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(a, b), master); String message = formatter.format(Arrays.asList(a, b), master);
assertEquals("Merge branches 'a' and 'b'", message); assertEquals("Merge branches 'a' and 'b'", message);
} }
@Test @Test
public void testThreeBranches() throws IOException { public void testThreeBranches() throws IOException {
Ref c = db.getRef("refs/heads/c"); Ref c = db.exactRef("refs/heads/c");
Ref b = db.getRef("refs/heads/b"); Ref b = db.exactRef("refs/heads/b");
Ref a = db.getRef("refs/heads/a"); Ref a = db.exactRef("refs/heads/a");
Ref master = db.getRef("refs/heads/master"); Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(c, b, a), master); String message = formatter.format(Arrays.asList(c, b, a), master);
assertEquals("Merge branches 'c', 'b' and 'a'", message); assertEquals("Merge branches 'c', 'b' and 'a'", message);
} }
@Test @Test
public void testRemoteBranch() throws Exception { public void testRemoteBranch() throws Exception {
Ref remoteA = db.getRef("refs/remotes/origin/remote-a"); Ref remoteA = db.exactRef("refs/remotes/origin/remote-a");
Ref master = db.getRef("refs/heads/master"); Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(remoteA), master); String message = formatter.format(Arrays.asList(remoteA), master);
assertEquals("Merge remote-tracking branch 'origin/remote-a'", message); assertEquals("Merge remote-tracking branch 'origin/remote-a'", message);
} }
@Test @Test
public void testMixed() throws IOException { public void testMixed() throws IOException {
Ref c = db.getRef("refs/heads/c"); Ref c = db.exactRef("refs/heads/c");
Ref remoteA = db.getRef("refs/remotes/origin/remote-a"); Ref remoteA = db.exactRef("refs/remotes/origin/remote-a");
Ref master = db.getRef("refs/heads/master"); Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(c, remoteA), master); String message = formatter.format(Arrays.asList(c, remoteA), master);
assertEquals("Merge branch 'c', remote-tracking branch 'origin/remote-a'", assertEquals("Merge branch 'c', remote-tracking branch 'origin/remote-a'",
message); message);
@ -129,8 +129,8 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase {
@Test @Test
public void testTag() throws IOException { public void testTag() throws IOException {
Ref tagA = db.getRef("refs/tags/A"); Ref tagA = db.exactRef("refs/tags/A");
Ref master = db.getRef("refs/heads/master"); Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(tagA), master); String message = formatter.format(Arrays.asList(tagA), master);
assertEquals("Merge tag 'A'", message); assertEquals("Merge tag 'A'", message);
} }
@ -141,7 +141,7 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase {
.fromString("6db9c2ebf75590eef973081736730a9ea169a0c4"); .fromString("6db9c2ebf75590eef973081736730a9ea169a0c4");
Ref commit = new ObjectIdRef.Unpeeled(Storage.LOOSE, Ref commit = new ObjectIdRef.Unpeeled(Storage.LOOSE,
objectId.getName(), objectId); objectId.getName(), objectId);
Ref master = db.getRef("refs/heads/master"); Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(commit), master); String message = formatter.format(Arrays.asList(commit), master);
assertEquals("Merge commit '6db9c2ebf75590eef973081736730a9ea169a0c4'", assertEquals("Merge commit '6db9c2ebf75590eef973081736730a9ea169a0c4'",
message); message);
@ -154,7 +154,7 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase {
.fromString("6db9c2ebf75590eef973081736730a9ea169a0c4"); .fromString("6db9c2ebf75590eef973081736730a9ea169a0c4");
Ref remoteBranch = new ObjectIdRef.Unpeeled(Storage.LOOSE, name, Ref remoteBranch = new ObjectIdRef.Unpeeled(Storage.LOOSE, name,
objectId); objectId);
Ref master = db.getRef("refs/heads/master"); Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(remoteBranch), master); String message = formatter.format(Arrays.asList(remoteBranch), master);
assertEquals("Merge branch 'test' of http://egit.eclipse.org/jgit.git", assertEquals("Merge branch 'test' of http://egit.eclipse.org/jgit.git",
message); message);
@ -162,16 +162,16 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase {
@Test @Test
public void testIntoOtherThanMaster() throws IOException { public void testIntoOtherThanMaster() throws IOException {
Ref a = db.getRef("refs/heads/a"); Ref a = db.exactRef("refs/heads/a");
Ref b = db.getRef("refs/heads/b"); Ref b = db.exactRef("refs/heads/b");
String message = formatter.format(Arrays.asList(a), b); String message = formatter.format(Arrays.asList(a), b);
assertEquals("Merge branch 'a' into b", message); assertEquals("Merge branch 'a' into b", message);
} }
@Test @Test
public void testIntoHeadOtherThanMaster() throws IOException { public void testIntoHeadOtherThanMaster() throws IOException {
Ref a = db.getRef("refs/heads/a"); Ref a = db.exactRef("refs/heads/a");
Ref b = db.getRef("refs/heads/b"); Ref b = db.exactRef("refs/heads/b");
SymbolicRef head = new SymbolicRef("HEAD", b); SymbolicRef head = new SymbolicRef("HEAD", b);
String message = formatter.format(Arrays.asList(a), head); String message = formatter.format(Arrays.asList(a), head);
assertEquals("Merge branch 'a' into b", message); assertEquals("Merge branch 'a' into b", message);
@ -179,8 +179,8 @@ public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase {
@Test @Test
public void testIntoSymbolicRefHeadPointingToMaster() throws IOException { public void testIntoSymbolicRefHeadPointingToMaster() throws IOException {
Ref a = db.getRef("refs/heads/a"); Ref a = db.exactRef("refs/heads/a");
Ref master = db.getRef("refs/heads/master"); Ref master = db.exactRef("refs/heads/master");
SymbolicRef head = new SymbolicRef("HEAD", master); SymbolicRef head = new SymbolicRef("HEAD", master);
String message = formatter.format(Arrays.asList(a), head); String message = formatter.format(Arrays.asList(a), head);
assertEquals("Merge branch 'a'", message); assertEquals("Merge branch 'a'", message);

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java

@ -630,7 +630,7 @@ public class ResolveMergerTest extends RepositoryTestCase {
// ResolveMerge // ResolveMerge
try { try {
MergeResult mergeResult = git.merge().setStrategy(strategy) MergeResult mergeResult = git.merge().setStrategy(strategy)
.include(git.getRepository().getRef("refs/heads/side")) .include(git.getRepository().exactRef("refs/heads/side"))
.call(); .call();
assertEquals(MergeStrategy.RECURSIVE, strategy); assertEquals(MergeStrategy.RECURSIVE, strategy);
assertEquals(MergeResult.MergeStatus.MERGED, assertEquals(MergeResult.MergeStatus.MERGED,

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SquashMessageFormatterTest.java

@ -76,7 +76,7 @@ public class SquashMessageFormatterTest extends SampleDataRepositoryTestCase {
Git git = new Git(db); Git git = new Git(db);
revCommit = git.commit().setMessage("squash_me").call(); revCommit = git.commit().setMessage("squash_me").call();
Ref master = db.getRef("refs/heads/master"); Ref master = db.exactRef("refs/heads/master");
String message = msgFormatter.format(Arrays.asList(revCommit), master); String message = msgFormatter.format(Arrays.asList(revCommit), master);
assertEquals( assertEquals(
"Squashed commit of the following:\n\ncommit " "Squashed commit of the following:\n\ncommit "

200
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java

@ -0,0 +1,200 @@
/*
* Copyright (C) 2015, Google Inc.
* 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.transport;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class AtomicPushTest {
private URIish uri;
private TestProtocol<Object> testProtocol;
private Object ctx = new Object();
private InMemoryRepository server;
private InMemoryRepository client;
private ObjectId obj1;
private ObjectId obj2;
@Before
public void setUp() throws Exception {
server = newRepo("server");
client = newRepo("client");
testProtocol = new TestProtocol<>(
null,
new ReceivePackFactory<Object>() {
@Override
public ReceivePack create(Object req, Repository db)
throws ServiceNotEnabledException,
ServiceNotAuthorizedException {
return new ReceivePack(db);
}
});
uri = testProtocol.register(ctx, server);
try (ObjectInserter ins = client.newObjectInserter()) {
obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test"));
obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file"));
ins.flush();
}
}
@After
public void tearDown() {
Transport.unregister(testProtocol);
}
private static InMemoryRepository newRepo(String name) {
return new InMemoryRepository(new DfsRepositoryDescription(name));
}
@Test
public void pushNonAtomic() throws Exception {
PushResult r;
server.setPerformsAtomicTransactions(false);
Transport tn = testProtocol.open(uri, client, "server");
try {
tn.setPushAtomic(false);
r = tn.push(NullProgressMonitor.INSTANCE, commands());
} finally {
tn.close();
}
RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
assertSame(RemoteRefUpdate.Status.OK, one.getStatus());
assertSame(
RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
two.getStatus());
}
@Test
public void pushAtomicClientGivesUpEarly() throws Exception {
PushResult r;
Transport tn = testProtocol.open(uri, client, "server");
try {
tn.setPushAtomic(true);
r = tn.push(NullProgressMonitor.INSTANCE, commands());
} finally {
tn.close();
}
RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
assertSame(
RemoteRefUpdate.Status.REJECTED_OTHER_REASON,
one.getStatus());
assertSame(
RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
two.getStatus());
assertEquals(JGitText.get().transactionAborted, one.getMessage());
}
@Test
public void pushAtomicDisabled() throws Exception {
List<RemoteRefUpdate> cmds = new ArrayList<>();
cmds.add(new RemoteRefUpdate(
null, null,
obj1, "refs/heads/one",
true /* force update */,
null /* no local tracking ref */,
ObjectId.zeroId()));
cmds.add(new RemoteRefUpdate(
null, null,
obj2, "refs/heads/two",
true /* force update */,
null /* no local tracking ref */,
ObjectId.zeroId()));
server.setPerformsAtomicTransactions(false);
Transport tn = testProtocol.open(uri, client, "server");
try {
tn.setPushAtomic(true);
tn.push(NullProgressMonitor.INSTANCE, cmds);
fail("did not throw TransportException");
} catch (TransportException e) {
assertEquals(
uri + ": " + JGitText.get().atomicPushNotSupported,
e.getMessage());
} finally {
tn.close();
}
}
private List<RemoteRefUpdate> commands() throws IOException {
List<RemoteRefUpdate> cmds = new ArrayList<>();
cmds.add(new RemoteRefUpdate(
null, null,
obj1, "refs/heads/one",
true /* force update */,
null /* no local tracking ref */,
ObjectId.zeroId()));
cmds.add(new RemoteRefUpdate(
null, null,
obj2, "refs/heads/two",
true /* force update */,
null /* no local tracking ref */,
obj1));
return cmds;
}
}

143
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java

@ -0,0 +1,143 @@
/*
* Copyright (C) 2015, Google Inc.
* 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.transport;
import static org.eclipse.jgit.transport.RemoteRefUpdate.Status.REJECTED_OTHER_REASON;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class PushConnectionTest {
private URIish uri;
private TestProtocol<Object> testProtocol;
private Object ctx = new Object();
private InMemoryRepository server;
private InMemoryRepository client;
private ObjectId obj1;
private ObjectId obj2;
private ObjectId obj3;
private String refName = "refs/tags/blob";
@Before
public void setUp() throws Exception {
server = newRepo("server");
client = newRepo("client");
testProtocol = new TestProtocol<>(
null,
new ReceivePackFactory<Object>() {
@Override
public ReceivePack create(Object req, Repository db)
throws ServiceNotEnabledException,
ServiceNotAuthorizedException {
return new ReceivePack(db);
}
});
uri = testProtocol.register(ctx, server);
try (ObjectInserter ins = server.newObjectInserter()) {
obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test"));
obj3 = ins.insert(Constants.OBJ_BLOB, Constants.encode("not"));
ins.flush();
RefUpdate u = server.updateRef(refName);
u.setNewObjectId(obj1);
assertEquals(RefUpdate.Result.NEW, u.update());
}
try (ObjectInserter ins = client.newObjectInserter()) {
obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file"));
ins.flush();
}
}
@After
public void tearDown() {
Transport.unregister(testProtocol);
}
private static InMemoryRepository newRepo(String name) {
return new InMemoryRepository(new DfsRepositoryDescription(name));
}
@Test
public void testWrongOldIdDoesNotReplace() throws IOException {
RemoteRefUpdate rru = new RemoteRefUpdate(null, null, obj2, refName,
false, null, obj3);
Map<String, RemoteRefUpdate> updates = new HashMap<>();
updates.put(rru.getRemoteName(), rru);
Transport tn = testProtocol.open(uri, client, "server");
try {
PushConnection connection = tn.openPush();
try {
connection.push(NullProgressMonitor.INSTANCE, updates);
} finally {
connection.close();
}
} finally {
tn.close();
}
assertEquals(REJECTED_OTHER_REASON, rru.getStatus());
assertEquals("invalid old id sent", rru.getMessage());
}
}

12
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java

@ -125,7 +125,7 @@ public class TestProtocolTest {
.setRefSpecs(HEADS) .setRefSpecs(HEADS)
.call(); .call();
assertEquals(master, assertEquals(master,
local.getRepository().getRef("master").getObjectId()); local.getRepository().exactRef("refs/heads/master").getObjectId());
} }
} }
@ -142,7 +142,7 @@ public class TestProtocolTest {
.setRefSpecs(HEADS) .setRefSpecs(HEADS)
.call(); .call();
assertEquals(master, assertEquals(master,
remote.getRepository().getRef("master").getObjectId()); remote.getRepository().exactRef("refs/heads/master").getObjectId());
} }
} }
@ -177,7 +177,7 @@ public class TestProtocolTest {
// Expected. // Expected.
} }
assertEquals(1, rejected.get()); assertEquals(1, rejected.get());
assertNull(local.getRepository().getRef("master")); assertNull(local.getRepository().exactRef("refs/heads/master"));
git.fetch() git.fetch()
.setRemote(user2Uri.toString()) .setRemote(user2Uri.toString())
@ -185,7 +185,7 @@ public class TestProtocolTest {
.call(); .call();
assertEquals(1, rejected.get()); assertEquals(1, rejected.get());
assertEquals(master, assertEquals(master,
local.getRepository().getRef("master").getObjectId()); local.getRepository().exactRef("refs/heads/master").getObjectId());
} }
} }
@ -222,7 +222,7 @@ public class TestProtocolTest {
JGitText.get().pushNotPermitted)); JGitText.get().pushNotPermitted));
} }
assertEquals(1, rejected.get()); assertEquals(1, rejected.get());
assertNull(remote.getRepository().getRef("master")); assertNull(remote.getRepository().exactRef("refs/heads/master"));
git.push() git.push()
.setRemote(user2Uri.toString()) .setRemote(user2Uri.toString())
@ -230,7 +230,7 @@ public class TestProtocolTest {
.call(); .call();
assertEquals(1, rejected.get()); assertEquals(1, rejected.get());
assertEquals(master, assertEquals(master,
remote.getRepository().getRef("master").getObjectId()); remote.getRepository().exactRef("refs/heads/master").getObjectId());
} }
} }

15
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java

@ -928,4 +928,19 @@ public class URIishTest {
} }
} }
} }
@Test
public void testStringConstructor() throws Exception {
String str = "http://example.com/";
URIish u = new URIish(str);
assertEquals("example.com", u.getHost());
assertEquals("/", u.getPath());
assertEquals(str, u.toString());
str = "http://example.com";
u = new URIish(str);
assertEquals("example.com", u.getHost());
assertEquals("", u.getPath());
assertEquals(str, u.toString());
}
} }

29
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java

@ -43,6 +43,20 @@
package org.eclipse.jgit.transport; package org.eclipse.jgit.transport;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.UTF_8;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.cryptoCipherListPBE;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.cryptoCipherListTrans;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.folderDelete;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.permitLongTests;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.policySetup;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.product;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.proxySetup;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.publicAddress;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.reportPolicy;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.securityProviderName;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.textWrite;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.transferStream;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.verifyFileContent;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
@ -59,7 +73,10 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.net.SocketTimeoutException;
import java.net.URL; import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.file.Files; import java.nio.file.Files;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
@ -94,8 +111,6 @@ import org.junit.runners.Suite;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.*;
/** /**
* Amazon S3 encryption pipeline test. * Amazon S3 encryption pipeline test.
* *
@ -401,15 +416,23 @@ public class WalkEncryptionTest {
* @throws Exception * @throws Exception
*/ */
static String publicAddress() throws Exception { static String publicAddress() throws Exception {
try {
String service = "http://checkip.amazonaws.com"; String service = "http://checkip.amazonaws.com";
URL url = new URL(service); URL url = new URL(service);
URLConnection c = url.openConnection();
c.setConnectTimeout(500);
c.setReadTimeout(500);
BufferedReader reader = new BufferedReader( BufferedReader reader = new BufferedReader(
new InputStreamReader(url.openStream())); new InputStreamReader(c.getInputStream()));
try { try {
return reader.readLine(); return reader.readLine();
} finally { } finally {
reader.close(); reader.close();
} }
} catch (UnknownHostException | SocketTimeoutException e) {
return "Can't reach http://checkip.amazonaws.com to"
+ " determine public address";
}
} }
/** /**

41
org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java

@ -43,6 +43,8 @@
package org.eclipse.jgit.treewalk; package org.eclipse.jgit.treewalk;
import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE;
import static org.eclipse.jgit.lib.FileMode.SYMLINK;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
@ -50,9 +52,11 @@ import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.TreeFormatter;
import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.RawParseUtils;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -369,4 +373,41 @@ public class CanonicalTreeParserTest {
assertEquals(name, RawParseUtils.decode(Constants.CHARSET, ctp.path, assertEquals(name, RawParseUtils.decode(Constants.CHARSET, ctp.path,
ctp.pathOffset, ctp.pathLen)); ctp.pathOffset, ctp.pathLen));
} }
@Test
public void testFindAttributesWhenFirst() throws CorruptObjectException {
TreeFormatter tree = new TreeFormatter();
tree.append(".gitattributes", REGULAR_FILE, hash_a);
ctp.reset(tree.toByteArray());
assertTrue(ctp.findFile(".gitattributes"));
assertEquals(REGULAR_FILE.getBits(), ctp.getEntryRawMode());
assertEquals(".gitattributes", ctp.getEntryPathString());
assertEquals(hash_a, ctp.getEntryObjectId());
}
@Test
public void testFindAttributesWhenSecond() throws CorruptObjectException {
TreeFormatter tree = new TreeFormatter();
tree.append(".config", SYMLINK, hash_a);
tree.append(".gitattributes", REGULAR_FILE, hash_foo);
ctp.reset(tree.toByteArray());
assertTrue(ctp.findFile(".gitattributes"));
assertEquals(REGULAR_FILE.getBits(), ctp.getEntryRawMode());
assertEquals(".gitattributes", ctp.getEntryPathString());
assertEquals(hash_foo, ctp.getEntryObjectId());
}
@Test
public void testFindAttributesWhenMissing() throws CorruptObjectException {
TreeFormatter tree = new TreeFormatter();
tree.append("src", REGULAR_FILE, hash_a);
tree.append("zoo", REGULAR_FILE, hash_foo);
ctp.reset(tree.toByteArray());
assertFalse(ctp.findFile(".gitattributes"));
assertEquals(11, ctp.idOffset()); // Did not walk the entire tree.
assertEquals("src", ctp.getEntryPathString());
}
} }

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java

@ -67,6 +67,7 @@ import org.junit.Test;
public class FileTreeIteratorJava7Test extends RepositoryTestCase { public class FileTreeIteratorJava7Test extends RepositoryTestCase {
@Test @Test
public void testFileModeSymLinkIsNotATree() throws IOException { public void testFileModeSymLinkIsNotATree() throws IOException {
org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
FS fs = db.getFS(); FS fs = db.getFS();
// mål = target in swedish, just to get som unicode in here // mål = target in swedish, just to get som unicode in here
writeTrashFile("mål/data", "targetdata"); writeTrashFile("mål/data", "targetdata");
@ -163,6 +164,7 @@ public class FileTreeIteratorJava7Test extends RepositoryTestCase {
*/ */
@Test @Test
public void testSymlinkActuallyModified() throws Exception { public void testSymlinkActuallyModified() throws Exception {
org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
final String NORMALIZED = "target"; final String NORMALIZED = "target";
final byte[] NORMALIZED_BYTES = Constants.encode(NORMALIZED); final byte[] NORMALIZED_BYTES = Constants.encode(NORMALIZED);
try (ObjectInserter oi = db.newObjectInserter()) { try (ObjectInserter oi = db.newObjectInserter()) {

1
org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java

@ -55,6 +55,7 @@ import org.junit.Test;
public class TreeWalkJava7Test extends RepositoryTestCase { public class TreeWalkJava7Test extends RepositoryTestCase {
@Test @Test
public void testSymlinkToDirNotRecursingViaSymlink() throws Exception { public void testSymlinkToDirNotRecursingViaSymlink() throws Exception {
org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
FS fs = db.getFS(); FS fs = db.getFS();
assertTrue(fs.supportsSymlinks()); assertTrue(fs.supportsSymlinks());
writeTrashFile("target/data", "targetdata"); writeTrashFile("target/data", "targetdata");

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java

@ -57,6 +57,7 @@ import java.util.Set;
import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.RepositoryTestCase;
import org.junit.After; import org.junit.After;
import org.junit.Assume;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -87,6 +88,7 @@ public class FSJava7Test {
*/ */
@Test @Test
public void testSymlinkAttributes() throws IOException, InterruptedException { public void testSymlinkAttributes() throws IOException, InterruptedException {
Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
FS fs = FS.DETECTED; FS fs = FS.DETECTED;
File link = new File(trash, "ä"); File link = new File(trash, "ä");
File target = new File(trash, "å"); File target = new File(trash, "å");

1
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java

@ -73,6 +73,7 @@ public class FileUtils7Test {
@Test @Test
public void testDeleteSymlinkToDirectoryDoesNotDeleteTarget() public void testDeleteSymlinkToDirectoryDoesNotDeleteTarget()
throws IOException { throws IOException {
org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
FS fs = FS.DETECTED; FS fs = FS.DETECTED;
File dir = new File(trash, "dir"); File dir = new File(trash, "dir");
File file = new File(dir, "file"); File file = new File(dir, "file");

21
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java

@ -92,11 +92,9 @@ public class HookTest extends RepositoryTestCase {
fail("expected commit-msg hook to abort commit"); fail("expected commit-msg hook to abort commit");
} catch (AbortedByHookException e) { } catch (AbortedByHookException e) {
assertEquals("unexpected error message from commit-msg hook", assertEquals("unexpected error message from commit-msg hook",
"Rejected by \"commit-msg\" hook.\nstderr" "Rejected by \"commit-msg\" hook.\nstderr\n",
+ System.lineSeparator(),
e.getMessage()); e.getMessage());
assertEquals("unexpected output from commit-msg hook", assertEquals("unexpected output from commit-msg hook", "test\n",
"test" + System.lineSeparator(),
out.toString()); out.toString());
} }
} }
@ -114,7 +112,7 @@ public class HookTest extends RepositoryTestCase {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
git.commit().setMessage("commit") git.commit().setMessage("commit")
.setHookOutputStream(new PrintStream(out)).call(); .setHookOutputStream(new PrintStream(out)).call();
assertEquals(".git/COMMIT_EDITMSG" + System.lineSeparator(), assertEquals(".git/COMMIT_EDITMSG\n",
out.toString("UTF-8")); out.toString("UTF-8"));
} }
@ -147,11 +145,10 @@ public class HookTest extends RepositoryTestCase {
new String[] { new String[] {
"arg1", "arg2" }, "arg1", "arg2" },
new PrintStream(out), new PrintStream(err), "stdin"); new PrintStream(out), new PrintStream(err), "stdin");
assertEquals("unexpected hook output", "test arg1 arg2"
+ System.lineSeparator() + "stdin" + System.lineSeparator(), assertEquals("unexpected hook output", "test arg1 arg2\nstdin\n",
out.toString("UTF-8")); out.toString("UTF-8"));
assertEquals("unexpected output on stderr stream", assertEquals("unexpected output on stderr stream", "stderr\n",
"stderr" + System.lineSeparator(),
err.toString("UTF-8")); err.toString("UTF-8"));
assertEquals("unexpected exit code", 0, res.getExitCode()); assertEquals("unexpected exit code", 0, res.getExitCode());
assertEquals("unexpected process status", ProcessResult.Status.OK, assertEquals("unexpected process status", ProcessResult.Status.OK,
@ -175,11 +172,9 @@ public class HookTest extends RepositoryTestCase {
fail("expected pre-commit hook to abort commit"); fail("expected pre-commit hook to abort commit");
} catch (AbortedByHookException e) { } catch (AbortedByHookException e) {
assertEquals("unexpected error message from pre-commit hook", assertEquals("unexpected error message from pre-commit hook",
"Rejected by \"pre-commit\" hook.\nstderr" "Rejected by \"pre-commit\" hook.\nstderr\n",
+ System.lineSeparator(),
e.getMessage()); e.getMessage());
assertEquals("unexpected output from pre-commit hook", assertEquals("unexpected output from pre-commit hook", "test\n",
"test" + System.lineSeparator(),
out.toString()); out.toString());
} }
} }

65
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java

@ -52,16 +52,17 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.util.FS.ExecutionResult;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
public class RunExternalScriptTest { public class RunExternalScriptTest {
private static final String LF = "\n";
private ByteArrayOutputStream out; private ByteArrayOutputStream out;
private ByteArrayOutputStream err; private ByteArrayOutputStream err;
private String sep = System.getProperty("line.separator");
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
out = new ByteArrayOutputStream(); out = new ByteArrayOutputStream();
@ -73,7 +74,7 @@ public class RunExternalScriptTest {
String inputStr = "a\nb\rc\r\nd"; String inputStr = "a\nb\rc\r\nd";
File script = writeTempFile("cat -"); File script = writeTempFile("cat -");
int rc = FS.DETECTED.runProcess( int rc = FS.DETECTED.runProcess(
new ProcessBuilder("/bin/sh", script.getPath()), out, err, new ProcessBuilder("sh", script.getPath()), out, err,
new ByteArrayInputStream(inputStr.getBytes())); new ByteArrayInputStream(inputStr.getBytes()));
assertEquals(0, rc); assertEquals(0, rc);
assertEquals(inputStr, new String(out.toByteArray())); assertEquals(inputStr, new String(out.toByteArray()));
@ -84,7 +85,7 @@ public class RunExternalScriptTest {
public void testCopyNullStdIn() throws IOException, InterruptedException { public void testCopyNullStdIn() throws IOException, InterruptedException {
File script = writeTempFile("cat -"); File script = writeTempFile("cat -");
int rc = FS.DETECTED.runProcess( int rc = FS.DETECTED.runProcess(
new ProcessBuilder("/bin/sh", script.getPath()), out, err, new ProcessBuilder("sh", script.getPath()), out, err,
(InputStream) null); (InputStream) null);
assertEquals(0, rc); assertEquals(0, rc);
assertEquals("", new String(out.toByteArray())); assertEquals("", new String(out.toByteArray()));
@ -94,7 +95,8 @@ public class RunExternalScriptTest {
@Test @Test
public void testArguments() throws IOException, InterruptedException { public void testArguments() throws IOException, InterruptedException {
File script = writeTempFile("echo $#,$1,$2,$3,$4,$5,$6"); File script = writeTempFile("echo $#,$1,$2,$3,$4,$5,$6");
int rc = FS.DETECTED.runProcess(new ProcessBuilder("/bin/bash", int rc = FS.DETECTED.runProcess(
new ProcessBuilder("sh",
script.getPath(), "a", "b", "c"), out, err, (InputStream) null); script.getPath(), "a", "b", "c"), out, err, (InputStream) null);
assertEquals(0, rc); assertEquals(0, rc);
assertEquals("3,a,b,c,,,\n", new String(out.toByteArray())); assertEquals("3,a,b,c,,,\n", new String(out.toByteArray()));
@ -105,7 +107,7 @@ public class RunExternalScriptTest {
public void testRc() throws IOException, InterruptedException { public void testRc() throws IOException, InterruptedException {
File script = writeTempFile("exit 3"); File script = writeTempFile("exit 3");
int rc = FS.DETECTED.runProcess( int rc = FS.DETECTED.runProcess(
new ProcessBuilder("/bin/sh", script.getPath(), "a", "b", "c"), new ProcessBuilder("sh", script.getPath(), "a", "b", "c"),
out, err, (InputStream) null); out, err, (InputStream) null);
assertEquals(3, rc); assertEquals(3, rc);
assertEquals("", new String(out.toByteArray())); assertEquals("", new String(out.toByteArray()));
@ -116,7 +118,7 @@ public class RunExternalScriptTest {
public void testNullStdout() throws IOException, InterruptedException { public void testNullStdout() throws IOException, InterruptedException {
File script = writeTempFile("echo hi"); File script = writeTempFile("echo hi");
int rc = FS.DETECTED.runProcess( int rc = FS.DETECTED.runProcess(
new ProcessBuilder("/bin/sh", script.getPath()), null, err, new ProcessBuilder("sh", script.getPath()), null, err,
(InputStream) null); (InputStream) null);
assertEquals(0, rc); assertEquals(0, rc);
assertEquals("", new String(out.toByteArray())); assertEquals("", new String(out.toByteArray()));
@ -127,11 +129,11 @@ public class RunExternalScriptTest {
public void testStdErr() throws IOException, InterruptedException { public void testStdErr() throws IOException, InterruptedException {
File script = writeTempFile("echo hi >&2"); File script = writeTempFile("echo hi >&2");
int rc = FS.DETECTED.runProcess( int rc = FS.DETECTED.runProcess(
new ProcessBuilder("/bin/sh", script.getPath()), null, err, new ProcessBuilder("sh", script.getPath()), null, err,
(InputStream) null); (InputStream) null);
assertEquals(0, rc); assertEquals(0, rc);
assertEquals("", new String(out.toByteArray())); assertEquals("", new String(out.toByteArray()));
assertEquals("hi" + sep, new String(err.toByteArray())); assertEquals("hi" + LF, new String(err.toByteArray()));
} }
@Test @Test
@ -139,11 +141,11 @@ public class RunExternalScriptTest {
String inputStr = "a\nb\rc\r\nd"; String inputStr = "a\nb\rc\r\nd";
File script = writeTempFile("echo $#,$1,$2,$3,$4,$5,$6 >&2 ; cat -; exit 5"); File script = writeTempFile("echo $#,$1,$2,$3,$4,$5,$6 >&2 ; cat -; exit 5");
int rc = FS.DETECTED.runProcess( int rc = FS.DETECTED.runProcess(
new ProcessBuilder("/bin/sh", script.getPath(), "a", "b", "c"), new ProcessBuilder("sh", script.getPath(), "a", "b", "c"),
out, err, new ByteArrayInputStream(inputStr.getBytes())); out, err, new ByteArrayInputStream(inputStr.getBytes()));
assertEquals(5, rc); assertEquals(5, rc);
assertEquals(inputStr, new String(out.toByteArray())); assertEquals(inputStr, new String(out.toByteArray()));
assertEquals("3,a,b,c,,," + sep, new String(err.toByteArray())); assertEquals("3,a,b,c,,," + LF, new String(err.toByteArray()));
} }
@Test(expected = IOException.class) @Test(expected = IOException.class)
@ -158,11 +160,50 @@ public class RunExternalScriptTest {
public void testWrongScript() throws IOException, InterruptedException { public void testWrongScript() throws IOException, InterruptedException {
File script = writeTempFile("cat-foo -"); File script = writeTempFile("cat-foo -");
int rc = FS.DETECTED.runProcess( int rc = FS.DETECTED.runProcess(
new ProcessBuilder("/bin/sh", script.getPath(), "a", "b", "c"), new ProcessBuilder("sh", script.getPath(), "a", "b", "c"),
out, err, (InputStream) null); out, err, (InputStream) null);
assertEquals(127, rc); assertEquals(127, rc);
} }
@Test
public void testCopyStdInExecute()
throws IOException, InterruptedException {
String inputStr = "a\nb\rc\r\nd";
File script = writeTempFile("cat -");
ProcessBuilder pb = new ProcessBuilder("sh", script.getPath());
ExecutionResult res = FS.DETECTED.execute(pb,
new ByteArrayInputStream(inputStr.getBytes()));
assertEquals(0, res.getRc());
assertEquals(inputStr, new String(res.getStdout().toByteArray()));
assertEquals("", new String(res.getStderr().toByteArray()));
}
@Test
public void testStdErrExecute() throws IOException, InterruptedException {
File script = writeTempFile("echo hi >&2");
ProcessBuilder pb = new ProcessBuilder("sh", script.getPath());
ExecutionResult res = FS.DETECTED.execute(pb, null);
assertEquals(0, res.getRc());
assertEquals("", new String(res.getStdout().toByteArray()));
assertEquals("hi" + LF, new String(res.getStderr().toByteArray()));
}
@Test
public void testAllTogetherBinExecute()
throws IOException, InterruptedException {
String inputStr = "a\nb\rc\r\nd";
File script = writeTempFile(
"echo $#,$1,$2,$3,$4,$5,$6 >&2 ; cat -; exit 5");
ProcessBuilder pb = new ProcessBuilder("sh", script.getPath(), "a",
"b", "c");
ExecutionResult res = FS.DETECTED.execute(pb,
new ByteArrayInputStream(inputStr.getBytes()));
assertEquals(5, res.getRc());
assertEquals(inputStr, new String(res.getStdout().toByteArray()));
assertEquals("3,a,b,c,,," + LF,
new String(res.getStderr().toByteArray()));
}
private File writeTempFile(String body) throws IOException { private File writeTempFile(String body) throws IOException {
File f = File.createTempFile("RunProcessTestScript_", ""); File f = File.createTempFile("RunProcessTestScript_", "");
JGitTestUtil.write(f, body); JGitTestUtil.write(f, body);

30
org.eclipse.jgit/.settings/.api_filters

@ -1,5 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.jgit" version="2"> <component id="org.eclipse.jgit" version="2">
<resource path="src/org/eclipse/jgit/attributes/AttributesNode.java" type="org.eclipse.jgit.attributes.AttributesNode">
<filter comment="attributes weren't really usable in earlier versions" id="338792546">
<message_arguments>
<message_argument value="org.eclipse.jgit.attributes.AttributesNode"/>
<message_argument value="getAttributes(String, boolean, Map&lt;String,Attribute&gt;)"/>
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/jgit/lib/BitmapIndex.java" type="org.eclipse.jgit.lib.BitmapIndex$BitmapBuilder"> <resource path="src/org/eclipse/jgit/lib/BitmapIndex.java" type="org.eclipse.jgit.lib.BitmapIndex$BitmapBuilder">
<filter comment="interface is implemented by extenders but not clients of the API" id="403804204"> <filter comment="interface is implemented by extenders but not clients of the API" id="403804204">
<message_arguments> <message_arguments>
@ -14,6 +22,14 @@
</message_arguments> </message_arguments>
</filter> </filter>
</resource> </resource>
<resource path="src/org/eclipse/jgit/lib/Repository.java" type="org.eclipse.jgit.lib.Repository">
<filter comment="Only implementors of Repository are affected. That should be allowed" id="336695337">
<message_arguments>
<message_argument value="org.eclipse.jgit.lib.Repository"/>
<message_argument value="createAttributesNodeProvider()"/>
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/jgit/transport/PushCertificate.java" type="org.eclipse.jgit.transport.PushCertificate"> <resource path="src/org/eclipse/jgit/transport/PushCertificate.java" type="org.eclipse.jgit.transport.PushCertificate">
<filter comment="PushCertificate wasn't really usable in 4.0" id="338722907"> <filter comment="PushCertificate wasn't really usable in 4.0" id="338722907">
<message_arguments> <message_arguments>
@ -35,6 +51,20 @@
</message_arguments> </message_arguments>
</filter> </filter>
</resource> </resource>
<resource path="src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java" type="org.eclipse.jgit.treewalk.WorkingTreeIterator">
<filter comment="attributes weren't really usable in earlier versions" id="338792546">
<message_arguments>
<message_argument value="org.eclipse.jgit.treewalk.WorkingTreeIterator"/>
<message_argument value="getGlobalAttributesNode()"/>
</message_arguments>
</filter>
<filter comment="attributes weren't really usable in earlier versions" id="338792546">
<message_arguments>
<message_argument value="org.eclipse.jgit.treewalk.WorkingTreeIterator"/>
<message_argument value="getInfoAttributesNode()"/>
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/jgit/util/FileUtils.java" type="org.eclipse.jgit.util.FileUtils"> <resource path="src/org/eclipse/jgit/util/FileUtils.java" type="org.eclipse.jgit.util.FileUtils">
<filter id="338792546"> <filter id="338792546">
<message_arguments> <message_arguments>

2
org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs

@ -2,7 +2,7 @@ eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jgit.annotations.NonNull org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jgit.annotations.NonNull
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jgit.annotations.NonByDefault org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jgit.annotations.NonNullByDefault
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jgit.annotations.Nullable org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jgit.annotations.Nullable
org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled

52
org.eclipse.jgit/META-INF/MANIFEST.MF

@ -6,7 +6,8 @@ Bundle-Version: 4.2.0.qualifier
Bundle-Localization: plugin Bundle-Localization: plugin
Bundle-Vendor: %provider_name Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Export-Package: org.eclipse.jgit.api;version="4.2.0"; Export-Package: org.eclipse.jgit.annotations;version="4.2.0",
org.eclipse.jgit.api;version="4.2.0";
uses:="org.eclipse.jgit.revwalk, uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff, org.eclipse.jgit.diff,
@ -20,9 +21,7 @@ Export-Package: org.eclipse.jgit.api;version="4.2.0";
org.eclipse.jgit.submodule, org.eclipse.jgit.submodule,
org.eclipse.jgit.transport, org.eclipse.jgit.transport,
org.eclipse.jgit.merge", org.eclipse.jgit.merge",
org.eclipse.jgit.api.errors;version="4.2.0"; org.eclipse.jgit.api.errors;version="4.2.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.errors",
org.eclipse.jgit.attributes;version="4.2.0", org.eclipse.jgit.attributes;version="4.2.0",
org.eclipse.jgit.blame;version="4.2.0"; org.eclipse.jgit.blame;version="4.2.0";
uses:="org.eclipse.jgit.lib, uses:="org.eclipse.jgit.lib,
@ -47,8 +46,7 @@ Export-Package: org.eclipse.jgit.api;version="4.2.0";
org.eclipse.jgit.internal.storage.pack, org.eclipse.jgit.internal.storage.pack,
org.eclipse.jgit.transport, org.eclipse.jgit.transport,
org.eclipse.jgit.dircache", org.eclipse.jgit.dircache",
org.eclipse.jgit.events;version="4.2.0"; org.eclipse.jgit.events;version="4.2.0";uses:="org.eclipse.jgit.lib",
uses:="org.eclipse.jgit.lib",
org.eclipse.jgit.fnmatch;version="4.2.0", org.eclipse.jgit.fnmatch;version="4.2.0",
org.eclipse.jgit.gitrepo;version="4.2.0"; org.eclipse.jgit.gitrepo;version="4.2.0";
uses:="org.eclipse.jgit.api, uses:="org.eclipse.jgit.api,
@ -57,14 +55,11 @@ Export-Package: org.eclipse.jgit.api;version="4.2.0";
org.xml.sax.helpers, org.xml.sax.helpers,
org.xml.sax", org.xml.sax",
org.eclipse.jgit.gitrepo.internal;version="4.2.0";x-internal:=true, org.eclipse.jgit.gitrepo.internal;version="4.2.0";x-internal:=true,
org.eclipse.jgit.hooks;version="4.2.0"; org.eclipse.jgit.hooks;version="4.2.0";uses:="org.eclipse.jgit.lib",
uses:="org.eclipse.jgit.lib",
org.eclipse.jgit.ignore;version="4.2.0", org.eclipse.jgit.ignore;version="4.2.0",
org.eclipse.jgit.ignore.internal;version="4.2.0";x-friends:="org.eclipse.jgit.test", org.eclipse.jgit.ignore.internal;version="4.2.0";x-friends:="org.eclipse.jgit.test",
org.eclipse.jgit.internal;version="4.2.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test", org.eclipse.jgit.internal;version="4.2.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
org.eclipse.jgit.internal.storage.dfs;version="4.2.0"; org.eclipse.jgit.internal.storage.dfs;version="4.2.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.server",
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.http.server",
org.eclipse.jgit.internal.storage.file;version="4.2.0"; org.eclipse.jgit.internal.storage.file;version="4.2.0";
x-friends:="org.eclipse.jgit.test, x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.junit, org.eclipse.jgit.junit,
@ -96,31 +91,18 @@ Export-Package: org.eclipse.jgit.api;version="4.2.0";
org.eclipse.jgit.treewalk, org.eclipse.jgit.treewalk,
org.eclipse.jgit.revwalk, org.eclipse.jgit.revwalk,
org.eclipse.jgit.merge", org.eclipse.jgit.merge",
org.eclipse.jgit.patch;version="4.2.0"; org.eclipse.jgit.patch;version="4.2.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revplot;version="4.2.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
org.eclipse.jgit.diff",
org.eclipse.jgit.revplot;version="4.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk",
org.eclipse.jgit.revwalk;version="4.2.0"; org.eclipse.jgit.revwalk;version="4.2.0";
uses:="org.eclipse.jgit.lib, uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk, org.eclipse.jgit.treewalk,
org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff, org.eclipse.jgit.diff,
org.eclipse.jgit.revwalk.filter", org.eclipse.jgit.revwalk.filter",
org.eclipse.jgit.revwalk.filter;version="4.2.0"; org.eclipse.jgit.revwalk.filter;version="4.2.0";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.storage.file;version="4.2.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
org.eclipse.jgit.lib, org.eclipse.jgit.storage.pack;version="4.2.0";uses:="org.eclipse.jgit.lib",
org.eclipse.jgit.util", org.eclipse.jgit.submodule;version="4.2.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
org.eclipse.jgit.storage.file;version="4.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.util",
org.eclipse.jgit.storage.pack;version="4.2.0";
uses:="org.eclipse.jgit.lib",
org.eclipse.jgit.submodule;version="4.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.treewalk",
org.eclipse.jgit.transport;version="4.2.0"; org.eclipse.jgit.transport;version="4.2.0";
uses:="org.eclipse.jgit.transport.resolver, uses:="org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.revwalk, org.eclipse.jgit.revwalk,
@ -133,11 +115,8 @@ Export-Package: org.eclipse.jgit.api;version="4.2.0";
org.eclipse.jgit.transport.http, org.eclipse.jgit.transport.http,
org.eclipse.jgit.errors, org.eclipse.jgit.errors,
org.eclipse.jgit.storage.pack", org.eclipse.jgit.storage.pack",
org.eclipse.jgit.transport.http;version="4.2.0"; org.eclipse.jgit.transport.http;version="4.2.0";uses:="javax.net.ssl",
uses:="javax.net.ssl", org.eclipse.jgit.transport.resolver;version="4.2.0";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
org.eclipse.jgit.transport.resolver;version="4.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.transport",
org.eclipse.jgit.treewalk;version="4.2.0"; org.eclipse.jgit.treewalk;version="4.2.0";
uses:="org.eclipse.jgit.lib, uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk, org.eclipse.jgit.revwalk,
@ -145,8 +124,7 @@ Export-Package: org.eclipse.jgit.api;version="4.2.0";
org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.util, org.eclipse.jgit.util,
org.eclipse.jgit.dircache", org.eclipse.jgit.dircache",
org.eclipse.jgit.treewalk.filter;version="4.2.0"; org.eclipse.jgit.treewalk.filter;version="4.2.0";uses:="org.eclipse.jgit.treewalk",
uses:="org.eclipse.jgit.treewalk",
org.eclipse.jgit.util;version="4.2.0"; org.eclipse.jgit.util;version="4.2.0";
uses:="org.eclipse.jgit.lib, uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.transport.http, org.eclipse.jgit.transport.http,

7
org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties

@ -20,6 +20,7 @@ argumentIsNotAValidCommentString=Invalid comment: {0}
atLeastOnePathIsRequired=At least one path is required. atLeastOnePathIsRequired=At least one path is required.
atLeastOnePatternIsRequired=At least one pattern is required. atLeastOnePatternIsRequired=At least one pattern is required.
atLeastTwoFiltersNeeded=At least two filters needed. atLeastTwoFiltersNeeded=At least two filters needed.
atomicPushNotSupported=Atomic push not supported.
authenticationNotSupported=authentication not supported authenticationNotSupported=authentication not supported
badBase64InputCharacterAt=Bad Base64 input character at {0} : {1} (decimal) badBase64InputCharacterAt=Bad Base64 input character at {0} : {1} (decimal)
badEntryDelimiter=Bad entry delimiter badEntryDelimiter=Bad entry delimiter
@ -45,6 +46,7 @@ cannotBeCombined=Cannot be combined.
cannotBeRecursiveWhenTreesAreIncluded=TreeWalk shouldn't be recursive when tree objects are included. cannotBeRecursiveWhenTreesAreIncluded=TreeWalk shouldn't be recursive when tree objects are included.
cannotChangeActionOnComment=Cannot change action on comment line in git-rebase-todo file, old action: {0}, new action: {1}. cannotChangeActionOnComment=Cannot change action on comment line in git-rebase-todo file, old action: {0}, new action: {1}.
cannotChangeToComment=Cannot change a non-comment line to a comment line. cannotChangeToComment=Cannot change a non-comment line to a comment line.
cannotCheckoutFromUnbornBranch=Cannot checkout from unborn branch
cannotCheckoutOursSwitchBranch=Checking out ours/theirs is only possible when checking out index, not when switching branches. cannotCheckoutOursSwitchBranch=Checking out ours/theirs is only possible when checking out index, not when switching branches.
cannotCombineSquashWithNoff=Cannot combine --squash with --no-ff. cannotCombineSquashWithNoff=Cannot combine --squash with --no-ff.
cannotCombineTreeFilterWithRevFilter=Cannot combine TreeFilter {0} with RevFilter {1}. cannotCombineTreeFilterWithRevFilter=Cannot combine TreeFilter {0} with RevFilter {1}.
@ -87,6 +89,7 @@ cannotReadBlob=Cannot read blob {0}
cannotReadCommit=Cannot read commit {0} cannotReadCommit=Cannot read commit {0}
cannotReadFile=Cannot read file {0} cannotReadFile=Cannot read file {0}
cannotReadHEAD=cannot read HEAD: {0} {1} cannotReadHEAD=cannot read HEAD: {0} {1}
cannotReadIndex=The index file {0} exists but cannot be read
cannotReadObject=Cannot read object cannotReadObject=Cannot read object
cannotReadObjectsPath=Cannot read {0}/{1}: {2} cannotReadObjectsPath=Cannot read {0}/{1}: {2}
cannotReadTree=Cannot read tree {0} cannotReadTree=Cannot read tree {0}
@ -279,6 +282,8 @@ fileCannotBeDeleted=File cannot be deleted: {0}
fileIsTooBigForThisConvenienceMethod=File is too big for this convenience method ({0} bytes). fileIsTooBigForThisConvenienceMethod=File is too big for this convenience method ({0} bytes).
fileIsTooLarge=File is too large: {0} fileIsTooLarge=File is too large: {0}
fileModeNotSetForPath=FileMode not set for path {0} fileModeNotSetForPath=FileMode not set for path {0}
filterExecutionFailed=Execution of filter command ''{0}'' on file ''{1}'' failed
filterExecutionFailedRc=Execution of filter command ''{0}'' on file ''{1}'' failed with return code ''{2}'', message on stderr: ''{3}''
findingGarbage=Finding garbage findingGarbage=Finding garbage
flagIsDisposed={0} is disposed. flagIsDisposed={0} is disposed.
flagNotFromThis={0} not from this. flagNotFromThis={0} not from this.
@ -344,6 +349,7 @@ invalidPathReservedOnWindows=Invalid path (''{0}'' is reserved on Windows): {1}
invalidReflogRevision=Invalid reflog revision: {0} invalidReflogRevision=Invalid reflog revision: {0}
invalidRefName=Invalid ref name: {0} invalidRefName=Invalid ref name: {0}
invalidRemote=Invalid remote: {0} invalidRemote=Invalid remote: {0}
invalidRepositoryStateNoHead=Invalid repository --- cannot read HEAD
invalidShallowObject=invalid shallow object {0}, expected commit invalidShallowObject=invalid shallow object {0}, expected commit
invalidStageForPath=Invalid stage {0} for path {1} invalidStageForPath=Invalid stage {0} for path {1}
invalidTagOption=Invalid tag option: {0} invalidTagOption=Invalid tag option: {0}
@ -450,6 +456,7 @@ packfileIsTruncated=Packfile {0} is truncated.
packfileIsTruncatedNoParam=Packfile is truncated. packfileIsTruncatedNoParam=Packfile is truncated.
packHandleIsStale=Pack file {0} handle is stale, removing it from pack list packHandleIsStale=Pack file {0} handle is stale, removing it from pack list
packHasUnresolvedDeltas=pack has unresolved deltas packHasUnresolvedDeltas=pack has unresolved deltas
packInaccessible=Pack file {0} now inaccessible; removing it from pack list
packingCancelledDuringObjectsWriting=Packing cancelled during objects writing packingCancelledDuringObjectsWriting=Packing cancelled during objects writing
packObjectCountMismatch=Pack object count mismatch: pack {0} index {1}: {2} packObjectCountMismatch=Pack object count mismatch: pack {0} index {1}: {2}
packRefs=Pack refs packRefs=Pack refs

69
org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java

@ -0,0 +1,69 @@
/*
* Copyright (C) 2015, Andrey Loskutov <loskutov@gmx.de>
* 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.annotations;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* JGit's replacement for the {@code javax.annotation.Nonnull}.
* <p>
* Denotes that a local variable, parameter, field, method return value expected
* to be non {@code null}.
*
* @since 4.2
*/
@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ FIELD, METHOD, PARAMETER, LOCAL_VARIABLE })
public @interface NonNull {
// marker annotation with no members
}

41
org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java

@ -54,13 +54,46 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* JGit's replacement for the {@code javax.annotations.Nullable}. * Marks types that can hold the value {@code null} at run time.
* <p> * <p>
* Denotes that a local variable, parameter, field, method return value can be * Unlike {@code org.eclipse.jdt.annotation.Nullable}, this has run-time
* {@code null}. * retention, allowing the annotation to be recognized by
* <a href="https://github.com/google/guice/wiki/UseNullable">Guice</a>. Unlike
* {@code javax.annotation.Nullable}, this does not involve importing new classes
* to a standard (Java EE) package, so it can be deployed in an OSGi container
* without running into
* <a href="http://wiki.osgi.org/wiki/Split_Packages">split-package</a>
* <a href="https://gerrit-review.googlesource.com/50112">problems</a>.
* <p>
* You can use this annotation to qualify a type in a method signature or local
* variable declaration. The entity whose type has this annotation is allowed to
* hold the value {@code null} at run time. This allows annotation based null
* analysis to infer that
* <ul>
* <li>Binding a {@code null} value to the entity is legal.
* <li>Dereferencing the entity is unsafe and can trigger a
* {@code NullPointerException}.
* </ul>
* <p>
* To avoid a dependency on Java 8, this annotation does not use
* {@link Target @Target} {@code TYPE_USE}. That may change when JGit starts
* requiring Java 8.
* <p>
* <b>Warning:</b> Please do not use this annotation on arrays. Different
* annotation processors treat {@code @Nullable Object[]} differently: some
* treat it as an array of nullable objects, for consistency with versions of
* {@code Nullable} defined with {@code @Target} {@code TYPE_USE}, while others
* treat it as a nullable array of objects. JGit therefore avoids using this
* annotation on arrays altogether.
*
* @see <a href=
* "http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html#faq-array-syntax-meaning">
* The checker-framework manual</a>
*
* @since 4.2
*/ */
@Documented @Documented
@Retention(RetentionPolicy.CLASS) @Retention(RetentionPolicy.RUNTIME)
@Target({ FIELD, METHOD, PARAMETER, LOCAL_VARIABLE }) @Target({ FIELD, METHOD, PARAMETER, LOCAL_VARIABLE })
public @interface Nullable { public @interface Nullable {
// marker annotation with no members // marker annotation with no members

7
org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java

@ -48,6 +48,7 @@ import java.io.InputStream;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
import org.eclipse.jgit.api.errors.FilterFailedException;
import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoFilepatternException; import org.eclipse.jgit.api.errors.NoFilepatternException;
@ -63,6 +64,7 @@ import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.jgit.treewalk.WorkingTreeIterator;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup; import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
@ -139,6 +141,7 @@ public class AddCommand extends GitCommand<DirCache> {
try (ObjectInserter inserter = repo.newObjectInserter(); try (ObjectInserter inserter = repo.newObjectInserter();
final TreeWalk tw = new TreeWalk(repo)) { final TreeWalk tw = new TreeWalk(repo)) {
tw.setOperationType(OperationType.CHECKIN_OP);
dc = repo.lockDirCache(); dc = repo.lockDirCache();
DirCacheIterator c; DirCacheIterator c;
@ -146,6 +149,7 @@ public class AddCommand extends GitCommand<DirCache> {
tw.addTree(new DirCacheBuildIterator(builder)); tw.addTree(new DirCacheBuildIterator(builder));
if (workingTreeIterator == null) if (workingTreeIterator == null)
workingTreeIterator = new FileTreeIterator(repo); workingTreeIterator = new FileTreeIterator(repo);
workingTreeIterator.setDirCacheIterator(tw, 0);
tw.addTree(workingTreeIterator); tw.addTree(workingTreeIterator);
tw.setRecursive(true); tw.setRecursive(true);
if (!addAll) if (!addAll)
@ -208,6 +212,9 @@ public class AddCommand extends GitCommand<DirCache> {
builder.commit(); builder.commit();
setCallable(false); setCallable(false);
} catch (IOException e) { } catch (IOException e) {
Throwable cause = e.getCause();
if (cause != null && cause instanceof FilterFailedException)
throw (FilterFailedException) cause;
throw new JGitInternalException( throw new JGitInternalException(
JGitText.get().exceptionCaughtDuringExecutionOfAddCommand, e); JGitText.get().exceptionCaughtDuringExecutionOfAddCommand, e);
} finally { } finally {

6
org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java

@ -222,6 +222,12 @@ public class CheckoutCommand extends GitCommand<Ref> {
} }
Ref headRef = repo.getRef(Constants.HEAD); Ref headRef = repo.getRef(Constants.HEAD);
if (headRef == null) {
// TODO Git CLI supports checkout from unborn branch, we should
// also allow this
throw new UnsupportedOperationException(
JGitText.get().cannotCheckoutFromUnbornBranch);
}
String shortHeadRef = getShortBranchName(headRef); String shortHeadRef = getShortBranchName(headRef);
String refLogMessage = "checkout: moving from " + shortHeadRef; //$NON-NLS-1$ String refLogMessage = "checkout: moving from " + shortHeadRef; //$NON-NLS-1$
ObjectId branch; ObjectId branch;

6
org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java

@ -86,6 +86,7 @@ import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.eclipse.jgit.util.ChangeIdUtil; import org.eclipse.jgit.util.ChangeIdUtil;
/** /**
@ -328,9 +329,12 @@ public class CommitCommand extends GitCommand<RevCommit> {
boolean emptyCommit = true; boolean emptyCommit = true;
try (TreeWalk treeWalk = new TreeWalk(repo)) { try (TreeWalk treeWalk = new TreeWalk(repo)) {
treeWalk.setOperationType(OperationType.CHECKIN_OP);
int dcIdx = treeWalk int dcIdx = treeWalk
.addTree(new DirCacheBuildIterator(existingBuilder)); .addTree(new DirCacheBuildIterator(existingBuilder));
int fIdx = treeWalk.addTree(new FileTreeIterator(repo)); FileTreeIterator fti = new FileTreeIterator(repo);
fti.setDirCacheIterator(treeWalk, 0);
int fIdx = treeWalk.addTree(fti);
int hIdx = -1; int hIdx = -1;
if (headId != null) if (headId != null)
hIdx = treeWalk.addTree(rw.parseTree(headId)); hIdx = treeWalk.addTree(rw.parseTree(headId));

44
org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java

@ -713,8 +713,48 @@ public class Git implements AutoCloseable {
} }
/** /**
* @return the git repository this class is interacting with; see {@link * Return a command used to list the available remotes.
* #close()} for notes on closing this repository. *
* @return a {@link RemoteListCommand}
* @since 4.2
*/
public RemoteListCommand remoteList() {
return new RemoteListCommand(repo);
}
/**
* Return a command used to add a new remote.
*
* @return a {@link RemoteAddCommand}
* @since 4.2
*/
public RemoteAddCommand remoteAdd() {
return new RemoteAddCommand(repo);
}
/**
* Return a command used to remove an existing remote.
*
* @return a {@link RemoteRemoveCommand}
* @since 4.2
*/
public RemoteRemoveCommand remoteRemove() {
return new RemoteRemoveCommand(repo);
}
/**
* Return a command used to change the URL of an existing remote.
*
* @return a {@link RemoteSetUrlCommand}
* @since 4.2
*/
public RemoteSetUrlCommand remoteSetUrl() {
return new RemoteSetUrlCommand(repo);
}
/**
* @return the git repository this class is interacting with; see
* {@link #close()} for notes on closing this repository.
*/ */
public Repository getRepository() { public Repository getRepository() {
return repo; return repo;

27
org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java

@ -89,9 +89,8 @@ public class PushCommand extends
private String receivePack = RemoteConfig.DEFAULT_RECEIVE_PACK; private String receivePack = RemoteConfig.DEFAULT_RECEIVE_PACK;
private boolean dryRun; private boolean dryRun;
private boolean atomic;
private boolean force; private boolean force;
private boolean thin = Transport.DEFAULT_PUSH_THIN; private boolean thin = Transport.DEFAULT_PUSH_THIN;
private OutputStream out; private OutputStream out;
@ -145,6 +144,7 @@ public class PushCommand extends
transports = Transport.openAll(repo, remote, Transport.Operation.PUSH); transports = Transport.openAll(repo, remote, Transport.Operation.PUSH);
for (final Transport transport : transports) { for (final Transport transport : transports) {
transport.setPushThin(thin); transport.setPushThin(thin);
transport.setPushAtomic(atomic);
if (receivePack != null) if (receivePack != null)
transport.setOptionReceivePack(receivePack); transport.setOptionReceivePack(receivePack);
transport.setDryRun(dryRun); transport.setDryRun(dryRun);
@ -396,6 +396,29 @@ public class PushCommand extends
return this; return this;
} }
/**
* @return true if all-or-nothing behavior is requested.
* @since 4.2
*/
public boolean isAtomic() {
return atomic;
}
/**
* Requests atomic push (all references updated, or no updates).
*
* Default setting is false.
*
* @param atomic
* @return {@code this}
* @since 4.2
*/
public PushCommand setAtomic(boolean atomic) {
checkCallable();
this.atomic = atomic;
return this;
}
/** /**
* @return the force preference for push operation * @return the force preference for push operation
*/ */

14
org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java

@ -668,12 +668,13 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
} }
private void writeRewrittenHashes() throws RevisionSyntaxException, private void writeRewrittenHashes() throws RevisionSyntaxException,
IOException { IOException, RefNotFoundException {
File currentCommitFile = rebaseState.getFile(CURRENT_COMMIT); File currentCommitFile = rebaseState.getFile(CURRENT_COMMIT);
if (!currentCommitFile.exists()) if (!currentCommitFile.exists())
return; return;
String head = repo.resolve(Constants.HEAD).getName(); ObjectId headId = getHead().getObjectId();
String head = headId.getName();
String currentCommits = rebaseState.readFile(CURRENT_COMMIT); String currentCommits = rebaseState.readFile(CURRENT_COMMIT);
for (String current : currentCommits.split("\n")) //$NON-NLS-1$ for (String current : currentCommits.split("\n")) //$NON-NLS-1$
RebaseState RebaseState
@ -743,8 +744,8 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
private void resetSoftToParent() throws IOException, private void resetSoftToParent() throws IOException,
GitAPIException, CheckoutConflictException { GitAPIException, CheckoutConflictException {
Ref orig_head = repo.getRef(Constants.ORIG_HEAD); Ref ref = repo.getRef(Constants.ORIG_HEAD);
ObjectId orig_headId = orig_head.getObjectId(); ObjectId orig_head = ref == null ? null : ref.getObjectId();
try { try {
// we have already commited the cherry-picked commit. // we have already commited the cherry-picked commit.
// what we need is to have changes introduced by this // what we need is to have changes introduced by this
@ -755,7 +756,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
} finally { } finally {
// set ORIG_HEAD back to where we started because soft // set ORIG_HEAD back to where we started because soft
// reset moved it // reset moved it
repo.writeOrigHead(orig_headId); repo.writeOrigHead(orig_head);
} }
} }
@ -980,6 +981,9 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
try { try {
raw = IO.readFully(authorScriptFile); raw = IO.readFully(authorScriptFile);
} catch (FileNotFoundException notFound) { } catch (FileNotFoundException notFound) {
if (authorScriptFile.exists()) {
throw notFound;
}
return null; return null;
} }
return parseAuthor(raw); return parseAuthor(raw);

133
org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java

@ -0,0 +1,133 @@
/*
* Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* 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.api;
import java.io.IOException;
import java.net.URISyntaxException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
/**
* Used to add a new remote.
*
* This class has setters for all supported options and arguments of this
* command and a {@link #call()} method to finally execute the command.
*
* @see <a href=
* "http://www.kernel.org/pub/software/scm/git/docs/git-remote.html" > Git
* documentation about Remote</a>
*
* @since 4.2
*/
public class RemoteAddCommand extends GitCommand<RemoteConfig> {
private String name;
private URIish uri;
/**
* @param repo
*/
protected RemoteAddCommand(Repository repo) {
super(repo);
}
/**
* The name of the remote to add.
*
* @param name
* a remote name
*/
public void setName(String name) {
this.name = name;
}
/**
* The URL of the repository for the new remote.
*
* @param uri
* an URL for the remote
*/
public void setUri(URIish uri) {
this.uri = uri;
}
/**
* Executes the {@code remote add} command with all the options and
* parameters collected by the setter methods of this class.
*
* @return the {@link RemoteConfig} object of the added remote
*/
@Override
public RemoteConfig call() throws GitAPIException {
checkCallable();
try {
StoredConfig config = repo.getConfig();
RemoteConfig remote = new RemoteConfig(config, name);
RefSpec refSpec = new RefSpec();
refSpec = refSpec.setForceUpdate(true);
refSpec = refSpec.setSourceDestination(Constants.R_HEADS + "*", //$NON-NLS-1$
Constants.R_REMOTES + name + "/*"); //$NON-NLS-1$
remote.addFetchRefSpec(refSpec);
remote.addURI(uri);
remote.update(config);
config.save();
return remote;
} catch (IOException | URISyntaxException e) {
throw new JGitInternalException(e.getMessage(), e);
}
}
}

91
org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java

@ -0,0 +1,91 @@
/*
* Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* 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.api;
import java.net.URISyntaxException;
import java.util.List;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.RemoteConfig;
/**
* Used to obtain the list of remotes.
*
* This class has setters for all supported options and arguments of this
* command and a {@link #call()} method to finally execute the command.
*
* @see <a href=
* "http://www.kernel.org/pub/software/scm/git/docs/git-remote.html" > Git
* documentation about Remote</a>
*
* @since 4.2
*/
public class RemoteListCommand extends GitCommand<List<RemoteConfig>> {
/**
* @param repo
*/
protected RemoteListCommand(Repository repo) {
super(repo);
}
/**
* Executes the {@code remote} command with all the options and parameters
* collected by the setter methods of this class.
*
* @return a list of {@link RemoteConfig} objects.
*/
@Override
public List<RemoteConfig> call() throws GitAPIException {
checkCallable();
try {
return RemoteConfig.getAllRemoteConfigs(repo.getConfig());
} catch (URISyntaxException e) {
throw new JGitInternalException(e.getMessage(), e);
}
}
}

110
org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java

@ -0,0 +1,110 @@
/*
* Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* 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.api;
import java.io.IOException;
import java.net.URISyntaxException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.transport.RemoteConfig;
/**
* Used to remove an existing remote.
*
* This class has setters for all supported options and arguments of this
* command and a {@link #call()} method to finally execute the command.
*
* @see <a href=
* "http://www.kernel.org/pub/software/scm/git/docs/git-remote.html" > Git
* documentation about Remote</a>
*
* @since 4.2
*/
public class RemoteRemoveCommand extends GitCommand<RemoteConfig> {
private String name;
/**
* @param repo
*/
protected RemoteRemoveCommand(Repository repo) {
super(repo);
}
/**
* The name of the remote to remove.
*
* @param name
* a remote name
*/
public void setName(String name) {
this.name = name;
}
/**
* Executes the {@code remote} command with all the options and parameters
* collected by the setter methods of this class.
*
* @return the {@link RemoteConfig} object of the removed remote
*/
@Override
public RemoteConfig call() throws GitAPIException {
checkCallable();
try {
StoredConfig config = repo.getConfig();
RemoteConfig remote = new RemoteConfig(config, name);
config.unsetSection(ConfigConstants.CONFIG_KEY_REMOTE, name);
config.save();
return remote;
} catch (IOException | URISyntaxException e) {
throw new JGitInternalException(e.getMessage(), e);
}
}
}

155
org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java

@ -0,0 +1,155 @@
/*
* Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* 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.api;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
/**
* Used to to change the URL of a remote.
*
* This class has setters for all supported options and arguments of this
* command and a {@link #call()} method to finally execute the command.
*
* @see <a href=
* "http://www.kernel.org/pub/software/scm/git/docs/git-remote.html" > Git
* documentation about Remote</a>
*
* @since 4.2
*/
public class RemoteSetUrlCommand extends GitCommand<RemoteConfig> {
private String name;
private URIish uri;
private boolean push;
/**
* @param repo
*/
protected RemoteSetUrlCommand(Repository repo) {
super(repo);
}
/**
* The name of the remote to change the URL for.
*
* @param name
* a remote name
*/
public void setName(String name) {
this.name = name;
}
/**
* The new URL for the remote.
*
* @param uri
* an URL for the remote
*/
public void setUri(URIish uri) {
this.uri = uri;
}
/**
* Whether to change the push URL of the remote instead of the fetch URL.
*
* @param push
* <code>true</code> to set the push url, <code>false</code> to
* set the fetch url
*/
public void setPush(boolean push) {
this.push = push;
}
/**
* Executes the {@code remote} command with all the options and parameters
* collected by the setter methods of this class.
*
* @return the {@link RemoteConfig} object of the modified remote
*/
@Override
public RemoteConfig call() throws GitAPIException {
checkCallable();
try {
StoredConfig config = repo.getConfig();
RemoteConfig remote = new RemoteConfig(config, name);
if (push) {
List<URIish> uris = remote.getPushURIs();
if (uris.size() > 1) {
throw new JGitInternalException(
"remote.newtest.pushurl has multiple values"); //$NON-NLS-1$
} else if (uris.size() == 1) {
remote.removePushURI(uris.get(0));
}
remote.addPushURI(uri);
} else {
List<URIish> uris = remote.getURIs();
if (uris.size() > 1) {
throw new JGitInternalException(
"remote.newtest.url has multiple values"); //$NON-NLS-1$
} else if (uris.size() == 1) {
remote.removeURI(uris.get(0));
}
remote.addURI(uri);
}
remote.update(config);
config.save();
return remote;
} catch (IOException | URISyntaxException e) {
throw new JGitInternalException(e.getMessage(), e);
}
}
}

5
org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java

@ -51,6 +51,7 @@ import org.eclipse.jgit.api.errors.DetachedHeadException;
import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRefNameException; import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoHeadException;
import org.eclipse.jgit.api.errors.RefAlreadyExistsException; import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
@ -121,6 +122,10 @@ public class RenameBranchCommand extends GitCommand<Ref> {
fullOldName = ref.getName(); fullOldName = ref.getName();
} else { } else {
fullOldName = repo.getFullBranch(); fullOldName = repo.getFullBranch();
if (fullOldName == null) {
throw new NoHeadException(
JGitText.get().invalidRepositoryStateNoHead);
}
if (ObjectId.isId(fullOldName)) if (ObjectId.isId(fullOldName))
throw new DetachedHeadException(); throw new DetachedHeadException();
} }

144
org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java

@ -0,0 +1,144 @@
/*
* Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com> 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.api.errors;
import java.text.MessageFormat;
import org.eclipse.jgit.internal.JGitText;
/**
* Exception thrown when the execution of a filter command failed
*
* @since 4.2
*/
public class FilterFailedException extends GitAPIException {
private static final long serialVersionUID = 1L;
private String filterCommand;
private String path;
private byte[] stdout;
private String stderr;
private int rc;
/**
* Thrown if during execution of filter command an exception occurred
*
* @param cause
* the exception
* @param filterCommand
* the command which failed
* @param path
* the path processed by the filter
*/
public FilterFailedException(Exception cause, String filterCommand,
String path) {
super(MessageFormat.format(JGitText.get().filterExecutionFailed,
filterCommand, path), cause);
this.filterCommand = filterCommand;
this.path = path;
}
/**
* Thrown if a filter command returns a non-zero return code
*
* @param rc
* the return code
* @param filterCommand
* the command which failed
* @param path
* the path processed by the filter
* @param stdout
* the output the filter generated so far. This should be limited
* to reasonable size.
* @param stderr
* the stderr output of the filter
*/
@SuppressWarnings("boxing")
public FilterFailedException(int rc, String filterCommand, String path,
byte[] stdout, String stderr) {
super(MessageFormat.format(JGitText.get().filterExecutionFailedRc,
filterCommand, path, rc, stderr));
this.rc = rc;
this.filterCommand = filterCommand;
this.path = path;
this.stdout = stdout;
this.stderr = stderr;
}
/**
* @return the filterCommand
*/
public String getFilterCommand() {
return filterCommand;
}
/**
* @return the path of the file processed by the filter command
*/
public String getPath() {
return path;
}
/**
* @return the output generated by the filter command. Might be truncated to
* limit memory consumption.
*/
public byte[] getOutput() {
return stdout;
}
/**
* @return the error output returned by the filter command
*/
public String getError() {
return stderr;
}
/**
* @return the return code returned by the filter command
*/
public int getReturnCode() {
return rc;
}
}

16
org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java

@ -50,8 +50,10 @@ package org.eclipse.jgit.attributes;
* <li>Set - represented by {@link State#SET}</li> * <li>Set - represented by {@link State#SET}</li>
* <li>Unset - represented by {@link State#UNSET}</li> * <li>Unset - represented by {@link State#UNSET}</li>
* <li>Set to a value - represented by {@link State#CUSTOM}</li> * <li>Set to a value - represented by {@link State#CUSTOM}</li>
* <li>Unspecified - <code>null</code> is used instead of an instance of this * <li>Unspecified - used to revert an attribute . This is crucial in order to
* class</li> * mark an attribute as unspecified in the attributes map and thus preventing
* following (with lower priority) nodes from setting the attribute to a value
* at all</li>
* </ul> * </ul>
* </p> * </p>
* *
@ -61,6 +63,7 @@ public final class Attribute {
/** /**
* The attribute value state * The attribute value state
* see also https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
*/ */
public static enum State { public static enum State {
/** the attribute is set */ /** the attribute is set */
@ -69,6 +72,13 @@ public final class Attribute {
/** the attribute is unset */ /** the attribute is unset */
UNSET, UNSET,
/**
* the attribute appears as if it would not be defined at all
*
* @since 4.2
*/
UNSPECIFIED,
/** the attribute is set to a custom value */ /** the attribute is set to a custom value */
CUSTOM CUSTOM
} }
@ -176,6 +186,8 @@ public final class Attribute {
return key; return key;
case UNSET: case UNSET:
return "-" + key; //$NON-NLS-1$ return "-" + key; //$NON-NLS-1$
case UNSPECIFIED:
return "!" + key; //$NON-NLS-1$
case CUSTOM: case CUSTOM:
default: default:
return key + "=" + value; //$NON-NLS-1$ return key + "=" + value; //$NON-NLS-1$

202
org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java

@ -0,0 +1,202 @@
/*
* Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
*
* 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.attributes;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import org.eclipse.jgit.attributes.Attribute.State;
/**
* Represents a set of attributes for a path
* <p>
*
* @since 4.2
*/
public final class Attributes {
private final Map<String, Attribute> map = new LinkedHashMap<>();
/**
* Creates a new instance
*
* @param attributes
*/
public Attributes(Attribute... attributes) {
if (attributes != null) {
for (Attribute a : attributes) {
put(a);
}
}
}
/**
* @return true if the set does not contain any attributes
*/
public boolean isEmpty() {
return map.isEmpty();
}
/**
* @param key
* @return the attribute or null
*/
public Attribute get(String key) {
return map.get(key);
}
/**
* @return all attributes
*/
public Collection<Attribute> getAll() {
return new ArrayList<>(map.values());
}
/**
* @param a
*/
public void put(Attribute a) {
map.put(a.getKey(), a);
}
/**
* @param key
*/
public void remove(String key) {
map.remove(key);
}
/**
* @param key
* @return true if the {@link Attributes} contains this key
*/
public boolean containsKey(String key) {
return map.containsKey(key);
}
/**
* Returns the state.
*
* @param key
*
* @return the state (never returns <code>null</code>)
*/
public Attribute.State getState(String key) {
Attribute a = map.get(key);
return a != null ? a.getState() : Attribute.State.UNSPECIFIED;
}
/**
* @param key
* @return true if the key is {@link State#SET}, false in all other cases
*/
public boolean isSet(String key) {
return (getState(key) == State.SET);
}
/**
* @param key
* @return true if the key is {@link State#UNSET}, false in all other cases
*/
public boolean isUnset(String key) {
return (getState(key) == State.UNSET);
}
/**
* @param key
* @return true if the key is {@link State#UNSPECIFIED}, false in all other
* cases
*/
public boolean isUnspecified(String key) {
return (getState(key) == State.UNSPECIFIED);
}
/**
* @param key
* @return true if the key is {@link State#CUSTOM}, false in all other cases
* see {@link #getValue(String)} for the value of the key
*/
public boolean isCustom(String key) {
return (getState(key) == State.CUSTOM);
}
/**
* @param key
* @return the attribute value (may be <code>null</code>)
*/
public String getValue(String key) {
Attribute a = map.get(key);
return a != null ? a.getValue() : null;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(getClass().getSimpleName());
buf.append("["); //$NON-NLS-1$
buf.append(" "); //$NON-NLS-1$
for (Attribute a : map.values()) {
buf.append(a.toString());
buf.append(" "); //$NON-NLS-1$
}
buf.append("]"); //$NON-NLS-1$
return buf.toString();
}
@Override
public int hashCode() {
return map.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof Attributes))
return false;
Attributes other = (Attributes) obj;
return this.map.equals(other.map);
}
}

12
org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java

@ -50,7 +50,6 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Map;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
@ -134,11 +133,12 @@ public class AttributesNode {
* true if the target item is a directory. * true if the target item is a directory.
* @param attributes * @param attributes
* Map that will hold the attributes matching this entry path. If * Map that will hold the attributes matching this entry path. If
* it is not empty, this method will NOT override any * it is not empty, this method will NOT override any existing
* existing entry. * entry.
* @since 4.2
*/ */
public void getAttributes(String entryPath, boolean isDirectory, public void getAttributes(String entryPath,
Map<String, Attribute> attributes) { boolean isDirectory, Attributes attributes) {
// Parse rules in the reverse order that they were read since the last // Parse rules in the reverse order that they were read since the last
// entry should be used // entry should be used
ListIterator<AttributesRule> ruleIterator = rules.listIterator(rules ListIterator<AttributesRule> ruleIterator = rules.listIterator(rules
@ -153,7 +153,7 @@ public class AttributesNode {
while (attributeIte.hasPrevious()) { while (attributeIte.hasPrevious()) {
Attribute attr = attributeIte.previous(); Attribute attr = attributeIte.previous();
if (!attributes.containsKey(attr.getKey())) if (!attributes.containsKey(attr.getKey()))
attributes.put(attr.getKey(), attr); attributes.put(attr);
} }
} }
} }

81
org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java

@ -0,0 +1,81 @@
/*
* Copyright (C) 2014, Arthur Daussy <arthur.daussy@obeo.fr>
* 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.attributes;
import java.io.IOException;
import org.eclipse.jgit.lib.CoreConfig;
/**
* An interface used to retrieve the global and info {@link AttributesNode}s.
*
* @since 4.2
*
*/
public interface AttributesNodeProvider {
/**
* Retrieve the {@link AttributesNode} that holds the information located
* in $GIT_DIR/info/attributes file.
*
* @return the {@link AttributesNode} that holds the information located in
* $GIT_DIR/info/attributes file.
* @throws IOException
* if an error is raised while parsing the attributes file
*/
public AttributesNode getInfoAttributesNode() throws IOException;
/**
* Retrieve the {@link AttributesNode} that holds the information located
* in the global gitattributes file.
*
* @return the {@link AttributesNode} that holds the information located in
* the global gitattributes file.
* @throws IOException
* IOException if an error is raised while parsing the
* attributes file
* @see CoreConfig#getAttributesFile()
*/
public AttributesNode getGlobalAttributesNode() throws IOException;
}

55
org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java

@ -0,0 +1,55 @@
/*
* Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com>
* 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.attributes;
/**
* Interface for classes which provide git attributes
*
* @since 4.2
*/
public interface AttributesProvider {
/**
* @return the currently active attributes
*/
public Attributes getAttributes();
}

19
org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java

@ -84,6 +84,13 @@ public class AttributesRule {
continue; continue;
} }
if (attribute.startsWith("!")) {//$NON-NLS-1$
if (attribute.length() > 1)
result.add(new Attribute(attribute.substring(1),
State.UNSPECIFIED));
continue;
}
final int equalsIndex = attribute.indexOf("="); //$NON-NLS-1$ final int equalsIndex = attribute.indexOf("="); //$NON-NLS-1$
if (equalsIndex == -1) if (equalsIndex == -1)
result.add(new Attribute(attribute, State.SET)); result.add(new Attribute(attribute, State.SET));
@ -200,4 +207,16 @@ public class AttributesRule {
boolean match = matcher.matches(relativeTarget, isDirectory); boolean match = matcher.matches(relativeTarget, isDirectory);
return match; return match;
} }
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(pattern);
for (Attribute a : attributes) {
sb.append(" "); //$NON-NLS-1$
sb.append(a);
}
return sb.toString();
}
} }

4
org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java

@ -132,7 +132,11 @@ public abstract class ContentSource {
@Override @Override
public long size(String path, ObjectId id) throws IOException { public long size(String path, ObjectId id) throws IOException {
try {
return reader.getObjectSize(id, Constants.OBJ_BLOB); return reader.getObjectSize(id, Constants.OBJ_BLOB);
} catch (MissingObjectException ignore) {
return 0;
}
} }
@Override @Override

38
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java vendored

@ -63,6 +63,7 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IndexReadException;
import org.eclipse.jgit.errors.LockFailedException; import org.eclipse.jgit.errors.LockFailedException;
import org.eclipse.jgit.errors.UnmergedPathException; import org.eclipse.jgit.errors.UnmergedPathException;
import org.eclipse.jgit.events.IndexChangedEvent; import org.eclipse.jgit.events.IndexChangedEvent;
@ -70,12 +71,15 @@ import org.eclipse.jgit.events.IndexChangedListener;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.FileSnapshot; import org.eclipse.jgit.internal.storage.file.FileSnapshot;
import org.eclipse.jgit.internal.storage.file.LockFile; import org.eclipse.jgit.internal.storage.file.LockFile;
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.ObjectInserter; import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup; import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.IO;
@ -144,6 +148,28 @@ public class DirCache {
return new DirCache(null, null); return new DirCache(null, null);
} }
/**
* Create a new in memory index read from the contents of a tree.
*
* @param reader
* reader to access the tree objects from a repository.
* @param treeId
* tree to read. Must identify a tree, not a tree-ish.
* @return a new cache which has no backing store file, but contains the
* contents of {@code treeId}.
* @throws IOException
* one or more trees not available from the ObjectReader.
* @since 4.2
*/
public static DirCache read(ObjectReader reader, AnyObjectId treeId)
throws IOException {
DirCache d = newInCore();
DirCacheBuilder b = d.builder();
b.addTree(null, DirCacheEntry.STAGE_0, reader, treeId);
b.finish();
return d;
}
/** /**
* Create a new in-core index representation and read an index from disk. * Create a new in-core index representation and read an index from disk.
* <p> * <p>
@ -417,6 +443,12 @@ public class DirCache {
} }
} }
} catch (FileNotFoundException fnfe) { } catch (FileNotFoundException fnfe) {
if (liveFile.exists()) {
// Panic: the index file exists but we can't read it
throw new IndexReadException(
MessageFormat.format(JGitText.get().cannotReadIndex,
liveFile.getAbsolutePath(), fnfe));
}
// Someone must have deleted it between our exists test // Someone must have deleted it between our exists test
// and actually opening the path. That's fine, its empty. // and actually opening the path. That's fine, its empty.
// //
@ -869,8 +901,8 @@ public class DirCache {
*/ */
public DirCacheEntry[] getEntriesWithin(String path) { public DirCacheEntry[] getEntriesWithin(String path) {
if (path.length() == 0) { if (path.length() == 0) {
final DirCacheEntry[] r = new DirCacheEntry[sortedEntries.length]; DirCacheEntry[] r = new DirCacheEntry[entryCnt];
System.arraycopy(sortedEntries, 0, r, 0, sortedEntries.length); System.arraycopy(sortedEntries, 0, r, 0, entryCnt);
return r; return r;
} }
if (!path.endsWith("/")) //$NON-NLS-1$ if (!path.endsWith("/")) //$NON-NLS-1$
@ -963,6 +995,7 @@ public class DirCache {
private void updateSmudgedEntries() throws IOException { private void updateSmudgedEntries() throws IOException {
List<String> paths = new ArrayList<String>(128); List<String> paths = new ArrayList<String>(128);
try (TreeWalk walk = new TreeWalk(repository)) { try (TreeWalk walk = new TreeWalk(repository)) {
walk.setOperationType(OperationType.CHECKIN_OP);
for (int i = 0; i < entryCnt; i++) for (int i = 0; i < entryCnt; i++)
if (sortedEntries[i].isSmudged()) if (sortedEntries[i].isSmudged())
paths.add(sortedEntries[i].getPathString()); paths.add(sortedEntries[i].getPathString());
@ -974,6 +1007,7 @@ public class DirCache {
FileTreeIterator fIter = new FileTreeIterator(repository); FileTreeIterator fIter = new FileTreeIterator(repository);
walk.addTree(iIter); walk.addTree(iIter);
walk.addTree(fIter); walk.addTree(fIter);
fIter.setDirCacheIterator(walk, 0);
walk.setRecursive(true); walk.setRecursive(true);
while (walk.next()) { while (walk.next()) {
iIter = walk.getTree(0, DirCacheIterator.class); iIter = walk.getTree(0, DirCacheIterator.class);

81
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java vendored

@ -44,6 +44,9 @@
package org.eclipse.jgit.dircache; package org.eclipse.jgit.dircache;
import static org.eclipse.jgit.lib.FileMode.TYPE_MASK;
import static org.eclipse.jgit.lib.FileMode.TYPE_TREE;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Arrays; import java.util.Arrays;
@ -51,9 +54,7 @@ import java.util.Arrays;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.TreeWalk;
/** /**
* Updates a {@link DirCache} by adding individual {@link DirCacheEntry}s. * Updates a {@link DirCache} by adding individual {@link DirCacheEntry}s.
@ -102,8 +103,9 @@ public class DirCacheBuilder extends BaseDirCacheEditor {
*/ */
public void add(final DirCacheEntry newEntry) { public void add(final DirCacheEntry newEntry) {
if (newEntry.getRawMode() == 0) if (newEntry.getRawMode() == 0)
throw new IllegalArgumentException(MessageFormat.format(JGitText.get().fileModeNotSetForPath throw new IllegalArgumentException(MessageFormat.format(
, newEntry.getPathString())); JGitText.get().fileModeNotSetForPath,
newEntry.getPathString()));
beforeAdd(newEntry); beforeAdd(newEntry);
fastAdd(newEntry); fastAdd(newEntry);
} }
@ -162,27 +164,56 @@ public class DirCacheBuilder extends BaseDirCacheEditor {
* @throws IOException * @throws IOException
* a tree cannot be read to iterate through its entries. * a tree cannot be read to iterate through its entries.
*/ */
public void addTree(final byte[] pathPrefix, final int stage, public void addTree(byte[] pathPrefix, int stage, ObjectReader reader,
final ObjectReader reader, final AnyObjectId tree) throws IOException { AnyObjectId tree) throws IOException {
final TreeWalk tw = new TreeWalk(reader); CanonicalTreeParser p = createTreeParser(pathPrefix, reader, tree);
tw.addTree(new CanonicalTreeParser(pathPrefix, reader, tree while (!p.eof()) {
.toObjectId())); if (isTree(p)) {
tw.setRecursive(true); p = enterTree(p, reader);
if (tw.next()) { continue;
final DirCacheEntry newEntry = toEntry(stage, tw); }
beforeAdd(newEntry);
fastAdd(newEntry); DirCacheEntry first = toEntry(stage, p);
while (tw.next()) beforeAdd(first);
fastAdd(toEntry(stage, tw)); fastAdd(first);
p = p.next();
break;
}
// Rest of tree entries are correctly sorted; use fastAdd().
while (!p.eof()) {
if (isTree(p)) {
p = enterTree(p, reader);
} else {
fastAdd(toEntry(stage, p));
p = p.next();
} }
} }
}
private static CanonicalTreeParser createTreeParser(byte[] pathPrefix,
ObjectReader reader, AnyObjectId tree) throws IOException {
return new CanonicalTreeParser(pathPrefix, reader, tree);
}
private static boolean isTree(CanonicalTreeParser p) {
return (p.getEntryRawMode() & TYPE_MASK) == TYPE_TREE;
}
private static CanonicalTreeParser enterTree(CanonicalTreeParser p,
ObjectReader reader) throws IOException {
p = p.createSubtreeIterator(reader);
return p.eof() ? p.next() : p;
}
private DirCacheEntry toEntry(final int stage, final TreeWalk tw) { private static DirCacheEntry toEntry(int stage, CanonicalTreeParser i) {
final DirCacheEntry e = new DirCacheEntry(tw.getRawPath(), stage); byte[] buf = i.getEntryPathBuffer();
final AbstractTreeIterator i; int len = i.getEntryPathLength();
byte[] path = new byte[len];
System.arraycopy(buf, 0, path, 0, len);
i = tw.getTree(0, AbstractTreeIterator.class); DirCacheEntry e = new DirCacheEntry(path, stage);
e.setFileMode(tw.getFileMode(0)); e.setFileMode(i.getEntryRawMode());
e.setObjectIdFromRaw(i.idBuffer(), i.idOffset()); e.setObjectIdFromRaw(i.idBuffer(), i.idOffset());
return e; return e;
} }
@ -242,9 +273,9 @@ public class DirCacheBuilder extends BaseDirCacheEditor {
sorted = true; sorted = true;
} }
private static IllegalStateException bad(final DirCacheEntry a, private static IllegalStateException bad(DirCacheEntry a, String msg) {
final String msg) { return new IllegalStateException(String.format(
return new IllegalStateException(msg + ": " + a.getStage() + " " //$NON-NLS-1$ //$NON-NLS-2$ "%s: %d %s", //$NON-NLS-1$
+ a.getPathString()); msg, Integer.valueOf(a.getStage()), a.getPathString()));
} }
} }

125
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java vendored

@ -52,15 +52,18 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.eclipse.jgit.api.errors.FilterFailedException;
import org.eclipse.jgit.errors.CheckoutConflictException; import org.eclipse.jgit.errors.CheckoutConflictException;
import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.IndexWriteException; import org.eclipse.jgit.errors.IndexWriteException;
import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF; import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
import org.eclipse.jgit.lib.CoreConfig.SymLinks; import org.eclipse.jgit.lib.CoreConfig.SymLinks;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectChecker; import org.eclipse.jgit.lib.ObjectChecker;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.ObjectLoader;
@ -76,6 +79,7 @@ import org.eclipse.jgit.treewalk.WorkingTreeIterator;
import org.eclipse.jgit.treewalk.WorkingTreeOptions; import org.eclipse.jgit.treewalk.WorkingTreeOptions;
import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FS.ExecutionResult;
import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.SystemReader; import org.eclipse.jgit.util.SystemReader;
@ -85,9 +89,10 @@ import org.eclipse.jgit.util.io.AutoCRLFOutputStream;
* This class handles checking out one or two trees merging with the index. * This class handles checking out one or two trees merging with the index.
*/ */
public class DirCacheCheckout { public class DirCacheCheckout {
private static final int MAX_EXCEPTION_TEXT_SIZE = 10 * 1024;
private Repository repo; private Repository repo;
private HashMap<String, ObjectId> updated = new HashMap<String, ObjectId>(); private HashMap<String, String> updated = new HashMap<String, String>();
private ArrayList<String> conflicts = new ArrayList<String>(); private ArrayList<String> conflicts = new ArrayList<String>();
@ -112,9 +117,9 @@ public class DirCacheCheckout {
private boolean emptyDirCache; private boolean emptyDirCache;
/** /**
* @return a list of updated paths and objectIds * @return a list of updated paths and smudgeFilterCommands
*/ */
public Map<String, ObjectId> getUpdated() { public Map<String, String> getUpdated() {
return updated; return updated;
} }
@ -447,7 +452,8 @@ public class DirCacheCheckout {
for (String path : updated.keySet()) { for (String path : updated.keySet()) {
DirCacheEntry entry = dc.getEntry(path); DirCacheEntry entry = dc.getEntry(path);
if (!FileMode.GITLINK.equals(entry.getRawMode())) if (!FileMode.GITLINK.equals(entry.getRawMode()))
checkoutEntry(repo, entry, objectReader, false); checkoutEntry(repo, entry, objectReader, false,
updated.get(path));
} }
// commit the index builder - a new index is persisted // commit the index builder - a new index is persisted
@ -996,9 +1002,12 @@ public class DirCacheCheckout {
removed.add(path); removed.add(path);
} }
private void update(String path, ObjectId mId, FileMode mode) { private void update(String path, ObjectId mId, FileMode mode)
throws IOException {
if (!FileMode.TREE.equals(mode)) { if (!FileMode.TREE.equals(mode)) {
updated.put(path, mId); updated.put(path,
walk.getFilterCommand(Constants.ATTR_FILTER_TYPE_SMUDGE));
DirCacheEntry entry = new DirCacheEntry(path, DirCacheEntry.STAGE_0); DirCacheEntry entry = new DirCacheEntry(path, DirCacheEntry.STAGE_0);
entry.setObjectId(mId); entry.setObjectId(mId);
entry.setFileMode(mode); entry.setFileMode(mode);
@ -1150,7 +1159,7 @@ public class DirCacheCheckout {
*/ */
public static void checkoutEntry(Repository repo, DirCacheEntry entry, public static void checkoutEntry(Repository repo, DirCacheEntry entry,
ObjectReader or) throws IOException { ObjectReader or) throws IOException {
checkoutEntry(repo, entry, or, false); checkoutEntry(repo, entry, or, false, null);
} }
/** /**
@ -1186,6 +1195,46 @@ public class DirCacheCheckout {
*/ */
public static void checkoutEntry(Repository repo, DirCacheEntry entry, public static void checkoutEntry(Repository repo, DirCacheEntry entry,
ObjectReader or, boolean deleteRecursive) throws IOException { ObjectReader or, boolean deleteRecursive) throws IOException {
checkoutEntry(repo, entry, or, deleteRecursive, null);
}
/**
* Updates the file in the working tree with content and mode from an entry
* in the index. The new content is first written to a new temporary file in
* the same directory as the real file. Then that new file is renamed to the
* final filename.
*
* <p>
* <b>Note:</b> if the entry path on local file system exists as a file, it
* will be deleted and if it exists as a directory, it will be deleted
* recursively, independently if has any content.
* </p>
*
* <p>
* TODO: this method works directly on File IO, we may need another
* abstraction (like WorkingTreeIterator). This way we could tell e.g.
* Eclipse that Files in the workspace got changed
* </p>
*
* @param repo
* repository managing the destination work tree.
* @param entry
* the entry containing new mode and content
* @param or
* object reader to use for checkout
* @param deleteRecursive
* true to recursively delete final path if it exists on the file
* system
* @param smudgeFilterCommand
* the filter command to be run for smudging the entry to be
* checked out
*
* @throws IOException
* @since 4.2
*/
public static void checkoutEntry(Repository repo, DirCacheEntry entry,
ObjectReader or, boolean deleteRecursive,
String smudgeFilterCommand) throws IOException {
ObjectLoader ol = or.open(entry.getObjectId()); ObjectLoader ol = or.open(entry.getObjectId());
File f = new File(repo.getWorkTree(), entry.getPathString()); File f = new File(repo.getWorkTree(), entry.getPathString());
File parentDir = f.getParentFile(); File parentDir = f.getParentFile();
@ -1210,14 +1259,52 @@ public class DirCacheCheckout {
OutputStream channel = new FileOutputStream(tmpFile); OutputStream channel = new FileOutputStream(tmpFile);
if (opt.getAutoCRLF() == AutoCRLF.TRUE) if (opt.getAutoCRLF() == AutoCRLF.TRUE)
channel = new AutoCRLFOutputStream(channel); channel = new AutoCRLFOutputStream(channel);
if (smudgeFilterCommand != null) {
ProcessBuilder filterProcessBuilder = fs
.runInShell(smudgeFilterCommand, new String[0]);
filterProcessBuilder.directory(repo.getWorkTree());
filterProcessBuilder.environment().put(Constants.GIT_DIR_KEY,
repo.getDirectory().getAbsolutePath());
ExecutionResult result;
int rc;
try {
// TODO: wire correctly with AUTOCRLF
result = fs.execute(filterProcessBuilder, ol.openStream());
rc = result.getRc();
if (rc == 0) {
result.getStdout().writeTo(channel,
NullProgressMonitor.INSTANCE);
}
} catch (IOException | InterruptedException e) {
throw new IOException(new FilterFailedException(e,
smudgeFilterCommand, entry.getPathString()));
} finally {
channel.close();
}
if (rc != 0) {
throw new IOException(new FilterFailedException(rc,
smudgeFilterCommand, entry.getPathString(),
result.getStdout().toByteArray(MAX_EXCEPTION_TEXT_SIZE),
RawParseUtils.decode(result.getStderr()
.toByteArray(MAX_EXCEPTION_TEXT_SIZE))));
}
} else {
try { try {
ol.copyTo(channel); ol.copyTo(channel);
} finally { } finally {
channel.close(); channel.close();
} }
entry.setLength(opt.getAutoCRLF() == AutoCRLF.TRUE ? // }
tmpFile.length() // AutoCRLF wants on-disk-size // The entry needs to correspond to the on-disk filesize. If the content
: (int) ol.getSize()); // was filtered (either by autocrlf handling or smudge filters) ask the
// filesystem again for the length. Otherwise the objectloader knows the
// size
if (opt.getAutoCRLF() == AutoCRLF.TRUE || smudgeFilterCommand != null) {
entry.setLength(tmpFile.length());
} else {
entry.setLength(ol.getSize());
}
if (opt.isFileMode() && fs.supportsExecute()) { if (opt.isFileMode() && fs.supportsExecute()) {
if (FileMode.EXECUTABLE_FILE.equals(entry.getRawMode())) { if (FileMode.EXECUTABLE_FILE.equals(entry.getRawMode())) {
@ -1255,24 +1342,6 @@ public class DirCacheCheckout {
checkValidPathSegment(chk, i); checkValidPathSegment(chk, i);
} }
/**
* Check if path is a valid path for a checked out file name or ref name.
*
* @param path
* @throws InvalidPathException
* if the path is invalid
* @since 3.3
*/
static void checkValidPath(String path) throws InvalidPathException {
try {
SystemReader.getInstance().checkPath(path);
} catch (CorruptObjectException e) {
InvalidPathException p = new InvalidPathException(path);
p.initCause(e);
throw p;
}
}
private static void checkValidPathSegment(ObjectChecker chk, private static void checkValidPathSegment(ObjectChecker chk,
CanonicalTreeParser t) throws InvalidPathException { CanonicalTreeParser t) throws InvalidPathException {
try { try {

31
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java vendored

@ -65,6 +65,7 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.MutableInteger; import org.eclipse.jgit.util.MutableInteger;
import org.eclipse.jgit.util.NB; import org.eclipse.jgit.util.NB;
import org.eclipse.jgit.util.SystemReader;
/** /**
* A single file (or stage of a file) in a {@link DirCache}. * A single file (or stage of a file) in a {@link DirCache}.
@ -191,7 +192,7 @@ public class DirCacheEntry {
} }
try { try {
DirCacheCheckout.checkValidPath(toString(path)); checkPath(path);
} catch (InvalidPathException e) { } catch (InvalidPathException e) {
CorruptObjectException p = CorruptObjectException p =
new CorruptObjectException(e.getMessage()); new CorruptObjectException(e.getMessage());
@ -263,7 +264,7 @@ public class DirCacheEntry {
/** /**
* Create an empty entry at the specified stage. * Create an empty entry at the specified stage.
* *
* @param newPath * @param path
* name of the cache entry, in the standard encoding. * name of the cache entry, in the standard encoding.
* @param stage * @param stage
* the stage index of the new entry. * the stage index of the new entry.
@ -274,16 +275,16 @@ public class DirCacheEntry {
* range 0..3, inclusive. * range 0..3, inclusive.
*/ */
@SuppressWarnings("boxing") @SuppressWarnings("boxing")
public DirCacheEntry(final byte[] newPath, final int stage) { public DirCacheEntry(byte[] path, final int stage) {
DirCacheCheckout.checkValidPath(toString(newPath)); checkPath(path);
if (stage < 0 || 3 < stage) if (stage < 0 || 3 < stage)
throw new IllegalArgumentException(MessageFormat.format( throw new IllegalArgumentException(MessageFormat.format(
JGitText.get().invalidStageForPath, JGitText.get().invalidStageForPath,
stage, toString(newPath))); stage, toString(path)));
info = new byte[INFO_LEN]; info = new byte[INFO_LEN];
infoOffset = 0; infoOffset = 0;
path = newPath; this.path = path;
int flags = ((stage & 0x3) << 12); int flags = ((stage & 0x3) << 12);
if (path.length < NAME_MASK) if (path.length < NAME_MASK)
@ -498,12 +499,16 @@ public class DirCacheEntry {
switch (mode.getBits() & FileMode.TYPE_MASK) { switch (mode.getBits() & FileMode.TYPE_MASK) {
case FileMode.TYPE_MISSING: case FileMode.TYPE_MISSING:
case FileMode.TYPE_TREE: case FileMode.TYPE_TREE:
throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidModeForPath throw new IllegalArgumentException(MessageFormat.format(
, mode, getPathString())); JGitText.get().invalidModeForPath, mode, getPathString()));
} }
NB.encodeInt32(info, infoOffset + P_MODE, mode.getBits()); NB.encodeInt32(info, infoOffset + P_MODE, mode.getBits());
} }
void setFileMode(int mode) {
NB.encodeInt32(info, infoOffset + P_MODE, mode);
}
/** /**
* Get the cached creation time of this file, in milliseconds. * Get the cached creation time of this file, in milliseconds.
* *
@ -730,6 +735,16 @@ public class DirCacheEntry {
return 0; return 0;
} }
private static void checkPath(byte[] path) {
try {
SystemReader.getInstance().checkPath(path);
} catch (CorruptObjectException e) {
InvalidPathException p = new InvalidPathException(toString(path));
p.initCause(e);
throw p;
}
}
private static String toString(final byte[] path) { private static String toString(final byte[] path) {
return Constants.CHARSET.decode(ByteBuffer.wrap(path)).toString(); return Constants.CHARSET.decode(ByteBuffer.wrap(path)).toString();
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save