Browse Source

Merge branch 'master' into stable-4.2

Change-Id: Ieec4f51aedadf5734ae0e3f4e8713248a3c4fc52
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
stable-4.2
Matthias Sohn 9 years ago
parent
commit
4ec84fac86
  1. 15
      .buckconfig
  2. 1
      .buckversion
  3. 2
      .gitignore
  4. 45
      BUCK
  5. 125
      lib/BUCK
  6. 56
      lib/jetty/BUCK
  7. 13
      org.eclipse.jgit.archive/BUCK
  8. 12
      org.eclipse.jgit.http.apache/BUCK
  9. 3
      org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
  10. 27
      org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
  11. 10
      org.eclipse.jgit.http.server/BUCK
  12. 40
      org.eclipse.jgit.http.test/BUCK
  13. 4
      org.eclipse.jgit.http.test/pom.xml
  14. 25
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
  15. 6
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java
  16. 93
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
  17. 58
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
  18. 18
      org.eclipse.jgit.junit.http/BUCK
  19. 10
      org.eclipse.jgit.junit/BUCK
  20. 9
      org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
  21. 38
      org.eclipse.jgit.pgm.test/BUCK
  22. 1
      org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
  23. 30
      org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests (Java8) (de).launch
  24. 79
      org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
  25. 175
      org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java
  26. 15
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/AddTest.java
  27. 95
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
  28. 194
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/BranchTest.java
  29. 41
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
  30. 100
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CommitTest.java
  31. 34
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java
  32. 10
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeTest.java
  33. 28
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RepoTest.java
  34. 39
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java
  35. 8
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java
  36. 2
      org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
  37. 70
      org.eclipse.jgit.pgm/BUCK
  38. 2
      org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
  39. 1
      org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
  40. 11
      org.eclipse.jgit.pgm/pom.xml
  41. 8
      org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
  42. 130
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
  43. 7
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
  44. 17
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
  45. 15
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java
  46. 129
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
  47. 9
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
  48. 3
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java
  49. 2
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
  50. 10
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
  51. 8
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
  52. 6
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
  53. 83
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
  54. 145
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java
  55. 15
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
  56. 161
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java
  57. 52
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java
  58. 95
      org.eclipse.jgit.test/BUCK
  59. 1
      org.eclipse.jgit.test/META-INF/MANIFEST.MF
  60. 31
      org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 8) (de).launch
  61. 98
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
  62. 31
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
  63. 65
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
  64. 56
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
  65. 121
      org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java
  66. 7
      org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
  67. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileRepositoryBuilderTest.java
  68. 70
      org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
  69. 53
      org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
  70. 685
      org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java
  71. 303
      org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeTest.java
  72. 6
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
  73. 91
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
  74. 1393
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
  75. 319
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_TreeTest.java
  76. 41
      org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java
  77. 85
      org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java
  78. 39
      org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java
  79. 15
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java
  80. 6
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
  81. 18
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
  82. 50
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
  83. 69
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java
  84. 42
      org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
  85. 45
      org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java
  86. 150
      org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java
  87. 3
      org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java
  88. 24
      org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java
  89. 118
      org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java
  90. 7
      org.eclipse.jgit.ui/BUCK
  91. 7
      org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java
  92. 40
      org.eclipse.jgit/.settings/.api_filters
  93. 20
      org.eclipse.jgit/BUCK
  94. 3
      org.eclipse.jgit/META-INF/MANIFEST.MF
  95. 11
      org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
  96. 112
      org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
  97. 9
      org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
  98. 11
      org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
  99. 13
      org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
  100. 44
      org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
  101. Some files were not shown because too many files have changed in this diff Show More

15
.buckconfig

@ -0,0 +1,15 @@
[buildfile]
includes = //tools/default.defs
[java]
src_roots = src, resources, tst
[project]
ignore = .git
[cache]
mode = dir
[download]
maven_repo = http://repo1.maven.org/maven2
in_build = true

1
.buckversion

@ -0,0 +1 @@
1b03b4313b91b634bd604fc3487a05f877e59dee

2
.gitignore vendored

@ -1,2 +1,4 @@
/target /target
/.project /.project
/buck-cache
/buck-out

45
BUCK

@ -0,0 +1,45 @@
java_library(
name = 'jgit',
exported_deps = ['//org.eclipse.jgit:jgit'],
visibility = ['PUBLIC'],
)
genrule(
name = 'jgit_src',
cmd = 'ln -s $(location //org.eclipse.jgit:jgit_src) $OUT',
out = 'jgit_src.zip',
visibility = ['PUBLIC'],
)
java_library(
name = 'jgit-servlet',
exported_deps = [
':jgit',
'//org.eclipse.jgit.http.server:jgit-servlet'
],
visibility = ['PUBLIC'],
)
java_library(
name = 'jgit-archive',
exported_deps = [
':jgit',
'//org.eclipse.jgit.archive:jgit-archive'
],
visibility = ['PUBLIC'],
)
java_library(
name = 'junit',
exported_deps = [
':jgit',
'//org.eclipse.jgit.junit:junit'
],
visibility = ['PUBLIC'],
)
genrule(
name = 'jgit_bin',
cmd = 'ln -s $(location //org.eclipse.jgit.pgm:jgit) $OUT',
out = 'jgit_bin',
)

125
lib/BUCK

@ -0,0 +1,125 @@
maven_jar(
name = 'jsch',
bin_sha1 = '658b682d5c817b27ae795637dfec047c63d29935',
src_sha1 = '791359d94d6edcace686a56d0727ee093a2f7c33',
group = 'com.jcraft',
artifact = 'jsch',
version = '0.1.53',
)
maven_jar(
name = 'javaewah',
bin_sha1 = 'eceaf316a8faf0e794296ebe158ae110c7d72a5a',
src_sha1 = 'a50d78eb630e05439461f3130b94b3bcd1ea6f03',
group = 'com.googlecode.javaewah',
artifact = 'JavaEWAH',
version = '0.7.9',
)
maven_jar(
name = 'httpcomponents',
bin_sha1 = '4c47155e3e6c9a41a28db36680b828ced53b8af4',
src_sha1 = 'af4d76be0c46ee26b0d9d1d4a34d244a633cac84',
group = 'org.apache.httpcomponents',
artifact = 'httpclient',
version = '4.3.6',
)
maven_jar(
name = 'httpcore',
bin_sha1 = 'f91b7a4aadc5cf486df6e4634748d7dd7a73f06d',
src_sha1 = '1b0aa62a6a91e9fa00c16f0a4a2c874804ed3b1e',
group = 'org.apache.httpcomponents',
artifact = 'httpcore',
version = '4.3.3',
)
maven_jar(
name = 'commons-logging',
bin_sha1 = 'f6f66e966c70a83ffbdb6f17a0919eaf7c8aca7f',
src_sha1 = '28bb0405fddaf04f15058fbfbe01fe2780d7d3b6',
group = 'commons-logging',
artifact = 'commons-logging',
version = '1.1.3',
)
maven_jar(
name = 'slf4j-api',
bin_sha1 = '0081d61b7f33ebeab314e07de0cc596f8e858d97',
src_sha1 = '58d38f68d4a867d4552ae27960bb348d7eaa1297',
group = 'org.slf4j',
artifact = 'slf4j-api',
version = '1.7.2',
)
maven_jar(
name = 'slf4j-simple',
bin_sha1 = '760055906d7353ba4f7ce1b8908bc6b2e91f39fa',
src_sha1 = '09474919128b3a7fcf21a5f9c907f5251f234544',
group = 'org.slf4j',
artifact = 'slf4j-simple',
version = '1.7.2',
)
maven_jar(
name = 'servlet-api',
bin_sha1 = '3cd63d075497751784b2fa84be59432f4905bf7c',
src_sha1 = 'ab3976d4574c48d22dc1abf6a9e8bd0fdf928223',
group = 'javax.servlet',
artifact = 'javax.servlet-api',
version = '3.1.0',
)
maven_jar(
name = 'commons-compress',
bin_sha1 = 'c7d9b580aff9e9f1998361f16578e63e5c064699',
src_sha1 = '396b81bdfd0fb617178e1707ef64832215307c78',
group = 'org.apache.commons',
artifact = 'commons-compress',
version = '1.6',
)
maven_jar(
name = 'tukaani-xz',
bin_sha1 = '66db21c8484120cb6a51b5b3ea47b6f383942bec',
src_sha1 = '6396220725701d767c553902c41120d7bf38e9f5',
group = 'org.tukaani',
artifact = 'xz',
version = '1.3',
)
maven_jar(
name = 'args4j',
bin_sha1 = '139441471327b9cc6d56436cb2a31e60eb6ed2ba',
src_sha1 = '22631b78cc8f60a6918557e8cbdb33e90f63a77f',
group = 'args4j',
artifact = 'args4j',
version = '2.0.15',
)
maven_jar(
name = 'junit',
bin_sha1 = '4e031bb61df09069aeb2bffb4019e7a5034a4ee0',
src_sha1 = '28e0ad201304e4a4abf999ca0570b7cffc352c3c',
group = 'junit',
artifact = 'junit',
version = '4.11',
)
maven_jar(
name = 'hamcrest-library',
bin_sha1 = '4785a3c21320980282f9f33d0d1264a69040538f',
src_sha1 = '047a7ee46628ab7133129cd7cef1e92657bc275e',
group = 'org.hamcrest',
artifact = 'hamcrest-library',
version = '1.3',
)
maven_jar(
name = 'hamcrest-core',
bin_sha1 = '42a25dc3219429f0e5d060061f71acb49bf010a0',
src_sha1 = '1dc37250fbc78e23a65a67fbbaf71d2e9cbc3c0b',
group = 'org.hamcrest',
artifact = 'hamcrest-core',
version = '1.3',
)

56
lib/jetty/BUCK

@ -0,0 +1,56 @@
VERSION = '9.2.13.v20150730'
GROUP = 'org.eclipse.jetty'
maven_jar(
name = 'servlet',
bin_sha1 = '5ad6e38015a97ae9a60b6c2ad744ccfa9cf93a50',
src_sha1 = '78fbec19321150552d91f9e079c2f2ca33222b01',
group = GROUP,
artifact = 'jetty-servlet',
version = VERSION,
)
maven_jar(
name = 'security',
bin_sha1 = 'cc7c7f27ec4cc279253be1675d9e47e58b995943',
src_sha1 = '75632ebdf8bd651faafb97106c92496db59e165d',
group = GROUP,
artifact = 'jetty-security',
version = VERSION,
)
maven_jar(
name = 'server',
bin_sha1 = '5be7d1da0a7abffd142de3091d160717c120b6ab',
src_sha1 = '203e123f83efe2a5b8a9c74854c7897fe3563302',
group = GROUP,
artifact = 'jetty-server',
version = VERSION,
)
maven_jar(
name = 'http',
bin_sha1 = '23a745d9177ef67ef53cc46b9b70c5870082efc2',
src_sha1 = '5f87f7ff2057cd4b0995bc4fffe17b2aff64c130',
group = GROUP,
artifact = 'jetty-http',
version = VERSION,
)
maven_jar(
name = 'io',
bin_sha1 = '7a351e6a1b63dfd56b6632623f7ca2793ffb67ad',
src_sha1 = 'bbd61a84b748fc295456e1c5c3070aaf40a68f62',
group = GROUP,
artifact = 'jetty-io',
version = VERSION,
)
maven_jar(
name = 'util',
bin_sha1 = 'c101476360a7cdd0670462de04053507d5e70c97',
src_sha1 = '15ceecce141971b4e0facb861b3d10120ad6ce03',
group = GROUP,
artifact = 'jetty-util',
version = VERSION,
)

13
org.eclipse.jgit.archive/BUCK

@ -0,0 +1,13 @@
java_library(
name = 'jgit-archive',
srcs = glob(
['src/**'],
excludes = ['src/org/eclipse/jgit/archive/FormatActivator.java'],
),
resources = glob(['resources/**']),
provided_deps = [
'//org.eclipse.jgit:jgit',
'//lib:commons-compress',
],
visibility = ['PUBLIC'],
)

12
org.eclipse.jgit.http.apache/BUCK

@ -0,0 +1,12 @@
java_library(
name = 'http-apache',
srcs = glob(['src/**']),
resources = glob(['resources/**']),
deps = [
'//org.eclipse.jgit:jgit',
'//lib:commons-logging',
'//lib:httpcomponents',
'//lib:httpcore',
],
visibility = ['PUBLIC'],
)

3
org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF

@ -7,7 +7,8 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-Localization: plugin Bundle-Localization: plugin
Bundle-Vendor: %Provider-Name Bundle-Vendor: %Provider-Name
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Import-Package: org.apache.http;version="[4.1.0,5.0.0)", Import-Package: org.apache.commons.logging;version="[1.1.1,2.0.0)",
org.apache.http;version="[4.1.0,5.0.0)",
org.apache.http.client;version="[4.1.0,5.0.0)", org.apache.http.client;version="[4.1.0,5.0.0)",
org.apache.http.client.methods;version="[4.1.0,5.0.0)", org.apache.http.client.methods;version="[4.1.0,5.0.0)",
org.apache.http.client.params;version="[4.1.0,5.0.0)", org.apache.http.client.params;version="[4.1.0,5.0.0)",

27
org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java

@ -100,7 +100,7 @@ import org.eclipse.jgit.util.TemporaryBuffer.LocalFile;
public class HttpClientConnection implements HttpConnection { public class HttpClientConnection implements HttpConnection {
HttpClient client; HttpClient client;
String urlStr; URL url;
HttpUriRequest req; HttpUriRequest req;
@ -176,16 +176,19 @@ public class HttpClientConnection implements HttpConnection {
/** /**
* @param urlStr * @param urlStr
* @throws MalformedURLException
*/ */
public HttpClientConnection(String urlStr) { public HttpClientConnection(String urlStr) throws MalformedURLException {
this(urlStr, null); this(urlStr, null);
} }
/** /**
* @param urlStr * @param urlStr
* @param proxy * @param proxy
* @throws MalformedURLException
*/ */
public HttpClientConnection(String urlStr, Proxy proxy) { public HttpClientConnection(String urlStr, Proxy proxy)
throws MalformedURLException {
this(urlStr, proxy, null); this(urlStr, proxy, null);
} }
@ -193,10 +196,12 @@ public class HttpClientConnection implements HttpConnection {
* @param urlStr * @param urlStr
* @param proxy * @param proxy
* @param cl * @param cl
* @throws MalformedURLException
*/ */
public HttpClientConnection(String urlStr, Proxy proxy, HttpClient cl) { public HttpClientConnection(String urlStr, Proxy proxy, HttpClient cl)
throws MalformedURLException {
this.client = cl; this.client = cl;
this.urlStr = urlStr; this.url = new URL(urlStr);
this.proxy = proxy; this.proxy = proxy;
} }
@ -206,11 +211,7 @@ public class HttpClientConnection implements HttpConnection {
} }
public URL getURL() { public URL getURL() {
try { return url;
return new URL(urlStr);
} catch (MalformedURLException e) {
return null;
}
} }
public String getResponseMessage() throws IOException { public String getResponseMessage() throws IOException {
@ -250,11 +251,11 @@ public class HttpClientConnection implements HttpConnection {
public void setRequestMethod(String method) throws ProtocolException { public void setRequestMethod(String method) throws ProtocolException {
this.method = method; this.method = method;
if ("GET".equalsIgnoreCase(method)) //$NON-NLS-1$ if ("GET".equalsIgnoreCase(method)) //$NON-NLS-1$
req = new HttpGet(urlStr); req = new HttpGet(url.toString());
else if ("PUT".equalsIgnoreCase(method)) //$NON-NLS-1$ else if ("PUT".equalsIgnoreCase(method)) //$NON-NLS-1$
req = new HttpPut(urlStr); req = new HttpPut(url.toString());
else if ("POST".equalsIgnoreCase(method)) //$NON-NLS-1$ else if ("POST".equalsIgnoreCase(method)) //$NON-NLS-1$
req = new HttpPost(urlStr); req = new HttpPost(url.toString());
else { else {
this.method = null; this.method = null;
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();

10
org.eclipse.jgit.http.server/BUCK

@ -0,0 +1,10 @@
java_library(
name = 'jgit-servlet',
srcs = glob(['src/**']),
resources = glob(['resources/**']),
provided_deps = [
'//org.eclipse.jgit:jgit',
'//lib:servlet-api',
],
visibility = ['PUBLIC'],
)

40
org.eclipse.jgit.http.test/BUCK

@ -0,0 +1,40 @@
TESTS = glob(['tst/**/*.java'])
for t in TESTS:
n = t[len('tst/'):len(t)-len('.java')].replace('/', '.')
java_test(
name = n,
labels = ['http'],
srcs = [t],
deps = [
':helpers',
'//org.eclipse.jgit:jgit',
'//org.eclipse.jgit.http.apache:http-apache',
'//org.eclipse.jgit.http.server:jgit-servlet',
'//org.eclipse.jgit.junit:junit',
'//org.eclipse.jgit.junit.http:junit-http',
'//lib:hamcrest-core',
'//lib:hamcrest-library',
'//lib:junit',
'//lib:servlet-api',
'//lib/jetty:http',
'//lib/jetty:io',
'//lib/jetty:server',
'//lib/jetty:servlet',
'//lib/jetty:security',
'//lib/jetty:util',
],
source_under_test = ['//org.eclipse.jgit.http.server:jgit-servlet'],
)
java_library(
name = 'helpers',
srcs = glob(['src/**/*.java']),
deps = [
'//org.eclipse.jgit:jgit',
'//org.eclipse.jgit.http.server:jgit-servlet',
'//org.eclipse.jgit.junit:junit',
'//org.eclipse.jgit.junit.http:junit-http',
'//lib:junit',
],
)

4
org.eclipse.jgit.http.test/pom.xml

@ -134,6 +134,10 @@
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<configuration> <configuration>
<argLine>-Djava.io.tmpdir=${project.build.directory} -Xmx300m</argLine> <argLine>-Djava.io.tmpdir=${project.build.directory} -Xmx300m</argLine>
<includes>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>

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

@ -140,8 +140,7 @@ public class DumbClientDumbServerTest extends HttpTestCase {
assertEquals("http", remoteURI.getScheme()); assertEquals("http", remoteURI.getScheme());
Map<String, Ref> map; Map<String, Ref> map;
Transport t = Transport.open(dst, remoteURI); try (Transport t = Transport.open(dst, remoteURI)) {
try {
// I didn't make up these public interface names, I just // I didn't make up these public interface names, I just
// approved them for inclusion into the code base. Sorry. // approved them for inclusion into the code base. Sorry.
// --spearce // --spearce
@ -149,14 +148,9 @@ public class DumbClientDumbServerTest extends HttpTestCase {
assertTrue("isa TransportHttp", t instanceof TransportHttp); assertTrue("isa TransportHttp", t instanceof TransportHttp);
assertTrue("isa HttpTransport", t instanceof HttpTransport); assertTrue("isa HttpTransport", t instanceof HttpTransport);
FetchConnection c = t.openFetch(); try (FetchConnection c = t.openFetch()) {
try {
map = c.getRefsMap(); map = c.getRefsMap();
} finally {
c.close();
} }
} finally {
t.close();
} }
assertNotNull("have map of refs", map); assertNotNull("have map of refs", map);
@ -201,11 +195,8 @@ public class DumbClientDumbServerTest extends HttpTestCase {
Repository dst = createBareRepository(); Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt)); assertFalse(dst.hasObject(A_txt));
Transport t = Transport.open(dst, remoteURI); try (Transport t = Transport.open(dst, remoteURI)) {
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
} }
assertTrue(dst.hasObject(A_txt)); assertTrue(dst.hasObject(A_txt));
@ -226,11 +217,8 @@ public class DumbClientDumbServerTest extends HttpTestCase {
Repository dst = createBareRepository(); Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt)); assertFalse(dst.hasObject(A_txt));
Transport t = Transport.open(dst, remoteURI); try (Transport t = Transport.open(dst, remoteURI)) {
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
} }
assertTrue(dst.hasObject(A_txt)); assertTrue(dst.hasObject(A_txt));
@ -265,8 +253,7 @@ public class DumbClientDumbServerTest extends HttpTestCase {
final RevCommit Q = src.commit().create(); final RevCommit Q = src.commit().create();
final Repository db = src.getRepository(); final Repository db = src.getRepository();
Transport t = Transport.open(db, remoteURI); try (Transport t = Transport.open(db, remoteURI)) {
try {
try { try {
t.push(NullProgressMonitor.INSTANCE, push(src, Q)); t.push(NullProgressMonitor.INSTANCE, push(src, Q));
fail("push incorrectly completed against a dumb server"); fail("push incorrectly completed against a dumb server");
@ -274,8 +261,6 @@ public class DumbClientDumbServerTest extends HttpTestCase {
String exp = "remote does not support smart HTTP push"; String exp = "remote does not support smart HTTP push";
assertEquals(exp, nse.getMessage()); assertEquals(exp, nse.getMessage());
} }
} finally {
t.close();
} }
} }
} }

6
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java

@ -60,6 +60,7 @@ import org.eclipse.jgit.http.server.GitServlet;
import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory; import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory;
import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.junit.http.HttpTestCase; import org.eclipse.jgit.junit.http.HttpTestCase;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectChecker; import org.eclipse.jgit.lib.ObjectChecker;
@ -221,8 +222,9 @@ public class GitServletResponseTests extends HttpTestCase {
preHook = null; preHook = null;
oc = new ObjectChecker() { oc = new ObjectChecker() {
@Override @Override
public void checkCommit(byte[] raw) throws CorruptObjectException { public void checkCommit(AnyObjectId id, byte[] raw)
throw new IllegalStateException(); throws CorruptObjectException {
throw new CorruptObjectException("refusing all commits");
} }
}; };

93
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java

@ -157,8 +157,7 @@ public class HttpClientTests extends HttpTestCase {
public void testRepositoryNotFound_Dumb() throws Exception { public void testRepositoryNotFound_Dumb() throws Exception {
URIish uri = toURIish("/dumb.none/not-found"); URIish uri = toURIish("/dumb.none/not-found");
Repository dst = createBareRepository(); Repository dst = createBareRepository();
Transport t = Transport.open(dst, uri); try (Transport t = Transport.open(dst, uri)) {
try {
try { try {
t.openFetch(); t.openFetch();
fail("connection opened to not found repository"); fail("connection opened to not found repository");
@ -167,8 +166,6 @@ public class HttpClientTests extends HttpTestCase {
+ "/info/refs?service=git-upload-pack not found"; + "/info/refs?service=git-upload-pack not found";
assertEquals(exp, err.getMessage()); assertEquals(exp, err.getMessage());
} }
} finally {
t.close();
} }
} }
@ -176,8 +173,7 @@ public class HttpClientTests extends HttpTestCase {
public void testRepositoryNotFound_Smart() throws Exception { public void testRepositoryNotFound_Smart() throws Exception {
URIish uri = toURIish("/smart.none/not-found"); URIish uri = toURIish("/smart.none/not-found");
Repository dst = createBareRepository(); Repository dst = createBareRepository();
Transport t = Transport.open(dst, uri); try (Transport t = Transport.open(dst, uri)) {
try {
try { try {
t.openFetch(); t.openFetch();
fail("connection opened to not found repository"); fail("connection opened to not found repository");
@ -186,8 +182,6 @@ public class HttpClientTests extends HttpTestCase {
+ "/info/refs?service=git-upload-pack not found"; + "/info/refs?service=git-upload-pack not found";
assertEquals(exp, err.getMessage()); assertEquals(exp, err.getMessage());
} }
} finally {
t.close();
} }
} }
@ -201,16 +195,9 @@ public class HttpClientTests extends HttpTestCase {
Repository dst = createBareRepository(); Repository dst = createBareRepository();
Ref head; Ref head;
Transport t = Transport.open(dst, dumbAuthNoneURI); try (Transport t = Transport.open(dst, dumbAuthNoneURI);
try { FetchConnection c = t.openFetch()) {
FetchConnection c = t.openFetch();
try {
head = c.getRef(Constants.HEAD); head = c.getRef(Constants.HEAD);
} finally {
c.close();
}
} finally {
t.close();
} }
assertNotNull("has " + Constants.HEAD, head); assertNotNull("has " + Constants.HEAD, head);
assertEquals(Q, head.getObjectId()); assertEquals(Q, head.getObjectId());
@ -225,16 +212,9 @@ public class HttpClientTests extends HttpTestCase {
Repository dst = createBareRepository(); Repository dst = createBareRepository();
Ref head; Ref head;
Transport t = Transport.open(dst, dumbAuthNoneURI); try (Transport t = Transport.open(dst, dumbAuthNoneURI);
try { FetchConnection c = t.openFetch()) {
FetchConnection c = t.openFetch();
try {
head = c.getRef(Constants.HEAD); head = c.getRef(Constants.HEAD);
} finally {
c.close();
}
} finally {
t.close();
} }
assertNull("has no " + Constants.HEAD, head); assertNull("has no " + Constants.HEAD, head);
} }
@ -249,16 +229,9 @@ public class HttpClientTests extends HttpTestCase {
Repository dst = createBareRepository(); Repository dst = createBareRepository();
Ref head; Ref head;
Transport t = Transport.open(dst, smartAuthNoneURI); try (Transport t = Transport.open(dst, smartAuthNoneURI);
try { FetchConnection c = t.openFetch()) {
FetchConnection c = t.openFetch();
try {
head = c.getRef(Constants.HEAD); head = c.getRef(Constants.HEAD);
} finally {
c.close();
}
} finally {
t.close();
} }
assertNotNull("has " + Constants.HEAD, head); assertNotNull("has " + Constants.HEAD, head);
assertEquals(Q, head.getObjectId()); assertEquals(Q, head.getObjectId());
@ -268,16 +241,13 @@ public class HttpClientTests extends HttpTestCase {
public void testListRemote_Smart_WithQueryParameters() throws Exception { public void testListRemote_Smart_WithQueryParameters() throws Exception {
URIish myURI = toURIish("/snone/do?r=1&p=test.git"); URIish myURI = toURIish("/snone/do?r=1&p=test.git");
Repository dst = createBareRepository(); Repository dst = createBareRepository();
Transport t = Transport.open(dst, myURI); try (Transport t = Transport.open(dst, myURI)) {
try {
try { try {
t.openFetch(); t.openFetch();
fail("test did not fail to find repository as expected"); fail("test did not fail to find repository as expected");
} catch (NoRemoteRepositoryException err) { } catch (NoRemoteRepositoryException err) {
// expected // expected
} }
} finally {
t.close();
} }
List<AccessEvent> requests = getRequests(); List<AccessEvent> requests = getRequests();
@ -296,33 +266,27 @@ public class HttpClientTests extends HttpTestCase {
@Test @Test
public void testListRemote_Dumb_NeedsAuth() throws Exception { public void testListRemote_Dumb_NeedsAuth() throws Exception {
Repository dst = createBareRepository(); Repository dst = createBareRepository();
Transport t = Transport.open(dst, dumbAuthBasicURI); try (Transport t = Transport.open(dst, dumbAuthBasicURI)) {
try {
try { try {
t.openFetch(); t.openFetch();
fail("connection opened even info/refs needs auth basic"); fail("connection opened even info/refs needs auth basic");
} catch (TransportException err) { } catch (TransportException err) {
String exp = dumbAuthBasicURI + ": " String exp = dumbAuthBasicURI + ": "
+ JGitText.get().notAuthorized; + JGitText.get().noCredentialsProvider;
assertEquals(exp, err.getMessage()); assertEquals(exp, err.getMessage());
} }
} finally {
t.close();
} }
} }
@Test @Test
public void testListRemote_Dumb_Auth() throws Exception { public void testListRemote_Dumb_Auth() throws Exception {
Repository dst = createBareRepository(); Repository dst = createBareRepository();
Transport t = Transport.open(dst, dumbAuthBasicURI); try (Transport t = Transport.open(dst, dumbAuthBasicURI)) {
t.setCredentialsProvider(new UsernamePasswordCredentialsProvider( t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
AppServer.username, AppServer.password)); AppServer.username, AppServer.password));
try { t.openFetch().close();
t.openFetch();
} finally {
t.close();
} }
t = Transport.open(dst, dumbAuthBasicURI); try (Transport t = Transport.open(dst, dumbAuthBasicURI)) {
t.setCredentialsProvider(new UsernamePasswordCredentialsProvider( t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
AppServer.username, "")); AppServer.username, ""));
try { try {
@ -332,26 +296,22 @@ public class HttpClientTests extends HttpTestCase {
String exp = dumbAuthBasicURI + ": " String exp = dumbAuthBasicURI + ": "
+ JGitText.get().notAuthorized; + JGitText.get().notAuthorized;
assertEquals(exp, err.getMessage()); assertEquals(exp, err.getMessage());
} finally { }
t.close();
} }
} }
@Test @Test
public void testListRemote_Smart_UploadPackNeedsAuth() throws Exception { public void testListRemote_Smart_UploadPackNeedsAuth() throws Exception {
Repository dst = createBareRepository(); Repository dst = createBareRepository();
Transport t = Transport.open(dst, smartAuthBasicURI); try (Transport t = Transport.open(dst, smartAuthBasicURI)) {
try {
try { try {
t.openFetch(); t.openFetch();
fail("connection opened even though service disabled"); fail("connection opened even though service disabled");
} catch (TransportException err) { } catch (TransportException err) {
String exp = smartAuthBasicURI + ": " String exp = smartAuthBasicURI + ": "
+ JGitText.get().notAuthorized; + JGitText.get().noCredentialsProvider;
assertEquals(exp, err.getMessage()); assertEquals(exp, err.getMessage());
} }
} finally {
t.close();
} }
} }
@ -363,33 +323,24 @@ public class HttpClientTests extends HttpTestCase {
cfg.save(); cfg.save();
Repository dst = createBareRepository(); Repository dst = createBareRepository();
Transport t = Transport.open(dst, smartAuthNoneURI); try (Transport t = Transport.open(dst, smartAuthNoneURI)) {
try {
try { try {
t.openFetch(); t.openFetch();
fail("connection opened even though service disabled"); fail("connection opened even though service disabled");
} catch (TransportException err) { } catch (TransportException err) {
String exp = smartAuthNoneURI + ": Git access forbidden"; String exp = smartAuthNoneURI + ": "
+ JGitText.get().serviceNotEnabledNoName;
assertEquals(exp, err.getMessage()); assertEquals(exp, err.getMessage());
} }
} finally {
t.close();
} }
} }
@Test @Test
public void testListRemoteWithoutLocalRepository() throws Exception { public void testListRemoteWithoutLocalRepository() throws Exception {
Transport t = Transport.open(smartAuthNoneURI); try (Transport t = Transport.open(smartAuthNoneURI);
try { FetchConnection c = t.openFetch()) {
FetchConnection c = t.openFetch();
try {
Ref head = c.getRef(Constants.HEAD); Ref head = c.getRef(Constants.HEAD);
assertNotNull(head); assertNotNull(head);
} finally {
c.close();
}
} finally {
t.close();
} }
} }
} }

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

@ -211,8 +211,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
assertEquals("http", remoteURI.getScheme()); assertEquals("http", remoteURI.getScheme());
Map<String, Ref> map; Map<String, Ref> map;
Transport t = Transport.open(dst, remoteURI); try (Transport t = Transport.open(dst, remoteURI)) {
try {
// I didn't make up these public interface names, I just // I didn't make up these public interface names, I just
// approved them for inclusion into the code base. Sorry. // approved them for inclusion into the code base. Sorry.
// --spearce // --spearce
@ -226,8 +225,6 @@ public class SmartClientSmartServerTest extends HttpTestCase {
} finally { } finally {
c.close(); c.close();
} }
} finally {
t.close();
} }
assertNotNull("have map of refs", map); assertNotNull("have map of refs", map);
@ -257,8 +254,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
public void testListRemote_BadName() throws IOException, URISyntaxException { public void testListRemote_BadName() throws IOException, URISyntaxException {
Repository dst = createBareRepository(); Repository dst = createBareRepository();
URIish uri = new URIish(this.remoteURI.toString() + ".invalid"); URIish uri = new URIish(this.remoteURI.toString() + ".invalid");
Transport t = Transport.open(dst, uri); try (Transport t = Transport.open(dst, uri)) {
try {
try { try {
t.openFetch(); t.openFetch();
fail("fetch connection opened"); fail("fetch connection opened");
@ -266,8 +262,6 @@ public class SmartClientSmartServerTest extends HttpTestCase {
assertEquals(uri + ": Git repository not found", assertEquals(uri + ": Git repository not found",
notFound.getMessage()); notFound.getMessage());
} }
} finally {
t.close();
} }
List<AccessEvent> requests = getRequests(); List<AccessEvent> requests = getRequests();
@ -288,11 +282,8 @@ public class SmartClientSmartServerTest extends HttpTestCase {
Repository dst = createBareRepository(); Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt)); assertFalse(dst.hasObject(A_txt));
Transport t = Transport.open(dst, remoteURI); try (Transport t = Transport.open(dst, remoteURI)) {
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
} }
assertTrue(dst.hasObject(A_txt)); assertTrue(dst.hasObject(A_txt));
@ -331,11 +322,8 @@ public class SmartClientSmartServerTest extends HttpTestCase {
// Bootstrap by doing the clone. // Bootstrap by doing the clone.
// //
TestRepository dst = createTestRepository(); TestRepository dst = createTestRepository();
Transport t = Transport.open(dst.getRepository(), remoteURI); try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
} }
assertEquals(B, dst.getRepository().exactRef(master).getObjectId()); assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
List<AccessEvent> cloneRequests = getRequests(); List<AccessEvent> cloneRequests = getRequests();
@ -352,11 +340,8 @@ public class SmartClientSmartServerTest extends HttpTestCase {
// Now incrementally update. // Now incrementally update.
// //
t = Transport.open(dst.getRepository(), remoteURI); try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
} }
assertEquals(Z, dst.getRepository().exactRef(master).getObjectId()); assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
@ -394,11 +379,8 @@ public class SmartClientSmartServerTest extends HttpTestCase {
// Bootstrap by doing the clone. // Bootstrap by doing the clone.
// //
TestRepository dst = createTestRepository(); TestRepository dst = createTestRepository();
Transport t = Transport.open(dst.getRepository(), remoteURI); try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
} }
assertEquals(B, dst.getRepository().exactRef(master).getObjectId()); assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
List<AccessEvent> cloneRequests = getRequests(); List<AccessEvent> cloneRequests = getRequests();
@ -418,11 +400,8 @@ public class SmartClientSmartServerTest extends HttpTestCase {
// Now incrementally update. // Now incrementally update.
// //
t = Transport.open(dst.getRepository(), remoteURI); try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
} }
assertEquals(Z, dst.getRepository().exactRef(master).getObjectId()); assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
@ -474,8 +453,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
Repository dst = createBareRepository(); Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt)); assertFalse(dst.hasObject(A_txt));
Transport t = Transport.open(dst, brokenURI); try (Transport t = Transport.open(dst, brokenURI)) {
try {
try { try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
fail("fetch completed despite upload-pack being broken"); fail("fetch completed despite upload-pack being broken");
@ -485,8 +463,6 @@ public class SmartClientSmartServerTest extends HttpTestCase {
+ " received Content-Type text/plain; charset=UTF-8"; + " received Content-Type text/plain; charset=UTF-8";
assertEquals(exp, err.getMessage()); assertEquals(exp, err.getMessage());
} }
} finally {
t.close();
} }
List<AccessEvent> requests = getRequests(); List<AccessEvent> requests = getRequests();
@ -517,12 +493,10 @@ public class SmartClientSmartServerTest extends HttpTestCase {
final RevCommit Q = src.commit().add("Q", Q_txt).create(); final RevCommit Q = src.commit().add("Q", Q_txt).create();
final Repository db = src.getRepository(); final Repository db = src.getRepository();
final String dstName = Constants.R_HEADS + "new.branch"; final String dstName = Constants.R_HEADS + "new.branch";
Transport t;
// push anonymous shouldn't be allowed. // push anonymous shouldn't be allowed.
// //
t = Transport.open(db, remoteURI); try (Transport t = Transport.open(db, remoteURI)) {
try {
final String srcExpr = Q.name(); final String srcExpr = Q.name();
final boolean forceUpdate = false; final boolean forceUpdate = false;
final String localName = null; final String localName = null;
@ -538,8 +512,6 @@ public class SmartClientSmartServerTest extends HttpTestCase {
+ JGitText.get().authenticationNotSupported; + JGitText.get().authenticationNotSupported;
assertEquals(exp, e.getMessage()); assertEquals(exp, e.getMessage());
} }
} finally {
t.close();
} }
List<AccessEvent> requests = getRequests(); List<AccessEvent> requests = getRequests();
@ -560,12 +532,10 @@ public class SmartClientSmartServerTest extends HttpTestCase {
final RevCommit Q = src.commit().add("Q", Q_txt).create(); final RevCommit Q = src.commit().add("Q", Q_txt).create();
final Repository db = src.getRepository(); final Repository db = src.getRepository();
final String dstName = Constants.R_HEADS + "new.branch"; final String dstName = Constants.R_HEADS + "new.branch";
Transport t;
enableReceivePack(); enableReceivePack();
t = Transport.open(db, remoteURI); try (Transport t = Transport.open(db, remoteURI)) {
try {
final String srcExpr = Q.name(); final String srcExpr = Q.name();
final boolean forceUpdate = false; final boolean forceUpdate = false;
final String localName = null; final String localName = null;
@ -574,8 +544,6 @@ public class SmartClientSmartServerTest extends HttpTestCase {
RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(), RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
srcExpr, dstName, forceUpdate, localName, oldId); srcExpr, dstName, forceUpdate, localName, oldId);
t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u)); t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
} finally {
t.close();
} }
assertTrue(remoteRepository.hasObject(Q_txt)); assertTrue(remoteRepository.hasObject(Q_txt));
@ -633,7 +601,6 @@ public class SmartClientSmartServerTest extends HttpTestCase {
final RevCommit Q = src.commit().add("Q", Q_bin).create(); final RevCommit Q = src.commit().add("Q", Q_bin).create();
final Repository db = src.getRepository(); final Repository db = src.getRepository();
final String dstName = Constants.R_HEADS + "new.branch"; final String dstName = Constants.R_HEADS + "new.branch";
Transport t;
enableReceivePack(); enableReceivePack();
@ -642,8 +609,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
cfg.setInt("http", null, "postbuffer", 8 * 1024); cfg.setInt("http", null, "postbuffer", 8 * 1024);
cfg.save(); cfg.save();
t = Transport.open(db, remoteURI); try (Transport t = Transport.open(db, remoteURI)) {
try {
final String srcExpr = Q.name(); final String srcExpr = Q.name();
final boolean forceUpdate = false; final boolean forceUpdate = false;
final String localName = null; final String localName = null;
@ -652,8 +618,6 @@ public class SmartClientSmartServerTest extends HttpTestCase {
RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(), RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
srcExpr, dstName, forceUpdate, localName, oldId); srcExpr, dstName, forceUpdate, localName, oldId);
t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u)); t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
} finally {
t.close();
} }
assertTrue(remoteRepository.hasObject(Q_bin)); assertTrue(remoteRepository.hasObject(Q_bin));

