Browse Source

Merge branch 'master' into stable-4.2

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

+ 15
- 0
.buckconfig View File

@@ -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
- 0
.buckversion View File

@@ -0,0 +1 @@
1b03b4313b91b634bd604fc3487a05f877e59dee

+ 2
- 0
.gitignore View File

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

+ 45
- 0
BUCK View File

@@ -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
- 0
lib/BUCK View File

@@ -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
- 0
lib/jetty/BUCK View File

@@ -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
- 0
org.eclipse.jgit.archive/BUCK View File

@@ -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
- 0
org.eclipse.jgit.http.apache/BUCK View File

@@ -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'],
)

+ 2
- 1
org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF View File

@@ -7,7 +7,8 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-Localization: plugin
Bundle-Vendor: %Provider-Name
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.methods;version="[4.1.0,5.0.0)",
org.apache.http.client.params;version="[4.1.0,5.0.0)",

+ 14
- 13
org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java View File

@@ -100,7 +100,7 @@ import org.eclipse.jgit.util.TemporaryBuffer.LocalFile;
public class HttpClientConnection implements HttpConnection {
HttpClient client;

String urlStr;
URL url;

HttpUriRequest req;

@@ -176,16 +176,19 @@ public class HttpClientConnection implements HttpConnection {

/**
* @param urlStr
* @throws MalformedURLException
*/
public HttpClientConnection(String urlStr) {
public HttpClientConnection(String urlStr) throws MalformedURLException {
this(urlStr, null);
}

/**
* @param urlStr
* @param proxy
* @throws MalformedURLException
*/
public HttpClientConnection(String urlStr, Proxy proxy) {
public HttpClientConnection(String urlStr, Proxy proxy)
throws MalformedURLException {
this(urlStr, proxy, null);
}

@@ -193,10 +196,12 @@ public class HttpClientConnection implements HttpConnection {
* @param urlStr
* @param proxy
* @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.urlStr = urlStr;
this.url = new URL(urlStr);
this.proxy = proxy;
}

@@ -206,11 +211,7 @@ public class HttpClientConnection implements HttpConnection {
}

public URL getURL() {
try {
return new URL(urlStr);
} catch (MalformedURLException e) {
return null;
}
return url;
}

public String getResponseMessage() throws IOException {
@@ -250,11 +251,11 @@ public class HttpClientConnection implements HttpConnection {
public void setRequestMethod(String method) throws ProtocolException {
this.method = method;
if ("GET".equalsIgnoreCase(method)) //$NON-NLS-1$
req = new HttpGet(urlStr);
req = new HttpGet(url.toString());
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$
req = new HttpPost(urlStr);
req = new HttpPost(url.toString());
else {
this.method = null;
throw new UnsupportedOperationException();

+ 10
- 0
org.eclipse.jgit.http.server/BUCK View File

@@ -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
- 0
org.eclipse.jgit.http.test/BUCK View File

@@ -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
- 0
org.eclipse.jgit.http.test/pom.xml View File

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

+ 5
- 20
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java View File

@@ -140,8 +140,7 @@ public class DumbClientDumbServerTest extends HttpTestCase {
assertEquals("http", remoteURI.getScheme());

Map<String, Ref> map;
Transport t = Transport.open(dst, remoteURI);
try {
try (Transport t = Transport.open(dst, remoteURI)) {
// I didn't make up these public interface names, I just
// approved them for inclusion into the code base. Sorry.
// --spearce
@@ -149,14 +148,9 @@ public class DumbClientDumbServerTest extends HttpTestCase {
assertTrue("isa TransportHttp", t instanceof TransportHttp);
assertTrue("isa HttpTransport", t instanceof HttpTransport);

FetchConnection c = t.openFetch();
try {
try (FetchConnection c = t.openFetch()) {
map = c.getRefsMap();
} finally {
c.close();
}
} finally {
t.close();
}

assertNotNull("have map of refs", map);
@@ -201,11 +195,8 @@ public class DumbClientDumbServerTest extends HttpTestCase {
Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt));

Transport t = Transport.open(dst, remoteURI);
try {
try (Transport t = Transport.open(dst, remoteURI)) {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}

assertTrue(dst.hasObject(A_txt));
@@ -226,11 +217,8 @@ public class DumbClientDumbServerTest extends HttpTestCase {
Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt));

Transport t = Transport.open(dst, remoteURI);
try {
try (Transport t = Transport.open(dst, remoteURI)) {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}

assertTrue(dst.hasObject(A_txt));
@@ -265,8 +253,7 @@ public class DumbClientDumbServerTest extends HttpTestCase {
final RevCommit Q = src.commit().create();
final Repository db = src.getRepository();

Transport t = Transport.open(db, remoteURI);
try {
try (Transport t = Transport.open(db, remoteURI)) {
try {
t.push(NullProgressMonitor.INSTANCE, push(src, Q));
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";
assertEquals(exp, nse.getMessage());
}
} finally {
t.close();
}
}
}

+ 4
- 2
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java View File

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


+ 38
- 87
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java View File

@@ -157,8 +157,7 @@ public class HttpClientTests extends HttpTestCase {
public void testRepositoryNotFound_Dumb() throws Exception {
URIish uri = toURIish("/dumb.none/not-found");
Repository dst = createBareRepository();
Transport t = Transport.open(dst, uri);
try {
try (Transport t = Transport.open(dst, uri)) {
try {
t.openFetch();
fail("connection opened to not found repository");
@@ -167,8 +166,6 @@ public class HttpClientTests extends HttpTestCase {
+ "/info/refs?service=git-upload-pack not found";
assertEquals(exp, err.getMessage());
}
} finally {
t.close();
}
}

@@ -176,8 +173,7 @@ public class HttpClientTests extends HttpTestCase {
public void testRepositoryNotFound_Smart() throws Exception {
URIish uri = toURIish("/smart.none/not-found");
Repository dst = createBareRepository();
Transport t = Transport.open(dst, uri);
try {
try (Transport t = Transport.open(dst, uri)) {
try {
t.openFetch();
fail("connection opened to not found repository");
@@ -186,8 +182,6 @@ public class HttpClientTests extends HttpTestCase {
+ "/info/refs?service=git-upload-pack not found";
assertEquals(exp, err.getMessage());
}
} finally {
t.close();
}
}

@@ -201,16 +195,9 @@ public class HttpClientTests extends HttpTestCase {

Repository dst = createBareRepository();
Ref head;
Transport t = Transport.open(dst, dumbAuthNoneURI);
try {
FetchConnection c = t.openFetch();
try {
head = c.getRef(Constants.HEAD);
} finally {
c.close();
}
} finally {
t.close();
try (Transport t = Transport.open(dst, dumbAuthNoneURI);
FetchConnection c = t.openFetch()) {
head = c.getRef(Constants.HEAD);
}
assertNotNull("has " + Constants.HEAD, head);
assertEquals(Q, head.getObjectId());
@@ -225,16 +212,9 @@ public class HttpClientTests extends HttpTestCase {

Repository dst = createBareRepository();
Ref head;
Transport t = Transport.open(dst, dumbAuthNoneURI);
try {
FetchConnection c = t.openFetch();
try {
head = c.getRef(Constants.HEAD);
} finally {
c.close();
}
} finally {
t.close();
try (Transport t = Transport.open(dst, dumbAuthNoneURI);
FetchConnection c = t.openFetch()) {
head = c.getRef(Constants.HEAD);
}
assertNull("has no " + Constants.HEAD, head);
}
@@ -249,16 +229,9 @@ public class HttpClientTests extends HttpTestCase {

Repository dst = createBareRepository();
Ref head;
Transport t = Transport.open(dst, smartAuthNoneURI);
try {
FetchConnection c = t.openFetch();
try {
head = c.getRef(Constants.HEAD);
} finally {
c.close();
}
} finally {
t.close();
try (Transport t = Transport.open(dst, smartAuthNoneURI);
FetchConnection c = t.openFetch()) {
head = c.getRef(Constants.HEAD);
}
assertNotNull("has " + Constants.HEAD, head);
assertEquals(Q, head.getObjectId());
@@ -268,16 +241,13 @@ public class HttpClientTests extends HttpTestCase {
public void testListRemote_Smart_WithQueryParameters() throws Exception {
URIish myURI = toURIish("/snone/do?r=1&p=test.git");
Repository dst = createBareRepository();
Transport t = Transport.open(dst, myURI);
try {
try (Transport t = Transport.open(dst, myURI)) {
try {
t.openFetch();
fail("test did not fail to find repository as expected");
} catch (NoRemoteRepositoryException err) {
// expected
}
} finally {
t.close();
}

List<AccessEvent> requests = getRequests();
@@ -296,62 +266,52 @@ public class HttpClientTests extends HttpTestCase {
@Test
public void testListRemote_Dumb_NeedsAuth() throws Exception {
Repository dst = createBareRepository();
Transport t = Transport.open(dst, dumbAuthBasicURI);
try {
try (Transport t = Transport.open(dst, dumbAuthBasicURI)) {
try {
t.openFetch();
fail("connection opened even info/refs needs auth basic");
} catch (TransportException err) {
String exp = dumbAuthBasicURI + ": "
+ JGitText.get().notAuthorized;
+ JGitText.get().noCredentialsProvider;
assertEquals(exp, err.getMessage());
}
} finally {
t.close();
}
}

@Test
public void testListRemote_Dumb_Auth() throws Exception {
Repository dst = createBareRepository();
Transport t = Transport.open(dst, dumbAuthBasicURI);
t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
AppServer.username, AppServer.password));
try {
t.openFetch();
} finally {
t.close();
try (Transport t = Transport.open(dst, dumbAuthBasicURI)) {
t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
AppServer.username, AppServer.password));
t.openFetch().close();
}
t = Transport.open(dst, dumbAuthBasicURI);
t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
AppServer.username, ""));
try {
t.openFetch();
fail("connection opened even info/refs needs auth basic and we provide wrong password");
} catch (TransportException err) {
String exp = dumbAuthBasicURI + ": "
+ JGitText.get().notAuthorized;
assertEquals(exp, err.getMessage());
} finally {
t.close();
try (Transport t = Transport.open(dst, dumbAuthBasicURI)) {
t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
AppServer.username, ""));
try {
t.openFetch();
fail("connection opened even info/refs needs auth basic and we provide wrong password");
} catch (TransportException err) {
String exp = dumbAuthBasicURI + ": "
+ JGitText.get().notAuthorized;
assertEquals(exp, err.getMessage());
}
}
}

@Test
public void testListRemote_Smart_UploadPackNeedsAuth() throws Exception {
Repository dst = createBareRepository();
Transport t = Transport.open(dst, smartAuthBasicURI);
try {
try (Transport t = Transport.open(dst, smartAuthBasicURI)) {
try {
t.openFetch();
fail("connection opened even though service disabled");
} catch (TransportException err) {
String exp = smartAuthBasicURI + ": "
+ JGitText.get().notAuthorized;
+ JGitText.get().noCredentialsProvider;
assertEquals(exp, err.getMessage());
}
} finally {
t.close();
}
}

@@ -363,33 +323,24 @@ public class HttpClientTests extends HttpTestCase {
cfg.save();

Repository dst = createBareRepository();
Transport t = Transport.open(dst, smartAuthNoneURI);
try {
try (Transport t = Transport.open(dst, smartAuthNoneURI)) {
try {
t.openFetch();
fail("connection opened even though service disabled");
} catch (TransportException err) {
String exp = smartAuthNoneURI + ": Git access forbidden";
String exp = smartAuthNoneURI + ": "
+ JGitText.get().serviceNotEnabledNoName;
assertEquals(exp, err.getMessage());
}
} finally {
t.close();
}
}

@Test
public void testListRemoteWithoutLocalRepository() throws Exception {
Transport t = Transport.open(smartAuthNoneURI);
try {
FetchConnection c = t.openFetch();
try {
Ref head = c.getRef(Constants.HEAD);
assertNotNull(head);
} finally {
c.close();
}
} finally {
t.close();
try (Transport t = Transport.open(smartAuthNoneURI);
FetchConnection c = t.openFetch()) {
Ref head = c.getRef(Constants.HEAD);
assertNotNull(head);
}
}
}

+ 11
- 47
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java View File

@@ -211,8 +211,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
assertEquals("http", remoteURI.getScheme());

Map<String, Ref> map;
Transport t = Transport.open(dst, remoteURI);
try {
try (Transport t = Transport.open(dst, remoteURI)) {
// I didn't make up these public interface names, I just
// approved them for inclusion into the code base. Sorry.
// --spearce
@@ -226,8 +225,6 @@ public class SmartClientSmartServerTest extends HttpTestCase {
} finally {
c.close();
}
} finally {
t.close();
}

assertNotNull("have map of refs", map);
@@ -257,8 +254,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
public void testListRemote_BadName() throws IOException, URISyntaxException {
Repository dst = createBareRepository();
URIish uri = new URIish(this.remoteURI.toString() + ".invalid");
Transport t = Transport.open(dst, uri);
try {
try (Transport t = Transport.open(dst, uri)) {
try {
t.openFetch();
fail("fetch connection opened");
@@ -266,8 +262,6 @@ public class SmartClientSmartServerTest extends HttpTestCase {
assertEquals(uri + ": Git repository not found",
notFound.getMessage());
}
} finally {
t.close();
}

List<AccessEvent> requests = getRequests();
@@ -288,11 +282,8 @@ public class SmartClientSmartServerTest extends HttpTestCase {
Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt));

Transport t = Transport.open(dst, remoteURI);
try {
try (Transport t = Transport.open(dst, remoteURI)) {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}

assertTrue(dst.hasObject(A_txt));
@@ -331,11 +322,8 @@ public class SmartClientSmartServerTest extends HttpTestCase {
// Bootstrap by doing the clone.
//
TestRepository dst = createTestRepository();
Transport t = Transport.open(dst.getRepository(), remoteURI);
try {
try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}
assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
List<AccessEvent> cloneRequests = getRequests();
@@ -352,11 +340,8 @@ public class SmartClientSmartServerTest extends HttpTestCase {

// Now incrementally update.
//
t = Transport.open(dst.getRepository(), remoteURI);
try {
try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}
assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());

@@ -394,11 +379,8 @@ public class SmartClientSmartServerTest extends HttpTestCase {
// Bootstrap by doing the clone.
//
TestRepository dst = createTestRepository();
Transport t = Transport.open(dst.getRepository(), remoteURI);
try {
try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}
assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
List<AccessEvent> cloneRequests = getRequests();
@@ -418,11 +400,8 @@ public class SmartClientSmartServerTest extends HttpTestCase {

// Now incrementally update.
//
t = Transport.open(dst.getRepository(), remoteURI);
try {
try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}
assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());

@@ -474,8 +453,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt));

Transport t = Transport.open(dst, brokenURI);
try {
try (Transport t = Transport.open(dst, brokenURI)) {
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
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";
assertEquals(exp, err.getMessage());
}
} finally {
t.close();
}

List<AccessEvent> requests = getRequests();
@@ -517,12 +493,10 @@ public class SmartClientSmartServerTest extends HttpTestCase {
final RevCommit Q = src.commit().add("Q", Q_txt).create();
final Repository db = src.getRepository();
final String dstName = Constants.R_HEADS + "new.branch";
Transport t;

// push anonymous shouldn't be allowed.
//
t = Transport.open(db, remoteURI);
try {
try (Transport t = Transport.open(db, remoteURI)) {
final String srcExpr = Q.name();
final boolean forceUpdate = false;
final String localName = null;
@@ -538,8 +512,6 @@ public class SmartClientSmartServerTest extends HttpTestCase {
+ JGitText.get().authenticationNotSupported;
assertEquals(exp, e.getMessage());
}
} finally {
t.close();
}

List<AccessEvent> requests = getRequests();
@@ -560,12 +532,10 @@ public class SmartClientSmartServerTest extends HttpTestCase {
final RevCommit Q = src.commit().add("Q", Q_txt).create();
final Repository db = src.getRepository();
final String dstName = Constants.R_HEADS + "new.branch";
Transport t;

enableReceivePack();

t = Transport.open(db, remoteURI);
try {
try (Transport t = Transport.open(db, remoteURI)) {
final String srcExpr = Q.name();
final boolean forceUpdate = false;
final String localName = null;
@@ -574,8 +544,6 @@ public class SmartClientSmartServerTest extends HttpTestCase {
RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
srcExpr, dstName, forceUpdate, localName, oldId);
t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
} finally {
t.close();
}

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 Repository db = src.getRepository();
final String dstName = Constants.R_HEADS + "new.branch";
Transport t;

enableReceivePack();

@@ -642,8 +609,7 @@ public class SmartClientSmartServerTest extends HttpTestCase {
cfg.setInt("http", null, "postbuffer", 8 * 1024);
cfg.save();

t = Transport.open(db, remoteURI);
try {
try (Transport t = Transport.open(db, remoteURI)) {
final String srcExpr = Q.name();
final boolean forceUpdate = false;
final String localName = null;
@@ -652,8 +618,6 @@ public class SmartClientSmartServerTest extends HttpTestCase {
RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
srcExpr, dstName, forceUpdate, localName, oldId);
t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
} finally {
t.close();
}

assertTrue(remoteRepository.hasObject(Q_bin));

+ 18
- 0
org.eclipse.jgit.junit.http/BUCK View File

@@ -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
- 0
org.eclipse.jgit.junit/BUCK View File

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

+ 4
- 5
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java View File

@@ -822,7 +822,7 @@ public class TestRepository<R extends Repository> {
break;

final byte[] bin = db.open(o, o.getType()).getCachedBytes();
oc.checkCommit(bin);
oc.checkCommit(o, bin);
assertHash(o, bin);
}

@@ -832,7 +832,7 @@ public class TestRepository<R extends Repository> {
break;

final byte[] bin = db.open(o, o.getType()).getCachedBytes();
oc.check(o.getType(), bin);
oc.check(o, o.getType(), bin);
assertHash(o, bin);
}
}
@@ -866,7 +866,7 @@ public class TestRepository<R extends Repository> {
Set<ObjectId> all = new HashSet<ObjectId>();
for (Ref r : db.getAllRefs().values())
all.add(r.getObjectId());
pw.preparePack(m, all, Collections.<ObjectId> emptySet());
pw.preparePack(m, all, PackWriter.NONE);

final ObjectId name = pw.computeName();

@@ -1155,8 +1155,7 @@ public class TestRepository<R extends Repository> {
return self;
}

private void insertChangeId(org.eclipse.jgit.lib.CommitBuilder c)
throws IOException {
private void insertChangeId(org.eclipse.jgit.lib.CommitBuilder c) {
if (changeId == null)
return;
int idx = ChangeIdUtil.indexOfChangeId(message, "\n");

+ 38
- 0
org.eclipse.jgit.pgm.test/BUCK View File

@@ -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
- 0
org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF View File

@@ -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.diff;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.lib;version="[4.2.0,4.3.0)",
org.eclipse.jgit.merge;version="[4.2.0,4.3.0)",

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

@@ -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>

+ 77
- 6
org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java View File

@@ -46,12 +46,16 @@ import static org.junit.Assert.assertEquals;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.pgm.CLIGitCommand;
import org.eclipse.jgit.pgm.CLIGitCommand.Result;
import org.eclipse.jgit.pgm.TextBuiltin.TerminatedByHelpException;
import org.junit.Before;

public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase {
@@ -69,13 +73,59 @@ public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase {
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 {
List<String> result = new ArrayList<String>(cmds.length);
for (String cmd : cmds)
result.addAll(CLIGitCommand.execute(cmd, db));
for (String cmd : cmds) {
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]);
}

/**
* @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)
throws IOException {
return JGitTestUtil.writeTrashFile(db, name, data);
@@ -173,15 +223,36 @@ public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase {
}

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();
for (String s : lines) {
b.append(s);
b.append('\n');
// trim indentation, to simplify tests
s = s.trim();
if (s != null && !s.isEmpty()) {
b.append(s);
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();
}

public static boolean contains(List<String> lines, String str) {
for (String s : lines) {
if (s.contains(str)) {
return true;
}
}
return false;
}
}

+ 139
- 38
org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java View File

@@ -42,71 +42,140 @@
*/
package org.eclipse.jgit.pgm;

import static org.junit.Assert.assertNull;

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.List;

import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.pgm.opt.CmdLineParser;
import org.eclipse.jgit.pgm.opt.SubcommandHandler;
import org.eclipse.jgit.pgm.TextBuiltin.TerminatedByHelpException;
import org.eclipse.jgit.util.IO;
import org.kohsuke.args4j.Argument;

public class CLIGitCommand {
@Argument(index = 0, metaVar = "metaVar_command", required = true, handler = SubcommandHandler.class)
private TextBuiltin subcommand;
public class CLIGitCommand extends Main {

@Argument(index = 1, metaVar = "metaVar_arg")
private List<String> arguments = new ArrayList<String>();
private final Result result;

public TextBuiltin getSubcommand() {
return subcommand;
private final Repository db;

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)
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 {
return IO.readLines(new String(rawExecute(str, db)));
} catch (Die e) {
return IO.readLines(MessageFormat.format(CLIText.get().fatalError,
e.getMessage()));
super.run(argv);
} catch (TerminatedByHelpException e) {
// this is not a failure, super called exit() on help
} finally {
writer.flush();
}
}

public static byte[] rawExecute(String str, Repository db)
private static String[] convertToMainArgs(String str)
throws Exception {
String[] args = split(str);
if (!args[0].equalsIgnoreCase("git") || args.length < 2)
if (!args[0].equalsIgnoreCase("git") || args.length < 2) {
throw new IllegalArgumentException(
"Expected 'git <command> [<args>]', was:" + str);
}
String[] argv = new String[args.length - 1];
System.arraycopy(args, 1, argv, 0, args.length - 1);
return argv;
}

CLIGitCommand bean = new CLIGitCommand();
final CmdLineParser clp = new CmdLineParser(bean);
clp.parseArgument(argv);

final TextBuiltin cmd = bean.getSubcommand();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
cmd.outs = baos;
if (cmd.requiresRepository())
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();
@Override
PrintWriter createErrorWriter() {
return new PrintWriter(result.err);
}

void init(final TextBuiltin cmd) throws IOException {
cmd.outs = result.out;
cmd.errs = result.err;
super.init(cmd);
}

@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));
}
return baos.toByteArray();
result.ex = t;
throw t;
}

/**
@@ -164,4 +233,36 @@ public class CLIGitCommand {
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());
}
}

}

+ 7
- 8
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/AddTest.java View File

@@ -45,15 +45,12 @@ package org.eclipse.jgit.pgm;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.lang.Exception;
import java.lang.String;
import static org.junit.Assert.fail;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

public class AddTest extends CLIRepositoryTestCase {
@@ -66,14 +63,16 @@ public class AddTest extends CLIRepositoryTestCase {
git = new Git(db);
}

@Ignore("args4j exit()s on error instead of throwing, JVM goes down")
@Test
public void testAddNothing() throws Exception {
assertEquals("fatal: Argument \"filepattern\" is required", //
execute("git add")[0]);
try {
execute("git add");
fail("Must die");
} catch (Die e) {
// expected, requires argument
}
}

@Ignore("args4j exit()s for --help, too")
@Test
public void testAddUsage() throws Exception {
execute("git add --help");

+ 46
- 49
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java View File

@@ -52,17 +52,15 @@ import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.Object;
import java.lang.String;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.zip.ZipEntry;
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.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.pgm.CLIGitCommand;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

public class ArchiveTest extends CLIRepositoryTestCase {
@@ -89,25 +85,26 @@ public class ArchiveTest extends CLIRepositoryTestCase {
emptyTree = db.resolve("HEAD^{tree}").abbreviate(12).name();
}

@Ignore("Some versions of java.util.zip refuse to write an empty ZIP")
@Test
public void testEmptyArchive() throws Exception {
byte[] result = CLIGitCommand.rawExecute(
"git archive --format=zip " + emptyTree, db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --format=zip " + emptyTree, db).outBytes();
assertArrayEquals(new String[0], listZipEntries(result));
}

@Test
public void testEmptyTar() throws Exception {
byte[] result = CLIGitCommand.rawExecute(
"git archive --format=tar " + emptyTree, db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --format=tar " + emptyTree, db).outBytes();
assertArrayEquals(new String[0], listTarEntries(result));
}

@Test
public void testUnrecognizedFormat() throws Exception {
String[] expect = new String[] { "fatal: Unknown archive format 'nonsense'" };
String[] actual = execute("git archive --format=nonsense " + emptyTree);
String[] expect = new String[] {
"fatal: Unknown archive format 'nonsense'", "" };
String[] actual = executeUnchecked(
"git archive --format=nonsense " + emptyTree);
assertArrayEquals(expect, actual);
}

@@ -120,8 +117,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("c").call();
git.commit().setMessage("populate toplevel").call();

byte[] result = CLIGitCommand.rawExecute(
"git archive --format=zip HEAD", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --format=zip HEAD", db).outBytes();
assertArrayEquals(new String[] { "a", "c" },
listZipEntries(result));
}
@@ -135,8 +132,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test
public void testDefaultFormatIsTar() throws Exception {
commitGreeting();
byte[] result = CLIGitCommand.rawExecute(
"git archive HEAD", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive HEAD", db).outBytes();
assertArrayEquals(new String[] { "greeting" },
listTarEntries(result));
}
@@ -302,8 +299,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("b").call();
git.commit().setMessage("add subdir").call();

byte[] result = CLIGitCommand.rawExecute(
"git archive --format=zip master", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --format=zip master", db).outBytes();
String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" };
String[] actual = listZipEntries(result);

@@ -328,8 +325,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("b").call();
git.commit().setMessage("add subdir").call();

byte[] result = CLIGitCommand.rawExecute(
"git archive --format=tar master", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --format=tar master", db).outBytes();
String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" };
String[] actual = listTarEntries(result);

@@ -349,8 +346,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test
public void testArchivePrefixOption() throws Exception {
commitBazAndFooSlashBar();
byte[] result = CLIGitCommand.rawExecute(
"git archive --prefix=x/ --format=zip master", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=x/ --format=zip master", db).outBytes();
String[] expect = { "x/baz", "x/foo/", "x/foo/bar" };
String[] actual = listZipEntries(result);

@@ -362,8 +359,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test
public void testTarPrefixOption() throws Exception {
commitBazAndFooSlashBar();
byte[] result = CLIGitCommand.rawExecute(
"git archive --prefix=x/ --format=tar master", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=x/ --format=tar master", db).outBytes();
String[] expect = { "x/baz", "x/foo/", "x/foo/bar" };
String[] actual = listTarEntries(result);

@@ -381,8 +378,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test
public void testPrefixDoesNotNormalizeDoubleSlash() throws Exception {
commitFoo();
byte[] result = CLIGitCommand.rawExecute(
"git archive --prefix=x// --format=zip master", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=x// --format=zip master", db).outBytes();
String[] expect = { "x//foo" };
assertArrayEquals(expect, listZipEntries(result));
}
@@ -390,8 +387,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test
public void testPrefixDoesNotNormalizeDoubleSlashInTar() throws Exception {
commitFoo();
byte[] result = CLIGitCommand.rawExecute(
"git archive --prefix=x// --format=tar master", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=x// --format=tar master", db).outBytes();
String[] expect = { "x//foo" };
assertArrayEquals(expect, listTarEntries(result));
}
@@ -408,8 +405,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test
public void testPrefixWithoutTrailingSlash() throws Exception {
commitBazAndFooSlashBar();
byte[] result = CLIGitCommand.rawExecute(
"git archive --prefix=my- --format=zip master", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=my- --format=zip master", db).outBytes();
String[] expect = { "my-baz", "my-foo/", "my-foo/bar" };
String[] actual = listZipEntries(result);

@@ -421,8 +418,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
@Test
public void testTarPrefixWithoutTrailingSlash() throws Exception {
commitBazAndFooSlashBar();
byte[] result = CLIGitCommand.rawExecute(
"git archive --prefix=my- --format=tar master", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --prefix=my- --format=tar master", db).outBytes();
String[] expect = { "my-baz", "my-foo/", "my-foo/bar" };
String[] actual = listTarEntries(result);

@@ -441,8 +438,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.submoduleAdd().setURI("./.").setPath("b").call().close();
git.commit().setMessage("add submodule").call();

byte[] result = CLIGitCommand.rawExecute(
"git archive --format=zip master", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --format=zip master", db).outBytes();
String[] expect = { ".gitmodules", "a", "b/", "c" };
String[] actual = listZipEntries(result);

@@ -461,8 +458,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.submoduleAdd().setURI("./.").setPath("b").call().close();
git.commit().setMessage("add submodule").call();

byte[] result = CLIGitCommand.rawExecute(
"git archive --format=tar master", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --format=tar master", db).outBytes();
String[] expect = { ".gitmodules", "a", "b/", "c" };
String[] actual = listTarEntries(result);

@@ -491,8 +488,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {

git.commit().setMessage("three files with different modes").call();

byte[] zipData = CLIGitCommand.rawExecute(
"git archive --format=zip master", db);
byte[] zipData = CLIGitCommand.executeRaw(
"git archive --format=zip master", db).outBytes();
writeRaw("zip-with-modes.zip", zipData);
assertContainsEntryWithMode("zip-with-modes.zip", "-rw-", "plain");
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();

byte[] archive = CLIGitCommand.rawExecute(
"git archive --format=tar master", db);
byte[] archive = CLIGitCommand.executeRaw(
"git archive --format=tar master", db).outBytes();
writeRaw("with-modes.tar", archive);
assertTarContainsEntry("with-modes.tar", "-rw-r--r--", "plain");
assertTarContainsEntry("with-modes.tar", "-rwxr-xr-x", "executable");
@@ -543,8 +540,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("1234567890").call();
git.commit().setMessage("file with long name").call();

byte[] result = CLIGitCommand.rawExecute(
"git archive --format=zip HEAD", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --format=zip HEAD", db).outBytes();
assertArrayEquals(l.toArray(new String[l.size()]),
listZipEntries(result));
}
@@ -563,8 +560,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("1234567890").call();
git.commit().setMessage("file with long name").call();

byte[] result = CLIGitCommand.rawExecute(
"git archive --format=tar HEAD", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --format=tar HEAD", db).outBytes();
assertArrayEquals(l.toArray(new String[l.size()]),
listTarEntries(result));
}
@@ -576,8 +573,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("xyzzy").call();
git.commit().setMessage("add file with content").call();

byte[] result = CLIGitCommand.rawExecute(
"git archive --format=zip HEAD", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --format=zip HEAD", db).outBytes();
assertArrayEquals(new String[] { payload },
zipEntryContent(result, "xyzzy"));
}
@@ -589,8 +586,8 @@ public class ArchiveTest extends CLIRepositoryTestCase {
git.add().addFilepattern("xyzzy").call();
git.commit().setMessage("add file with content").call();

byte[] result = CLIGitCommand.rawExecute(
"git archive --format=tar HEAD", db);
byte[] result = CLIGitCommand.executeRaw(
"git archive --format=tar HEAD", db).outBytes();
assertArrayEquals(new String[] { payload },
tarEntryContent(result, "xyzzy"));
}

+ 187
- 9
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/BranchTest.java View File

@@ -43,11 +43,17 @@
package org.eclipse.jgit.pgm;

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.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
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
public void testList() throws Exception {
assertEquals("* master", toString(execute("git branch")));
assertEquals("* master 6fd41be initial commit",
execute("git branch -v")[0]);
toString(execute("git branch -v")));
}

@Test
@@ -73,26 +89,188 @@ public class BranchTest extends CLIRepositoryTestCase {
RefUpdate updateRef = db.updateRef(Constants.HEAD, true);
updateRef.setNewObjectId(db.resolve("6fd41be"));
updateRef.update();
assertEquals("* (no branch) 6fd41be initial commit",
execute("git branch -v")[0]);
assertEquals(
toString("* (no branch) 6fd41be initial commit",
"master 6fd41be initial commit"),
toString(execute("git branch -v")));
}

@Test
public void testListContains() throws Exception {
try (Git git = new Git(db)) {
git.branchCreate().setName("initial").call();
git.branchCreate().setName("initial").call();
RevCommit second = git.commit().setMessage("second commit")
.call();
assertArrayOfLinesEquals(new String[] { " initial", "* master", "" },
execute("git branch --contains 6fd41be"));
assertArrayOfLinesEquals(new String[] { "* master", "" },
execute("git branch --contains " + second.name()));
assertEquals(toString(" initial", "* master"),
toString(execute("git branch --contains 6fd41be")));
assertEquals("* master",
toString(execute("git branch --contains " + second.name())));
}
}

@Test
public void testExistingBranch() throws Exception {
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());
}
}

+ 39
- 2
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java View File

@@ -44,9 +44,14 @@ package org.eclipse.jgit.pgm;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;

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.FileEntry;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
import org.junit.Assume;
import org.junit.Test;

public class CheckoutTest extends CLIRepositoryTestCase {
@@ -109,14 +116,14 @@ public class CheckoutTest extends CLIRepositoryTestCase {

assertStringArrayEquals(
"fatal: A branch named 'master' already exists.",
execute("git checkout -b master"));
executeUnchecked("git checkout -b master"));
}
}

@Test
public void testCheckoutNewBranchOnBranchToBeBorn() throws Exception {
assertStringArrayEquals("fatal: You are on a branch yet to be born",
execute("git checkout -b side"));
executeUnchecked("git checkout -b side"));
}

@Test
@@ -599,4 +606,34 @@ public class CheckoutTest extends CLIRepositoryTestCase {
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
- 0
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CommitTest.java View File

@@ -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);
}

}

+ 28
- 6
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java View File

@@ -43,9 +43,15 @@
package org.eclipse.jgit.pgm;

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.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.junit.Before;
import org.junit.Test;

@@ -67,17 +73,15 @@ public class DescribeTest extends CLIRepositoryTestCase {

@Test
public void testNoHead() throws Exception {
assertArrayEquals(
new String[] { "fatal: No names found, cannot describe anything." },
execute("git describe"));
assertEquals(CLIText.fatalError(CLIText.get().noNamesFound),
toString(executeUnchecked("git describe")));
}

@Test
public void testHeadNoTag() throws Exception {
git.commit().setMessage("initial commit").call();
assertArrayEquals(
new String[] { "fatal: No names found, cannot describe anything." },
execute("git describe"));
assertEquals(CLIText.fatalError(CLIText.get().noNamesFound),
toString(executeUnchecked("git describe")));
}

@Test
@@ -103,4 +107,22 @@ public class DescribeTest extends CLIRepositoryTestCase {
assertArrayEquals(new String[] { "v1.0-0-g6fd41be", "" },
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"));
}
}

+ 6
- 4
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeTest.java View File

@@ -50,6 +50,7 @@ import java.util.Iterator;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
import org.junit.Test;
@@ -194,8 +195,9 @@ public class MergeTest extends CLIRepositoryTestCase {

@Test
public void testNoFastForwardAndSquash() throws Exception {
assertEquals("fatal: You cannot combine --squash with --no-ff.",
execute("git merge master --no-ff --squash")[0]);
assertEquals(
CLIText.fatalError(CLIText.get().cannotCombineSquashWithNoff),
executeUnchecked("git merge master --no-ff --squash")[0]);
}

@Test
@@ -209,8 +211,8 @@ public class MergeTest extends CLIRepositoryTestCase {
git.add().addFilepattern("file").call();
git.commit().setMessage("commit#2").call();

assertEquals("fatal: Not possible to fast-forward, aborting.",
execute("git merge master --ff-only")[0]);
assertEquals(CLIText.fatalError(CLIText.get().ffNotPossibleAborting),
executeUnchecked("git merge master --ff-only")[0]);
}

@Test

+ 28
- 0
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RepoTest.java View File

@@ -44,8 +44,11 @@ package org.eclipse.jgit.pgm;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.File;
import java.util.Arrays;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
@@ -97,6 +100,31 @@ public class RepoTest extends CLIRepositoryTestCase {
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
public void testAddRepoManifest() throws Exception {
StringBuilder xmlContent = new StringBuilder();

+ 34
- 5
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java View File

@@ -48,6 +48,7 @@ import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

public class ResetTest extends CLIRepositoryTestCase {
@@ -61,6 +62,20 @@ public class ResetTest extends CLIRepositoryTestCase {
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
public void testResetSelf() throws Exception {
RevCommit commit = git.commit().setMessage("initial commit").call();
@@ -91,15 +106,28 @@ public class ResetTest extends CLIRepositoryTestCase {

@Test
public void testResetPathDoubleDash() throws Exception {
resetPath(true);
resetPath(true, true);
}

@Test
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
writeTrashFile("a", "Hello world a");
writeTrashFile("b", "Hello world b");
@@ -115,8 +143,9 @@ public class ResetTest extends CLIRepositoryTestCase {
git.add().addFilepattern(".").call();

// reset only file a
String cmd = String.format("git reset %s%s a", commit.getId().name(),
(useDoubleDash) ? " --" : "");
String cmd = String.format("git reset %s%s a",
supplyCommit ? commit.getId().name() : "",
useDoubleDash ? " --" : "");
assertStringArrayEquals("", execute(cmd));
assertEquals(commit.getId(),
git.getRepository().exactRef("HEAD").getObjectId());

+ 8
- 0
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java View File

@@ -44,6 +44,7 @@ package org.eclipse.jgit.pgm;

import static org.eclipse.jgit.lib.Constants.MASTER;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.junit.Assert.assertTrue;

import java.io.IOException;

@@ -55,6 +56,13 @@ import org.junit.Test;

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
public void testStatusDefault() throws Exception {
executeTest("git status", false, true);

+ 1
- 1
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java View File

@@ -68,6 +68,6 @@ public class TagTest extends CLIRepositoryTestCase {
git.commit().setMessage("commit").call();

assertEquals("fatal: tag 'test' already exists",
execute("git tag test")[0]);
executeUnchecked("git tag test")[0]);
}
}

+ 70
- 0
org.eclipse.jgit.pgm/BUCK View File

@@ -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
- 0
org.eclipse.jgit.pgm/META-INF/MANIFEST.MF View File

@@ -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.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.reftree;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.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.pack;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.treewalk;version="[4.2.0,4.3.0)",
org.eclipse.jgit.treewalk.filter;version="[4.2.0,4.3.0)",

+ 1
- 0
org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin View File

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

+ 11
- 0
org.eclipse.jgit.pgm/pom.xml View File

@@ -94,6 +94,17 @@
<version>${project.version}</version>
</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>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>

+ 8
- 0
org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties View File

@@ -20,6 +20,7 @@ branchAlreadyExists=A branch named ''{0}'' already exists.
branchCreatedFrom=branch: Created from {0}
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}''.
branchNameRequired=branch name required
branchNotFound=branch ''{0}'' not found.
cacheTreePathInfo="{0}": {1} entries, {2} children
cannotBeRenamed={0} cannot be renamed
@@ -89,7 +90,9 @@ metaVar_author=AUTHOR
metaVar_base=base
metaVar_blameL=START,END
metaVar_blameReverse=START..END
metaVar_branchAndStartPoint=branch [start-name]
metaVar_branchName=branch
metaVar_branchNames=branch ...
metaVar_bucket=BUCKET
metaVar_command=command
metaVar_commandDetail=DETAIL
@@ -109,6 +112,7 @@ metaVar_message=message
metaVar_n=n
metaVar_name=name
metaVar_object=object
metaVar_oldNewBranchNames=[oldbranch] newbranch
metaVar_op=OP
metaVar_pass=PASS
metaVar_path=path
@@ -125,6 +129,7 @@ metaVar_treeish=tree-ish
metaVar_uriish=uri-ish
metaVar_url=URL
metaVar_user=USER
metaVar_values=value ...
metaVar_version=VERSION
mostCommonlyUsedCommandsAre=The most commonly used commands are:
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_ReadDirCache= Read the DirCache 100 times
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_RepositoryToReadFrom=Repository to read from
usage_RepositoryToReceiveInto=Repository to receive into
@@ -337,6 +343,7 @@ usage_recordChangesToRepository=Record changes to the repository
usage_recurseIntoSubtrees=recurse into subtrees
usage_renameLimit=limit size of rename matrix
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_resetSoft=Resets without touching the index file nor 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_tagMessage=tag message
usage_untrackedFilesMode=show untracked files
usage_updateRef=reference to update
usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository
usage_useNameInsteadOfOriginToTrackUpstream=use <name> instead of 'origin' to track upstream
usage_checkoutBranchAfterClone=checkout named branch instead of remotes's HEAD

+ 94
- 36
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java View File

@@ -45,7 +45,6 @@ package org.eclipse.jgit.pgm;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
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.Repository;
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.kohsuke.args4j.Argument;
import org.kohsuke.args4j.ExampleMode;
import org.kohsuke.args4j.Option;

@Command(common = true, usage = "usage_listCreateOrDeleteBranches")
class Branch extends TextBuiltin {

private String otherBranch;
private boolean createForce;
private boolean rename;

@Option(name = "--remote", aliases = { "-r" }, usage = "usage_actOnRemoteTrackingBranches")
private boolean remote = false;

@@ -83,23 +85,69 @@ class Branch extends TextBuiltin {
@Option(name = "--contains", metaVar = "metaVar_commitish", usage = "usage_printOnlyBranchesThatContainTheCommit")
private String containsCommitish;

@Option(name = "--delete", aliases = { "-d" }, usage = "usage_deleteFullyMergedBranch")
private boolean delete = false;
private List<String> delete;

@Option(name = "--delete-force", aliases = { "-D" }, usage = "usage_deleteBranchEvenIfNotMerged")
private boolean deleteForce = 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 = "--create-force", aliases = { "-f" }, usage = "usage_forceCreateBranchEvenExists")
private boolean createForce = false;
private List<String> deleteForce;

@Option(name = "-m", usage = "usage_moveRenameABranch")
private boolean rename = false;
@Option(name = "--delete-force", aliases = {
"-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 = "--create-force", aliases = {
"-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")
private boolean verbose = false;

@Argument
private List<String> branches = new ArrayList<String>();
@Argument(metaVar = "metaVar_name")
private String branch;

private final Map<String, Ref> printRefs = new LinkedHashMap<String, Ref>();

@@ -110,30 +158,33 @@ class Branch extends TextBuiltin {

@Override
protected void run() throws Exception {
if (delete || deleteForce)
delete(deleteForce);
else {
if (branches.size() > 2)
throw die(CLIText.get().tooManyRefsGiven + new CmdLineParser(this).printExample(ExampleMode.ALL));

if (delete != null || deleteForce != null) {
if (delete != null) {
delete(delete, false);
}
if (deleteForce != null) {
delete(deleteForce, true);
}
} else {
if (rename) {
String src, dst;
if (branches.size() == 1) {
if (otherBranch == null) {
final Ref head = db.getRef(Constants.HEAD);
if (head != null && head.isSymbolic())
if (head != null && head.isSymbolic()) {
src = head.getLeaf().getName();
else
} else {
throw die(CLIText.get().cannotRenameDetachedHEAD);
dst = branches.get(0);
}
dst = branch;
} else {
src = branches.get(0);
src = branch;
final Ref old = db.getRef(src);
if (old == null)
throw die(MessageFormat.format(CLIText.get().doesNotExist, src));
if (!old.getName().startsWith(Constants.R_HEADS))
throw die(MessageFormat.format(CLIText.get().notABranch, src));
src = old.getName();
dst = branches.get(1);
dst = otherBranch;
}

if (!dst.startsWith(Constants.R_HEADS))
@@ -145,13 +196,14 @@ class Branch extends TextBuiltin {
if (r.rename() != Result.RENAMED)
throw die(MessageFormat.format(CLIText.get().cannotBeRenamed, src));

} else if (branches.size() > 0) {
String newHead = branches.get(0);
} else if (createForce || branch != null) {
String newHead = branch;
String startBranch;
if (branches.size() == 2)
startBranch = branches.get(1);
else
if (createForce) {
startBranch = otherBranch;
} else {
startBranch = Constants.HEAD;
}
Ref startRef = db.getRef(startBranch);
ObjectId startAt = db.resolve(startBranch + "^0"); //$NON-NLS-1$
if (startRef != null) {
@@ -164,22 +216,27 @@ class Branch extends TextBuiltin {
}
startBranch = Repository.shortenRefName(startBranch);
String newRefName = newHead;
if (!newRefName.startsWith(Constants.R_HEADS))
if (!newRefName.startsWith(Constants.R_HEADS)) {
newRefName = Constants.R_HEADS + newRefName;
if (!Repository.isValidRefName(newRefName))
}
if (!Repository.isValidRefName(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));
}
RefUpdate updateRef = db.updateRef(newRefName);
updateRef.setNewObjectId(startAt);
updateRef.setForceUpdate(createForce);
updateRef.setRefLogMessage(MessageFormat.format(CLIText.get().branchCreatedFrom, startBranch), false);
Result update = updateRef.update();
if (update == Result.REJECTED)
if (update == Result.REJECTED) {
throw die(MessageFormat.format(CLIText.get().couldNotCreateBranch, newHead, update.toString()));
}
} else {
if (verbose)
if (verbose) {
rw = new RevWalk(db);
}
list();
}
}
@@ -249,7 +306,8 @@ class Branch extends TextBuiltin {
outw.println();
}

private void delete(boolean force) throws IOException {
private void delete(List<String> branches, boolean force)
throws IOException {
String current = db.getBranch();
ObjectId head = db.resolve(Constants.HEAD);
for (String branch : branches) {

+ 3
- 4
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java View File

@@ -60,7 +60,7 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.spi.StopOptionHandler;
import org.kohsuke.args4j.spi.RestOfArgumentsHandler;

@Command(common = true, usage = "usage_checkout")
class Checkout extends TextBuiltin {
@@ -74,11 +74,10 @@ class Checkout extends TextBuiltin {
@Option(name = "--orphan", usage = "usage_orphan")
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;

@Argument(index = 1)
@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>();

@Override

+ 16
- 5
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java View File

@@ -50,6 +50,7 @@ import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.TextProgressMonitor;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.SystemReader;
@@ -70,6 +71,9 @@ class Clone extends AbstractFetchCommand {
@Option(name = "--bare", usage = "usage_bareClone")
private boolean isBare;

@Option(name = "--quiet", usage = "usage_quiet")
private Boolean quiet;

@Argument(index = 0, required = true, metaVar = "metaVar_uriish")
private String sourceUri;

@@ -109,10 +113,16 @@ class Clone extends AbstractFetchCommand {

command.setGitDir(gitdir == null ? null : new File(gitdir));
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 {
db = command.call().getRepository();
if (db.resolve(Constants.HEAD) == null)
if (msgs && db.resolve(Constants.HEAD) == null)
outw.println(CLIText.get().clonedEmptyRepository);
} catch (InvalidRemoteException e) {
throw die(MessageFormat.format(CLIText.get().doesNotExist,
@@ -121,8 +131,9 @@ class Clone extends AbstractFetchCommand {
if (db != null)
db.close();
}

outw.println();
outw.flush();
if (msgs) {
outw.println();
outw.flush();
}
}
}

+ 15
- 0
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java View File

@@ -86,6 +86,21 @@ public class Die extends RuntimeException {
* @since 3.4
*/
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;
}


+ 95
- 36
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java View File

@@ -62,6 +62,8 @@ import org.eclipse.jgit.lib.RepositoryBuilder;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.pgm.opt.CmdLineParser;
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.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
@@ -88,13 +90,23 @@ public class Main {
@Argument(index = 1, metaVar = "metaVar_arg")
private List<String> arguments = new ArrayList<String>();

PrintWriter writer;

/**
*
*/
public Main() {
HttpTransport.setConnectionFactory(new HttpClientConnectionFactory());
}

/**
* Execute the command line.
*
* @param argv
* arguments.
* @throws Exception
*/
public static void main(final String[] argv) {
public static void main(final String[] argv) throws Exception {
new Main().run(argv);
}

@@ -113,8 +125,10 @@ public class Main {
*
* @param argv
* arguments.
* @throws Exception
*/
protected void run(final String[] argv) {
protected void run(final String[] argv) throws Exception {
writer = createErrorWriter();
try {
if (!installConsole()) {
AwtAuthenticator.install();
@@ -123,12 +137,14 @@ public class Main {
configureHttpProxy();
execute(argv);
} catch (Die err) {
if (err.isAborted())
System.exit(1);
System.err.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage()));
if (showStackTrace)
err.printStackTrace();
System.exit(128);
if (err.isAborted()) {
exit(1, err);
}
writer.println(CLIText.fatalError(err.getMessage()));
if (showStackTrace) {
err.printStackTrace(writer);
}
exit(128, err);
} catch (Exception err) {
// Try to detect errno == EPIPE and exit normally if that happens
// There may be issues with operating system versions and locale,
@@ -136,46 +152,54 @@ public class Main {
// under other circumstances.
if (err.getClass() == IOException.class) {
// Linux, OS X
if (err.getMessage().equals("Broken pipe")) //$NON-NLS-1$
System.exit(0);
if (err.getMessage().equals("Broken pipe")) { //$NON-NLS-1$
exit(0, err);
}
// Windows
if (err.getMessage().equals("The pipe is being closed")) //$NON-NLS-1$
System.exit(0);
if (err.getMessage().equals("The pipe is being closed")) { //$NON-NLS-1$
exit(0, err);
}
}
if (!showStackTrace && err.getCause() != null
&& err instanceof TransportException)
System.err.println(MessageFormat.format(CLIText.get().fatalError, err.getCause().getMessage()));
&& err instanceof TransportException) {
writer.println(CLIText.fatalError(err.getCause().getMessage()));
}

if (err.getClass().getName().startsWith("org.eclipse.jgit.errors.")) { //$NON-NLS-1$
System.err.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage()));
if (showStackTrace)
writer.println(CLIText.fatalError(err.getMessage()));
if (showStackTrace) {
err.printStackTrace();
System.exit(128);
}
exit(128, err);
}
err.printStackTrace();
System.exit(1);
exit(1, err);
}
if (System.out.checkError()) {
System.err.println(CLIText.get().unknownIoErrorStdout);
System.exit(1);
writer.println(CLIText.get().unknownIoErrorStdout);
exit(1, null);
}
if (System.err.checkError()) {
if (writer.checkError()) {
// No idea how to present an error here, most likely disk full or
// broken pipe
System.exit(1);
exit(1, null);
}
}

PrintWriter createErrorWriter() {
return new PrintWriter(System.err);
}

private void execute(final String[] argv) throws Exception {
final CmdLineParser clp = new CmdLineParser(this);
PrintWriter writer = new PrintWriter(System.err);
final CmdLineParser clp = new SubcommandLineParser(this);
try {
clp.parseArgument(argv);
} catch (CmdLineException err) {
if (argv.length > 0 && !help && !version) {
writer.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage()));
writer.println(CLIText.fatalError(err.getMessage()));
writer.flush();
System.exit(1);
exit(1, err);
}
}

@@ -191,22 +215,24 @@ public class Main {
writer.println(CLIText.get().mostCommonlyUsedCommandsAre);
final CommandRef[] common = CommandCatalog.common();
int width = 0;
for (final CommandRef c : common)
for (final CommandRef c : common) {
width = Math.max(width, c.getName().length());
}
width += 2;

for (final CommandRef c : common) {
writer.print(' ');
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(CLIText.get().resourceBundle().getString(c.getUsage()));
writer.println();
}
writer.println();
}
writer.flush();
System.exit(1);
exit(1, null);
}

if (version) {
@@ -215,20 +241,38 @@ public class Main {
}

final TextBuiltin cmd = subcommand;
if (cmd.requiresRepository())
cmd.init(openGitDir(gitdir), null);
else
cmd.init(null, gitdir);
init(cmd);
try {
cmd.execute(arguments.toArray(new String[arguments.size()]));
} finally {
if (cmd.outw != null)
if (cmd.outw != null) {
cmd.outw.flush();
if (cmd.errw != null)
}
if (cmd.errw != null) {
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.
*
@@ -278,7 +322,7 @@ public class Main {
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException, ClassNotFoundException {
try {
Class.forName(name).getMethod("install").invoke(null); //$NON-NLS-1$
Class.forName(name).getMethod("install").invoke(null); //$NON-NLS-1$
} catch (InvocationTargetException e) {
if (e.getCause() instanceof RuntimeException)
throw (RuntimeException) e.getCause();
@@ -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;
}
}
}

+ 6
- 3
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java View File

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

+ 1
- 2
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java View File

@@ -144,7 +144,7 @@ class Remote extends TextBuiltin {
}

@Override
public void printUsageAndExit(final String message, final CmdLineParser clp)
public void printUsage(final String message, final CmdLineParser clp)
throws IOException {
errw.println(message);
errw.println("jgit remote [--verbose (-v)] [--help (-h)]"); //$NON-NLS-1$
@@ -160,7 +160,6 @@ class Remote extends TextBuiltin {
errw.println();

errw.flush();
throw die(true);
}

private void print(List<RemoteConfig> remotes) throws IOException {

+ 1
- 1
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java View File

@@ -55,7 +55,7 @@ class Repo extends TextBuiltin {
@Option(name = "--groups", aliases = { "-g" }, usage = "usage_groups")
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;

@Option(name = "--record-remote-branch", usage = "usage_branches")

+ 5
- 5
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java View File

@@ -51,7 +51,7 @@ import org.eclipse.jgit.api.ResetCommand;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.spi.StopOptionHandler;
import org.kohsuke.args4j.spi.RestOfArgumentsHandler;

@Command(common = true, usage = "usage_reset")
class Reset extends TextBuiltin {
@@ -65,12 +65,12 @@ class Reset extends TextBuiltin {
@Option(name = "--hard", usage = "usage_resetHard")
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;

@Argument(index = 1)
@Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = StopOptionHandler.class)
private List<String> paths = new ArrayList<String>();
@Argument(required = false, index = 1, metaVar = "metaVar_paths")
@Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = RestOfArgumentsHandler.class)
private List<String> paths = new ArrayList<>();

@Override
protected void run() throws Exception {

+ 7
- 1
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java View File

@@ -75,7 +75,13 @@ class RevParse extends TextBuiltin {
if (all) {
Map<String, Ref> allRefs = db.getRefDatabase().getRefs(ALL);
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 {
if (verify && commits.size() > 1) {

+ 4
- 2
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java View File

@@ -59,8 +59,9 @@ import org.eclipse.jgit.lib.IndexDiff.StageState;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.spi.RestOfArgumentsHandler;
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)
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;

@Override

+ 76
- 7
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java View File

@@ -212,17 +212,20 @@ public abstract class TextBuiltin {
*/
protected void parseArguments(final String[] args) throws IOException {
final CmdLineParser clp = new CmdLineParser(this);
help = containsHelp(args);
try {
clp.parseArgument(args);
} catch (CmdLineException err) {
if (!help) {
this.errw.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage()));
throw die(true);
this.errw.println(CLIText.fatalError(err.getMessage()));
if (help) {
printUsage("", clp); //$NON-NLS-1$
}
throw die(true, err);
}

if (help) {
printUsageAndExit(clp);
printUsage("", clp); //$NON-NLS-1$
throw new TerminatedByHelpException();
}

argWalk = clp.getRevWalkGently();
@@ -246,6 +249,20 @@ public abstract class TextBuiltin {
* @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.print("jgit "); //$NON-NLS-1$
errw.print(commandName);
@@ -257,12 +274,19 @@ public abstract class TextBuiltin {
errw.println();

errw.flush();
throw die(true);
}

/**
* @return the resource bundle that will be passed to args4j for purpose
* of string localization
* @return error writer, typically this is standard error.
* @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() {
return CLIText.get().resourceBundle();
@@ -324,6 +348,19 @@ public abstract class TextBuiltin {
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) {
if (dst.startsWith(R_HEADS))
dst = dst.substring(R_HEADS.length());
@@ -333,4 +370,36 @@ public abstract class TextBuiltin {
dst = dst.substring(R_REMOTES.length());
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
- 0
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java View File

@@ -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
- 0
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java View File

@@ -74,6 +74,19 @@ public class CLIText extends TranslationBundle {
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
/***/ public String alreadyOnBranch;
/***/ public String alreadyUpToDate;
@@ -85,6 +98,7 @@ public class CLIText extends TranslationBundle {
/***/ public String branchCreatedFrom;
/***/ public String branchDetachedHEAD;
/***/ public String branchIsNotAnAncestorOfYourCurrentHEAD;
/***/ public String branchNameRequired;
/***/ public String branchNotFound;
/***/ public String cacheTreePathInfo;
/***/ public String configFileNotFound;
@@ -184,6 +198,7 @@ public class CLIText extends TranslationBundle {
/***/ public String metaVar_uriish;
/***/ public String metaVar_url;
/***/ public String metaVar_user;
/***/ public String metaVar_values;
/***/ public String metaVar_version;
/***/ public String mostCommonlyUsedCommandsAre;
/***/ public String needApprovalToDestroyCurrentRepository;

+ 151
- 12
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java View File

@@ -43,19 +43,18 @@

package org.eclipse.jgit.pgm.opt;

import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Field;
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.Repository;
import org.eclipse.jgit.pgm.Die;
import org.eclipse.jgit.pgm.TextBuiltin;
import org.eclipse.jgit.pgm.internal.CLIText;
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.transport.RefSpec;
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.
@@ -80,12 +88,17 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
registerHandler(RefSpec.class, RefSpecHandler.class);
registerHandler(RevCommit.class, RevCommitHandler.class);
registerHandler(RevTree.class, RevTreeHandler.class);
registerHandler(List.class, OptionWithValuesListHandler.class);
}

private final Repository db;

private RevWalk walk;

private boolean seenHelp;

private TextBuiltin cmd;

/**
* Creates a new command line owner that parses arguments/options and set
* them into the given object.
@@ -117,8 +130,12 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
*/
public CmdLineParser(final Object bean, Repository repo) {
super(bean);
if (repo == null && bean instanceof TextBuiltin)
repo = ((TextBuiltin) bean).getRepository();
if (bean instanceof TextBuiltin) {
cmd = (TextBuiltin) bean;
}
if (repo == null && cmd != null) {
repo = cmd.getRepository();
}
this.db = repo;
}

@@ -143,9 +160,75 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
}

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();
}

super.parseArgument(tmp.toArray(new String[tmp.size()]));
try {
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;
}

static class MyOptionDef extends OptionDef {
class MyOptionDef extends OptionDef {

public MyOptionDef(OptionDef 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();
}
}

@Override
public boolean required() {
return seenHelp ? false : super.required();
}
}

@Override
@@ -211,4 +299,55 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser {
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
- 0
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java View File

@@ -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
- 0
org.eclipse.jgit.test/BUCK View File

@@ -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
- 0
org.eclipse.jgit.test/META-INF/MANIFEST.MF View File

@@ -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.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.reftree;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.merge;version="[4.2.0,4.3.0)",

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

@@ -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>

+ 97
- 1
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java View File

@@ -43,6 +43,7 @@
*/
package org.eclipse.jgit.api;

import static org.eclipse.jgit.util.FileUtils.RECURSIVE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -797,13 +798,108 @@ public class AddCommandTest extends RepositoryTestCase {

assertEquals("[a.txt, mode:100644, content:more content,"
+ " assume-unchanged:false][b.txt, mode:100644,"
+ "" + ""
+ " content:content, assume-unchanged:true]",
indexState(CONTENT
| 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
public void testExecutableRetention() throws Exception {
StoredConfig config = db.getConfig();

+ 31
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java View File

@@ -46,12 +46,15 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;

import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import org.eclipse.jgit.api.errors.EmtpyCommitException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.dircache.DirCache;
@@ -476,6 +479,34 @@ public class CommitCommandTest extends RepositoryTestCase {
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
public void commitOnlyShouldCommitUnmergedPathAndNotAffectOthers()
throws Exception {

+ 65
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java View File

@@ -43,10 +43,12 @@
package org.eclipse.jgit.api;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;

import org.eclipse.jgit.api.CheckoutCommand.Stage;
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.StoredConfig;
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.Test;

@@ -73,6 +78,8 @@ public class PathCheckoutCommandTest extends RepositoryTestCase {

private static final String FILE3 = "Test3.txt";

private static final String LINK = "link";

Git git;

RevCommit initialCommit;
@@ -98,6 +105,64 @@ public class PathCheckoutCommandTest extends RepositoryTestCase {
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
public void testUpdateWorkingDirectory() throws Exception {
CheckoutCommand co = git.checkout();

+ 35
- 21
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java View File

@@ -65,6 +65,7 @@ import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
@@ -139,8 +140,8 @@ public class ResetCommandTest extends RepositoryTestCase {
AmbiguousObjectException, IOException, GitAPIException {
setupRepository();
ObjectId prevHead = db.resolve(Constants.HEAD);
git.reset().setMode(ResetType.HARD).setRef(initialCommit.getName())
.call();
assertSameAsHead(git.reset().setMode(ResetType.HARD)
.setRef(initialCommit.getName()).call());
// check if HEAD points to initial commit now
ObjectId head = db.resolve(Constants.HEAD);
assertEquals(initialCommit, head);
@@ -176,8 +177,8 @@ public class ResetCommandTest extends RepositoryTestCase {
AmbiguousObjectException, IOException, GitAPIException {
setupRepository();
ObjectId prevHead = db.resolve(Constants.HEAD);
git.reset().setMode(ResetType.SOFT).setRef(initialCommit.getName())
.call();
assertSameAsHead(git.reset().setMode(ResetType.SOFT)
.setRef(initialCommit.getName()).call());
// check if HEAD points to initial commit now
ObjectId head = db.resolve(Constants.HEAD);
assertEquals(initialCommit, head);
@@ -197,8 +198,8 @@ public class ResetCommandTest extends RepositoryTestCase {
AmbiguousObjectException, IOException, GitAPIException {
setupRepository();
ObjectId prevHead = db.resolve(Constants.HEAD);
git.reset().setMode(ResetType.MIXED).setRef(initialCommit.getName())
.call();
assertSameAsHead(git.reset().setMode(ResetType.MIXED)
.setRef(initialCommit.getName()).call());
// check if HEAD points to initial commit now
ObjectId head = db.resolve(Constants.HEAD);
assertEquals(initialCommit, head);
@@ -241,7 +242,8 @@ public class ResetCommandTest extends RepositoryTestCase {
assertTrue(bEntry.getLength() > 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();

@@ -280,7 +282,7 @@ public class ResetCommandTest extends RepositoryTestCase {
+ "[a.txt, mode:100644, stage:3]",
indexState(0));

git.reset().setMode(ResetType.MIXED).call();
assertSameAsHead(git.reset().setMode(ResetType.MIXED).call());

assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]",
indexState(0));
@@ -298,8 +300,8 @@ public class ResetCommandTest extends RepositoryTestCase {

// 'a.txt' has already been modified in setupRepository
// 'notAddedToIndex.txt' has been added to repository
git.reset().addPath(indexFile.getName())
.addPath(untrackedFile.getName()).call();
assertSameAsHead(git.reset().addPath(indexFile.getName())
.addPath(untrackedFile.getName()).call());

DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS())
.getEntry(indexFile.getName());
@@ -329,7 +331,7 @@ public class ResetCommandTest extends RepositoryTestCase {
git.add().addFilepattern(untrackedFile.getName()).call();

// '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())
.getEntry("dir/b.txt");
@@ -358,9 +360,9 @@ public class ResetCommandTest extends RepositoryTestCase {
// 'a.txt' has already been modified in setupRepository
// 'notAddedToIndex.txt' has been added to repository
// reset to the inital commit
git.reset().setRef(initialCommit.getName())
.addPath(indexFile.getName())
.addPath(untrackedFile.getName()).call();
assertSameAsHead(git.reset().setRef(initialCommit.getName())
.addPath(indexFile.getName()).addPath(untrackedFile.getName())
.call());

// check that HEAD hasn't moved
ObjectId head = db.resolve(Constants.HEAD);
@@ -397,7 +399,7 @@ public class ResetCommandTest extends RepositoryTestCase {
+ "[b.txt, mode:100644]",
indexState(0));

git.reset().addPath(file).call();
assertSameAsHead(git.reset().addPath(file).call());

assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]",
indexState(0));
@@ -409,7 +411,7 @@ public class ResetCommandTest extends RepositoryTestCase {
writeTrashFile("a.txt", "content");
git.add().addFilepattern("a.txt").call();
// 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();
DirCacheEntry aEntry = cache.getEntry("a.txt");
@@ -421,7 +423,8 @@ public class ResetCommandTest extends RepositoryTestCase {
git = new Git(db);
writeTrashFile("a.txt", "content");
git.add().addFilepattern("a.txt").call();
git.reset().setRef("doesnotexist").addPath("a.txt").call();
assertSameAsHead(
git.reset().setRef("doesnotexist").addPath("a.txt").call());
}

@Test
@@ -431,7 +434,7 @@ public class ResetCommandTest extends RepositoryTestCase {
git.add().addFilepattern("a.txt").call();
writeTrashFile("a.txt", "modified");
// should use default mode MIXED
git.reset().call();
assertSameAsHead(git.reset().call());

DirCache cache = db.readDirCache();
DirCacheEntry aEntry = cache.getEntry("a.txt");
@@ -452,7 +455,7 @@ public class ResetCommandTest extends RepositoryTestCase {

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);
assertEquals(secondCommit, head);
@@ -486,7 +489,8 @@ public class ResetCommandTest extends RepositoryTestCase {
result.getMergeStatus());
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());
}
@@ -497,7 +501,7 @@ public class ResetCommandTest extends RepositoryTestCase {
File fileA = writeTrashFile("a.txt", "content");
git.add().addFilepattern("a.txt").call();
// 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();
DirCacheEntry aEntry = cache.getEntry("a.txt");
@@ -558,4 +562,14 @@ public class ResetCommandTest extends RepositoryTestCase {
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
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java View File

@@ -43,11 +43,13 @@
package org.eclipse.jgit.dircache;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.errors.DirCacheNameConflictException;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.junit.Test;
@@ -154,6 +156,125 @@ public class DirCachePathEditTest {
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) {
DirCacheEntry entry = new DirCacheEntry(path, stage);
entry.setFileMode(FileMode.REGULAR_FILE);

+ 6
- 1
org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java View File

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

+ 1
- 1
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileRepositoryBuilderTest.java View File

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

try {

+ 46
- 24
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java View File

@@ -43,11 +43,13 @@

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.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.eclipse.jgit.internal.storage.pack.PackWriter.NONE;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -66,19 +68,19 @@ import java.util.Set;
import org.eclipse.jgit.errors.MissingObjectException;
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.ObjectIdSet;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdSet;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
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.transport.PackParser;
import org.junit.After;
@@ -87,9 +89,6 @@ import org.junit.Test;

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
.<RevObject> emptyList();

@@ -170,7 +169,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
*/
@Test
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, pack.getObjectCount());
@@ -203,8 +202,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
final ObjectId nonExisting = ObjectId
.fromString("0000000000000000000000000000000000000001");
try {
createVerifyOpenPack(EMPTY_SET_OBJECT, Collections.singleton(
nonExisting), false, false);
createVerifyOpenPack(NONE, Collections.singleton(nonExisting),
false, false);
fail("Should have thrown MissingObjectException");
} catch (MissingObjectException x) {
// expected
@@ -220,8 +219,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
public void testIgnoreNonExistingObjects() throws IOException {
final ObjectId nonExisting = ObjectId
.fromString("0000000000000000000000000000000000000001");
createVerifyOpenPack(EMPTY_SET_OBJECT, Collections.singleton(
nonExisting), false, true);
createVerifyOpenPack(NONE, Collections.singleton(nonExisting),
false, true);
// shouldn't throw anything
}

@@ -239,8 +238,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
final ObjectId nonExisting = ObjectId
.fromString("0000000000000000000000000000000000000001");
new GC(db).gc();
createVerifyOpenPack(EMPTY_SET_OBJECT,
Collections.singleton(nonExisting), false, true, true);
createVerifyOpenPack(NONE, Collections.singleton(nonExisting), false,
true, true);
// shouldn't throw anything
}

@@ -437,6 +436,38 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
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
public void testWriteIndex() throws Exception {
config.setIndexVersion(2);
@@ -494,7 +525,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
RevCommit c2 = bb.commit().add("f", contentB).create();
testRepo.getRevWalk().parseHeaders(c2);
PackIndex pf2 = writePack(repo, Collections.singleton(c2),
Collections.singleton(objectIdSet(pf1)));
Collections.<ObjectIdSet> singleton(pf1));
assertContent(
pf2,
Arrays.asList(c2.getId(), c2.getTree().getId(),
@@ -519,8 +550,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
pw.setReuseDeltaCommits(false);
for (ObjectIdSet idx : excludeObjects)
pw.excludeObjects(idx);
pw.preparePack(NullProgressMonitor.INSTANCE, want,
Collections.<ObjectId> emptySet());
pw.preparePack(NullProgressMonitor.INSTANCE, want, NONE);
String id = pw.computeName().getName();
File packdir = new File(repo.getObjectsDirectory(), "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>();
interestings.add(ObjectId
.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"));
createVerifyOpenPack(interestings, EMPTY_SET_OBJECT, false, false);
createVerifyOpenPack(interestings, NONE, false, false);

final ObjectId expectedOrder[] = new ObjectId[] {
ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
@@ -699,12 +729,4 @@ public class PackWriterTest extends SampleDataRepositoryTestCase {
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);
}
};
}
}

+ 8
- 45
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java View File

@@ -67,7 +67,6 @@ import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.FileTreeEntry;
import org.eclipse.jgit.lib.ObjectDatabase;
import org.eclipse.jgit.lib.ObjectId;
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.Repository;
import org.eclipse.jgit.lib.TagBuilder;
import org.eclipse.jgit.lib.Tree;
import org.eclipse.jgit.lib.TreeFormatter;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTag;
@@ -419,29 +417,6 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
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
public void test020_createBlobTag() throws IOException {
final ObjectId emptyId = insertEmptyBlob();
@@ -465,9 +440,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
@Test
public void test021_createTreeTag() throws IOException {
final ObjectId emptyId = insertEmptyBlob();
final Tree almostEmptyTree = new Tree(db);
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId,
"empty".getBytes(), false));
TreeFormatter almostEmptyTree = new TreeFormatter();
almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId);
final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree);
final TagBuilder t = new TagBuilder();
t.setObjectId(almostEmptyTreeId, Constants.OBJ_TREE);
@@ -489,9 +463,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
@Test
public void test022_createCommitTag() throws IOException {
final ObjectId emptyId = insertEmptyBlob();
final Tree almostEmptyTree = new Tree(db);
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId,
"empty".getBytes(), false));
TreeFormatter almostEmptyTree = new TreeFormatter();
almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId);
final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree);
final CommitBuilder almostEmptyCommit = new CommitBuilder();
almostEmptyCommit.setAuthor(new PersonIdent(author, 1154236443000L,
@@ -521,9 +494,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
@Test
public void test023_createCommitNonAnullii() throws IOException {
final ObjectId emptyId = insertEmptyBlob();
final Tree almostEmptyTree = new Tree(db);
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId,
"empty".getBytes(), false));
TreeFormatter almostEmptyTree = new TreeFormatter();
almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId);
final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree);
CommitBuilder commit = new CommitBuilder();
commit.setTreeId(almostEmptyTreeId);
@@ -543,9 +515,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
@Test
public void test024_createCommitNonAscii() throws IOException {
final ObjectId emptyId = insertEmptyBlob();
final Tree almostEmptyTree = new Tree(db);
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId,
"empty".getBytes(), false));
TreeFormatter almostEmptyTree = new TreeFormatter();
almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId);
final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree);
CommitBuilder commit = new CommitBuilder();
commit.setTreeId(almostEmptyTreeId);
@@ -747,14 +718,6 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase {
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 {
try (ObjectInserter oi = db.newObjectInserter()) {
ObjectId id = oi.insert(tree);

+ 685
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java View File

@@ -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
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeTest.java View File

@@ -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;
}
}
}

+ 2
- 4
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java View File

@@ -1084,7 +1084,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
assertWorkDir(mkmap(linkName, "a", fname, "a"));

Status st = git.status().call();
assertFalse(st.isClean());
assertTrue(st.isClean());
}

@Test
@@ -1213,9 +1213,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
assertWorkDir(mkmap(fname, "a"));

Status st = git.status().call();
assertFalse(st.isClean());
assertEquals(1, st.getAdded().size());
assertTrue(st.getAdded().contains(fname + "/dir/file1"));
assertTrue(st.isClean());
}

@Test

+ 45
- 46
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java View File

@@ -99,8 +99,7 @@ public class IndexDiffTest extends RepositoryTestCase {
public void testAdded() throws IOException {
writeTrashFile("file1", "file1");
writeTrashFile("dir/subfile", "dir/subfile");
Tree tree = new Tree(db);
tree.setId(insertTree(tree));
ObjectId tree = insertTree(new TreeFormatter());

DirCache index = db.lockDirCache();
DirCacheEditor editor = index.editor();
@@ -108,7 +107,7 @@ public class IndexDiffTest extends RepositoryTestCase {
editor.add(add(db, trash, "dir/subfile"));
editor.commit();
FileTreeIterator iterator = new FileTreeIterator(db);
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator);
IndexDiff diff = new IndexDiff(db, tree, iterator);
diff.diff();
assertEquals(2, diff.getAdded().size());
assertTrue(diff.getAdded().contains("file1"));
@@ -124,18 +123,16 @@ public class IndexDiffTest extends RepositoryTestCase {
writeTrashFile("file2", "file2");
writeTrashFile("dir/file3", "dir/file3");

Tree tree = new Tree(db);
tree.addFile("file2");
tree.addFile("dir/file3");
assertEquals(2, tree.memberCount());
tree.findBlobMember("file2").setId(ObjectId.fromString("30d67d4672d5c05833b7192cc77a79eaafb5c7ad"));
Tree tree2 = (Tree) tree.findTreeMember("dir");
tree2.findBlobMember("file3").setId(ObjectId.fromString("873fb8d667d05436d728c52b1d7a09528e6eb59b"));
tree2.setId(insertTree(tree2));
tree.setId(insertTree(tree));
TreeFormatter dir = new TreeFormatter();
dir.append("file3", FileMode.REGULAR_FILE, ObjectId.fromString("873fb8d667d05436d728c52b1d7a09528e6eb59b"));

TreeFormatter tree = new TreeFormatter();
tree.append("file2", FileMode.REGULAR_FILE, ObjectId.fromString("30d67d4672d5c05833b7192cc77a79eaafb5c7ad"));
tree.append("dir", FileMode.TREE, insertTree(dir));
ObjectId treeId = insertTree(tree);

FileTreeIterator iterator = new FileTreeIterator(db);
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator);
IndexDiff diff = new IndexDiff(db, treeId, iterator);
diff.diff();
assertEquals(2, diff.getRemoved().size());
assertTrue(diff.getRemoved().contains("file2"));
@@ -157,16 +154,16 @@ public class IndexDiffTest extends RepositoryTestCase {

writeTrashFile("dir/file3", "changed");

Tree tree = new Tree(db);
tree.addFile("file2").setId(ObjectId.fromString("0123456789012345678901234567890123456789"));
tree.addFile("dir/file3").setId(ObjectId.fromString("0123456789012345678901234567890123456789"));
assertEquals(2, tree.memberCount());
TreeFormatter dir = new TreeFormatter();
dir.append("file3", FileMode.REGULAR_FILE, ObjectId.fromString("0123456789012345678901234567890123456789"));

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);
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator);
IndexDiff diff = new IndexDiff(db, treeId, iterator);
diff.diff();
assertEquals(2, diff.getChanged().size());
assertTrue(diff.getChanged().contains("file2"));
@@ -314,17 +311,16 @@ public class IndexDiffTest extends RepositoryTestCase {
git.add().addFilepattern("a=c").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
tree.addFile("a.b").setId(ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851"));
tree.addFile("a.c").setId(ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca"));
tree.addFile("a=c").setId(ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714"));
tree.addFile("a=d").setId(ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2"));

tree.setId(insertTree(tree));
tree.append("a.b", FileMode.REGULAR_FILE, ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851"));
tree.append("a.c", FileMode.REGULAR_FILE, ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca"));
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);
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator);
IndexDiff diff = new IndexDiff(db, treeId, iterator);
diff.diff();
assertEquals(0, diff.getChanged().size());
assertEquals(0, diff.getAdded().size());
@@ -356,24 +352,27 @@ public class IndexDiffTest extends RepositoryTestCase {
.addFilepattern("a/c").addFilepattern("a=c")
.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
tree.addFile("a.b").setId(ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851"));
tree.addFile("a.c").setId(ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca"));
tree.addFile("a/b.b/b").setId(ObjectId.fromString("8d840bd4e2f3a48ff417c8e927d94996849933fd"));
tree.addFile("a/b").setId(ObjectId.fromString("db89c972fc57862eae378f45b74aca228037d415"));
tree.addFile("a/c").setId(ObjectId.fromString("52ad142a008aeb39694bafff8e8f1be75ed7f007"));
tree.addFile("a=c").setId(ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714"));
tree.addFile("a=d").setId(ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2"));

Tree tree3 = (Tree) tree.findTreeMember("a/b.b");
tree3.setId(insertTree(tree3));
Tree tree2 = (Tree) tree.findTreeMember("a");
tree2.setId(insertTree(tree2));
tree.setId(insertTree(tree));
TreeFormatter bb = new TreeFormatter();
bb.append("b", FileMode.REGULAR_FILE, ObjectId.fromString("8d840bd4e2f3a48ff417c8e927d94996849933fd"));

TreeFormatter a = new TreeFormatter();
a.append("b", FileMode.REGULAR_FILE, ObjectId
.fromString("db89c972fc57862eae378f45b74aca228037d415"));
a.append("b.b", FileMode.TREE, insertTree(bb));
a.append("c", FileMode.REGULAR_FILE, ObjectId.fromString("52ad142a008aeb39694bafff8e8f1be75ed7f007"));

TreeFormatter tree = new TreeFormatter();
tree.append("a.b", FileMode.REGULAR_FILE, ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851"));
tree.append("a.c", FileMode.REGULAR_FILE, ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca"));
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);
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator);
IndexDiff diff = new IndexDiff(db, treeId, iterator);
diff.diff();
assertEquals(0, diff.getChanged().size());
assertEquals(0, diff.getAdded().size());
@@ -383,9 +382,9 @@ public class IndexDiffTest extends RepositoryTestCase {
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()) {
ObjectId id = oi.insert(Constants.OBJ_TREE, tree.format());
ObjectId id = oi.insert(tree);
oi.flush();
return id;
}

+ 588
- 881
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
File diff suppressed because it is too large
View File


+ 0
- 319
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_TreeTest.java View File

@@ -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());
}
}

+ 20
- 25
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java View File

@@ -47,11 +47,10 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;

import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileTreeEntry;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Tree;
import org.eclipse.jgit.lib.TreeFormatter;
import org.junit.Test;

@SuppressWarnings("deprecation")
@@ -220,28 +219,24 @@ public class ObjectWalkTest extends RevWalkTestCase {
.fromString("abbbfafe3129f85747aba7bfac992af77134c607");
final RevTree tree_root, tree_A, tree_AB;
final RevCommit b;
{
Tree root = new Tree(db);
Tree A = root.addTree("A");
FileTreeEntry B = root.addFile("B");
B.setId(bId);

Tree A_A = A.addTree("A");
Tree A_B = A.addTree("B");

try (final ObjectInserter inserter = db.newObjectInserter()) {
A_A.setId(inserter.insert(Constants.OBJ_TREE, A_A.format()));
A_B.setId(inserter.insert(Constants.OBJ_TREE, A_B.format()));
A.setId(inserter.insert(Constants.OBJ_TREE, A.format()));
root.setId(inserter.insert(Constants.OBJ_TREE, root.format()));
inserter.flush();
}

tree_root = rw.parseTree(root.getId());
tree_A = rw.parseTree(A.getId());
tree_AB = rw.parseTree(A_A.getId());
assertSame(tree_AB, rw.parseTree(A_B.getId()));
b = commit(rw.parseTree(root.getId()));
try (ObjectInserter inserter = db.newObjectInserter()) {
ObjectId empty = inserter.insert(new TreeFormatter());

TreeFormatter A = new TreeFormatter();
A.append("A", FileMode.TREE, empty);
A.append("B", FileMode.TREE, empty);
ObjectId idA = inserter.insert(A);

TreeFormatter root = new TreeFormatter();
root.append("A", FileMode.TREE, idA);
root.append("B", FileMode.REGULAR_FILE, bId);
ObjectId idRoot = inserter.insert(root);
inserter.flush();

tree_root = objw.parseTree(idRoot);
tree_A = objw.parseTree(idA);
tree_AB = objw.parseTree(empty);
b = commit(tree_root);
}

markStart(b);

+ 85
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java View File

@@ -43,13 +43,18 @@

package org.eclipse.jgit.revwalk;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
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.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.TimeZone;

import org.eclipse.jgit.junit.RepositoryTestCase;
@@ -303,6 +308,86 @@ public class RevCommitParseTest extends RepositoryTestCase {
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
public void testParse_NoMessage() throws Exception {
final String msg = "";

+ 39
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java View File

@@ -43,6 +43,7 @@

package org.eclipse.jgit.revwalk;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -361,6 +362,44 @@ public class RevTagParseTest extends RepositoryTestCase {
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
public void testParse_NoMessage() throws Exception {
final String msg = "";

+ 3
- 12
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java View File

@@ -112,12 +112,9 @@ public class AtomicPushTest {
public void pushNonAtomic() throws Exception {
PushResult r;
server.setPerformsAtomicTransactions(false);
Transport tn = testProtocol.open(uri, client, "server");
try {
try (Transport tn = testProtocol.open(uri, client, "server")) {
tn.setPushAtomic(false);
r = tn.push(NullProgressMonitor.INSTANCE, commands());
} finally {
tn.close();
}

RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
@@ -131,12 +128,9 @@ public class AtomicPushTest {
@Test
public void pushAtomicClientGivesUpEarly() throws Exception {
PushResult r;
Transport tn = testProtocol.open(uri, client, "server");
try {
try (Transport tn = testProtocol.open(uri, client, "server")) {
tn.setPushAtomic(true);
r = tn.push(NullProgressMonitor.INSTANCE, commands());
} finally {
tn.close();
}

RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
@@ -167,8 +161,7 @@ public class AtomicPushTest {
ObjectId.zeroId()));

server.setPerformsAtomicTransactions(false);
Transport tn = testProtocol.open(uri, client, "server");
try {
try (Transport tn = testProtocol.open(uri, client, "server")) {
tn.setPushAtomic(true);
tn.push(NullProgressMonitor.INSTANCE, cmds);
fail("did not throw TransportException");
@@ -176,8 +169,6 @@ public class AtomicPushTest {
assertEquals(
uri + ": " + JGitText.get().atomicPushNotSupported,
e.getMessage());
} finally {
tn.close();
}
}


+ 4
- 2
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java View File

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

private byte[] makeBundle(final String name,

+ 5
- 13
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java View File

@@ -116,12 +116,9 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas

// Clone from dst into src
//
Transport t = Transport.open(src, uriOf(dst));
try {
try (Transport t = Transport.open(src, uriOf(dst))) {
t.fetch(PM, Collections.singleton(new RefSpec("+refs/*:refs/*")));
assertEquals(B, src.resolve(R_MASTER));
} finally {
t.close();
}

// Now put private stuff into dst.
@@ -144,7 +141,8 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas
@Test
public void testFilterHidesPrivate() throws Exception {
Map<String, Ref> refs;
TransportLocal t = new TransportLocal(src, uriOf(dst), dst.getDirectory()) {
try (TransportLocal t = new TransportLocal(src, uriOf(dst),
dst.getDirectory()) {
@Override
ReceivePack createReceivePack(final Repository db) {
db.close();
@@ -154,16 +152,10 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas
rp.setAdvertiseRefsHook(new HidePrivateHook());
return rp;
}
};
try {
PushConnection c = t.openPush();
try {
}) {
try (PushConnection c = t.openPush()) {
refs = c.getRefsMap();
} finally {
c.close();
}
} finally {
t.close();
}

assertNotNull(refs);

+ 35
- 15
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java View File

@@ -340,6 +340,41 @@ public class RefSpecTest {
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
public void testWildcardMirror() {
RefSpec a = new RefSpec("*:*");
@@ -403,21 +438,6 @@ public class RefSpecTest {
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)
public void invalidSourceDoubleSlashes() {
assertNotNull(new RefSpec("refs/heads//wrong"));

+ 32
- 41
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java View File

@@ -61,13 +61,10 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TransportTest extends SampleDataRepositoryTestCase {
private Transport transport;

private RemoteConfig remoteConfig;

@Override
@@ -77,17 +74,6 @@ public class TransportTest extends SampleDataRepositoryTestCase {
final Config config = db.getConfig();
remoteConfig = new RemoteConfig(config, "test");
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
public void testFindRemoteRefUpdatesNoWildcardNoTracking()
throws IOException {
transport = Transport.open(db, remoteConfig);
final Collection<RemoteRefUpdate> result = transport
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
"refs/heads/master:refs/heads/x")));
Collection<RemoteRefUpdate> result;
try (Transport transport = Transport.open(db, remoteConfig)) {
result = transport.findRemoteRefUpdatesFor(Collections.nCopies(1,
new RefSpec("refs/heads/master:refs/heads/x")));
}

assertEquals(1, result.size());
final RemoteRefUpdate rru = result.iterator().next();
@@ -122,10 +109,11 @@ public class TransportTest extends SampleDataRepositoryTestCase {
@Test
public void testFindRemoteRefUpdatesNoWildcardNoDestination()
throws IOException {
transport = Transport.open(db, remoteConfig);
final Collection<RemoteRefUpdate> result = transport
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
"+refs/heads/master")));
Collection<RemoteRefUpdate> result;
try (Transport transport = Transport.open(db, remoteConfig)) {
result = transport.findRemoteRefUpdatesFor(
Collections.nCopies(1, new RefSpec("+refs/heads/master")));
}

assertEquals(1, result.size());
final RemoteRefUpdate rru = result.iterator().next();
@@ -143,10 +131,11 @@ public class TransportTest extends SampleDataRepositoryTestCase {
*/
@Test
public void testFindRemoteRefUpdatesWildcardNoTracking() throws IOException {
transport = Transport.open(db, remoteConfig);
final Collection<RemoteRefUpdate> result = transport
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
"+refs/heads/*:refs/heads/test/*")));
Collection<RemoteRefUpdate> result;
try (Transport transport = Transport.open(db, remoteConfig)) {
result = transport.findRemoteRefUpdatesFor(Collections.nCopies(1,
new RefSpec("+refs/heads/*:refs/heads/test/*")));
}

assertEquals(12, result.size());
boolean foundA = false;
@@ -171,12 +160,14 @@ public class TransportTest extends SampleDataRepositoryTestCase {
*/
@Test
public void testFindRemoteRefUpdatesTwoRefSpecs() throws IOException {
transport = Transport.open(db, remoteConfig);
final RefSpec specA = new RefSpec("+refs/heads/a:refs/heads/b");
final RefSpec specC = new RefSpec("+refs/heads/c:refs/heads/d");
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());
boolean foundA = false;
@@ -202,10 +193,12 @@ public class TransportTest extends SampleDataRepositoryTestCase {
public void testFindRemoteRefUpdatesTrackingRef() throws IOException {
remoteConfig.addFetchRefSpec(new RefSpec(
"refs/heads/*:refs/remotes/test/*"));
transport = Transport.open(db, remoteConfig);
final Collection<RemoteRefUpdate> result = transport
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
"+refs/heads/a:refs/heads/a")));

Collection<RemoteRefUpdate> result;
try (Transport transport = Transport.open(db, remoteConfig)) {
result = transport.findRemoteRefUpdatesFor(Collections.nCopies(1,
new RefSpec("+refs/heads/a:refs/heads/a")));
}

assertEquals(1, result.size());
final TrackingRefUpdate tru = result.iterator().next()
@@ -225,20 +218,18 @@ public class TransportTest extends SampleDataRepositoryTestCase {
config.addURI(new URIish("../" + otherDir));

// Should not throw NoRemoteRepositoryException
transport = Transport.open(db, config);
Transport.open(db, config).close();
}

@Test
public void testLocalTransportFetchWithoutLocalRepository()
throws Exception {
URIish uri = new URIish("file://" + db.getWorkTree().getAbsolutePath());
transport = Transport.open(uri);
FetchConnection fetchConnection = transport.openFetch();
try {
Ref head = fetchConnection.getRef(Constants.HEAD);
assertNotNull(head);
} finally {
fetchConnection.close();
try (Transport transport = Transport.open(uri)) {
try (FetchConnection fetchConnection = transport.openFetch()) {
Ref head = fetchConnection.getRef(Constants.HEAD);
assertNotNull(head);
}
}
}


+ 42
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java View File

@@ -459,6 +459,48 @@ public class URIishTest {
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
public void testSshProtoWithADUserPassAndPort() throws Exception {
final String str = "ssh://DOMAIN\\user:pass@example.com:33/some/p ath";

+ 38
- 39
org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java View File

@@ -44,7 +44,6 @@
package org.eclipse.jgit.treewalk;

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.junit.Assert.assertEquals;
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.ObjectId;
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.junit.Test;

@SuppressWarnings("deprecation")
public class TreeWalkBasicDiffTest extends RepositoryTestCase {
@Test
public void testMissingSubtree_DetectFileAdded_FileModified()
@@ -72,62 +70,63 @@ public class TreeWalkBasicDiffTest extends RepositoryTestCase {

// 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");
subA.addFile("empty").setId(aFileId);
subA.setId(inserter.insert(OBJ_TREE, subA.format()));
TreeFormatter subA = new TreeFormatter();
subA.append("empty", FileMode.REGULAR_FILE, aFileId);
root.append("sub-a", FileMode.TREE, inserter.insert(subA));
}
{
final Tree subC = root.addTree("sub-c");
subC.addFile("empty").setId(cFileId1);
subC.setId(inserter.insert(OBJ_TREE, subC.format()));
TreeFormatter subC = new TreeFormatter();
subC.append("empty", FileMode.REGULAR_FILE, cFileId1);
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.
{
final Tree root = new Tree(db);
TreeFormatter root = new TreeFormatter();
{
final Tree subA = root.addTree("sub-a");
subA.addFile("empty").setId(aFileId);
subA.setId(inserter.insert(OBJ_TREE, subA.format()));
TreeFormatter subA = new TreeFormatter();
subA.append("empty", FileMode.REGULAR_FILE, aFileId);
root.append("sub-a", FileMode.TREE, inserter.insert(subA));
}
{
final Tree subB = root.addTree("sub-b");
subB.addFile("empty").setId(bFileId);
subB.setId(inserter.insert(OBJ_TREE, subB.format()));
TreeFormatter subB = new TreeFormatter();
subB.append("empty", FileMode.REGULAR_FILE, bFileId);
root.append("sub-b", FileMode.TREE, inserter.insert(subB));
}
{
final Tree subC = root.addTree("sub-c");
subC.addFile("empty").setId(cFileId2);
subC.setId(inserter.insert(OBJ_TREE, subC.format()));
TreeFormatter subC = new TreeFormatter();
subC.append("empty", FileMode.REGULAR_FILE, cFileId2);
root.append("sub-c", FileMode.TREE, inserter.insert(subC));
}
newTree = inserter.insert(OBJ_TREE, root.format());
newTree = inserter.insert(root);
}
inserter.flush();
}

final TreeWalk tw = new TreeWalk(db);
tw.reset(oldTree, newTree);
tw.setRecursive(true);
tw.setFilter(TreeFilter.ANY_DIFF);
try (TreeWalk tw = new TreeWalk(db)) {
tw.reset(oldTree, newTree);
tw.setRecursive(true);
tw.setFilter(TreeFilter.ANY_DIFF);

assertTrue(tw.next());
assertEquals("sub-b/empty", tw.getPathString());
assertEquals(FileMode.MISSING, tw.getFileMode(0));
assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1));
assertEquals(ObjectId.zeroId(), tw.getObjectId(0));
assertEquals(bFileId, tw.getObjectId(1));
assertTrue(tw.next());
assertEquals("sub-b/empty", tw.getPathString());
assertEquals(FileMode.MISSING, tw.getFileMode(0));
assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1));
assertEquals(ObjectId.zeroId(), tw.getObjectId(0));
assertEquals(bFileId, tw.getObjectId(1));

assertTrue(tw.next());
assertEquals("sub-c/empty", tw.getPathString());
assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(0));
assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1));
assertEquals(cFileId1, tw.getObjectId(0));
assertEquals(cFileId2, tw.getObjectId(1));
assertTrue(tw.next());
assertEquals("sub-c/empty", tw.getPathString());
assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(0));
assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1));
assertEquals(cFileId1, tw.getObjectId(0));
assertEquals(cFileId2, tw.getObjectId(1));

assertFalse(tw.next());
assertFalse(tw.next());
}
}
}

+ 117
- 33
org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java View File

@@ -43,11 +43,18 @@

package org.eclipse.jgit.treewalk.filter;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

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.DirCacheEditor;
@@ -58,6 +65,7 @@ import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.StopWalkException;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Sets;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.junit.Before;
import org.junit.Test;
@@ -66,6 +74,8 @@ public class PathFilterGroupTest {

private TreeFilter filter;

private Map<String, TreeFilter> singles;

@Before
public void setup() {
// @formatter:off
@@ -81,64 +91,75 @@ public class PathFilterGroupTest {
};
// @formatter:on
filter = PathFilterGroup.createFromStrings(paths);
singles = new HashMap<>();
for (String path : paths) {
singles.put(path, PathFilterGroup.createFromStrings(path));
}
}

@Test
public void testExact() throws MissingObjectException,
IncorrectObjectTypeException, IOException {
assertTrue(filter.include(fakeWalk("a")));
assertTrue(filter.include(fakeWalk("b/c")));
assertTrue(filter.include(fakeWalk("c/d/e")));
assertTrue(filter.include(fakeWalk("c/d/f")));
assertTrue(filter.include(fakeWalk("d/e/f/g")));
assertTrue(filter.include(fakeWalk("d/e/f/g.x")));
assertMatches(Sets.of("a"), fakeWalk("a"));
assertMatches(Sets.of("b/c"), fakeWalk("b/c"));
assertMatches(Sets.of("c/d/e"), fakeWalk("c/d/e"));
assertMatches(Sets.of("c/d/f"), fakeWalk("c/d/f"));
assertMatches(Sets.of("d/e/f/g"), fakeWalk("d/e/f/g"));
assertMatches(Sets.of("d/e/f/g.x"), fakeWalk("d/e/f/g.x"));
}

@Test
public void testNoMatchButClose() throws MissingObjectException,
IncorrectObjectTypeException, IOException {
assertFalse(filter.include(fakeWalk("a+")));
assertFalse(filter.include(fakeWalk("b+/c")));
assertFalse(filter.include(fakeWalk("c+/d/e")));
assertFalse(filter.include(fakeWalk("c+/d/f")));
assertFalse(filter.include(fakeWalk("c/d.a")));
assertFalse(filter.include(fakeWalk("d+/e/f/g")));
assertNoMatches(fakeWalk("a+"));
assertNoMatches(fakeWalk("b+/c"));
assertNoMatches(fakeWalk("c+/d/e"));
assertNoMatches(fakeWalk("c+/d/f"));
assertNoMatches(fakeWalk("c/d.a"));
assertNoMatches(fakeWalk("d+/e/f/g"));
}

@Test
public void testJustCommonPrefixIsNotMatch() throws MissingObjectException,
IncorrectObjectTypeException, IOException {
assertFalse(filter.include(fakeWalk("b/a")));
assertFalse(filter.include(fakeWalk("b/d")));
assertFalse(filter.include(fakeWalk("c/d/a")));
assertFalse(filter.include(fakeWalk("d/e/e")));
assertNoMatches(fakeWalk("b/a"));
assertNoMatches(fakeWalk("b/d"));
assertNoMatches(fakeWalk("c/d/a"));
assertNoMatches(fakeWalk("d/e/e"));
assertNoMatches(fakeWalk("d/e/f/g.y"));
}

@Test
public void testKeyIsPrefixOfFilter() throws MissingObjectException,
IncorrectObjectTypeException, IOException {
assertTrue(filter.include(fakeWalk("b")));
assertTrue(filter.include(fakeWalk("c/d")));
assertTrue(filter.include(fakeWalk("c/d")));
assertTrue(filter.include(fakeWalk("c")));
assertTrue(filter.include(fakeWalk("d/e/f")));
assertTrue(filter.include(fakeWalk("d/e")));
assertTrue(filter.include(fakeWalk("d")));
assertMatches(Sets.of("b/c"), fakeWalkAtSubtree("b"));
assertMatches(Sets.of("c/d/e", "c/d/f"), fakeWalkAtSubtree("c/d"));
assertMatches(Sets.of("c/d/e", "c/d/f"), fakeWalkAtSubtree("c"));
assertMatches(Sets.of("d/e/f/g", "d/e/f/g.x"),
fakeWalkAtSubtree("d/e/f"));
assertMatches(Sets.of("d/e/f/g", "d/e/f/g.x"),
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
public void testFilterIsPrefixOfKey() throws MissingObjectException,
IncorrectObjectTypeException, IOException {
assertTrue(filter.include(fakeWalk("a/b")));
assertTrue(filter.include(fakeWalk("b/c/d")));
assertTrue(filter.include(fakeWalk("c/d/e/f")));
assertTrue(filter.include(fakeWalk("c/d/f/g")));
assertTrue(filter.include(fakeWalk("d/e/f/g/h")));
assertTrue(filter.include(fakeWalk("d/e/f/g/y")));
assertTrue(filter.include(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")));
assertMatches(Sets.of("a"), fakeWalk("a/b"));
assertMatches(Sets.of("b/c"), fakeWalk("b/c/d"));
assertMatches(Sets.of("c/d/e"), fakeWalk("c/d/e/f"));
assertMatches(Sets.of("c/d/f"), fakeWalk("c/d/f/g"));
assertMatches(Sets.of("d/e/f/g"), fakeWalk("d/e/f/g/h"));
assertMatches(Sets.of("d/e/f/g"), fakeWalk("d/e/f/g/y"));
assertMatches(Sets.of("d/e/f/g.x"), fakeWalk("d/e/f/g.x/h"));
}

@Test
@@ -182,6 +203,10 @@ public class PathFilterGroupTest {
// less obvious #2 due to git sorting order
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
try {
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 {
DirCache dc = DirCache.newInCore();
DirCacheEditor dce = dc.editor();
@@ -210,4 +273,25 @@ public class PathFilterGroupTest {
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;
}
}

+ 1
- 2
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java View File

@@ -45,7 +45,6 @@ package org.eclipse.jgit.util;

import static org.junit.Assert.assertEquals;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import org.eclipse.jgit.junit.MockSystemReader;
@@ -113,7 +112,7 @@ public class ChangeIdUtilTest {
}

@Test
public void testId() throws IOException {
public void testId() {
String msg = "A\nMessage\n";
ObjectId id = ChangeIdUtil.computeChangeId(treeId, parentId, p, q, msg);
assertEquals("73f3751208ac92cbb76f9a26ac4a0d9d472e381b", ObjectId

+ 18
- 8
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java View File

@@ -54,6 +54,7 @@ import java.util.regex.Matcher;

import org.eclipse.jgit.junit.JGitTestUtil;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;

@@ -424,18 +425,27 @@ public class FileUtilTest {
@Test
public void testCreateSymlink() throws IOException {
FS fs = FS.DETECTED;
try {
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());
// show test as ignored if the FS doesn't support symlinks
Assume.assumeTrue(fs.supportsSymlinks());
fs.createSymLink(new File(trash, "x"), "y");
String target = fs.readSymLink(new File(trash, "x"));
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
public void testRelativize_doc() {
// This is the javadoc example

+ 118
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java View File

@@ -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
- 0
org.eclipse.jgit.ui/BUCK View File

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

+ 6
- 1
org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java View File

@@ -56,15 +56,20 @@ import javax.swing.JPasswordField;
import javax.swing.JTextField;

import org.eclipse.jgit.errors.UnsupportedCredentialItem;
import org.eclipse.jgit.transport.ChainingCredentialsProvider;
import org.eclipse.jgit.transport.CredentialItem;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.NetRCCredentialsProvider;
import org.eclipse.jgit.transport.URIish;

/** Interacts with the user during authentication by using AWT/Swing dialogs. */
public class AwtCredentialsProvider extends CredentialsProvider {
/** Install this implementation as the default. */
public static void install() {
CredentialsProvider.setDefault(new AwtCredentialsProvider());
final AwtCredentialsProvider c = new AwtCredentialsProvider();
CredentialsProvider cp = new ChainingCredentialsProvider(
new NetRCCredentialsProvider(), c);
CredentialsProvider.setDefault(cp);
}

@Override

+ 40
- 0
org.eclipse.jgit/.settings/.api_filters View File

@@ -1,5 +1,45 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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">
<filter comment="attributes weren't really usable in earlier versions" id="338792546">
<message_arguments>

+ 20
- 0
org.eclipse.jgit/BUCK View File

@@ -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,
)

+ 2
- 1
org.eclipse.jgit/META-INF/MANIFEST.MF View File

@@ -65,9 +65,10 @@ Export-Package: org.eclipse.jgit.annotations;version="4.2.0",
org.eclipse.jgit.junit,
org.eclipse.jgit.junit.http,
org.eclipse.jgit.http.server,
org.eclipse.jgit.java7.test,
org.eclipse.jgit.pgm.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";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,

+ 8
- 3
org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties View File

@@ -99,6 +99,7 @@ cannotSquashFixupWithoutPreviousCommit=Cannot {0} without previous commit.
cannotStoreObjects=cannot store objects
cannotResolveUniquelyAbbrevObjectId=Could not resolve uniquely the abbreviated object ID
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.
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.
@@ -125,14 +126,15 @@ connectionFailed=connection failed
connectionTimeOut=Connection time out: {0}
contextMustBeNonNegative=context must be >= 0
corruptionDetectedReReadingAt=Corruption detected re-reading at {0}
corruptObjectBadDate=bad date
corruptObjectBadEmail=bad email
corruptObjectBadStream=bad stream
corruptObjectBadStreamCorruptHeader=bad stream, corrupt header
corruptObjectBadTimezone=bad time zone
corruptObjectDuplicateEntryNames=duplicate entry names
corruptObjectGarbageAfterSize=garbage after size
corruptObjectIncorrectLength=incorrect length
corruptObjectIncorrectSorting=incorrectly sorted
corruptObjectInvalidAuthor=invalid author
corruptObjectInvalidCommitter=invalid committer
corruptObjectInvalidEntryMode=invalid entry mode
corruptObjectInvalidMode=invalid mode
corruptObjectInvalidModeChar=invalid mode character
@@ -151,11 +153,11 @@ corruptObjectInvalidNameNul=invalid name 'NUL'
corruptObjectInvalidNamePrn=invalid name 'PRN'
corruptObjectInvalidObject=invalid object
corruptObjectInvalidParent=invalid parent
corruptObjectInvalidTagger=invalid tagger
corruptObjectInvalidTree=invalid tree
corruptObjectInvalidType=invalid type
corruptObjectInvalidType2=invalid type {0}
corruptObjectMalformedHeader=malformed header: {0}
corruptObjectMissingEmail=missing email
corruptObjectNameContainsByte=name contains byte 0x%x
corruptObjectNameContainsChar=name contains '%c'
corruptObjectNameContainsNullByte=name contains byte 0x00
@@ -181,6 +183,7 @@ corruptObjectPackfileChecksumIncorrect=Packfile checksum incorrect.
corruptObjectTruncatedInMode=truncated in mode
corruptObjectTruncatedInName=truncated in name
corruptObjectTruncatedInObjectId=truncated in object id
corruptObjectZeroId=entry points to null SHA-1
couldNotCheckOutBecauseOfConflicts=Could not check out because of conflicts
couldNotDeleteLockFileShouldNotHappen=Could not delete lock 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
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}
objectIsCorrupt3={0}: object {1}: {2}
objectIsNotA=Object {0} is not a {1}.
objectNotFound=Object {0} not found.
objectNotFoundIn=Object {0} not found in {1}.
@@ -595,6 +599,7 @@ transportExceptionInvalid=Invalid {0} {1}:{2}
transportExceptionMissingAssumed=Missing assumed {0}
transportExceptionReadRef=read {0}
transportNeedsRepository=Transport needs repository
transportProvidedRefWithNoObjectId=Transport provided ref {0} with no object id
transportProtoAmazonS3=Amazon S3
transportProtoBundleFile=Git Bundle File
transportProtoFTP=FTP

+ 77
- 53
org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java View File

@@ -43,6 +43,10 @@
*/
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.InputStream;
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.DirCacheIterator;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.Repository;
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.WorkingTreeIterator;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
@@ -135,15 +139,12 @@ public class AddCommand extends GitCommand<DirCache> {
throw new NoFilepatternException(JGitText.get().atLeastOnePatternIsRequired);
checkCallable();
DirCache dc = null;
boolean addAll = false;
if (filepatterns.contains(".")) //$NON-NLS-1$
addAll = true;
boolean addAll = filepatterns.contains("."); //$NON-NLS-1$

try (ObjectInserter inserter = repo.newObjectInserter();
final TreeWalk tw = new TreeWalk(repo)) {
NameConflictTreeWalk tw = new NameConflictTreeWalk(repo)) {
tw.setOperationType(OperationType.CHECKIN_OP);
dc = repo.lockDirCache();
DirCacheIterator c;

DirCacheBuilder builder = dc.builder();
tw.addTree(new DirCacheBuildIterator(builder));
@@ -151,62 +152,85 @@ public class AddCommand extends GitCommand<DirCache> {
workingTreeIterator = new FileTreeIterator(repo);
workingTreeIterator.setDirCacheIterator(tw, 0);
tw.addTree(workingTreeIterator);
tw.setRecursive(true);
if (!addAll)
tw.setFilter(PathFilterGroup.createFromStrings(filepatterns));

String lastAddedFile = null;
byte[] lastAdded = null;

while (tw.next()) {
String path = tw.getPathString();

DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
WorkingTreeIterator f = tw.getTree(1, WorkingTreeIterator.class);
if (tw.getTree(0, DirCacheIterator.class) == null &&
f != null && f.isEntryIgnored()) {
if (c == null && f != null && f.isEntryIgnored()) {
// 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
// DirCacheBuildIterator iterates over all stages of
// this path, we however want to add only one
// new DirCacheEntry per path.
continue;
}

if (tw.isSubtree() && !tw.isDirectoryFileConflict()) {
tw.enterSubtree();
continue;
}

if (f == null) { // working tree file does not exist
if (entry != null
&& (!update || GITLINK == entry.getFileMode())) {
builder.add(entry);
}
continue;
}

if (entry != null && entry.isAssumeValid()) {
// Index entry is marked assume valid. Even though
// the user specified the file to be added JGit does
// 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);
}
// In case of an existing merge conflict the
// DirCacheBuildIterator iterates over all stages of
// this path, we however want to add only one
// new DirCacheEntry per path.
else if (!(path.equals(lastAddedFile))) {
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) {
entry.setLength(sz);
entry.setLastModified(f
.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());
builder.add(entry);
lastAddedFile = path;
} else {
builder.add(c.getDirCacheEntry());
}

} else if (c != null
&& (!update || FileMode.GITLINK == c
.getEntryFileMode()))
builder.add(c.getDirCacheEntry());
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();
builder.commit();

+ 7
- 2
org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java View File

@@ -47,6 +47,7 @@ import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.StandardCopyOption;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
@@ -141,9 +142,13 @@ public class ApplyCommand extends GitCommand<ApplyResult> {
case RENAME:
f = getFile(fh.getOldPath(), 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(
JGitText.get().renameFileFailed, f, dest));
JGitText.get().renameFileFailed, f, dest), e);
}
break;
case COPY:
f = getFile(fh.getOldPath(), false);

+ 10
- 3
org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java View File

@@ -331,9 +331,16 @@ public class CheckoutCommand extends GitCommand<Ref> {
}

private String getShortBranchName(Ref headRef) {
if (headRef.getTarget().getName().equals(headRef.getName()))
return headRef.getTarget().getObjectId().getName();
return Repository.shortenRefName(headRef.getTarget().getName());
if (headRef.isSymbolic()) {
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();
}

/**

+ 9
- 4
org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java View File

@@ -61,6 +61,7 @@ import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
@@ -235,7 +236,7 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> {
}

if (head == null || head.getObjectId() == null)
return; // throw exception?
return; // TODO throw exception?

if (head.getName().startsWith(Constants.R_HEADS)) {
final RefUpdate newHead = clonedRepo.updateRef(Constants.HEAD);
@@ -287,20 +288,24 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> {

private Ref findBranchToCheckout(FetchResult result) {
final Ref idHEAD = result.getAdvertisedRef(Constants.HEAD);
if (idHEAD == null)
ObjectId headId = idHEAD != null ? idHEAD.getObjectId() : null;
if (headId == null) {
return null;
}

Ref master = result.getAdvertisedRef(Constants.R_HEADS
+ Constants.MASTER);
if (master != null && master.getObjectId().equals(idHEAD.getObjectId()))
ObjectId objectId = master != null ? master.getObjectId() : null;
if (headId.equals(objectId)) {
return master;
}

Ref foundBranch = null;
for (final Ref r : result.getAdvertisedRefs()) {
final String n = r.getName();
if (!n.startsWith(Constants.R_HEADS))
continue;
if (r.getObjectId().equals(idHEAD.getObjectId())) {
if (headId.equals(r.getObjectId())) {
foundBranch = r;
break;
}

+ 0
- 0
org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java View File


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

Loading…
Cancel
Save