18
org.eclipse.jgit.junit.http/BUCK

@ -0,0 +1,18 @@
java_library(
name = 'junit-http',
srcs = glob(['src/**']),
resources = glob(['resources/**']),
provided_deps = [
'//org.eclipse.jgit:jgit',
'//org.eclipse.jgit.http.server:jgit-servlet',
'//org.eclipse.jgit.junit:junit',
'//lib:junit',
'//lib:servlet-api',
'//lib/jetty:http',
'//lib/jetty:server',
'//lib/jetty:servlet',
'//lib/jetty:security',
'//lib/jetty:util',
],
visibility = ['PUBLIC'],
)

10
org.eclipse.jgit.junit/BUCK

@ -0,0 +1,10 @@
java_library(
name = 'junit',
srcs = glob(['src/**']),
resources = glob(['resources/**']),
provided_deps = [
'//org.eclipse.jgit:jgit',
'//lib:junit',
],
visibility = ['PUBLIC'],
)

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

@ -822,7 +822,7 @@ public class TestRepository<R extends Repository> {
break; break;
final byte[] bin = db.open(o, o.getType()).getCachedBytes(); final byte[] bin = db.open(o, o.getType()).getCachedBytes();
oc.checkCommit(bin); oc.checkCommit(o, bin);
assertHash(o, bin); assertHash(o, bin);
} }
@ -832,7 +832,7 @@ public class TestRepository<R extends Repository> {
break; break;
final byte[] bin = db.open(o, o.getType()).getCachedBytes(); final byte[] bin = db.open(o, o.getType()).getCachedBytes();
oc.check(o.getType(), bin); oc.check(o, o.getType(), bin);
assertHash(o, bin); assertHash(o, bin);
} }
} }
@ -866,7 +866,7 @@ public class TestRepository<R extends Repository> {
Set<ObjectId> all = new HashSet<ObjectId>(); Set<ObjectId> all = new HashSet<ObjectId>();
for (Ref r : db.getAllRefs().values()) for (Ref r : db.getAllRefs().values())
all.add(r.getObjectId()); all.add(r.getObjectId());
pw.preparePack(m, all, Collections.<ObjectId> emptySet()); pw.preparePack(m, all, PackWriter.NONE);
final ObjectId name = pw.computeName(); final ObjectId name = pw.computeName();
@ -1155,8 +1155,7 @@ public class TestRepository<R extends Repository> {
return self; return self;
} }
private void insertChangeId(org.eclipse.jgit.lib.CommitBuilder c) private void insertChangeId(org.eclipse.jgit.lib.CommitBuilder c) {
throws IOException {
if (changeId == null) if (changeId == null)
return; return;
int idx = ChangeIdUtil.indexOfChangeId(message, "\n"); int idx = ChangeIdUtil.indexOfChangeId(message, "\n");

38
org.eclipse.jgit.pgm.test/BUCK

@ -0,0 +1,38 @@
TESTS = glob(['tst/**/*.java'])
for t in TESTS:
n = t[len('tst/'):len(t)-len('.java')].replace('/', '.')
java_test(
name = n,
labels = ['pgm'],
srcs = [t],
deps = [
':helpers',
'//org.eclipse.jgit:jgit',
'//org.eclipse.jgit.archive:jgit-archive',
'//org.eclipse.jgit.junit:junit',
'//org.eclipse.jgit.pgm:pgm',
'//lib:hamcrest-core',
'//lib:hamcrest-library',
'//lib:javaewah',
'//lib:junit',
'//lib:slf4j-api',
'//lib:slf4j-simple',
'//lib:commons-compress',
'//lib:tukaani-xz',
],
source_under_test = ['//org.eclipse.jgit.pgm:pgm'],
vm_args = ['-Xmx256m', '-Dfile.encoding=UTF-8'],
)
java_library(
name = 'helpers',
srcs = glob(['src/**/*.java']),
deps = [
'//org.eclipse.jgit:jgit',
'//org.eclipse.jgit.pgm:pgm',
'//org.eclipse.jgit.junit:junit',
'//lib:args4j',
'//lib:junit',
],
)

1
org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF

@ -11,6 +11,7 @@ Import-Package: org.eclipse.jgit.api;version="[4.2.0,4.3.0)",
org.eclipse.jgit.api.errors;version="[4.2.0,4.3.0)", org.eclipse.jgit.api.errors;version="[4.2.0,4.3.0)",
org.eclipse.jgit.diff;version="[4.2.0,4.3.0)", org.eclipse.jgit.diff;version="[4.2.0,4.3.0)",
org.eclipse.jgit.dircache;version="[4.2.0,4.3.0)", org.eclipse.jgit.dircache;version="[4.2.0,4.3.0)",
org.eclipse.jgit.internal.storage.file;version="4.2.0",
org.eclipse.jgit.junit;version="[4.2.0,4.3.0)", org.eclipse.jgit.junit;version="[4.2.0,4.3.0)",
org.eclipse.jgit.lib;version="[4.2.0,4.3.0)", org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
org.eclipse.jgit.merge;version="[4.2.0,4.3.0)", org.eclipse.jgit.merge;version="[4.2.0,4.3.0)",

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

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/org.eclipse.jgit.pgm.test/tst"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="2"/>
</listAttribute>
<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
<mapAttribute key="org.eclipse.debug.core.environmentVariables">
<mapEntry key="LANG" value="de_DE.UTF-8"/>
</mapAttribute>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.pgm.test/tst"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<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;"/>
</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.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.pgm.test"/>
</launchConfiguration>

79
org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java

@ -46,12 +46,16 @@ import static org.junit.Assert.assertEquals;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.pgm.CLIGitCommand; import org.eclipse.jgit.pgm.CLIGitCommand;
import org.eclipse.jgit.pgm.CLIGitCommand.Result;
import org.eclipse.jgit.pgm.TextBuiltin.TerminatedByHelpException;
import org.junit.Before; import org.junit.Before;
public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase { public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase {
@ -69,13 +73,59 @@ public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase {
trash = db.getWorkTree(); trash = db.getWorkTree();
} }
/**
* Executes specified git commands (with arguments)
*
* @param cmds
* each string argument must be a valid git command line, e.g.
* "git branch -h"
* @return command output
* @throws Exception
*/
protected String[] executeUnchecked(String... cmds) throws Exception {
List<String> result = new ArrayList<String>(cmds.length);
for (String cmd : cmds) {
result.addAll(CLIGitCommand.executeUnchecked(cmd, db));
}
return result.toArray(new String[0]);
}
/**
* Executes specified git commands (with arguments), throws exception and
* stops execution on first command which output contains a 'fatal:' error
*
* @param cmds
* each string argument must be a valid git command line, e.g.
* "git branch -h"
* @return command output
* @throws Exception
*/
protected String[] execute(String... cmds) throws Exception { protected String[] execute(String... cmds) throws Exception {
List<String> result = new ArrayList<String>(cmds.length); List<String> result = new ArrayList<String>(cmds.length);
for (String cmd : cmds) for (String cmd : cmds) {
result.addAll(CLIGitCommand.execute(cmd, db)); Result r = CLIGitCommand.executeRaw(cmd, db);
if (r.ex instanceof TerminatedByHelpException) {
result.addAll(r.errLines());
} else if (r.ex != null) {
throw r.ex;
}
result.addAll(r.outLines());
}
return result.toArray(new String[0]); return result.toArray(new String[0]);
} }
/**
* @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
*/
protected Path writeLink(String link, String target) throws Exception {
return JGitTestUtil.writeLink(db, link, target);
}
protected File writeTrashFile(final String name, final String data) protected File writeTrashFile(final String name, final String data)
throws IOException { throws IOException {
return JGitTestUtil.writeTrashFile(db, name, data); return JGitTestUtil.writeTrashFile(db, name, data);
@ -173,15 +223,36 @@ public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase {
} }
protected void assertArrayOfLinesEquals(String[] expected, String[] actual) { protected void assertArrayOfLinesEquals(String[] expected, String[] actual) {
assertEquals(toText(expected), toText(actual)); assertEquals(toString(expected), toString(actual));
}
public static String toString(String... lines) {
return toString(Arrays.asList(lines));
} }
private static String toText(String[] lines) { public static String toString(List<String> lines) {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
for (String s : lines) { for (String s : lines) {
// trim indentation, to simplify tests
s = s.trim();
if (s != null && !s.isEmpty()) {
b.append(s); b.append(s);
b.append('\n'); b.append('\n');
} }
}
// delete last line break to allow simpler tests with one line compare
if (b.length() > 0 && b.charAt(b.length() - 1) == '\n') {
b.deleteCharAt(b.length() - 1);
}
return b.toString(); return b.toString();
} }
public static boolean contains(List<String> lines, String str) {
for (String s : lines) {
if (s.contains(str)) {
return true;
}
}
return false;
}
} }

175
org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java

@ -42,71 +42,140 @@
*/ */
package org.eclipse.jgit.pgm; package org.eclipse.jgit.pgm;
import static org.junit.Assert.assertNull;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.text.MessageFormat; import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.TextBuiltin.TerminatedByHelpException;
import org.eclipse.jgit.pgm.opt.CmdLineParser;
import org.eclipse.jgit.pgm.opt.SubcommandHandler;
import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.IO;
import org.kohsuke.args4j.Argument;
public class CLIGitCommand { public class CLIGitCommand extends Main {
@Argument(index = 0, metaVar = "metaVar_command", required = true, handler = SubcommandHandler.class)
private TextBuiltin subcommand;
@Argument(index = 1, metaVar = "metaVar_arg") private final Result result;
private List<String> arguments = new ArrayList<String>();
public TextBuiltin getSubcommand() { private final Repository db;
return subcommand;
public CLIGitCommand(Repository db) {
super();
this.db = db;
result = new Result();
} }
public List<String> getArguments() { /**
return arguments; * Executes git commands (with arguments) specified on the command line. The
* git repository (same for all commands) can be specified via system
* property "-Dgit_work_tree=path_to_work_tree". If the property is not set,
* current directory is used.
*
* @param args
* each element in the array must be a valid git command line,
* e.g. "git branch -h"
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String workDir = System.getProperty("git_work_tree");
if (workDir == null) {
workDir = ".";
System.out.println(
"System property 'git_work_tree' not specified, using current directory: "
+ new File(workDir).getAbsolutePath());
}
try (Repository db = new FileRepository(workDir + "/.git")) {
for (String cmd : args) {
List<String> result = execute(cmd, db);
for (String line : result) {
System.out.println(line);
}
}
}
} }
public static List<String> execute(String str, Repository db) public static List<String> execute(String str, Repository db)
throws Exception { throws Exception {
Result result = executeRaw(str, db);
return getOutput(result);
}
public static Result executeRaw(String str, Repository db)
throws Exception {
CLIGitCommand cmd = new CLIGitCommand(db);
cmd.run(str);
return cmd.result;
}
public static List<String> executeUnchecked(String str, Repository db)
throws Exception {
CLIGitCommand cmd = new CLIGitCommand(db);
try {
cmd.run(str);
return getOutput(cmd.result);
} catch (Throwable e) {
return cmd.result.errLines();
}
}
private static List<String> getOutput(Result result) {
if (result.ex instanceof TerminatedByHelpException) {
return result.errLines();
}
return result.outLines();
}
private void run(String commandLine) throws Exception {
String[] argv = convertToMainArgs(commandLine);
try { try {
return IO.readLines(new String(rawExecute(str, db))); super.run(argv);
} catch (Die e) { } catch (TerminatedByHelpException e) {
return IO.readLines(MessageFormat.format(CLIText.get().fatalError, // this is not a failure, super called exit() on help
e.getMessage())); } finally {
writer.flush();
} }
} }
public static byte[] rawExecute(String str, Repository db) private static String[] convertToMainArgs(String str)
throws Exception { throws Exception {
String[] args = split(str); String[] args = split(str);
if (!args[0].equalsIgnoreCase("git") || args.length < 2) if (!args[0].equalsIgnoreCase("git") || args.length < 2) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Expected 'git <command> [<args>]', was:" + str); "Expected 'git <command> [<args>]', was:" + str);
}
String[] argv = new String[args.length - 1]; String[] argv = new String[args.length - 1];
System.arraycopy(args, 1, argv, 0, args.length - 1); System.arraycopy(args, 1, argv, 0, args.length - 1);
return argv;
}
CLIGitCommand bean = new CLIGitCommand(); @Override
final CmdLineParser clp = new CmdLineParser(bean); PrintWriter createErrorWriter() {
clp.parseArgument(argv); return new PrintWriter(result.err);
}
final TextBuiltin cmd = bean.getSubcommand(); void init(final TextBuiltin cmd) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); cmd.outs = result.out;
cmd.outs = baos; cmd.errs = result.err;
if (cmd.requiresRepository()) super.init(cmd);
cmd.init(db, null);
else
cmd.init(null, null);
try {
cmd.execute(bean.getArguments().toArray(
new String[bean.getArguments().size()]));
} finally {
if (cmd.outw != null)
cmd.outw.flush();
} }
return baos.toByteArray();
@Override
protected Repository openGitDir(String aGitdir) throws IOException {
assertNull(aGitdir);
return db;
}
@Override
void exit(int status, Exception t) throws Exception {
if (t == null) {
t = new IllegalStateException(Integer.toString(status));
}
result.ex = t;
throw t;
} }
/** /**
@ -164,4 +233,36 @@ public class CLIGitCommand {
return list.toArray(new String[list.size()]); return list.toArray(new String[list.size()]);
} }
public static class Result {
public final ByteArrayOutputStream out = new ByteArrayOutputStream();
public final ByteArrayOutputStream err = new ByteArrayOutputStream();
public Exception ex;
public byte[] outBytes() {
return out.toByteArray();
}
public byte[] errBytes() {
return err.toByteArray();
}
public String outString() {
return out.toString();
}
public List<String> outLines() {
return IO.readLines(out.toString());
}
public String errString() {
return err.toString();
}
public List<String> errLines() {
return IO.readLines(err.toString());
}
}
} }

15
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/AddTest.java

@ -45,15 +45,12 @@ package org.eclipse.jgit.pgm;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
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.fail;
import java.lang.Exception;
import java.lang.String;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
public class AddTest extends CLIRepositoryTestCase { public class AddTest extends CLIRepositoryTestCase {
@ -66,14 +63,16 @@ public class AddTest extends CLIRepositoryTestCase {
git = new Git(db); git = new Git(db);
} }
@Ignore("args4j exit()s on error instead of throwing, JVM goes down")
@Test @Test
public void testAddNothing() throws Exception { public void testAddNothing() throws Exception {
assertEquals("fatal: Argument \"filepattern\" is required", // try {
execute("git add")[0]); execute("git add");
fail("Must die");
} catch (Die e) {
// expected, requires argument
}
} }
@Ignore("args4j exit()s for --help, too")
@Test @Test
public void testAddUsage() throws Exception { public void testAddUsage() throws Exception {
execute("git add --help"); execute("git add --help");

95
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java

@ -52,17 +52,15 @@ import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.Object;
import java.lang.String;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
@ -71,9 +69,7 @@ import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.pgm.CLIGitCommand;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
public class ArchiveTest extends CLIRepositoryTestCase { public class ArchiveTest extends CLIRepositoryTestCase {
@ -89,25 +85,26 @@ public class ArchiveTest extends CLIRepositoryTestCase {
emptyTree = db.resolve("HEAD^{tree}").abbreviate(12).name(); emptyTree = db.resolve("HEAD^{tree}").abbreviate(12).name();
} }
@Ignore("Some versions of java.util.zip refuse to write an empty ZIP")
@Test @Test
public void testEmptyArchive() throws Exception { public void testEmptyArchive() throws Exception {
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --format=zip " + emptyTree, db); "git archive --format=zip " + emptyTree, db).outBytes();
assertArrayEquals(new String[0], listZipEntries(result)); assertArrayEquals(new String[0], listZipEntries(result));
} }
@Test @Test
public void testEmptyTar() throws Exception { public void testEmptyTar() throws Exception {
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --format=tar " + emptyTree, db); "git archive --format=tar " + emptyTree, db).outBytes();
assertArrayEquals(new String[0], listTarEntries(result)); assertArrayEquals(new String[0], listTarEntries(result));
} }
@Test @Test
public void testUnrecognizedFormat() throws Exception { public void testUnrecognizedFormat() throws Exception {
String[] expect = new String[] { "fatal: Unknown archive format 'nonsense'" }; String[] expect = new String[] {
String[] actual = execute("git archive --format=nonsense " + emptyTree); "fatal: Unknown archive format 'nonsense'", "" };
String[] actual = executeUnchecked(
"git archive --format=nonsense " + emptyTree);
assertArrayEquals(expect, actual); assertArrayEquals(expect, actual);
} }
@ -120,8 +117,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("c").call(); git.add().addFilepattern("c").call();
git.commit().setMessage("populate toplevel").call(); git.commit().setMessage("populate toplevel").call();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --format=zip HEAD", db); "git archive --format=zip HEAD", db).outBytes();
assertArrayEquals(new String[] { "a", "c" }, assertArrayEquals(new String[] { "a", "c" },
listZipEntries(result)); listZipEntries(result));
} }
@ -135,8 +132,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testDefaultFormatIsTar() throws Exception { public void testDefaultFormatIsTar() throws Exception {
commitGreeting(); commitGreeting();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive HEAD", db); "git archive HEAD", db).outBytes();
assertArrayEquals(new String[] { "greeting" }, assertArrayEquals(new String[] { "greeting" },
listTarEntries(result)); listTarEntries(result));
} }
@ -302,8 +299,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("b").call(); git.add().addFilepattern("b").call();
git.commit().setMessage("add subdir").call(); git.commit().setMessage("add subdir").call();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --format=zip master", db); "git archive --format=zip master", db).outBytes();
String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" }; String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" };
String[] actual = listZipEntries(result); String[] actual = listZipEntries(result);
@ -328,8 +325,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("b").call(); git.add().addFilepattern("b").call();
git.commit().setMessage("add subdir").call(); git.commit().setMessage("add subdir").call();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --format=tar master", db); "git archive --format=tar master", db).outBytes();
String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" }; String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" };
String[] actual = listTarEntries(result); String[] actual = listTarEntries(result);
@ -349,8 +346,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testArchivePrefixOption() throws Exception { public void testArchivePrefixOption() throws Exception {
commitBazAndFooSlashBar(); commitBazAndFooSlashBar();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=x/ --format=zip master", db); "git archive --prefix=x/ --format=zip master", db).outBytes();
String[] expect = { "x/baz", "x/foo/", "x/foo/bar" }; String[] expect = { "x/baz", "x/foo/", "x/foo/bar" };
String[] actual = listZipEntries(result); String[] actual = listZipEntries(result);
@ -362,8 +359,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testTarPrefixOption() throws Exception { public void testTarPrefixOption() throws Exception {
commitBazAndFooSlashBar(); commitBazAndFooSlashBar();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=x/ --format=tar master", db); "git archive --prefix=x/ --format=tar master", db).outBytes();
String[] expect = { "x/baz", "x/foo/", "x/foo/bar" }; String[] expect = { "x/baz", "x/foo/", "x/foo/bar" };
String[] actual = listTarEntries(result); String[] actual = listTarEntries(result);
@ -381,8 +378,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testPrefixDoesNotNormalizeDoubleSlash() throws Exception { public void testPrefixDoesNotNormalizeDoubleSlash() throws Exception {
commitFoo(); commitFoo();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=x// --format=zip master", db); "git archive --prefix=x// --format=zip master", db).outBytes();
String[] expect = { "x//foo" }; String[] expect = { "x//foo" };
assertArrayEquals(expect, listZipEntries(result)); assertArrayEquals(expect, listZipEntries(result));
} }
@ -390,8 +387,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testPrefixDoesNotNormalizeDoubleSlashInTar() throws Exception { public void testPrefixDoesNotNormalizeDoubleSlashInTar() throws Exception {
commitFoo(); commitFoo();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=x// --format=tar master", db); "git archive --prefix=x// --format=tar master", db).outBytes();
String[] expect = { "x//foo" }; String[] expect = { "x//foo" };
assertArrayEquals(expect, listTarEntries(result)); assertArrayEquals(expect, listTarEntries(result));
} }
@ -408,8 +405,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testPrefixWithoutTrailingSlash() throws Exception { public void testPrefixWithoutTrailingSlash() throws Exception {
commitBazAndFooSlashBar(); commitBazAndFooSlashBar();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=my- --format=zip master", db); "git archive --prefix=my- --format=zip master", db).outBytes();
String[] expect = { "my-baz", "my-foo/", "my-foo/bar" }; String[] expect = { "my-baz", "my-foo/", "my-foo/bar" };
String[] actual = listZipEntries(result); String[] actual = listZipEntries(result);
@ -421,8 +418,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test @Test
public void testTarPrefixWithoutTrailingSlash() throws Exception { public void testTarPrefixWithoutTrailingSlash() throws Exception {
commitBazAndFooSlashBar(); commitBazAndFooSlashBar();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=my- --format=tar master", db); "git archive --prefix=my- --format=tar master", db).outBytes();
String[] expect = { "my-baz", "my-foo/", "my-foo/bar" }; String[] expect = { "my-baz", "my-foo/", "my-foo/bar" };
String[] actual = listTarEntries(result); String[] actual = listTarEntries(result);
@ -441,8 +438,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.submoduleAdd().setURI("./.").setPath("b").call().close(); git.submoduleAdd().setURI("./.").setPath("b").call().close();
git.commit().setMessage("add submodule").call(); git.commit().setMessage("add submodule").call();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --format=zip master", db); "git archive --format=zip master", db).outBytes();
String[] expect = { ".gitmodules", "a", "b/", "c" }; String[] expect = { ".gitmodules", "a", "b/", "c" };
String[] actual = listZipEntries(result); String[] actual = listZipEntries(result);
@ -461,8 +458,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.submoduleAdd().setURI("./.").setPath("b").call().close(); git.submoduleAdd().setURI("./.").setPath("b").call().close();
git.commit().setMessage("add submodule").call(); git.commit().setMessage("add submodule").call();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --format=tar master", db); "git archive --format=tar master", db).outBytes();
String[] expect = { ".gitmodules", "a", "b/", "c" }; String[] expect = { ".gitmodules", "a", "b/", "c" };
String[] actual = listTarEntries(result); String[] actual = listTarEntries(result);
@ -491,8 +488,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.commit().setMessage("three files with different modes").call(); git.commit().setMessage("three files with different modes").call();
byte[] zipData = CLIGitCommand.rawExecute( byte[] zipData = CLIGitCommand.executeRaw(
"git archive --format=zip master", db); "git archive --format=zip master", db).outBytes();
writeRaw("zip-with-modes.zip", zipData); writeRaw("zip-with-modes.zip", zipData);
assertContainsEntryWithMode("zip-with-modes.zip", "-rw-", "plain"); assertContainsEntryWithMode("zip-with-modes.zip", "-rw-", "plain");
assertContainsEntryWithMode("zip-with-modes.zip", "-rwx", "executable"); assertContainsEntryWithMode("zip-with-modes.zip", "-rwx", "executable");
@ -520,8 +517,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.commit().setMessage("three files with different modes").call(); git.commit().setMessage("three files with different modes").call();
byte[] archive = CLIGitCommand.rawExecute( byte[] archive = CLIGitCommand.executeRaw(
"git archive --format=tar master", db); "git archive --format=tar master", db).outBytes();
writeRaw("with-modes.tar", archive); writeRaw("with-modes.tar", archive);
assertTarContainsEntry("with-modes.tar", "-rw-r--r--", "plain"); assertTarContainsEntry("with-modes.tar", "-rw-r--r--", "plain");
assertTarContainsEntry("with-modes.tar", "-rwxr-xr-x", "executable"); assertTarContainsEntry("with-modes.tar", "-rwxr-xr-x", "executable");
@ -543,8 +540,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("1234567890").call(); git.add().addFilepattern("1234567890").call();
git.commit().setMessage("file with long name").call(); git.commit().setMessage("file with long name").call();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --format=zip HEAD", db); "git archive --format=zip HEAD", db).outBytes();
assertArrayEquals(l.toArray(new String[l.size()]), assertArrayEquals(l.toArray(new String[l.size()]),
listZipEntries(result)); listZipEntries(result));
} }
@ -563,8 +560,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("1234567890").call(); git.add().addFilepattern("1234567890").call();
git.commit().setMessage("file with long name").call(); git.commit().setMessage("file with long name").call();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --format=tar HEAD", db); "git archive --format=tar HEAD", db).outBytes();
assertArrayEquals(l.toArray(new String[l.size()]), assertArrayEquals(l.toArray(new String[l.size()]),
listTarEntries(result)); listTarEntries(result));
} }
@ -576,8 +573,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("xyzzy").call(); git.add().addFilepattern("xyzzy").call();
git.commit().setMessage("add file with content").call(); git.commit().setMessage("add file with content").call();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --format=zip HEAD", db); "git archive --format=zip HEAD", db).outBytes();
assertArrayEquals(new String[] { payload }, assertArrayEquals(new String[] { payload },
zipEntryContent(result, "xyzzy")); zipEntryContent(result, "xyzzy"));
} }
@ -589,8 +586,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("xyzzy").call(); git.add().addFilepattern("xyzzy").call();
git.commit().setMessage("add file with content").call(); git.commit().setMessage("add file with content").call();
byte[] result = CLIGitCommand.rawExecute( byte[] result = CLIGitCommand.executeRaw(
"git archive --format=tar HEAD", db); "git archive --format=tar HEAD", db).outBytes();
assertArrayEquals(new String[] { payload }, assertArrayEquals(new String[] { payload },
tarEntryContent(result, "xyzzy")); tarEntryContent(result, "xyzzy"));
} }

194
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/BranchTest.java

@ -43,11 +43,17 @@
package org.eclipse.jgit.pgm; package org.eclipse.jgit.pgm;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -62,10 +68,20 @@ public class BranchTest extends CLIRepositoryTestCase {
} }
} }
@Test
public void testHelpAfterDelete() throws Exception {
String err = toString(executeUnchecked("git branch -d"));
String help = toString(executeUnchecked("git branch -h"));
String errAndHelp = toString(executeUnchecked("git branch -d -h"));
assertEquals(CLIText.fatalError(CLIText.get().branchNameRequired), err);
assertEquals(toString(err, help), errAndHelp);
}
@Test @Test
public void testList() throws Exception { public void testList() throws Exception {
assertEquals("* master", toString(execute("git branch")));
assertEquals("* master 6fd41be initial commit", assertEquals("* master 6fd41be initial commit",
execute("git branch -v")[0]); toString(execute("git branch -v")));
} }
@Test @Test
@ -73,8 +89,10 @@ public class BranchTest extends CLIRepositoryTestCase {
RefUpdate updateRef = db.updateRef(Constants.HEAD, true); RefUpdate updateRef = db.updateRef(Constants.HEAD, true);
updateRef.setNewObjectId(db.resolve("6fd41be")); updateRef.setNewObjectId(db.resolve("6fd41be"));
updateRef.update(); updateRef.update();
assertEquals("* (no branch) 6fd41be initial commit", assertEquals(
execute("git branch -v")[0]); toString("* (no branch) 6fd41be initial commit",
"master 6fd41be initial commit"),
toString(execute("git branch -v")));
} }
@Test @Test
@ -83,16 +101,176 @@ public class BranchTest extends CLIRepositoryTestCase {
git.branchCreate().setName("initial").call(); git.branchCreate().setName("initial").call();
RevCommit second = git.commit().setMessage("second commit") RevCommit second = git.commit().setMessage("second commit")
.call(); .call();
assertArrayOfLinesEquals(new String[] { " initial", "* master", "" }, assertEquals(toString(" initial", "* master"),
execute("git branch --contains 6fd41be")); toString(execute("git branch --contains 6fd41be")));
assertArrayOfLinesEquals(new String[] { "* master", "" }, assertEquals("* master",
execute("git branch --contains " + second.name())); toString(execute("git branch --contains " + second.name())));
} }
} }
@Test @Test
public void testExistingBranch() throws Exception { public void testExistingBranch() throws Exception {
assertEquals("fatal: A branch named 'master' already exists.", assertEquals("fatal: A branch named 'master' already exists.",
execute("git branch master")[0]); toString(executeUnchecked("git branch master")));
}
@Test
public void testRenameSingleArg() throws Exception {
try {
toString(execute("git branch -m"));
fail("Must die");
} catch (Die e) {
// expected, requires argument
}
String result = toString(execute("git branch -m slave"));
assertEquals("", result);
result = toString(execute("git branch -a"));
assertEquals("* slave", result);
}
@Test
public void testRenameTwoArgs() throws Exception {
String result = toString(execute("git branch -m master slave"));
assertEquals("", result);
result = toString(execute("git branch -a"));
assertEquals("* slave", result);
}
@Test
public void testCreate() throws Exception {
try {
toString(execute("git branch a b"));
fail("Must die");
} catch (Die e) {
// expected, too many arguments
}
String result = toString(execute("git branch second"));
assertEquals("", result);
result = toString(execute("git branch"));
assertEquals(toString("* master", "second"), result);
result = toString(execute("git branch -v"));
assertEquals(toString("* master 6fd41be initial commit",
"second 6fd41be initial commit"), result);
}
@Test
public void testDelete() throws Exception {
try {
toString(execute("git branch -d"));
fail("Must die");
} catch (Die e) {
// expected, requires argument
}
String result = toString(execute("git branch second"));
assertEquals("", result);
result = toString(execute("git branch -d second"));
assertEquals("", result);
result = toString(execute("git branch"));
assertEquals("* master", result);
}
@Test
public void testDeleteMultiple() throws Exception {
String result = toString(execute("git branch second",
"git branch third", "git branch fourth"));
assertEquals("", result);
result = toString(execute("git branch -d second third fourth"));
assertEquals("", result);
result = toString(execute("git branch"));
assertEquals("* master", result);
}
@Test
public void testDeleteForce() throws Exception {
try {
toString(execute("git branch -D"));
fail("Must die");
} catch (Die e) {
// expected, requires argument
}
String result = toString(execute("git branch second"));
assertEquals("", result);
result = toString(execute("git checkout second"));
assertEquals("Switched to branch 'second'", result);
File a = writeTrashFile("a", "a");
assertTrue(a.exists());
execute("git add a", "git commit -m 'added a'");
result = toString(execute("git checkout master"));
assertEquals("Switched to branch 'master'", result);
result = toString(execute("git branch"));
assertEquals(toString("* master", "second"), result);
try {
toString(execute("git branch -d second"));
fail("Must die");
} catch (Die e) {
// expected, the current HEAD is on second and not merged to master
}
result = toString(execute("git branch -D second"));
assertEquals("", result);
result = toString(execute("git branch"));
assertEquals("* master", result);
}
@Test
public void testDeleteForceMultiple() throws Exception {
String result = toString(execute("git branch second",
"git branch third", "git branch fourth"));
assertEquals("", result);
result = toString(execute("git checkout second"));
assertEquals("Switched to branch 'second'", result);
File a = writeTrashFile("a", "a");
assertTrue(a.exists());
execute("git add a", "git commit -m 'added a'");
result = toString(execute("git checkout master"));
assertEquals("Switched to branch 'master'", result);
result = toString(execute("git branch"));
assertEquals(toString("fourth", "* master", "second", "third"), result);
try {
toString(execute("git branch -d second third fourth"));
fail("Must die");
} catch (Die e) {
// expected, the current HEAD is on second and not merged to master
}
result = toString(execute("git branch"));
assertEquals(toString("fourth", "* master", "second", "third"), result);
result = toString(execute("git branch -D second third fourth"));
assertEquals("", result);
result = toString(execute("git branch"));
assertEquals("* master", result);
}
@Test
public void testCreateFromOldCommit() throws Exception {
File a = writeTrashFile("a", "a");
assertTrue(a.exists());
execute("git add a", "git commit -m 'added a'");
File b = writeTrashFile("b", "b");
assertTrue(b.exists());
execute("git add b", "git commit -m 'added b'");
String result = toString(execute("git log -n 1 --reverse"));
String firstCommitId = result.substring("commit ".length(),
result.indexOf('\n'));
result = toString(execute("git branch -f second " + firstCommitId));
assertEquals("", result);
result = toString(execute("git branch"));
assertEquals(toString("* master", "second"), result);
result = toString(execute("git checkout second"));
assertEquals("Switched to branch 'second'", result);
assertFalse(b.exists());
} }
} }

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

@ -44,9 +44,14 @@ package org.eclipse.jgit.pgm;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File; import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
@ -59,7 +64,9 @@ import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry; import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
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 CheckoutTest extends CLIRepositoryTestCase { public class CheckoutTest extends CLIRepositoryTestCase {
@ -109,14 +116,14 @@ public class CheckoutTest extends CLIRepositoryTestCase {
assertStringArrayEquals( assertStringArrayEquals(
"fatal: A branch named 'master' already exists.", "fatal: A branch named 'master' already exists.",
execute("git checkout -b master")); executeUnchecked("git checkout -b master"));
} }
} }
@Test @Test
public void testCheckoutNewBranchOnBranchToBeBorn() throws Exception { public void testCheckoutNewBranchOnBranchToBeBorn() throws Exception {
assertStringArrayEquals("fatal: You are on a branch yet to be born", assertStringArrayEquals("fatal: You are on a branch yet to be born",
execute("git checkout -b side")); executeUnchecked("git checkout -b side"));
} }
@Test @Test
@ -599,4 +606,34 @@ public class CheckoutTest extends CLIRepositoryTestCase {
assertEquals("Hello world b", read(b)); assertEquals("Hello world b", read(b));
} }
} }
@Test
public void testCheckouSingleFile() throws Exception {
try (Git git = new Git(db)) {
File a = writeTrashFile("a", "file a");
git.add().addFilepattern(".").call();
git.commit().setMessage("commit file a").call();
writeTrashFile("a", "b");
assertEquals("b", read(a));
assertEquals("[]", Arrays.toString(execute("git checkout -- a")));
assertEquals("file a", read(a));
}
}
@Test
public void testCheckoutLink() throws Exception {
Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
try (Git git = new Git(db)) {
Path path = writeLink("a", "link_a");
assertTrue(Files.isSymbolicLink(path));
git.add().addFilepattern(".").call();
git.commit().setMessage("commit link a").call();
deleteTrashFile("a");
writeTrashFile("a", "Hello world a");
assertFalse(Files.isSymbolicLink(path));
assertEquals("[]", Arrays.toString(execute("git checkout -- a")));
assertEquals("link_a", FileUtils.readSymLink(path.toFile()));
assertTrue(Files.isSymbolicLink(path));
}
}
} }

100
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CommitTest.java

@ -0,0 +1,100 @@
/*
* 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.pgm;
import static org.junit.Assert.assertEquals;
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.junit.Test;
public class CommitTest extends CLIRepositoryTestCase {
@Test
public void testCommitPath() throws Exception {
writeTrashFile("a", "a");
writeTrashFile("b", "a");
String result = toString(execute("git add a"));
assertEquals("", result);
result = toString(execute("git status -- a"));
assertEquals(toString("On branch master", "Changes to be committed:",
"new file: a"), result);
result = toString(execute("git status -- b"));
assertEquals(toString("On branch master", "Untracked files:", "b"),
result);
result = toString(execute("git commit a -m 'added a'"));
assertEquals(
"[master 8cb3ef7e5171aaee1792df6302a5a0cd30425f7a] added a",
result);
result = toString(execute("git status -- a"));
assertEquals("On branch master", result);
result = toString(execute("git status -- b"));
assertEquals(toString("On branch master", "Untracked files:", "b"),
result);
}
@Test
public void testCommitAll() throws Exception {
writeTrashFile("a", "a");
writeTrashFile("b", "a");
String result = toString(execute("git add a b"));
assertEquals("", result);
result = toString(execute("git status -- a b"));
assertEquals(toString("On branch master", "Changes to be committed:",
"new file: a", "new file: b"), result);
result = toString(execute("git commit -m 'added a b'"));
assertEquals(
"[master 3c93fa8e3a28ee26690498be78016edcb3a38c73] added a b",
result);
result = toString(execute("git status -- a b"));
assertEquals("On branch master", result);
}
}

34
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java

@ -43,9 +43,15 @@
package org.eclipse.jgit.pgm; package org.eclipse.jgit.pgm;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -67,17 +73,15 @@ public class DescribeTest extends CLIRepositoryTestCase {
@Test @Test
public void testNoHead() throws Exception { public void testNoHead() throws Exception {
assertArrayEquals( assertEquals(CLIText.fatalError(CLIText.get().noNamesFound),
new String[] { "fatal: No names found, cannot describe anything." }, toString(executeUnchecked("git describe")));
execute("git describe"));
} }
@Test @Test
public void testHeadNoTag() throws Exception { public void testHeadNoTag() throws Exception {
git.commit().setMessage("initial commit").call(); git.commit().setMessage("initial commit").call();
assertArrayEquals( assertEquals(CLIText.fatalError(CLIText.get().noNamesFound),
new String[] { "fatal: No names found, cannot describe anything." }, toString(executeUnchecked("git describe")));
execute("git describe"));
} }
@Test @Test
@ -103,4 +107,22 @@ public class DescribeTest extends CLIRepositoryTestCase {
assertArrayEquals(new String[] { "v1.0-0-g6fd41be", "" }, assertArrayEquals(new String[] { "v1.0-0-g6fd41be", "" },
execute("git describe --long HEAD")); execute("git describe --long HEAD"));
} }
@Test
public void testHelpArgumentBeforeUnknown() throws Exception {
String[] output = execute("git describe -h -XYZ");
String all = Arrays.toString(output);
assertTrue("Unexpected help output: " + all,
all.contains("jgit describe"));
assertFalse("Unexpected help output: " + all, all.contains("fatal"));
}
@Test
public void testHelpArgumentAfterUnknown() throws Exception {
String[] output = executeUnchecked("git describe -XYZ -h");
String all = Arrays.toString(output);
assertTrue("Unexpected help output: " + all,
all.contains("jgit describe"));
assertTrue("Unexpected help output: " + all, all.contains("fatal"));
}
} }

10
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeTest.java

@ -50,6 +50,7 @@ import java.util.Iterator;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.merge.MergeStrategy; import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -194,8 +195,9 @@ public class MergeTest extends CLIRepositoryTestCase {
@Test @Test
public void testNoFastForwardAndSquash() throws Exception { public void testNoFastForwardAndSquash() throws Exception {
assertEquals("fatal: You cannot combine --squash with --no-ff.", assertEquals(
execute("git merge master --no-ff --squash")[0]); CLIText.fatalError(CLIText.get().cannotCombineSquashWithNoff),
executeUnchecked("git merge master --no-ff --squash")[0]);
} }
@Test @Test
@ -209,8 +211,8 @@ public class MergeTest extends CLIRepositoryTestCase {
git.add().addFilepattern("file").call(); git.add().addFilepattern("file").call();
git.commit().setMessage("commit#2").call(); git.commit().setMessage("commit#2").call();
assertEquals("fatal: Not possible to fast-forward, aborting.", assertEquals(CLIText.fatalError(CLIText.get().ffNotPossibleAborting),
execute("git merge master --ff-only")[0]); executeUnchecked("git merge master --ff-only")[0]);
} }
@Test @Test

28
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RepoTest.java

@ -44,8 +44,11 @@ package org.eclipse.jgit.pgm;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File; import java.io.File;
import java.util.Arrays;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.lib.CLIRepositoryTestCase;
@ -97,6 +100,31 @@ public class RepoTest extends CLIRepositoryTestCase {
resolveRelativeUris(); resolveRelativeUris();
} }
@Test
public void testMissingPath() throws Exception {
try {
execute("git repo");
fail("Must die");
} catch (Die e) {
// expected, requires argument
}
}
/**
* See bug 484951: "git repo -h" should not print unexpected values
*
* @throws Exception
*/
@Test
public void testZombieHelpArgument() throws Exception {
String[] output = execute("git repo -h");
String all = Arrays.toString(output);
assertTrue("Unexpected help output: " + all,
all.contains("jgit repo"));
assertFalse("Unexpected help output: " + all,
all.contains("jgit repo VAL"));
}
@Test @Test
public void testAddRepoManifest() throws Exception { public void testAddRepoManifest() throws Exception {
StringBuilder xmlContent = new StringBuilder(); StringBuilder xmlContent = new StringBuilder();

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

@ -48,6 +48,7 @@ import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
public class ResetTest extends CLIRepositoryTestCase { public class ResetTest extends CLIRepositoryTestCase {
@ -61,6 +62,20 @@ public class ResetTest extends CLIRepositoryTestCase {
git = new Git(db); git = new Git(db);
} }
@Test
public void testPathOptionHelp() throws Exception {
String[] result = execute("git reset -h");
assertTrue("Unexpected argument: " + result[1],
result[1].endsWith("[-- path ... ...]"));
}
@Test
public void testZombieArgument_Bug484951() throws Exception {
String[] result = execute("git reset -h");
assertFalse("Unexpected argument: " + result[0],
result[0].contains("[VAL ...]"));
}
@Test @Test
public void testResetSelf() throws Exception { public void testResetSelf() throws Exception {
RevCommit commit = git.commit().setMessage("initial commit").call(); RevCommit commit = git.commit().setMessage("initial commit").call();
@ -91,15 +106,28 @@ public class ResetTest extends CLIRepositoryTestCase {
@Test @Test
public void testResetPathDoubleDash() throws Exception { public void testResetPathDoubleDash() throws Exception {
resetPath(true); resetPath(true, true);
} }
@Test @Test
public void testResetPathNoDoubleDash() throws Exception { public void testResetPathNoDoubleDash() throws Exception {
resetPath(false); resetPath(false, true);
}
@Test
public void testResetPathDoubleDashNoRef() throws Exception {
resetPath(true, false);
}
@Ignore("Currently we cannote recognize if a name is a commit-ish or a path, "
+ "so 'git reset a' will not work if 'a' is not a branch name but a file path")
@Test
public void testResetPathNoDoubleDashNoRef() throws Exception {
resetPath(false, false);
} }
private void resetPath(boolean useDoubleDash) throws Exception { private void resetPath(boolean useDoubleDash, boolean supplyCommit)
throws Exception {
// create files a and b // create files a and b
writeTrashFile("a", "Hello world a"); writeTrashFile("a", "Hello world a");
writeTrashFile("b", "Hello world b"); writeTrashFile("b", "Hello world b");
@ -115,8 +143,9 @@ public class ResetTest extends CLIRepositoryTestCase {
git.add().addFilepattern(".").call(); git.add().addFilepattern(".").call();
// reset only file a // reset only file a
String cmd = String.format("git reset %s%s a", commit.getId().name(), String cmd = String.format("git reset %s%s a",
(useDoubleDash) ? " --" : ""); supplyCommit ? commit.getId().name() : "",
useDoubleDash ? " --" : "");
assertStringArrayEquals("", execute(cmd)); assertStringArrayEquals("", execute(cmd));
assertEquals(commit.getId(), assertEquals(commit.getId(),
git.getRepository().exactRef("HEAD").getObjectId()); git.getRepository().exactRef("HEAD").getObjectId());

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

@ -44,6 +44,7 @@ package org.eclipse.jgit.pgm;
import static org.eclipse.jgit.lib.Constants.MASTER; import static org.eclipse.jgit.lib.Constants.MASTER;
import static org.eclipse.jgit.lib.Constants.R_HEADS; import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
@ -55,6 +56,13 @@ import org.junit.Test;
public class StatusTest extends CLIRepositoryTestCase { public class StatusTest extends CLIRepositoryTestCase {
@Test
public void testPathOptionHelp() throws Exception {
String[] result = execute("git status -h");
assertTrue("Unexpected argument: " + result[1],
result[1].endsWith("[-- path ... ...]"));
}
@Test @Test
public void testStatusDefault() throws Exception { public void testStatusDefault() throws Exception {
executeTest("git status", false, true); executeTest("git status", false, true);

2
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java

@ -68,6 +68,6 @@ public class TagTest extends CLIRepositoryTestCase {
git.commit().setMessage("commit").call(); git.commit().setMessage("commit").call();
assertEquals("fatal: tag 'test' already exists", assertEquals("fatal: tag 'test' already exists",
execute("git tag test")[0]); executeUnchecked("git tag test")[0]);
} }
} }

70
org.eclipse.jgit.pgm/BUCK

@ -0,0 +1,70 @@
include_defs('//tools/git.defs')
java_library(
name = 'pgm',
srcs = glob(['src/**']),
resources = glob(['resources/**']),
deps = [
':services',
'//org.eclipse.jgit:jgit',
'//org.eclipse.jgit.archive:jgit-archive',
'//org.eclipse.jgit.http.apache:http-apache',
'//org.eclipse.jgit.ui:ui',
'//lib:args4j',
],
visibility = ['PUBLIC'],
)
prebuilt_jar(
name = 'services',
binary_jar = ':services__jar',
)
genrule(
name = 'services__jar',
cmd = 'cd $SRCDIR ; zip -qr $OUT .',
srcs = glob(['META-INF/services/*']),
out = 'services.jar',
)
genrule(
name = 'jgit',
cmd = ''.join([
'mkdir $TMP/META-INF &&',
'cp $(location :binary_manifest) $TMP/META-INF/MANIFEST.MF &&',
'cp $(location :jgit_jar) $TMP/jgit.jar &&',
'cd $TMP && zip $TMP/jgit.jar META-INF/MANIFEST.MF &&',
'cat $SRCDIR/jgit.sh $TMP/jgit.jar >$OUT &&',
'chmod a+x $OUT',
]),
srcs = ['jgit.sh'],
out = 'jgit',
visibility = ['PUBLIC'],
)
java_binary(
name = 'jgit_jar',
deps = [
':pgm',
'//lib:slf4j-simple',
'//lib:tukaani-xz',
],
blacklist = [
'META-INF/DEPENDENCIES',
'META-INF/maven/.*',
],
)
genrule(
name = 'binary_manifest',
cmd = ';'.join(['echo "%s: %s" >>$OUT' % e for e in [
('Manifest-Version', '1.0'),
('Main-Class', 'org.eclipse.jgit.pgm.Main'),
('Bundle-Version', git_version()),
('Implementation-Title', 'JGit Command Line Interface'),
('Implementation-Vendor', 'Eclipse.org - JGit'),
('Implementation-Vendor-URL', 'http://www.eclipse.org/jgit/'),
('Implementation-Vendor-Id', 'org.eclipse.jgit'),
]] + ['echo >>$OUT']),
out = 'MANIFEST.MF',
)

2
org.eclipse.jgit.pgm/META-INF/MANIFEST.MF

@ -21,6 +21,7 @@ Import-Package: org.apache.commons.compress.archivers;version="[1.3,2.0)",
org.eclipse.jgit.gitrepo;version="[4.2.0,4.3.0)", org.eclipse.jgit.gitrepo;version="[4.2.0,4.3.0)",
org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)", org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)",
org.eclipse.jgit.internal.storage.pack;version="[4.2.0,4.3.0)", org.eclipse.jgit.internal.storage.pack;version="[4.2.0,4.3.0)",
org.eclipse.jgit.internal.storage.reftree;version="[4.2.0,4.3.0)",
org.eclipse.jgit.lib;version="[4.2.0,4.3.0)", org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
org.eclipse.jgit.merge;version="4.2.0", org.eclipse.jgit.merge;version="4.2.0",
org.eclipse.jgit.nls;version="[4.2.0,4.3.0)", org.eclipse.jgit.nls;version="[4.2.0,4.3.0)",
@ -31,6 +32,7 @@ Import-Package: org.apache.commons.compress.archivers;version="[1.3,2.0)",
org.eclipse.jgit.storage.file;version="[4.2.0,4.3.0)", org.eclipse.jgit.storage.file;version="[4.2.0,4.3.0)",
org.eclipse.jgit.storage.pack;version="[4.2.0,4.3.0)", org.eclipse.jgit.storage.pack;version="[4.2.0,4.3.0)",
org.eclipse.jgit.transport;version="[4.2.0,4.3.0)", org.eclipse.jgit.transport;version="[4.2.0,4.3.0)",
org.eclipse.jgit.transport.http.apache;version="[4.2.0,4.3.0)",
org.eclipse.jgit.transport.resolver;version="[4.2.0,4.3.0)", org.eclipse.jgit.transport.resolver;version="[4.2.0,4.3.0)",
org.eclipse.jgit.treewalk;version="[4.2.0,4.3.0)", org.eclipse.jgit.treewalk;version="[4.2.0,4.3.0)",
org.eclipse.jgit.treewalk.filter;version="[4.2.0,4.3.0)", org.eclipse.jgit.treewalk.filter;version="[4.2.0,4.3.0)",

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

@ -41,6 +41,7 @@ org.eclipse.jgit.pgm.debug.DiffAlgorithms
org.eclipse.jgit.pgm.debug.MakeCacheTree org.eclipse.jgit.pgm.debug.MakeCacheTree
org.eclipse.jgit.pgm.debug.ReadDirCache org.eclipse.jgit.pgm.debug.ReadDirCache
org.eclipse.jgit.pgm.debug.RebuildCommitGraph org.eclipse.jgit.pgm.debug.RebuildCommitGraph
org.eclipse.jgit.pgm.debug.RebuildRefTree
org.eclipse.jgit.pgm.debug.ShowCacheTree org.eclipse.jgit.pgm.debug.ShowCacheTree
org.eclipse.jgit.pgm.debug.ShowCommands org.eclipse.jgit.pgm.debug.ShowCommands
org.eclipse.jgit.pgm.debug.ShowDirCache org.eclipse.jgit.pgm.debug.ShowDirCache

11
org.eclipse.jgit.pgm/pom.xml

@ -94,6 +94,17 @@
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.http.apache</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>

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

@ -20,6 +20,7 @@ branchAlreadyExists=A branch named ''{0}'' already exists.
branchCreatedFrom=branch: Created from {0} branchCreatedFrom=branch: Created from {0}
branchDetachedHEAD=detached HEAD branchDetachedHEAD=detached HEAD
branchIsNotAnAncestorOfYourCurrentHEAD=The branch ''{0}'' is not an ancestor of your current HEAD.\nIf you are sure you want to delete it, run ''jgit branch -D {0}''. branchIsNotAnAncestorOfYourCurrentHEAD=The branch ''{0}'' is not an ancestor of your current HEAD.\nIf you are sure you want to delete it, run ''jgit branch -D {0}''.
branchNameRequired=branch name required
branchNotFound=branch ''{0}'' not found. branchNotFound=branch ''{0}'' not found.
cacheTreePathInfo="{0}": {1} entries, {2} children cacheTreePathInfo="{0}": {1} entries, {2} children
cannotBeRenamed={0} cannot be renamed cannotBeRenamed={0} cannot be renamed
@ -89,7 +90,9 @@ metaVar_author=AUTHOR
metaVar_base=base metaVar_base=base
metaVar_blameL=START,END metaVar_blameL=START,END
metaVar_blameReverse=START..END metaVar_blameReverse=START..END
metaVar_branchAndStartPoint=branch [start-name]
metaVar_branchName=branch metaVar_branchName=branch
metaVar_branchNames=branch ...
metaVar_bucket=BUCKET metaVar_bucket=BUCKET
metaVar_command=command metaVar_command=command
metaVar_commandDetail=DETAIL metaVar_commandDetail=DETAIL
@ -109,6 +112,7 @@ metaVar_message=message
metaVar_n=n metaVar_n=n
metaVar_name=name metaVar_name=name
metaVar_object=object metaVar_object=object
metaVar_oldNewBranchNames=[oldbranch] newbranch
metaVar_op=OP metaVar_op=OP
metaVar_pass=PASS metaVar_pass=PASS
metaVar_path=path metaVar_path=path
@ -125,6 +129,7 @@ metaVar_treeish=tree-ish
metaVar_uriish=uri-ish metaVar_uriish=uri-ish
metaVar_url=URL metaVar_url=URL
metaVar_user=USER metaVar_user=USER
metaVar_values=value ...
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
@ -223,6 +228,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_RebuildRefTree=Copy references into a RefTree
usage_Remote=Manage set of tracked repositories 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
@ -337,6 +343,7 @@ usage_recordChangesToRepository=Record changes to the repository
usage_recurseIntoSubtrees=recurse into subtrees usage_recurseIntoSubtrees=recurse into subtrees
usage_renameLimit=limit size of rename matrix usage_renameLimit=limit size of rename matrix
usage_reset=Reset current HEAD to the specified state usage_reset=Reset current HEAD to the specified state
usage_resetReference=Reset to given reference name
usage_resetHard=Resets the index and working tree usage_resetHard=Resets the index and working tree
usage_resetSoft=Resets without touching the index file nor the working tree usage_resetSoft=Resets without touching the index file nor the working tree
usage_resetMixed=Resets the index but not the working tree usage_resetMixed=Resets the index but not the working tree
@ -353,6 +360,7 @@ usage_tags=fetch all tags
usage_notags=do not fetch tags usage_notags=do not fetch tags
usage_tagMessage=tag message usage_tagMessage=tag message
usage_untrackedFilesMode=show untracked files usage_untrackedFilesMode=show untracked files
usage_updateRef=reference to update
usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository
usage_useNameInsteadOfOriginToTrackUpstream=use <name> instead of 'origin' to track upstream usage_useNameInsteadOfOriginToTrackUpstream=use <name> instead of 'origin' to track upstream
usage_checkoutBranchAfterClone=checkout named branch instead of remotes's HEAD usage_checkoutBranchAfterClone=checkout named branch instead of remotes's HEAD

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

@ -45,7 +45,6 @@ package org.eclipse.jgit.pgm;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@ -65,15 +64,18 @@ import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefUpdate.Result; import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.pgm.opt.CmdLineParser; import org.eclipse.jgit.pgm.opt.OptionWithValuesListHandler;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.ExampleMode;
import org.kohsuke.args4j.Option; import org.kohsuke.args4j.Option;
@Command(common = true, usage = "usage_listCreateOrDeleteBranches") @Command(common = true, usage = "usage_listCreateOrDeleteBranches")
class Branch extends TextBuiltin { class Branch extends TextBuiltin {
private String otherBranch;
private boolean createForce;
private boolean rename;
@Option(name = "--remote", aliases = { "-r" }, usage = "usage_actOnRemoteTrackingBranches") @Option(name = "--remote", aliases = { "-r" }, usage = "usage_actOnRemoteTrackingBranches")
private boolean remote = false; private boolean remote = false;
@ -83,23 +85,69 @@ class Branch extends TextBuiltin {
@Option(name = "--contains", metaVar = "metaVar_commitish", usage = "usage_printOnlyBranchesThatContainTheCommit") @Option(name = "--contains", metaVar = "metaVar_commitish", usage = "usage_printOnlyBranchesThatContainTheCommit")
private String containsCommitish; private String containsCommitish;
@Option(name = "--delete", aliases = { "-d" }, usage = "usage_deleteFullyMergedBranch") private List<String> delete;
private boolean delete = false;
@Option(name = "--delete", aliases = {
"-d" }, metaVar = "metaVar_branchNames", usage = "usage_deleteFullyMergedBranch", handler = OptionWithValuesListHandler.class)
public void delete(List<String> names) {
if (names.isEmpty()) {
throw die(CLIText.get().branchNameRequired);
}
delete = names;
}
@Option(name = "--delete-force", aliases = { "-D" }, usage = "usage_deleteBranchEvenIfNotMerged") private List<String> deleteForce;
private boolean deleteForce = false;
@Option(name = "--create-force", aliases = { "-f" }, usage = "usage_forceCreateBranchEvenExists") @Option(name = "--delete-force", aliases = {
private boolean createForce = false; "-D" }, metaVar = "metaVar_branchNames", usage = "usage_deleteBranchEvenIfNotMerged", handler = OptionWithValuesListHandler.class)
public void deleteForce(List<String> names) {
if (names.isEmpty()) {
throw die(CLIText.get().branchNameRequired);
}
deleteForce = names;
}
@Option(name = "-m", usage = "usage_moveRenameABranch") @Option(name = "--create-force", aliases = {
private boolean rename = false; "-f" }, metaVar = "metaVar_branchAndStartPoint", usage = "usage_forceCreateBranchEvenExists", handler = OptionWithValuesListHandler.class)
public void createForce(List<String> branchAndStartPoint) {
createForce = true;
if (branchAndStartPoint.isEmpty()) {
throw die(CLIText.get().branchNameRequired);
}
if (branchAndStartPoint.size() > 2) {
throw die(CLIText.get().tooManyRefsGiven);
}
if (branchAndStartPoint.size() == 1) {
branch = branchAndStartPoint.get(0);
} else {
branch = branchAndStartPoint.get(0);
otherBranch = branchAndStartPoint.get(1);
}
}
@Option(name = "--move", aliases = {
"-m" }, metaVar = "metaVar_oldNewBranchNames", usage = "usage_moveRenameABranch", handler = OptionWithValuesListHandler.class)
public void moveRename(List<String> currentAndNew) {
rename = true;
if (currentAndNew.isEmpty()) {
throw die(CLIText.get().branchNameRequired);
}
if (currentAndNew.size() > 2) {
throw die(CLIText.get().tooManyRefsGiven);
}
if (currentAndNew.size() == 1) {
branch = currentAndNew.get(0);
} else {
branch = currentAndNew.get(0);
otherBranch = currentAndNew.get(1);
}
}
@Option(name = "--verbose", aliases = { "-v" }, usage = "usage_beVerbose") @Option(name = "--verbose", aliases = { "-v" }, usage = "usage_beVerbose")
private boolean verbose = false; private boolean verbose = false;
@Argument @Argument(metaVar = "metaVar_name")
private List<String> branches = new ArrayList<String>(); private String branch;
private final Map<String, Ref> printRefs = new LinkedHashMap<String, Ref>(); private final Map<String, Ref> printRefs = new LinkedHashMap<String, Ref>();
@ -110,30 +158,33 @@ class Branch extends TextBuiltin {
@Override @Override
protected void run() throws Exception { protected void run() throws Exception {
if (delete || deleteForce) if (delete != null || deleteForce != null) {
delete(deleteForce); if (delete != null) {
else { delete(delete, false);
if (branches.size() > 2) }
throw die(CLIText.get().tooManyRefsGiven + new CmdLineParser(this).printExample(ExampleMode.ALL)); if (deleteForce != null) {
delete(deleteForce, true);
}
} else {
if (rename) { if (rename) {
String src, dst; String src, dst;
if (branches.size() == 1) { if (otherBranch == null) {
final Ref head = db.getRef(Constants.HEAD); final Ref head = db.getRef(Constants.HEAD);
if (head != null && head.isSymbolic()) if (head != null && head.isSymbolic()) {
src = head.getLeaf().getName(); src = head.getLeaf().getName();
else } else {
throw die(CLIText.get().cannotRenameDetachedHEAD); throw die(CLIText.get().cannotRenameDetachedHEAD);
dst = branches.get(0); }
dst = branch;
} else { } else {
src = branches.get(0); src = branch;
final Ref old = db.getRef(src); final Ref old = db.getRef(src);
if (old == null) if (old == null)
throw die(MessageFormat.format(CLIText.get().doesNotExist, src)); throw die(MessageFormat.format(CLIText.get().doesNotExist, src));
if (!old.getName().startsWith(Constants.R_HEADS)) if (!old.getName().startsWith(Constants.R_HEADS))
throw die(MessageFormat.format(CLIText.get().notABranch, src)); throw die(MessageFormat.format(CLIText.get().notABranch, src));
src = old.getName(); src = old.getName();
dst = branches.get(1); dst = otherBranch;
} }
if (!dst.startsWith(Constants.R_HEADS)) if (!dst.startsWith(Constants.R_HEADS))
@ -145,13 +196,14 @@ class Branch extends TextBuiltin {
if (r.rename() != Result.RENAMED) if (r.rename() != Result.RENAMED)
throw die(MessageFormat.format(CLIText.get().cannotBeRenamed, src)); throw die(MessageFormat.format(CLIText.get().cannotBeRenamed, src));
} else if (branches.size() > 0) { } else if (createForce || branch != null) {
String newHead = branches.get(0); String newHead = branch;
String startBranch; String startBranch;
if (branches.size() == 2) if (createForce) {
startBranch = branches.get(1); startBranch = otherBranch;
else } else {
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) {
@ -164,22 +216,27 @@ class Branch extends TextBuiltin {
} }
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)) {
newRefName = Constants.R_HEADS + newRefName; newRefName = Constants.R_HEADS + newRefName;
if (!Repository.isValidRefName(newRefName)) }
if (!Repository.isValidRefName(newRefName)) {
throw die(MessageFormat.format(CLIText.get().notAValidRefName, newRefName)); throw die(MessageFormat.format(CLIText.get().notAValidRefName, newRefName));
if (!createForce && db.resolve(newRefName) != null) }
if (!createForce && db.resolve(newRefName) != null) {
throw die(MessageFormat.format(CLIText.get().branchAlreadyExists, newHead)); throw die(MessageFormat.format(CLIText.get().branchAlreadyExists, newHead));
}
RefUpdate updateRef = db.updateRef(newRefName); RefUpdate updateRef = db.updateRef(newRefName);
updateRef.setNewObjectId(startAt); updateRef.setNewObjectId(startAt);
updateRef.setForceUpdate(createForce); updateRef.setForceUpdate(createForce);
updateRef.setRefLogMessage(MessageFormat.format(CLIText.get().branchCreatedFrom, startBranch), false); updateRef.setRefLogMessage(MessageFormat.format(CLIText.get().branchCreatedFrom, startBranch), false);
Result update = updateRef.update(); Result update = updateRef.update();
if (update == Result.REJECTED) if (update == Result.REJECTED) {
throw die(MessageFormat.format(CLIText.get().couldNotCreateBranch, newHead, update.toString())); throw die(MessageFormat.format(CLIText.get().couldNotCreateBranch, newHead, update.toString()));
}
} else { } else {
if (verbose) if (verbose) {
rw = new RevWalk(db); rw = new RevWalk(db);
}
list(); list();
} }
} }
@ -249,7 +306,8 @@ class Branch extends TextBuiltin {
outw.println(); outw.println();
} }
private void delete(boolean force) throws IOException { private void delete(List<String> branches, boolean force)
throws IOException {
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) {

7
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java

@ -60,7 +60,7 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.internal.CLIText;
import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option; import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.spi.StopOptionHandler; import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
@Command(common = true, usage = "usage_checkout") @Command(common = true, usage = "usage_checkout")
class Checkout extends TextBuiltin { class Checkout extends TextBuiltin {
@ -74,11 +74,10 @@ class Checkout extends TextBuiltin {
@Option(name = "--orphan", usage = "usage_orphan") @Option(name = "--orphan", usage = "usage_orphan")
private boolean orphan = false; private boolean orphan = false;
@Argument(required = true, index = 0, metaVar = "metaVar_name", usage = "usage_checkout") @Argument(required = false, index = 0, metaVar = "metaVar_name", usage = "usage_checkout")
private String name; private String name;
@Argument(index = 1) @Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = RestOfArgumentsHandler.class)
@Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = StopOptionHandler.class)
private List<String> paths = new ArrayList<String>(); private List<String> paths = new ArrayList<String>();
@Override @Override

17
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java

@ -50,6 +50,7 @@ import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.InvalidRemoteException; import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.TextProgressMonitor;
import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.SystemReader; import org.eclipse.jgit.util.SystemReader;
@ -70,6 +71,9 @@ class Clone extends AbstractFetchCommand {
@Option(name = "--bare", usage = "usage_bareClone") @Option(name = "--bare", usage = "usage_bareClone")
private boolean isBare; private boolean isBare;
@Option(name = "--quiet", usage = "usage_quiet")
private Boolean quiet;
@Argument(index = 0, required = true, metaVar = "metaVar_uriish") @Argument(index = 0, required = true, metaVar = "metaVar_uriish")
private String sourceUri; private String sourceUri;
@ -109,10 +113,16 @@ class Clone extends AbstractFetchCommand {
command.setGitDir(gitdir == null ? null : new File(gitdir)); command.setGitDir(gitdir == null ? null : new File(gitdir));
command.setDirectory(localNameF); command.setDirectory(localNameF);
outw.println(MessageFormat.format(CLIText.get().cloningInto, localName)); boolean msgs = quiet == null || !quiet.booleanValue();
if (msgs) {
command.setProgressMonitor(new TextProgressMonitor(errw));
outw.println(MessageFormat.format(
CLIText.get().cloningInto, localName));
outw.flush();
}
try { try {
db = command.call().getRepository(); db = command.call().getRepository();
if (db.resolve(Constants.HEAD) == null) if (msgs && db.resolve(Constants.HEAD) == null)
outw.println(CLIText.get().clonedEmptyRepository); outw.println(CLIText.get().clonedEmptyRepository);
} catch (InvalidRemoteException e) { } catch (InvalidRemoteException e) {
throw die(MessageFormat.format(CLIText.get().doesNotExist, throw die(MessageFormat.format(CLIText.get().doesNotExist,
@ -121,8 +131,9 @@ class Clone extends AbstractFetchCommand {
if (db != null) if (db != null)
db.close(); db.close();
} }
if (msgs) {
outw.println(); outw.println();
outw.flush(); outw.flush();
} }
}
} }

15
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java

@ -86,6 +86,21 @@ public class Die extends RuntimeException {
* @since 3.4 * @since 3.4
*/ */
public Die(boolean aborted) { public Die(boolean aborted) {
this(aborted, null);
}
/**
* Construct a new exception reflecting the fact that the command execution
* has been aborted before running.
*
* @param aborted
* boolean indicating the fact the execution has been aborted
* @param cause
* can be null
* @since 4.2
*/
public Die(boolean aborted, final Throwable cause) {
super(cause != null ? cause.getMessage() : null, cause);
this.aborted = aborted; this.aborted = aborted;
} }

129
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java

@ -62,6 +62,8 @@ import org.eclipse.jgit.lib.RepositoryBuilder;
import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.pgm.opt.CmdLineParser; import org.eclipse.jgit.pgm.opt.CmdLineParser;
import org.eclipse.jgit.pgm.opt.SubcommandHandler; import org.eclipse.jgit.pgm.opt.SubcommandHandler;
import org.eclipse.jgit.transport.HttpTransport;
import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory;
import org.eclipse.jgit.util.CachedAuthenticator; import org.eclipse.jgit.util.CachedAuthenticator;
import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineException;
@ -88,13 +90,23 @@ public class Main {
@Argument(index = 1, metaVar = "metaVar_arg") @Argument(index = 1, metaVar = "metaVar_arg")
private List<String> arguments = new ArrayList<String>(); private List<String> arguments = new ArrayList<String>();
PrintWriter writer;
/**
*
*/
public Main() {
HttpTransport.setConnectionFactory(new HttpClientConnectionFactory());
}
/** /**
* Execute the command line. * Execute the command line.
* *
* @param argv * @param argv
* arguments. * arguments.
* @throws Exception
*/ */
public static void main(final String[] argv) { public static void main(final String[] argv) throws Exception {
new Main().run(argv); new Main().run(argv);
} }
@ -113,8 +125,10 @@ public class Main {
* *
* @param argv * @param argv
* arguments. * arguments.
* @throws Exception
*/ */
protected void run(final String[] argv) { protected void run(final String[] argv) throws Exception {
writer = createErrorWriter();
try { try {
if (!installConsole()) { if (!installConsole()) {
AwtAuthenticator.install(); AwtAuthenticator.install();
@ -123,12 +137,14 @@ public class Main {
configureHttpProxy(); configureHttpProxy();
execute(argv); execute(argv);
} catch (Die err) { } catch (Die err) {
if (err.isAborted()) if (err.isAborted()) {
System.exit(1); exit(1, err);
System.err.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage())); }
if (showStackTrace) writer.println(CLIText.fatalError(err.getMessage()));
err.printStackTrace(); if (showStackTrace) {
System.exit(128); err.printStackTrace(writer);
}
exit(128, err);
} catch (Exception err) { } catch (Exception err) {
// Try to detect errno == EPIPE and exit normally if that happens // Try to detect errno == EPIPE and exit normally if that happens
// There may be issues with operating system versions and locale, // There may be issues with operating system versions and locale,
@ -136,46 +152,54 @@ public class Main {
// under other circumstances. // under other circumstances.
if (err.getClass() == IOException.class) { if (err.getClass() == IOException.class) {
// Linux, OS X // Linux, OS X
if (err.getMessage().equals("Broken pipe")) //$NON-NLS-1$ if (err.getMessage().equals("Broken pipe")) { //$NON-NLS-1$
System.exit(0); exit(0, err);
}
// Windows // Windows
if (err.getMessage().equals("The pipe is being closed")) //$NON-NLS-1$ if (err.getMessage().equals("The pipe is being closed")) { //$NON-NLS-1$
System.exit(0); exit(0, err);
}
} }
if (!showStackTrace && err.getCause() != null if (!showStackTrace && err.getCause() != null
&& err instanceof TransportException) && err instanceof TransportException) {
System.err.println(MessageFormat.format(CLIText.get().fatalError, err.getCause().getMessage())); writer.println(CLIText.fatalError(err.getCause().getMessage()));
}
if (err.getClass().getName().startsWith("org.eclipse.jgit.errors.")) { //$NON-NLS-1$ if (err.getClass().getName().startsWith("org.eclipse.jgit.errors.")) { //$NON-NLS-1$
System.err.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage())); writer.println(CLIText.fatalError(err.getMessage()));
if (showStackTrace) if (showStackTrace) {
err.printStackTrace(); err.printStackTrace();
System.exit(128); }
exit(128, err);
} }
err.printStackTrace(); err.printStackTrace();
System.exit(1); exit(1, err);
} }
if (System.out.checkError()) { if (System.out.checkError()) {
System.err.println(CLIText.get().unknownIoErrorStdout); writer.println(CLIText.get().unknownIoErrorStdout);
System.exit(1); exit(1, null);
} }
if (System.err.checkError()) { if (writer.checkError()) {
// No idea how to present an error here, most likely disk full or // No idea how to present an error here, most likely disk full or
// broken pipe // broken pipe
System.exit(1); exit(1, null);
} }
} }
PrintWriter createErrorWriter() {
return new PrintWriter(System.err);
}
private void execute(final String[] argv) throws Exception { private void execute(final String[] argv) throws Exception {
final CmdLineParser clp = new CmdLineParser(this); final CmdLineParser clp = new SubcommandLineParser(this);
PrintWriter writer = new PrintWriter(System.err);
try { try {
clp.parseArgument(argv); clp.parseArgument(argv);
} catch (CmdLineException err) { } catch (CmdLineException err) {
if (argv.length > 0 && !help && !version) { if (argv.length > 0 && !help && !version) {
writer.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage())); writer.println(CLIText.fatalError(err.getMessage()));
writer.flush(); writer.flush();
System.exit(1); exit(1, err);
} }
} }
@ -191,22 +215,24 @@ public class Main {
writer.println(CLIText.get().mostCommonlyUsedCommandsAre); writer.println(CLIText.get().mostCommonlyUsedCommandsAre);
final CommandRef[] common = CommandCatalog.common(); final CommandRef[] common = CommandCatalog.common();
int width = 0; int width = 0;
for (final CommandRef c : common) for (final CommandRef c : common) {
width = Math.max(width, c.getName().length()); width = Math.max(width, c.getName().length());
}
width += 2; width += 2;
for (final CommandRef c : common) { for (final CommandRef c : common) {
writer.print(' '); writer.print(' ');
writer.print(c.getName()); writer.print(c.getName());
for (int i = c.getName().length(); i < width; i++) for (int i = c.getName().length(); i < width; i++) {
writer.print(' '); writer.print(' ');
}
writer.print(CLIText.get().resourceBundle().getString(c.getUsage())); writer.print(CLIText.get().resourceBundle().getString(c.getUsage()));
writer.println(); writer.println();
} }
writer.println(); writer.println();
} }
writer.flush(); writer.flush();
System.exit(1); exit(1, null);
} }
if (version) { if (version) {
@ -215,19 +241,37 @@ public class Main {
} }
final TextBuiltin cmd = subcommand; final TextBuiltin cmd = subcommand;
if (cmd.requiresRepository()) init(cmd);
cmd.init(openGitDir(gitdir), null);
else
cmd.init(null, gitdir);
try { try {
cmd.execute(arguments.toArray(new String[arguments.size()])); cmd.execute(arguments.toArray(new String[arguments.size()]));
} finally { } finally {
if (cmd.outw != null) if (cmd.outw != null) {
cmd.outw.flush(); cmd.outw.flush();
if (cmd.errw != null) }
if (cmd.errw != null) {
cmd.errw.flush(); cmd.errw.flush();
} }
} }
}
void init(final TextBuiltin cmd) throws IOException {
if (cmd.requiresRepository()) {
cmd.init(openGitDir(gitdir), null);
} else {
cmd.init(null, gitdir);
}
}
/**
* @param status
* @param t
* can be {@code null}
* @throws Exception
*/
void exit(int status, Exception t) throws Exception {
writer.flush();
System.exit(status);
}
/** /**
* Evaluate the {@code --git-dir} option and open the repository. * Evaluate the {@code --git-dir} option and open the repository.
@ -332,4 +376,19 @@ public class Main {
} }
} }
} }
/**
* Parser for subcommands which doesn't stop parsing on help options and so
* proceeds all specified options
*/
static class SubcommandLineParser extends CmdLineParser {
public SubcommandLineParser(Object bean) {
super(bean);
}
@Override
protected boolean containsHelp(String... args) {
return false;
}
}
} }

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

@ -148,9 +148,12 @@ class Merge extends TextBuiltin {
break; break;
case FAST_FORWARD: case FAST_FORWARD:
ObjectId oldHeadId = oldHead.getObjectId(); ObjectId oldHeadId = oldHead.getObjectId();
outw.println(MessageFormat.format(CLIText.get().updating, oldHeadId if (oldHeadId != null) {
.abbreviate(7).name(), result.getNewHead().abbreviate(7) String oldId = oldHeadId.abbreviate(7).name();
.name())); String newId = result.getNewHead().abbreviate(7).name();
outw.println(MessageFormat.format(CLIText.get().updating, oldId,
newId));
}
outw.println(result.getMergeStatus().toString()); outw.println(result.getMergeStatus().toString());
break; break;
case CHECKOUT_CONFLICT: case CHECKOUT_CONFLICT:

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

@ -144,7 +144,7 @@ class Remote extends TextBuiltin {
} }
@Override @Override
public void printUsageAndExit(final String message, final CmdLineParser clp) public void printUsage(final String message, final CmdLineParser clp)
throws IOException { throws IOException {
errw.println(message); errw.println(message);
errw.println("jgit remote [--verbose (-v)] [--help (-h)]"); //$NON-NLS-1$ errw.println("jgit remote [--verbose (-v)] [--help (-h)]"); //$NON-NLS-1$
@ -160,7 +160,6 @@ class Remote extends TextBuiltin {
errw.println(); errw.println();
errw.flush(); errw.flush();
throw die(true);
} }
private void print(List<RemoteConfig> remotes) throws IOException { private void print(List<RemoteConfig> remotes) throws IOException {

2
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java

@ -55,7 +55,7 @@ class Repo extends TextBuiltin {
@Option(name = "--groups", aliases = { "-g" }, usage = "usage_groups") @Option(name = "--groups", aliases = { "-g" }, usage = "usage_groups")
private String groups = "default"; //$NON-NLS-1$ private String groups = "default"; //$NON-NLS-1$
@Argument(required = true, usage = "usage_pathToXml") @Argument(required = true, metaVar = "metaVar_path", usage = "usage_pathToXml")
private String path; private String path;
@Option(name = "--record-remote-branch", usage = "usage_branches") @Option(name = "--record-remote-branch", usage = "usage_branches")

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

@ -51,7 +51,7 @@ import org.eclipse.jgit.api.ResetCommand;
import org.eclipse.jgit.api.ResetCommand.ResetType; import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option; import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.spi.StopOptionHandler; import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
@Command(common = true, usage = "usage_reset") @Command(common = true, usage = "usage_reset")
class Reset extends TextBuiltin { class Reset extends TextBuiltin {
@ -65,12 +65,12 @@ class Reset extends TextBuiltin {
@Option(name = "--hard", usage = "usage_resetHard") @Option(name = "--hard", usage = "usage_resetHard")
private boolean hard = false; private boolean hard = false;
@Argument(required = true, index = 0, metaVar = "metaVar_name", usage = "usage_reset") @Argument(required = false, index = 0, metaVar = "metaVar_commitish", usage = "usage_resetReference")
private String commit; private String commit;
@Argument(index = 1) @Argument(required = false, index = 1, metaVar = "metaVar_paths")
@Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = StopOptionHandler.class) @Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = RestOfArgumentsHandler.class)
private List<String> paths = new ArrayList<String>(); private List<String> paths = new ArrayList<>();
@Override @Override
protected void run() throws Exception { protected void run() throws Exception {

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

@ -75,7 +75,13 @@ class RevParse extends TextBuiltin {
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()); ObjectId objectId = r.getObjectId();
// getRefs skips dangling symrefs, so objectId should never be
// null.
if (objectId == null) {
throw new NullPointerException();
}
outw.println(objectId.name());
} }
} else { } else {
if (verify && commits.size() > 1) { if (verify && commits.size() > 1) {

6
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java

@ -59,8 +59,9 @@ import org.eclipse.jgit.lib.IndexDiff.StageState;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.internal.CLIText;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option; import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
import org.eclipse.jgit.pgm.opt.UntrackedFilesHandler; import org.eclipse.jgit.pgm.opt.UntrackedFilesHandler;
/** /**
@ -83,7 +84,8 @@ class Status extends TextBuiltin {
@Option(name = "--untracked-files", aliases = { "-u", "-uno", "-uall" }, usage = "usage_untrackedFilesMode", handler = UntrackedFilesHandler.class) @Option(name = "--untracked-files", aliases = { "-u", "-uno", "-uall" }, usage = "usage_untrackedFilesMode", handler = UntrackedFilesHandler.class)
protected String untrackedFilesMode = "all"; // default value //$NON-NLS-1$ protected String untrackedFilesMode = "all"; // default value //$NON-NLS-1$
@Option(name = "--", metaVar = "metaVar_path", multiValued = true) @Argument(required = false, index = 0, metaVar = "metaVar_paths")
@Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = RestOfArgumentsHandler.class)
protected List<String> filterPaths; protected List<String> filterPaths;
@Override @Override

83
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java

@ -212,17 +212,20 @@ public abstract class TextBuiltin {
*/ */
protected void parseArguments(final String[] args) throws IOException { protected void parseArguments(final String[] args) throws IOException {
final CmdLineParser clp = new CmdLineParser(this); final CmdLineParser clp = new CmdLineParser(this);
help = containsHelp(args);
try { try {
clp.parseArgument(args); clp.parseArgument(args);
} catch (CmdLineException err) { } catch (CmdLineException err) {
if (!help) { this.errw.println(CLIText.fatalError(err.getMessage()));
this.errw.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage())); if (help) {
throw die(true); printUsage("", clp); //$NON-NLS-1$
} }
throw die(true, err);
} }
if (help) { if (help) {
printUsageAndExit(clp); printUsage("", clp); //$NON-NLS-1$
throw new TerminatedByHelpException();
} }
argWalk = clp.getRevWalkGently(); argWalk = clp.getRevWalkGently();
@ -246,6 +249,20 @@ public abstract class TextBuiltin {
* @throws IOException * @throws IOException
*/ */
public void printUsageAndExit(final String message, final CmdLineParser clp) throws IOException { public void printUsageAndExit(final String message, final CmdLineParser clp) throws IOException {
printUsage(message, clp);
throw die(true);
}
/**
* @param message
* non null
* @param clp
* parser used to print options
* @throws IOException
* @since 4.2
*/
protected void printUsage(final String message, final CmdLineParser clp)
throws IOException {
errw.println(message); errw.println(message);
errw.print("jgit "); //$NON-NLS-1$ errw.print("jgit "); //$NON-NLS-1$
errw.print(commandName); errw.print(commandName);
@ -257,12 +274,19 @@ public abstract class TextBuiltin {
errw.println(); errw.println();
errw.flush(); errw.flush();
throw die(true);
} }
/** /**
* @return the resource bundle that will be passed to args4j for purpose * @return error writer, typically this is standard error.
* of string localization * @since 4.2
*/
public ThrowingPrintWriter getErrorWriter() {
return errw;
}
/**
* @return the resource bundle that will be passed to args4j for purpose of
* string localization
*/ */
protected ResourceBundle getResourceBundle() { protected ResourceBundle getResourceBundle() {
return CLIText.get().resourceBundle(); return CLIText.get().resourceBundle();
@ -324,6 +348,19 @@ public abstract class TextBuiltin {
return new Die(aborted); return new Die(aborted);
} }
/**
* @param aborted
* boolean indicating that the execution has been aborted before
* running
* @param cause
* why the command has failed.
* @return a runtime exception the caller is expected to throw
* @since 4.2
*/
protected static Die die(boolean aborted, final Throwable cause) {
return new Die(aborted, cause);
}
String abbreviateRef(String dst, boolean abbreviateRemote) { String abbreviateRef(String dst, boolean abbreviateRemote) {
if (dst.startsWith(R_HEADS)) if (dst.startsWith(R_HEADS))
dst = dst.substring(R_HEADS.length()); dst = dst.substring(R_HEADS.length());
@ -333,4 +370,36 @@ public abstract class TextBuiltin {
dst = dst.substring(R_REMOTES.length()); dst = dst.substring(R_REMOTES.length());
return dst; return dst;
} }
/**
* @param args
* non null
* @return true if the given array contains help option
* @since 4.2
*/
public static boolean containsHelp(String[] args) {
for (String str : args) {
if (str.equals("-h") || str.equals("--help")) { //$NON-NLS-1$ //$NON-NLS-2$
return true;
}
}
return false;
}
/**
* Exception thrown by {@link TextBuiltin} if it proceeds 'help' option
*
* @since 4.2
*/
public static class TerminatedByHelpException extends Die {
private static final long serialVersionUID = 1L;
/**
* Default constructor
*/
public TerminatedByHelpException() {
super(true);
}
}
} }

145
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java

@ -0,0 +1,145 @@
/*
* 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.pgm.debug;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.jgit.internal.storage.reftree.RefTree;
import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.pgm.Command;
import org.eclipse.jgit.pgm.TextBuiltin;
import org.eclipse.jgit.revwalk.RevWalk;
@Command(usage = "usage_RebuildRefTree")
class RebuildRefTree extends TextBuiltin {
private String txnNamespace;
private String txnCommitted;
@Override
protected void run() throws Exception {
try (ObjectReader reader = db.newObjectReader();
RevWalk rw = new RevWalk(reader);
ObjectInserter inserter = db.newObjectInserter()) {
RefDatabase refDb = db.getRefDatabase();
if (refDb instanceof RefTreeDatabase) {
RefTreeDatabase d = (RefTreeDatabase) refDb;
refDb = d.getBootstrap();
txnNamespace = d.getTxnNamespace();
txnCommitted = d.getTxnCommitted();
} else {
RefTreeDatabase d = new RefTreeDatabase(db, refDb);
txnNamespace = d.getTxnNamespace();
txnCommitted = d.getTxnCommitted();
}
errw.format("Rebuilding %s from %s", //$NON-NLS-1$
txnCommitted, refDb.getClass().getSimpleName());
errw.println();
errw.flush();
CommitBuilder b = new CommitBuilder();
Ref ref = refDb.exactRef(txnCommitted);
RefUpdate update = refDb.newUpdate(txnCommitted, true);
ObjectId oldTreeId;
if (ref != null && ref.getObjectId() != null) {
ObjectId oldId = ref.getObjectId();
update.setExpectedOldObjectId(oldId);
b.setParentId(oldId);
oldTreeId = rw.parseCommit(oldId).getTree();
} else {
update.setExpectedOldObjectId(ObjectId.zeroId());
oldTreeId = ObjectId.zeroId();
}
RefTree tree = rebuild(refDb.getRefs(RefDatabase.ALL));
b.setTreeId(tree.writeTree(inserter));
b.setAuthor(new PersonIdent(db));
b.setCommitter(b.getAuthor());
if (b.getTreeId().equals(oldTreeId)) {
return;
}
update.setNewObjectId(inserter.insert(b));
inserter.flush();
RefUpdate.Result result = update.update(rw);
switch (result) {
case NEW:
case FAST_FORWARD:
break;
default:
throw die(String.format("%s: %s", update.getName(), result)); //$NON-NLS-1$
}
}
}
private RefTree rebuild(Map<String, Ref> refMap) {
RefTree tree = RefTree.newEmptyTree();
List<org.eclipse.jgit.internal.storage.reftree.Command> cmds
= new ArrayList<>();
for (Ref r : refMap.values()) {
if (r.getName().equals(txnCommitted)
|| r.getName().startsWith(txnNamespace)) {
continue;
}
cmds.add(new org.eclipse.jgit.internal.storage.reftree.Command(
null,
db.peel(r)));
}
tree.apply(cmds);
return tree;
}
}

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

@ -74,6 +74,19 @@ public class CLIText extends TranslationBundle {
return MessageFormat.format(get().lineFormat, line); return MessageFormat.format(get().lineFormat, line);
} }
/**
* Format the given argument as fatal error using the format defined by
* {@link #fatalError} ("fatal: " by default).
*
* @param message
* the message to format
* @return the formatted line
* @since 4.2
*/
public static String fatalError(String message) {
return MessageFormat.format(get().fatalError, message);
}
// @formatter:off // @formatter:off
/***/ public String alreadyOnBranch; /***/ public String alreadyOnBranch;
/***/ public String alreadyUpToDate; /***/ public String alreadyUpToDate;
@ -85,6 +98,7 @@ public class CLIText extends TranslationBundle {
/***/ public String branchCreatedFrom; /***/ public String branchCreatedFrom;
/***/ public String branchDetachedHEAD; /***/ public String branchDetachedHEAD;
/***/ public String branchIsNotAnAncestorOfYourCurrentHEAD; /***/ public String branchIsNotAnAncestorOfYourCurrentHEAD;
/***/ public String branchNameRequired;
/***/ public String branchNotFound; /***/ public String branchNotFound;
/***/ public String cacheTreePathInfo; /***/ public String cacheTreePathInfo;
/***/ public String configFileNotFound; /***/ public String configFileNotFound;
@ -184,6 +198,7 @@ public class CLIText extends TranslationBundle {
/***/ public String metaVar_uriish; /***/ public String metaVar_uriish;
/***/ public String metaVar_url; /***/ public String metaVar_url;
/***/ public String metaVar_user; /***/ public String metaVar_user;
/***/ public String metaVar_values;
/***/ public String metaVar_version; /***/ public String metaVar_version;
/***/ public String mostCommonlyUsedCommandsAre; /***/ public String mostCommonlyUsedCommandsAre;
/***/ public String needApprovalToDestroyCurrentRepository; /***/ public String needApprovalToDestroyCurrentRepository;

161
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java

@ -43,19 +43,18 @@
package org.eclipse.jgit.pgm.opt; package org.eclipse.jgit.pgm.opt;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.IllegalAnnotationError;
import org.kohsuke.args4j.NamedOptionDef;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.OptionDef;
import org.kohsuke.args4j.spi.OptionHandler;
import org.kohsuke.args4j.spi.Setter;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.Die;
import org.eclipse.jgit.pgm.TextBuiltin; import org.eclipse.jgit.pgm.TextBuiltin;
import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
@ -63,6 +62,15 @@ import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.IllegalAnnotationError;
import org.kohsuke.args4j.NamedOptionDef;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.OptionDef;
import org.kohsuke.args4j.spi.OptionHandler;
import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
import org.kohsuke.args4j.spi.Setter;
/** /**
* Extended command line parser which handles --foo=value arguments. * Extended command line parser which handles --foo=value arguments.
@ -80,12 +88,17 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
registerHandler(RefSpec.class, RefSpecHandler.class); registerHandler(RefSpec.class, RefSpecHandler.class);
registerHandler(RevCommit.class, RevCommitHandler.class); registerHandler(RevCommit.class, RevCommitHandler.class);
registerHandler(RevTree.class, RevTreeHandler.class); registerHandler(RevTree.class, RevTreeHandler.class);
registerHandler(List.class, OptionWithValuesListHandler.class);
} }
private final Repository db; private final Repository db;
private RevWalk walk; private RevWalk walk;
private boolean seenHelp;
private TextBuiltin cmd;
/** /**
* Creates a new command line owner that parses arguments/options and set * Creates a new command line owner that parses arguments/options and set
* them into the given object. * them into the given object.
@ -117,8 +130,12 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
*/ */
public CmdLineParser(final Object bean, Repository repo) { public CmdLineParser(final Object bean, Repository repo) {
super(bean); super(bean);
if (repo == null && bean instanceof TextBuiltin) if (bean instanceof TextBuiltin) {
repo = ((TextBuiltin) bean).getRepository(); cmd = (TextBuiltin) bean;
}
if (repo == null && cmd != null) {
repo = cmd.getRepository();
}
this.db = repo; this.db = repo;
} }
@ -143,9 +160,75 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
} }
tmp.add(str); tmp.add(str);
if (containsHelp(args)) {
// suppress exceptions on required parameters if help is present
seenHelp = true;
// stop argument parsing here
break;
}
}
List<OptionHandler> backup = null;
if (seenHelp) {
backup = unsetRequiredOptions();
} }
try {
super.parseArgument(tmp.toArray(new String[tmp.size()])); super.parseArgument(tmp.toArray(new String[tmp.size()]));
} catch (Die e) {
if (!seenHelp) {
throw e;
}
printToErrorWriter(CLIText.fatalError(e.getMessage()));
} finally {
// reset "required" options to defaults for correct command printout
if (backup != null && !backup.isEmpty()) {
restoreRequiredOptions(backup);
}
seenHelp = false;
}
}
private void printToErrorWriter(String error) {
if (cmd == null) {
System.err.println(error);
} else {
try {
cmd.getErrorWriter().println(error);
} catch (IOException e1) {
System.err.println(error);
}
}
}
private List<OptionHandler> unsetRequiredOptions() {
List<OptionHandler> options = getOptions();
List<OptionHandler> backup = new ArrayList<>(options);
for (Iterator<OptionHandler> iterator = options.iterator(); iterator
.hasNext();) {
OptionHandler handler = iterator.next();
if (handler.option instanceof NamedOptionDef
&& handler.option.required()) {
iterator.remove();
}
}
return backup;
}
private void restoreRequiredOptions(List<OptionHandler> backup) {
List<OptionHandler> options = getOptions();
options.clear();
options.addAll(backup);
}
/**
* @param args
* non null
* @return true if the given array contains help option
* @since 4.2
*/
protected boolean containsHelp(final String... args) {
return TextBuiltin.containsHelp(args);
} }
/** /**
@ -181,7 +264,7 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
return walk; return walk;
} }
static class MyOptionDef extends OptionDef { class MyOptionDef extends OptionDef {
public MyOptionDef(OptionDef o) { public MyOptionDef(OptionDef o) {
super(o.usage(), o.metaVar(), o.required(), o.handler(), o super(o.usage(), o.metaVar(), o.required(), o.handler(), o
@ -201,6 +284,11 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
return metaVar(); return metaVar();
} }
} }
@Override
public boolean required() {
return seenHelp ? false : super.required();
}
} }
@Override @Override
@ -211,4 +299,55 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
return super.createOptionHandler(new MyOptionDef(o), setter); return super.createOptionHandler(new MyOptionDef(o), setter);
} }
@SuppressWarnings("unchecked")
private List<OptionHandler> getOptions() {
List<OptionHandler> options = null;
try {
Field field = org.kohsuke.args4j.CmdLineParser.class
.getDeclaredField("options"); //$NON-NLS-1$
field.setAccessible(true);
options = (List<OptionHandler>) field.get(this);
} catch (NoSuchFieldException | SecurityException
| IllegalArgumentException | IllegalAccessException e) {
// ignore
}
if (options == null) {
return Collections.emptyList();
}
return options;
}
@Override
public void printSingleLineUsage(Writer w, ResourceBundle rb) {
List<OptionHandler> options = getOptions();
if (options.isEmpty()) {
super.printSingleLineUsage(w, rb);
return;
}
List<OptionHandler> backup = new ArrayList<>(options);
boolean changed = sortRestOfArgumentsHandlerToTheEnd(options);
try {
super.printSingleLineUsage(w, rb);
} finally {
if (changed) {
options.clear();
options.addAll(backup);
}
}
}
private boolean sortRestOfArgumentsHandlerToTheEnd(
List<OptionHandler> options) {
for (int i = 0; i < options.size(); i++) {
OptionHandler handler = options.get(i);
if (handler instanceof RestOfArgumentsHandler
|| handler instanceof PathTreeFilterHandler) {
options.remove(i);
options.add(handler);
return true;
}
}
return false;
}
} }

52
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java

@ -0,0 +1,52 @@
package org.eclipse.jgit.pgm.opt;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.OptionDef;
import org.kohsuke.args4j.spi.OptionHandler;
import org.kohsuke.args4j.spi.Parameters;
import org.kohsuke.args4j.spi.Setter;
/**
* Handler which allows to parse option with few values
*
* @since 4.2
*/
public class OptionWithValuesListHandler extends OptionHandler<List<?>> {
/**
* @param parser
* @param option
* @param setter
*/
public OptionWithValuesListHandler(CmdLineParser parser,
OptionDef option, Setter<List<?>> setter) {
super(parser, option, setter);
}
@Override
public int parseArguments(Parameters params) throws CmdLineException {
final List<String> list = new ArrayList<>();
for (int idx = 0; idx < params.size(); idx++) {
final String p;
try {
p = params.getParameter(idx);
} catch (CmdLineException cle) {
break;
}
list.add(p);
}
setter.addValue(list);
return list.size();
}
@Override
public String getDefaultMetaVariable() {
return CLIText.get().metaVar_values;
}
}

95
org.eclipse.jgit.test/BUCK

@ -0,0 +1,95 @@
PKG = 'tst/org/eclipse/jgit/'
HELPERS = glob(['src/**/*.java']) + [PKG + c for c in [
'api/AbstractRemoteCommandTest.java',
'diff/AbstractDiffTestCase.java',
'internal/storage/file/GcTestCase.java',
'internal/storage/file/PackIndexTestCase.java',
'internal/storage/file/XInputStream.java',
'nls/GermanTranslatedBundle.java',
'nls/MissingPropertyBundle.java',
'nls/NoPropertiesBundle.java',
'nls/NonTranslatedBundle.java',
'revwalk/RevQueueTestCase.java',
'revwalk/RevWalkTestCase.java',
'transport/SpiTransport.java',
'treewalk/FileTreeIteratorWithTimeControl.java',
'treewalk/filter/AlwaysCloneTreeFilter.java',
'test/resources/SampleDataRepositoryTestCase.java',
'util/CPUTimeStopWatch.java',
'util/io/Strings.java',
]]
DATA = [
PKG + 'lib/empty.gitindex.dat',
PKG + 'lib/sorttest.gitindex.dat',
]
TESTS = glob(
['tst/**/*.java'],
excludes = HELPERS + DATA,
)
DEPS = {
PKG + 'nls/RootLocaleTest.java': [
'//org.eclipse.jgit.pgm:pgm',
'//org.eclipse.jgit.ui:ui',
],
}
for src in TESTS:
name = src[len('tst/'):len(src)-len('.java')].replace('/', '.')
labels = []
if name.startswith('org.eclipse.jgit.'):
l = name[len('org.eclipse.jgit.'):]
if l.startswith('internal.storage.'):
l = l[len('internal.storage.'):]
i = l.find('.')
if i > 0:
labels.append(l[:i])
else:
labels.append(i)
if 'lib' not in labels:
labels.append('lib')
java_test(
name = name,
labels = labels,
srcs = [src],
deps = [
':helpers',
':tst_rsrc',
'//org.eclipse.jgit:jgit',
'//org.eclipse.jgit.junit:junit',
'//lib:hamcrest-core',
'//lib:hamcrest-library',
'//lib:javaewah',
'//lib:junit',
'//lib:slf4j-api',
'//lib:slf4j-simple',
] + DEPS.get(src, []),
source_under_test = ['//org.eclipse.jgit:jgit'],
vm_args = ['-Xmx256m', '-Dfile.encoding=UTF-8'],
)
java_library(
name = 'helpers',
srcs = HELPERS,
resources = DATA,
deps = [
'//org.eclipse.jgit:jgit',
'//org.eclipse.jgit.junit:junit',
'//lib:junit',
],
)
prebuilt_jar(
name = 'tst_rsrc',
binary_jar = ':tst_rsrc_jar',
)
genrule(
name = 'tst_rsrc_jar',
cmd = 'cd $SRCDIR/tst-rsrc ; zip -qr $OUT .',
srcs = glob(['tst-rsrc/**']),
out = 'tst_rsrc.jar',
)

1
org.eclipse.jgit.test/META-INF/MANIFEST.MF

@ -26,6 +26,7 @@ Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)",
org.eclipse.jgit.internal.storage.dfs;version="[4.2.0,4.3.0)", org.eclipse.jgit.internal.storage.dfs;version="[4.2.0,4.3.0)",
org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)", org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)",
org.eclipse.jgit.internal.storage.pack;version="[4.2.0,4.3.0)", org.eclipse.jgit.internal.storage.pack;version="[4.2.0,4.3.0)",
org.eclipse.jgit.internal.storage.reftree;version="[4.2.0,4.3.0)",
org.eclipse.jgit.junit;version="[4.2.0,4.3.0)", org.eclipse.jgit.junit;version="[4.2.0,4.3.0)",
org.eclipse.jgit.lib;version="[4.2.0,4.3.0)", org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
org.eclipse.jgit.merge;version="[4.2.0,4.3.0)", org.eclipse.jgit.merge;version="[4.2.0,4.3.0)",

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

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/org.eclipse.jgit.test/tst"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="2"/>
</listAttribute>
<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
<mapAttribute key="org.eclipse.debug.core.environmentVariables">
<mapEntry key="LANG" value="de_DE.UTF-8"/>
</mapAttribute>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/tst"/>
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<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 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;"/>
</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.8"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.test"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx256m"/>
</launchConfiguration>

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

@ -43,6 +43,7 @@
*/ */
package org.eclipse.jgit.api; package org.eclipse.jgit.api;
import static org.eclipse.jgit.util.FileUtils.RECURSIVE;
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.assertTrue;
@ -797,13 +798,108 @@ public class AddCommandTest extends RepositoryTestCase {
assertEquals("[a.txt, mode:100644, content:more content," assertEquals("[a.txt, mode:100644, content:more content,"
+ " assume-unchanged:false][b.txt, mode:100644," + " assume-unchanged:false][b.txt, mode:100644,"
+ "" + ""
+ " content:content, assume-unchanged:true]", + " content:content, assume-unchanged:true]",
indexState(CONTENT indexState(CONTENT
| ASSUME_UNCHANGED)); | ASSUME_UNCHANGED));
} }
} }
@Test
public void testReplaceFileWithDirectory()
throws IOException, NoFilepatternException, GitAPIException {
try (Git git = new Git(db)) {
writeTrashFile("df", "before replacement");
git.add().addFilepattern("df").call();
assertEquals("[df, mode:100644, content:before replacement]",
indexState(CONTENT));
FileUtils.delete(new File(db.getWorkTree(), "df"));
writeTrashFile("df/f", "after replacement");
git.add().addFilepattern("df").call();
assertEquals("[df/f, mode:100644, content:after replacement]",
indexState(CONTENT));
}
}
@Test
public void testReplaceDirectoryWithFile()
throws IOException, NoFilepatternException, GitAPIException {
try (Git git = new Git(db)) {
writeTrashFile("df/f", "before replacement");
git.add().addFilepattern("df").call();
assertEquals("[df/f, mode:100644, content:before replacement]",
indexState(CONTENT));
FileUtils.delete(new File(db.getWorkTree(), "df"), RECURSIVE);
writeTrashFile("df", "after replacement");
git.add().addFilepattern("df").call();
assertEquals("[df, mode:100644, content:after replacement]",
indexState(CONTENT));
}
}
@Test
public void testReplaceFileByPartOfDirectory()
throws IOException, NoFilepatternException, GitAPIException {
try (Git git = new Git(db)) {
writeTrashFile("src/main", "df", "before replacement");
writeTrashFile("src/main", "z", "z");
writeTrashFile("z", "z2");
git.add().addFilepattern("src/main/df")
.addFilepattern("src/main/z")
.addFilepattern("z")
.call();
assertEquals(
"[src/main/df, mode:100644, content:before replacement]" +
"[src/main/z, mode:100644, content:z]" +
"[z, mode:100644, content:z2]",
indexState(CONTENT));
FileUtils.delete(new File(db.getWorkTree(), "src/main/df"));
writeTrashFile("src/main/df", "a", "after replacement");
writeTrashFile("src/main/df", "b", "unrelated file");
git.add().addFilepattern("src/main/df/a").call();
assertEquals(
"[src/main/df/a, mode:100644, content:after replacement]" +
"[src/main/z, mode:100644, content:z]" +
"[z, mode:100644, content:z2]",
indexState(CONTENT));
}
}
@Test
public void testReplaceDirectoryConflictsWithFile()
throws IOException, NoFilepatternException, GitAPIException {
DirCache dc = db.lockDirCache();
try (ObjectInserter oi = db.newObjectInserter()) {
DirCacheBuilder builder = dc.builder();
File f = writeTrashFile("a", "df", "content");
addEntryToBuilder("a", f, oi, builder, 1);
f = writeTrashFile("a", "df", "other content");
addEntryToBuilder("a/df", f, oi, builder, 3);
f = writeTrashFile("a", "df", "our content");
addEntryToBuilder("a/df", f, oi, builder, 2);
f = writeTrashFile("z", "z");
addEntryToBuilder("z", f, oi, builder, 0);
builder.commit();
}
assertEquals(
"[a, mode:100644, stage:1, content:content]" +
"[a/df, mode:100644, stage:2, content:our content]" +
"[a/df, mode:100644, stage:3, content:other content]" +
"[z, mode:100644, content:z]",
indexState(CONTENT));
try (Git git = new Git(db)) {
FileUtils.delete(new File(db.getWorkTree(), "a"), RECURSIVE);
writeTrashFile("a", "merged");
git.add().addFilepattern("a").call();
assertEquals("[a, mode:100644, content:merged]" +
"[z, mode:100644, content:z]",
indexState(CONTENT));
}
}
@Test @Test
public void testExecutableRetention() throws Exception { public void testExecutableRetention() throws Exception {
StoredConfig config = db.getConfig(); StoredConfig config = db.getConfig();

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

@ -46,12 +46,15 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
import java.io.File; import java.io.File;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import org.eclipse.jgit.api.errors.EmtpyCommitException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCache;
@ -476,6 +479,34 @@ public class CommitCommandTest extends RepositoryTestCase {
assertEquals("newauthor@example.org", amendedAuthor.getEmailAddress()); assertEquals("newauthor@example.org", amendedAuthor.getEmailAddress());
} }
@Test
public void commitEmptyCommits() throws Exception {
try (Git git = new Git(db)) {
writeTrashFile("file1", "file1");
git.add().addFilepattern("file1").call();
RevCommit initial = git.commit().setMessage("initial commit")
.call();
RevCommit emptyFollowUp = git.commit()
.setAuthor("New Author", "newauthor@example.org")
.setMessage("no change").call();
assertNotEquals(initial.getId(), emptyFollowUp.getId());
assertEquals(initial.getTree().getId(),
emptyFollowUp.getTree().getId());
try {
git.commit().setAuthor("New Author", "newauthor@example.org")
.setMessage("again no change").setAllowEmpty(false)
.call();
fail("Didn't get the expected EmtpyCommitException");
} catch (EmtpyCommitException e) {
// expect this exception
}
}
}
@Test @Test
public void commitOnlyShouldCommitUnmergedPathAndNotAffectOthers() public void commitOnlyShouldCommitUnmergedPathAndNotAffectOthers()
throws Exception { throws Exception {

65
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java

@ -43,10 +43,12 @@
package org.eclipse.jgit.api; package org.eclipse.jgit.api;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path;
import org.eclipse.jgit.api.CheckoutCommand.Stage; import org.eclipse.jgit.api.CheckoutCommand.Stage;
import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.JGitInternalException;
@ -59,6 +61,9 @@ import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.jgit.lib.RepositoryState;
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.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.junit.Assume;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -73,6 +78,8 @@ public class PathCheckoutCommandTest extends RepositoryTestCase {
private static final String FILE3 = "Test3.txt"; private static final String FILE3 = "Test3.txt";
private static final String LINK = "link";
Git git; Git git;
RevCommit initialCommit; RevCommit initialCommit;
@ -98,6 +105,64 @@ public class PathCheckoutCommandTest extends RepositoryTestCase {
git.commit().setMessage("Third commit").call(); git.commit().setMessage("Third commit").call();
} }
@Test
public void testUpdateSymLink() throws Exception {
Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
Path path = writeLink(LINK, FILE1);
git.add().addFilepattern(LINK).call();
git.commit().setMessage("Added link").call();
assertEquals("3", read(path.toFile()));
writeLink(LINK, FILE2);
assertEquals("c", read(path.toFile()));
CheckoutCommand co = git.checkout();
co.addPath(LINK).call();
assertEquals("3", read(path.toFile()));
}
@Test
public void testUpdateBrokenSymLinkToDirectory() throws Exception {
Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
Path path = writeLink(LINK, "f");
git.add().addFilepattern(LINK).call();
git.commit().setMessage("Added link").call();
assertEquals("f", FileUtils.readSymLink(path.toFile()));
assertTrue(path.toFile().exists());
writeLink(LINK, "link_to_nowhere");
assertFalse(path.toFile().exists());
assertEquals("link_to_nowhere", FileUtils.readSymLink(path.toFile()));
CheckoutCommand co = git.checkout();
co.addPath(LINK).call();
assertEquals("f", FileUtils.readSymLink(path.toFile()));
}
@Test
public void testUpdateBrokenSymLink() throws Exception {
Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
Path path = writeLink(LINK, FILE1);
git.add().addFilepattern(LINK).call();
git.commit().setMessage("Added link").call();
assertEquals("3", read(path.toFile()));
assertEquals(FILE1, FileUtils.readSymLink(path.toFile()));
writeLink(LINK, "link_to_nowhere");
assertFalse(path.toFile().exists());
assertEquals("link_to_nowhere", FileUtils.readSymLink(path.toFile()));
CheckoutCommand co = git.checkout();
co.addPath(LINK).call();
assertEquals("3", read(path.toFile()));
}
@Test @Test
public void testUpdateWorkingDirectory() throws Exception { public void testUpdateWorkingDirectory() throws Exception {
CheckoutCommand co = git.checkout(); CheckoutCommand co = git.checkout();

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

@ -65,6 +65,7 @@ import org.eclipse.jgit.junit.RepositoryTestCase;
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.Ref;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
@ -139,8 +140,8 @@ public class ResetCommandTest extends RepositoryTestCase {
AmbiguousObjectException, IOException, GitAPIException { AmbiguousObjectException, IOException, GitAPIException {
setupRepository(); setupRepository();
ObjectId prevHead = db.resolve(Constants.HEAD); ObjectId prevHead = db.resolve(Constants.HEAD);
git.reset().setMode(ResetType.HARD).setRef(initialCommit.getName()) assertSameAsHead(git.reset().setMode(ResetType.HARD)
.call(); .setRef(initialCommit.getName()).call());
// check if HEAD points to initial commit now // check if HEAD points to initial commit now
ObjectId head = db.resolve(Constants.HEAD); ObjectId head = db.resolve(Constants.HEAD);
assertEquals(initialCommit, head); assertEquals(initialCommit, head);
@ -176,8 +177,8 @@ public class ResetCommandTest extends RepositoryTestCase {
AmbiguousObjectException, IOException, GitAPIException { AmbiguousObjectException, IOException, GitAPIException {
setupRepository(); setupRepository();
ObjectId prevHead = db.resolve(Constants.HEAD); ObjectId prevHead = db.resolve(Constants.HEAD);
git.reset().setMode(ResetType.SOFT).setRef(initialCommit.getName()) assertSameAsHead(git.reset().setMode(ResetType.SOFT)
.call(); .setRef(initialCommit.getName()).call());
// check if HEAD points to initial commit now // check if HEAD points to initial commit now
ObjectId head = db.resolve(Constants.HEAD); ObjectId head = db.resolve(Constants.HEAD);
assertEquals(initialCommit, head); assertEquals(initialCommit, head);
@ -197,8 +198,8 @@ public class ResetCommandTest extends RepositoryTestCase {
AmbiguousObjectException, IOException, GitAPIException { AmbiguousObjectException, IOException, GitAPIException {
setupRepository(); setupRepository();
ObjectId prevHead = db.resolve(Constants.HEAD); ObjectId prevHead = db.resolve(Constants.HEAD);
git.reset().setMode(ResetType.MIXED).setRef(initialCommit.getName()) assertSameAsHead(git.reset().setMode(ResetType.MIXED)
.call(); .setRef(initialCommit.getName()).call());
// check if HEAD points to initial commit now // check if HEAD points to initial commit now
ObjectId head = db.resolve(Constants.HEAD); ObjectId head = db.resolve(Constants.HEAD);
assertEquals(initialCommit, head); assertEquals(initialCommit, head);
@ -241,7 +242,8 @@ public class ResetCommandTest extends RepositoryTestCase {
assertTrue(bEntry.getLength() > 0); assertTrue(bEntry.getLength() > 0);
assertTrue(bEntry.getLastModified() > 0); assertTrue(bEntry.getLastModified() > 0);
git.reset().setMode(ResetType.MIXED).setRef(commit2.getName()).call(); assertSameAsHead(git.reset().setMode(ResetType.MIXED)
.setRef(commit2.getName()).call());
cache = db.readDirCache(); cache = db.readDirCache();
@ -280,7 +282,7 @@ public class ResetCommandTest extends RepositoryTestCase {
+ "[a.txt, mode:100644, stage:3]", + "[a.txt, mode:100644, stage:3]",
indexState(0)); indexState(0));
git.reset().setMode(ResetType.MIXED).call(); assertSameAsHead(git.reset().setMode(ResetType.MIXED).call());
assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]", assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]",
indexState(0)); indexState(0));
@ -298,8 +300,8 @@ public class ResetCommandTest extends RepositoryTestCase {
// 'a.txt' has already been modified in setupRepository // 'a.txt' has already been modified in setupRepository
// 'notAddedToIndex.txt' has been added to repository // 'notAddedToIndex.txt' has been added to repository
git.reset().addPath(indexFile.getName()) assertSameAsHead(git.reset().addPath(indexFile.getName())
.addPath(untrackedFile.getName()).call(); .addPath(untrackedFile.getName()).call());
DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS()) DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS())
.getEntry(indexFile.getName()); .getEntry(indexFile.getName());
@ -329,7 +331,7 @@ public class ResetCommandTest extends RepositoryTestCase {
git.add().addFilepattern(untrackedFile.getName()).call(); git.add().addFilepattern(untrackedFile.getName()).call();
// 'dir/b.txt' has already been modified in setupRepository // 'dir/b.txt' has already been modified in setupRepository
git.reset().addPath("dir").call(); assertSameAsHead(git.reset().addPath("dir").call());
DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS()) DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS())
.getEntry("dir/b.txt"); .getEntry("dir/b.txt");
@ -358,9 +360,9 @@ public class ResetCommandTest extends RepositoryTestCase {
// 'a.txt' has already been modified in setupRepository // 'a.txt' has already been modified in setupRepository
// 'notAddedToIndex.txt' has been added to repository // 'notAddedToIndex.txt' has been added to repository
// reset to the inital commit // reset to the inital commit
git.reset().setRef(initialCommit.getName()) assertSameAsHead(git.reset().setRef(initialCommit.getName())
.addPath(indexFile.getName()) .addPath(indexFile.getName()).addPath(untrackedFile.getName())
.addPath(untrackedFile.getName()).call(); .call());
// check that HEAD hasn't moved // check that HEAD hasn't moved
ObjectId head = db.resolve(Constants.HEAD); ObjectId head = db.resolve(Constants.HEAD);
@ -397,7 +399,7 @@ public class ResetCommandTest extends RepositoryTestCase {
+ "[b.txt, mode:100644]", + "[b.txt, mode:100644]",
indexState(0)); indexState(0));
git.reset().addPath(file).call(); assertSameAsHead(git.reset().addPath(file).call());
assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]", assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]",
indexState(0)); indexState(0));
@ -409,7 +411,7 @@ public class ResetCommandTest extends RepositoryTestCase {
writeTrashFile("a.txt", "content"); writeTrashFile("a.txt", "content");
git.add().addFilepattern("a.txt").call(); git.add().addFilepattern("a.txt").call();
// Should assume an empty tree, like in C Git 1.8.2 // Should assume an empty tree, like in C Git 1.8.2
git.reset().addPath("a.txt").call(); assertSameAsHead(git.reset().addPath("a.txt").call());
DirCache cache = db.readDirCache(); DirCache cache = db.readDirCache();
DirCacheEntry aEntry = cache.getEntry("a.txt"); DirCacheEntry aEntry = cache.getEntry("a.txt");
@ -421,7 +423,8 @@ public class ResetCommandTest extends RepositoryTestCase {
git = new Git(db); git = new Git(db);
writeTrashFile("a.txt", "content"); writeTrashFile("a.txt", "content");
git.add().addFilepattern("a.txt").call(); git.add().addFilepattern("a.txt").call();
git.reset().setRef("doesnotexist").addPath("a.txt").call(); assertSameAsHead(
git.reset().setRef("doesnotexist").addPath("a.txt").call());
} }
@Test @Test
@ -431,7 +434,7 @@ public class ResetCommandTest extends RepositoryTestCase {
git.add().addFilepattern("a.txt").call(); git.add().addFilepattern("a.txt").call();
writeTrashFile("a.txt", "modified"); writeTrashFile("a.txt", "modified");
// should use default mode MIXED // should use default mode MIXED
git.reset().call(); assertSameAsHead(git.reset().call());
DirCache cache = db.readDirCache(); DirCache cache = db.readDirCache();
DirCacheEntry aEntry = cache.getEntry("a.txt"); DirCacheEntry aEntry = cache.getEntry("a.txt");
@ -452,7 +455,7 @@ public class ResetCommandTest extends RepositoryTestCase {
git.add().addFilepattern(untrackedFile.getName()).call(); git.add().addFilepattern(untrackedFile.getName()).call();
git.reset().setRef(tagName).setMode(HARD).call(); assertSameAsHead(git.reset().setRef(tagName).setMode(HARD).call());
ObjectId head = db.resolve(Constants.HEAD); ObjectId head = db.resolve(Constants.HEAD);
assertEquals(secondCommit, head); assertEquals(secondCommit, head);
@ -486,7 +489,8 @@ public class ResetCommandTest extends RepositoryTestCase {
result.getMergeStatus()); result.getMergeStatus());
assertNotNull(db.readSquashCommitMsg()); assertNotNull(db.readSquashCommitMsg());
g.reset().setMode(ResetType.HARD).setRef(first.getName()).call(); assertSameAsHead(g.reset().setMode(ResetType.HARD)
.setRef(first.getName()).call());
assertNull(db.readSquashCommitMsg()); assertNull(db.readSquashCommitMsg());
} }
@ -497,7 +501,7 @@ public class ResetCommandTest extends RepositoryTestCase {
File fileA = writeTrashFile("a.txt", "content"); File fileA = writeTrashFile("a.txt", "content");
git.add().addFilepattern("a.txt").call(); git.add().addFilepattern("a.txt").call();
// Should assume an empty tree, like in C Git 1.8.2 // Should assume an empty tree, like in C Git 1.8.2
git.reset().setMode(ResetType.HARD).call(); assertSameAsHead(git.reset().setMode(ResetType.HARD).call());
DirCache cache = db.readDirCache(); DirCache cache = db.readDirCache();
DirCacheEntry aEntry = cache.getEntry("a.txt"); DirCacheEntry aEntry = cache.getEntry("a.txt");
@ -558,4 +562,14 @@ public class ResetCommandTest extends RepositoryTestCase {
return dc.getEntry(path) != null; return dc.getEntry(path) != null;
} }
/**
* Asserts that a certain ref is similar to repos HEAD.
* @param ref
* @throws IOException
*/
private void assertSameAsHead(Ref ref) throws IOException {
Ref headRef = db.getRef(Constants.HEAD);
assertEquals(headRef.getName(), ref.getName());
assertEquals(headRef.getObjectId(), ref.getObjectId());
}
} }

121
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java vendored

@ -43,11 +43,13 @@
package org.eclipse.jgit.dircache; package org.eclipse.jgit.dircache;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit; import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.errors.DirCacheNameConflictException;
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.junit.Test; import org.junit.Test;
@ -154,6 +156,125 @@ public class DirCachePathEditTest {
assertEquals(DirCacheEntry.STAGE_3, entries.get(2).getStage()); assertEquals(DirCacheEntry.STAGE_3, entries.get(2).getStage());
} }
@Test
public void testFileReplacesTree() throws Exception {
DirCache dc = DirCache.newInCore();
DirCacheEditor editor = dc.editor();
editor.add(new AddEdit("a"));
editor.add(new AddEdit("b/c"));
editor.add(new AddEdit("b/d"));
editor.add(new AddEdit("e"));
editor.finish();
editor = dc.editor();
editor.add(new AddEdit("b"));
editor.finish();
assertEquals(3, dc.getEntryCount());
assertEquals("a", dc.getEntry(0).getPathString());
assertEquals("b", dc.getEntry(1).getPathString());
assertEquals("e", dc.getEntry(2).getPathString());
dc.clear();
editor = dc.editor();
editor.add(new AddEdit("A.c"));
editor.add(new AddEdit("A/c"));
editor.add(new AddEdit("A0c"));
editor.finish();
editor = dc.editor();
editor.add(new AddEdit("A"));
editor.finish();
assertEquals(3, dc.getEntryCount());
assertEquals("A", dc.getEntry(0).getPathString());
assertEquals("A.c", dc.getEntry(1).getPathString());
assertEquals("A0c", dc.getEntry(2).getPathString());
}
@Test
public void testTreeReplacesFile() throws Exception {
DirCache dc = DirCache.newInCore();
DirCacheEditor editor = dc.editor();
editor.add(new AddEdit("a"));
editor.add(new AddEdit("ab"));
editor.add(new AddEdit("b"));
editor.add(new AddEdit("e"));
editor.finish();
editor = dc.editor();
editor.add(new AddEdit("b/c/d/f"));
editor.add(new AddEdit("b/g/h/i"));
editor.finish();
assertEquals(5, dc.getEntryCount());
assertEquals("a", dc.getEntry(0).getPathString());
assertEquals("ab", dc.getEntry(1).getPathString());
assertEquals("b/c/d/f", dc.getEntry(2).getPathString());
assertEquals("b/g/h/i", dc.getEntry(3).getPathString());
assertEquals("e", dc.getEntry(4).getPathString());
}
@Test
public void testDuplicateFiles() throws Exception {
DirCache dc = DirCache.newInCore();
DirCacheEditor editor = dc.editor();
editor.add(new AddEdit("a"));
editor.add(new AddEdit("a"));
try {
editor.finish();
fail("Expected DirCacheNameConflictException to be thrown");
} catch (DirCacheNameConflictException e) {
assertEquals("a a", e.getMessage());
assertEquals("a", e.getPath1());
assertEquals("a", e.getPath2());
}
}
@Test
public void testFileOverlapsTree() throws Exception {
DirCache dc = DirCache.newInCore();
DirCacheEditor editor = dc.editor();
editor.add(new AddEdit("a"));
editor.add(new AddEdit("a/b").setReplace(false));
try {
editor.finish();
fail("Expected DirCacheNameConflictException to be thrown");
} catch (DirCacheNameConflictException e) {
assertEquals("a a/b", e.getMessage());
assertEquals("a", e.getPath1());
assertEquals("a/b", e.getPath2());
}
editor = dc.editor();
editor.add(new AddEdit("A.c"));
editor.add(new AddEdit("A/c").setReplace(false));
editor.add(new AddEdit("A0c"));
editor.add(new AddEdit("A"));
try {
editor.finish();
fail("Expected DirCacheNameConflictException to be thrown");
} catch (DirCacheNameConflictException e) {
assertEquals("A A/c", e.getMessage());
assertEquals("A", e.getPath1());
assertEquals("A/c", e.getPath2());
}
editor = dc.editor();
editor.add(new AddEdit("A.c"));
editor.add(new AddEdit("A/b/c/d").setReplace(false));
editor.add(new AddEdit("A/b/c"));
editor.add(new AddEdit("A0c"));
try {
editor.finish();
fail("Expected DirCacheNameConflictException to be thrown");
} catch (DirCacheNameConflictException e) {
assertEquals("A/b/c A/b/c/d", e.getMessage());
assertEquals("A/b/c", e.getPath1());
assertEquals("A/b/c/d", e.getPath2());
}
}
private static DirCacheEntry createEntry(String path, int stage) { private static DirCacheEntry createEntry(String path, int stage) {
DirCacheEntry entry = new DirCacheEntry(path, stage); DirCacheEntry entry = new DirCacheEntry(path, stage);
entry.setFileMode(FileMode.REGULAR_FILE); entry.setFileMode(FileMode.REGULAR_FILE);

7
org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java

@ -409,6 +409,7 @@ public class RepoCommandTest extends RepositoryTestCase {
.append("<project path=\"foo\" name=\"").append(defaultUri) .append("<project path=\"foo\" name=\"").append(defaultUri)
.append("\" revision=\"").append(BRANCH).append("\" >") .append("\" revision=\"").append(BRANCH).append("\" >")
.append("<copyfile src=\"hello.txt\" dest=\"Hello\" />") .append("<copyfile src=\"hello.txt\" dest=\"Hello\" />")
.append("<copyfile src=\"hello.txt\" dest=\"foo/Hello\" />")
.append("</project>").append("</manifest>"); .append("</project>").append("</manifest>");
JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
xmlContent.toString()); xmlContent.toString());
@ -423,8 +424,12 @@ public class RepoCommandTest extends RepositoryTestCase {
.getRepository(); .getRepository();
// The Hello file should exist // The Hello file should exist
File hello = new File(localDb.getWorkTree(), "Hello"); File hello = new File(localDb.getWorkTree(), "Hello");
localDb.close();
assertTrue("The Hello file should exist", hello.exists()); assertTrue("The Hello file should exist", hello.exists());
// The foo/Hello file should be skipped.
File foohello = new File(localDb.getWorkTree(), "foo/Hello");
assertFalse(
"The foo/Hello file should be skipped", foohello.exists());
localDb.close();
// The content of Hello file should be expected // The content of Hello file should be expected
BufferedReader reader = new BufferedReader(new FileReader(hello)); BufferedReader reader = new BufferedReader(new FileReader(hello));
String content = reader.readLine(); String content = reader.readLine();

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileRepositoryBuilderTest.java

@ -107,7 +107,7 @@ public class FileRepositoryBuilderTest extends LocalDiskRepositoryTestCase {
Repository r = createWorkRepository(); Repository r = createWorkRepository();
StoredConfig config = r.getConfig(); StoredConfig config = r.getConfig();
config.setLong(ConfigConstants.CONFIG_CORE_SECTION, null, config.setLong(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 1); ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 999999);
config.save(); config.save();
try { try {

70
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java

@ -43,11 +43,13 @@
package org.eclipse.jgit.internal.storage.file; package org.eclipse.jgit.internal.storage.file;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
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;
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 static org.eclipse.jgit.internal.storage.pack.PackWriter.NONE;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -66,19 +68,19 @@ import java.util.Set;
import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
import org.eclipse.jgit.internal.storage.pack.PackWriter; import org.eclipse.jgit.internal.storage.pack.PackWriter;
import org.eclipse.jgit.internal.storage.pack.PackWriter.ObjectIdSet;
import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.junit.TestRepository.BranchBuilder; import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdSet;
import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.revwalk.RevBlob; import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.storage.pack.PackStatistics;
import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
import org.eclipse.jgit.transport.PackParser; import org.eclipse.jgit.transport.PackParser;
import org.junit.After; import org.junit.After;
@ -87,9 +89,6 @@ import org.junit.Test;
public class PackWriterTest extends SampleDataRepositoryTestCase { public class PackWriterTest extends SampleDataRepositoryTestCase {
private static final Set<ObjectId> EMPTY_SET_OBJECT = Collections
.<ObjectId> emptySet();
private static final List<RevObject> EMPTY_LIST_REVS = Collections private static final List<RevObject> EMPTY_LIST_REVS = Collections
.<RevObject> emptyList(); .<RevObject> emptyList();
@ -170,7 +169,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
*/ */
@Test @Test
public void testWriteEmptyPack1() throws IOException { public void testWriteEmptyPack1() throws IOException {
createVerifyOpenPack(EMPTY_SET_OBJECT, EMPTY_SET_OBJECT, false, false); createVerifyOpenPack(NONE, NONE, false, false);
assertEquals(0, writer.getObjectCount()); assertEquals(0, writer.getObjectCount());
assertEquals(0, pack.getObjectCount()); assertEquals(0, pack.getObjectCount());
@ -203,8 +202,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
final ObjectId nonExisting = ObjectId final ObjectId nonExisting = ObjectId
.fromString("0000000000000000000000000000000000000001"); .fromString("0000000000000000000000000000000000000001");
try { try {
createVerifyOpenPack(EMPTY_SET_OBJECT, Collections.singleton( createVerifyOpenPack(NONE, Collections.singleton(nonExisting),
nonExisting), false, false); false, false);
fail("Should have thrown MissingObjectException"); fail("Should have thrown MissingObjectException");
} catch (MissingObjectException x) { } catch (MissingObjectException x) {
// expected // expected
@ -220,8 +219,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
public void testIgnoreNonExistingObjects() throws IOException { public void testIgnoreNonExistingObjects() throws IOException {
final ObjectId nonExisting = ObjectId final ObjectId nonExisting = ObjectId
.fromString("0000000000000000000000000000000000000001"); .fromString("0000000000000000000000000000000000000001");
createVerifyOpenPack(EMPTY_SET_OBJECT, Collections.singleton( createVerifyOpenPack(NONE, Collections.singleton(nonExisting),
nonExisting), false, true); false, true);
// shouldn't throw anything // shouldn't throw anything
} }
@ -239,8 +238,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
final ObjectId nonExisting = ObjectId final ObjectId nonExisting = ObjectId
.fromString("0000000000000000000000000000000000000001"); .fromString("0000000000000000000000000000000000000001");
new GC(db).gc(); new GC(db).gc();
createVerifyOpenPack(EMPTY_SET_OBJECT, createVerifyOpenPack(NONE, Collections.singleton(nonExisting), false,
Collections.singleton(nonExisting), false, true, true); true, true);
// shouldn't throw anything // shouldn't throw anything
} }
@ -437,6 +436,38 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
assertTrue(sizePack4 > sizePack4Thin); assertTrue(sizePack4 > sizePack4Thin);
} }
@Test
public void testDeltaStatistics() throws Exception {
config.setDeltaCompress(true);
FileRepository repo = createBareRepository();
TestRepository<FileRepository> testRepo = new TestRepository<FileRepository>(repo);
ArrayList<RevObject> blobs = new ArrayList<>();
blobs.add(testRepo.blob(genDeltableData(1000)));
blobs.add(testRepo.blob(genDeltableData(1005)));
try (PackWriter pw = new PackWriter(repo)) {
NullProgressMonitor m = NullProgressMonitor.INSTANCE;
pw.preparePack(blobs.iterator());
pw.writePack(m, m, os);
PackStatistics stats = pw.getStatistics();
assertEquals(1, stats.getTotalDeltas());
assertTrue("Delta bytes not set.",
stats.byObjectType(OBJ_BLOB).getDeltaBytes() > 0);
}
}
// Generate consistent junk data for building files that delta well
private String genDeltableData(int length) {
assertTrue("Generated data must have a length > 0", length > 0);
char[] data = {'a', 'b', 'c', '\n'};
StringBuilder builder = new StringBuilder(length);
for (int i = 0; i < length; i++) {
builder.append(data[i % 4]);
}
return builder.toString();
}
@Test @Test
public void testWriteIndex() throws Exception { public void testWriteIndex() throws Exception {
config.setIndexVersion(2); config.setIndexVersion(2);
@ -494,7 +525,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
RevCommit c2 = bb.commit().add("f", contentB).create(); RevCommit c2 = bb.commit().add("f", contentB).create();
testRepo.getRevWalk().parseHeaders(c2); testRepo.getRevWalk().parseHeaders(c2);
PackIndex pf2 = writePack(repo, Collections.singleton(c2), PackIndex pf2 = writePack(repo, Collections.singleton(c2),
Collections.singleton(objectIdSet(pf1))); Collections.<ObjectIdSet> singleton(pf1));
assertContent( assertContent(
pf2, pf2,
Arrays.asList(c2.getId(), c2.getTree().getId(), Arrays.asList(c2.getId(), c2.getTree().getId(),
@ -519,8 +550,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
pw.setReuseDeltaCommits(false); pw.setReuseDeltaCommits(false);
for (ObjectIdSet idx : excludeObjects) for (ObjectIdSet idx : excludeObjects)
pw.excludeObjects(idx); pw.excludeObjects(idx);
pw.preparePack(NullProgressMonitor.INSTANCE, want, pw.preparePack(NullProgressMonitor.INSTANCE, want, NONE);
Collections.<ObjectId> emptySet());
String id = pw.computeName().getName(); String id = pw.computeName().getName();
File packdir = new File(repo.getObjectsDirectory(), "pack"); File packdir = new File(repo.getObjectsDirectory(), "pack");
File packFile = new File(packdir, "pack-" + id + ".pack"); File packFile = new File(packdir, "pack-" + id + ".pack");
@ -543,7 +573,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
final HashSet<ObjectId> interestings = new HashSet<ObjectId>(); final HashSet<ObjectId> interestings = new HashSet<ObjectId>();
interestings.add(ObjectId interestings.add(ObjectId
.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7")); .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"));
createVerifyOpenPack(interestings, EMPTY_SET_OBJECT, false, false); createVerifyOpenPack(interestings, NONE, false, false);
final ObjectId expectedOrder[] = new ObjectId[] { final ObjectId expectedOrder[] = new ObjectId[] {
ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"), ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
@ -699,12 +729,4 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
assertEquals(objectsOrder[i++].toObjectId(), me.toObjectId()); assertEquals(objectsOrder[i++].toObjectId(), me.toObjectId());
} }
} }
private static ObjectIdSet objectIdSet(final PackIndex idx) {
return new ObjectIdSet() {
public boolean contains(AnyObjectId objectId) {
return idx.hasObject(objectId);
}
};
}
} }

53
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java

@ -67,7 +67,6 @@ import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.CommitBuilder; import org.eclipse.jgit.lib.CommitBuilder;
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.FileTreeEntry;
import org.eclipse.jgit.lib.ObjectDatabase; import org.eclipse.jgit.lib.ObjectDatabase;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.ObjectInserter;
@ -75,7 +74,6 @@ import org.eclipse.jgit.lib.PersonIdent;
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.TagBuilder; import org.eclipse.jgit.lib.TagBuilder;
import org.eclipse.jgit.lib.Tree;
import org.eclipse.jgit.lib.TreeFormatter; import org.eclipse.jgit.lib.TreeFormatter;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTag; import org.eclipse.jgit.revwalk.RevTag;
@ -419,29 +417,6 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
assertEquals(c.getCommitter(), c2.getCommitterIdent()); assertEquals(c.getCommitter(), c2.getCommitterIdent());
} }
@Test
public void test012_SubtreeExternalSorting() throws IOException {
final ObjectId emptyBlob = insertEmptyBlob();
final Tree t = new Tree(db);
final FileTreeEntry e0 = t.addFile("a-");
final FileTreeEntry e1 = t.addFile("a-b");
final FileTreeEntry e2 = t.addFile("a/b");
final FileTreeEntry e3 = t.addFile("a=");
final FileTreeEntry e4 = t.addFile("a=b");
e0.setId(emptyBlob);
e1.setId(emptyBlob);
e2.setId(emptyBlob);
e3.setId(emptyBlob);
e4.setId(emptyBlob);
final Tree a = (Tree) t.findTreeMember("a");
a.setId(insertTree(a));
assertEquals(ObjectId
.fromString("b47a8f0a4190f7572e11212769090523e23eb1ea"),
insertTree(t));
}
@Test @Test
public void test020_createBlobTag() throws IOException { public void test020_createBlobTag() throws IOException {
final ObjectId emptyId = insertEmptyBlob(); final ObjectId emptyId = insertEmptyBlob();
@ -465,9 +440,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
@Test @Test
public void test021_createTreeTag() throws IOException { public void test021_createTreeTag() throws IOException {
final ObjectId emptyId = insertEmptyBlob(); final ObjectId emptyId = insertEmptyBlob();
final Tree almostEmptyTree = new Tree(db); TreeFormatter almostEmptyTree = new TreeFormatter();
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId);
"empty".getBytes(), false));
final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree);
final TagBuilder t = new TagBuilder(); final TagBuilder t = new TagBuilder();
t.setObjectId(almostEmptyTreeId, Constants.OBJ_TREE); t.setObjectId(almostEmptyTreeId, Constants.OBJ_TREE);
@ -489,9 +463,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
@Test @Test
public void test022_createCommitTag() throws IOException { public void test022_createCommitTag() throws IOException {
final ObjectId emptyId = insertEmptyBlob(); final ObjectId emptyId = insertEmptyBlob();
final Tree almostEmptyTree = new Tree(db); TreeFormatter almostEmptyTree = new TreeFormatter();
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId);
"empty".getBytes(), false));
final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree);
final CommitBuilder almostEmptyCommit = new CommitBuilder(); final CommitBuilder almostEmptyCommit = new CommitBuilder();
almostEmptyCommit.setAuthor(new PersonIdent(author, 1154236443000L, almostEmptyCommit.setAuthor(new PersonIdent(author, 1154236443000L,
@ -521,9 +494,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
@Test @Test
public void test023_createCommitNonAnullii() throws IOException { public void test023_createCommitNonAnullii() throws IOException {
final ObjectId emptyId = insertEmptyBlob(); final ObjectId emptyId = insertEmptyBlob();
final Tree almostEmptyTree = new Tree(db); TreeFormatter almostEmptyTree = new TreeFormatter();
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId);
"empty".getBytes(), false));
final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree);
CommitBuilder commit = new CommitBuilder(); CommitBuilder commit = new CommitBuilder();
commit.setTreeId(almostEmptyTreeId); commit.setTreeId(almostEmptyTreeId);
@ -543,9 +515,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
@Test @Test
public void test024_createCommitNonAscii() throws IOException { public void test024_createCommitNonAscii() throws IOException {
final ObjectId emptyId = insertEmptyBlob(); final ObjectId emptyId = insertEmptyBlob();
final Tree almostEmptyTree = new Tree(db); TreeFormatter almostEmptyTree = new TreeFormatter();
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId);
"empty".getBytes(), false));
final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree);
CommitBuilder commit = new CommitBuilder(); CommitBuilder commit = new CommitBuilder();
commit.setTreeId(almostEmptyTreeId); commit.setTreeId(almostEmptyTreeId);
@ -747,14 +718,6 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
return emptyId; return emptyId;
} }
private ObjectId insertTree(Tree tree) throws IOException {
try (ObjectInserter oi = db.newObjectInserter()) {
ObjectId id = oi.insert(Constants.OBJ_TREE, tree.format());
oi.flush();
return id;
}
}
private ObjectId insertTree(TreeFormatter tree) throws IOException { private ObjectId insertTree(TreeFormatter tree) throws IOException {
try (ObjectInserter oi = db.newObjectInserter()) { try (ObjectInserter oi = db.newObjectInserter()) {
ObjectId id = oi.insert(tree); ObjectId id = oi.insert(tree);

685
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java

@ -0,0 +1,685 @@
/*
* Copyright (C) 2010, 2013, 2016 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.internal.storage.reftree;
import static org.eclipse.jgit.lib.Constants.HEAD;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
import static org.eclipse.jgit.lib.Ref.Storage.LOOSE;
import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
import static org.eclipse.jgit.lib.RefDatabase.ALL;
import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE;
import static org.eclipse.jgit.transport.ReceiveCommand.Result.OK;
import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_NONFASTFORWARD;
import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
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.junit.TestRepository;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.SymbolicRef;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.junit.Before;
import org.junit.Test;
public class RefTreeDatabaseTest {
private InMemRefTreeRepo repo;
private RefTreeDatabase refdb;
private RefDatabase bootstrap;
private TestRepository<InMemRefTreeRepo> testRepo;
private RevCommit A;
private RevCommit B;
private RevTag v1_0;
@Before
public void setUp() throws Exception {
repo = new InMemRefTreeRepo(new DfsRepositoryDescription("test"));
bootstrap = refdb.getBootstrap();
testRepo = new TestRepository<>(repo);
A = testRepo.commit().create();
B = testRepo.commit(testRepo.getRevWalk().parseCommit(A));
v1_0 = testRepo.tag("v1_0", B);
testRepo.getRevWalk().parseBody(v1_0);
}
@Test
public void testSupportsAtomic() {
assertTrue(refdb.performsAtomicTransactions());
}
@Test
public void testGetRefs_EmptyDatabase() throws IOException {
assertTrue("no references", refdb.getRefs(ALL).isEmpty());
assertTrue("no references", refdb.getRefs(R_HEADS).isEmpty());
assertTrue("no references", refdb.getRefs(R_TAGS).isEmpty());
}
@Test
public void testGetRefs_HeadOnOneBranch() throws IOException {
symref(HEAD, "refs/heads/master");
update("refs/heads/master", A);
Map<String, Ref> all = refdb.getRefs(ALL);
assertEquals(2, all.size());
assertTrue("has HEAD", all.containsKey(HEAD));
assertTrue("has master", all.containsKey("refs/heads/master"));
Ref head = all.get(HEAD);
Ref master = all.get("refs/heads/master");
assertEquals(HEAD, head.getName());
assertTrue(head.isSymbolic());
assertSame(LOOSE, head.getStorage());
assertSame("uses same ref as target", master, head.getTarget());
assertEquals("refs/heads/master", master.getName());
assertFalse(master.isSymbolic());
assertSame(PACKED, master.getStorage());
assertEquals(A, master.getObjectId());
}
@Test
public void testGetRefs_DetachedHead() throws IOException {
update(HEAD, A);
Map<String, Ref> all = refdb.getRefs(ALL);
assertEquals(1, all.size());
assertTrue("has HEAD", all.containsKey(HEAD));
Ref head = all.get(HEAD);
assertEquals(HEAD, head.getName());
assertFalse(head.isSymbolic());
assertSame(PACKED, head.getStorage());
assertEquals(A, head.getObjectId());
}
@Test
public void testGetRefs_DeeplyNestedBranch() throws IOException {
String name = "refs/heads/a/b/c/d/e/f/g/h/i/j/k";
update(name, A);
Map<String, Ref> all = refdb.getRefs(ALL);
assertEquals(1, all.size());
Ref r = all.get(name);
assertEquals(name, r.getName());
assertFalse(r.isSymbolic());
assertSame(PACKED, r.getStorage());
assertEquals(A, r.getObjectId());
}
@Test
public void testGetRefs_HeadBranchNotBorn() throws IOException {
update("refs/heads/A", A);
update("refs/heads/B", B);
Map<String, Ref> all = refdb.getRefs(ALL);
assertEquals(2, all.size());
assertFalse("no HEAD", all.containsKey(HEAD));
Ref a = all.get("refs/heads/A");
Ref b = all.get("refs/heads/B");
assertEquals(A, a.getObjectId());
assertEquals(B, b.getObjectId());
assertEquals("refs/heads/A", a.getName());
assertEquals("refs/heads/B", b.getName());
}
@Test
public void testGetRefs_HeadsOnly() throws IOException {
update("refs/heads/A", A);
update("refs/heads/B", B);
update("refs/tags/v1.0", v1_0);
Map<String, Ref> heads = refdb.getRefs(R_HEADS);
assertEquals(2, heads.size());
Ref a = heads.get("A");
Ref b = heads.get("B");
assertEquals("refs/heads/A", a.getName());
assertEquals("refs/heads/B", b.getName());
assertEquals(A, a.getObjectId());
assertEquals(B, b.getObjectId());
}
@Test
public void testGetRefs_TagsOnly() throws IOException {
update("refs/heads/A", A);
update("refs/heads/B", B);
update("refs/tags/v1.0", v1_0);
Map<String, Ref> tags = refdb.getRefs(R_TAGS);
assertEquals(1, tags.size());
Ref a = tags.get("v1.0");
assertEquals("refs/tags/v1.0", a.getName());
assertEquals(v1_0, a.getObjectId());
assertTrue(a.isPeeled());
assertEquals(v1_0.getObject(), a.getPeeledObjectId());
}
@Test
public void testGetRefs_HeadsSymref() throws IOException {
symref("refs/heads/other", "refs/heads/master");
update("refs/heads/master", A);
Map<String, Ref> heads = refdb.getRefs(R_HEADS);
assertEquals(2, heads.size());
Ref master = heads.get("master");
Ref other = heads.get("other");
assertEquals("refs/heads/master", master.getName());
assertEquals(A, master.getObjectId());
assertEquals("refs/heads/other", other.getName());
assertEquals(A, other.getObjectId());
assertSame(master, other.getTarget());
}
@Test
public void testGetRefs_InvalidPrefixes() throws IOException {
update("refs/heads/A", A);
assertTrue("empty refs/heads", refdb.getRefs("refs/heads").isEmpty());
assertTrue("empty objects", refdb.getRefs("objects").isEmpty());
assertTrue("empty objects/", refdb.getRefs("objects/").isEmpty());
}
@Test
public void testGetRefs_DiscoversNew() throws IOException {
update("refs/heads/master", A);
Map<String, Ref> orig = refdb.getRefs(ALL);
update("refs/heads/next", B);
Map<String, Ref> next = refdb.getRefs(ALL);
assertEquals(1, orig.size());
assertEquals(2, next.size());
assertFalse(orig.containsKey("refs/heads/next"));
assertTrue(next.containsKey("refs/heads/next"));
assertEquals(A, next.get("refs/heads/master").getObjectId());
assertEquals(B, next.get("refs/heads/next").getObjectId());
}
@Test
public void testGetRefs_DiscoversModified() throws IOException {
symref(HEAD, "refs/heads/master");
update("refs/heads/master", A);
Map<String, Ref> all = refdb.getRefs(ALL);
assertEquals(A, all.get(HEAD).getObjectId());
update("refs/heads/master", B);
all = refdb.getRefs(ALL);
assertEquals(B, all.get(HEAD).getObjectId());
assertEquals(B, refdb.exactRef(HEAD).getObjectId());
}
@Test
public void testGetRefs_CycleInSymbolicRef() throws IOException {
symref("refs/1", "refs/2");
symref("refs/2", "refs/3");
symref("refs/3", "refs/4");
symref("refs/4", "refs/5");
symref("refs/5", "refs/end");
update("refs/end", A);
Map<String, Ref> all = refdb.getRefs(ALL);
Ref r = all.get("refs/1");
assertNotNull("has 1", r);
assertEquals("refs/1", r.getName());
assertEquals(A, r.getObjectId());
assertTrue(r.isSymbolic());
r = r.getTarget();
assertEquals("refs/2", r.getName());
assertEquals(A, r.getObjectId());
assertTrue(r.isSymbolic());
r = r.getTarget();
assertEquals("refs/3", r.getName());
assertEquals(A, r.getObjectId());
assertTrue(r.isSymbolic());
r = r.getTarget();
assertEquals("refs/4", r.getName());
assertEquals(A, r.getObjectId());
assertTrue(r.isSymbolic());
r = r.getTarget();
assertEquals("refs/5", r.getName());
assertEquals(A, r.getObjectId());
assertTrue(r.isSymbolic());
r = r.getTarget();
assertEquals("refs/end", r.getName());
assertEquals(A, r.getObjectId());
assertFalse(r.isSymbolic());
symref("refs/5", "refs/6");
symref("refs/6", "refs/end");
all = refdb.getRefs(ALL);
assertNull("mising 1 due to cycle", all.get("refs/1"));
assertEquals(A, all.get("refs/2").getObjectId());
assertEquals(A, all.get("refs/3").getObjectId());
assertEquals(A, all.get("refs/4").getObjectId());
assertEquals(A, all.get("refs/5").getObjectId());
assertEquals(A, all.get("refs/6").getObjectId());
assertEquals(A, all.get("refs/end").getObjectId());
}
@Test
public void testGetRef_NonExistingBranchConfig() throws IOException {
assertNull("find branch config", refdb.getRef("config"));
assertNull("find branch config", refdb.getRef("refs/heads/config"));
}
@Test
public void testGetRef_FindBranchConfig() throws IOException {
update("refs/heads/config", A);
for (String t : new String[] { "config", "refs/heads/config" }) {
Ref r = refdb.getRef(t);
assertNotNull("find branch config (" + t + ")", r);
assertEquals("for " + t, "refs/heads/config", r.getName());
assertEquals("for " + t, A, r.getObjectId());
}
}
@Test
public void testFirstExactRef() throws IOException {
update("refs/heads/A", A);
update("refs/tags/v1.0", v1_0);
Ref a = refdb.firstExactRef("refs/heads/A", "refs/tags/v1.0");
Ref one = refdb.firstExactRef("refs/tags/v1.0", "refs/heads/A");
assertEquals("refs/heads/A", a.getName());
assertEquals("refs/tags/v1.0", one.getName());
assertEquals(A, a.getObjectId());
assertEquals(v1_0, one.getObjectId());
}
@Test
public void testExactRef_DiscoversModified() throws IOException {
symref(HEAD, "refs/heads/master");
update("refs/heads/master", A);
assertEquals(A, refdb.exactRef(HEAD).getObjectId());
update("refs/heads/master", B);
assertEquals(B, refdb.exactRef(HEAD).getObjectId());
}
@Test
public void testIsNameConflicting() throws IOException {
update("refs/heads/a/b", A);
update("refs/heads/q", B);
// new references cannot replace an existing container
assertTrue(refdb.isNameConflicting("refs"));
assertTrue(refdb.isNameConflicting("refs/heads"));
assertTrue(refdb.isNameConflicting("refs/heads/a"));
// existing reference is not conflicting
assertFalse(refdb.isNameConflicting("refs/heads/a/b"));
// new references are not conflicting
assertFalse(refdb.isNameConflicting("refs/heads/a/d"));
assertFalse(refdb.isNameConflicting("refs/heads/master"));
// existing reference must not be used as a container
assertTrue(refdb.isNameConflicting("refs/heads/a/b/c"));
assertTrue(refdb.isNameConflicting("refs/heads/q/master"));
// refs/txn/ names always conflict.
assertTrue(refdb.isNameConflicting(refdb.getTxnCommitted()));
assertTrue(refdb.isNameConflicting("refs/txn/foo"));
}
@Test
public void testUpdate_RefusesRefsTxnNamespace() throws IOException {
ObjectId txnId = getTxnCommitted();
RefUpdate u = refdb.newUpdate("refs/txn/tmp", false);
u.setNewObjectId(B);
assertEquals(RefUpdate.Result.LOCK_FAILURE, u.update());
assertEquals(txnId, getTxnCommitted());
ReceiveCommand cmd = command(null, B, "refs/txn/tmp");
BatchRefUpdate batch = refdb.newBatchUpdate();
batch.addCommand(cmd);
batch.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE);
assertEquals(REJECTED_OTHER_REASON, cmd.getResult());
assertEquals(MessageFormat.format(JGitText.get().invalidRefName,
"refs/txn/tmp"), cmd.getMessage());
assertEquals(txnId, getTxnCommitted());
}
@Test
public void testUpdate_RefusesDotLockInRefName() throws IOException {
ObjectId txnId = getTxnCommitted();
RefUpdate u = refdb.newUpdate("refs/heads/pu.lock", false);
u.setNewObjectId(B);
assertEquals(RefUpdate.Result.REJECTED, u.update());
assertEquals(txnId, getTxnCommitted());
ReceiveCommand cmd = command(null, B, "refs/heads/pu.lock");
BatchRefUpdate batch = refdb.newBatchUpdate();
batch.addCommand(cmd);
batch.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE);
assertEquals(REJECTED_OTHER_REASON, cmd.getResult());
assertEquals(JGitText.get().funnyRefname, cmd.getMessage());
assertEquals(txnId, getTxnCommitted());
}
@Test
public void testBatchRefUpdate_NonFastForwardAborts() throws IOException {
update("refs/heads/master", A);
update("refs/heads/masters", B);
ObjectId txnId = getTxnCommitted();
List<ReceiveCommand> commands = Arrays.asList(
command(A, B, "refs/heads/master"),
command(B, A, "refs/heads/masters"));
BatchRefUpdate batchUpdate = refdb.newBatchUpdate();
batchUpdate.addCommand(commands);
batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE);
assertEquals(txnId, getTxnCommitted());
assertEquals(REJECTED_NONFASTFORWARD,
commands.get(1).getResult());
assertEquals(REJECTED_OTHER_REASON,
commands.get(0).getResult());
assertEquals(JGitText.get().transactionAborted,
commands.get(0).getMessage());
}
@Test
public void testBatchRefUpdate_ForceUpdate() throws IOException {
update("refs/heads/master", A);
update("refs/heads/masters", B);
ObjectId txnId = getTxnCommitted();
List<ReceiveCommand> commands = Arrays.asList(
command(A, B, "refs/heads/master"),
command(B, A, "refs/heads/masters"));
BatchRefUpdate batchUpdate = refdb.newBatchUpdate();
batchUpdate.setAllowNonFastForwards(true);
batchUpdate.addCommand(commands);
batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE);
assertNotEquals(txnId, getTxnCommitted());
Map<String, Ref> refs = refdb.getRefs(ALL);
assertEquals(OK, commands.get(0).getResult());
assertEquals(OK, commands.get(1).getResult());
assertEquals(
"[refs/heads/master, refs/heads/masters]",
refs.keySet().toString());
assertEquals(B.getId(), refs.get("refs/heads/master").getObjectId());
assertEquals(A.getId(), refs.get("refs/heads/masters").getObjectId());
}
@Test
public void testBatchRefUpdate_NonFastForwardDoesNotDoExpensiveMergeCheck()
throws IOException {
update("refs/heads/master", B);
ObjectId txnId = getTxnCommitted();
List<ReceiveCommand> commands = Arrays.asList(
command(B, A, "refs/heads/master"));
BatchRefUpdate batchUpdate = refdb.newBatchUpdate();
batchUpdate.setAllowNonFastForwards(true);
batchUpdate.addCommand(commands);
batchUpdate.execute(new RevWalk(repo) {
@Override
public boolean isMergedInto(RevCommit base, RevCommit tip) {
fail("isMergedInto() should not be called");
return false;
}
}, NullProgressMonitor.INSTANCE);
assertNotEquals(txnId, getTxnCommitted());
Map<String, Ref> refs = refdb.getRefs(ALL);
assertEquals(OK, commands.get(0).getResult());
assertEquals(A.getId(), refs.get("refs/heads/master").getObjectId());
}
@Test
public void testBatchRefUpdate_ConflictCausesAbort() throws IOException {
update("refs/heads/master", A);
update("refs/heads/masters", B);
ObjectId txnId = getTxnCommitted();
List<ReceiveCommand> commands = Arrays.asList(
command(A, B, "refs/heads/master"),
command(null, A, "refs/heads/master/x"),
command(null, A, "refs/heads"));
BatchRefUpdate batchUpdate = refdb.newBatchUpdate();
batchUpdate.setAllowNonFastForwards(true);
batchUpdate.addCommand(commands);
batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE);
assertEquals(txnId, getTxnCommitted());
assertEquals(LOCK_FAILURE, commands.get(0).getResult());
assertEquals(REJECTED_OTHER_REASON, commands.get(1).getResult());
assertEquals(JGitText.get().transactionAborted,
commands.get(1).getMessage());
assertEquals(REJECTED_OTHER_REASON, commands.get(2).getResult());
assertEquals(JGitText.get().transactionAborted,
commands.get(2).getMessage());
}
@Test
public void testBatchRefUpdate_NoConflictIfDeleted() throws IOException {
update("refs/heads/master", A);
update("refs/heads/masters", B);
ObjectId txnId = getTxnCommitted();
List<ReceiveCommand> commands = Arrays.asList(
command(A, B, "refs/heads/master"),
command(null, A, "refs/heads/masters/x"),
command(B, null, "refs/heads/masters"));
BatchRefUpdate batchUpdate = refdb.newBatchUpdate();
batchUpdate.setAllowNonFastForwards(true);
batchUpdate.addCommand(commands);
batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE);
assertNotEquals(txnId, getTxnCommitted());
assertEquals(OK, commands.get(0).getResult());
assertEquals(OK, commands.get(1).getResult());
assertEquals(OK, commands.get(2).getResult());
Map<String, Ref> refs = refdb.getRefs(ALL);
assertEquals(
"[refs/heads/master, refs/heads/masters/x]",
refs.keySet().toString());
assertEquals(A.getId(), refs.get("refs/heads/masters/x").getObjectId());
}
private ObjectId getTxnCommitted() throws IOException {
Ref r = bootstrap.exactRef(refdb.getTxnCommitted());
if (r != null && r.getObjectId() != null) {
return r.getObjectId();
}
return ObjectId.zeroId();
}
private static ReceiveCommand command(AnyObjectId a, AnyObjectId b,
String name) {
return new ReceiveCommand(
a != null ? a.copy() : ObjectId.zeroId(),
b != null ? b.copy() : ObjectId.zeroId(),
name);
}
private void symref(final String name, final String dst)
throws IOException {
commit(new Function() {
@Override
public boolean apply(ObjectReader reader, RefTree tree)
throws IOException {
Ref old = tree.exactRef(reader, name);
Command n = new Command(
old,
new SymbolicRef(
name,
new ObjectIdRef.Unpeeled(Ref.Storage.NEW, dst, null)));
return tree.apply(Collections.singleton(n));
}
});
}
private void update(final String name, final ObjectId id)
throws IOException {
commit(new Function() {
@Override
public boolean apply(ObjectReader reader, RefTree tree)
throws IOException {
Ref old = tree.exactRef(reader, name);
Command n;
try (RevWalk rw = new RevWalk(repo)) {
n = new Command(old, Command.toRef(rw, id, name, true));
}
return tree.apply(Collections.singleton(n));
}
});
}
interface Function {
boolean apply(ObjectReader reader, RefTree tree) throws IOException;
}
private void commit(Function fun) throws IOException {
try (ObjectReader reader = repo.newObjectReader();
ObjectInserter inserter = repo.newObjectInserter();
RevWalk rw = new RevWalk(reader)) {
RefUpdate u = bootstrap.newUpdate(refdb.getTxnCommitted(), false);
CommitBuilder cb = new CommitBuilder();
testRepo.setAuthorAndCommitter(cb);
Ref ref = bootstrap.exactRef(refdb.getTxnCommitted());
RefTree tree;
if (ref != null && ref.getObjectId() != null) {
tree = RefTree.read(reader, rw.parseTree(ref.getObjectId()));
cb.setParentId(ref.getObjectId());
u.setExpectedOldObjectId(ref.getObjectId());
} else {
tree = RefTree.newEmptyTree();
u.setExpectedOldObjectId(ObjectId.zeroId());
}
assertTrue(fun.apply(reader, tree));
cb.setTreeId(tree.writeTree(inserter));
u.setNewObjectId(inserter.insert(cb));
inserter.flush();
switch (u.update(rw)) {
case NEW:
case FAST_FORWARD:
break;
default:
fail("Expected " + u.getName() + " to update");
}
}
}
private class InMemRefTreeRepo extends InMemoryRepository {
private final RefTreeDatabase refs;
InMemRefTreeRepo(DfsRepositoryDescription repoDesc) {
super(repoDesc);
refs = new RefTreeDatabase(this, super.getRefDatabase(),
"refs/txn/committed");
RefTreeDatabaseTest.this.refdb = refs;
}
public RefDatabase getRefDatabase() {
return refs;
}
}
}

303
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeTest.java

@ -0,0 +1,303 @@
/*
* Copyright (C) 2016, 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.internal.storage.reftree;
import static org.eclipse.jgit.lib.Constants.HEAD;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
import static org.eclipse.jgit.lib.Ref.Storage.LOOSE;
import static org.eclipse.jgit.lib.Ref.Storage.NEW;
import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE;
import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import org.eclipse.jgit.errors.MissingObjectException;
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.junit.TestRepository;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.SymbolicRef;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.junit.Before;
import org.junit.Test;
public class RefTreeTest {
private static final String R_MASTER = R_HEADS + "master";
private InMemoryRepository repo;
private TestRepository<InMemoryRepository> git;
@Before
public void setUp() throws IOException {
repo = new InMemoryRepository(new DfsRepositoryDescription("RefTree"));
git = new TestRepository<>(repo);
}
@Test
public void testEmptyTree() throws IOException {
RefTree tree = RefTree.newEmptyTree();
try (ObjectReader reader = repo.newObjectReader()) {
assertNull(HEAD, tree.exactRef(reader, HEAD));
assertNull("master", tree.exactRef(reader, R_MASTER));
}
}
@Test
public void testApplyThenReadMaster() throws Exception {
RefTree tree = RefTree.newEmptyTree();
RevBlob id = git.blob("A");
Command cmd = new Command(null, ref(R_MASTER, id));
assertTrue(tree.apply(Collections.singletonList(cmd)));
assertSame(NOT_ATTEMPTED, cmd.getResult());
try (ObjectReader reader = repo.newObjectReader()) {
Ref m = tree.exactRef(reader, R_MASTER);
assertNotNull(R_MASTER, m);
assertEquals(R_MASTER, m.getName());
assertEquals(id, m.getObjectId());
assertTrue("peeled", m.isPeeled());
}
}
@Test
public void testUpdateMaster() throws Exception {
RefTree tree = RefTree.newEmptyTree();
RevBlob id1 = git.blob("A");
Command cmd1 = new Command(null, ref(R_MASTER, id1));
assertTrue(tree.apply(Collections.singletonList(cmd1)));
assertSame(NOT_ATTEMPTED, cmd1.getResult());
RevBlob id2 = git.blob("B");
Command cmd2 = new Command(ref(R_MASTER, id1), ref(R_MASTER, id2));
assertTrue(tree.apply(Collections.singletonList(cmd2)));
assertSame(NOT_ATTEMPTED, cmd2.getResult());
try (ObjectReader reader = repo.newObjectReader()) {
Ref m = tree.exactRef(reader, R_MASTER);
assertNotNull(R_MASTER, m);
assertEquals(R_MASTER, m.getName());
assertEquals(id2, m.getObjectId());
assertTrue("peeled", m.isPeeled());
}
}
@Test
public void testHeadSymref() throws Exception {
RefTree tree = RefTree.newEmptyTree();
RevBlob id = git.blob("A");
Command cmd1 = new Command(null, ref(R_MASTER, id));
Command cmd2 = new Command(null, symref(HEAD, R_MASTER));
assertTrue(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 })));
assertSame(NOT_ATTEMPTED, cmd1.getResult());
assertSame(NOT_ATTEMPTED, cmd2.getResult());
try (ObjectReader reader = repo.newObjectReader()) {
Ref m = tree.exactRef(reader, HEAD);
assertNotNull(HEAD, m);
assertEquals(HEAD, m.getName());
assertTrue("symbolic", m.isSymbolic());
assertNotNull(m.getTarget());
assertEquals(R_MASTER, m.getTarget().getName());
assertEquals(id, m.getTarget().getObjectId());
}
// Writing flushes some buffers, re-read from blob.
ObjectId newId = write(tree);
try (ObjectReader reader = repo.newObjectReader();
RevWalk rw = new RevWalk(reader)) {
tree = RefTree.read(reader, rw.parseTree(newId));
Ref m = tree.exactRef(reader, HEAD);
assertEquals(R_MASTER, m.getTarget().getName());
}
}
@Test
public void testTagIsPeeled() throws Exception {
String name = "v1.0";
RefTree tree = RefTree.newEmptyTree();
RevBlob id = git.blob("A");
RevTag tag = git.tag(name, id);
String ref = R_TAGS + name;
Command cmd = create(ref, tag);
assertTrue(tree.apply(Collections.singletonList(cmd)));
assertSame(NOT_ATTEMPTED, cmd.getResult());
try (ObjectReader reader = repo.newObjectReader()) {
Ref m = tree.exactRef(reader, ref);
assertNotNull(ref, m);
assertEquals(ref, m.getName());
assertEquals(tag, m.getObjectId());
assertTrue("peeled", m.isPeeled());
assertEquals(id, m.getPeeledObjectId());
}
}
@Test
public void testApplyAlreadyExists() throws Exception {
RefTree tree = RefTree.newEmptyTree();
RevBlob a = git.blob("A");
Command cmd = new Command(null, ref(R_MASTER, a));
assertTrue(tree.apply(Collections.singletonList(cmd)));
ObjectId treeId = write(tree);
RevBlob b = git.blob("B");
Command cmd1 = create(R_MASTER, b);
Command cmd2 = create(R_MASTER, b);
assertFalse(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 })));
assertSame(LOCK_FAILURE, cmd1.getResult());
assertSame(REJECTED_OTHER_REASON, cmd2.getResult());
assertEquals(JGitText.get().transactionAborted, cmd2.getMessage());
assertEquals(treeId, write(tree));
}
@Test
public void testApplyWrongOldId() throws Exception {
RefTree tree = RefTree.newEmptyTree();
RevBlob a = git.blob("A");
Command cmd = new Command(null, ref(R_MASTER, a));
assertTrue(tree.apply(Collections.singletonList(cmd)));
ObjectId treeId = write(tree);
RevBlob b = git.blob("B");
RevBlob c = git.blob("C");
Command cmd1 = update(R_MASTER, b, c);
Command cmd2 = create(R_MASTER, b);
assertFalse(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 })));
assertSame(LOCK_FAILURE, cmd1.getResult());
assertSame(REJECTED_OTHER_REASON, cmd2.getResult());
assertEquals(JGitText.get().transactionAborted, cmd2.getMessage());
assertEquals(treeId, write(tree));
}
@Test
public void testApplyWrongOldIdButAlreadyCurrentIsNoOp() throws Exception {
RefTree tree = RefTree.newEmptyTree();
RevBlob a = git.blob("A");
Command cmd = new Command(null, ref(R_MASTER, a));
assertTrue(tree.apply(Collections.singletonList(cmd)));
ObjectId treeId = write(tree);
RevBlob b = git.blob("B");
cmd = update(R_MASTER, b, a);
assertTrue(tree.apply(Collections.singletonList(cmd)));
assertEquals(treeId, write(tree));
}
@Test
public void testApplyCannotCreateSubdirectory() throws Exception {
RefTree tree = RefTree.newEmptyTree();
RevBlob a = git.blob("A");
Command cmd = new Command(null, ref(R_MASTER, a));
assertTrue(tree.apply(Collections.singletonList(cmd)));
ObjectId treeId = write(tree);
RevBlob b = git.blob("B");
Command cmd1 = create(R_MASTER + "/fail", b);
assertFalse(tree.apply(Collections.singletonList(cmd1)));
assertSame(LOCK_FAILURE, cmd1.getResult());
assertEquals(treeId, write(tree));
}
@Test
public void testApplyCannotCreateParentRef() throws Exception {
RefTree tree = RefTree.newEmptyTree();
RevBlob a = git.blob("A");
Command cmd = new Command(null, ref(R_MASTER, a));
assertTrue(tree.apply(Collections.singletonList(cmd)));
ObjectId treeId = write(tree);
RevBlob b = git.blob("B");
Command cmd1 = create("refs/heads", b);
assertFalse(tree.apply(Collections.singletonList(cmd1)));
assertSame(LOCK_FAILURE, cmd1.getResult());
assertEquals(treeId, write(tree));
}
private static Ref ref(String name, ObjectId id) {
return new ObjectIdRef.PeeledNonTag(LOOSE, name, id);
}
private static Ref symref(String name, String dest) {
Ref d = new ObjectIdRef.PeeledNonTag(NEW, dest, null);
return new SymbolicRef(name, d);
}
private Command create(String name, ObjectId id)
throws MissingObjectException, IOException {
return update(name, ObjectId.zeroId(), id);
}
private Command update(String name, ObjectId oldId, ObjectId newId)
throws MissingObjectException, IOException {
try (RevWalk rw = new RevWalk(repo)) {
return new Command(rw, new ReceiveCommand(oldId, newId, name));
}
}
private ObjectId write(RefTree tree) throws IOException {
try (ObjectInserter ins = repo.newObjectInserter()) {
ObjectId id = tree.writeTree(ins);
ins.flush();
return id;
}
}
}

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

@ -1084,7 +1084,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
assertWorkDir(mkmap(linkName, "a", fname, "a")); assertWorkDir(mkmap(linkName, "a", fname, "a"));
Status st = git.status().call(); Status st = git.status().call();
assertFalse(st.isClean()); assertTrue(st.isClean());
} }
@Test @Test
@ -1213,9 +1213,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
assertWorkDir(mkmap(fname, "a")); assertWorkDir(mkmap(fname, "a"));
Status st = git.status().call(); Status st = git.status().call();
assertFalse(st.isClean()); assertTrue(st.isClean());
assertEquals(1, st.getAdded().size());
assertTrue(st.getAdded().contains(fname + "/dir/file1"));
} }
@Test @Test

91
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java

@ -99,8 +99,7 @@ public class IndexDiffTest extends RepositoryTestCase {
public void testAdded() throws IOException { public void testAdded() throws IOException {
writeTrashFile("file1", "file1"); writeTrashFile("file1", "file1");
writeTrashFile("dir/subfile", "dir/subfile"); writeTrashFile("dir/subfile", "dir/subfile");
Tree tree = new Tree(db); ObjectId tree = insertTree(new TreeFormatter());
tree.setId(insertTree(tree));
DirCache index = db.lockDirCache(); DirCache index = db.lockDirCache();
DirCacheEditor editor = index.editor(); DirCacheEditor editor = index.editor();
@ -108,7 +107,7 @@ public class IndexDiffTest extends RepositoryTestCase {
editor.add(add(db, trash, "dir/subfile")); editor.add(add(db, trash, "dir/subfile"));
editor.commit(); editor.commit();
FileTreeIterator iterator = new FileTreeIterator(db); FileTreeIterator iterator = new FileTreeIterator(db);
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); IndexDiff diff = new IndexDiff(db, tree, iterator);
diff.diff(); diff.diff();
assertEquals(2, diff.getAdded().size()); assertEquals(2, diff.getAdded().size());
assertTrue(diff.getAdded().contains("file1")); assertTrue(diff.getAdded().contains("file1"));
@ -124,18 +123,16 @@ public class IndexDiffTest extends RepositoryTestCase {
writeTrashFile("file2", "file2"); writeTrashFile("file2", "file2");
writeTrashFile("dir/file3", "dir/file3"); writeTrashFile("dir/file3", "dir/file3");
Tree tree = new Tree(db); TreeFormatter dir = new TreeFormatter();
tree.addFile("file2"); dir.append("file3", FileMode.REGULAR_FILE, ObjectId.fromString("873fb8d667d05436d728c52b1d7a09528e6eb59b"));
tree.addFile("dir/file3");
assertEquals(2, tree.memberCount()); TreeFormatter tree = new TreeFormatter();
tree.findBlobMember("file2").setId(ObjectId.fromString("30d67d4672d5c05833b7192cc77a79eaafb5c7ad")); tree.append("file2", FileMode.REGULAR_FILE, ObjectId.fromString("30d67d4672d5c05833b7192cc77a79eaafb5c7ad"));
Tree tree2 = (Tree) tree.findTreeMember("dir"); tree.append("dir", FileMode.TREE, insertTree(dir));
tree2.findBlobMember("file3").setId(ObjectId.fromString("873fb8d667d05436d728c52b1d7a09528e6eb59b")); ObjectId treeId = insertTree(tree);
tree2.setId(insertTree(tree2));
tree.setId(insertTree(tree));
FileTreeIterator iterator = new FileTreeIterator(db); FileTreeIterator iterator = new FileTreeIterator(db);
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); IndexDiff diff = new IndexDiff(db, treeId, iterator);
diff.diff(); diff.diff();
assertEquals(2, diff.getRemoved().size()); assertEquals(2, diff.getRemoved().size());
assertTrue(diff.getRemoved().contains("file2")); assertTrue(diff.getRemoved().contains("file2"));
@ -157,16 +154,16 @@ public class IndexDiffTest extends RepositoryTestCase {
writeTrashFile("dir/file3", "changed"); writeTrashFile("dir/file3", "changed");
Tree tree = new Tree(db); TreeFormatter dir = new TreeFormatter();
tree.addFile("file2").setId(ObjectId.fromString("0123456789012345678901234567890123456789")); dir.append("file3", FileMode.REGULAR_FILE, ObjectId.fromString("0123456789012345678901234567890123456789"));
tree.addFile("dir/file3").setId(ObjectId.fromString("0123456789012345678901234567890123456789"));
assertEquals(2, tree.memberCount()); TreeFormatter tree = new TreeFormatter();
tree.append("dir", FileMode.TREE, insertTree(dir));
tree.append("file2", FileMode.REGULAR_FILE, ObjectId.fromString("0123456789012345678901234567890123456789"));
ObjectId treeId = insertTree(tree);
Tree tree2 = (Tree) tree.findTreeMember("dir");
tree2.setId(insertTree(tree2));
tree.setId(insertTree(tree));
FileTreeIterator iterator = new FileTreeIterator(db); FileTreeIterator iterator = new FileTreeIterator(db);
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); IndexDiff diff = new IndexDiff(db, treeId, iterator);
diff.diff(); diff.diff();
assertEquals(2, diff.getChanged().size()); assertEquals(2, diff.getChanged().size());
assertTrue(diff.getChanged().contains("file2")); assertTrue(diff.getChanged().contains("file2"));
@ -314,17 +311,16 @@ public class IndexDiffTest extends RepositoryTestCase {
git.add().addFilepattern("a=c").call(); git.add().addFilepattern("a=c").call();
git.add().addFilepattern("a=d").call(); git.add().addFilepattern("a=d").call();
Tree tree = new Tree(db); TreeFormatter tree = new TreeFormatter();
// got the hash id'd from the data using echo -n a.b|git hash-object -t blob --stdin // got the hash id'd from the data using echo -n a.b|git hash-object -t blob --stdin
tree.addFile("a.b").setId(ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851")); tree.append("a.b", FileMode.REGULAR_FILE, ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851"));
tree.addFile("a.c").setId(ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca")); tree.append("a.c", FileMode.REGULAR_FILE, ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca"));
tree.addFile("a=c").setId(ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714")); tree.append("a=c", FileMode.REGULAR_FILE, ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714"));
tree.addFile("a=d").setId(ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2")); tree.append("a=d", FileMode.REGULAR_FILE, ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2"));
ObjectId treeId = insertTree(tree);
tree.setId(insertTree(tree));
FileTreeIterator iterator = new FileTreeIterator(db); FileTreeIterator iterator = new FileTreeIterator(db);
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); IndexDiff diff = new IndexDiff(db, treeId, iterator);
diff.diff(); diff.diff();
assertEquals(0, diff.getChanged().size()); assertEquals(0, diff.getChanged().size());
assertEquals(0, diff.getAdded().size()); assertEquals(0, diff.getAdded().size());
@ -356,24 +352,27 @@ public class IndexDiffTest extends RepositoryTestCase {
.addFilepattern("a/c").addFilepattern("a=c") .addFilepattern("a/c").addFilepattern("a=c")
.addFilepattern("a=d").call(); .addFilepattern("a=d").call();
Tree tree = new Tree(db);
// got the hash id'd from the data using echo -n a.b|git hash-object -t blob --stdin // got the hash id'd from the data using echo -n a.b|git hash-object -t blob --stdin
tree.addFile("a.b").setId(ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851")); TreeFormatter bb = new TreeFormatter();
tree.addFile("a.c").setId(ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca")); bb.append("b", FileMode.REGULAR_FILE, ObjectId.fromString("8d840bd4e2f3a48ff417c8e927d94996849933fd"));
tree.addFile("a/b.b/b").setId(ObjectId.fromString("8d840bd4e2f3a48ff417c8e927d94996849933fd"));
tree.addFile("a/b").setId(ObjectId.fromString("db89c972fc57862eae378f45b74aca228037d415")); TreeFormatter a = new TreeFormatter();
tree.addFile("a/c").setId(ObjectId.fromString("52ad142a008aeb39694bafff8e8f1be75ed7f007")); a.append("b", FileMode.REGULAR_FILE, ObjectId
tree.addFile("a=c").setId(ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714")); .fromString("db89c972fc57862eae378f45b74aca228037d415"));
tree.addFile("a=d").setId(ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2")); a.append("b.b", FileMode.TREE, insertTree(bb));
a.append("c", FileMode.REGULAR_FILE, ObjectId.fromString("52ad142a008aeb39694bafff8e8f1be75ed7f007"));
Tree tree3 = (Tree) tree.findTreeMember("a/b.b");
tree3.setId(insertTree(tree3)); TreeFormatter tree = new TreeFormatter();
Tree tree2 = (Tree) tree.findTreeMember("a"); tree.append("a.b", FileMode.REGULAR_FILE, ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851"));
tree2.setId(insertTree(tree2)); tree.append("a.c", FileMode.REGULAR_FILE, ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca"));
tree.setId(insertTree(tree)); tree.append("a", FileMode.TREE, insertTree(a));
tree.append("a=c", FileMode.REGULAR_FILE, ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714"));
tree.append("a=d", FileMode.REGULAR_FILE, ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2"));
ObjectId treeId = insertTree(tree);
FileTreeIterator iterator = new FileTreeIterator(db); FileTreeIterator iterator = new FileTreeIterator(db);
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); IndexDiff diff = new IndexDiff(db, treeId, iterator);
diff.diff(); diff.diff();
assertEquals(0, diff.getChanged().size()); assertEquals(0, diff.getChanged().size());
assertEquals(0, diff.getAdded().size()); assertEquals(0, diff.getAdded().size());
@ -383,9 +382,9 @@ public class IndexDiffTest extends RepositoryTestCase {
assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders()); assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders());
} }
private ObjectId insertTree(Tree tree) throws IOException { private ObjectId insertTree(TreeFormatter tree) throws IOException {
try (ObjectInserter oi = db.newObjectInserter()) { try (ObjectInserter oi = db.newObjectInserter()) {
ObjectId id = oi.insert(Constants.OBJ_TREE, tree.format()); ObjectId id = oi.insert(tree);
oi.flush(); oi.flush();
return id; return id;
} }

1393
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java

File diff suppressed because it is too large Load Diff

319
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_TreeTest.java

@ -1,319 +0,0 @@
/*
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.lib;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
import org.junit.Test;
@SuppressWarnings("deprecation")
public class T0002_TreeTest extends SampleDataRepositoryTestCase {
private static final ObjectId SOME_FAKE_ID = ObjectId.fromString(
"0123456789abcdef0123456789abcdef01234567");
private static int compareNamesUsingSpecialCompare(String a, String b)
throws UnsupportedEncodingException {
char lasta = '\0';
byte[] abytes;
if (a.length() > 0 && a.charAt(a.length()-1) == '/') {
lasta = '/';
a = a.substring(0, a.length() - 1);
}
abytes = a.getBytes("ISO-8859-1");
char lastb = '\0';
byte[] bbytes;
if (b.length() > 0 && b.charAt(b.length()-1) == '/') {
lastb = '/';
b = b.substring(0, b.length() - 1);
}
bbytes = b.getBytes("ISO-8859-1");
return Tree.compareNames(abytes, bbytes, lasta, lastb);
}
@Test
public void test000_sort_01() throws UnsupportedEncodingException {
assertEquals(0, compareNamesUsingSpecialCompare("a","a"));
}
@Test
public void test000_sort_02() throws UnsupportedEncodingException {
assertEquals(-1, compareNamesUsingSpecialCompare("a","b"));
assertEquals(1, compareNamesUsingSpecialCompare("b","a"));
}
@Test
public void test000_sort_03() throws UnsupportedEncodingException {
assertEquals(1, compareNamesUsingSpecialCompare("a:","a"));
assertEquals(1, compareNamesUsingSpecialCompare("a/","a"));
assertEquals(-1, compareNamesUsingSpecialCompare("a","a/"));
assertEquals(-1, compareNamesUsingSpecialCompare("a","a:"));
assertEquals(1, compareNamesUsingSpecialCompare("a:","a/"));
assertEquals(-1, compareNamesUsingSpecialCompare("a/","a:"));
}
@Test
public void test000_sort_04() throws UnsupportedEncodingException {
assertEquals(-1, compareNamesUsingSpecialCompare("a.a","a/a"));
assertEquals(1, compareNamesUsingSpecialCompare("a/a","a.a"));
}
@Test
public void test000_sort_05() throws UnsupportedEncodingException {
assertEquals(-1, compareNamesUsingSpecialCompare("a.","a/"));
assertEquals(1, compareNamesUsingSpecialCompare("a/","a."));
}
@Test
public void test001_createEmpty() throws IOException {
final Tree t = new Tree(db);
assertTrue("isLoaded", t.isLoaded());
assertTrue("isModified", t.isModified());
assertTrue("no parent", t.getParent() == null);
assertTrue("isRoot", t.isRoot());
assertTrue("no name", t.getName() == null);
assertTrue("no nameUTF8", t.getNameUTF8() == null);
assertTrue("has entries array", t.members() != null);
assertEquals("entries is empty", 0, t.members().length);
assertEquals("full name is empty", "", t.getFullName());
assertTrue("no id", t.getId() == null);
assertTrue("database is r", t.getRepository() == db);
assertTrue("no foo child", t.findTreeMember("foo") == null);
assertTrue("no foo child", t.findBlobMember("foo") == null);
}
@Test
public void test002_addFile() throws IOException {
final Tree t = new Tree(db);
t.setId(SOME_FAKE_ID);
assertTrue("has id", t.getId() != null);
assertFalse("not modified", t.isModified());
final String n = "bob";
final FileTreeEntry f = t.addFile(n);
assertNotNull("have file", f);
assertEquals("name matches", n, f.getName());
assertEquals("name matches", f.getName(), new String(f.getNameUTF8(),
"UTF-8"));
assertEquals("full name matches", n, f.getFullName());
assertTrue("no id", f.getId() == null);
assertTrue("is modified", t.isModified());
assertTrue("has no id", t.getId() == null);
assertTrue("found bob", t.findBlobMember(f.getName()) == f);
final TreeEntry[] i = t.members();
assertNotNull("members array not null", i);
assertTrue("iterator is not empty", i != null && i.length > 0);
assertTrue("iterator returns file", i != null && i[0] == f);
assertTrue("iterator is empty", i != null && i.length == 1);
}
@Test
public void test004_addTree() throws IOException {
final Tree t = new Tree(db);
t.setId(SOME_FAKE_ID);
assertTrue("has id", t.getId() != null);
assertFalse("not modified", t.isModified());
final String n = "bob";
final Tree f = t.addTree(n);
assertNotNull("have tree", f);
assertEquals("name matches", n, f.getName());
assertEquals("name matches", f.getName(), new String(f.getNameUTF8(),
"UTF-8"));
assertEquals("full name matches", n, f.getFullName());
assertTrue("no id", f.getId() == null);
assertTrue("parent matches", f.getParent() == t);
assertTrue("repository matches", f.getRepository() == db);
assertTrue("isLoaded", f.isLoaded());
assertFalse("has items", f.members().length > 0);
assertFalse("is root", f.isRoot());
assertTrue("parent is modified", t.isModified());
assertTrue("parent has no id", t.getId() == null);
assertTrue("found bob child", t.findTreeMember(f.getName()) == f);
final TreeEntry[] i = t.members();
assertTrue("iterator is not empty", i.length > 0);
assertTrue("iterator returns file", i[0] == f);
assertEquals("iterator is empty", 1, i.length);
}
@Test
public void test005_addRecursiveFile() throws IOException {
final Tree t = new Tree(db);
final FileTreeEntry f = t.addFile("a/b/c");
assertNotNull("created f", f);
assertEquals("c", f.getName());
assertEquals("b", f.getParent().getName());
assertEquals("a", f.getParent().getParent().getName());
assertTrue("t is great-grandparent", t == f.getParent().getParent()
.getParent());
}
@Test
public void test005_addRecursiveTree() throws IOException {
final Tree t = new Tree(db);
final Tree f = t.addTree("a/b/c");
assertNotNull("created f", f);
assertEquals("c", f.getName());
assertEquals("b", f.getParent().getName());
assertEquals("a", f.getParent().getParent().getName());
assertTrue("t is great-grandparent", t == f.getParent().getParent()
.getParent());
}
@Test
public void test006_addDeepTree() throws IOException {
final Tree t = new Tree(db);
final Tree e = t.addTree("e");
assertNotNull("have e", e);
assertTrue("e.parent == t", e.getParent() == t);
final Tree f = t.addTree("f");
assertNotNull("have f", f);
assertTrue("f.parent == t", f.getParent() == t);
final Tree g = f.addTree("g");
assertNotNull("have g", g);
assertTrue("g.parent == f", g.getParent() == f);
final Tree h = g.addTree("h");
assertNotNull("have h", h);
assertTrue("h.parent = g", h.getParent() == g);
h.setId(SOME_FAKE_ID);
assertTrue("h not modified", !h.isModified());
g.setId(SOME_FAKE_ID);
assertTrue("g not modified", !g.isModified());
f.setId(SOME_FAKE_ID);
assertTrue("f not modified", !f.isModified());
e.setId(SOME_FAKE_ID);
assertTrue("e not modified", !e.isModified());
t.setId(SOME_FAKE_ID);
assertTrue("t not modified.", !t.isModified());
assertEquals("full path of h ok", "f/g/h", h.getFullName());
assertTrue("Can find h", t.findTreeMember(h.getFullName()) == h);
assertTrue("Can't find f/z", t.findBlobMember("f/z") == null);
assertTrue("Can't find y/z", t.findBlobMember("y/z") == null);
final FileTreeEntry i = h.addFile("i");
assertNotNull(i);
assertEquals("full path of i ok", "f/g/h/i", i.getFullName());
assertTrue("Can find i", t.findBlobMember(i.getFullName()) == i);
assertTrue("h modified", h.isModified());
assertTrue("g modified", g.isModified());
assertTrue("f modified", f.isModified());
assertTrue("e not modified", !e.isModified());
assertTrue("t modified", t.isModified());
assertTrue("h no id", h.getId() == null);
assertTrue("g no id", g.getId() == null);
assertTrue("f no id", f.getId() == null);
assertTrue("e has id", e.getId() != null);
assertTrue("t no id", t.getId() == null);
}
@Test
public void test007_manyFileLookup() throws IOException {
final Tree t = new Tree(db);
final List<FileTreeEntry> files = new ArrayList<FileTreeEntry>(26 * 26);
for (char level1 = 'a'; level1 <= 'z'; level1++) {
for (char level2 = 'a'; level2 <= 'z'; level2++) {
final String n = "." + level1 + level2 + "9";
final FileTreeEntry f = t.addFile(n);
assertNotNull("File " + n + " added.", f);
assertEquals(n, f.getName());
files.add(f);
}
}
assertEquals(files.size(), t.memberCount());
final TreeEntry[] ents = t.members();
assertNotNull(ents);
assertEquals(files.size(), ents.length);
for (int k = 0; k < ents.length; k++) {
assertTrue("File " + files.get(k).getName()
+ " is at " + k + ".", files.get(k) == ents[k]);
}
}
@Test
public void test008_SubtreeInternalSorting() throws IOException {
final Tree t = new Tree(db);
final FileTreeEntry e0 = t.addFile("a-b");
final FileTreeEntry e1 = t.addFile("a-");
final FileTreeEntry e2 = t.addFile("a=b");
final Tree e3 = t.addTree("a");
final FileTreeEntry e4 = t.addFile("a=");
final TreeEntry[] ents = t.members();
assertSame(e1, ents[0]);
assertSame(e0, ents[1]);
assertSame(e3, ents[2]);
assertSame(e4, ents[3]);
assertSame(e2, ents[4]);
}
@Test
public void test009_SymlinkAndGitlink() throws IOException {
final Tree symlinkTree = mapTree("symlink");
assertTrue("Symlink entry exists", symlinkTree.existsBlob("symlink.txt"));
final Tree gitlinkTree = mapTree("gitlink");
assertTrue("Gitlink entry exists", gitlinkTree.existsBlob("submodule"));
}
private Tree mapTree(String name) throws IOException {
ObjectId id = db.resolve(name + "^{tree}");
return new Tree(db, id, db.open(id).getCachedBytes());
}
}

41
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java

@ -47,11 +47,10 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.FileTreeEntry;
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.Tree; import org.eclipse.jgit.lib.TreeFormatter;
import org.junit.Test; import org.junit.Test;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@ -220,28 +219,24 @@ public class ObjectWalkTest extends RevWalkTestCase {
.fromString("abbbfafe3129f85747aba7bfac992af77134c607"); .fromString("abbbfafe3129f85747aba7bfac992af77134c607");
final RevTree tree_root, tree_A, tree_AB; final RevTree tree_root, tree_A, tree_AB;
final RevCommit b; final RevCommit b;
{ try (ObjectInserter inserter = db.newObjectInserter()) {
Tree root = new Tree(db); ObjectId empty = inserter.insert(new TreeFormatter());
Tree A = root.addTree("A");
FileTreeEntry B = root.addFile("B"); TreeFormatter A = new TreeFormatter();
B.setId(bId); A.append("A", FileMode.TREE, empty);
A.append("B", FileMode.TREE, empty);
Tree A_A = A.addTree("A"); ObjectId idA = inserter.insert(A);
Tree A_B = A.addTree("B");
TreeFormatter root = new TreeFormatter();
try (final ObjectInserter inserter = db.newObjectInserter()) { root.append("A", FileMode.TREE, idA);
A_A.setId(inserter.insert(Constants.OBJ_TREE, A_A.format())); root.append("B", FileMode.REGULAR_FILE, bId);
A_B.setId(inserter.insert(Constants.OBJ_TREE, A_B.format())); ObjectId idRoot = inserter.insert(root);
A.setId(inserter.insert(Constants.OBJ_TREE, A.format()));
root.setId(inserter.insert(Constants.OBJ_TREE, root.format()));
inserter.flush(); inserter.flush();
}
tree_root = rw.parseTree(root.getId()); tree_root = objw.parseTree(idRoot);
tree_A = rw.parseTree(A.getId()); tree_A = objw.parseTree(idA);
tree_AB = rw.parseTree(A_A.getId()); tree_AB = objw.parseTree(empty);
assertSame(tree_AB, rw.parseTree(A_B.getId())); b = commit(tree_root);
b = commit(rw.parseTree(root.getId()));
} }
markStart(b); markStart(b);

85
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java

@ -43,13 +43,18 @@
package org.eclipse.jgit.revwalk; package org.eclipse.jgit.revwalk;
import static java.nio.charset.StandardCharsets.UTF_8;
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.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.TimeZone; import java.util.TimeZone;
import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.RepositoryTestCase;
@ -303,6 +308,86 @@ public class RevCommitParseTest extends RepositoryTestCase {
assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage()); assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
} }
@Test
public void testParse_incorrectUtf8Name() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
.getBytes(UTF_8));
b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8));
b.write("committer co <c@example.com> 1218123390 -0500\n"
.getBytes(UTF_8));
b.write("encoding 'utf8'\n".getBytes(UTF_8));
b.write("\n".getBytes(UTF_8));
b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(UTF_8));
RevCommit c = new RevCommit(
id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
c.parseCanonical(new RevWalk(db), b.toByteArray());
assertEquals("'utf8'", c.getEncodingName());
assertEquals("Sm\u00f6rg\u00e5sbord\n", c.getFullMessage());
try {
c.getEncoding();
fail("Expected " + IllegalCharsetNameException.class);
} catch (IllegalCharsetNameException badName) {
assertEquals("'utf8'", badName.getMessage());
}
}
@Test
public void testParse_illegalEncoding() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8));
b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8));
b.write("committer co <c@example.com> 1218123390 -0500\n".getBytes(UTF_8));
b.write("encoding utf-8logoutputencoding=gbk\n".getBytes(UTF_8));
b.write("\n".getBytes(UTF_8));
b.write("message\n".getBytes(UTF_8));
RevCommit c = new RevCommit(
id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
c.parseCanonical(new RevWalk(db), b.toByteArray());
assertEquals("utf-8logoutputencoding=gbk", c.getEncodingName());
assertEquals("message\n", c.getFullMessage());
assertEquals("message", c.getShortMessage());
assertTrue(c.getFooterLines().isEmpty());
assertEquals("au", c.getAuthorIdent().getName());
try {
c.getEncoding();
fail("Expected " + IllegalCharsetNameException.class);
} catch (IllegalCharsetNameException badName) {
assertEquals("utf-8logoutputencoding=gbk", badName.getMessage());
}
}
@Test
public void testParse_unsupportedEncoding() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8));
b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8));
b.write("committer co <c@example.com> 1218123390 -0500\n".getBytes(UTF_8));
b.write("encoding it_IT.UTF8\n".getBytes(UTF_8));
b.write("\n".getBytes(UTF_8));
b.write("message\n".getBytes(UTF_8));
RevCommit c = new RevCommit(
id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
c.parseCanonical(new RevWalk(db), b.toByteArray());
assertEquals("it_IT.UTF8", c.getEncodingName());
assertEquals("message\n", c.getFullMessage());
assertEquals("message", c.getShortMessage());
assertTrue(c.getFooterLines().isEmpty());
assertEquals("au", c.getAuthorIdent().getName());
try {
c.getEncoding();
fail("Expected " + UnsupportedCharsetException.class);
} catch (UnsupportedCharsetException badName) {
assertEquals("it_IT.UTF8", badName.getMessage());
}
}
@Test @Test
public void testParse_NoMessage() throws Exception { public void testParse_NoMessage() throws Exception {
final String msg = ""; final String msg = "";

39
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java

@ -43,6 +43,7 @@
package org.eclipse.jgit.revwalk; package org.eclipse.jgit.revwalk;
import static java.nio.charset.StandardCharsets.UTF_8;
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.assertNull; import static org.junit.Assert.assertNull;
@ -361,6 +362,44 @@ public class RevTagParseTest extends RepositoryTestCase {
assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage()); assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
} }
@Test
public void testParse_illegalEncoding() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8));
b.write("type tree\n".getBytes(UTF_8));
b.write("tag v1.0\n".getBytes(UTF_8));
b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8));
b.write("encoding utf-8logoutputencoding=gbk\n".getBytes(UTF_8));
b.write("\n".getBytes(UTF_8));
b.write("message\n".getBytes(UTF_8));
RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
t.parseCanonical(new RevWalk(db), b.toByteArray());
assertEquals("t", t.getTaggerIdent().getName());
assertEquals("message", t.getShortMessage());
assertEquals("message\n", t.getFullMessage());
}
@Test
public void testParse_unsupportedEncoding() throws Exception {
ByteArrayOutputStream b = new ByteArrayOutputStream();
b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8));
b.write("type tree\n".getBytes(UTF_8));
b.write("tag v1.0\n".getBytes(UTF_8));
b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8));
b.write("encoding it_IT.UTF8\n".getBytes(UTF_8));
b.write("\n".getBytes(UTF_8));
b.write("message\n".getBytes(UTF_8));
RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
t.parseCanonical(new RevWalk(db), b.toByteArray());
assertEquals("t", t.getTaggerIdent().getName());
assertEquals("message", t.getShortMessage());
assertEquals("message\n", t.getFullMessage());
}
@Test @Test
public void testParse_NoMessage() throws Exception { public void testParse_NoMessage() throws Exception {
final String msg = ""; final String msg = "";

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

@ -112,12 +112,9 @@ public class AtomicPushTest {
public void pushNonAtomic() throws Exception { public void pushNonAtomic() throws Exception {
PushResult r; PushResult r;
server.setPerformsAtomicTransactions(false); server.setPerformsAtomicTransactions(false);
Transport tn = testProtocol.open(uri, client, "server"); try (Transport tn = testProtocol.open(uri, client, "server")) {
try {
tn.setPushAtomic(false); tn.setPushAtomic(false);
r = tn.push(NullProgressMonitor.INSTANCE, commands()); r = tn.push(NullProgressMonitor.INSTANCE, commands());
} finally {
tn.close();
} }
RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one"); RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
@ -131,12 +128,9 @@ public class AtomicPushTest {
@Test @Test
public void pushAtomicClientGivesUpEarly() throws Exception { public void pushAtomicClientGivesUpEarly() throws Exception {
PushResult r; PushResult r;
Transport tn = testProtocol.open(uri, client, "server"); try (Transport tn = testProtocol.open(uri, client, "server")) {
try {
tn.setPushAtomic(true); tn.setPushAtomic(true);
r = tn.push(NullProgressMonitor.INSTANCE, commands()); r = tn.push(NullProgressMonitor.INSTANCE, commands());
} finally {
tn.close();
} }
RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one"); RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
@ -167,8 +161,7 @@ public class AtomicPushTest {
ObjectId.zeroId())); ObjectId.zeroId()));
server.setPerformsAtomicTransactions(false); server.setPerformsAtomicTransactions(false);
Transport tn = testProtocol.open(uri, client, "server"); try (Transport tn = testProtocol.open(uri, client, "server")) {
try {
tn.setPushAtomic(true); tn.setPushAtomic(true);
tn.push(NullProgressMonitor.INSTANCE, cmds); tn.push(NullProgressMonitor.INSTANCE, cmds);
fail("did not throw TransportException"); fail("did not throw TransportException");
@ -176,8 +169,6 @@ public class AtomicPushTest {
assertEquals( assertEquals(
uri + ": " + JGitText.get().atomicPushNotSupported, uri + ": " + JGitText.get().atomicPushNotSupported,
e.getMessage()); e.getMessage());
} finally {
tn.close();
} }
} }

6
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java

@ -168,8 +168,10 @@ public class BundleWriterTest extends SampleDataRepositoryTestCase {
final ByteArrayInputStream in = new ByteArrayInputStream(bundle); final ByteArrayInputStream in = new ByteArrayInputStream(bundle);
final RefSpec rs = new RefSpec("refs/heads/*:refs/heads/*"); final RefSpec rs = new RefSpec("refs/heads/*:refs/heads/*");
final Set<RefSpec> refs = Collections.singleton(rs); final Set<RefSpec> refs = Collections.singleton(rs);
return new TransportBundleStream(newRepo, uri, in).fetch( try (TransportBundleStream transport = new TransportBundleStream(
NullProgressMonitor.INSTANCE, refs); newRepo, uri, in)) {
return transport.fetch(NullProgressMonitor.INSTANCE, refs);
}
} }
private byte[] makeBundle(final String name, private byte[] makeBundle(final String name,

18
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java

@ -116,12 +116,9 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas
// Clone from dst into src // Clone from dst into src
// //
Transport t = Transport.open(src, uriOf(dst)); try (Transport t = Transport.open(src, uriOf(dst))) {
try {
t.fetch(PM, Collections.singleton(new RefSpec("+refs/*:refs/*"))); t.fetch(PM, Collections.singleton(new RefSpec("+refs/*:refs/*")));
assertEquals(B, src.resolve(R_MASTER)); assertEquals(B, src.resolve(R_MASTER));
} finally {
t.close();
} }
// Now put private stuff into dst. // Now put private stuff into dst.
@ -144,7 +141,8 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas
@Test @Test
public void testFilterHidesPrivate() throws Exception { public void testFilterHidesPrivate() throws Exception {
Map<String, Ref> refs; Map<String, Ref> refs;
TransportLocal t = new TransportLocal(src, uriOf(dst), dst.getDirectory()) { try (TransportLocal t = new TransportLocal(src, uriOf(dst),
dst.getDirectory()) {
@Override @Override
ReceivePack createReceivePack(final Repository db) { ReceivePack createReceivePack(final Repository db) {
db.close(); db.close();
@ -154,16 +152,10 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas
rp.setAdvertiseRefsHook(new HidePrivateHook()); rp.setAdvertiseRefsHook(new HidePrivateHook());
return rp; return rp;
} }
}; }) {
try { try (PushConnection c = t.openPush()) {
PushConnection c = t.openPush();
try {
refs = c.getRefsMap(); refs = c.getRefsMap();
} finally {
c.close();
} }
} finally {
t.close();
} }
assertNotNull(refs); assertNotNull(refs);

50
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java

@ -340,6 +340,41 @@ public class RefSpecTest {
assertEquals("refs/heads/foo", c.getSource()); assertEquals("refs/heads/foo", c.getSource());
} }
@Test
public void testWildcardAfterText1() {
RefSpec a = new RefSpec("refs/heads/*/for-linus:refs/remotes/mine/*-blah");
assertTrue(a.isWildcard());
assertTrue(a.matchDestination("refs/remotes/mine/x-blah"));
assertTrue(a.matchDestination("refs/remotes/mine/foo-blah"));
assertTrue(a.matchDestination("refs/remotes/mine/foo/x-blah"));
assertFalse(a.matchDestination("refs/remotes/origin/foo/x-blah"));
RefSpec b = a.expandFromSource("refs/heads/foo/for-linus");
assertEquals("refs/remotes/mine/foo-blah", b.getDestination());
RefSpec c = a.expandFromDestination("refs/remotes/mine/foo-blah");
assertEquals("refs/heads/foo/for-linus", c.getSource());
}
@Test
public void testWildcardAfterText2() {
RefSpec a = new RefSpec("refs/heads*/for-linus:refs/remotes/mine/*");
assertTrue(a.isWildcard());
assertTrue(a.matchSource("refs/headsx/for-linus"));
assertTrue(a.matchSource("refs/headsfoo/for-linus"));
assertTrue(a.matchSource("refs/headsx/foo/for-linus"));
assertFalse(a.matchSource("refs/headx/for-linus"));
RefSpec b = a.expandFromSource("refs/headsx/for-linus");
assertEquals("refs/remotes/mine/x", b.getDestination());
RefSpec c = a.expandFromDestination("refs/remotes/mine/x");
assertEquals("refs/headsx/for-linus", c.getSource());
RefSpec d = a.expandFromSource("refs/headsx/foo/for-linus");
assertEquals("refs/remotes/mine/x/foo", d.getDestination());
RefSpec e = a.expandFromDestination("refs/remotes/mine/x/foo");
assertEquals("refs/headsx/foo/for-linus", e.getSource());
}
@Test @Test
public void testWildcardMirror() { public void testWildcardMirror() {
RefSpec a = new RefSpec("*:*"); RefSpec a = new RefSpec("*:*");
@ -403,21 +438,6 @@ public class RefSpecTest {
assertNotNull(new RefSpec("refs/heads/*:refs/heads/*/*")); assertNotNull(new RefSpec("refs/heads/*:refs/heads/*/*"));
} }
@Test(expected = IllegalArgumentException.class)
public void invalidWhenWildcardAfterText() {
assertNotNull(new RefSpec("refs/heads/wrong*:refs/heads/right/*"));
}
@Test(expected = IllegalArgumentException.class)
public void invalidWhenWildcardBeforeText() {
assertNotNull(new RefSpec("*wrong:right/*"));
}
@Test(expected = IllegalArgumentException.class)
public void invalidWhenWildcardBeforeTextAtEnd() {
assertNotNull(new RefSpec("refs/heads/*wrong:right/*"));
}
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void invalidSourceDoubleSlashes() { public void invalidSourceDoubleSlashes() {
assertNotNull(new RefSpec("refs/heads//wrong")); assertNotNull(new RefSpec("refs/heads//wrong"));

69
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java

@ -61,13 +61,10 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
public class TransportTest extends SampleDataRepositoryTestCase { public class TransportTest extends SampleDataRepositoryTestCase {
private Transport transport;
private RemoteConfig remoteConfig; private RemoteConfig remoteConfig;
@Override @Override
@ -77,17 +74,6 @@ public class TransportTest extends SampleDataRepositoryTestCase {
final Config config = db.getConfig(); final Config config = db.getConfig();
remoteConfig = new RemoteConfig(config, "test"); remoteConfig = new RemoteConfig(config, "test");
remoteConfig.addURI(new URIish("http://everyones.loves.git/u/2")); remoteConfig.addURI(new URIish("http://everyones.loves.git/u/2"));
transport = null;
}
@Override
@After
public void tearDown() throws Exception {
if (transport != null) {
transport.close();
transport = null;
}
super.tearDown();
} }
/** /**
@ -99,10 +85,11 @@ public class TransportTest extends SampleDataRepositoryTestCase {
@Test @Test
public void testFindRemoteRefUpdatesNoWildcardNoTracking() public void testFindRemoteRefUpdatesNoWildcardNoTracking()
throws IOException { throws IOException {
transport = Transport.open(db, remoteConfig); Collection<RemoteRefUpdate> result;
final Collection<RemoteRefUpdate> result = transport try (Transport transport = Transport.open(db, remoteConfig)) {
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec( result = transport.findRemoteRefUpdatesFor(Collections.nCopies(1,
"refs/heads/master:refs/heads/x"))); new RefSpec("refs/heads/master:refs/heads/x")));
}
assertEquals(1, result.size()); assertEquals(1, result.size());
final RemoteRefUpdate rru = result.iterator().next(); final RemoteRefUpdate rru = result.iterator().next();
@ -122,10 +109,11 @@ public class TransportTest extends SampleDataRepositoryTestCase {
@Test @Test
public void testFindRemoteRefUpdatesNoWildcardNoDestination() public void testFindRemoteRefUpdatesNoWildcardNoDestination()
throws IOException { throws IOException {
transport = Transport.open(db, remoteConfig); Collection<RemoteRefUpdate> result;
final Collection<RemoteRefUpdate> result = transport try (Transport transport = Transport.open(db, remoteConfig)) {
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec( result = transport.findRemoteRefUpdatesFor(
"+refs/heads/master"))); Collections.nCopies(1, new RefSpec("+refs/heads/master")));
}
assertEquals(1, result.size()); assertEquals(1, result.size());
final RemoteRefUpdate rru = result.iterator().next(); final RemoteRefUpdate rru = result.iterator().next();
@ -143,10 +131,11 @@ public class TransportTest extends SampleDataRepositoryTestCase {
*/ */
@Test @Test
public void testFindRemoteRefUpdatesWildcardNoTracking() throws IOException { public void testFindRemoteRefUpdatesWildcardNoTracking() throws IOException {
transport = Transport.open(db, remoteConfig); Collection<RemoteRefUpdate> result;
final Collection<RemoteRefUpdate> result = transport try (Transport transport = Transport.open(db, remoteConfig)) {
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec( result = transport.findRemoteRefUpdatesFor(Collections.nCopies(1,
"+refs/heads/*:refs/heads/test/*"))); new RefSpec("+refs/heads/*:refs/heads/test/*")));
}
assertEquals(12, result.size()); assertEquals(12, result.size());
boolean foundA = false; boolean foundA = false;
@ -171,12 +160,14 @@ public class TransportTest extends SampleDataRepositoryTestCase {
*/ */
@Test @Test
public void testFindRemoteRefUpdatesTwoRefSpecs() throws IOException { public void testFindRemoteRefUpdatesTwoRefSpecs() throws IOException {
transport = Transport.open(db, remoteConfig);
final RefSpec specA = new RefSpec("+refs/heads/a:refs/heads/b"); final RefSpec specA = new RefSpec("+refs/heads/a:refs/heads/b");
final RefSpec specC = new RefSpec("+refs/heads/c:refs/heads/d"); final RefSpec specC = new RefSpec("+refs/heads/c:refs/heads/d");
final Collection<RefSpec> specs = Arrays.asList(specA, specC); final Collection<RefSpec> specs = Arrays.asList(specA, specC);
final Collection<RemoteRefUpdate> result = transport
.findRemoteRefUpdatesFor(specs); Collection<RemoteRefUpdate> result;
try (Transport transport = Transport.open(db, remoteConfig)) {
result = transport.findRemoteRefUpdatesFor(specs);
}
assertEquals(2, result.size()); assertEquals(2, result.size());
boolean foundA = false; boolean foundA = false;
@ -202,10 +193,12 @@ public class TransportTest extends SampleDataRepositoryTestCase {
public void testFindRemoteRefUpdatesTrackingRef() throws IOException { public void testFindRemoteRefUpdatesTrackingRef() throws IOException {
remoteConfig.addFetchRefSpec(new RefSpec( remoteConfig.addFetchRefSpec(new RefSpec(
"refs/heads/*:refs/remotes/test/*")); "refs/heads/*:refs/remotes/test/*"));
transport = Transport.open(db, remoteConfig);
final Collection<RemoteRefUpdate> result = transport Collection<RemoteRefUpdate> result;
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec( try (Transport transport = Transport.open(db, remoteConfig)) {
"+refs/heads/a:refs/heads/a"))); result = transport.findRemoteRefUpdatesFor(Collections.nCopies(1,
new RefSpec("+refs/heads/a:refs/heads/a")));
}
assertEquals(1, result.size()); assertEquals(1, result.size());
final TrackingRefUpdate tru = result.iterator().next() final TrackingRefUpdate tru = result.iterator().next()
@ -225,20 +218,18 @@ public class TransportTest extends SampleDataRepositoryTestCase {
config.addURI(new URIish("../" + otherDir)); config.addURI(new URIish("../" + otherDir));
// Should not throw NoRemoteRepositoryException // Should not throw NoRemoteRepositoryException
transport = Transport.open(db, config); Transport.open(db, config).close();
} }
@Test @Test
public void testLocalTransportFetchWithoutLocalRepository() public void testLocalTransportFetchWithoutLocalRepository()
throws Exception { throws Exception {
URIish uri = new URIish("file://" + db.getWorkTree().getAbsolutePath()); URIish uri = new URIish("file://" + db.getWorkTree().getAbsolutePath());
transport = Transport.open(uri); try (Transport transport = Transport.open(uri)) {
FetchConnection fetchConnection = transport.openFetch(); try (FetchConnection fetchConnection = transport.openFetch()) {
try {
Ref head = fetchConnection.getRef(Constants.HEAD); Ref head = fetchConnection.getRef(Constants.HEAD);
assertNotNull(head); assertNotNull(head);
} finally { }
fetchConnection.close();
} }
} }

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

@ -459,6 +459,48 @@ public class URIishTest {
assertEquals(u, new URIish(str)); assertEquals(u, new URIish(str));
} }
@Test
public void testSshProtoWithEmailUserAndPort() throws Exception {
final String str = "ssh://user.name@email.com@example.com:33/some/p ath";
URIish u = new URIish(str);
assertEquals("ssh", u.getScheme());
assertTrue(u.isRemote());
assertEquals("/some/p ath", u.getRawPath());
assertEquals("/some/p ath", u.getPath());
assertEquals("example.com", u.getHost());
assertEquals("user.name@email.com", u.getUser());
assertNull(u.getPass());
assertEquals(33, u.getPort());
assertEquals("ssh://user.name%40email.com@example.com:33/some/p ath",
u.toPrivateString());
assertEquals("ssh://user.name%40email.com@example.com:33/some/p%20ath",
u.toPrivateASCIIString());
assertEquals(u.setPass(null).toPrivateString(), u.toString());
assertEquals(u.setPass(null).toPrivateASCIIString(), u.toASCIIString());
assertEquals(u, new URIish(str));
}
@Test
public void testSshProtoWithEmailUserPassAndPort() throws Exception {
final String str = "ssh://user.name@email.com:pass@wor:d@example.com:33/some/p ath";
URIish u = new URIish(str);
assertEquals("ssh", u.getScheme());
assertTrue(u.isRemote());
assertEquals("/some/p ath", u.getRawPath());
assertEquals("/some/p ath", u.getPath());
assertEquals("example.com", u.getHost());
assertEquals("user.name@email.com", u.getUser());
assertEquals("pass@wor:d", u.getPass());
assertEquals(33, u.getPort());
assertEquals("ssh://user.name%40email.com:pass%40wor%3ad@example.com:33/some/p ath",
u.toPrivateString());
assertEquals("ssh://user.name%40email.com:pass%40wor%3ad@example.com:33/some/p%20ath",
u.toPrivateASCIIString());
assertEquals(u.setPass(null).toPrivateString(), u.toString());
assertEquals(u.setPass(null).toPrivateASCIIString(), u.toASCIIString());
assertEquals(u, new URIish(str));
}
@Test @Test
public void testSshProtoWithADUserPassAndPort() throws Exception { public void testSshProtoWithADUserPassAndPort() throws Exception {
final String str = "ssh://DOMAIN\\user:pass@example.com:33/some/p ath"; final String str = "ssh://DOMAIN\\user:pass@example.com:33/some/p ath";

45
org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java

@ -44,7 +44,6 @@
package org.eclipse.jgit.treewalk; package org.eclipse.jgit.treewalk;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
import static org.eclipse.jgit.lib.Constants.encode; import static org.eclipse.jgit.lib.Constants.encode;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
@ -54,11 +53,10 @@ import org.eclipse.jgit.junit.RepositoryTestCase;
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.ObjectInserter; import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Tree; import org.eclipse.jgit.lib.TreeFormatter;
import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.junit.Test; import org.junit.Test;
@SuppressWarnings("deprecation")
public class TreeWalkBasicDiffTest extends RepositoryTestCase { public class TreeWalkBasicDiffTest extends RepositoryTestCase {
@Test @Test
public void testMissingSubtree_DetectFileAdded_FileModified() public void testMissingSubtree_DetectFileAdded_FileModified()
@ -72,44 +70,44 @@ public class TreeWalkBasicDiffTest extends RepositoryTestCase {
// Create sub-a/empty, sub-c/empty = hello. // Create sub-a/empty, sub-c/empty = hello.
{ {
final Tree root = new Tree(db); TreeFormatter root = new TreeFormatter();
{ {
final Tree subA = root.addTree("sub-a"); TreeFormatter subA = new TreeFormatter();
subA.addFile("empty").setId(aFileId); subA.append("empty", FileMode.REGULAR_FILE, aFileId);
subA.setId(inserter.insert(OBJ_TREE, subA.format())); root.append("sub-a", FileMode.TREE, inserter.insert(subA));
} }
{ {
final Tree subC = root.addTree("sub-c"); TreeFormatter subC = new TreeFormatter();
subC.addFile("empty").setId(cFileId1); subC.append("empty", FileMode.REGULAR_FILE, cFileId1);
subC.setId(inserter.insert(OBJ_TREE, subC.format())); root.append("sub-c", FileMode.TREE, inserter.insert(subC));
} }
oldTree = inserter.insert(OBJ_TREE, root.format()); oldTree = inserter.insert(root);
} }
// Create sub-a/empty, sub-b/empty, sub-c/empty. // Create sub-a/empty, sub-b/empty, sub-c/empty.
{ {
final Tree root = new Tree(db); TreeFormatter root = new TreeFormatter();
{ {
final Tree subA = root.addTree("sub-a"); TreeFormatter subA = new TreeFormatter();
subA.addFile("empty").setId(aFileId); subA.append("empty", FileMode.REGULAR_FILE, aFileId);
subA.setId(inserter.insert(OBJ_TREE, subA.format())); root.append("sub-a", FileMode.TREE, inserter.insert(subA));
} }
{ {
final Tree subB = root.addTree("sub-b"); TreeFormatter subB = new TreeFormatter();
subB.addFile("empty").setId(bFileId); subB.append("empty", FileMode.REGULAR_FILE, bFileId);
subB.setId(inserter.insert(OBJ_TREE, subB.format())); root.append("sub-b", FileMode.TREE, inserter.insert(subB));
} }
{ {
final Tree subC = root.addTree("sub-c"); TreeFormatter subC = new TreeFormatter();
subC.addFile("empty").setId(cFileId2); subC.append("empty", FileMode.REGULAR_FILE, cFileId2);
subC.setId(inserter.insert(OBJ_TREE, subC.format())); root.append("sub-c", FileMode.TREE, inserter.insert(subC));
} }
newTree = inserter.insert(OBJ_TREE, root.format()); newTree = inserter.insert(root);
} }
inserter.flush(); inserter.flush();
} }
final TreeWalk tw = new TreeWalk(db); try (TreeWalk tw = new TreeWalk(db)) {
tw.reset(oldTree, newTree); tw.reset(oldTree, newTree);
tw.setRecursive(true); tw.setRecursive(true);
tw.setFilter(TreeFilter.ANY_DIFF); tw.setFilter(TreeFilter.ANY_DIFF);
@ -130,4 +128,5 @@ public class TreeWalkBasicDiffTest extends RepositoryTestCase {
assertFalse(tw.next()); assertFalse(tw.next());
} }
}
} }

150
org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java

@ -43,11 +43,18 @@
package org.eclipse.jgit.treewalk.filter; package org.eclipse.jgit.treewalk.filter;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
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.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEditor; import org.eclipse.jgit.dircache.DirCacheEditor;
@ -58,6 +65,7 @@ import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.StopWalkException; import org.eclipse.jgit.errors.StopWalkException;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Sets;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -66,6 +74,8 @@ public class PathFilterGroupTest {
private TreeFilter filter; private TreeFilter filter;
private Map<String, TreeFilter> singles;
@Before @Before
public void setup() { public void setup() {
// @formatter:off // @formatter:off
@ -81,64 +91,75 @@ public class PathFilterGroupTest {
}; };
// @formatter:on // @formatter:on
filter = PathFilterGroup.createFromStrings(paths); filter = PathFilterGroup.createFromStrings(paths);
singles = new HashMap<>();
for (String path : paths) {
singles.put(path, PathFilterGroup.createFromStrings(path));
}
} }
@Test @Test
public void testExact() throws MissingObjectException, public void testExact() throws MissingObjectException,
IncorrectObjectTypeException, IOException { IncorrectObjectTypeException, IOException {
assertTrue(filter.include(fakeWalk("a"))); assertMatches(Sets.of("a"), fakeWalk("a"));
assertTrue(filter.include(fakeWalk("b/c"))); assertMatches(Sets.of("b/c"), fakeWalk("b/c"));
assertTrue(filter.include(fakeWalk("c/d/e"))); assertMatches(Sets.of("c/d/e"), fakeWalk("c/d/e"));
assertTrue(filter.include(fakeWalk("c/d/f"))); assertMatches(Sets.of("c/d/f"), fakeWalk("c/d/f"));
assertTrue(filter.include(fakeWalk("d/e/f/g"))); assertMatches(Sets.of("d/e/f/g"), fakeWalk("d/e/f/g"));
assertTrue(filter.include(fakeWalk("d/e/f/g.x"))); assertMatches(Sets.of("d/e/f/g.x"), fakeWalk("d/e/f/g.x"));
} }
@Test @Test
public void testNoMatchButClose() throws MissingObjectException, public void testNoMatchButClose() throws MissingObjectException,
IncorrectObjectTypeException, IOException { IncorrectObjectTypeException, IOException {
assertFalse(filter.include(fakeWalk("a+"))); assertNoMatches(fakeWalk("a+"));
assertFalse(filter.include(fakeWalk("b+/c"))); assertNoMatches(fakeWalk("b+/c"));
assertFalse(filter.include(fakeWalk("c+/d/e"))); assertNoMatches(fakeWalk("c+/d/e"));
assertFalse(filter.include(fakeWalk("c+/d/f"))); assertNoMatches(fakeWalk("c+/d/f"));
assertFalse(filter.include(fakeWalk("c/d.a"))); assertNoMatches(fakeWalk("c/d.a"));
assertFalse(filter.include(fakeWalk("d+/e/f/g"))); assertNoMatches(fakeWalk("d+/e/f/g"));
} }
@Test @Test
public void testJustCommonPrefixIsNotMatch() throws MissingObjectException, public void testJustCommonPrefixIsNotMatch() throws MissingObjectException,
IncorrectObjectTypeException, IOException { IncorrectObjectTypeException, IOException {
assertFalse(filter.include(fakeWalk("b/a"))); assertNoMatches(fakeWalk("b/a"));
assertFalse(filter.include(fakeWalk("b/d"))); assertNoMatches(fakeWalk("b/d"));
assertFalse(filter.include(fakeWalk("c/d/a"))); assertNoMatches(fakeWalk("c/d/a"));
assertFalse(filter.include(fakeWalk("d/e/e"))); assertNoMatches(fakeWalk("d/e/e"));
assertNoMatches(fakeWalk("d/e/f/g.y"));
} }
@Test @Test
public void testKeyIsPrefixOfFilter() throws MissingObjectException, public void testKeyIsPrefixOfFilter() throws MissingObjectException,
IncorrectObjectTypeException, IOException { IncorrectObjectTypeException, IOException {
assertTrue(filter.include(fakeWalk("b"))); assertMatches(Sets.of("b/c"), fakeWalkAtSubtree("b"));
assertTrue(filter.include(fakeWalk("c/d"))); assertMatches(Sets.of("c/d/e", "c/d/f"), fakeWalkAtSubtree("c/d"));
assertTrue(filter.include(fakeWalk("c/d"))); assertMatches(Sets.of("c/d/e", "c/d/f"), fakeWalkAtSubtree("c"));
assertTrue(filter.include(fakeWalk("c"))); assertMatches(Sets.of("d/e/f/g", "d/e/f/g.x"),
assertTrue(filter.include(fakeWalk("d/e/f"))); fakeWalkAtSubtree("d/e/f"));
assertTrue(filter.include(fakeWalk("d/e"))); assertMatches(Sets.of("d/e/f/g", "d/e/f/g.x"),
assertTrue(filter.include(fakeWalk("d"))); fakeWalkAtSubtree("d/e"));
assertMatches(Sets.of("d/e/f/g", "d/e/f/g.x"), fakeWalkAtSubtree("d"));
assertNoMatches(fakeWalk("b"));
assertNoMatches(fakeWalk("c/d"));
assertNoMatches(fakeWalk("c"));
assertNoMatches(fakeWalk("d/e/f"));
assertNoMatches(fakeWalk("d/e"));
assertNoMatches(fakeWalk("d"));
} }
@Test @Test
public void testFilterIsPrefixOfKey() throws MissingObjectException, public void testFilterIsPrefixOfKey() throws MissingObjectException,
IncorrectObjectTypeException, IOException { IncorrectObjectTypeException, IOException {
assertTrue(filter.include(fakeWalk("a/b"))); assertMatches(Sets.of("a"), fakeWalk("a/b"));
assertTrue(filter.include(fakeWalk("b/c/d"))); assertMatches(Sets.of("b/c"), fakeWalk("b/c/d"));
assertTrue(filter.include(fakeWalk("c/d/e/f"))); assertMatches(Sets.of("c/d/e"), fakeWalk("c/d/e/f"));
assertTrue(filter.include(fakeWalk("c/d/f/g"))); assertMatches(Sets.of("c/d/f"), fakeWalk("c/d/f/g"));
assertTrue(filter.include(fakeWalk("d/e/f/g/h"))); assertMatches(Sets.of("d/e/f/g"), fakeWalk("d/e/f/g/h"));
assertTrue(filter.include(fakeWalk("d/e/f/g/y"))); assertMatches(Sets.of("d/e/f/g"), fakeWalk("d/e/f/g/y"));
assertTrue(filter.include(fakeWalk("d/e/f/g.x/h"))); assertMatches(Sets.of("d/e/f/g.x"), fakeWalk("d/e/f/g.x/h"));
// listed before g/y, so can't StopWalk here, but it's not included
// either
assertFalse(filter.include(fakeWalk("d/e/f/g.y")));
} }
@Test @Test
@ -182,6 +203,10 @@ public class PathFilterGroupTest {
// less obvious #2 due to git sorting order // less obvious #2 due to git sorting order
filter.include(fakeWalk("d/e/f/g/h.txt")); filter.include(fakeWalk("d/e/f/g/h.txt"));
// listed before g/y, so can't StopWalk here
filter.include(fakeWalk("d/e/f/g.y"));
singles.get("d/e/f/g").include(fakeWalk("d/e/f/g.y"));
// non-ascii // non-ascii
try { try {
filter.include(fakeWalk("\u00C0")); filter.include(fakeWalk("\u00C0"));
@ -191,6 +216,44 @@ public class PathFilterGroupTest {
} }
} }
private void assertNoMatches(TreeWalk tw) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
assertMatches(Sets.<String> of(), tw);
}
private void assertMatches(Set<String> expect, TreeWalk tw)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
List<String> actual = new ArrayList<>();
for (String path : singles.keySet()) {
if (includes(singles.get(path), tw)) {
actual.add(path);
}
}
String[] e = expect.toArray(new String[expect.size()]);
String[] a = actual.toArray(new String[actual.size()]);
Arrays.sort(e);
Arrays.sort(a);
assertArrayEquals(e, a);
if (expect.isEmpty()) {
assertFalse(includes(filter, tw));
} else {
assertTrue(includes(filter, tw));
}
}
private static boolean includes(TreeFilter f, TreeWalk tw)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
try {
return f.include(tw);
} catch (StopWalkException e) {
return false;
}
}
TreeWalk fakeWalk(final String path) throws IOException { TreeWalk fakeWalk(final String path) throws IOException {
DirCache dc = DirCache.newInCore(); DirCache dc = DirCache.newInCore();
DirCacheEditor dce = dc.editor(); DirCacheEditor dce = dc.editor();
@ -210,4 +273,25 @@ public class PathFilterGroupTest {
return ret; return ret;
} }
TreeWalk fakeWalkAtSubtree(final String path) throws IOException {
DirCache dc = DirCache.newInCore();
DirCacheEditor dce = dc.editor();
dce.add(new DirCacheEditor.PathEdit(path + "/README") {
public void apply(DirCacheEntry ent) {
ent.setFileMode(FileMode.REGULAR_FILE);
}
});
dce.finish();
TreeWalk ret = new TreeWalk((ObjectReader) null);
ret.addTree(new DirCacheIterator(dc));
ret.next();
while (!path.equals(ret.getPathString())) {
if (ret.isSubtree()) {
ret.enterSubtree();
}
ret.next();
}
return ret;
}
} }

3
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java

@ -45,7 +45,6 @@ package org.eclipse.jgit.util;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.junit.MockSystemReader; import org.eclipse.jgit.junit.MockSystemReader;
@ -113,7 +112,7 @@ public class ChangeIdUtilTest {
} }
@Test @Test
public void testId() throws IOException { public void testId() {
String msg = "A\nMessage\n"; String msg = "A\nMessage\n";
ObjectId id = ChangeIdUtil.computeChangeId(treeId, parentId, p, q, msg); ObjectId id = ChangeIdUtil.computeChangeId(treeId, parentId, p, q, msg);
assertEquals("73f3751208ac92cbb76f9a26ac4a0d9d472e381b", ObjectId assertEquals("73f3751208ac92cbb76f9a26ac4a0d9d472e381b", ObjectId

24
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java

@ -54,6 +54,7 @@ import java.util.regex.Matcher;
import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.JGitTestUtil;
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;
@ -424,18 +425,27 @@ public class FileUtilTest {
@Test @Test
public void testCreateSymlink() throws IOException { public void testCreateSymlink() throws IOException {
FS fs = FS.DETECTED; FS fs = FS.DETECTED;
try { // show test as ignored if the FS doesn't support symlinks
Assume.assumeTrue(fs.supportsSymlinks());
fs.createSymLink(new File(trash, "x"), "y"); fs.createSymLink(new File(trash, "x"), "y");
} catch (IOException e) {
if (fs.supportsSymlinks())
fail("FS claims to support symlinks but attempt to create symlink failed");
return;
}
assertTrue(fs.supportsSymlinks());
String target = fs.readSymLink(new File(trash, "x")); String target = fs.readSymLink(new File(trash, "x"));
assertEquals("y", target); assertEquals("y", target);
} }
@Test
public void testCreateSymlinkOverrideExisting() throws IOException {
FS fs = FS.DETECTED;
// show test as ignored if the FS doesn't support symlinks
Assume.assumeTrue(fs.supportsSymlinks());
File file = new File(trash, "x");
fs.createSymLink(file, "y");
String target = fs.readSymLink(file);
assertEquals("y", target);
fs.createSymLink(file, "z");
target = fs.readSymLink(file);
assertEquals("z", target);
}
@Test @Test
public void testRelativize_doc() { public void testRelativize_doc() {
// This is the javadoc example // This is the javadoc example

118
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java

@ -0,0 +1,118 @@
/*
* Copyright (C) 2016, 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.util;
import static org.eclipse.jgit.util.Paths.compare;
import static org.eclipse.jgit.util.Paths.compareSameName;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.junit.Test;
public class PathsTest {
@Test
public void testStripTrailingSeparator() {
assertNull(Paths.stripTrailingSeparator(null));
assertEquals("", Paths.stripTrailingSeparator(""));
assertEquals("a", Paths.stripTrailingSeparator("a"));
assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo"));
assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo/"));
assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo//"));
assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo///"));
}
@Test
public void testPathCompare() {
byte[] a = Constants.encode("afoo/bar.c");
byte[] b = Constants.encode("bfoo/bar.c");
assertEquals(0, compare(a, 1, a.length, 0, b, 1, b.length, 0));
assertEquals(-1, compare(a, 0, a.length, 0, b, 0, b.length, 0));
assertEquals(1, compare(b, 0, b.length, 0, a, 0, a.length, 0));
a = Constants.encode("a");
b = Constants.encode("aa");
assertEquals(-97, compare(a, 0, a.length, 0, b, 0, b.length, 0));
assertEquals(0, compare(a, 0, a.length, 0, b, 0, 1, 0));
assertEquals(0, compare(a, 0, a.length, 0, b, 1, 2, 0));
assertEquals(0, compareSameName(a, 0, a.length, b, 1, b.length, 0));
assertEquals(0, compareSameName(a, 0, a.length, b, 0, 1, 0));
assertEquals(-50, compareSameName(a, 0, a.length, b, 0, b.length, 0));
assertEquals(97, compareSameName(b, 0, b.length, a, 0, a.length, 0));
a = Constants.encode("a");
b = Constants.encode("a");
assertEquals(0, compare(
a, 0, a.length, FileMode.TREE.getBits(),
b, 0, b.length, FileMode.TREE.getBits()));
assertEquals(0, compare(
a, 0, a.length, FileMode.REGULAR_FILE.getBits(),
b, 0, b.length, FileMode.REGULAR_FILE.getBits()));
assertEquals(-47, compare(
a, 0, a.length, FileMode.REGULAR_FILE.getBits(),
b, 0, b.length, FileMode.TREE.getBits()));
assertEquals(47, compare(
a, 0, a.length, FileMode.TREE.getBits(),
b, 0, b.length, FileMode.REGULAR_FILE.getBits()));
assertEquals(0, compareSameName(
a, 0, a.length,
b, 0, b.length, FileMode.TREE.getBits()));
assertEquals(0, compareSameName(
a, 0, a.length,
b, 0, b.length, FileMode.REGULAR_FILE.getBits()));
a = Constants.encode("a.c");
b = Constants.encode("a");
byte[] c = Constants.encode("a0c");
assertEquals(-1, compare(
a, 0, a.length, FileMode.REGULAR_FILE.getBits(),
b, 0, b.length, FileMode.TREE.getBits()));
assertEquals(-1, compare(
b, 0, b.length, FileMode.TREE.getBits(),
c, 0, c.length, FileMode.REGULAR_FILE.getBits()));
}
}

7
org.eclipse.jgit.ui/BUCK

@ -0,0 +1,7 @@
java_library(
name = 'ui',
srcs = glob(['src/**']),
resources = glob(['resources/**']),
deps = ['//org.eclipse.jgit:jgit'],
visibility = ['PUBLIC'],
)

7
org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java

@ -56,15 +56,20 @@ import javax.swing.JPasswordField;
import javax.swing.JTextField; import javax.swing.JTextField;
import org.eclipse.jgit.errors.UnsupportedCredentialItem; import org.eclipse.jgit.errors.UnsupportedCredentialItem;
import org.eclipse.jgit.transport.ChainingCredentialsProvider;
import org.eclipse.jgit.transport.CredentialItem; import org.eclipse.jgit.transport.CredentialItem;
import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.NetRCCredentialsProvider;
import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.transport.URIish;
/** Interacts with the user during authentication by using AWT/Swing dialogs. */ /** Interacts with the user during authentication by using AWT/Swing dialogs. */
public class AwtCredentialsProvider extends CredentialsProvider { public class AwtCredentialsProvider extends CredentialsProvider {
/** Install this implementation as the default. */ /** Install this implementation as the default. */
public static void install() { public static void install() {
CredentialsProvider.setDefault(new AwtCredentialsProvider()); final AwtCredentialsProvider c = new AwtCredentialsProvider();
CredentialsProvider cp = new ChainingCredentialsProvider(
new NetRCCredentialsProvider(), c);
CredentialsProvider.setDefault(cp);
} }
@Override @Override

40
org.eclipse.jgit/.settings/.api_filters

@ -1,5 +1,45 @@
<?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="META-INF/MANIFEST.MF" type="org.eclipse.jgit.lib.FileTreeEntry">
<filter id="305324134">
<message_arguments>
<message_argument value="org.eclipse.jgit.lib.FileTreeEntry"/>
<message_argument value="org.eclipse.jgit_4.2.0"/>
</message_arguments>
</filter>
</resource>
<resource path="META-INF/MANIFEST.MF" type="org.eclipse.jgit.lib.GitlinkTreeEntry">
<filter id="305324134">
<message_arguments>
<message_argument value="org.eclipse.jgit.lib.GitlinkTreeEntry"/>
<message_argument value="org.eclipse.jgit_4.2.0"/>
</message_arguments>
</filter>
</resource>
<resource path="META-INF/MANIFEST.MF" type="org.eclipse.jgit.lib.SymlinkTreeEntry">
<filter id="305324134">
<message_arguments>
<message_argument value="org.eclipse.jgit.lib.SymlinkTreeEntry"/>
<message_argument value="org.eclipse.jgit_4.2.0"/>
</message_arguments>
</filter>
</resource>
<resource path="META-INF/MANIFEST.MF" type="org.eclipse.jgit.lib.Tree">
<filter id="305324134">
<message_arguments>
<message_argument value="org.eclipse.jgit.lib.Tree"/>
<message_argument value="org.eclipse.jgit_4.2.0"/>
</message_arguments>
</filter>
</resource>
<resource path="META-INF/MANIFEST.MF" type="org.eclipse.jgit.lib.TreeEntry">
<filter id="305324134">
<message_arguments>
<message_argument value="org.eclipse.jgit.lib.TreeEntry"/>
<message_argument value="org.eclipse.jgit_4.2.0"/>
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/jgit/attributes/AttributesNode.java" type="org.eclipse.jgit.attributes.AttributesNode"> <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"> <filter comment="attributes weren't really usable in earlier versions" id="338792546">
<message_arguments> <message_arguments>

20
org.eclipse.jgit/BUCK

@ -0,0 +1,20 @@
SRCS = glob(['src/**'])
RESOURCES = glob(['resources/**'])
java_library(
name = 'jgit',
srcs = SRCS,
resources = RESOURCES,
deps = [
'//lib:javaewah',
'//lib:jsch',
'//lib:httpcomponents',
'//lib:slf4j-api',
],
visibility = ['PUBLIC'],
)
java_sources(
name = 'jgit_src',
srcs = SRCS + RESOURCES,
)

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

@ -65,9 +65,10 @@ Export-Package: org.eclipse.jgit.annotations;version="4.2.0",
org.eclipse.jgit.junit, org.eclipse.jgit.junit,
org.eclipse.jgit.junit.http, org.eclipse.jgit.junit.http,
org.eclipse.jgit.http.server, org.eclipse.jgit.http.server,
org.eclipse.jgit.java7.test, org.eclipse.jgit.pgm.test,
org.eclipse.jgit.pgm", org.eclipse.jgit.pgm",
org.eclipse.jgit.internal.storage.pack;version="4.2.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", org.eclipse.jgit.internal.storage.pack;version="4.2.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
org.eclipse.jgit.internal.storage.reftree;version="4.2.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
org.eclipse.jgit.lib;version="4.2.0"; org.eclipse.jgit.lib;version="4.2.0";
uses:="org.eclipse.jgit.revwalk, uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.treewalk.filter,

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

@ -99,6 +99,7 @@ cannotSquashFixupWithoutPreviousCommit=Cannot {0} without previous commit.
cannotStoreObjects=cannot store objects cannotStoreObjects=cannot store objects
cannotResolveUniquelyAbbrevObjectId=Could not resolve uniquely the abbreviated object ID cannotResolveUniquelyAbbrevObjectId=Could not resolve uniquely the abbreviated object ID
cannotUnloadAModifiedTree=Cannot unload a modified tree. cannotUnloadAModifiedTree=Cannot unload a modified tree.
cannotUpdateUnbornBranch=Cannot update unborn branch
cannotWorkWithOtherStagesThanZeroRightNow=Cannot work with other stages than zero right now. Won't write corrupt index. cannotWorkWithOtherStagesThanZeroRightNow=Cannot work with other stages than zero right now. Won't write corrupt index.
cannotWriteObjectsPath=Cannot write {0}/{1}: {2} cannotWriteObjectsPath=Cannot write {0}/{1}: {2}
canOnlyCherryPickCommitsWithOneParent=Cannot cherry-pick commit ''{0}'' because it has {1} parents, only commits with exactly one parent are supported. canOnlyCherryPickCommitsWithOneParent=Cannot cherry-pick commit ''{0}'' because it has {1} parents, only commits with exactly one parent are supported.
@ -125,14 +126,15 @@ connectionFailed=connection failed
connectionTimeOut=Connection time out: {0} connectionTimeOut=Connection time out: {0}
contextMustBeNonNegative=context must be >= 0 contextMustBeNonNegative=context must be >= 0
corruptionDetectedReReadingAt=Corruption detected re-reading at {0} corruptionDetectedReReadingAt=Corruption detected re-reading at {0}
corruptObjectBadDate=bad date
corruptObjectBadEmail=bad email
corruptObjectBadStream=bad stream corruptObjectBadStream=bad stream
corruptObjectBadStreamCorruptHeader=bad stream, corrupt header corruptObjectBadStreamCorruptHeader=bad stream, corrupt header
corruptObjectBadTimezone=bad time zone
corruptObjectDuplicateEntryNames=duplicate entry names corruptObjectDuplicateEntryNames=duplicate entry names
corruptObjectGarbageAfterSize=garbage after size corruptObjectGarbageAfterSize=garbage after size
corruptObjectIncorrectLength=incorrect length corruptObjectIncorrectLength=incorrect length
corruptObjectIncorrectSorting=incorrectly sorted corruptObjectIncorrectSorting=incorrectly sorted
corruptObjectInvalidAuthor=invalid author
corruptObjectInvalidCommitter=invalid committer
corruptObjectInvalidEntryMode=invalid entry mode corruptObjectInvalidEntryMode=invalid entry mode
corruptObjectInvalidMode=invalid mode corruptObjectInvalidMode=invalid mode
corruptObjectInvalidModeChar=invalid mode character corruptObjectInvalidModeChar=invalid mode character
@ -151,11 +153,11 @@ corruptObjectInvalidNameNul=invalid name 'NUL'
corruptObjectInvalidNamePrn=invalid name 'PRN' corruptObjectInvalidNamePrn=invalid name 'PRN'
corruptObjectInvalidObject=invalid object corruptObjectInvalidObject=invalid object
corruptObjectInvalidParent=invalid parent corruptObjectInvalidParent=invalid parent
corruptObjectInvalidTagger=invalid tagger
corruptObjectInvalidTree=invalid tree corruptObjectInvalidTree=invalid tree
corruptObjectInvalidType=invalid type corruptObjectInvalidType=invalid type
corruptObjectInvalidType2=invalid type {0} corruptObjectInvalidType2=invalid type {0}
corruptObjectMalformedHeader=malformed header: {0} corruptObjectMalformedHeader=malformed header: {0}
corruptObjectMissingEmail=missing email
corruptObjectNameContainsByte=name contains byte 0x%x corruptObjectNameContainsByte=name contains byte 0x%x
corruptObjectNameContainsChar=name contains '%c' corruptObjectNameContainsChar=name contains '%c'
corruptObjectNameContainsNullByte=name contains byte 0x00 corruptObjectNameContainsNullByte=name contains byte 0x00
@ -181,6 +183,7 @@ corruptObjectPackfileChecksumIncorrect=Packfile checksum incorrect.
corruptObjectTruncatedInMode=truncated in mode corruptObjectTruncatedInMode=truncated in mode
corruptObjectTruncatedInName=truncated in name corruptObjectTruncatedInName=truncated in name
corruptObjectTruncatedInObjectId=truncated in object id corruptObjectTruncatedInObjectId=truncated in object id
corruptObjectZeroId=entry points to null SHA-1
couldNotCheckOutBecauseOfConflicts=Could not check out because of conflicts couldNotCheckOutBecauseOfConflicts=Could not check out because of conflicts
couldNotDeleteLockFileShouldNotHappen=Could not delete lock file. Should not happen couldNotDeleteLockFileShouldNotHappen=Could not delete lock file. Should not happen
couldNotDeleteTemporaryIndexFileShouldNotHappen=Could not delete temporary index file. Should not happen couldNotDeleteTemporaryIndexFileShouldNotHappen=Could not delete temporary index file. Should not happen
@ -432,6 +435,7 @@ noXMLParserAvailable=No XML parser available.
objectAtHasBadZlibStream=Object at {0} in {1} has bad zlib stream objectAtHasBadZlibStream=Object at {0} in {1} has bad zlib stream
objectAtPathDoesNotHaveId=Object at path "{0}" does not have an id assigned. All object ids must be assigned prior to writing a tree. objectAtPathDoesNotHaveId=Object at path "{0}" does not have an id assigned. All object ids must be assigned prior to writing a tree.
objectIsCorrupt=Object {0} is corrupt: {1} objectIsCorrupt=Object {0} is corrupt: {1}
objectIsCorrupt3={0}: object {1}: {2}
objectIsNotA=Object {0} is not a {1}. objectIsNotA=Object {0} is not a {1}.
objectNotFound=Object {0} not found. objectNotFound=Object {0} not found.
objectNotFoundIn=Object {0} not found in {1}. objectNotFoundIn=Object {0} not found in {1}.
@ -595,6 +599,7 @@ transportExceptionInvalid=Invalid {0} {1}:{2}
transportExceptionMissingAssumed=Missing assumed {0} transportExceptionMissingAssumed=Missing assumed {0}
transportExceptionReadRef=read {0} transportExceptionReadRef=read {0}
transportNeedsRepository=Transport needs repository transportNeedsRepository=Transport needs repository
transportProvidedRefWithNoObjectId=Transport provided ref {0} with no object id
transportProtoAmazonS3=Amazon S3 transportProtoAmazonS3=Amazon S3
transportProtoBundleFile=Git Bundle File transportProtoBundleFile=Git Bundle File
transportProtoFTP=FTP transportProtoFTP=FTP

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

@ -43,6 +43,10 @@
*/ */
package org.eclipse.jgit.api; package org.eclipse.jgit.api;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static org.eclipse.jgit.lib.FileMode.GITLINK;
import static org.eclipse.jgit.lib.FileMode.TYPE_TREE;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collection; import java.util.Collection;
@ -58,12 +62,12 @@ import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
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.ObjectInserter; 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.NameConflictTreeWalk;
import org.eclipse.jgit.treewalk.TreeWalk.OperationType; 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;
@ -135,15 +139,12 @@ public class AddCommand extends GitCommand<DirCache> {
throw new NoFilepatternException(JGitText.get().atLeastOnePatternIsRequired); throw new NoFilepatternException(JGitText.get().atLeastOnePatternIsRequired);
checkCallable(); checkCallable();
DirCache dc = null; DirCache dc = null;
boolean addAll = false; boolean addAll = filepatterns.contains("."); //$NON-NLS-1$
if (filepatterns.contains(".")) //$NON-NLS-1$
addAll = true;
try (ObjectInserter inserter = repo.newObjectInserter(); try (ObjectInserter inserter = repo.newObjectInserter();
final TreeWalk tw = new TreeWalk(repo)) { NameConflictTreeWalk tw = new NameConflictTreeWalk(repo)) {
tw.setOperationType(OperationType.CHECKIN_OP); tw.setOperationType(OperationType.CHECKIN_OP);
dc = repo.lockDirCache(); dc = repo.lockDirCache();
DirCacheIterator c;
DirCacheBuilder builder = dc.builder(); DirCacheBuilder builder = dc.builder();
tw.addTree(new DirCacheBuildIterator(builder)); tw.addTree(new DirCacheBuildIterator(builder));
@ -151,62 +152,85 @@ public class AddCommand extends GitCommand<DirCache> {
workingTreeIterator = new FileTreeIterator(repo); workingTreeIterator = new FileTreeIterator(repo);
workingTreeIterator.setDirCacheIterator(tw, 0); workingTreeIterator.setDirCacheIterator(tw, 0);
tw.addTree(workingTreeIterator); tw.addTree(workingTreeIterator);
tw.setRecursive(true);
if (!addAll) if (!addAll)
tw.setFilter(PathFilterGroup.createFromStrings(filepatterns)); tw.setFilter(PathFilterGroup.createFromStrings(filepatterns));
String lastAddedFile = null; byte[] lastAdded = null;
while (tw.next()) { while (tw.next()) {
String path = tw.getPathString(); DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
WorkingTreeIterator f = tw.getTree(1, WorkingTreeIterator.class); WorkingTreeIterator f = tw.getTree(1, WorkingTreeIterator.class);
if (tw.getTree(0, DirCacheIterator.class) == null && if (c == null && f != null && f.isEntryIgnored()) {
f != null && f.isEntryIgnored()) {
// file is not in index but is ignored, do nothing // file is not in index but is ignored, do nothing
continue;
} else if (c == null && update) {
// Only update of existing entries was requested.
continue;
} }
DirCacheEntry entry = c != null ? c.getDirCacheEntry() : null;
if (entry != null && entry.getStage() > 0
&& lastAdded != null
&& lastAdded.length == tw.getPathLength()
&& tw.isPathPrefix(lastAdded, lastAdded.length) == 0) {
// In case of an existing merge conflict the // In case of an existing merge conflict the
// DirCacheBuildIterator iterates over all stages of // DirCacheBuildIterator iterates over all stages of
// this path, we however want to add only one // this path, we however want to add only one
// new DirCacheEntry per path. // new DirCacheEntry per path.
else if (!(path.equals(lastAddedFile))) { continue;
if (!(update && tw.getTree(0, DirCacheIterator.class) == null)) { }
c = tw.getTree(0, DirCacheIterator.class);
if (f != null) { // the file exists
long sz = f.getEntryLength();
DirCacheEntry entry = new DirCacheEntry(path);
if (c == null || c.getDirCacheEntry() == null
|| !c.getDirCacheEntry().isAssumeValid()) {
FileMode mode = f.getIndexFileMode(c);
entry.setFileMode(mode);
if (FileMode.GITLINK != mode) { if (tw.isSubtree() && !tw.isDirectoryFileConflict()) {
entry.setLength(sz); tw.enterSubtree();
entry.setLastModified(f continue;
.getEntryLastModified());
long contentSize = f
.getEntryContentLength();
InputStream in = f.openEntryStream();
try {
entry.setObjectId(inserter.insert(
Constants.OBJ_BLOB, contentSize, in));
} finally {
in.close();
} }
} else
entry.setObjectId(f.getEntryObjectId()); if (f == null) { // working tree file does not exist
if (entry != null
&& (!update || GITLINK == entry.getFileMode())) {
builder.add(entry); builder.add(entry);
lastAddedFile = path; }
} else { continue;
builder.add(c.getDirCacheEntry());
} }
} else if (c != null if (entry != null && entry.isAssumeValid()) {
&& (!update || FileMode.GITLINK == c // Index entry is marked assume valid. Even though
.getEntryFileMode())) // the user specified the file to be added JGit does
builder.add(c.getDirCacheEntry()); // not consider the file for addition.
builder.add(entry);
continue;
} }
if (f.getEntryRawMode() == TYPE_TREE) {
// Index entry exists and is symlink, gitlink or file,
// otherwise the tree would have been entered above.
// Replace the index entry by diving into tree of files.
tw.enterSubtree();
continue;
}
byte[] path = tw.getRawPath();
if (entry == null || entry.getStage() > 0) {
entry = new DirCacheEntry(path);
} }
FileMode mode = f.getIndexFileMode(c);
entry.setFileMode(mode);
if (GITLINK != mode) {
entry.setLength(f.getEntryLength());
entry.setLastModified(f.getEntryLastModified());
long len = f.getEntryContentLength();
try (InputStream in = f.openEntryStream()) {
ObjectId id = inserter.insert(OBJ_BLOB, len, in);
entry.setObjectId(id);
}
} else {
entry.setLength(0);
entry.setLastModified(0);
entry.setObjectId(f.getEntryObjectId());
}
builder.add(entry);
lastAdded = path;
} }
inserter.flush(); inserter.flush();
builder.commit(); builder.commit();

9
org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java

@ -47,6 +47,7 @@ import java.io.FileOutputStream;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.StandardCopyOption;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -141,9 +142,13 @@ public class ApplyCommand extends GitCommand<ApplyResult> {
case RENAME: case RENAME:
f = getFile(fh.getOldPath(), false); f = getFile(fh.getOldPath(), false);
File dest = getFile(fh.getNewPath(), false); File dest = getFile(fh.getNewPath(), false);
if (!f.renameTo(dest)) try {
FileUtils.rename(f, dest,
StandardCopyOption.ATOMIC_MOVE);
} catch (IOException e) {
throw new PatchApplyException(MessageFormat.format( throw new PatchApplyException(MessageFormat.format(
JGitText.get().renameFileFailed, f, dest)); JGitText.get().renameFileFailed, f, dest), e);
}
break; break;
case COPY: case COPY:
f = getFile(fh.getOldPath(), false); f = getFile(fh.getOldPath(), false);

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

@ -331,10 +331,17 @@ public class CheckoutCommand extends GitCommand<Ref> {
} }
private String getShortBranchName(Ref headRef) { private String getShortBranchName(Ref headRef) {
if (headRef.getTarget().getName().equals(headRef.getName())) if (headRef.isSymbolic()) {
return headRef.getTarget().getObjectId().getName();
return Repository.shortenRefName(headRef.getTarget().getName()); return Repository.shortenRefName(headRef.getTarget().getName());
} }
// Detached HEAD. Every non-symbolic ref in the ref database has an
// object id, so this cannot be null.
ObjectId id = headRef.getObjectId();
if (id == null) {
throw new NullPointerException();
}
return id.getName();
}
/** /**
* Add a single slash-separated path to the list of paths to check out. To * Add a single slash-separated path to the list of paths to check out. To

13
org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java

@ -61,6 +61,7 @@ import org.eclipse.jgit.internal.JGitText;
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.NullProgressMonitor; import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RefUpdate;
@ -235,7 +236,7 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> {
} }
if (head == null || head.getObjectId() == null) if (head == null || head.getObjectId() == null)
return; // throw exception? return; // TODO throw exception?
if (head.getName().startsWith(Constants.R_HEADS)) { if (head.getName().startsWith(Constants.R_HEADS)) {
final RefUpdate newHead = clonedRepo.updateRef(Constants.HEAD); final RefUpdate newHead = clonedRepo.updateRef(Constants.HEAD);
@ -287,20 +288,24 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> {
private Ref findBranchToCheckout(FetchResult result) { private Ref findBranchToCheckout(FetchResult result) {
final Ref idHEAD = result.getAdvertisedRef(Constants.HEAD); final Ref idHEAD = result.getAdvertisedRef(Constants.HEAD);
if (idHEAD == null) ObjectId headId = idHEAD != null ? idHEAD.getObjectId() : null;
if (headId == null) {
return null; return null;
}
Ref master = result.getAdvertisedRef(Constants.R_HEADS Ref master = result.getAdvertisedRef(Constants.R_HEADS
+ Constants.MASTER); + Constants.MASTER);
if (master != null && master.getObjectId().equals(idHEAD.getObjectId())) ObjectId objectId = master != null ? master.getObjectId() : null;
if (headId.equals(objectId)) {
return master; return master;
}
Ref foundBranch = null; Ref foundBranch = null;
for (final Ref r : result.getAdvertisedRefs()) { for (final Ref r : result.getAdvertisedRefs()) {
final String n = r.getName(); final String n = r.getName();
if (!n.startsWith(Constants.R_HEADS)) if (!n.startsWith(Constants.R_HEADS))
continue; continue;
if (r.getObjectId().equals(idHEAD.getObjectId())) { if (headId.equals(r.getObjectId())) {
foundBranch = r; foundBranch = r;
break; break;
} }

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

@ -53,6 +53,7 @@ import java.util.List;
import org.eclipse.jgit.api.errors.AbortedByHookException; import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
import org.eclipse.jgit.api.errors.EmtpyCommitException;
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;
@ -130,6 +131,8 @@ public class CommitCommand extends GitCommand<RevCommit> {
private PrintStream hookOutRedirect; private PrintStream hookOutRedirect;
private Boolean allowEmpty;
/** /**
* @param repo * @param repo
*/ */
@ -231,6 +234,16 @@ public class CommitCommand extends GitCommand<RevCommit> {
if (insertChangeId) if (insertChangeId)
insertChangeId(indexTreeId); insertChangeId(indexTreeId);
// Check for empty commits
if (headId != null && !allowEmpty.booleanValue()) {
RevCommit headCommit = rw.parseCommit(headId);
headCommit.getTree();
if (indexTreeId.equals(headCommit.getTree())) {
throw new EmtpyCommitException(
JGitText.get().emptyCommit);
}
}
// Create a Commit object, populate it and write it // Create a Commit object, populate it and write it
CommitBuilder commit = new CommitBuilder(); CommitBuilder commit = new CommitBuilder();
commit.setCommitter(committer); commit.setCommitter(committer);
@ -457,6 +470,8 @@ public class CommitCommand extends GitCommand<RevCommit> {
// there must be at least one change // there must be at least one change
if (emptyCommit) if (emptyCommit)
// Would like to throw a EmptyCommitException. But this would break the API
// TODO(ch): Change this in the next release
throw new JGitInternalException(JGitText.get().emptyCommit); throw new JGitInternalException(JGitText.get().emptyCommit);
// update index // update index
@ -510,6 +525,12 @@ public class CommitCommand extends GitCommand<RevCommit> {
committer = new PersonIdent(repo); committer = new PersonIdent(repo);
if (author == null && !amend) if (author == null && !amend)
author = committer; author = committer;
if (allowEmpty == null)
// JGit allows empty commits by default. Only when pathes are
// specified the commit should not be empty. This behaviour differs
// from native git but can only be adapted in the next release.
// TODO(ch) align the defaults with native git
allowEmpty = (only.isEmpty()) ? Boolean.TRUE : Boolean.FALSE;
// when doing a merge commit parse MERGE_HEAD and MERGE_MSG files // when doing a merge commit parse MERGE_HEAD and MERGE_MSG files
if (state == RepositoryState.MERGING_RESOLVED if (state == RepositoryState.MERGING_RESOLVED
@ -578,6 +599,27 @@ public class CommitCommand extends GitCommand<RevCommit> {
return this; return this;
} }
/**
* @param allowEmpty
* whether it should be allowed to create a commit which has the
* same tree as it's sole predecessor (a commit which doesn't
* change anything). By default when creating standard commits
* (without specifying paths) JGit allows to create such commits.
* When this flag is set to false an attempt to create an "empty"
* standard commit will lead to an EmptyCommitException.
* <p>
* By default when creating a commit containing only specified
* paths an attempt to create an empty commit leads to a
* {@link JGitInternalException}. By setting this flag to
* <code>true</code> this exception will not be thrown.
* @return {@code this}
* @since 4.2
*/
public CommitCommand setAllowEmpty(boolean allowEmpty) {
this.allowEmpty = Boolean.valueOf(allowEmpty);
return this;
}
/** /**
* @return the commit message used for the <code>commit</code> * @return the commit message used for the <code>commit</code>
*/ */
@ -681,7 +723,7 @@ public class CommitCommand extends GitCommand<RevCommit> {
*/ */
public CommitCommand setAll(boolean all) { public CommitCommand setAll(boolean all) {
checkCallable(); checkCallable();
if (!only.isEmpty()) if (all && !only.isEmpty())
throw new JGitInternalException(MessageFormat.format( throw new JGitInternalException(MessageFormat.format(
JGitText.get().illegalCombinationOfArguments, "--all", //$NON-NLS-1$ JGitText.get().illegalCombinationOfArguments, "--all", //$NON-NLS-1$
"--only")); //$NON-NLS-1$ "--only")); //$NON-NLS-1$

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

Loading…
Cancel
Save