Merge branch 'stable-4.1' into stable-4.2
* stable-4.1:
JGit v4.0.3.201509231615-r
Change-Id: I6cc5bcefad2e8dee3394770d36608f981bfc9a9e
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
diff --git a/.buckconfig b/.buckconfig
new file mode 100644
index 0000000..b2e07ac
--- /dev/null
+++ b/.buckconfig
@@ -0,0 +1,15 @@
+[buildfile]
+ includes = //tools/default.defs
+
+[java]
+ src_roots = src, resources, tst
+
+[project]
+ ignore = .git
+
+[cache]
+ mode = dir
+
+[download]
+ maven_repo = http://repo1.maven.org/maven2
+ in_build = true
diff --git a/.buckversion b/.buckversion
new file mode 100644
index 0000000..9daac2c
--- /dev/null
+++ b/.buckversion
@@ -0,0 +1 @@
+1b03b4313b91b634bd604fc3487a05f877e59dee
diff --git a/.gitignore b/.gitignore
index ea8c4bf..6c62199 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
/target
+/.project
+/buck-cache
+/buck-out
diff --git a/.mailmap b/.mailmap
index 8701b19..8f11a1c 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1,5 +1,6 @@
-Shawn Pearce <spearce@spearce.org> Shawn O. Pearce <sop@google.com>
-Shawn Pearce <spearce@spearce.org> Shawn Pearce <sop@google.com>
-Shawn Pearce <spearce@spearce.org> Shawn O. Pearce <spearce@spearce.org>
-Saša Živkov <sasa.zivkov@sap.com> Sasa Zivkov <sasa.zivkov@sap.com>
-Saša Živkov <sasa.zivkov@sap.com> Saša Živkov <zivkov@gmail.com>
+Roberto Tyley <roberto.tyley@guardian.co.uk> roberto <roberto.tyley@guardian.co.uk>
+Saša Živkov <sasa.zivkov@sap.com> Sasa Zivkov <sasa.zivkov@sap.com>
+Saša Živkov <sasa.zivkov@sap.com> Saša Živkov <zivkov@gmail.com>
+Shawn Pearce <spearce@spearce.org> Shawn O. Pearce <sop@google.com>
+Shawn Pearce <spearce@spearce.org> Shawn Pearce <sop@google.com>
+Shawn Pearce <spearce@spearce.org> Shawn O. Pearce <spearce@spearce.org>
diff --git a/BUCK b/BUCK
new file mode 100644
index 0000000..f19b7bd
--- /dev/null
+++ b/BUCK
@@ -0,0 +1,45 @@
+java_library(
+ name = 'jgit',
+ exported_deps = ['//org.eclipse.jgit:jgit'],
+ visibility = ['PUBLIC'],
+)
+
+genrule(
+ name = 'jgit_src',
+ cmd = 'ln -s $(location //org.eclipse.jgit:jgit_src) $OUT',
+ out = 'jgit_src.zip',
+ visibility = ['PUBLIC'],
+)
+
+java_library(
+ name = 'jgit-servlet',
+ exported_deps = [
+ ':jgit',
+ '//org.eclipse.jgit.http.server:jgit-servlet'
+ ],
+ visibility = ['PUBLIC'],
+)
+
+java_library(
+ name = 'jgit-archive',
+ exported_deps = [
+ ':jgit',
+ '//org.eclipse.jgit.archive:jgit-archive'
+ ],
+ visibility = ['PUBLIC'],
+)
+
+java_library(
+ name = 'junit',
+ exported_deps = [
+ ':jgit',
+ '//org.eclipse.jgit.junit:junit'
+ ],
+ visibility = ['PUBLIC'],
+)
+
+genrule(
+ name = 'jgit_bin',
+ cmd = 'ln -s $(location //org.eclipse.jgit.pgm:jgit) $OUT',
+ out = 'jgit_bin',
+)
diff --git a/lib/BUCK b/lib/BUCK
new file mode 100644
index 0000000..524612b
--- /dev/null
+++ b/lib/BUCK
@@ -0,0 +1,125 @@
+maven_jar(
+ name = 'jsch',
+ bin_sha1 = '658b682d5c817b27ae795637dfec047c63d29935',
+ src_sha1 = '791359d94d6edcace686a56d0727ee093a2f7c33',
+ group = 'com.jcraft',
+ artifact = 'jsch',
+ version = '0.1.53',
+)
+
+maven_jar(
+ name = 'javaewah',
+ bin_sha1 = 'eceaf316a8faf0e794296ebe158ae110c7d72a5a',
+ src_sha1 = 'a50d78eb630e05439461f3130b94b3bcd1ea6f03',
+ group = 'com.googlecode.javaewah',
+ artifact = 'JavaEWAH',
+ version = '0.7.9',
+)
+
+maven_jar(
+ name = 'httpcomponents',
+ bin_sha1 = '4c47155e3e6c9a41a28db36680b828ced53b8af4',
+ src_sha1 = 'af4d76be0c46ee26b0d9d1d4a34d244a633cac84',
+ group = 'org.apache.httpcomponents',
+ artifact = 'httpclient',
+ version = '4.3.6',
+)
+
+maven_jar(
+ name = 'httpcore',
+ bin_sha1 = 'f91b7a4aadc5cf486df6e4634748d7dd7a73f06d',
+ src_sha1 = '1b0aa62a6a91e9fa00c16f0a4a2c874804ed3b1e',
+ group = 'org.apache.httpcomponents',
+ artifact = 'httpcore',
+ version = '4.3.3',
+)
+
+maven_jar(
+ name = 'commons-logging',
+ bin_sha1 = 'f6f66e966c70a83ffbdb6f17a0919eaf7c8aca7f',
+ src_sha1 = '28bb0405fddaf04f15058fbfbe01fe2780d7d3b6',
+ group = 'commons-logging',
+ artifact = 'commons-logging',
+ version = '1.1.3',
+)
+
+maven_jar(
+ name = 'slf4j-api',
+ bin_sha1 = '0081d61b7f33ebeab314e07de0cc596f8e858d97',
+ src_sha1 = '58d38f68d4a867d4552ae27960bb348d7eaa1297',
+ group = 'org.slf4j',
+ artifact = 'slf4j-api',
+ version = '1.7.2',
+)
+
+maven_jar(
+ name = 'slf4j-simple',
+ bin_sha1 = '760055906d7353ba4f7ce1b8908bc6b2e91f39fa',
+ src_sha1 = '09474919128b3a7fcf21a5f9c907f5251f234544',
+ group = 'org.slf4j',
+ artifact = 'slf4j-simple',
+ version = '1.7.2',
+)
+
+maven_jar(
+ name = 'servlet-api',
+ bin_sha1 = '3cd63d075497751784b2fa84be59432f4905bf7c',
+ src_sha1 = 'ab3976d4574c48d22dc1abf6a9e8bd0fdf928223',
+ group = 'javax.servlet',
+ artifact = 'javax.servlet-api',
+ version = '3.1.0',
+)
+
+maven_jar(
+ name = 'commons-compress',
+ bin_sha1 = 'c7d9b580aff9e9f1998361f16578e63e5c064699',
+ src_sha1 = '396b81bdfd0fb617178e1707ef64832215307c78',
+ group = 'org.apache.commons',
+ artifact = 'commons-compress',
+ version = '1.6',
+)
+
+maven_jar(
+ name = 'tukaani-xz',
+ bin_sha1 = '66db21c8484120cb6a51b5b3ea47b6f383942bec',
+ src_sha1 = '6396220725701d767c553902c41120d7bf38e9f5',
+ group = 'org.tukaani',
+ artifact = 'xz',
+ version = '1.3',
+)
+
+maven_jar(
+ name = 'args4j',
+ bin_sha1 = '139441471327b9cc6d56436cb2a31e60eb6ed2ba',
+ src_sha1 = '22631b78cc8f60a6918557e8cbdb33e90f63a77f',
+ group = 'args4j',
+ artifact = 'args4j',
+ version = '2.0.15',
+)
+
+maven_jar(
+ name = 'junit',
+ bin_sha1 = '4e031bb61df09069aeb2bffb4019e7a5034a4ee0',
+ src_sha1 = '28e0ad201304e4a4abf999ca0570b7cffc352c3c',
+ group = 'junit',
+ artifact = 'junit',
+ version = '4.11',
+)
+
+maven_jar(
+ name = 'hamcrest-library',
+ bin_sha1 = '4785a3c21320980282f9f33d0d1264a69040538f',
+ src_sha1 = '047a7ee46628ab7133129cd7cef1e92657bc275e',
+ group = 'org.hamcrest',
+ artifact = 'hamcrest-library',
+ version = '1.3',
+)
+
+maven_jar(
+ name = 'hamcrest-core',
+ bin_sha1 = '42a25dc3219429f0e5d060061f71acb49bf010a0',
+ src_sha1 = '1dc37250fbc78e23a65a67fbbaf71d2e9cbc3c0b',
+ group = 'org.hamcrest',
+ artifact = 'hamcrest-core',
+ version = '1.3',
+)
diff --git a/lib/jetty/BUCK b/lib/jetty/BUCK
new file mode 100644
index 0000000..6e7dec3
--- /dev/null
+++ b/lib/jetty/BUCK
@@ -0,0 +1,56 @@
+VERSION = '9.2.13.v20150730'
+GROUP = 'org.eclipse.jetty'
+
+maven_jar(
+ name = 'servlet',
+ bin_sha1 = '5ad6e38015a97ae9a60b6c2ad744ccfa9cf93a50',
+ src_sha1 = '78fbec19321150552d91f9e079c2f2ca33222b01',
+ group = GROUP,
+ artifact = 'jetty-servlet',
+ version = VERSION,
+)
+
+maven_jar(
+ name = 'security',
+ bin_sha1 = 'cc7c7f27ec4cc279253be1675d9e47e58b995943',
+ src_sha1 = '75632ebdf8bd651faafb97106c92496db59e165d',
+ group = GROUP,
+ artifact = 'jetty-security',
+ version = VERSION,
+)
+
+maven_jar(
+ name = 'server',
+ bin_sha1 = '5be7d1da0a7abffd142de3091d160717c120b6ab',
+ src_sha1 = '203e123f83efe2a5b8a9c74854c7897fe3563302',
+ group = GROUP,
+ artifact = 'jetty-server',
+ version = VERSION,
+)
+
+maven_jar(
+ name = 'http',
+ bin_sha1 = '23a745d9177ef67ef53cc46b9b70c5870082efc2',
+ src_sha1 = '5f87f7ff2057cd4b0995bc4fffe17b2aff64c130',
+ group = GROUP,
+ artifact = 'jetty-http',
+ version = VERSION,
+)
+
+maven_jar(
+ name = 'io',
+ bin_sha1 = '7a351e6a1b63dfd56b6632623f7ca2793ffb67ad',
+ src_sha1 = 'bbd61a84b748fc295456e1c5c3070aaf40a68f62',
+ group = GROUP,
+ artifact = 'jetty-io',
+ version = VERSION,
+)
+
+maven_jar(
+ name = 'util',
+ bin_sha1 = 'c101476360a7cdd0670462de04053507d5e70c97',
+ src_sha1 = '15ceecce141971b4e0facb861b3d10120ad6ce03',
+ group = GROUP,
+ artifact = 'jetty-util',
+ version = VERSION,
+)
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index 83051f9..cfaefcd 100644
--- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
@@ -3,14 +3,14 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.ant.test
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.ant.tasks;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.junit;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.ant.tasks;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.junit;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.1,4.3.0)",
org.hamcrest;version="[1.1.0,2.0.0)",
org.junit;version="[4.0.0,5.0.0)"
diff --git a/org.eclipse.jgit.ant.test/pom.xml b/org.eclipse.jgit.ant.test/pom.xml
index 67e6c38..f1e7e36 100644
--- a/org.eclipse.jgit.ant.test/pom.xml
+++ b/org.eclipse.jgit.ant.test/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ant.test</artifactId>
diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
index 5ff9fd5..74720fe 100644
--- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
@@ -2,11 +2,11 @@
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.jgit.ant
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: org.apache.tools.ant,
- org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)"
+ org.eclipse.jgit.storage.file;version="[4.2.1,4.3.0)"
Bundle-Localization: plugin
Bundle-Vendor: %Provider-Name
-Export-Package: org.eclipse.jgit.ant.tasks;version="4.1.2";
+Export-Package: org.eclipse.jgit.ant.tasks;version="4.2.1";
uses:="org.apache.tools.ant.types,org.apache.tools.ant"
diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml
index f40e0f7..0e69457 100644
--- a/org.eclipse.jgit.ant/pom.xml
+++ b/org.eclipse.jgit.ant/pom.xml
@@ -48,7 +48,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ant</artifactId>
@@ -102,24 +102,92 @@
</configuration>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
- </plugin>
+ <plugin>
+ <groupId>com.github.siom79.japicmp</groupId>
+ <artifactId>japicmp-maven-plugin</artifactId>
+ <version>${japicmp-version}</version>
+ <configuration>
+ <oldVersion>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${jgit-last-release-version}</version>
+ </dependency>
+ </oldVersion>
+ <newVersion>
+ <file>
+ <path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+ </file>
+ </newVersion>
+ <parameter>
+ <onlyModified>true</onlyModified>
+ <includes>
+ <include>org.eclipse.jgit.*</include>
+ </includes>
+ <accessModifier>public</accessModifier>
+ <breakBuildOnModifications>false</breakBuildOnModifications>
+ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
+ <onlyBinaryIncompatible>false</onlyBinaryIncompatible>
+ <includeSynthetic>false</includeSynthetic>
+ <ignoreMissingClasses>false</ignoreMissingClasses>
+ <skipPomModules>true</skipPomModules>
+ </parameter>
+ <skip>false</skip>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>cmp</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
<reporting>
- <plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
- <version>${clirr-version}</version>
- <configuration>
- <comparisonVersion>${jgit-last-release-version}</comparisonVersion>
- <minSeverity>info</minSeverity>
- </configuration>
- </plugin>
- </plugins>
- </reporting>
+ <plugins>
+ <plugin>
+ <groupId>com.github.siom79.japicmp</groupId>
+ <artifactId>japicmp-maven-plugin</artifactId>
+ <version>${japicmp-version}</version>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>cmp-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ <configuration>
+ <oldVersion>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${jgit-last-release-version}</version>
+ </dependency>
+ </oldVersion>
+ <newVersion>
+ <file>
+ <path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+ </file>
+ </newVersion>
+ <parameter>
+ <onlyModified>true</onlyModified>
+ <includes>
+ <include>org.eclipse.jgit.*</include>
+ </includes>
+ <accessModifier>public</accessModifier>
+ <breakBuildOnModifications>false</breakBuildOnModifications>
+ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
+ <onlyBinaryIncompatible>false</onlyBinaryIncompatible>
+ <includeSynthetic>false</includeSynthetic>
+ <ignoreMissingClasses>false</ignoreMissingClasses>
+ <skipPomModules>true</skipPomModules>
+ </parameter>
+ <skip>false</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
</project>
diff --git a/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
index 4e28e0b..45d6d2c 100644
--- a/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs
@@ -1,9 +1,9 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
-org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
-org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
-org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jgit.annotations.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jgit.annotations.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jgit.annotations.Nullable
org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
diff --git a/org.eclipse.jgit.archive/BUCK b/org.eclipse.jgit.archive/BUCK
new file mode 100644
index 0000000..ae17032
--- /dev/null
+++ b/org.eclipse.jgit.archive/BUCK
@@ -0,0 +1,13 @@
+java_library(
+ name = 'jgit-archive',
+ srcs = glob(
+ ['src/**'],
+ excludes = ['src/org/eclipse/jgit/archive/FormatActivator.java'],
+ ),
+ resources = glob(['resources/**']),
+ provided_deps = [
+ '//org.eclipse.jgit:jgit',
+ '//lib:commons-compress',
+ ],
+ visibility = ['PUBLIC'],
+)
diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index 3787f86..4f3a61f 100644
--- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.archive
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
@@ -12,16 +12,15 @@
org.apache.commons.compress.compressors.bzip2;version="[1.4,2.0)",
org.apache.commons.compress.compressors.gzip;version="[1.4,2.0)",
org.apache.commons.compress.compressors.xz;version="[1.4,2.0)",
- org.eclipse.jgit.api;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.api;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.nls;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.1,4.3.0)",
org.osgi.framework;version="[1.3.0,2.0.0)"
Bundle-ActivationPolicy: lazy
Bundle-Activator: org.eclipse.jgit.archive.FormatActivator
-Export-Package: org.eclipse.jgit.archive;version="4.1.2";
+Export-Package: org.eclipse.jgit.archive;version="4.2.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.api,
org.apache.commons.compress.archivers,
org.osgi.framework"
-Require-Bundle: org.eclipse.jdt.annotation;bundle-version="[1.1.0,2.0.0)";resolution:=optional
diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
index d1f674d..61fbb7e 100644
--- a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.archive - Sources
Bundle-SymbolicName: org.eclipse.jgit.archive.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.1.2.201602141800-r
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.1.2.201602141800-r";roots="."
+Bundle-Version: 4.2.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.2.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index 377d812..b9c509f 100644
--- a/org.eclipse.jgit.archive/pom.xml
+++ b/org.eclipse.jgit.archive/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.archive</artifactId>
@@ -106,6 +106,93 @@
</archive>
</configuration>
</plugin>
+
+ <plugin>
+ <groupId>com.github.siom79.japicmp</groupId>
+ <artifactId>japicmp-maven-plugin</artifactId>
+ <version>${japicmp-version}</version>
+ <configuration>
+ <oldVersion>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${jgit-last-release-version}</version>
+ </dependency>
+ </oldVersion>
+ <newVersion>
+ <file>
+ <path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+ </file>
+ </newVersion>
+ <parameter>
+ <onlyModified>true</onlyModified>
+ <includes>
+ <include>org.eclipse.jgit.*</include>
+ </includes>
+ <accessModifier>public</accessModifier>
+ <breakBuildOnModifications>false</breakBuildOnModifications>
+ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
+ <onlyBinaryIncompatible>false</onlyBinaryIncompatible>
+ <includeSynthetic>false</includeSynthetic>
+ <ignoreMissingClasses>false</ignoreMissingClasses>
+ <skipPomModules>true</skipPomModules>
+ </parameter>
+ <skip>false</skip>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>cmp</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>com.github.siom79.japicmp</groupId>
+ <artifactId>japicmp-maven-plugin</artifactId>
+ <version>${japicmp-version}</version>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>cmp-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ <configuration>
+ <oldVersion>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${jgit-last-release-version}</version>
+ </dependency>
+ </oldVersion>
+ <newVersion>
+ <file>
+ <path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+ </file>
+ </newVersion>
+ <parameter>
+ <onlyModified>true</onlyModified>
+ <includes>
+ <include>org.eclipse.jgit.*</include>
+ </includes>
+ <accessModifier>public</accessModifier>
+ <breakBuildOnModifications>false</breakBuildOnModifications>
+ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
+ <onlyBinaryIncompatible>false</onlyBinaryIncompatible>
+ <includeSynthetic>false</includeSynthetic>
+ <ignoreMissingClasses>false</ignoreMissingClasses>
+ <skipPomModules>true</skipPomModules>
+ </parameter>
+ <skip>false</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
</project>
diff --git a/org.eclipse.jgit.http.apache/BUCK b/org.eclipse.jgit.http.apache/BUCK
new file mode 100644
index 0000000..f48f33a
--- /dev/null
+++ b/org.eclipse.jgit.http.apache/BUCK
@@ -0,0 +1,12 @@
+java_library(
+ name = 'http-apache',
+ srcs = glob(['src/**']),
+ resources = glob(['resources/**']),
+ deps = [
+ '//org.eclipse.jgit:jgit',
+ '//lib:commons-logging',
+ '//lib:httpcomponents',
+ '//lib:httpcore',
+ ],
+ visibility = ['PUBLIC'],
+)
diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index 182262f..b775549 100644
--- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
@@ -2,12 +2,13 @@
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.jgit.http.apache
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
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)",
@@ -19,10 +20,10 @@
org.apache.http.impl.client;version="[4.1.0,5.0.0)",
org.apache.http.impl.client.cache;version="[4.1.0,5.0.0)",
org.apache.http.params;version="[4.1.0,5.0.0)",
- org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport.http;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util;version="[4.1.2,4.2.0)"
-Export-Package: org.eclipse.jgit.transport.http.apache;version="4.1.2";
+ org.eclipse.jgit.nls;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport.http;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.1,4.3.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="4.2.1";
uses:="org.eclipse.jgit.transport.http,
javax.net.ssl,
org.apache.http.client,
diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml
index 7510088..e2df65b 100644
--- a/org.eclipse.jgit.http.apache/pom.xml
+++ b/org.eclipse.jgit.http.apache/pom.xml
@@ -48,7 +48,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.apache</artifactId>
@@ -96,24 +96,92 @@
</configuration>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
- </plugin>
+ <plugin>
+ <groupId>com.github.siom79.japicmp</groupId>
+ <artifactId>japicmp-maven-plugin</artifactId>
+ <version>${japicmp-version}</version>
+ <configuration>
+ <oldVersion>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${jgit-last-release-version}</version>
+ </dependency>
+ </oldVersion>
+ <newVersion>
+ <file>
+ <path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+ </file>
+ </newVersion>
+ <parameter>
+ <onlyModified>true</onlyModified>
+ <includes>
+ <include>org.eclipse.jgit.*</include>
+ </includes>
+ <accessModifier>public</accessModifier>
+ <breakBuildOnModifications>false</breakBuildOnModifications>
+ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
+ <onlyBinaryIncompatible>false</onlyBinaryIncompatible>
+ <includeSynthetic>false</includeSynthetic>
+ <ignoreMissingClasses>false</ignoreMissingClasses>
+ <skipPomModules>true</skipPomModules>
+ </parameter>
+ <skip>false</skip>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>cmp</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
<reporting>
- <plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
- <version>${clirr-version}</version>
- <configuration>
- <comparisonVersion>${jgit-last-release-version}</comparisonVersion>
- <minSeverity>info</minSeverity>
- </configuration>
- </plugin>
- </plugins>
- </reporting>
+ <plugins>
+ <plugin>
+ <groupId>com.github.siom79.japicmp</groupId>
+ <artifactId>japicmp-maven-plugin</artifactId>
+ <version>${japicmp-version}</version>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>cmp-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ <configuration>
+ <oldVersion>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${jgit-last-release-version}</version>
+ </dependency>
+ </oldVersion>
+ <newVersion>
+ <file>
+ <path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+ </file>
+ </newVersion>
+ <parameter>
+ <onlyModified>true</onlyModified>
+ <includes>
+ <include>org.eclipse.jgit.*</include>
+ </includes>
+ <accessModifier>public</accessModifier>
+ <breakBuildOnModifications>false</breakBuildOnModifications>
+ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
+ <onlyBinaryIncompatible>false</onlyBinaryIncompatible>
+ <includeSynthetic>false</includeSynthetic>
+ <ignoreMissingClasses>false</ignoreMissingClasses>
+ <skipPomModules>true</skipPomModules>
+ </parameter>
+ <skip>false</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
</project>
diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
index d42d6f2..de81bf8 100644
--- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
+++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java
@@ -100,7 +100,7 @@
public class HttpClientConnection implements HttpConnection {
HttpClient client;
- String urlStr;
+ URL url;
HttpUriRequest req;
@@ -176,16 +176,19 @@
/**
* @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 @@
* @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 URL getURL() {
- try {
- return new URL(urlStr);
- } catch (MalformedURLException e) {
- return null;
- }
+ return url;
}
public String getResponseMessage() throws IOException {
@@ -250,11 +251,11 @@
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();
diff --git a/org.eclipse.jgit.http.server/BUCK b/org.eclipse.jgit.http.server/BUCK
new file mode 100644
index 0000000..3743557
--- /dev/null
+++ b/org.eclipse.jgit.http.server/BUCK
@@ -0,0 +1,10 @@
+java_library(
+ name = 'jgit-servlet',
+ srcs = glob(['src/**']),
+ resources = glob(['resources/**']),
+ provided_deps = [
+ '//org.eclipse.jgit:jgit',
+ '//lib:servlet-api',
+ ],
+ visibility = ['PUBLIC'],
+)
diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index b66606c..9f87aab 100644
--- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
@@ -2,13 +2,13 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.http.server
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
-Export-Package: org.eclipse.jgit.http.server;version="4.1.2",
- org.eclipse.jgit.http.server.glue;version="4.1.2";
+Export-Package: org.eclipse.jgit.http.server;version="4.2.1",
+ org.eclipse.jgit.http.server.glue;version="4.2.1";
uses:="javax.servlet,javax.servlet.http",
- org.eclipse.jgit.http.server.resolver;version="4.1.2";
+ org.eclipse.jgit.http.server.resolver;version="4.2.1";
uses:="org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.lib,
org.eclipse.jgit.transport,
@@ -17,12 +17,12 @@
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: javax.servlet;version="[2.5.0,3.2.0)",
javax.servlet.http;version="[2.5.0,3.2.0)",
- org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util;version="[4.1.2,4.2.0)"
+ org.eclipse.jgit.errors;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.nls;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.1,4.3.0)"
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index ea60b00..e13e9fa 100644
--- a/org.eclipse.jgit.http.server/pom.xml
+++ b/org.eclipse.jgit.http.server/pom.xml
@@ -52,7 +52,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.server</artifactId>
@@ -127,8 +127,45 @@
</plugin>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
+ <groupId>com.github.siom79.japicmp</groupId>
+ <artifactId>japicmp-maven-plugin</artifactId>
+ <version>${japicmp-version}</version>
+ <configuration>
+ <oldVersion>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${jgit-last-release-version}</version>
+ </dependency>
+ </oldVersion>
+ <newVersion>
+ <file>
+ <path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+ </file>
+ </newVersion>
+ <parameter>
+ <onlyModified>true</onlyModified>
+ <includes>
+ <include>org.eclipse.jgit.*</include>
+ </includes>
+ <accessModifier>public</accessModifier>
+ <breakBuildOnModifications>false</breakBuildOnModifications>
+ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
+ <onlyBinaryIncompatible>false</onlyBinaryIncompatible>
+ <includeSynthetic>false</includeSynthetic>
+ <ignoreMissingClasses>false</ignoreMissingClasses>
+ <skipPomModules>true</skipPomModules>
+ </parameter>
+ <skip>false</skip>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>cmp</goal>
+ </goals>
+ </execution>
+ </executions>
</plugin>
</plugins>
</build>
@@ -136,13 +173,44 @@
<reporting>
<plugins>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
- <version>${clirr-version}</version>
- <configuration>
- <comparisonVersion>${jgit-last-release-version}</comparisonVersion>
- <minSeverity>info</minSeverity>
- </configuration>
+ <groupId>com.github.siom79.japicmp</groupId>
+ <artifactId>japicmp-maven-plugin</artifactId>
+ <version>${japicmp-version}</version>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>cmp-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ <configuration>
+ <oldVersion>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${jgit-last-release-version}</version>
+ </dependency>
+ </oldVersion>
+ <newVersion>
+ <file>
+ <path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+ </file>
+ </newVersion>
+ <parameter>
+ <onlyModified>true</onlyModified>
+ <includes>
+ <include>org.eclipse.jgit.*</include>
+ </includes>
+ <accessModifier>public</accessModifier>
+ <breakBuildOnModifications>false</breakBuildOnModifications>
+ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
+ <onlyBinaryIncompatible>false</onlyBinaryIncompatible>
+ <includeSynthetic>false</includeSynthetic>
+ <ignoreMissingClasses>false</ignoreMissingClasses>
+ <skipPomModules>true</skipPomModules>
+ </parameter>
+ <skip>false</skip>
+ </configuration>
</plugin>
</plugins>
</reporting>
diff --git a/org.eclipse.jgit.http.test/BUCK b/org.eclipse.jgit.http.test/BUCK
new file mode 100644
index 0000000..d2ced7a
--- /dev/null
+++ b/org.eclipse.jgit.http.test/BUCK
@@ -0,0 +1,40 @@
+TESTS = glob(['tst/**/*.java'])
+
+for t in TESTS:
+ n = t[len('tst/'):len(t)-len('.java')].replace('/', '.')
+ java_test(
+ name = n,
+ labels = ['http'],
+ srcs = [t],
+ deps = [
+ ':helpers',
+ '//org.eclipse.jgit:jgit',
+ '//org.eclipse.jgit.http.apache:http-apache',
+ '//org.eclipse.jgit.http.server:jgit-servlet',
+ '//org.eclipse.jgit.junit:junit',
+ '//org.eclipse.jgit.junit.http:junit-http',
+ '//lib:hamcrest-core',
+ '//lib:hamcrest-library',
+ '//lib:junit',
+ '//lib:servlet-api',
+ '//lib/jetty:http',
+ '//lib/jetty:io',
+ '//lib/jetty:server',
+ '//lib/jetty:servlet',
+ '//lib/jetty:security',
+ '//lib/jetty:util',
+ ],
+ source_under_test = ['//org.eclipse.jgit.http.server:jgit-servlet'],
+ )
+
+java_library(
+ name = 'helpers',
+ srcs = glob(['src/**/*.java']),
+ deps = [
+ '//org.eclipse.jgit:jgit',
+ '//org.eclipse.jgit.http.server:jgit-servlet',
+ '//org.eclipse.jgit.junit:junit',
+ '//org.eclipse.jgit.junit.http:junit-http',
+ '//lib:junit',
+ ],
+)
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index a5bf31a..05e4f81 100644
--- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.http.test
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
@@ -22,23 +22,23 @@
org.eclipse.jetty.util.log;version="[9.0.0,10.0.0)",
org.eclipse.jetty.util.security;version="[9.0.0,10.0.0)",
org.eclipse.jetty.util.thread;version="[9.0.0,10.0.0)",
- org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.http.server;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.http.server.glue;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.http.server.resolver;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.junit;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.junit.http;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport.http;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport.http.apache;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.errors;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.http.server;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.http.server.glue;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.http.server.resolver;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.junit;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.junit.http;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.nls;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.storage.file;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport.http;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.1,4.3.0)",
org.hamcrest.core;version="[1.1.0,2.0.0)",
org.junit;version="[4.0.0,5.0.0)",
org.junit.runner;version="[4.0.0,5.0.0)",
diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml
index 17128ed..44f7a38 100644
--- a/org.eclipse.jgit.http.test/pom.xml
+++ b/org.eclipse.jgit.http.test/pom.xml
@@ -51,7 +51,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.test</artifactId>
@@ -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>
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultReceivePackFactoryTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultReceivePackFactoryTest.java
index 772865d..f2879e0 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultReceivePackFactoryTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultReceivePackFactoryTest.java
@@ -79,6 +79,7 @@
factory = new DefaultReceivePackFactory();
}
+ @SuppressWarnings("unchecked")
@Test
public void testDisabledSingleton() throws ServiceNotAuthorizedException {
factory = (ReceivePackFactory<HttpServletRequest>) ReceivePackFactory.DISABLED;
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultUploadPackFactoryTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultUploadPackFactoryTest.java
index c9d43cd..3bcb057 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultUploadPackFactoryTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultUploadPackFactoryTest.java
@@ -77,6 +77,7 @@
factory = new DefaultUploadPackFactory();
}
+ @SuppressWarnings("unchecked")
@Test
public void testDisabledSingleton() throws ServiceNotAuthorizedException {
factory = (UploadPackFactory<HttpServletRequest>) UploadPackFactory.DISABLED;
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
index dec9b59..677132d 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
@@ -140,8 +140,7 @@
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 @@
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,15 +195,12 @@
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));
- assertEquals(B, dst.getRef(master).getObjectId());
+ assertEquals(B, dst.exactRef(master).getObjectId());
fsck(dst, B);
List<AccessEvent> loose = getRequests(loose(remoteURI, A_txt));
@@ -226,15 +217,12 @@
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));
- assertEquals(B, dst.getRef(master).getObjectId());
+ assertEquals(B, dst.exactRef(master).getObjectId());
fsck(dst, B);
List<AccessEvent> req;
@@ -265,8 +253,7 @@
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 @@
String exp = "remote does not support smart HTTP push";
assertEquals(exp, nse.getMessage());
}
- } finally {
- t.close();
}
}
}
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
index e385b95..da3a098 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
@@ -225,7 +225,7 @@
}
assertTrue(dst.hasObject(A_txt));
- assertEquals(B, dst.getRef(master).getObjectId());
+ assertEquals(B, dst.exactRef(master).getObjectId());
fsck(dst, B);
List<AccessEvent> loose = getRequests(loose(remoteURI, A_txt));
@@ -253,7 +253,7 @@
}
assertTrue(dst.hasObject(A_txt));
- assertEquals(B, dst.getRef(master).getObjectId());
+ assertEquals(B, dst.exactRef(master).getObjectId());
fsck(dst, B);
List<AccessEvent> req;
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java
index fba1a52..4b15d4b 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletResponseTests.java
@@ -60,6 +60,7 @@
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 @@
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");
}
};
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
index f1056f2..d67c817 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HookMessageTest.java
@@ -164,8 +164,8 @@
}
assertTrue(remoteRepository.hasObject(Q_txt));
- assertNotNull("has " + dstName, remoteRepository.getRef(dstName));
- assertEquals(Q, remoteRepository.getRef(dstName).getObjectId());
+ assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
+ assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
fsck(remoteRepository, Q);
List<AccessEvent> requests = getRequests();
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
index 6fb1302..ce78442 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
@@ -157,8 +157,7 @@
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 @@
+ "/info/refs?service=git-upload-pack not found";
assertEquals(exp, err.getMessage());
}
- } finally {
- t.close();
}
}
@@ -176,8 +173,7 @@
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 @@
+ "/info/refs?service=git-upload-pack not found";
assertEquals(exp, err.getMessage());
}
- } finally {
- t.close();
}
}
@@ -201,16 +195,9 @@
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 @@
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 @@
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 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 @@
@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 @@
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);
}
}
}
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
index 1b6c552..82861ed 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
@@ -211,8 +211,7 @@
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 @@
} finally {
c.close();
}
- } finally {
- t.close();
}
assertNotNull("have map of refs", map);
@@ -257,8 +254,7 @@
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 @@
assertEquals(uri + ": Git repository not found",
notFound.getMessage());
}
- } finally {
- t.close();
}
List<AccessEvent> requests = getRequests();
@@ -288,15 +282,12 @@
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));
- assertEquals(B, dst.getRef(master).getObjectId());
+ assertEquals(B, dst.exactRef(master).getObjectId());
fsck(dst, B);
List<AccessEvent> requests = getRequests();
@@ -331,13 +322,10 @@
// 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().getRef(master).getObjectId());
+ assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
List<AccessEvent> cloneRequests = getRequests();
// Only create a few new commits.
@@ -352,13 +340,10 @@
// 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().getRef(master).getObjectId());
+ assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
List<AccessEvent> requests = getRequests();
requests.removeAll(cloneRequests);
@@ -394,13 +379,10 @@
// 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().getRef(master).getObjectId());
+ assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
List<AccessEvent> cloneRequests = getRequests();
// Force enough into the local client that enumeration will
@@ -418,13 +400,10 @@
// 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().getRef(master).getObjectId());
+ assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
List<AccessEvent> requests = getRequests();
requests.removeAll(cloneRequests);
@@ -474,8 +453,7 @@
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 @@
+ " received Content-Type text/plain; charset=UTF-8";
assertEquals(exp, err.getMessage());
}
- } finally {
- t.close();
}
List<AccessEvent> requests = getRequests();
@@ -517,12 +493,10 @@
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 @@
+ JGitText.get().authenticationNotSupported;
assertEquals(exp, e.getMessage());
}
- } finally {
- t.close();
}
List<AccessEvent> requests = getRequests();
@@ -560,12 +532,10 @@
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,13 +544,11 @@
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));
- assertNotNull("has " + dstName, remoteRepository.getRef(dstName));
- assertEquals(Q, remoteRepository.getRef(dstName).getObjectId());
+ assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
+ assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
fsck(remoteRepository, Q);
final ReflogReader log = remoteRepository.getReflogReader(dstName);
@@ -633,7 +601,6 @@
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 @@
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,13 +618,11 @@
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));
- assertNotNull("has " + dstName, remoteRepository.getRef(dstName));
- assertEquals(Q, remoteRepository.getRef(dstName).getObjectId());
+ assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
+ assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
fsck(remoteRepository, Q);
List<AccessEvent> requests = getRequests();
diff --git a/org.eclipse.jgit.junit.http/BUCK b/org.eclipse.jgit.junit.http/BUCK
new file mode 100644
index 0000000..68976a6
--- /dev/null
+++ b/org.eclipse.jgit.junit.http/BUCK
@@ -0,0 +1,18 @@
+java_library(
+ name = 'junit-http',
+ srcs = glob(['src/**']),
+ resources = glob(['resources/**']),
+ provided_deps = [
+ '//org.eclipse.jgit:jgit',
+ '//org.eclipse.jgit.http.server:jgit-servlet',
+ '//org.eclipse.jgit.junit:junit',
+ '//lib:junit',
+ '//lib:servlet-api',
+ '//lib/jetty:http',
+ '//lib/jetty:server',
+ '//lib/jetty:servlet',
+ '//lib/jetty:security',
+ '//lib/jetty:util',
+ ],
+ visibility = ['PUBLIC'],
+)
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index 8a5ee6c..bec4178 100644
--- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.junit.http
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
@@ -20,16 +20,16 @@
org.eclipse.jetty.util.component;version="[9.0.0,10.0.0)",
org.eclipse.jetty.util.log;version="[9.0.0,10.0.0)",
org.eclipse.jetty.util.security;version="[9.0.0,10.0.0)",
- org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.http.server;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.junit;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.errors;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.http.server;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.junit;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.2.1,4.3.0)",
org.junit;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit.http;version="4.1.2";
+Export-Package: org.eclipse.jgit.junit.http;version="4.2.1";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.junit,
javax.servlet.http,
diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml
index d25ae00..47be76b 100644
--- a/org.eclipse.jgit.junit.http/pom.xml
+++ b/org.eclipse.jgit.junit.http/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/MockServletConfig.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/MockServletConfig.java
index 0b4530d..5976589 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/MockServletConfig.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/MockServletConfig.java
@@ -62,7 +62,7 @@
return parameters.get(name);
}
- public Enumeration getInitParameterNames() {
+ public Enumeration<String> getInitParameterNames() {
final Iterator<String> i = parameters.keySet().iterator();
return new Enumeration<String>() {
public boolean hasMoreElements() {
diff --git a/org.eclipse.jgit.junit/BUCK b/org.eclipse.jgit.junit/BUCK
new file mode 100644
index 0000000..7e25432
--- /dev/null
+++ b/org.eclipse.jgit.junit/BUCK
@@ -0,0 +1,10 @@
+java_library(
+ name = 'junit',
+ srcs = glob(['src/**']),
+ resources = glob(['resources/**']),
+ provided_deps = [
+ '//org.eclipse.jgit:jgit',
+ '//lib:junit',
+ ],
+ visibility = ['PUBLIC'],
+)
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index ea32b1b..794e3d3 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -2,27 +2,27 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.api;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.api.errors;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.dircache;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.merge;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.treewalk;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util.io;version="[4.1.2,4.2.0)",
+Import-Package: org.eclipse.jgit.api;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.api.errors;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.dircache;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.errors;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.merge;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.storage.file;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.treewalk;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util.io;version="[4.2.1,4.3.0)",
org.junit;version="[4.0.0,5.0.0)"
-Export-Package: org.eclipse.jgit.junit;version="4.1.2";
+Export-Package: org.eclipse.jgit.junit;version="4.2.1";
uses:="org.eclipse.jgit.dircache,
org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml
index d3616a7..4c7a85b 100644
--- a/org.eclipse.jgit.junit/pom.xml
+++ b/org.eclipse.jgit.junit/pom.xml
@@ -52,7 +52,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.junit</artifactId>
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
index 136c647..2962e71 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
@@ -55,6 +55,7 @@
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
+import java.nio.file.Path;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.FileUtils;
@@ -240,4 +241,21 @@
FileUtils.delete(path);
}
+ /**
+ * @param db
+ * the repository
+ * @param link
+ * the path of the symbolic link to create
+ * @param target
+ * the target of the symbolic link
+ * @return the path to the symbolic link
+ * @throws Exception
+ * @since 4.2
+ */
+ public static Path writeLink(Repository db, String link,
+ String target) throws Exception {
+ return FileUtils.createSymLink(new File(db.getWorkTree(), link),
+ target);
+ }
+
}
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
index b5348f9..4d713b5 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
@@ -51,7 +51,6 @@
import java.io.File;
import java.io.IOException;
import java.util.*;
-import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEntry;
@@ -92,11 +91,15 @@
/** A fake (but stable) identity for committer fields in the test. */
protected PersonIdent committer;
+ /**
+ * A {@link SystemReader} used to coordinate time, envars, etc.
+ * @since 4.2
+ */
+ protected MockSystemReader mockSystemReader;
+
private final List<Repository> toClose = new ArrayList<Repository>();
private File tmp;
- private MockSystemReader mockSystemReader;
-
@Before
public void setUp() throws Exception {
tmp = File.createTempFile("jgit_test_", "_tmp");
@@ -171,9 +174,8 @@
/** Increment the {@link #author} and {@link #committer} times. */
protected void tick() {
- final long delta = TimeUnit.MILLISECONDS.convert(5 * 60,
- TimeUnit.SECONDS);
- final long now = author.getWhen().getTime() + delta;
+ mockSystemReader.tick(5 * 60);
+ final long now = mockSystemReader.getCurrentTime();
final int tz = mockSystemReader.getTimezone(now);
author = new PersonIdent(author, now, tz);
@@ -278,11 +280,10 @@
throws IllegalStateException, IOException {
DirCache dc = repo.readDirCache();
StringBuilder sb = new StringBuilder();
- TreeSet<Long> timeStamps = null;
+ TreeSet<Long> timeStamps = new TreeSet<Long>();
// iterate once over the dircache just to collect all time stamps
if (0 != (includedOptions & MOD_TIME)) {
- timeStamps = new TreeSet<Long>();
for (int i=0; i<dc.getEntryCount(); ++i)
timeStamps.add(Long.valueOf(dc.getEntry(i).getLastModified()));
}
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
index d24dd44..28a9556 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
@@ -62,6 +62,9 @@
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.SystemReader;
+/**
+ * Mock {@link SystemReader} for tests.
+ */
public class MockSystemReader extends SystemReader {
private final class MockConfig extends FileBasedConfig {
private MockConfig(File cfgLocation, FS fs) {
@@ -79,6 +82,8 @@
}
}
+ long now = 1250379778668L; // Sat Aug 15 20:12:58 GMT-03:30 2009
+
final Map<String, String> values = new HashMap<String, String>();
FileBasedConfig userGitConfig;
@@ -138,7 +143,18 @@
@Override
public long getCurrentTime() {
- return 1250379778668L; // Sat Aug 15 20:12:58 GMT-03:30 2009
+ return now;
+ }
+
+ /**
+ * Adjusts the current time in seconds.
+ *
+ * @param secDelta
+ * number of seconds to add to the current time.
+ * @since 4.2
+ */
+ public void tick(final int secDelta) {
+ now += secDelta * 1000L;
}
@Override
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
index ac4539a..0db71f7 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
@@ -55,6 +55,7 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.nio.file.Path;
import java.util.Map;
import org.eclipse.jgit.api.Git;
@@ -107,6 +108,22 @@
return JGitTestUtil.writeTrashFile(db, name, data);
}
+ /**
+ * Create a symbolic link
+ *
+ * @param link
+ * the path of the symbolic link to create
+ * @param target
+ * the target of the symbolic link
+ * @return the path to the symbolic link
+ * @throws Exception
+ * @since 4.2
+ */
+ protected Path writeLink(final String link, final String target)
+ throws Exception {
+ return JGitTestUtil.writeLink(db, link, target);
+ }
+
protected File writeTrashFile(final String subdir, final String name,
final String data)
throws IOException {
@@ -266,6 +283,19 @@
}
/**
+ * Replaces '\' by '/'
+ *
+ * @param str
+ * the string in which backslashes should be replaced
+ * @return the resulting string with slashes
+ * @since 4.2
+ */
+ public static String slashify(String str) {
+ str = str.replace('\\', '/');
+ return str;
+ }
+
+ /**
* Waits until it is guaranteed that a subsequent file modification has a
* younger modification timestamp than the modification timestamp of the
* given file. This is done by touching a temporary file, reading the
@@ -371,8 +401,7 @@
* @return the created commit
*/
protected RevCommit commitFile(String filename, String contents, String branch) {
- try {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
Repository repo = git.getRepository();
String originalBranch = repo.getFullBranch();
boolean empty = repo.resolve(Constants.HEAD) == null;
@@ -413,8 +442,10 @@
final int stage, final String content) {
final DirCacheEntry entry = new DirCacheEntry(path, stage);
entry.setFileMode(mode);
- entry.setObjectId(new ObjectInserter.Formatter().idFor(
- Constants.OBJ_BLOB, Constants.encode(content)));
+ try (ObjectInserter.Formatter formatter = new ObjectInserter.Formatter()) {
+ entry.setObjectId(formatter.idFor(
+ Constants.OBJ_BLOB, Constants.encode(content)));
+ }
return entry;
}
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
index 925a6b0..e259156 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
@@ -138,7 +138,7 @@
private final ObjectInserter inserter;
- private long now;
+ private final MockSystemReader mockSystemReader;
/**
* Wrap a repository with test building tools.
@@ -148,7 +148,7 @@
* @throws IOException
*/
public TestRepository(R db) throws IOException {
- this(db, new RevWalk(db));
+ this(db, new RevWalk(db), new MockSystemReader());
}
/**
@@ -161,11 +161,29 @@
* @throws IOException
*/
public TestRepository(R db, RevWalk rw) throws IOException {
+ this(db, rw, new MockSystemReader());
+ }
+
+ /**
+ * Wrap a repository with test building tools.
+ *
+ * @param db
+ * the test repository to write into.
+ * @param rw
+ * the RevObject pool to use for object lookup.
+ * @param reader
+ * the MockSystemReader to use for clock and other system
+ * operations.
+ * @throws IOException
+ * @since 4.2
+ */
+ public TestRepository(R db, RevWalk rw, MockSystemReader reader)
+ throws IOException {
this.db = db;
this.git = Git.wrap(db);
this.pool = rw;
this.inserter = db.newObjectInserter();
- this.now = 1236977987000L;
+ this.mockSystemReader = reader;
}
/** @return the repository this helper class operates against. */
@@ -186,14 +204,28 @@
return git;
}
- /** @return current time adjusted by {@link #tick(int)}. */
+ /**
+ * @return current date.
+ * @since 4.2
+ */
+ public Date getDate() {
+ return new Date(mockSystemReader.getCurrentTime());
+ }
+
+ /**
+ * @return current date.
+ *
+ * @deprecated Use {@link #getDate()} instead.
+ */
+ @Deprecated
public Date getClock() {
- return new Date(now);
+ // Remove once Gitiles and Gerrit are using the updated JGit.
+ return getDate();
}
/** @return timezone used for default identities. */
public TimeZone getTimeZone() {
- return defaultCommitter.getTimeZone();
+ return mockSystemReader.getTimeZone();
}
/**
@@ -203,18 +235,18 @@
* number of seconds to add to the current time.
*/
public void tick(final int secDelta) {
- now += secDelta * 1000L;
+ mockSystemReader.tick(secDelta);
}
/**
- * Set the author and committer using {@link #getClock()}.
+ * Set the author and committer using {@link #getDate()}.
*
* @param c
* the commit builder to store.
*/
public void setAuthorAndCommitter(org.eclipse.jgit.lib.CommitBuilder c) {
- c.setAuthor(new PersonIdent(defaultAuthor, new Date(now)));
- c.setCommitter(new PersonIdent(defaultCommitter, new Date(now)));
+ c.setAuthor(new PersonIdent(defaultAuthor, getDate()));
+ c.setCommitter(new PersonIdent(defaultCommitter, getDate()));
}
/**
@@ -392,8 +424,8 @@
c = new org.eclipse.jgit.lib.CommitBuilder();
c.setTreeId(tree);
c.setParentIds(parents);
- c.setAuthor(new PersonIdent(defaultAuthor, new Date(now)));
- c.setCommitter(new PersonIdent(defaultCommitter, new Date(now)));
+ c.setAuthor(new PersonIdent(defaultAuthor, getDate()));
+ c.setCommitter(new PersonIdent(defaultCommitter, getDate()));
c.setMessage("");
ObjectId id;
try (ObjectInserter ins = inserter) {
@@ -428,7 +460,7 @@
final TagBuilder t = new TagBuilder();
t.setObjectId(dst);
t.setTag(name);
- t.setTagger(new PersonIdent(defaultCommitter, new Date(now)));
+ t.setTagger(new PersonIdent(defaultCommitter, getDate()));
t.setMessage("");
ObjectId id;
try (ObjectInserter ins = inserter) {
@@ -663,7 +695,7 @@
b.setParentId(head);
b.setTreeId(merger.getResultTreeId());
b.setAuthor(commit.getAuthorIdent());
- b.setCommitter(new PersonIdent(defaultCommitter, new Date(now)));
+ b.setCommitter(new PersonIdent(defaultCommitter, getDate()));
b.setMessage(commit.getFullMessage());
ObjectId result;
try (ObjectInserter ins = inserter) {
@@ -790,7 +822,7 @@
break;
final byte[] bin = db.open(o, o.getType()).getCachedBytes();
- oc.checkCommit(bin);
+ oc.checkCommit(o, bin);
assertHash(o, bin);
}
@@ -800,7 +832,7 @@
break;
final byte[] bin = db.open(o, o.getType()).getCachedBytes();
- oc.check(o.getType(), bin);
+ oc.check(o, o.getType(), bin);
assertHash(o, bin);
}
}
@@ -834,7 +866,7 @@
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();
@@ -873,7 +905,7 @@
private void writeFile(final File p, final byte[] bin) throws IOException,
ObjectWritingException {
- final LockFile lck = new LockFile(p, db.getFS());
+ final LockFile lck = new LockFile(p);
if (!lck.lock())
throw new ObjectWritingException("Can't write " + p);
try {
@@ -1100,7 +1132,7 @@
c.setAuthor(author);
if (committer != null) {
if (updateCommitterTime)
- committer = new PersonIdent(committer, new Date(now));
+ committer = new PersonIdent(committer, getDate());
c.setCommitter(committer);
}
@@ -1123,8 +1155,7 @@
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");
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
index 09b59b0..c22b3bc 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit"
label="%featureName"
- version="4.1.2.201602141800-r"
+ version="4.2.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
index ce0f9b9..cbfa6b6 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
index 31295cf..73b6eb6 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.http.apache"
label="%featureName"
- version="4.1.2.201602141800-r"
+ version="4.2.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
index 350de3c..82dfb1f 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
index cb9fbf3..186b263 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.junit"
label="%featureName"
- version="4.1.2.201602141800-r"
+ version="4.2.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
index cb76911..4cee17e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
index e1dcfcd..67ff3cf 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.pgm"
label="%featureName"
- version="4.1.2.201602141800-r"
+ version="4.2.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
@@ -27,7 +27,7 @@
version="0.0.0"/>
<requires>
- <import feature="org.eclipse.jgit" version="4.1.0" match="equivalent"/>
+ <import feature="org.eclipse.jgit" version="4.2.1" match="equivalent"/>
</requires>
<plugin
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
index 9076053..8cbbdc5 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
index bbd0aa0..d53df31 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.pgm.source"
label="%featureName"
- version="4.1.2.201602141800-r"
+ version="4.2.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
index 0e64da4..8dd726d 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
index 88ad032..bf8c7cb 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.repository</artifactId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
index 17030ff..38db4f6 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml
@@ -2,7 +2,7 @@
<feature
id="org.eclipse.jgit.source"
label="%featureName"
- version="4.1.2.201602141800-r"
+ version="4.2.1.qualifier"
provider-name="%providerName">
<description url="http://www.eclipse.org/jgit/">
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
index aa7128e..ef6de2b 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.jgit.feature</groupId>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
index 38732b5..09e7c94 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF
@@ -2,4 +2,4 @@
Bundle-ManifestVersion: 2
Bundle-Name: JGit Target Platform Bundle
Bundle-SymbolicName: org.eclipse.jgit.target
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
index 9b565ec..a4fcefa 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml
@@ -49,7 +49,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.target</artifactId>
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index 3b5b7d8..7231c9c 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -53,7 +53,7 @@
<groupId>org.eclipse.jgit</groupId>
<artifactId>jgit.tycho.parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>JGit Tycho Parent</name>
diff --git a/org.eclipse.jgit.pgm.test/BUCK b/org.eclipse.jgit.pgm.test/BUCK
new file mode 100644
index 0000000..a3859c9
--- /dev/null
+++ b/org.eclipse.jgit.pgm.test/BUCK
@@ -0,0 +1,38 @@
+TESTS = glob(['tst/**/*.java'])
+
+for t in TESTS:
+ n = t[len('tst/'):len(t)-len('.java')].replace('/', '.')
+ java_test(
+ name = n,
+ labels = ['pgm'],
+ srcs = [t],
+ deps = [
+ ':helpers',
+ '//org.eclipse.jgit:jgit',
+ '//org.eclipse.jgit.archive:jgit-archive',
+ '//org.eclipse.jgit.junit:junit',
+ '//org.eclipse.jgit.pgm:pgm',
+ '//lib:hamcrest-core',
+ '//lib:hamcrest-library',
+ '//lib:javaewah',
+ '//lib:junit',
+ '//lib:slf4j-api',
+ '//lib:slf4j-simple',
+ '//lib:commons-compress',
+ '//lib:tukaani-xz',
+ ],
+ source_under_test = ['//org.eclipse.jgit.pgm:pgm'],
+ vm_args = ['-Xmx256m', '-Dfile.encoding=UTF-8'],
+ )
+
+java_library(
+ name = 'helpers',
+ srcs = glob(['src/**/*.java']),
+ deps = [
+ '//org.eclipse.jgit:jgit',
+ '//org.eclipse.jgit.pgm:pgm',
+ '//org.eclipse.jgit.junit:junit',
+ '//lib:args4j',
+ '//lib:junit',
+ ],
+)
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index 1693bee..b64f5f0 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -2,27 +2,28 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.pgm.test
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: org.eclipse.jgit.api;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.api.errors;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.diff;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.dircache;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.junit;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.merge;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.pgm;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.pgm.internal;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.pgm.opt;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.treewalk;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util.io;version="[4.1.2,4.2.0)",
+Import-Package: org.eclipse.jgit.api;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.api.errors;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.diff;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.dircache;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="4.2.1",
+ org.eclipse.jgit.junit;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.merge;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.pgm;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.pgm.internal;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.pgm.opt;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.storage.file;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.treewalk;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util.io;version="[4.2.1,4.3.0)",
org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
org.junit;version="[4.4.0,5.0.0)",
org.kohsuke.args4j;version="[2.0.12,2.1.0)"
diff --git "a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java7\051.launch" "b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java7\051.launch"
index 600ce7b..3df0dcb 100644
--- "a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java7\051.launch"
+++ "b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java7\051.launch"
@@ -15,12 +15,6 @@
<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"/>
-<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
-<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7" path="1" type="4"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="org.eclipse.jgit.pgm.test"/> </runtimeClasspathEntry> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry path="3" projectName="org.eclipse.jgit.java7" type="1"/> "/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.pgm.test"/>
diff --git "a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051 \050de\051.launch" "b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051 \050de\051.launch"
new file mode 100644
index 0000000..5c137f2
--- /dev/null
+++ "b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051 \050de\051.launch"
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.eclipse.jgit.pgm.test/tst"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="2"/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+<mapAttribute key="org.eclipse.debug.core.environmentVariables">
+<mapEntry key="LANG" value="de_DE.UTF-8"/>
+</mapAttribute>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.pgm.test/tst"/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
+<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
+<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7" path="1" type="4"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="org.eclipse.jgit.pgm.test"/> </runtimeClasspathEntry> "/>
+</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>
diff --git "a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051.launch" "b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051.launch"
index 1b61d3d..ce473ed 100644
--- "a/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051.launch"
+++ "b/org.eclipse.jgit.pgm.test/org.eclipse.jgit.pgm--All-Tests \050Java8\051.launch"
@@ -19,7 +19,6 @@
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7" path="1" type="4"/> "/>
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="org.eclipse.jgit.pgm.test"/> </runtimeClasspathEntry> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry path="3" projectName="org.eclipse.jgit.java7" type="1"/> "/>
</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"/>
diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml
index cca2e92..135bf65 100644
--- a/org.eclipse.jgit.pgm.test/pom.xml
+++ b/org.eclipse.jgit.pgm.test/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.pgm.test</artifactId>
diff --git a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
index 50ddfe0..a6af077 100644
--- a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
+++ b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
@@ -46,12 +46,16 @@
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 @@
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);
@@ -164,16 +214,45 @@
.replaceAll("\t", "\\\\t");
}
- protected void assertArrayOfLinesEquals(String[] expected, String[] actual) {
- assertEquals(toText(expected), toText(actual));
+ protected void assertStringArrayEquals(String expected, String[] actual) {
+ // if there is more than one line, ignore last one if empty
+ assertEquals(1,
+ actual.length > 1 && actual[actual.length - 1].equals("")
+ ? actual.length - 1 : actual.length);
+ assertEquals(expected, actual[0]);
}
- private static String toText(String[] lines) {
+ protected void assertArrayOfLinesEquals(String[] expected, String[] actual) {
+ assertEquals(toString(expected), toString(actual));
+ }
+
+ public static String toString(String... lines) {
+ return toString(Arrays.asList(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;
+ }
}
diff --git a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java
index d77b150..3f39656 100644
--- a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java
+++ b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java
@@ -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 {
- return IO.readLines(new String(rawExecute(str, db)));
- } catch (Die e) {
- return IO.readLines(MessageFormat.format(CLIText.get().fatalError,
- e.getMessage()));
+ cmd.run(str);
+ return getOutput(cmd.result);
+ } catch (Throwable e) {
+ return cmd.result.errLines();
}
}
- public static byte[] rawExecute(String str, Repository db)
+ 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 {
+ super.run(argv);
+ } catch (TerminatedByHelpException e) {
+ // this is not a failure, super called exit() on help
+ } finally {
+ writer.flush();
+ }
+ }
+
+ 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);
+ @Override
+ PrintWriter createErrorWriter() {
+ return new PrintWriter(result.err);
+ }
- 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();
+ 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 @@
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());
+ }
+ }
+
}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/AddTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/AddTest.java
index 4253080..3edd9b8 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/AddTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/AddTest.java
@@ -45,15 +45,12 @@
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 @@
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");
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
index 4222a2d..a503ffd 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
@@ -52,17 +52,15 @@
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.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 @@
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 @@
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 @@
@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 @@
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 @@
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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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"));
}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/BranchTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/BranchTest.java
index 4200cd0..55f4d8b 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/BranchTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/BranchTest.java
@@ -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;
@@ -57,13 +63,25 @@
@Before
public void setUp() throws Exception {
super.setUp();
- new Git(db).commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ }
+ }
+
+ @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
@@ -71,24 +89,188 @@
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 {
- new Git(db).branchCreate().setName("initial").call();
- RevCommit second = new Git(db).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()));
+ try (Git git = new Git(db)) {
+ git.branchCreate().setName("initial").call();
+ RevCommit second = git.commit().setMessage("second commit")
+ .call();
+ 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());
}
}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
index 387eb2b..e690ad6 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java
@@ -44,9 +44,14 @@
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,34 +64,42 @@
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 {
@Test
public void testCheckoutSelf() throws Exception {
- new Git(db).commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
- assertStringArrayEquals("Already on 'master'",
- execute("git checkout master"));
+ assertStringArrayEquals("Already on 'master'",
+ execute("git checkout master"));
+ }
}
@Test
public void testCheckoutBranch() throws Exception {
- new Git(db).commit().setMessage("initial commit").call();
- new Git(db).branchCreate().setName("side").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ git.branchCreate().setName("side").call();
- assertStringArrayEquals("Switched to branch 'side'",
- execute("git checkout side"));
+ assertStringArrayEquals("Switched to branch 'side'",
+ execute("git checkout side"));
+ }
}
@Test
public void testCheckoutNewBranch() throws Exception {
- new Git(db).commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
- assertStringArrayEquals("Switched to a new branch 'side'",
- execute("git checkout -b side"));
+ assertStringArrayEquals("Switched to a new branch 'side'",
+ execute("git checkout -b side"));
+ }
}
@Test
@@ -98,17 +111,19 @@
@Test
public void testCheckoutNewBranchThatAlreadyExists() throws Exception {
- new Git(db).commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
- assertStringArrayEquals(
- "fatal: A branch named 'master' already exists.",
- execute("git checkout -b master"));
+ assertStringArrayEquals(
+ "fatal: A branch named 'master' already exists.",
+ 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
@@ -120,32 +135,35 @@
@Test
public void testCheckoutHead() throws Exception {
- new Git(db).commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
- assertStringArrayEquals("", execute("git checkout HEAD"));
+ assertStringArrayEquals("", execute("git checkout HEAD"));
+ }
}
@Test
public void testCheckoutExistingBranchWithConflict() throws Exception {
- Git git = new Git(db);
- writeTrashFile("a", "Hello world a");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("commit file a").call();
- git.branchCreate().setName("branch_1").call();
- git.rm().addFilepattern("a").call();
- FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
- writeTrashFile("a/b", "Hello world b");
- git.add().addFilepattern("a/b").call();
- git.commit().setMessage("commit folder a").call();
- git.rm().addFilepattern("a").call();
- writeTrashFile("a", "New Hello world a");
- git.add().addFilepattern(".").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "Hello world a");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("commit file a").call();
+ git.branchCreate().setName("branch_1").call();
+ git.rm().addFilepattern("a").call();
+ FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
+ writeTrashFile("a/b", "Hello world b");
+ git.add().addFilepattern("a/b").call();
+ git.commit().setMessage("commit folder a").call();
+ git.rm().addFilepattern("a").call();
+ writeTrashFile("a", "New Hello world a");
+ git.add().addFilepattern(".").call();
- String[] execute = execute("git checkout branch_1");
- assertEquals(
- "error: Your local changes to the following files would be overwritten by checkout:",
- execute[0]);
- assertEquals("\ta", execute[1]);
+ String[] execute = execute("git checkout branch_1");
+ assertEquals(
+ "error: Your local changes to the following files would be overwritten by checkout:",
+ execute[0]);
+ assertEquals("\ta", execute[1]);
+ }
}
/**
@@ -167,40 +185,43 @@
*/
@Test
public void testCheckoutWithMissingWorkingTreeFile() throws Exception {
- Git git = new Git(db);
- File fileA = writeTrashFile("a", "Hello world a");
- writeTrashFile("b", "Hello world b");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add files a & b").call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- writeTrashFile("a", "b");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("modify file a").call();
+ try (Git git = new Git(db)) {
+ File fileA = writeTrashFile("a", "Hello world a");
+ writeTrashFile("b", "Hello world b");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add files a & b").call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ writeTrashFile("a", "b");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("modify file a").call();
- FileEntry entry = new FileTreeIterator.FileEntry(new File(
- db.getWorkTree(), "a"), db.getFS());
- assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ FileEntry entry = new FileTreeIterator.FileEntry(new File(
+ db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.REGULAR_FILE, entry.getMode());
- FileUtils.delete(fileA);
+ FileUtils.delete(fileA);
- git.checkout().setName(branch_1.getName()).call();
+ git.checkout().setName(branch_1.getName()).call();
- entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
- db.getFS());
- assertEquals(FileMode.REGULAR_FILE, entry.getMode());
- assertEquals("Hello world a", read(fileA));
+ entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
+ db.getFS());
+ assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ assertEquals("Hello world a", read(fileA));
+ }
}
@Test
public void testCheckoutOrphan() throws Exception {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
- assertStringArrayEquals("Switched to a new branch 'new_branch'",
- execute("git checkout --orphan new_branch"));
- assertEquals("refs/heads/new_branch", db.getRef("HEAD").getTarget().getName());
- RevCommit commit = git.commit().setMessage("orphan commit").call();
- assertEquals(0, commit.getParentCount());
+ assertStringArrayEquals("Switched to a new branch 'new_branch'",
+ execute("git checkout --orphan new_branch"));
+ assertEquals("refs/heads/new_branch",
+ db.exactRef("HEAD").getTarget().getName());
+ RevCommit commit = git.commit().setMessage("orphan commit").call();
+ assertEquals(0, commit.getParentCount());
+ }
}
/**
@@ -223,33 +244,34 @@
@Test
public void fileModeTestMissingThenFolderWithFileInWorkingTree()
throws Exception {
- Git git = new Git(db);
- writeTrashFile("b", "Hello world b");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add file b").call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- File folderA = new File(db.getWorkTree(), "a");
- FileUtils.mkdirs(folderA);
- writeTrashFile("a/c", "Hello world c");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add folder a").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("b", "Hello world b");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add file b").call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ File folderA = new File(db.getWorkTree(), "a");
+ FileUtils.mkdirs(folderA);
+ writeTrashFile("a/c", "Hello world c");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add folder a").call();
- FileEntry entry = new FileTreeIterator.FileEntry(new File(
- db.getWorkTree(), "a"), db.getFS());
- assertEquals(FileMode.TREE, entry.getMode());
+ FileEntry entry = new FileTreeIterator.FileEntry(new File(
+ db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.TREE, entry.getMode());
- FileUtils.delete(folderA, FileUtils.RECURSIVE);
- writeTrashFile("a", "b");
+ FileUtils.delete(folderA, FileUtils.RECURSIVE);
+ writeTrashFile("a", "b");
- entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
- db.getFS());
- assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
+ db.getFS());
+ assertEquals(FileMode.REGULAR_FILE, entry.getMode());
- git.checkout().setName(branch_1.getName()).call();
+ git.checkout().setName(branch_1.getName()).call();
- entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
- db.getFS());
- assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
+ db.getFS());
+ assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ }
}
/**
@@ -271,30 +293,31 @@
*/
@Test
public void fileModeTestFolderWithMissingInWorkingTree() throws Exception {
- Git git = new Git(db);
- writeTrashFile("b", "Hello world b");
- writeTrashFile("a", "b");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add file b & file a").call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- git.rm().addFilepattern("a").call();
- File folderA = new File(db.getWorkTree(), "a");
- FileUtils.mkdirs(folderA);
- writeTrashFile("a/c", "Hello world c");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add folder a").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("b", "Hello world b");
+ writeTrashFile("a", "b");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add file b & file a").call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ git.rm().addFilepattern("a").call();
+ File folderA = new File(db.getWorkTree(), "a");
+ FileUtils.mkdirs(folderA);
+ writeTrashFile("a/c", "Hello world c");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add folder a").call();
- FileEntry entry = new FileTreeIterator.FileEntry(new File(
- db.getWorkTree(), "a"), db.getFS());
- assertEquals(FileMode.TREE, entry.getMode());
+ FileEntry entry = new FileTreeIterator.FileEntry(new File(
+ db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.TREE, entry.getMode());
- FileUtils.delete(folderA, FileUtils.RECURSIVE);
+ FileUtils.delete(folderA, FileUtils.RECURSIVE);
- git.checkout().setName(branch_1.getName()).call();
+ git.checkout().setName(branch_1.getName()).call();
- entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
- db.getFS());
- assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
+ db.getFS());
+ assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ }
}
/**
@@ -316,32 +339,33 @@
*/
@Test
public void fileModeTestMissingWithFolderInWorkingTree() throws Exception {
- Git git = new Git(db);
- writeTrashFile("b", "Hello world b");
- writeTrashFile("a", "b");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add file b & file a").call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- git.rm().addFilepattern("a").call();
- git.commit().setMessage("delete file a").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("b", "Hello world b");
+ writeTrashFile("a", "b");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add file b & file a").call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ git.rm().addFilepattern("a").call();
+ git.commit().setMessage("delete file a").call();
- FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
- writeTrashFile("a/c", "Hello world c");
+ FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
+ writeTrashFile("a/c", "Hello world c");
- FileEntry entry = new FileTreeIterator.FileEntry(new File(
- db.getWorkTree(), "a"), db.getFS());
- assertEquals(FileMode.TREE, entry.getMode());
+ FileEntry entry = new FileTreeIterator.FileEntry(new File(
+ db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.TREE, entry.getMode());
- CheckoutConflictException exception = null;
- try {
- git.checkout().setName(branch_1.getName()).call();
- } catch (CheckoutConflictException e) {
- exception = e;
+ CheckoutConflictException exception = null;
+ try {
+ git.checkout().setName(branch_1.getName()).call();
+ } catch (CheckoutConflictException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ assertEquals(2, exception.getConflictingPaths().size());
+ assertEquals("a", exception.getConflictingPaths().get(0));
+ assertEquals("a/c", exception.getConflictingPaths().get(1));
}
- assertNotNull(exception);
- assertEquals(2, exception.getConflictingPaths().size());
- assertEquals("a", exception.getConflictingPaths().get(0));
- assertEquals("a/c", exception.getConflictingPaths().get(1));
}
/**
@@ -363,40 +387,41 @@
@Test
public void fileModeTestFolderThenMissingWithFileInWorkingTree()
throws Exception {
- Git git = new Git(db);
- FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
- writeTrashFile("a/c", "Hello world c");
- writeTrashFile("b", "Hello world b");
- git.add().addFilepattern(".").call();
- RevCommit commit1 = git.commit().setMessage("add folder a & file b")
- .call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- git.rm().addFilepattern("a").call();
- RevCommit commit2 = git.commit().setMessage("delete folder a").call();
+ try (Git git = new Git(db)) {
+ FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
+ writeTrashFile("a/c", "Hello world c");
+ writeTrashFile("b", "Hello world b");
+ git.add().addFilepattern(".").call();
+ RevCommit commit1 = git.commit().setMessage("add folder a & file b")
+ .call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ git.rm().addFilepattern("a").call();
+ RevCommit commit2 = git.commit().setMessage("delete folder a").call();
- TreeWalk tw = new TreeWalk(db);
- tw.addTree(commit1.getTree());
- tw.addTree(commit2.getTree());
- List<DiffEntry> scan = DiffEntry.scan(tw);
- assertEquals(1, scan.size());
- assertEquals(FileMode.MISSING, scan.get(0).getNewMode());
- assertEquals(FileMode.TREE, scan.get(0).getOldMode());
+ TreeWalk tw = new TreeWalk(db);
+ tw.addTree(commit1.getTree());
+ tw.addTree(commit2.getTree());
+ List<DiffEntry> scan = DiffEntry.scan(tw);
+ assertEquals(1, scan.size());
+ assertEquals(FileMode.MISSING, scan.get(0).getNewMode());
+ assertEquals(FileMode.TREE, scan.get(0).getOldMode());
- writeTrashFile("a", "b");
+ writeTrashFile("a", "b");
- FileEntry entry = new FileTreeIterator.FileEntry(new File(
- db.getWorkTree(), "a"), db.getFS());
- assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ FileEntry entry = new FileTreeIterator.FileEntry(new File(
+ db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.REGULAR_FILE, entry.getMode());
- CheckoutConflictException exception = null;
- try {
- git.checkout().setName(branch_1.getName()).call();
- } catch (CheckoutConflictException e) {
- exception = e;
+ CheckoutConflictException exception = null;
+ try {
+ git.checkout().setName(branch_1.getName()).call();
+ } catch (CheckoutConflictException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ assertEquals(1, exception.getConflictingPaths().size());
+ assertEquals("a", exception.getConflictingPaths().get(0));
}
- assertNotNull(exception);
- assertEquals(1, exception.getConflictingPaths().size());
- assertEquals("a", exception.getConflictingPaths().get(0));
}
/**
@@ -419,30 +444,31 @@
@Test
public void fileModeTestFolderThenFileWithMissingInWorkingTree()
throws Exception {
- Git git = new Git(db);
- FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
- writeTrashFile("a/c", "Hello world c");
- writeTrashFile("b", "Hello world b");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add folder a & file b").call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- git.rm().addFilepattern("a").call();
- File fileA = new File(db.getWorkTree(), "a");
- writeTrashFile("a", "b");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("add file a").call();
+ try (Git git = new Git(db)) {
+ FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
+ writeTrashFile("a/c", "Hello world c");
+ writeTrashFile("b", "Hello world b");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add folder a & file b").call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ git.rm().addFilepattern("a").call();
+ File fileA = new File(db.getWorkTree(), "a");
+ writeTrashFile("a", "b");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("add file a").call();
- FileEntry entry = new FileTreeIterator.FileEntry(new File(
- db.getWorkTree(), "a"), db.getFS());
- assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ FileEntry entry = new FileTreeIterator.FileEntry(new File(
+ db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.REGULAR_FILE, entry.getMode());
- FileUtils.delete(fileA);
+ FileUtils.delete(fileA);
- git.checkout().setName(branch_1.getName()).call();
+ git.checkout().setName(branch_1.getName()).call();
- entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
- db.getFS());
- assertEquals(FileMode.TREE, entry.getMode());
+ entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
+ db.getFS());
+ assertEquals(FileMode.TREE, entry.getMode());
+ }
}
/**
@@ -463,38 +489,39 @@
*/
@Test
public void fileModeTestFileThenFileWithFolderInIndex() throws Exception {
- Git git = new Git(db);
- writeTrashFile("a", "Hello world a");
- writeTrashFile("b", "Hello world b");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add files a & b").call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- writeTrashFile("a", "b");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("add file a").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "Hello world a");
+ writeTrashFile("b", "Hello world b");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add files a & b").call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ writeTrashFile("a", "b");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("add file a").call();
- FileEntry entry = new FileTreeIterator.FileEntry(new File(
- db.getWorkTree(), "a"), db.getFS());
- assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ FileEntry entry = new FileTreeIterator.FileEntry(new File(
+ db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.REGULAR_FILE, entry.getMode());
- git.rm().addFilepattern("a").call();
- FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
- writeTrashFile("a/c", "Hello world c");
- git.add().addFilepattern(".").call();
+ git.rm().addFilepattern("a").call();
+ FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
+ writeTrashFile("a/c", "Hello world c");
+ git.add().addFilepattern(".").call();
- entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
- db.getFS());
- assertEquals(FileMode.TREE, entry.getMode());
+ entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
+ db.getFS());
+ assertEquals(FileMode.TREE, entry.getMode());
- CheckoutConflictException exception = null;
- try {
- git.checkout().setName(branch_1.getName()).call();
- } catch (CheckoutConflictException e) {
- exception = e;
+ CheckoutConflictException exception = null;
+ try {
+ git.checkout().setName(branch_1.getName()).call();
+ } catch (CheckoutConflictException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ assertEquals(1, exception.getConflictingPaths().size());
+ assertEquals("a", exception.getConflictingPaths().get(0));
}
- assertNotNull(exception);
- assertEquals(1, exception.getConflictingPaths().size());
- assertEquals("a", exception.getConflictingPaths().get(0));
}
/**
@@ -516,74 +543,97 @@
*/
@Test
public void fileModeTestFileWithFolderInIndex() throws Exception {
- Git git = new Git(db);
- writeTrashFile("b", "Hello world b");
- writeTrashFile("a", "b");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add file b & file a").call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- git.rm().addFilepattern("a").call();
- writeTrashFile("a", "Hello world a");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("add file a").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("b", "Hello world b");
+ writeTrashFile("a", "b");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add file b & file a").call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ git.rm().addFilepattern("a").call();
+ writeTrashFile("a", "Hello world a");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("add file a").call();
- FileEntry entry = new FileTreeIterator.FileEntry(new File(
- db.getWorkTree(), "a"), db.getFS());
- assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ FileEntry entry = new FileTreeIterator.FileEntry(new File(
+ db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.REGULAR_FILE, entry.getMode());
- git.rm().addFilepattern("a").call();
- FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
- writeTrashFile("a/c", "Hello world c");
- git.add().addFilepattern(".").call();
+ git.rm().addFilepattern("a").call();
+ FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
+ writeTrashFile("a/c", "Hello world c");
+ git.add().addFilepattern(".").call();
- entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
- db.getFS());
- assertEquals(FileMode.TREE, entry.getMode());
+ entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
+ db.getFS());
+ assertEquals(FileMode.TREE, entry.getMode());
- CheckoutConflictException exception = null;
- try {
- git.checkout().setName(branch_1.getName()).call();
- } catch (CheckoutConflictException e) {
- exception = e;
+ CheckoutConflictException exception = null;
+ try {
+ git.checkout().setName(branch_1.getName()).call();
+ } catch (CheckoutConflictException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ assertEquals(1, exception.getConflictingPaths().size());
+ assertEquals("a", exception.getConflictingPaths().get(0));
+
+ // TODO: ideally we'd like to get two paths from this exception
+ // assertEquals(2, exception.getConflictingPaths().size());
+ // assertEquals("a", exception.getConflictingPaths().get(0));
+ // assertEquals("a/c", exception.getConflictingPaths().get(1));
}
- assertNotNull(exception);
- assertEquals(1, exception.getConflictingPaths().size());
- assertEquals("a", exception.getConflictingPaths().get(0));
-
- // TODO: ideally we'd like to get two paths from this exception
- // assertEquals(2, exception.getConflictingPaths().size());
- // assertEquals("a", exception.getConflictingPaths().get(0));
- // assertEquals("a/c", exception.getConflictingPaths().get(1));
- }
-
- static private void assertStringArrayEquals(String expected, String[] actual) {
- // if there is more than one line, ignore last one if empty
- assertEquals(
- 1,
- actual.length > 1 && actual[actual.length - 1].equals("") ? actual.length - 1
- : actual.length);
- assertEquals(expected, actual[0]);
}
@Test
public void testCheckoutPath() throws Exception {
- Git git = new Git(db);
- writeTrashFile("a", "Hello world a");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("commit file a").call();
- git.branchCreate().setName("branch_1").call();
- git.checkout().setName("branch_1").call();
- File b = writeTrashFile("b", "Hello world b");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("commit file b").call();
- File a = writeTrashFile("a", "New Hello world a");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("modified a").call();
- assertArrayEquals(new String[] { "" },
- execute("git checkout HEAD~2 -- a"));
- assertEquals("Hello world a", read(a));
- assertArrayEquals(new String[] { "* branch_1", " master", "" },
- execute("git branch"));
- assertEquals("Hello world b", read(b));
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "Hello world a");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("commit file a").call();
+ git.branchCreate().setName("branch_1").call();
+ git.checkout().setName("branch_1").call();
+ File b = writeTrashFile("b", "Hello world b");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("commit file b").call();
+ File a = writeTrashFile("a", "New Hello world a");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("modified a").call();
+ assertArrayEquals(new String[] { "" },
+ execute("git checkout HEAD~2 -- a"));
+ assertEquals("Hello world a", read(a));
+ assertArrayEquals(new String[] { "* branch_1", " master", "" },
+ execute("git branch"));
+ 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));
+ }
}
}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CommitTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CommitTest.java
new file mode 100644
index 0000000..6bccb6d
--- /dev/null
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CommitTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015, Andrey Loskutov <loskutov@gmx.de>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.pgm;
+
+import static org.junit.Assert.assertEquals;
+
+import org.eclipse.jgit.lib.CLIRepositoryTestCase;
+import org.junit.Test;
+
+public class CommitTest extends CLIRepositoryTestCase {
+
+ @Test
+ public void testCommitPath() throws Exception {
+ writeTrashFile("a", "a");
+ writeTrashFile("b", "a");
+ String result = toString(execute("git add a"));
+ assertEquals("", result);
+
+ result = toString(execute("git status -- a"));
+ assertEquals(toString("On branch master", "Changes to be committed:",
+ "new file: a"), result);
+
+ result = toString(execute("git status -- b"));
+ assertEquals(toString("On branch master", "Untracked files:", "b"),
+ result);
+
+ result = toString(execute("git commit a -m 'added a'"));
+ assertEquals(
+ "[master 8cb3ef7e5171aaee1792df6302a5a0cd30425f7a] added a",
+ result);
+
+ result = toString(execute("git status -- a"));
+ assertEquals("On branch master", result);
+
+ result = toString(execute("git status -- b"));
+ assertEquals(toString("On branch master", "Untracked files:", "b"),
+ result);
+ }
+
+ @Test
+ public void testCommitAll() throws Exception {
+ writeTrashFile("a", "a");
+ writeTrashFile("b", "a");
+ String result = toString(execute("git add a b"));
+ assertEquals("", result);
+
+ result = toString(execute("git status -- a b"));
+ assertEquals(toString("On branch master", "Changes to be committed:",
+ "new file: a", "new file: b"), result);
+
+ result = toString(execute("git commit -m 'added a b'"));
+ assertEquals(
+ "[master 3c93fa8e3a28ee26690498be78016edcb3a38c73] added a b",
+ result);
+
+ result = toString(execute("git status -- a b"));
+ assertEquals("On branch master", result);
+ }
+
+}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ConfigTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ConfigTest.java
index aefdff1..23aa97e 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ConfigTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ConfigTest.java
@@ -60,7 +60,9 @@
@Before
public void setUp() throws Exception {
super.setUp();
- new Git(db).commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ }
}
@Test
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java
index 6352a26..086e72e 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DescribeTest.java
@@ -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 @@
@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 @@
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"));
+ }
}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeTest.java
index 975e8c4..4719901 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeTest.java
@@ -50,6 +50,7 @@
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 @@
@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 @@
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
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ReflogTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ReflogTest.java
index ce80832..7330ee9 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ReflogTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ReflogTest.java
@@ -57,24 +57,27 @@
@Test
public void testSingleCommit() throws Exception {
- new Git(db).commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
- assertEquals("6fd41be HEAD@{0}: commit (initial): initial commit",
- execute("git reflog")[0]);
+ assertEquals("6fd41be HEAD@{0}: commit (initial): initial commit",
+ execute("git reflog")[0]);
+ }
}
@Test
public void testBranch() throws Exception {
- Git git = new Git(db);
- git.commit().setMessage("first commit").call();
- git.checkout().setCreateBranch(true).setName("side").call();
- writeTrashFile("file", "side content");
- git.add().addFilepattern("file").call();
- git.commit().setMessage("side commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("first commit").call();
+ git.checkout().setCreateBranch(true).setName("side").call();
+ writeTrashFile("file", "side content");
+ git.add().addFilepattern("file").call();
+ git.commit().setMessage("side commit").call();
- assertArrayEquals(new String[] {
- "38890c7 side@{0}: commit: side commit",
- "d216986 side@{1}: branch: Created from commit first commit",
- "" }, execute("git reflog refs/heads/side"));
+ assertArrayEquals(new String[] {
+ "38890c7 side@{0}: commit: side commit",
+ "d216986 side@{1}: branch: Created from commit first commit",
+ "" }, execute("git reflog refs/heads/side"));
+ }
}
}
\ No newline at end of file
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RemoteTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RemoteTest.java
new file mode 100644
index 0000000..58e0e19
--- /dev/null
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RemoteTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.pgm;
+
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.lib.CLIRepositoryTestCase;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.transport.RefSpec;
+import org.eclipse.jgit.transport.RemoteConfig;
+import org.eclipse.jgit.transport.URIish;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RemoteTest extends CLIRepositoryTestCase {
+
+ private StoredConfig config;
+
+ private RemoteConfig remote;
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // create another repository
+ Repository remoteRepository = createWorkRepository();
+
+ // set it up as a remote to this repository
+ config = db.getConfig();
+ remote = new RemoteConfig(config, "test");
+ remote.addFetchRefSpec(
+ new RefSpec("+refs/heads/*:refs/remotes/test/*"));
+ URIish uri = new URIish(
+ remoteRepository.getDirectory().toURI().toURL());
+ remote.addURI(uri);
+ remote.update(config);
+ config.save();
+
+ Git.wrap(remoteRepository).commit().setMessage("initial commit").call();
+ }
+
+ @Test
+ public void testList() throws Exception {
+ assertArrayEquals(new String[] { remote.getName(), "" },
+ execute("git remote"));
+ }
+
+ @Test
+ public void testVerboseList() throws Exception {
+ assertArrayEquals(
+ new String[] {
+ String.format("%s\t%s (fetch)", remote.getName(),
+ remote.getURIs().get(0)),
+ String.format("%s\t%s (push)", remote.getName(),
+ remote.getURIs().get(0)),
+ "" },
+ execute("git remote -v"));
+ }
+
+ @Test
+ public void testAdd() throws Exception {
+ assertArrayEquals(new String[] { "" },
+ execute("git remote add second git://test.com/second"));
+
+ List<RemoteConfig> remotes = RemoteConfig.getAllRemoteConfigs(config);
+ assertEquals(2, remotes.size());
+ assertEquals("second", remotes.get(0).getName());
+ assertEquals("test", remotes.get(1).getName());
+ }
+
+ @Test
+ public void testRemove() throws Exception {
+ assertArrayEquals(new String[] { "" },
+ execute("git remote remove test"));
+
+ assertTrue(RemoteConfig.getAllRemoteConfigs(config).isEmpty());
+ }
+
+ @Test
+ public void testSetUrl() throws Exception {
+ assertArrayEquals(new String[] { "" },
+ execute("git remote set-url test git://test.com/test"));
+
+ RemoteConfig result = new RemoteConfig(config, "test");
+ assertEquals("test", result.getName());
+ assertArrayEquals(new URIish[] { new URIish("git://test.com/test") },
+ result.getURIs().toArray());
+ assertTrue(result.getPushURIs().isEmpty());
+ }
+
+ @Test
+ public void testSetUrlPush() throws Exception {
+ assertArrayEquals(new String[] { "" },
+ execute("git remote set-url --push test git://test.com/test"));
+
+ RemoteConfig result = new RemoteConfig(config, "test");
+ assertEquals("test", result.getName());
+ assertEquals(remote.getURIs(), result.getURIs());
+ assertArrayEquals(new URIish[] { new URIish("git://test.com/test") },
+ result.getPushURIs().toArray());
+ }
+
+ @Test
+ public void testUpdate() throws Exception {
+ assertArrayEquals(new String[] {
+ "From " + remote.getURIs().get(0).toString(),
+ " * [new branch] master -> test/master", "", "" },
+ execute("git remote update test"));
+ }
+
+}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RepoTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RepoTest.java
index 90efae2..ba62383 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RepoTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/RepoTest.java
@@ -44,8 +44,11 @@
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;
@@ -71,33 +74,62 @@
super.setUp();
defaultDb = createWorkRepository();
- Git git = new Git(defaultDb);
- JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "world");
- git.add().addFilepattern("hello.txt").call();
- git.commit().setMessage("Initial commit").call();
+ try (Git git = new Git(defaultDb)) {
+ JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "world");
+ git.add().addFilepattern("hello.txt").call();
+ git.commit().setMessage("Initial commit").call();
+ }
notDefaultDb = createWorkRepository();
- git = new Git(notDefaultDb);
- JGitTestUtil.writeTrashFile(notDefaultDb, "world.txt", "hello");
- git.add().addFilepattern("world.txt").call();
- git.commit().setMessage("Initial commit").call();
+ try (Git git = new Git(notDefaultDb)) {
+ JGitTestUtil.writeTrashFile(notDefaultDb, "world.txt", "hello");
+ git.add().addFilepattern("world.txt").call();
+ git.commit().setMessage("Initial commit").call();
+ }
groupADb = createWorkRepository();
- git = new Git(groupADb);
- JGitTestUtil.writeTrashFile(groupADb, "a.txt", "world");
- git.add().addFilepattern("a.txt").call();
- git.commit().setMessage("Initial commit").call();
+ try (Git git = new Git(groupADb)) {
+ JGitTestUtil.writeTrashFile(groupADb, "a.txt", "world");
+ git.add().addFilepattern("a.txt").call();
+ git.commit().setMessage("Initial commit").call();
+ }
groupBDb = createWorkRepository();
- git = new Git(groupBDb);
- JGitTestUtil.writeTrashFile(groupBDb, "b.txt", "world");
- git.add().addFilepattern("b.txt").call();
- git.commit().setMessage("Initial commit").call();
+ try (Git git = new Git(groupBDb)) {
+ JGitTestUtil.writeTrashFile(groupBDb, "b.txt", "world");
+ git.add().addFilepattern("b.txt").call();
+ git.commit().setMessage("Initial commit").call();
+ }
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();
xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java
new file mode 100644
index 0000000..16c5889
--- /dev/null
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.pgm;
+
+import static org.junit.Assert.*;
+
+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 {
+
+ private Git git;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ 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();
+ assertStringArrayEquals("",
+ execute("git reset --hard " + commit.getId().name()));
+ assertEquals(commit.getId(),
+ git.getRepository().exactRef("HEAD").getObjectId());
+ }
+
+ @Test
+ public void testResetPrevious() throws Exception {
+ RevCommit commit = git.commit().setMessage("initial commit").call();
+ git.commit().setMessage("second commit").call();
+ assertStringArrayEquals("",
+ execute("git reset --hard " + commit.getId().name()));
+ assertEquals(commit.getId(),
+ git.getRepository().exactRef("HEAD").getObjectId());
+ }
+
+ @Test
+ public void testResetEmptyPath() throws Exception {
+ RevCommit commit = git.commit().setMessage("initial commit").call();
+ assertStringArrayEquals("",
+ execute("git reset --hard " + commit.getId().name() + " --"));
+ assertEquals(commit.getId(),
+ git.getRepository().exactRef("HEAD").getObjectId());
+ }
+
+ @Test
+ public void testResetPathDoubleDash() throws Exception {
+ resetPath(true, true);
+ }
+
+ @Test
+ public void testResetPathNoDoubleDash() throws Exception {
+ 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, boolean supplyCommit)
+ throws Exception {
+ // create files a and b
+ writeTrashFile("a", "Hello world a");
+ writeTrashFile("b", "Hello world b");
+ // stage the files
+ git.add().addFilepattern(".").call();
+ // commit the files
+ RevCommit commit = git.commit().setMessage("files a & b").call();
+
+ // change both files a and b
+ writeTrashFile("a", "New Hello world a");
+ writeTrashFile("b", "New Hello world b");
+ // stage the files
+ git.add().addFilepattern(".").call();
+
+ // reset only file a
+ 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());
+
+ org.eclipse.jgit.api.Status status = git.status().call();
+ // assert that file a is unstaged
+ assertArrayEquals(new String[] { "a" },
+ status.getModified().toArray());
+ // assert that file b is still staged
+ assertArrayEquals(new String[] { "b" },
+ status.getChanged().toArray());
+ }
+
+}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java
index 793fc7d..368047c 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java
@@ -42,19 +42,28 @@
*/
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;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
-import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.revwalk.RevCommit;
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);
}
@@ -254,7 +263,7 @@
}
private void detachHead(Git git) throws IOException, GitAPIException {
- String commitId = db.getRef(Constants.MASTER).getObjectId().name();
+ String commitId = db.exactRef(R_HEADS + MASTER).getObjectId().name();
git.checkout().setName(commitId).call();
}
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
index ab09db5..0fe25f5 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
@@ -68,6 +68,6 @@
git.commit().setMessage("commit").call();
assertEquals("fatal: tag 'test' already exists",
- execute("git tag test")[0]);
+ executeUnchecked("git tag test")[0]);
}
}
diff --git a/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
index 4e28e0b..45d6d2c 100644
--- a/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
@@ -1,9 +1,9 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
-org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
-org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
-org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jgit.annotations.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jgit.annotations.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jgit.annotations.Nullable
org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
diff --git a/org.eclipse.jgit.pgm/BUCK b/org.eclipse.jgit.pgm/BUCK
new file mode 100644
index 0000000..edcf2fc
--- /dev/null
+++ b/org.eclipse.jgit.pgm/BUCK
@@ -0,0 +1,70 @@
+include_defs('//tools/git.defs')
+
+java_library(
+ name = 'pgm',
+ srcs = glob(['src/**']),
+ resources = glob(['resources/**']),
+ deps = [
+ ':services',
+ '//org.eclipse.jgit:jgit',
+ '//org.eclipse.jgit.archive:jgit-archive',
+ '//org.eclipse.jgit.http.apache:http-apache',
+ '//org.eclipse.jgit.ui:ui',
+ '//lib:args4j',
+ ],
+ visibility = ['PUBLIC'],
+)
+
+prebuilt_jar(
+ name = 'services',
+ binary_jar = ':services__jar',
+)
+
+genrule(
+ name = 'services__jar',
+ cmd = 'cd $SRCDIR ; zip -qr $OUT .',
+ srcs = glob(['META-INF/services/*']),
+ out = 'services.jar',
+)
+
+genrule(
+ name = 'jgit',
+ cmd = ''.join([
+ 'mkdir $TMP/META-INF &&',
+ 'cp $(location :binary_manifest) $TMP/META-INF/MANIFEST.MF &&',
+ 'cp $(location :jgit_jar) $TMP/jgit.jar &&',
+ 'cd $TMP && zip $TMP/jgit.jar META-INF/MANIFEST.MF &&',
+ 'cat $SRCDIR/jgit.sh $TMP/jgit.jar >$OUT &&',
+ 'chmod a+x $OUT',
+ ]),
+ srcs = ['jgit.sh'],
+ out = 'jgit',
+ visibility = ['PUBLIC'],
+)
+
+java_binary(
+ name = 'jgit_jar',
+ deps = [
+ ':pgm',
+ '//lib:slf4j-simple',
+ '//lib:tukaani-xz',
+ ],
+ blacklist = [
+ 'META-INF/DEPENDENCIES',
+ 'META-INF/maven/.*',
+ ],
+)
+
+genrule(
+ name = 'binary_manifest',
+ cmd = ';'.join(['echo "%s: %s" >>$OUT' % e for e in [
+ ('Manifest-Version', '1.0'),
+ ('Main-Class', 'org.eclipse.jgit.pgm.Main'),
+ ('Bundle-Version', git_version()),
+ ('Implementation-Title', 'JGit Command Line Interface'),
+ ('Implementation-Vendor', 'Eclipse.org - JGit'),
+ ('Implementation-Vendor-URL', 'http://www.eclipse.org/jgit/'),
+ ('Implementation-Vendor-Id', 'org.eclipse.jgit'),
+ ]] + ['echo >>$OUT']),
+ out = 'MANIFEST.MF',
+)
diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index 7d00a96..5c6a16b 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.pgm
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin
@@ -10,38 +10,40 @@
Import-Package: org.apache.commons.compress.archivers;version="[1.3,2.0)",
org.apache.commons.compress.archivers.tar;version="[1.3,2.0)",
org.apache.commons.compress.archivers.zip;version="[1.3,2.0)",
- org.eclipse.jgit.api;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.api.errors;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.archive;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.awtui;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.blame;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.diff;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.dircache;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.gitrepo;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.merge;version="4.1.2",
- org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.notes;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revplot;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.storage.pack;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.treewalk;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util.io;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.api;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.api.errors;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.archive;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.awtui;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.blame;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.diff;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.dircache;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.errors;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.gitrepo;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.merge;version="4.2.1",
+ org.eclipse.jgit.nls;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.notes;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revplot;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revwalk.filter;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.storage.file;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.storage.pack;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.treewalk;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util.io;version="[4.2.1,4.3.0)",
org.kohsuke.args4j;version="[2.0.12,2.1.0)",
org.kohsuke.args4j.spi;version="[2.0.15,2.1.0)"
-Export-Package: org.eclipse.jgit.console;version="4.1.2";
+Export-Package: org.eclipse.jgit.console;version="4.2.1";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="4.1.2";
+ org.eclipse.jgit.pgm;version="4.2.1";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.pgm.opt,
@@ -52,15 +54,14 @@
org.eclipse.jgit.treewalk,
javax.swing,
org.eclipse.jgit.transport",
- org.eclipse.jgit.pgm.debug;version="4.1.2";
+ org.eclipse.jgit.pgm.debug;version="4.2.1";
uses:="org.eclipse.jgit.util.io,
org.eclipse.jgit.pgm",
- org.eclipse.jgit.pgm.internal;version="4.1.2";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
- org.eclipse.jgit.pgm.opt;version="4.1.2";
+ org.eclipse.jgit.pgm.internal;version="4.2.1";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
+ org.eclipse.jgit.pgm.opt;version="4.2.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.kohsuke.args4j.spi,
org.kohsuke.args4j"
Main-Class: org.eclipse.jgit.pgm.Main
Implementation-Title: JGit Command Line Interface
-Require-Bundle: org.eclipse.jdt.annotation;bundle-version="[1.1.0,2.0.0)";resolution:=optional
diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
index 215f8e7..5df8f53 100644
--- a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit.pgm - Sources
Bundle-SymbolicName: org.eclipse.jgit.pgm.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.1.2.201602141800-r
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.1.2.201602141800-r";roots="."
+Bundle-Version: 4.2.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.2.1.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
index e1b0549..6aa2004 100644
--- a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
+++ b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
@@ -24,6 +24,7 @@
org.eclipse.jgit.pgm.Push
org.eclipse.jgit.pgm.ReceivePack
org.eclipse.jgit.pgm.Reflog
+org.eclipse.jgit.pgm.Remote
org.eclipse.jgit.pgm.Repo
org.eclipse.jgit.pgm.Reset
org.eclipse.jgit.pgm.RevList
@@ -40,6 +41,7 @@
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
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index f84e746..b9ad706 100644
--- a/org.eclipse.jgit.pgm/pom.xml
+++ b/org.eclipse.jgit.pgm/pom.xml
@@ -50,7 +50,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.pgm</artifactId>
@@ -95,6 +95,17 @@
</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>
<version>${slf4j-version}</version>
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index f7591fd..b4b1261 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -20,6 +20,7 @@
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_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_n=n
metaVar_name=name
metaVar_object=object
+metaVar_oldNewBranchNames=[oldbranch] newbranch
metaVar_op=OP
metaVar_pass=PASS
metaVar_path=path
@@ -125,9 +129,11 @@
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
+needSingleRevision=Needed a single revision
noGitRepositoryConfigured=No Git repository configured.
noNamesFound=No names found, cannot describe anything.
noSuchFile=no such file: {0}
@@ -142,6 +148,7 @@
notARevision=Not a revision: {0}
notATree={0} is not a tree
notAValidRefName={0} is not a valid ref name
+notAValidCommitName={0} is not a valid commit name
notAnIndexFile={0} is not an index file
notAnObject={0} is not an object
notFound=!! NOT FOUND !!
@@ -186,12 +193,14 @@
tooManyRefsGiven=Too many refs given
unknownIoErrorStdout=An unknown I/O error occurred on standard output
unknownMergeStrategy=unknown merge strategy {0} specified
+unknownSubcommand=Unknown subcommand: {0}
unmergedPaths=Unmerged paths:
unsupportedOperation=Unsupported operation: {0}
untrackedFiles=Untracked files:
updating=Updating {0}..{1}
usage_Aggressive=This option will cause gc to more aggressively optimize the repository at the expense of taking much more time
usage_bareClone=Make a bare Git repository. That is, instead of creating [DIRECTORY] and placing the administrative files in [DIRECTORY]/.git, make the [DIRECTORY] itself the $GIT_DIR.
+usage_branches=Set branch field in .gitmodules
usage_Blame=Show what revision and author last modified each line
usage_CommandLineClientForamazonsS3Service=Command line client for Amazon's S3 service
usage_CommitAll=commit all modified and deleted files
@@ -219,6 +228,8 @@
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
usage_RevList=List commit objects in reverse chronological order
@@ -326,11 +337,13 @@
usage_portNumberToListenOn=port number to listen on
usage_printOnlyBranchesThatContainTheCommit=print only branches that contain the commit
usage_pruneStaleTrackingRefs=prune stale tracking refs
+usage_pushUrls=push URLs are manipulated
usage_quiet=don't show progress messages
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
@@ -347,6 +360,7 @@
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
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
index fde0a78..2cee2cb 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
@@ -129,20 +129,20 @@
final TrackingRefUpdate u) {
final RefUpdate.Result r = u.getResult();
if (r == RefUpdate.Result.LOCK_FAILURE)
- return "[lock fail]";
+ return "[lock fail]"; //$NON-NLS-1$
if (r == RefUpdate.Result.IO_FAILURE)
- return "[i/o error]";
+ return "[i/o error]"; //$NON-NLS-1$
if (r == RefUpdate.Result.REJECTED)
- return "[rejected]";
+ return "[rejected]"; //$NON-NLS-1$
if (ObjectId.zeroId().equals(u.getNewObjectId()))
- return "[deleted]";
+ return "[deleted]"; //$NON-NLS-1$
if (r == RefUpdate.Result.NEW) {
if (u.getRemoteName().startsWith(Constants.R_HEADS))
- return "[new branch]";
+ return "[new branch]"; //$NON-NLS-1$
else if (u.getLocalName().startsWith(Constants.R_TAGS))
- return "[new tag]";
- return "[new]";
+ return "[new tag]"; //$NON-NLS-1$
+ return "[new]"; //$NON-NLS-1$
}
if (r == RefUpdate.Result.FORCED) {
@@ -158,7 +158,7 @@
}
if (r == RefUpdate.Result.NO_CHANGE)
- return "[up to date]";
+ return "[up to date]"; //$NON-NLS-1$
return "[" + r.name() + "]"; //$NON-NLS-1$//$NON-NLS-2$
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
index 83a1ca7..bf6ee3a 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
@@ -45,7 +45,6 @@
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.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 @@
@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 @@
@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,37 +196,47 @@
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)
+ if (startRef != null) {
startBranch = startRef.getName();
- else
+ } else if (startAt != null) {
startBranch = startAt.name();
+ } else {
+ throw die(MessageFormat.format(
+ CLIText.get().notAValidCommitName, startBranch));
+ }
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();
}
}
@@ -245,27 +306,28 @@
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) {
- if (current.equals(branch)) {
- throw die(MessageFormat.format(CLIText.get().cannotDeleteTheBranchWhichYouAreCurrentlyOn, branch));
+ for (String b : branches) {
+ if (b.equals(current)) {
+ throw die(MessageFormat.format(CLIText.get().cannotDeleteTheBranchWhichYouAreCurrentlyOn, b));
}
RefUpdate update = db.updateRef((remote ? Constants.R_REMOTES
: Constants.R_HEADS)
- + branch);
+ + b);
update.setNewObjectId(head);
update.setForceUpdate(force || remote);
Result result = update.delete();
if (result == Result.REJECTED) {
- throw die(MessageFormat.format(CLIText.get().branchIsNotAnAncestorOfYourCurrentHEAD, branch));
+ throw die(MessageFormat.format(CLIText.get().branchIsNotAnAncestorOfYourCurrentHEAD, b));
} else if (result == Result.NEW)
- throw die(MessageFormat.format(CLIText.get().branchNotFound, branch));
+ throw die(MessageFormat.format(CLIText.get().branchNotFound, b));
if (remote)
- outw.println(MessageFormat.format(CLIText.get().deletedRemoteBranch, branch));
+ outw.println(MessageFormat.format(CLIText.get().deletedRemoteBranch, b));
else if (verbose)
- outw.println(MessageFormat.format(CLIText.get().deletedBranch, branch));
+ outw.println(MessageFormat.format(CLIText.get().deletedBranch, b));
}
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
index 4579462..94517db 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Checkout.java
@@ -60,7 +60,7 @@
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 @@
@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
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
index cd6953c..0407828 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java
@@ -50,6 +50,7 @@
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 @@
@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 @@
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 @@
if (db != null)
db.close();
}
-
- outw.println();
- outw.flush();
+ if (msgs) {
+ outw.println();
+ outw.flush();
+ }
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
index f18242d..38d8d70 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
@@ -96,6 +96,9 @@
commitCmd.setAmend(amend);
commitCmd.setAll(all);
Ref head = db.getRef(Constants.HEAD);
+ if (head == null) {
+ throw die(CLIText.get().onBranchToBeBorn);
+ }
RevCommit commit;
try {
commit = commitCmd.call();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
index 8569e92..faae13a 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
@@ -74,7 +74,7 @@
list();
else
throw new NotSupportedException(
- "only --list option is currently supported");
+ "only --list option is currently supported"); //$NON-NLS-1$
}
private void list() throws IOException, ConfigInvalidException {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java
index f07df1a..a25f1e9 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Die.java
@@ -86,6 +86,21 @@
* @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;
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
index d43424c..6947cdd 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
@@ -324,7 +324,7 @@
return false;
if (emptyLine)
outw.println();
- outw.print("Notes");
+ outw.print("Notes"); //$NON-NLS-1$
if (label != null) {
outw.print(" ("); //$NON-NLS-1$
outw.print(label);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
index ceb0d6b..d701f22 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
@@ -62,6 +62,8 @@
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 @@
@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 @@
*
* @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 @@
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 @@
// 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 @@
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 @@
}
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 @@
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 @@
}
}
}
+
+ /**
+ * 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;
+ }
+ }
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
index e0ff058..e739b58 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
@@ -120,7 +120,7 @@
throw die(MessageFormat.format(
CLIText.get().refDoesNotExistOrNoCommit, ref));
- Ref oldHead = db.getRef(Constants.HEAD);
+ Ref oldHead = getOldHead();
MergeResult result;
try (Git git = new Git(db)) {
MergeCommand mergeCmd = git.merge().setStrategy(mergeStrategy)
@@ -148,9 +148,12 @@
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:
@@ -205,6 +208,14 @@
}
}
+ private Ref getOldHead() throws IOException {
+ Ref oldHead = db.getRef(Constants.HEAD);
+ if (oldHead == null) {
+ throw die(CLIText.get().onBranchToBeBorn);
+ }
+ return oldHead;
+ }
+
private boolean isMergedInto(Ref oldHead, AnyObjectId src)
throws IOException {
try (RevWalk revWalk = new RevWalk(db)) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
index 1879ef5..33ea1de 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
@@ -82,6 +82,9 @@
@Option(name = "--all")
private boolean all;
+ @Option(name = "--atomic")
+ private boolean atomic;
+
@Option(name = "--tags")
private boolean tags;
@@ -122,6 +125,7 @@
push.setPushTags();
push.setRemote(remote);
push.setThin(thin);
+ push.setAtomic(atomic);
push.setTimeout(timeout);
Iterable<PushResult> results = push.call();
for (PushResult result : results) {
@@ -178,15 +182,15 @@
switch (rru.getStatus()) {
case OK:
if (rru.isDelete())
- printUpdateLine('-', "[deleted]", null, remoteName, null);
+ printUpdateLine('-', "[deleted]", null, remoteName, null); //$NON-NLS-1$
else {
final Ref oldRef = result.getAdvertisedRef(remoteName);
if (oldRef == null) {
final String summary;
if (remoteName.startsWith(Constants.R_TAGS))
- summary = "[new tag]";
+ summary = "[new tag]"; //$NON-NLS-1$
else
- summary = "[new branch]";
+ summary = "[new branch]"; //$NON-NLS-1$
printUpdateLine('*', summary, srcRef, remoteName, null);
} else {
boolean fastForward = rru.isFastForward();
@@ -202,16 +206,16 @@
break;
case NON_EXISTING:
- printUpdateLine('X', "[no match]", null, remoteName, null);
+ printUpdateLine('X', "[no match]", null, remoteName, null); //$NON-NLS-1$
break;
case REJECTED_NODELETE:
- printUpdateLine('!', "[rejected]", null, remoteName,
+ printUpdateLine('!', "[rejected]", null, remoteName, //$NON-NLS-1$
CLIText.get().remoteSideDoesNotSupportDeletingRefs);
break;
case REJECTED_NONFASTFORWARD:
- printUpdateLine('!', "[rejected]", srcRef, remoteName,
+ printUpdateLine('!', "[rejected]", srcRef, remoteName, //$NON-NLS-1$
CLIText.get().nonFastForward);
break;
@@ -219,22 +223,22 @@
final String message = MessageFormat.format(
CLIText.get().remoteRefObjectChangedIsNotExpectedOne,
safeAbbreviate(reader, rru.getExpectedOldObjectId()));
- printUpdateLine('!', "[rejected]", srcRef, remoteName, message);
+ printUpdateLine('!', "[rejected]", srcRef, remoteName, message); //$NON-NLS-1$
break;
case REJECTED_OTHER_REASON:
- printUpdateLine('!', "[remote rejected]", srcRef, remoteName, rru
+ printUpdateLine('!', "[remote rejected]", srcRef, remoteName, rru //$NON-NLS-1$
.getMessage());
break;
case UP_TO_DATE:
if (verbose)
- printUpdateLine('=', "[up to date]", srcRef, remoteName, null);
+ printUpdateLine('=', "[up to date]", srcRef, remoteName, null); //$NON-NLS-1$
break;
case NOT_ATTEMPTED:
case AWAITING_REPORT:
- printUpdateLine('?', "[unexpected push-process behavior]", srcRef,
+ printUpdateLine('?', "[unexpected push-process behavior]", srcRef, //$NON-NLS-1$
remoteName, rru.getMessage());
break;
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java
new file mode 100644
index 0000000..24916bd
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Remote.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.pgm;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.RemoteAddCommand;
+import org.eclipse.jgit.api.RemoteListCommand;
+import org.eclipse.jgit.api.RemoteRemoveCommand;
+import org.eclipse.jgit.api.RemoteSetUrlCommand;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.pgm.opt.CmdLineParser;
+import org.eclipse.jgit.transport.RemoteConfig;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.util.io.ThrowingPrintWriter;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+@Command(common = false, usage = "usage_Remote")
+class Remote extends TextBuiltin {
+
+ @Option(name = "--verbose", aliases = { "-v" }, usage = "usage_beVerbose")
+ private boolean verbose = false;
+
+ @Option(name = "--prune", aliases = {
+ "-p" }, usage = "usage_pruneStaleTrackingRefs")
+ private boolean prune;
+
+ @Option(name = "--push", usage = "usage_pushUrls")
+ private boolean push;
+
+ @Argument(index = 0, metaVar = "metaVar_command")
+ private String command;
+
+ @Argument(index = 1, metaVar = "metaVar_remoteName")
+ private String name;
+
+ @Argument(index = 2, metaVar = "metaVar_uriish")
+ private String uri;
+
+ @Override
+ protected void run() throws Exception {
+ try (Git git = new Git(db)) {
+ if (command == null) {
+ RemoteListCommand cmd = git.remoteList();
+ List<RemoteConfig> remotes = cmd.call();
+ print(remotes);
+ } else if ("add".equals(command)) { //$NON-NLS-1$
+ RemoteAddCommand cmd = git.remoteAdd();
+ cmd.setName(name);
+ cmd.setUri(new URIish(uri));
+ cmd.call();
+ } else if ("remove".equals(command) || "rm".equals(command)) { //$NON-NLS-1$ //$NON-NLS-2$
+ RemoteRemoveCommand cmd = git.remoteRemove();
+ cmd.setName(name);
+ cmd.call();
+ } else if ("set-url".equals(command)) { //$NON-NLS-1$
+ RemoteSetUrlCommand cmd = git.remoteSetUrl();
+ cmd.setName(name);
+ cmd.setUri(new URIish(uri));
+ cmd.setPush(push);
+ cmd.call();
+ } else if ("update".equals(command)) { //$NON-NLS-1$
+ // reuse fetch command for basic implementation of remote update
+ Fetch fetch = new Fetch();
+ fetch.init(db, gitdir);
+
+ // redirect the output stream
+ StringWriter osw = new StringWriter();
+ fetch.outw = new ThrowingPrintWriter(osw);
+ // redirect the error stream
+ StringWriter esw = new StringWriter();
+ fetch.errw = new ThrowingPrintWriter(esw);
+
+ List<String> fetchArgs = new ArrayList<>();
+ if (verbose) {
+ fetchArgs.add("--verbose"); //$NON-NLS-1$
+ }
+ if (prune) {
+ fetchArgs.add("--prune"); //$NON-NLS-1$
+ }
+ if (name != null) {
+ fetchArgs.add(name);
+ }
+
+ fetch.execute(fetchArgs.toArray(new String[fetchArgs.size()]));
+
+ // flush the streams
+ fetch.outw.flush();
+ fetch.errw.flush();
+ outw.println(osw.toString());
+ errw.println(esw.toString());
+ } else {
+ throw new JGitInternalException(MessageFormat
+ .format(CLIText.get().unknownSubcommand, command));
+ }
+ }
+ }
+
+ @Override
+ public void printUsage(final String message, final CmdLineParser clp)
+ throws IOException {
+ errw.println(message);
+ errw.println("jgit remote [--verbose (-v)] [--help (-h)]"); //$NON-NLS-1$
+ errw.println("jgit remote add name uri-ish [--help (-h)]"); //$NON-NLS-1$
+ errw.println("jgit remote remove name [--help (-h)]"); //$NON-NLS-1$
+ errw.println("jgit remote rm name [--help (-h)]"); //$NON-NLS-1$
+ errw.println(
+ "jgit remote [--verbose (-v)] update [name] [--prune (-p)] [--help (-h)]"); //$NON-NLS-1$
+ errw.println("jgit remote set-url name uri-ish [--push] [--help (-h)]"); //$NON-NLS-1$
+
+ errw.println();
+ clp.printUsage(errw, getResourceBundle());
+ errw.println();
+
+ errw.flush();
+ }
+
+ private void print(List<RemoteConfig> remotes) throws IOException {
+ for (RemoteConfig remote : remotes) {
+ String remoteName = remote.getName();
+ if (verbose) {
+ List<URIish> fetchURIs = remote.getURIs();
+ List<URIish> pushURIs = remote.getPushURIs();
+
+ String fetchURI = ""; //$NON-NLS-1$
+ if (!fetchURIs.isEmpty()) {
+ fetchURI = fetchURIs.get(0).toString();
+ } else if (!pushURIs.isEmpty()) {
+ fetchURI = pushURIs.get(0).toString();
+ }
+
+ String pushURI = ""; //$NON-NLS-1$
+ if (!pushURIs.isEmpty()) {
+ pushURI = pushURIs.get(0).toString();
+ } else if (!fetchURIs.isEmpty()) {
+ pushURI = fetchURIs.get(0).toString();
+ }
+
+ outw.println(
+ String.format("%s\t%s (fetch)", remoteName, fetchURI)); //$NON-NLS-1$
+ outw.println(
+ String.format("%s\t%s (push)", remoteName, pushURI)); //$NON-NLS-1$
+ } else {
+ outw.println(remoteName);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
index 9b191e6..ea59527 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
@@ -55,15 +55,19 @@
@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")
+ private boolean branches;
+
@Override
protected void run() throws Exception {
new RepoCommand(db)
.setURI(uri)
.setPath(path)
.setGroups(groups)
+ .setRecordRemoteBranch(branches)
.call();
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
index 6d1b1c5..9cee37b 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java
@@ -43,11 +43,15 @@
package org.eclipse.jgit.pgm;
+import java.util.ArrayList;
+import java.util.List;
+
import org.eclipse.jgit.api.Git;
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.RestOfArgumentsHandler;
@Command(common = true, usage = "usage_reset")
class Reset extends TextBuiltin {
@@ -61,31 +65,40 @@
@Option(name = "--hard", usage = "usage_resetHard")
private boolean hard = false;
- @Argument(required = true, metaVar = "metaVar_name", usage = "usage_reset")
+ @Argument(required = false, index = 0, metaVar = "metaVar_commitish", usage = "usage_resetReference")
private String commit;
+ @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 {
try (Git git = new Git(db)) {
ResetCommand command = git.reset();
command.setRef(commit);
- ResetType mode = null;
- if (soft)
- mode = selectMode(mode, ResetType.SOFT);
- if (mixed)
- mode = selectMode(mode, ResetType.MIXED);
- if (hard)
- mode = selectMode(mode, ResetType.HARD);
- if (mode == null)
- throw die("no reset mode set");
- command.setMode(mode);
+ if (paths.size() > 0) {
+ for (String path : paths)
+ command.addPath(path);
+ } else {
+ ResetType mode = null;
+ if (soft)
+ mode = selectMode(mode, ResetType.SOFT);
+ if (mixed)
+ mode = selectMode(mode, ResetType.MIXED);
+ if (hard)
+ mode = selectMode(mode, ResetType.HARD);
+ if (mode == null)
+ throw die("no reset mode set"); //$NON-NLS-1$
+ command.setMode(mode);
+ }
command.call();
}
}
private static ResetType selectMode(ResetType mode, ResetType want) {
if (mode != null)
- throw die("reset modes are mutually exclusive, select one");
+ throw die("reset modes are mutually exclusive, select one"); //$NON-NLS-1$
return want;
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
index 5530ac5..c5ecb84 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevParse.java
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2009, Daniel Cheng (aka SDiZ) <git@sdiz.net>
* Copyright (C) 2009, Daniel Cheng (aka SDiZ) <j16sdiz+freenet@gmail.com>
+ * Copyright (C) 2015 Thomas Meyer <thomas@m3y3r.de>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -51,14 +52,20 @@
import java.util.Map;
import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.Option;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.pgm.opt.CmdLineParser;
@Command(usage = "usage_RevParse")
class RevParse extends TextBuiltin {
@Option(name = "--all", usage = "usage_RevParseAll")
- boolean all = false;
+ boolean all;
+
+ @Option(name = "--verify", usage = "usage_RevParseVerify")
+ boolean verify;
@Argument(index = 0, metaVar = "metaVar_commitish")
private final List<ObjectId> commits = new ArrayList<ObjectId>();
@@ -67,11 +74,24 @@
protected void run() throws Exception {
if (all) {
Map<String, Ref> allRefs = db.getRefDatabase().getRefs(ALL);
- for (final Ref r : allRefs.values())
- outw.println(r.getObjectId().name());
+ for (final Ref r : allRefs.values()) {
+ 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 {
- for (final ObjectId o : commits)
+ if (verify && commits.size() > 1) {
+ final CmdLineParser clp = new CmdLineParser(this);
+ throw new CmdLineException(clp, CLIText.get().needSingleRevision);
+ }
+
+ for (final ObjectId o : commits) {
outw.println(o.name());
+ }
}
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
index be82d07..6a63221 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
@@ -59,8 +59,9 @@
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 @@
@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
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
index 56cfc7e..0dc549c 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
@@ -212,17 +212,20 @@
*/
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 @@
* @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 @@
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 @@
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 @@
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);
+ }
+
+ }
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
index df7ebb7..05d094f 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
@@ -136,7 +136,7 @@
protected void run() throws Exception {
mxBean = ManagementFactory.getThreadMXBean();
if (!mxBean.isCurrentThreadCpuTimeSupported())
- throw die("Current thread CPU time not supported on this JRE");
+ throw die("Current thread CPU time not supported on this JRE"); //$NON-NLS-1$
if (gitDirs.isEmpty()) {
RepositoryBuilder rb = new RepositoryBuilder() //
@@ -155,16 +155,16 @@
else
rb.findGitDir(dir);
- Repository db = rb.build();
+ Repository repo = rb.build();
try {
- run(db);
+ run(repo);
} finally {
- db.close();
+ repo.close();
}
}
}
- private void run(Repository db) throws Exception {
+ private void run(Repository repo) throws Exception {
List<Test> all = init();
long files = 0;
@@ -173,14 +173,14 @@
int maxN = 0;
AbbreviatedObjectId startId;
- try (ObjectReader or = db.newObjectReader();
+ try (ObjectReader or = repo.newObjectReader();
RevWalk rw = new RevWalk(or)) {
final MutableObjectId id = new MutableObjectId();
TreeWalk tw = new TreeWalk(or);
tw.setFilter(TreeFilter.ANY_DIFF);
tw.setRecursive(true);
- ObjectId start = db.resolve(Constants.HEAD);
+ ObjectId start = repo.resolve(Constants.HEAD);
startId = or.abbreviate(start);
rw.markStart(rw.parseCommit(start));
for (;;) {
@@ -235,30 +235,32 @@
Collections.sort(all, new Comparator<Test>() {
public int compare(Test a, Test b) {
- int cmp = Long.signum(a.runningTimeNanos - b.runningTimeNanos);
- if (cmp == 0)
- cmp = a.algorithm.name.compareTo(b.algorithm.name);
- return cmp;
+ int result = Long.signum(a.runningTimeNanos - b.runningTimeNanos);
+ if (result == 0) {
+ result = a.algorithm.name.compareTo(b.algorithm.name);
+ }
+ return result;
}
});
- if (db.getDirectory() != null) {
- String name = db.getDirectory().getName();
- File parent = db.getDirectory().getParentFile();
+ File directory = repo.getDirectory();
+ if (directory != null) {
+ String name = directory.getName();
+ File parent = directory.getParentFile();
if (name.equals(Constants.DOT_GIT) && parent != null)
name = parent.getName();
- outw.println(name + ": start at " + startId.name());
+ outw.println(name + ": start at " + startId.name()); //$NON-NLS-1$
}
- outw.format(" %12d files, %8d commits\n", valueOf(files),
+ outw.format(" %12d files, %8d commits\n", valueOf(files), //$NON-NLS-1$
valueOf(commits));
- outw.format(" N=%10d min lines, %8d max lines\n", valueOf(minN),
+ outw.format(" N=%10d min lines, %8d max lines\n", valueOf(minN), //$NON-NLS-1$
valueOf(maxN));
- outw.format("%-25s %12s ( %12s %12s )\n", //
- "Algorithm", "Time(ns)", "Time(ns) on", "Time(ns) on");
- outw.format("%-25s %12s ( %12s %12s )\n", //
- "", "", "N=" + minN, "N=" + maxN);
+ outw.format("%-25s %12s ( %12s %12s )\n", //$NON-NLS-1$
+ "Algorithm", "Time(ns)", "Time(ns) on", "Time(ns) on"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ outw.format("%-25s %12s ( %12s %12s )\n", //$NON-NLS-1$
+ "", "", "N=" + minN, "N=" + maxN); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
outw.println("-----------------------------------------------------" //$NON-NLS-1$
+ "----------------"); //$NON-NLS-1$
@@ -334,9 +336,9 @@
}
}
} catch (IllegalArgumentException e) {
- throw die("Cannot determine names", e);
+ throw die("Cannot determine names", e); //$NON-NLS-1$
} catch (IllegalAccessException e) {
- throw die("Cannot determine names", e);
+ throw die("Cannot determine names", e); //$NON-NLS-1$
}
return all;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
index 494055a..8cfcba9 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
@@ -117,9 +117,12 @@
@Override
protected void run() throws Exception {
if (!really && !db.getRefDatabase().getRefs(ALL).isEmpty()) {
+ File directory = db.getDirectory();
+ String absolutePath = directory == null ? "null" //$NON-NLS-1$
+ : directory.getAbsolutePath();
errw.println(
MessageFormat.format(CLIText.get().fatalThisProgramWillDestroyTheRepository
- , db.getDirectory().getAbsolutePath(), REALLY));
+ , absolutePath, REALLY));
throw die(CLIText.get().needApprovalToDestroyCurrentRepository);
}
if (!refList.isFile())
@@ -164,7 +167,7 @@
}
}
- pm.beginTask("Rewriting commits", queue.size());
+ pm.beginTask("Rewriting commits", queue.size()); //$NON-NLS-1$
try (ObjectInserter oi = db.newObjectInserter()) {
final ObjectId emptyTree = oi.insert(Constants.OBJ_TREE,
new byte[] {});
@@ -200,7 +203,7 @@
newc.setAuthor(new PersonIdent(me, new Date(t.commitTime)));
newc.setCommitter(newc.getAuthor());
newc.setParentIds(newParents);
- newc.setMessage("ORIGINAL " + t.oldId.name() + "\n"); //$NON-NLS-2$
+ newc.setMessage("ORIGINAL " + t.oldId.name() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
t.newId = oi.insert(newc);
rewrites.put(t.oldId, t.newId);
pm.update(1);
@@ -232,7 +235,7 @@
final ObjectId id = db.resolve(Constants.HEAD);
if (!ObjectId.isId(head) && id != null) {
final LockFile lf;
- lf = new LockFile(new File(db.getDirectory(), Constants.HEAD), db.getFS());
+ lf = new LockFile(new File(db.getDirectory(), Constants.HEAD));
if (!lf.lock())
throw new IOException(MessageFormat.format(CLIText.get().cannotLock, Constants.HEAD));
lf.write(id);
@@ -260,7 +263,7 @@
protected void writeFile(final String name, final byte[] content)
throws IOException {
final File file = new File(db.getDirectory(), name);
- final LockFile lck = new LockFile(file, db.getFS());
+ final LockFile lck = new LockFile(file);
if (!lck.lock())
throw new ObjectWritingException(MessageFormat.format(CLIText.get().cantWrite, file));
try {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java
new file mode 100644
index 0000000..78ca1a7
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildRefTree.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.pgm.debug;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jgit.internal.storage.reftree.RefTree;
+import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.pgm.Command;
+import org.eclipse.jgit.pgm.TextBuiltin;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+@Command(usage = "usage_RebuildRefTree")
+class RebuildRefTree extends TextBuiltin {
+ private String txnNamespace;
+ private String txnCommitted;
+
+ @Override
+ protected void run() throws Exception {
+ try (ObjectReader reader = db.newObjectReader();
+ RevWalk rw = new RevWalk(reader);
+ ObjectInserter inserter = db.newObjectInserter()) {
+ RefDatabase refDb = db.getRefDatabase();
+ if (refDb instanceof RefTreeDatabase) {
+ RefTreeDatabase d = (RefTreeDatabase) refDb;
+ refDb = d.getBootstrap();
+ txnNamespace = d.getTxnNamespace();
+ txnCommitted = d.getTxnCommitted();
+ } else {
+ RefTreeDatabase d = new RefTreeDatabase(db, refDb);
+ txnNamespace = d.getTxnNamespace();
+ txnCommitted = d.getTxnCommitted();
+ }
+
+ errw.format("Rebuilding %s from %s", //$NON-NLS-1$
+ txnCommitted, refDb.getClass().getSimpleName());
+ errw.println();
+ errw.flush();
+
+ CommitBuilder b = new CommitBuilder();
+ Ref ref = refDb.exactRef(txnCommitted);
+ RefUpdate update = refDb.newUpdate(txnCommitted, true);
+ ObjectId oldTreeId;
+
+ if (ref != null && ref.getObjectId() != null) {
+ ObjectId oldId = ref.getObjectId();
+ update.setExpectedOldObjectId(oldId);
+ b.setParentId(oldId);
+ oldTreeId = rw.parseCommit(oldId).getTree();
+ } else {
+ update.setExpectedOldObjectId(ObjectId.zeroId());
+ oldTreeId = ObjectId.zeroId();
+ }
+
+ RefTree tree = rebuild(refDb.getRefs(RefDatabase.ALL));
+ b.setTreeId(tree.writeTree(inserter));
+ b.setAuthor(new PersonIdent(db));
+ b.setCommitter(b.getAuthor());
+ if (b.getTreeId().equals(oldTreeId)) {
+ return;
+ }
+
+ update.setNewObjectId(inserter.insert(b));
+ inserter.flush();
+
+ RefUpdate.Result result = update.update(rw);
+ switch (result) {
+ case NEW:
+ case FAST_FORWARD:
+ break;
+ default:
+ throw die(String.format("%s: %s", update.getName(), result)); //$NON-NLS-1$
+ }
+ }
+ }
+
+ private RefTree rebuild(Map<String, Ref> refMap) {
+ RefTree tree = RefTree.newEmptyTree();
+ List<org.eclipse.jgit.internal.storage.reftree.Command> cmds
+ = new ArrayList<>();
+
+ for (Ref r : refMap.values()) {
+ if (r.getName().equals(txnCommitted)
+ || r.getName().startsWith(txnNamespace)) {
+ continue;
+ }
+ cmds.add(new org.eclipse.jgit.internal.storage.reftree.Command(
+ null,
+ db.peel(r)));
+ }
+ tree.apply(cmds);
+ return tree;
+ }
+}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java
index d3eb245..150fe6e 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowPackDelta.java
@@ -87,9 +87,9 @@
long size = reader.getObjectSize(obj, obj.getType());
try {
if (BinaryDelta.getResultSize(delta) != size)
- throw die("Object " + obj.name() + " is not a delta");
+ throw die("Object " + obj.name() + " is not a delta"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (ArrayIndexOutOfBoundsException bad) {
- throw die("Object " + obj.name() + " is not a delta");
+ throw die("Object " + obj.name() + " is not a delta"); //$NON-NLS-1$ //$NON-NLS-2$
}
outw.println(BinaryDelta.format(delta));
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
index dcbc37b..28d92ae 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
@@ -286,25 +286,25 @@
else
rb.findGitDir(dir);
- Repository db = rb.build();
+ Repository repo = rb.build();
try {
- run(db);
+ run(repo);
} finally {
- db.close();
+ repo.close();
}
}
}
- private void run(Repository db) throws Exception {
+ private void run(Repository repo) throws Exception {
List<Function> all = init();
long fileCnt = 0;
long lineCnt = 0;
- try (ObjectReader or = db.newObjectReader();
+ try (ObjectReader or = repo.newObjectReader();
RevWalk rw = new RevWalk(or);
TreeWalk tw = new TreeWalk(or)) {
final MutableObjectId id = new MutableObjectId();
- tw.reset(rw.parseTree(db.resolve(Constants.HEAD)));
+ tw.reset(rw.parseTree(repo.resolve(Constants.HEAD)));
tw.setRecursive(true);
while (tw.next()) {
@@ -341,17 +341,18 @@
}
}
- if (db.getDirectory() != null) {
- String name = db.getDirectory().getName();
- File parent = db.getDirectory().getParentFile();
+ File directory = repo.getDirectory();
+ if (directory != null) {
+ String name = directory.getName();
+ File parent = directory.getParentFile();
if (name.equals(Constants.DOT_GIT) && parent != null)
name = parent.getName();
outw.println(name + ":"); //$NON-NLS-1$
}
- outw.format(" %6d files; %5d avg. unique lines/file\n", //
+ outw.format(" %6d files; %5d avg. unique lines/file\n", //$NON-NLS-1$
valueOf(fileCnt), //
valueOf(lineCnt / fileCnt));
- outw.format("%-20s %-15s %9s\n", "Hash", "Fold", "Max Len");
+ outw.format("%-20s %-15s %9s\n", "Hash", "Fold", "Max Len"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
outw.println("-----------------------------------------------"); //$NON-NLS-1$
String lastHashName = null;
for (Function fun : all) {
@@ -404,9 +405,9 @@
}
}
} catch (IllegalArgumentException e) {
- throw new RuntimeException("Cannot determine names", e);
+ throw new RuntimeException("Cannot determine names", e); //$NON-NLS-1$
} catch (IllegalAccessException e) {
- throw new RuntimeException("Cannot determine names", e);
+ throw new RuntimeException("Cannot determine names", e); //$NON-NLS-1$
}
List<Function> all = new ArrayList<Function>();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
index 433ddf2..2812137 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java
@@ -74,6 +74,19 @@
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 String branchCreatedFrom;
/***/ public String branchDetachedHEAD;
/***/ public String branchIsNotAnAncestorOfYourCurrentHEAD;
+ /***/ public String branchNameRequired;
/***/ public String branchNotFound;
/***/ public String cacheTreePathInfo;
/***/ public String configFileNotFound;
@@ -184,9 +198,11 @@
/***/ 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;
+ /***/ public String needSingleRevision;
/***/ public String noGitRepositoryConfigured;
/***/ public String noNamesFound;
/***/ public String noSuchFile;
@@ -201,6 +217,7 @@
/***/ public String notARevision;
/***/ public String notATree;
/***/ public String notAValidRefName;
+ /***/ public String notAValidCommitName;
/***/ public String notAnIndexFile;
/***/ public String notAnObject;
/***/ public String notFound;
@@ -245,6 +262,7 @@
/***/ public String treeIsRequired;
/***/ public char[] unknownIoErrorStdout;
/***/ public String unknownMergeStrategy;
+ /***/ public String unknownSubcommand;
/***/ public String unmergedPaths;
/***/ public String unsupportedOperation;
/***/ public String untrackedFiles;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
index 229fb67..6b8a61d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
@@ -109,7 +109,7 @@
try {
dirc = DirCache.read(new File(name), FS.DETECTED);
} catch (IOException e) {
- throw new CmdLineException(MessageFormat.format(CLIText.get().notAnIndexFile, name), e);
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().notAnIndexFile, name), e);
}
setter.addValue(new DirCacheIterator(dirc));
return 1;
@@ -119,20 +119,20 @@
try {
id = clp.getRepository().resolve(name);
} catch (IOException e) {
- throw new CmdLineException(e.getMessage());
+ throw new CmdLineException(clp, e.getMessage());
}
if (id == null)
- throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().notATree, name));
final CanonicalTreeParser p = new CanonicalTreeParser();
try (ObjectReader curs = clp.getRepository().newObjectReader()) {
p.reset(curs, clp.getRevWalk().parseTree(id));
} catch (MissingObjectException e) {
- throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().notATree, name));
} catch (IncorrectObjectTypeException e) {
- throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().notATree, name));
} catch (IOException e) {
- throw new CmdLineException(MessageFormat.format(CLIText.get().cannotReadBecause, name, e.getMessage()));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().cannotReadBecause, name, e.getMessage()));
}
setter.addValue(p);
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java
index 3f77aa6..b531ba6 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java
@@ -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.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 @@
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 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 @@
}
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 @@
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 @@
return metaVar();
}
}
+
+ @Override
+ public boolean required() {
+ return seenHelp ? false : super.required();
+ }
}
@Override
@@ -211,4 +299,55 @@
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;
+ }
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java
index fa24d4b0..364809d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/ObjectIdHandler.java
@@ -86,14 +86,14 @@
try {
id = clp.getRepository().resolve(name);
} catch (IOException e) {
- throw new CmdLineException(e.getMessage());
+ throw new CmdLineException(clp, e.getMessage());
}
if (id != null) {
setter.addValue(id);
return 1;
}
- throw new CmdLineException(MessageFormat.format(CLIText.get().notAnObject, name));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().notAnObject, name));
}
@Override
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java
new file mode 100644
index 0000000..3de7a81
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/OptionWithValuesListHandler.java
@@ -0,0 +1,52 @@
+package org.eclipse.jgit.pgm.opt;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.pgm.internal.CLIText;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.spi.OptionHandler;
+import org.kohsuke.args4j.spi.Parameters;
+import org.kohsuke.args4j.spi.Setter;
+
+/**
+ * Handler which allows to parse option with few values
+ *
+ * @since 4.2
+ */
+public class OptionWithValuesListHandler extends OptionHandler<List<?>> {
+
+ /**
+ * @param parser
+ * @param option
+ * @param setter
+ */
+ public OptionWithValuesListHandler(CmdLineParser parser,
+ OptionDef option, Setter<List<?>> setter) {
+ super(parser, option, setter);
+ }
+
+ @Override
+ public int parseArguments(Parameters params) throws CmdLineException {
+ final List<String> list = new ArrayList<>();
+ for (int idx = 0; idx < params.size(); idx++) {
+ final String p;
+ try {
+ p = params.getParameter(idx);
+ } catch (CmdLineException cle) {
+ break;
+ }
+ list.add(p);
+ }
+ setter.addValue(list);
+ return list.size();
+ }
+
+ @Override
+ public String getDefaultMetaVariable() {
+ return CLIText.get().metaVar_values;
+ }
+
+}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java
index b1be128..9ae56e4 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevCommitHandler.java
@@ -96,8 +96,10 @@
final int dot2 = name.indexOf(".."); //$NON-NLS-1$
if (dot2 != -1) {
if (!option.isMultiValued())
- throw new CmdLineException(MessageFormat.format(CLIText.get().onlyOneMetaVarExpectedIn
- , option.metaVar(), name));
+ throw new CmdLineException(clp,
+ MessageFormat.format(
+ CLIText.get().onlyOneMetaVarExpectedIn,
+ option.metaVar(), name));
final String left = name.substring(0, dot2);
final String right = name.substring(dot2 + 2);
@@ -116,20 +118,20 @@
try {
id = clp.getRepository().resolve(name);
} catch (IOException e) {
- throw new CmdLineException(e.getMessage());
+ throw new CmdLineException(clp, e.getMessage());
}
if (id == null)
- throw new CmdLineException(MessageFormat.format(CLIText.get().notACommit, name));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().notACommit, name));
final RevCommit c;
try {
c = clp.getRevWalk().parseCommit(id);
} catch (MissingObjectException e) {
- throw new CmdLineException(MessageFormat.format(CLIText.get().notACommit, name));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().notACommit, name));
} catch (IncorrectObjectTypeException e) {
- throw new CmdLineException(MessageFormat.format(CLIText.get().notACommit, name));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().notACommit, name));
} catch (IOException e) {
- throw new CmdLineException(MessageFormat.format(CLIText.get().cannotReadBecause, name, e.getMessage()));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().cannotReadBecause, name, e.getMessage()));
}
if (interesting)
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java
index eb155af..e2879e0 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/RevTreeHandler.java
@@ -89,20 +89,20 @@
try {
id = clp.getRepository().resolve(name);
} catch (IOException e) {
- throw new CmdLineException(e.getMessage());
+ throw new CmdLineException(clp, e.getMessage());
}
if (id == null)
- throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().notATree, name));
final RevTree c;
try {
c = clp.getRevWalk().parseTree(id);
} catch (MissingObjectException e) {
- throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().notATree, name));
} catch (IncorrectObjectTypeException e) {
- throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().notATree, name));
} catch (IOException e) {
- throw new CmdLineException(MessageFormat.format(CLIText.get().cannotReadBecause, name, e.getMessage()));
+ throw new CmdLineException(clp, MessageFormat.format(CLIText.get().cannotReadBecause, name, e.getMessage()));
}
setter.addValue(c);
return 1;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java
index c62ef0d..96f3ed0 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/SubcommandHandler.java
@@ -63,6 +63,8 @@
* we can execute at runtime with the remaining arguments of the parser.
*/
public class SubcommandHandler extends OptionHandler<TextBuiltin> {
+ private final org.eclipse.jgit.pgm.opt.CmdLineParser clp;
+
/**
* Create a new handler for the command name.
* <p>
@@ -75,6 +77,7 @@
public SubcommandHandler(final CmdLineParser parser,
final OptionDef option, final Setter<? super TextBuiltin> setter) {
super(parser, option, setter);
+ clp = (org.eclipse.jgit.pgm.opt.CmdLineParser) parser;
}
@Override
@@ -82,7 +85,7 @@
final String name = params.getParameter(0);
final CommandRef cr = CommandCatalog.get(name);
if (cr == null)
- throw new CmdLineException(MessageFormat.format(
+ throw new CmdLineException(clp, MessageFormat.format(
CLIText.get().notAJgitCommand, name));
// Force option parsing to stop. Everything after us should
diff --git a/org.eclipse.jgit.test/BUCK b/org.eclipse.jgit.test/BUCK
new file mode 100644
index 0000000..3df3336
--- /dev/null
+++ b/org.eclipse.jgit.test/BUCK
@@ -0,0 +1,95 @@
+PKG = 'tst/org/eclipse/jgit/'
+HELPERS = glob(['src/**/*.java']) + [PKG + c for c in [
+ 'api/AbstractRemoteCommandTest.java',
+ 'diff/AbstractDiffTestCase.java',
+ 'internal/storage/file/GcTestCase.java',
+ 'internal/storage/file/PackIndexTestCase.java',
+ 'internal/storage/file/XInputStream.java',
+ 'nls/GermanTranslatedBundle.java',
+ 'nls/MissingPropertyBundle.java',
+ 'nls/NoPropertiesBundle.java',
+ 'nls/NonTranslatedBundle.java',
+ 'revwalk/RevQueueTestCase.java',
+ 'revwalk/RevWalkTestCase.java',
+ 'transport/SpiTransport.java',
+ 'treewalk/FileTreeIteratorWithTimeControl.java',
+ 'treewalk/filter/AlwaysCloneTreeFilter.java',
+ 'test/resources/SampleDataRepositoryTestCase.java',
+ 'util/CPUTimeStopWatch.java',
+ 'util/io/Strings.java',
+]]
+
+DATA = [
+ PKG + 'lib/empty.gitindex.dat',
+ PKG + 'lib/sorttest.gitindex.dat',
+]
+
+TESTS = glob(
+ ['tst/**/*.java'],
+ excludes = HELPERS + DATA,
+)
+
+DEPS = {
+ PKG + 'nls/RootLocaleTest.java': [
+ '//org.eclipse.jgit.pgm:pgm',
+ '//org.eclipse.jgit.ui:ui',
+ ],
+}
+
+for src in TESTS:
+ name = src[len('tst/'):len(src)-len('.java')].replace('/', '.')
+ labels = []
+ if name.startswith('org.eclipse.jgit.'):
+ l = name[len('org.eclipse.jgit.'):]
+ if l.startswith('internal.storage.'):
+ l = l[len('internal.storage.'):]
+ i = l.find('.')
+ if i > 0:
+ labels.append(l[:i])
+ else:
+ labels.append(i)
+ if 'lib' not in labels:
+ labels.append('lib')
+
+ java_test(
+ name = name,
+ labels = labels,
+ srcs = [src],
+ deps = [
+ ':helpers',
+ ':tst_rsrc',
+ '//org.eclipse.jgit:jgit',
+ '//org.eclipse.jgit.junit:junit',
+ '//lib:hamcrest-core',
+ '//lib:hamcrest-library',
+ '//lib:javaewah',
+ '//lib:junit',
+ '//lib:slf4j-api',
+ '//lib:slf4j-simple',
+ ] + DEPS.get(src, []),
+ source_under_test = ['//org.eclipse.jgit:jgit'],
+ vm_args = ['-Xmx256m', '-Dfile.encoding=UTF-8'],
+ )
+
+java_library(
+ name = 'helpers',
+ srcs = HELPERS,
+ resources = DATA,
+ deps = [
+ '//org.eclipse.jgit:jgit',
+ '//org.eclipse.jgit.junit:junit',
+ '//lib:junit',
+ ],
+)
+
+prebuilt_jar(
+ name = 'tst_rsrc',
+ binary_jar = ':tst_rsrc_jar',
+)
+
+genrule(
+ name = 'tst_rsrc_jar',
+ cmd = 'cd $SRCDIR/tst-rsrc ; zip -qr $OUT .',
+ srcs = glob(['tst-rsrc/**']),
+ out = 'tst_rsrc.jar',
+)
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index f059fdb..abb86e8 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -2,54 +2,56 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)",
- org.eclipse.jgit.api;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.api.errors;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.attributes;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.awtui;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.blame;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.diff;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.dircache;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.events;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.fnmatch;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.gitrepo;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.hooks;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.ignore;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.ignore.internal;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal.storage.dfs;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal.storage.file;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.internal.storage.pack;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.junit;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.merge;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.notes;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.patch;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.pgm;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.pgm.internal;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revplot;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revwalk.filter;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.storage.file;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.storage.pack;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.submodule;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport.http;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport.resolver;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.treewalk;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.treewalk.filter;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util.io;version="[4.1.2,4.2.0)",
+ org.eclipse.jgit.api;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.api.errors;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.attributes;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.awtui;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.blame;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.diff;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.dircache;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.errors;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.events;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.fnmatch;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.gitrepo;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.hooks;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.ignore;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.ignore.internal;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.internal.storage.reftree;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.junit;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.merge;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.nls;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.notes;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.patch;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.pgm;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.pgm.internal;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revplot;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revwalk.filter;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.storage.file;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.storage.pack;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.submodule;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport.http;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.treewalk;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util.io;version="[4.2.1,4.3.0)",
org.hamcrest;version="[1.1.0,2.0.0)",
org.junit;version="[4.4.0,5.0.0)",
org.junit.experimental.theories;version="[4.4.0,5.0.0)",
org.junit.runner;version="[4.4.0,5.0.0)",
- org.junit.runners;version="[4.11.0,5.0.0)"
+ org.junit.runners;version="[4.11.0,5.0.0)",
+ org.slf4j;version="[1.7.2,2.0.0)"
Require-Bundle: org.hamcrest.core;bundle-version="[1.1.0,2.0.0)"
diff --git a/org.eclipse.jgit.test/build.properties b/org.eclipse.jgit.test/build.properties
index afc4855..786046c 100644
--- a/org.eclipse.jgit.test/build.properties
+++ b/org.eclipse.jgit.test/build.properties
@@ -4,3 +4,4 @@
bin.includes = META-INF/,\
.,\
plugin.properties
+additional.bundles = org.apache.log4j
diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java
new file mode 100644
index 0000000..db5f1b2
--- /dev/null
+++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2015, Sebastien Arod <sebastien.arod@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.ignore;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.file.Files;
+import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import org.eclipse.jgit.api.Git;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * This test generates random ignore patterns and random path and compares the
+ * output of Cgit check-ignore to the output of {@link FastIgnoreRule}.
+ */
+public class CGitVsJGitRandomIgnorePatternTest {
+
+ private static class PseudoRandomPatternGenerator {
+
+ private static final int DEFAULT_MAX_FRAGMENTS_PER_PATTERN = 15;
+
+ /**
+ * Generates 75% Special fragments and 25% "standard" characters
+ */
+ private static final double DEFAULT_SPECIAL_FRAGMENTS_FREQUENCY = 0.75d;
+
+ private static final List<String> SPECIAL_FRAGMENTS = Arrays.asList(
+ "\\", "!", "#", "[", "]", "|", "/", "*", "?", "{", "}", "(",
+ ")", "\\d", "(", "**", "[a\\]]", "\\ ", "+", "-", "^", "$", ".",
+ ":", "=", "[[:", ":]]"
+
+ );
+
+ private static final String STANDARD_CHARACTERS = new String(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
+
+ private final Random random = new Random();
+
+ private final int maxFragmentsPerPattern;
+
+ private final double specialFragmentsFrequency;
+
+ public PseudoRandomPatternGenerator() {
+ this(DEFAULT_MAX_FRAGMENTS_PER_PATTERN,
+ DEFAULT_SPECIAL_FRAGMENTS_FREQUENCY);
+ }
+
+ public PseudoRandomPatternGenerator(int maxFragmentsPerPattern,
+ double specialFragmentsFrequency) {
+ this.maxFragmentsPerPattern = maxFragmentsPerPattern;
+ this.specialFragmentsFrequency = specialFragmentsFrequency;
+ }
+
+ public String nextRandomString() {
+ StringBuilder builder = new StringBuilder();
+ int length = randomFragmentCount();
+ for (int i = 0; i < length; i++) {
+ if (useSpecialFragment()) {
+ builder.append(randomSpecialFragment());
+ } else {
+ builder.append(randomStandardCharacters());
+ }
+
+ }
+ return builder.toString();
+ }
+
+ private int randomFragmentCount() {
+ // We want at least one fragment
+ return 1 + random.nextInt(maxFragmentsPerPattern - 1);
+ }
+
+ private char randomStandardCharacters() {
+ return STANDARD_CHARACTERS
+ .charAt(random.nextInt(STANDARD_CHARACTERS.length()));
+ }
+
+ private boolean useSpecialFragment() {
+ return random.nextDouble() < specialFragmentsFrequency;
+ }
+
+ private String randomSpecialFragment() {
+ return SPECIAL_FRAGMENTS
+ .get(random.nextInt(SPECIAL_FRAGMENTS.size()));
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class CgitFatalException extends Exception {
+
+ public CgitFatalException(int cgitExitCode, String pattern, String path,
+ String cgitStdError) {
+ super("CgitFatalException (" + cgitExitCode + ") for pattern:["
+ + pattern + "] and path:[" + path + "]\n" + cgitStdError);
+ }
+
+ }
+
+ public static class CGitIgnoreRule {
+
+ private File gitDir;
+
+ private String pattern;
+
+ public CGitIgnoreRule(File gitDir, String pattern)
+ throws UnsupportedEncodingException, IOException {
+ this.gitDir = gitDir;
+ this.pattern = pattern;
+ Files.write(new File(gitDir, ".gitignore").toPath(),
+ (pattern + "\n").getBytes("UTF-8"),
+ StandardOpenOption.CREATE,
+ StandardOpenOption.TRUNCATE_EXISTING,
+ StandardOpenOption.WRITE);
+ }
+
+ public boolean isMatch(String path)
+ throws IOException, InterruptedException, CgitFatalException {
+ Process proc = startCgitCheckIgnore(path);
+
+ String cgitStdOutput = readProcessStream(proc.getInputStream());
+ String cgitStdError = readProcessStream(proc.getErrorStream());
+
+ int cgitExitCode = proc.waitFor();
+
+ if (cgitExitCode == 128) {
+ throw new CgitFatalException(cgitExitCode, pattern, path,
+ cgitStdError);
+ }
+ return !cgitStdOutput.startsWith("::");
+ }
+
+ private Process startCgitCheckIgnore(String path) throws IOException {
+ // Use --stdin instead of using argument otherwise paths starting
+ // with "-" were interpreted as
+ // options by git check-ignore
+ String[] command = new String[] { "git", "check-ignore",
+ "--no-index", "-v", "-n", "--stdin" };
+ Process proc = Runtime.getRuntime().exec(command, new String[0],
+ gitDir);
+ OutputStream out = proc.getOutputStream();
+ out.write((path + "\n").getBytes("UTF-8"));
+ out.flush();
+ out.close();
+ return proc;
+ }
+
+ private String readProcessStream(InputStream processStream)
+ throws IOException {
+ try (BufferedReader stdOut = new BufferedReader(
+ new InputStreamReader(processStream))) {
+
+ StringBuilder out = new StringBuilder();
+ String s;
+ while ((s = stdOut.readLine()) != null) {
+ out.append(s);
+ }
+ return out.toString();
+ }
+ }
+ }
+
+ private static final int NB_PATTERN = 1000;
+
+ private static final int PATH_PER_PATTERN = 1000;
+
+ @Test
+ public void testRandomPatterns() throws Exception {
+ // Initialize new git repo
+ File gitDir = Files.createTempDirectory("jgit").toFile();
+ Git.init().setDirectory(gitDir).call();
+ PseudoRandomPatternGenerator generator = new PseudoRandomPatternGenerator();
+
+ // Generate random patterns and paths
+ for (int i = 0; i < NB_PATTERN; i++) {
+ String pattern = generator.nextRandomString();
+
+ FastIgnoreRule jgitIgnoreRule = new FastIgnoreRule(pattern);
+ CGitIgnoreRule cgitIgnoreRule = new CGitIgnoreRule(gitDir, pattern);
+
+ // Test path with pattern as path
+ assertCgitAndJgitMatch(pattern, jgitIgnoreRule, cgitIgnoreRule,
+ pattern);
+
+ for (int p = 0; p < PATH_PER_PATTERN; p++) {
+ String path = generator.nextRandomString();
+ assertCgitAndJgitMatch(pattern, jgitIgnoreRule, cgitIgnoreRule,
+ path);
+ }
+ }
+ }
+
+ @SuppressWarnings({ "boxing" })
+ private void assertCgitAndJgitMatch(String pattern,
+ FastIgnoreRule jgitIgnoreRule, CGitIgnoreRule cgitIgnoreRule,
+ String pathToTest) throws IOException, InterruptedException {
+
+ try {
+ boolean cgitMatch = cgitIgnoreRule.isMatch(pathToTest);
+ boolean jgitMatch = jgitIgnoreRule.isMatch(pathToTest,
+ pathToTest.endsWith("/"));
+ if (cgitMatch != jgitMatch) {
+ System.err.println(
+ buildAssertionToAdd(pattern, pathToTest, cgitMatch));
+ }
+ Assert.assertEquals("jgit:" + jgitMatch + " <> cgit:" + cgitMatch
+ + " for pattern:[" + pattern + "] and path:[" + pathToTest
+ + "]", cgitMatch, jgitMatch);
+ } catch (CgitFatalException e) {
+ // Lots of generated patterns or path are rejected by Cgit with a
+ // fatal error. We want to ignore them.
+ }
+ }
+
+ private String buildAssertionToAdd(String pattern, String pathToTest,
+ boolean cgitMatch) {
+ return "assertMatch(" + toJavaString(pattern) + ", "
+ + toJavaString(pathToTest) + ", " + cgitMatch
+ + " /*cgit result*/);";
+ }
+
+ private String toJavaString(String pattern2) {
+ return "\"" + pattern2.replace("\\", "\\\\").replace("\"", "\\\"")
+ + "\"";
+ }
+}
diff --git "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051.launch" "b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051.launch"
index af009c0..a83fabb 100644
--- "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051.launch"
+++ "b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 7\051.launch"
@@ -18,7 +18,6 @@
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" path="1" type="4"/> "/>
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="org.eclipse.jgit.test"/> </runtimeClasspathEntry> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry path="3" projectName="org.eclipse.jgit.java7" type="1"/> "/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
diff --git "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 8\051 \050de\051.launch" "b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 8\051 \050de\051.launch"
new file mode 100644
index 0000000..f12a529
--- /dev/null
+++ "b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 8\051 \050de\051.launch"
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.eclipse.jgit.test/tst"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="2"/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+<mapAttribute key="org.eclipse.debug.core.environmentVariables">
+<mapEntry key="LANG" value="de_DE.UTF-8"/>
+</mapAttribute>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/tst"/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
+<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
+<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" path="1" type="4"/> "/>
+<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="org.eclipse.jgit.test"/> </runtimeClasspathEntry> "/>
+</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>
diff --git "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 8\051.launch" "b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 8\051.launch"
index 04aa3ea..b221a11 100644
--- "a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 8\051.launch"
+++ "b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests \050Java 8\051.launch"
@@ -19,7 +19,6 @@
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" path="1" type="4"/> "/>
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="org.eclipse.jgit.test"/> </runtimeClasspathEntry> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry path="3" projectName="org.eclipse.jgit.java7" type="1"/> "/>
</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"/>
diff --git a/org.eclipse.jgit.test/org.eclipse.jgit.test-WalkEncryptionTest-Proxy.launch b/org.eclipse.jgit.test/org.eclipse.jgit.test-WalkEncryptionTest-Proxy.launch
new file mode 100644
index 0000000..fe3a013
--- /dev/null
+++ b/org.eclipse.jgit.test/org.eclipse.jgit.test-WalkEncryptionTest-Proxy.launch
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.m2e.Maven2LaunchConfigurationType">
+<booleanAttribute key="M2_DEBUG_OUTPUT" value="false"/>
+<stringAttribute key="M2_GOALS" value="test --define test=WalkEncryptionTest --define http_proxy=http://proxy:3128"/>
+<booleanAttribute key="M2_NON_RECURSIVE" value="false"/>
+<booleanAttribute key="M2_OFFLINE" value="false"/>
+<stringAttribute key="M2_PROFILES" value=""/>
+<listAttribute key="M2_PROPERTIES"/>
+<stringAttribute key="M2_RUNTIME" value="EMBEDDED"/>
+<booleanAttribute key="M2_SKIP_TESTS" value="false"/>
+<intAttribute key="M2_THREADS" value="1"/>
+<booleanAttribute key="M2_UPDATE_SNAPSHOTS" value="false"/>
+<stringAttribute key="M2_USER_SETTINGS" value=""/>
+<booleanAttribute key="M2_WORKSPACE_RESOLUTION" value="false"/>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/java-8-oracle"/>
+<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc:/org.eclipse.jgit.test}"/>
+</launchConfiguration>
diff --git a/org.eclipse.jgit.test/org.eclipse.jgit.test-WalkEncryptionTest.launch b/org.eclipse.jgit.test/org.eclipse.jgit.test-WalkEncryptionTest.launch
new file mode 100644
index 0000000..3b4a5a2
--- /dev/null
+++ b/org.eclipse.jgit.test/org.eclipse.jgit.test-WalkEncryptionTest.launch
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.m2e.Maven2LaunchConfigurationType">
+<booleanAttribute key="M2_DEBUG_OUTPUT" value="false"/>
+<stringAttribute key="M2_GOALS" value="test --define test=WalkEncryptionTest --activate-profiles test.long"/>
+<booleanAttribute key="M2_NON_RECURSIVE" value="false"/>
+<booleanAttribute key="M2_OFFLINE" value="false"/>
+<stringAttribute key="M2_PROFILES" value=""/>
+<listAttribute key="M2_PROPERTIES"/>
+<stringAttribute key="M2_RUNTIME" value="EMBEDDED"/>
+<booleanAttribute key="M2_SKIP_TESTS" value="false"/>
+<intAttribute key="M2_THREADS" value="1"/>
+<booleanAttribute key="M2_UPDATE_SNAPSHOTS" value="false"/>
+<stringAttribute key="M2_USER_SETTINGS" value=""/>
+<booleanAttribute key="M2_WORKSPACE_RESOLUTION" value="false"/>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/java-8-oracle"/>
+<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc:/org.eclipse.jgit.test}"/>
+</launchConfiguration>
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index be72211..0985c3d 100644
--- a/org.eclipse.jgit.test/pom.xml
+++ b/org.eclipse.jgit.test/pom.xml
@@ -52,7 +52,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.test</artifactId>
@@ -69,6 +69,16 @@
<scope>test</scope>
</dependency>
+ <!-- Optional security provider for encryption tests. -->
+ <!-- See https://dev.eclipse.org/ipzilla/show_bug.cgi?id=9554 -->
+ <!-- See https://bugs.eclipse.org/bugs/show_bug.cgi?id=467064 -->
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ <version>1.52</version>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
@@ -101,6 +111,24 @@
</dependency>
</dependencies>
+ <profiles>
+ <!-- Profile provides a property which enables long running tests. -->
+ <profile>
+ <id>test.long</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <argLine>-Djgit.test.long=true</argLine>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
<build>
<sourceDirectory>src/</sourceDirectory>
<testSourceDirectory>tst/</testSourceDirectory>
diff --git a/org.eclipse.jgit.test/tst-rsrc/jgit-s3-config.disabled.properties b/org.eclipse.jgit.test/tst-rsrc/jgit-s3-config.disabled.properties
new file mode 100644
index 0000000..d540977
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/jgit-s3-config.disabled.properties
@@ -0,0 +1,48 @@
+#
+# See WalkEncryptionTest.java
+#
+# This file is a template for test configuration file used by WalkEncryptionTest.
+# To be active, this file must have the following hard coded name: jgit-s3-config.properties
+# To be active, this file must be discovered by WalkEncryptionTest from one of these locations:
+# * ${user.home}/jgit-s3-config.properties
+# * ${user.dir}/jgit-s3-config.properties
+# * ${user.dir}/tst-rsrc/jgit-s3-config.properties
+# When this file is missing, tests in WalkEncryptionTest will not run, only report a warning.
+#
+
+#
+# WalkEncryptionTest requires amazon s3 test bucket setup.
+#
+# Test bucket setup instructions:
+#
+# Create IAM user:
+# http://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html
+# * user name: jgit.eclipse.org
+#
+# Configure IAM user S3 bucket access
+# http://docs.aws.amazon.com/AmazonS3/latest/dev/example-policies-s3.html
+# * attach S3 user policy to user account: jgit-s3-config.policy.user.json
+#
+# Create S3 bucket:
+# http://docs.aws.amazon.com/AmazonS3/latest/gsg/CreatingABucket.html
+# * bucket name: jgit.eclipse.org
+#
+# Configure S3 bucket source address/mask access:
+# http://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html
+# * attach bucket policy to the test bucket: jgit-s3-config.policy.bucket.json
+# * verify that any required source address/mask is included in the bucket policy:
+# * see https://wiki.eclipse.org/Hudson
+# * see http://www.tcpiputils.com/browse/ip-address/198.41.30.200
+# * proxy.eclipse.org 198.41.30.0/24
+# * Andrei Pozolotin 67.175.188.187/32
+#
+# Configure bucket 1 day expiration in object life cycle management:
+# * https://docs.aws.amazon.com/AmazonS3/latest/dev/manage-lifecycle-using-console.html
+#
+
+# Test bucket name
+test.bucket=jgit.eclipse.org
+
+# IAM credentials for user jgit.eclipse.org
+accesskey=AKIAIYWXB4ETREBRMZDQ
+secretkey=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
diff --git a/org.eclipse.jgit.test/tst-rsrc/jgit-s3-config.policy.bucket.json b/org.eclipse.jgit.test/tst-rsrc/jgit-s3-config.policy.bucket.json
new file mode 100644
index 0000000..3020b09
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/jgit-s3-config.policy.bucket.json
@@ -0,0 +1,20 @@
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "DenyAllButKnownSourceAddressWithMask",
+ "Effect": "Deny",
+ "Principal": "*",
+ "Action": "s3:*",
+ "Resource": "arn:aws:s3:::jgit.eclipse.org/*",
+ "Condition": {
+ "NotIpAddress": {
+ "aws:SourceIp": [
+ "198.41.30.0/24",
+ "67.175.188.187/32"
+ ]
+ }
+ }
+ }
+ ]
+}
diff --git a/org.eclipse.jgit.test/tst-rsrc/jgit-s3-config.policy.user.json b/org.eclipse.jgit.test/tst-rsrc/jgit-s3-config.policy.user.json
new file mode 100644
index 0000000..830d088
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/jgit-s3-config.policy.user.json
@@ -0,0 +1,24 @@
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "BucketList",
+ "Effect": "Allow",
+ "Action": "s3:ListAllMyBuckets",
+ "Resource": [
+ "arn:aws:s3:::jgit.eclipse.org"
+ ]
+ },
+ {
+ "Sid": "BucketFullControl",
+ "Effect": "Allow",
+ "Action": [
+ "s3:*"
+ ],
+ "Resource": [
+ "arn:aws:s3:::jgit.eclipse.org",
+ "arn:aws:s3:::jgit.eclipse.org/*"
+ ]
+ }
+ ]
+}
diff --git a/org.eclipse.jgit.test/tst-rsrc/jgit-s3-connection-v-0.properties b/org.eclipse.jgit.test/tst-rsrc/jgit-s3-connection-v-0.properties
new file mode 100644
index 0000000..2402a49
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/jgit-s3-connection-v-0.properties
@@ -0,0 +1,11 @@
+#
+# Sample Amazon S3 connection configuration file, Version 0.
+# Version 0 (or lack of version) will produce JetS3tV2 compatible encryption.
+# JetS3tV2 supports only PBE algorithms, with partially compromised AES mode.
+#
+
+accesskey = AKIAIYWXB4ETREBRM123
+secretkey = ozCuIsqxsARoPe3FFyv3F/jiMSc3Yqay7B9UF234
+
+crypto.algorithm = PBEWithMD5AndDES
+password = secret
diff --git a/org.eclipse.jgit.test/tst-rsrc/jgit-s3-connection-v-1.properties b/org.eclipse.jgit.test/tst-rsrc/jgit-s3-connection-v-1.properties
new file mode 100644
index 0000000..d0d1611
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/jgit-s3-connection-v-1.properties
@@ -0,0 +1,14 @@
+#
+# Sample Amazon S3 connection configuration file, Version 1.
+# Version 1 will produce JGitV1 compatible encryption.
+# It is JetS3tV2-like mode with proper AES support.
+# JGitV1 uses hard coded encryption parameters.
+# JGitV1 supports only PBE algorithms.
+#
+
+accesskey = AKIAIYWXB4ETREBRM123
+secretkey = ozCuIsqxsARoPe3FFyv3F/jiMSc3Yqay7B9UF234
+
+crypto.algorithm = PBEWithHmacSHA1AndAES_128
+crypto.version = 1
+password = secret
diff --git a/org.eclipse.jgit.test/tst-rsrc/jgit-s3-connection-v-2.properties b/org.eclipse.jgit.test/tst-rsrc/jgit-s3-connection-v-2.properties
new file mode 100644
index 0000000..731b324
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/jgit-s3-connection-v-2.properties
@@ -0,0 +1,48 @@
+#
+# Sample Amazon S3 connection configuration file, Version 2.
+# Version 2 will produce JGitV2 compatible encryption.
+# JGitV2 introduces more flexible control over cipher and key factory parameters.
+# JGitV2 hides actual cipher/key algorithms inside the encryption profile.
+# JGitV2 does not use any hard coded encryption parameters.
+# JGitV2 supports both PBE and Non-PBE algorithms.
+
+accesskey = AKIAIYWXB4ETREBRM123
+secretkey = ozCuIsqxsARoPe3FFyv3F/jiMSc3Yqay7B9UF234
+
+# In Version 2 "crypto.algorithm" is a reference to the encryption "profile".
+crypto.algorithm = custom
+crypto.version = 2
+password = secret
+
+#
+# Encryption profile is a collection of related properties,
+# all having common property root name, or prefix:
+#
+# Cipher algorithm.
+custom.algo = AES/CBC/PKCS5Padding
+# Key factory algorithm.
+custom.key.algo = PBKDF2WithHmacSHA512
+# Key size, bits.
+custom.key.size = 256
+# Number of key generation iterations.
+custom.key.iter = 50000
+# Salt used in key generation (hex value, white space OK).
+custom.key.salt = e2 55 89 67 8e 8d e8 4c
+
+# Same file can store multiple profiles.
+# Only one profile can be active at a time.
+# Active profile is selected via "crypto.algorithm"
+
+#
+# Here is how to create V1 encryption in V2 format:
+#
+# Cipher algorithm.
+legacy.algo = PBEWithHmacSHA1AndAES_128
+# Key factory algorithm.
+legacy.key.algo = PBEWithHmacSHA1AndAES_128
+# Key size, bits.
+legacy.key.size = 32
+# Number of key generation iterations.
+legacy.key.iter = 5000
+# Salt used in key generation (hex value, white space OK).
+legacy.key.salt = A40BC834D695F313
diff --git a/org.eclipse.jgit.test/tst-rsrc/log4j.properties b/org.eclipse.jgit.test/tst-rsrc/log4j.properties
new file mode 100644
index 0000000..14620ff
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/log4j.properties
@@ -0,0 +1,9 @@
+
+# Root logger option
+log4j.rootLogger=INFO, stdout
+
+# Direct log messages to stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AbstractRemoteCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AbstractRemoteCommandTest.java
new file mode 100644
index 0000000..d6a6342
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AbstractRemoteCommandTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.transport.RefSpec;
+import org.eclipse.jgit.transport.RemoteConfig;
+import org.eclipse.jgit.transport.URIish;
+
+public class AbstractRemoteCommandTest extends RepositoryTestCase {
+
+ protected static final String REMOTE_NAME = "test";
+
+ protected RemoteConfig setupRemote()
+ throws IOException, URISyntaxException {
+ // create another repository
+ Repository remoteRepository = createWorkRepository();
+
+ // set it up as a remote to this repository
+ final StoredConfig config = db.getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, REMOTE_NAME);
+
+ RefSpec refSpec = new RefSpec();
+ refSpec = refSpec.setForceUpdate(true);
+ refSpec = refSpec.setSourceDestination(Constants.R_HEADS + "*",
+ Constants.R_REMOTES + REMOTE_NAME + "/*");
+ remoteConfig.addFetchRefSpec(refSpec);
+
+ URIish uri = new URIish(
+ remoteRepository.getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+
+ remoteConfig.update(config);
+ config.save();
+
+ return remoteConfig;
+ }
+
+ protected void assertRemoteConfigEquals(RemoteConfig expected,
+ RemoteConfig actual) {
+ assertEquals(expected.getName(), actual.getName());
+ assertEquals(expected.getURIs(), actual.getURIs());
+ assertEquals(expected.getPushURIs(), actual.getPushURIs());
+ assertEquals(expected.getFetchRefSpecs(), actual.getFetchRefSpecs());
+ assertEquals(expected.getPushRefSpecs(), actual.getPushRefSpecs());
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
index 2abed3a..4fefdfd 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
@@ -43,8 +43,10 @@
*/
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;
import static org.junit.Assert.fail;
import java.io.File;
@@ -52,11 +54,13 @@
import java.io.IOException;
import java.io.PrintWriter;
+import org.eclipse.jgit.api.errors.FilterFailedException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
@@ -74,9 +78,7 @@
@Test
public void testAddNothing() throws GitAPIException {
- Git git = new Git(db);
-
- try {
+ try (Git git = new Git(db)) {
git.add().call();
fail("Expected IllegalArgumentException");
} catch (NoFilepatternException e) {
@@ -87,11 +89,10 @@
@Test
public void testAddNonExistingSingleFile() throws GitAPIException {
- Git git = new Git(db);
-
- DirCache dc = git.add().addFilepattern("a.txt").call();
- assertEquals(0, dc.getEntryCount());
-
+ try (Git git = new Git(db)) {
+ DirCache dc = git.add().addFilepattern("a.txt").call();
+ assertEquals(0, dc.getEntryCount());
+ }
}
@Test
@@ -102,13 +103,207 @@
writer.print("content");
writer.close();
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("a.txt").call();
- git.add().addFilepattern("a.txt").call();
+ assertEquals(
+ "[a.txt, mode:100644, content:content]",
+ indexState(CONTENT));
+ }
+ }
- assertEquals(
- "[a.txt, mode:100644, content:content]",
- indexState(CONTENT));
+ @Test
+ public void testCleanFilter() throws IOException,
+ GitAPIException {
+ writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+ writeTrashFile("src/a.tmp", "foo");
+ // Caution: we need a trailing '\n' since sed on mac always appends
+ // linefeeds if missing
+ writeTrashFile("src/a.txt", "foo\n");
+ File script = writeTempFile("sed s/o/e/g");
+
+ try (Git git = new Git(db)) {
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "tstFilter", "clean",
+ "sh " + slashify(script.getPath()));
+ config.save();
+
+ git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp")
+ .call();
+
+ assertEquals(
+ "[src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:fee\n]",
+ indexState(CONTENT));
+ }
+ }
+
+ @Test
+ public void testCleanFilterEnvironment()
+ throws IOException, GitAPIException {
+ writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+ writeTrashFile("src/a.txt", "foo");
+ File script = writeTempFile("echo $GIT_DIR; echo 1 >xyz");
+
+ try (Git git = new Git(db)) {
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "tstFilter", "clean",
+ "sh " + slashify(script.getPath()));
+ config.save();
+ git.add().addFilepattern("src/a.txt").call();
+
+ String gitDir = db.getDirectory().getAbsolutePath();
+ assertEquals("[src/a.txt, mode:100644, content:" + gitDir
+ + "\n]", indexState(CONTENT));
+ assertTrue(new File(db.getWorkTree(), "xyz").exists());
+ }
+ }
+
+ @Test
+ public void testMultipleCleanFilter() throws IOException, GitAPIException {
+ writeTrashFile(".gitattributes",
+ "*.txt filter=tstFilter\n*.tmp filter=tstFilter2");
+ // Caution: we need a trailing '\n' since sed on mac always appends
+ // linefeeds if missing
+ writeTrashFile("src/a.tmp", "foo\n");
+ writeTrashFile("src/a.txt", "foo\n");
+ File script = writeTempFile("sed s/o/e/g");
+ File script2 = writeTempFile("sed s/f/x/g");
+
+ try (Git git = new Git(db)) {
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "tstFilter", "clean",
+ "sh " + slashify(script.getPath()));
+ config.setString("filter", "tstFilter2", "clean",
+ "sh " + slashify(script2.getPath()));
+ config.save();
+
+ git.add().addFilepattern("src/a.txt").addFilepattern("src/a.tmp")
+ .call();
+
+ assertEquals(
+ "[src/a.tmp, mode:100644, content:xoo\n][src/a.txt, mode:100644, content:fee\n]",
+ indexState(CONTENT));
+
+ // TODO: multiple clean filters for one file???
+ }
+ }
+
+ /**
+ * The path of an added file name contains ';' and afterwards malicious
+ * commands. Make sure when calling filter commands to properly escape the
+ * filenames
+ *
+ * @throws IOException
+ * @throws GitAPIException
+ */
+ @Test
+ public void testCommandInjection() throws IOException, GitAPIException {
+ // Caution: we need a trailing '\n' since sed on mac always appends
+ // linefeeds if missing
+ writeTrashFile("; echo virus", "foo\n");
+ File script = writeTempFile("sed s/o/e/g");
+
+ try (Git git = new Git(db)) {
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "tstFilter", "clean",
+ "sh " + slashify(script.getPath()) + " %f");
+ writeTrashFile(".gitattributes", "* filter=tstFilter");
+
+ git.add().addFilepattern("; echo virus").call();
+ // Without proper escaping the content would be "feovirus". The sed
+ // command and the "echo virus" would contribute to the content
+ assertEquals("[; echo virus, mode:100644, content:fee\n]",
+ indexState(CONTENT));
+ }
+ }
+
+ @Test
+ public void testBadCleanFilter() throws IOException, GitAPIException {
+ writeTrashFile("a.txt", "foo");
+ File script = writeTempFile("sedfoo s/o/e/g");
+
+ try (Git git = new Git(db)) {
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "tstFilter", "clean",
+ "sh " + script.getPath());
+ config.save();
+ writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+
+ try {
+ git.add().addFilepattern("a.txt").call();
+ fail("Didn't received the expected exception");
+ } catch (FilterFailedException e) {
+ assertEquals(127, e.getReturnCode());
+ }
+ }
+ }
+
+ @Test
+ public void testBadCleanFilter2() throws IOException, GitAPIException {
+ writeTrashFile("a.txt", "foo");
+ File script = writeTempFile("sed s/o/e/g");
+
+ try (Git git = new Git(db)) {
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "tstFilter", "clean",
+ "shfoo " + script.getPath());
+ config.save();
+ writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+
+ try {
+ git.add().addFilepattern("a.txt").call();
+ fail("Didn't received the expected exception");
+ } catch (FilterFailedException e) {
+ assertEquals(127, e.getReturnCode());
+ }
+ }
+ }
+
+ @Test
+ public void testCleanFilterReturning12() throws IOException,
+ GitAPIException {
+ writeTrashFile("a.txt", "foo");
+ File script = writeTempFile("exit 12");
+
+ try (Git git = new Git(db)) {
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "tstFilter", "clean",
+ "sh " + slashify(script.getPath()));
+ config.save();
+ writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+
+ try {
+ git.add().addFilepattern("a.txt").call();
+ fail("Didn't received the expected exception");
+ } catch (FilterFailedException e) {
+ assertEquals(12, e.getReturnCode());
+ }
+ }
+ }
+
+ @Test
+ public void testNotApplicableFilter() throws IOException, GitAPIException {
+ writeTrashFile("a.txt", "foo");
+ File script = writeTempFile("sed s/o/e/g");
+
+ try (Git git = new Git(db)) {
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "tstFilter", "something",
+ "sh " + script.getPath());
+ config.save();
+ writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+
+ git.add().addFilepattern("a.txt").call();
+
+ assertEquals("[a.txt, mode:100644, content:foo]",
+ indexState(CONTENT));
+ }
+ }
+
+ private File writeTempFile(String body) throws IOException {
+ File f = File.createTempFile("AddCommandTest_", "");
+ JGitTestUtil.write(f, body);
+ return f;
}
@Test
@@ -120,19 +315,20 @@
writer.print("row1\r\nrow2");
writer.close();
- Git git = new Git(db);
- db.getConfig().setString("core", null, "autocrlf", "false");
- git.add().addFilepattern("a.txt").call();
- assertEquals("[a.txt, mode:100644, content:row1\r\nrow2]",
- indexState(CONTENT));
- db.getConfig().setString("core", null, "autocrlf", "true");
- git.add().addFilepattern("a.txt").call();
- assertEquals("[a.txt, mode:100644, content:row1\nrow2]",
- indexState(CONTENT));
- db.getConfig().setString("core", null, "autocrlf", "input");
- git.add().addFilepattern("a.txt").call();
- assertEquals("[a.txt, mode:100644, content:row1\nrow2]",
- indexState(CONTENT));
+ try (Git git = new Git(db)) {
+ db.getConfig().setString("core", null, "autocrlf", "false");
+ git.add().addFilepattern("a.txt").call();
+ assertEquals("[a.txt, mode:100644, content:row1\r\nrow2]",
+ indexState(CONTENT));
+ db.getConfig().setString("core", null, "autocrlf", "true");
+ git.add().addFilepattern("a.txt").call();
+ assertEquals("[a.txt, mode:100644, content:row1\nrow2]",
+ indexState(CONTENT));
+ db.getConfig().setString("core", null, "autocrlf", "input");
+ git.add().addFilepattern("a.txt").call();
+ assertEquals("[a.txt, mode:100644, content:row1\nrow2]",
+ indexState(CONTENT));
+ }
}
@Test
@@ -149,19 +345,20 @@
writer.print(crData);
writer.close();
String lfData = data.toString().replaceAll("\r", "");
- Git git = new Git(db);
- db.getConfig().setString("core", null, "autocrlf", "false");
- git.add().addFilepattern("a.txt").call();
- assertEquals("[a.txt, mode:100644, content:" + data + "]",
- indexState(CONTENT));
- db.getConfig().setString("core", null, "autocrlf", "true");
- git.add().addFilepattern("a.txt").call();
- assertEquals("[a.txt, mode:100644, content:" + lfData + "]",
- indexState(CONTENT));
- db.getConfig().setString("core", null, "autocrlf", "input");
- git.add().addFilepattern("a.txt").call();
- assertEquals("[a.txt, mode:100644, content:" + lfData + "]",
- indexState(CONTENT));
+ try (Git git = new Git(db)) {
+ db.getConfig().setString("core", null, "autocrlf", "false");
+ git.add().addFilepattern("a.txt").call();
+ assertEquals("[a.txt, mode:100644, content:" + data + "]",
+ indexState(CONTENT));
+ db.getConfig().setString("core", null, "autocrlf", "true");
+ git.add().addFilepattern("a.txt").call();
+ assertEquals("[a.txt, mode:100644, content:" + lfData + "]",
+ indexState(CONTENT));
+ db.getConfig().setString("core", null, "autocrlf", "input");
+ git.add().addFilepattern("a.txt").call();
+ assertEquals("[a.txt, mode:100644, content:" + lfData + "]",
+ indexState(CONTENT));
+ }
}
@Test
@@ -173,19 +370,20 @@
writer.print("row1\r\nrow2\u0000");
writer.close();
- Git git = new Git(db);
- db.getConfig().setString("core", null, "autocrlf", "false");
- git.add().addFilepattern("a.txt").call();
- assertEquals("[a.txt, mode:100644, content:row1\r\nrow2\u0000]",
- indexState(CONTENT));
- db.getConfig().setString("core", null, "autocrlf", "true");
- git.add().addFilepattern("a.txt").call();
- assertEquals("[a.txt, mode:100644, content:row1\r\nrow2\u0000]",
- indexState(CONTENT));
- db.getConfig().setString("core", null, "autocrlf", "input");
- git.add().addFilepattern("a.txt").call();
- assertEquals("[a.txt, mode:100644, content:row1\r\nrow2\u0000]",
- indexState(CONTENT));
+ try (Git git = new Git(db)) {
+ db.getConfig().setString("core", null, "autocrlf", "false");
+ git.add().addFilepattern("a.txt").call();
+ assertEquals("[a.txt, mode:100644, content:row1\r\nrow2\u0000]",
+ indexState(CONTENT));
+ db.getConfig().setString("core", null, "autocrlf", "true");
+ git.add().addFilepattern("a.txt").call();
+ assertEquals("[a.txt, mode:100644, content:row1\r\nrow2\u0000]",
+ indexState(CONTENT));
+ db.getConfig().setString("core", null, "autocrlf", "input");
+ git.add().addFilepattern("a.txt").call();
+ assertEquals("[a.txt, mode:100644, content:row1\r\nrow2\u0000]",
+ indexState(CONTENT));
+ }
}
@Test
@@ -198,13 +396,13 @@
writer.print("content");
writer.close();
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("sub/a.txt").call();
- git.add().addFilepattern("sub/a.txt").call();
-
- assertEquals(
- "[sub/a.txt, mode:100644, content:content]",
- indexState(CONTENT));
+ assertEquals(
+ "[sub/a.txt, mode:100644, content:content]",
+ indexState(CONTENT));
+ }
}
@Test
@@ -216,20 +414,21 @@
writer.print("content");
writer.close();
- Git git = new Git(db);
- DirCache dc = git.add().addFilepattern("a.txt").call();
+ try (Git git = new Git(db)) {
+ DirCache dc = git.add().addFilepattern("a.txt").call();
- dc.getEntry(0).getObjectId();
+ dc.getEntry(0).getObjectId();
- writer = new PrintWriter(file);
- writer.print("other content");
- writer.close();
+ writer = new PrintWriter(file);
+ writer.print("other content");
+ writer.close();
- dc = git.add().addFilepattern("a.txt").call();
+ dc = git.add().addFilepattern("a.txt").call();
- assertEquals(
- "[a.txt, mode:100644, content:other content]",
- indexState(CONTENT));
+ assertEquals(
+ "[a.txt, mode:100644, content:other content]",
+ indexState(CONTENT));
+ }
}
@Test
@@ -240,22 +439,23 @@
writer.print("content");
writer.close();
- Git git = new Git(db);
- DirCache dc = git.add().addFilepattern("a.txt").call();
+ try (Git git = new Git(db)) {
+ DirCache dc = git.add().addFilepattern("a.txt").call();
- dc.getEntry(0).getObjectId();
+ dc.getEntry(0).getObjectId();
- git.commit().setMessage("commit a.txt").call();
+ git.commit().setMessage("commit a.txt").call();
- writer = new PrintWriter(file);
- writer.print("other content");
- writer.close();
+ writer = new PrintWriter(file);
+ writer.print("other content");
+ writer.close();
- dc = git.add().addFilepattern("a.txt").call();
+ dc = git.add().addFilepattern("a.txt").call();
- assertEquals(
- "[a.txt, mode:100644, content:other content]",
- indexState(CONTENT));
+ assertEquals(
+ "[a.txt, mode:100644, content:other content]",
+ indexState(CONTENT));
+ }
}
@Test
@@ -266,18 +466,19 @@
writer.print("content");
writer.close();
- Git git = new Git(db);
- DirCache dc = git.add().addFilepattern("a.txt").call();
+ try (Git git = new Git(db)) {
+ DirCache dc = git.add().addFilepattern("a.txt").call();
- dc.getEntry(0).getObjectId();
- FileUtils.delete(file);
+ dc.getEntry(0).getObjectId();
+ FileUtils.delete(file);
- // is supposed to do nothing
- dc = git.add().addFilepattern("a.txt").call();
+ // is supposed to do nothing
+ dc = git.add().addFilepattern("a.txt").call();
- assertEquals(
- "[a.txt, mode:100644, content:content]",
- indexState(CONTENT));
+ assertEquals(
+ "[a.txt, mode:100644, content:content]",
+ indexState(CONTENT));
+ }
}
@Test
@@ -288,20 +489,21 @@
writer.print("content");
writer.close();
- Git git = new Git(db);
- DirCache dc = git.add().addFilepattern("a.txt").call();
+ try (Git git = new Git(db)) {
+ DirCache dc = git.add().addFilepattern("a.txt").call();
- git.commit().setMessage("commit a.txt").call();
+ git.commit().setMessage("commit a.txt").call();
- dc.getEntry(0).getObjectId();
- FileUtils.delete(file);
+ dc.getEntry(0).getObjectId();
+ FileUtils.delete(file);
- // is supposed to do nothing
- dc = git.add().addFilepattern("a.txt").call();
+ // is supposed to do nothing
+ dc = git.add().addFilepattern("a.txt").call();
- assertEquals(
- "[a.txt, mode:100644, content:content]",
- indexState(CONTENT));
+ assertEquals(
+ "[a.txt, mode:100644, content:content]",
+ indexState(CONTENT));
+ }
}
@Test
@@ -349,13 +551,14 @@
// now the test begins
- Git git = new Git(db);
- dc = git.add().addFilepattern("a.txt").call();
+ try (Git git = new Git(db)) {
+ dc = git.add().addFilepattern("a.txt").call();
- assertEquals(
- "[a.txt, mode:100644, content:our content]" +
- "[b.txt, mode:100644, content:content b]",
- indexState(CONTENT));
+ assertEquals(
+ "[a.txt, mode:100644, content:our content]" +
+ "[b.txt, mode:100644, content:content b]",
+ indexState(CONTENT));
+ }
}
@Test
@@ -372,12 +575,13 @@
writer.print("content b");
writer.close();
- Git git = new Git(db);
- git.add().addFilepattern("a.txt").addFilepattern("b.txt").call();
- assertEquals(
- "[a.txt, mode:100644, content:content]" +
- "[b.txt, mode:100644, content:content b]",
- indexState(CONTENT));
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("a.txt").addFilepattern("b.txt").call();
+ assertEquals(
+ "[a.txt, mode:100644, content:content]" +
+ "[b.txt, mode:100644, content:content b]",
+ indexState(CONTENT));
+ }
}
@Test
@@ -395,12 +599,13 @@
writer.print("content b");
writer.close();
- Git git = new Git(db);
- git.add().addFilepattern("sub").call();
- assertEquals(
- "[sub/a.txt, mode:100644, content:content]" +
- "[sub/b.txt, mode:100644, content:content b]",
- indexState(CONTENT));
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("sub").call();
+ assertEquals(
+ "[sub/a.txt, mode:100644, content:content]" +
+ "[sub/b.txt, mode:100644, content:content b]",
+ indexState(CONTENT));
+ }
}
@Test
@@ -424,12 +629,13 @@
writer.print("content b");
writer.close();
- Git git = new Git(db);
- git.add().addFilepattern("sub").call();
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("sub").call();
- assertEquals(
- "[sub/a.txt, mode:100644, content:content]",
- indexState(CONTENT));
+ assertEquals(
+ "[sub/a.txt, mode:100644, content:content]",
+ indexState(CONTENT));
+ }
}
@Test
@@ -447,12 +653,13 @@
writer.print("content b");
writer.close();
- Git git = new Git(db);
- git.add().addFilepattern(".").call();
- assertEquals(
- "[sub/a.txt, mode:100644, content:content]" +
- "[sub/b.txt, mode:100644, content:content b]",
- indexState(CONTENT));
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(".").call();
+ assertEquals(
+ "[sub/a.txt, mode:100644, content:content]" +
+ "[sub/b.txt, mode:100644, content:content b]",
+ indexState(CONTENT));
+ }
}
// the same three cases as in testAddWithParameterUpdate
@@ -474,40 +681,41 @@
writer.print("content b");
writer.close();
- Git git = new Git(db);
- git.add().addFilepattern("sub").call();
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("sub").call();
- assertEquals(
- "[sub/a.txt, mode:100644, content:content]" +
- "[sub/b.txt, mode:100644, content:content b]",
- indexState(CONTENT));
+ assertEquals(
+ "[sub/a.txt, mode:100644, content:content]" +
+ "[sub/b.txt, mode:100644, content:content b]",
+ indexState(CONTENT));
- git.commit().setMessage("commit").call();
+ git.commit().setMessage("commit").call();
- // new unstaged file sub/c.txt
- File file3 = new File(db.getWorkTree(), "sub/c.txt");
- FileUtils.createNewFile(file3);
- writer = new PrintWriter(file3);
- writer.print("content c");
- writer.close();
+ // new unstaged file sub/c.txt
+ File file3 = new File(db.getWorkTree(), "sub/c.txt");
+ FileUtils.createNewFile(file3);
+ writer = new PrintWriter(file3);
+ writer.print("content c");
+ writer.close();
- // file sub/a.txt is modified
- writer = new PrintWriter(file);
- writer.print("modified content");
- writer.close();
+ // file sub/a.txt is modified
+ writer = new PrintWriter(file);
+ writer.print("modified content");
+ writer.close();
- // file sub/b.txt is deleted
- FileUtils.delete(file2);
+ // file sub/b.txt is deleted
+ FileUtils.delete(file2);
- git.add().addFilepattern("sub").call();
- // change in sub/a.txt is staged
- // deletion of sub/b.txt is not staged
- // sub/c.txt is staged
- assertEquals(
- "[sub/a.txt, mode:100644, content:modified content]" +
- "[sub/b.txt, mode:100644, content:content b]" +
- "[sub/c.txt, mode:100644, content:content c]",
- indexState(CONTENT));
+ git.add().addFilepattern("sub").call();
+ // change in sub/a.txt is staged
+ // deletion of sub/b.txt is not staged
+ // sub/c.txt is staged
+ assertEquals(
+ "[sub/a.txt, mode:100644, content:modified content]" +
+ "[sub/b.txt, mode:100644, content:content b]" +
+ "[sub/c.txt, mode:100644, content:content c]",
+ indexState(CONTENT));
+ }
}
// file a exists in workdir and in index -> added
@@ -528,71 +736,168 @@
writer.print("content b");
writer.close();
- Git git = new Git(db);
- git.add().addFilepattern("sub").call();
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("sub").call();
- assertEquals(
- "[sub/a.txt, mode:100644, content:content]" +
- "[sub/b.txt, mode:100644, content:content b]",
- indexState(CONTENT));
+ assertEquals(
+ "[sub/a.txt, mode:100644, content:content]" +
+ "[sub/b.txt, mode:100644, content:content b]",
+ indexState(CONTENT));
- git.commit().setMessage("commit").call();
+ git.commit().setMessage("commit").call();
- // new unstaged file sub/c.txt
- File file3 = new File(db.getWorkTree(), "sub/c.txt");
- FileUtils.createNewFile(file3);
- writer = new PrintWriter(file3);
- writer.print("content c");
- writer.close();
+ // new unstaged file sub/c.txt
+ File file3 = new File(db.getWorkTree(), "sub/c.txt");
+ FileUtils.createNewFile(file3);
+ writer = new PrintWriter(file3);
+ writer.print("content c");
+ writer.close();
- // file sub/a.txt is modified
- writer = new PrintWriter(file);
- writer.print("modified content");
- writer.close();
+ // file sub/a.txt is modified
+ writer = new PrintWriter(file);
+ writer.print("modified content");
+ writer.close();
- FileUtils.delete(file2);
+ FileUtils.delete(file2);
- // change in sub/a.txt is staged
- // deletion of sub/b.txt is staged
- // sub/c.txt is not staged
- git.add().addFilepattern("sub").setUpdate(true).call();
- // change in sub/a.txt is staged
- assertEquals(
- "[sub/a.txt, mode:100644, content:modified content]",
- indexState(CONTENT));
+ // change in sub/a.txt is staged
+ // deletion of sub/b.txt is staged
+ // sub/c.txt is not staged
+ git.add().addFilepattern("sub").setUpdate(true).call();
+ // change in sub/a.txt is staged
+ assertEquals(
+ "[sub/a.txt, mode:100644, content:modified content]",
+ indexState(CONTENT));
+ }
}
@Test
public void testAssumeUnchanged() throws Exception {
- Git git = new Git(db);
- String path = "a.txt";
- writeTrashFile(path, "content");
- git.add().addFilepattern(path).call();
- String path2 = "b.txt";
- writeTrashFile(path2, "content");
- git.add().addFilepattern(path2).call();
- git.commit().setMessage("commit").call();
- assertEquals("[a.txt, mode:100644, content:"
- + "content, assume-unchanged:false]"
- + "[b.txt, mode:100644, content:content, "
- + "assume-unchanged:false]", indexState(CONTENT
- | ASSUME_UNCHANGED));
- assumeUnchanged(path2);
- assertEquals("[a.txt, mode:100644, content:content, "
- + "assume-unchanged:false][b.txt, mode:100644, "
- + "content:content, assume-unchanged:true]", indexState(CONTENT
- | ASSUME_UNCHANGED));
- writeTrashFile(path, "more content");
- writeTrashFile(path2, "more content");
+ try (Git git = new Git(db)) {
+ String path = "a.txt";
+ writeTrashFile(path, "content");
+ git.add().addFilepattern(path).call();
+ String path2 = "b.txt";
+ writeTrashFile(path2, "content");
+ git.add().addFilepattern(path2).call();
+ git.commit().setMessage("commit").call();
+ assertEquals("[a.txt, mode:100644, content:"
+ + "content, assume-unchanged:false]"
+ + "[b.txt, mode:100644, content:content, "
+ + "assume-unchanged:false]", indexState(CONTENT
+ | ASSUME_UNCHANGED));
+ assumeUnchanged(path2);
+ assertEquals("[a.txt, mode:100644, content:content, "
+ + "assume-unchanged:false][b.txt, mode:100644, "
+ + "content:content, assume-unchanged:true]", indexState(CONTENT
+ | ASSUME_UNCHANGED));
+ writeTrashFile(path, "more content");
+ writeTrashFile(path2, "more content");
- git.add().addFilepattern(".").call();
+ git.add().addFilepattern(".").call();
- assertEquals("[a.txt, mode:100644, content:more content,"
- + " assume-unchanged:false][b.txt, mode:100644,"
- + "" + ""
- + " content:content, assume-unchanged:true]",
- indexState(CONTENT
- | ASSUME_UNCHANGED));
+ 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
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
index ad3ff60..d842046 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java
@@ -69,23 +69,24 @@
private ApplyResult init(final String name, final boolean preExists,
final boolean postExists) throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ if (preExists) {
+ a = new RawText(readFile(name + "_PreImage"));
+ write(new File(db.getDirectory().getParent(), name),
+ a.getString(0, a.size(), false));
- if (preExists) {
- a = new RawText(readFile(name + "_PreImage"));
- write(new File(db.getDirectory().getParent(), name),
- a.getString(0, a.size(), false));
+ git.add().addFilepattern(name).call();
+ git.commit().setMessage("PreImage").call();
+ }
- git.add().addFilepattern(name).call();
- git.commit().setMessage("PreImage").call();
+ if (postExists) {
+ b = new RawText(readFile(name + "_PostImage"));
+ }
+
+ return git
+ .apply()
+ .setPatch(getTestResource(name + ".patch")).call();
}
-
- if (postExists)
- b = new RawText(readFile(name + "_PostImage"));
-
- return git
- .apply()
- .setPatch(getTestResource(name + ".patch")).call();
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java
index 44e7088..fc8df42 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ArchiveCommandTest.java
@@ -85,103 +85,107 @@
@Test
public void archiveHeadAllFiles() throws IOException, GitAPIException {
- Git git = new Git(db);
- writeTrashFile("file_1.txt", "content_1_1");
- git.add().addFilepattern("file_1.txt").call();
- git.commit().setMessage("create file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file_1.txt", "content_1_1");
+ git.add().addFilepattern("file_1.txt").call();
+ git.commit().setMessage("create file").call();
- writeTrashFile("file_1.txt", "content_1_2");
- writeTrashFile("file_2.txt", "content_2_2");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("updated file").call();
+ writeTrashFile("file_1.txt", "content_1_2");
+ writeTrashFile("file_2.txt", "content_2_2");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("updated file").call();
- git.archive().setOutputStream(new MockOutputStream())
- .setFormat(format.SUFFIXES.get(0))
- .setTree(git.getRepository().resolve("HEAD")).call();
+ git.archive().setOutputStream(new MockOutputStream())
+ .setFormat(format.SUFFIXES.get(0))
+ .setTree(git.getRepository().resolve("HEAD")).call();
- assertEquals(UNEXPECTED_ARCHIVE_SIZE, 2, format.size());
- assertEquals(UNEXPECTED_FILE_CONTENTS, "content_1_2", format.getByPath("file_1.txt"));
- assertEquals(UNEXPECTED_FILE_CONTENTS, "content_2_2", format.getByPath("file_2.txt"));
+ assertEquals(UNEXPECTED_ARCHIVE_SIZE, 2, format.size());
+ assertEquals(UNEXPECTED_FILE_CONTENTS, "content_1_2", format.getByPath("file_1.txt"));
+ assertEquals(UNEXPECTED_FILE_CONTENTS, "content_2_2", format.getByPath("file_2.txt"));
+ }
}
@Test
public void archiveHeadSpecificPath() throws IOException, GitAPIException {
- Git git = new Git(db);
- writeTrashFile("file_1.txt", "content_1_1");
- git.add().addFilepattern("file_1.txt").call();
- git.commit().setMessage("create file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file_1.txt", "content_1_1");
+ git.add().addFilepattern("file_1.txt").call();
+ git.commit().setMessage("create file").call();
- writeTrashFile("file_1.txt", "content_1_2");
- String expectedFilePath = "some_directory/file_2.txt";
- writeTrashFile(expectedFilePath, "content_2_2");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("updated file").call();
+ writeTrashFile("file_1.txt", "content_1_2");
+ String expectedFilePath = "some_directory/file_2.txt";
+ writeTrashFile(expectedFilePath, "content_2_2");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("updated file").call();
- git.archive().setOutputStream(new MockOutputStream())
- .setFormat(format.SUFFIXES.get(0))
- .setTree(git.getRepository().resolve("HEAD"))
- .setPaths(expectedFilePath).call();
+ git.archive().setOutputStream(new MockOutputStream())
+ .setFormat(format.SUFFIXES.get(0))
+ .setTree(git.getRepository().resolve("HEAD"))
+ .setPaths(expectedFilePath).call();
- assertEquals(UNEXPECTED_ARCHIVE_SIZE, 2, format.size());
- assertEquals(UNEXPECTED_FILE_CONTENTS, "content_2_2", format.getByPath(expectedFilePath));
- assertNull(UNEXPECTED_TREE_CONTENTS, format.getByPath("some_directory"));
+ assertEquals(UNEXPECTED_ARCHIVE_SIZE, 2, format.size());
+ assertEquals(UNEXPECTED_FILE_CONTENTS, "content_2_2", format.getByPath(expectedFilePath));
+ assertNull(UNEXPECTED_TREE_CONTENTS, format.getByPath("some_directory"));
+ }
}
@Test
public void archiveByIdSpecificFile() throws IOException, GitAPIException {
- Git git = new Git(db);
- writeTrashFile("file_1.txt", "content_1_1");
- git.add().addFilepattern("file_1.txt").call();
- RevCommit first = git.commit().setMessage("create file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file_1.txt", "content_1_1");
+ git.add().addFilepattern("file_1.txt").call();
+ RevCommit first = git.commit().setMessage("create file").call();
- writeTrashFile("file_1.txt", "content_1_2");
- String expectedFilePath = "some_directory/file_2.txt";
- writeTrashFile(expectedFilePath, "content_2_2");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("updated file").call();
+ writeTrashFile("file_1.txt", "content_1_2");
+ String expectedFilePath = "some_directory/file_2.txt";
+ writeTrashFile(expectedFilePath, "content_2_2");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("updated file").call();
- Map<String, Object> options = new HashMap<>();
- Integer opt = Integer.valueOf(42);
- options.put("foo", opt);
- MockOutputStream out = new MockOutputStream();
- git.archive().setOutputStream(out)
- .setFormat(format.SUFFIXES.get(0))
- .setFormatOptions(options)
- .setTree(first)
- .setPaths("file_1.txt").call();
+ Map<String, Object> options = new HashMap<>();
+ Integer opt = Integer.valueOf(42);
+ options.put("foo", opt);
+ MockOutputStream out = new MockOutputStream();
+ git.archive().setOutputStream(out)
+ .setFormat(format.SUFFIXES.get(0))
+ .setFormatOptions(options)
+ .setTree(first)
+ .setPaths("file_1.txt").call();
- assertEquals(opt.intValue(), out.getFoo());
- assertEquals(UNEXPECTED_ARCHIVE_SIZE, 1, format.size());
- assertEquals(UNEXPECTED_FILE_CONTENTS, "content_1_1", format.getByPath("file_1.txt"));
+ assertEquals(opt.intValue(), out.getFoo());
+ assertEquals(UNEXPECTED_ARCHIVE_SIZE, 1, format.size());
+ assertEquals(UNEXPECTED_FILE_CONTENTS, "content_1_1", format.getByPath("file_1.txt"));
+ }
}
@Test
public void archiveByDirectoryPath() throws GitAPIException, IOException {
- Git git = new Git(db);
- writeTrashFile("file_0.txt", "content_0_1");
- git.add().addFilepattern("file_0.txt").call();
- git.commit().setMessage("commit_1").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file_0.txt", "content_0_1");
+ git.add().addFilepattern("file_0.txt").call();
+ git.commit().setMessage("commit_1").call();
- writeTrashFile("file_0.txt", "content_0_2");
- String expectedFilePath1 = "some_directory/file_1.txt";
- writeTrashFile(expectedFilePath1, "content_1_2");
- String expectedFilePath2 = "some_directory/file_2.txt";
- writeTrashFile(expectedFilePath2, "content_2_2");
- String expectedFilePath3 = "some_directory/nested_directory/file_3.txt";
- writeTrashFile(expectedFilePath3, "content_3_2");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("commit_2").call();
- git.archive().setOutputStream(new MockOutputStream())
- .setFormat(format.SUFFIXES.get(0))
- .setTree(git.getRepository().resolve("HEAD"))
- .setPaths("some_directory/").call();
+ writeTrashFile("file_0.txt", "content_0_2");
+ String expectedFilePath1 = "some_directory/file_1.txt";
+ writeTrashFile(expectedFilePath1, "content_1_2");
+ String expectedFilePath2 = "some_directory/file_2.txt";
+ writeTrashFile(expectedFilePath2, "content_2_2");
+ String expectedFilePath3 = "some_directory/nested_directory/file_3.txt";
+ writeTrashFile(expectedFilePath3, "content_3_2");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("commit_2").call();
+ git.archive().setOutputStream(new MockOutputStream())
+ .setFormat(format.SUFFIXES.get(0))
+ .setTree(git.getRepository().resolve("HEAD"))
+ .setPaths("some_directory/").call();
- assertEquals(UNEXPECTED_ARCHIVE_SIZE, 5, format.size());
- assertEquals(UNEXPECTED_FILE_CONTENTS, "content_1_2", format.getByPath(expectedFilePath1));
- assertEquals(UNEXPECTED_FILE_CONTENTS, "content_2_2", format.getByPath(expectedFilePath2));
- assertEquals(UNEXPECTED_FILE_CONTENTS, "content_3_2", format.getByPath(expectedFilePath3));
- assertNull(UNEXPECTED_TREE_CONTENTS, format.getByPath("some_directory"));
- assertNull(UNEXPECTED_TREE_CONTENTS, format.getByPath("some_directory/nested_directory"));
+ assertEquals(UNEXPECTED_ARCHIVE_SIZE, 5, format.size());
+ assertEquals(UNEXPECTED_FILE_CONTENTS, "content_1_2", format.getByPath(expectedFilePath1));
+ assertEquals(UNEXPECTED_FILE_CONTENTS, "content_2_2", format.getByPath(expectedFilePath2));
+ assertEquals(UNEXPECTED_FILE_CONTENTS, "content_3_2", format.getByPath(expectedFilePath3));
+ assertNull(UNEXPECTED_TREE_CONTENTS, format.getByPath("some_directory"));
+ assertNull(UNEXPECTED_TREE_CONTENTS, format.getByPath("some_directory/nested_directory"));
+ }
}
private class MockFormat implements ArchiveCommand.Format<MockOutputStream> {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java
index 0745eb6..f37aa13 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java
@@ -72,53 +72,53 @@
@Test
public void testSingleRevision() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ String[] content = new String[] { "first", "second", "third" };
- String[] content = new String[] { "first", "second", "third" };
+ writeTrashFile("file.txt", join(content));
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit = git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", join(content));
- git.add().addFilepattern("file.txt").call();
- RevCommit commit = git.commit().setMessage("create file").call();
+ BlameCommand command = new BlameCommand(db);
+ command.setFilePath("file.txt");
+ BlameResult lines = command.call();
+ assertNotNull(lines);
+ assertEquals(3, lines.getResultContents().size());
- BlameCommand command = new BlameCommand(db);
- command.setFilePath("file.txt");
- BlameResult lines = command.call();
- assertNotNull(lines);
- assertEquals(3, lines.getResultContents().size());
-
- for (int i = 0; i < 3; i++) {
- assertEquals(commit, lines.getSourceCommit(i));
- assertEquals(i, lines.getSourceLine(i));
+ for (int i = 0; i < 3; i++) {
+ assertEquals(commit, lines.getSourceCommit(i));
+ assertEquals(i, lines.getSourceLine(i));
+ }
}
}
@Test
public void testTwoRevisions() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ String[] content1 = new String[] { "first", "second" };
+ writeTrashFile("file.txt", join(content1));
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit1 = git.commit().setMessage("create file").call();
- String[] content1 = new String[] { "first", "second" };
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
- RevCommit commit1 = git.commit().setMessage("create file").call();
+ String[] content2 = new String[] { "first", "second", "third" };
+ writeTrashFile("file.txt", join(content2));
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit2 = git.commit().setMessage("create file").call();
- String[] content2 = new String[] { "first", "second", "third" };
- writeTrashFile("file.txt", join(content2));
- git.add().addFilepattern("file.txt").call();
- RevCommit commit2 = git.commit().setMessage("create file").call();
+ BlameCommand command = new BlameCommand(db);
+ command.setFilePath("file.txt");
+ BlameResult lines = command.call();
+ assertEquals(3, lines.getResultContents().size());
- BlameCommand command = new BlameCommand(db);
- command.setFilePath("file.txt");
- BlameResult lines = command.call();
- assertEquals(3, lines.getResultContents().size());
+ assertEquals(commit1, lines.getSourceCommit(0));
+ assertEquals(0, lines.getSourceLine(0));
- assertEquals(commit1, lines.getSourceCommit(0));
- assertEquals(0, lines.getSourceLine(0));
+ assertEquals(commit1, lines.getSourceCommit(1));
+ assertEquals(1, lines.getSourceLine(1));
- assertEquals(commit1, lines.getSourceCommit(1));
- assertEquals(1, lines.getSourceLine(1));
-
- assertEquals(commit2, lines.getSourceCommit(2));
- assertEquals(2, lines.getSourceLine(2));
+ assertEquals(commit2, lines.getSourceCommit(2));
+ assertEquals(2, lines.getSourceLine(2));
+ }
}
@Test
@@ -138,200 +138,200 @@
private void testRename(final String sourcePath, final String destPath)
throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ String[] content1 = new String[] { "a", "b", "c" };
+ writeTrashFile(sourcePath, join(content1));
+ git.add().addFilepattern(sourcePath).call();
+ RevCommit commit1 = git.commit().setMessage("create file").call();
- String[] content1 = new String[] { "a", "b", "c" };
- writeTrashFile(sourcePath, join(content1));
- git.add().addFilepattern(sourcePath).call();
- RevCommit commit1 = git.commit().setMessage("create file").call();
+ writeTrashFile(destPath, join(content1));
+ git.add().addFilepattern(destPath).call();
+ git.rm().addFilepattern(sourcePath).call();
+ git.commit().setMessage("moving file").call();
- writeTrashFile(destPath, join(content1));
- git.add().addFilepattern(destPath).call();
- git.rm().addFilepattern(sourcePath).call();
- git.commit().setMessage("moving file").call();
+ String[] content2 = new String[] { "a", "b", "c2" };
+ writeTrashFile(destPath, join(content2));
+ git.add().addFilepattern(destPath).call();
+ RevCommit commit3 = git.commit().setMessage("editing file").call();
- String[] content2 = new String[] { "a", "b", "c2" };
- writeTrashFile(destPath, join(content2));
- git.add().addFilepattern(destPath).call();
- RevCommit commit3 = git.commit().setMessage("editing file").call();
+ BlameCommand command = new BlameCommand(db);
+ command.setFollowFileRenames(true);
+ command.setFilePath(destPath);
+ BlameResult lines = command.call();
- BlameCommand command = new BlameCommand(db);
- command.setFollowFileRenames(true);
- command.setFilePath(destPath);
- BlameResult lines = command.call();
+ assertEquals(commit1, lines.getSourceCommit(0));
+ assertEquals(0, lines.getSourceLine(0));
+ assertEquals(sourcePath, lines.getSourcePath(0));
- assertEquals(commit1, lines.getSourceCommit(0));
- assertEquals(0, lines.getSourceLine(0));
- assertEquals(sourcePath, lines.getSourcePath(0));
+ assertEquals(commit1, lines.getSourceCommit(1));
+ assertEquals(1, lines.getSourceLine(1));
+ assertEquals(sourcePath, lines.getSourcePath(1));
- assertEquals(commit1, lines.getSourceCommit(1));
- assertEquals(1, lines.getSourceLine(1));
- assertEquals(sourcePath, lines.getSourcePath(1));
-
- assertEquals(commit3, lines.getSourceCommit(2));
- assertEquals(2, lines.getSourceLine(2));
- assertEquals(destPath, lines.getSourcePath(2));
+ assertEquals(commit3, lines.getSourceCommit(2));
+ assertEquals(2, lines.getSourceLine(2));
+ assertEquals(destPath, lines.getSourcePath(2));
+ }
}
@Test
public void testTwoRenames() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ // Commit 1: Add file.txt
+ String[] content1 = new String[] { "a" };
+ writeTrashFile("file.txt", join(content1));
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit1 = git.commit().setMessage("create file").call();
- // Commit 1: Add file.txt
- String[] content1 = new String[] { "a" };
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
- RevCommit commit1 = git.commit().setMessage("create file").call();
+ // Commit 2: Rename to file1.txt
+ writeTrashFile("file1.txt", join(content1));
+ git.add().addFilepattern("file1.txt").call();
+ git.rm().addFilepattern("file.txt").call();
+ git.commit().setMessage("moving file").call();
- // Commit 2: Rename to file1.txt
- writeTrashFile("file1.txt", join(content1));
- git.add().addFilepattern("file1.txt").call();
- git.rm().addFilepattern("file.txt").call();
- git.commit().setMessage("moving file").call();
+ // Commit 3: Edit file1.txt
+ String[] content2 = new String[] { "a", "b" };
+ writeTrashFile("file1.txt", join(content2));
+ git.add().addFilepattern("file1.txt").call();
+ RevCommit commit3 = git.commit().setMessage("editing file").call();
- // Commit 3: Edit file1.txt
- String[] content2 = new String[] { "a", "b" };
- writeTrashFile("file1.txt", join(content2));
- git.add().addFilepattern("file1.txt").call();
- RevCommit commit3 = git.commit().setMessage("editing file").call();
+ // Commit 4: Rename to file2.txt
+ writeTrashFile("file2.txt", join(content2));
+ git.add().addFilepattern("file2.txt").call();
+ git.rm().addFilepattern("file1.txt").call();
+ git.commit().setMessage("moving file again").call();
- // Commit 4: Rename to file2.txt
- writeTrashFile("file2.txt", join(content2));
- git.add().addFilepattern("file2.txt").call();
- git.rm().addFilepattern("file1.txt").call();
- git.commit().setMessage("moving file again").call();
+ BlameCommand command = new BlameCommand(db);
+ command.setFollowFileRenames(true);
+ command.setFilePath("file2.txt");
+ BlameResult lines = command.call();
- BlameCommand command = new BlameCommand(db);
- command.setFollowFileRenames(true);
- command.setFilePath("file2.txt");
- BlameResult lines = command.call();
+ assertEquals(commit1, lines.getSourceCommit(0));
+ assertEquals(0, lines.getSourceLine(0));
+ assertEquals("file.txt", lines.getSourcePath(0));
- assertEquals(commit1, lines.getSourceCommit(0));
- assertEquals(0, lines.getSourceLine(0));
- assertEquals("file.txt", lines.getSourcePath(0));
-
- assertEquals(commit3, lines.getSourceCommit(1));
- assertEquals(1, lines.getSourceLine(1));
- assertEquals("file1.txt", lines.getSourcePath(1));
+ assertEquals(commit3, lines.getSourceCommit(1));
+ assertEquals(1, lines.getSourceLine(1));
+ assertEquals("file1.txt", lines.getSourcePath(1));
+ }
}
@Test
public void testDeleteTrailingLines() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ String[] content1 = new String[] { "a", "b", "c", "d" };
+ String[] content2 = new String[] { "a", "b" };
- String[] content1 = new String[] { "a", "b", "c", "d" };
- String[] content2 = new String[] { "a", "b" };
+ writeTrashFile("file.txt", join(content2));
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit1 = git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", join(content2));
- git.add().addFilepattern("file.txt").call();
- RevCommit commit1 = git.commit().setMessage("create file").call();
+ writeTrashFile("file.txt", join(content1));
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("edit file").call();
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("edit file").call();
+ writeTrashFile("file.txt", join(content2));
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("edit file").call();
- writeTrashFile("file.txt", join(content2));
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("edit file").call();
+ BlameCommand command = new BlameCommand(db);
- BlameCommand command = new BlameCommand(db);
+ command.setFilePath("file.txt");
+ BlameResult lines = command.call();
+ assertEquals(content2.length, lines.getResultContents().size());
- command.setFilePath("file.txt");
- BlameResult lines = command.call();
- assertEquals(content2.length, lines.getResultContents().size());
+ assertEquals(commit1, lines.getSourceCommit(0));
+ assertEquals(commit1, lines.getSourceCommit(1));
- assertEquals(commit1, lines.getSourceCommit(0));
- assertEquals(commit1, lines.getSourceCommit(1));
-
- assertEquals(0, lines.getSourceLine(0));
- assertEquals(1, lines.getSourceLine(1));
+ assertEquals(0, lines.getSourceLine(0));
+ assertEquals(1, lines.getSourceLine(1));
+ }
}
@Test
public void testDeleteMiddleLines() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ String[] content1 = new String[] { "a", "b", "c", "d", "e" };
+ String[] content2 = new String[] { "a", "c", "e" };
- String[] content1 = new String[] { "a", "b", "c", "d", "e" };
- String[] content2 = new String[] { "a", "c", "e" };
+ writeTrashFile("file.txt", join(content2));
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit1 = git.commit().setMessage("edit file").call();
- writeTrashFile("file.txt", join(content2));
- git.add().addFilepattern("file.txt").call();
- RevCommit commit1 = git.commit().setMessage("edit file").call();
+ writeTrashFile("file.txt", join(content1));
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("edit file").call();
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("edit file").call();
+ writeTrashFile("file.txt", join(content2));
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("edit file").call();
- writeTrashFile("file.txt", join(content2));
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("edit file").call();
+ BlameCommand command = new BlameCommand(db);
- BlameCommand command = new BlameCommand(db);
+ command.setFilePath("file.txt");
+ BlameResult lines = command.call();
+ assertEquals(content2.length, lines.getResultContents().size());
- command.setFilePath("file.txt");
- BlameResult lines = command.call();
- assertEquals(content2.length, lines.getResultContents().size());
+ assertEquals(commit1, lines.getSourceCommit(0));
+ assertEquals(0, lines.getSourceLine(0));
- assertEquals(commit1, lines.getSourceCommit(0));
- assertEquals(0, lines.getSourceLine(0));
+ assertEquals(commit1, lines.getSourceCommit(1));
+ assertEquals(1, lines.getSourceLine(1));
- assertEquals(commit1, lines.getSourceCommit(1));
- assertEquals(1, lines.getSourceLine(1));
-
- assertEquals(commit1, lines.getSourceCommit(2));
- assertEquals(2, lines.getSourceLine(2));
+ assertEquals(commit1, lines.getSourceCommit(2));
+ assertEquals(2, lines.getSourceLine(2));
+ }
}
@Test
public void testEditAllLines() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ String[] content1 = new String[] { "a", "1" };
+ String[] content2 = new String[] { "b", "2" };
- String[] content1 = new String[] { "a", "1" };
- String[] content2 = new String[] { "b", "2" };
+ writeTrashFile("file.txt", join(content1));
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("edit file").call();
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("edit file").call();
+ writeTrashFile("file.txt", join(content2));
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit2 = git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", join(content2));
- git.add().addFilepattern("file.txt").call();
- RevCommit commit2 = git.commit().setMessage("create file").call();
+ BlameCommand command = new BlameCommand(db);
- BlameCommand command = new BlameCommand(db);
-
- command.setFilePath("file.txt");
- BlameResult lines = command.call();
- assertEquals(content2.length, lines.getResultContents().size());
- assertEquals(commit2, lines.getSourceCommit(0));
- assertEquals(commit2, lines.getSourceCommit(1));
+ command.setFilePath("file.txt");
+ BlameResult lines = command.call();
+ assertEquals(content2.length, lines.getResultContents().size());
+ assertEquals(commit2, lines.getSourceCommit(0));
+ assertEquals(commit2, lines.getSourceCommit(1));
+ }
}
@Test
public void testMiddleClearAllLines() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ String[] content1 = new String[] { "a", "b", "c" };
- String[] content1 = new String[] { "a", "b", "c" };
+ writeTrashFile("file.txt", join(content1));
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("edit file").call();
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("edit file").call();
+ writeTrashFile("file.txt", "");
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", "");
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("create file").call();
+ writeTrashFile("file.txt", join(content1));
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit3 = git.commit().setMessage("edit file").call();
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
- RevCommit commit3 = git.commit().setMessage("edit file").call();
+ BlameCommand command = new BlameCommand(db);
- BlameCommand command = new BlameCommand(db);
-
- command.setFilePath("file.txt");
- BlameResult lines = command.call();
- assertEquals(content1.length, lines.getResultContents().size());
- assertEquals(commit3, lines.getSourceCommit(0));
- assertEquals(commit3, lines.getSourceCommit(1));
- assertEquals(commit3, lines.getSourceCommit(2));
+ command.setFilePath("file.txt");
+ BlameResult lines = command.call();
+ assertEquals(content1.length, lines.getResultContents().size());
+ assertEquals(commit3, lines.getSourceCommit(0));
+ assertEquals(commit3, lines.getSourceCommit(1));
+ assertEquals(commit3, lines.getSourceCommit(2));
+ }
}
@Test
@@ -361,130 +361,132 @@
private void testCoreAutoCrlf(AutoCRLF modeForCommitting,
AutoCRLF modeForReset) throws Exception {
- Git git = new Git(db);
- FileBasedConfig config = db.getConfig();
- config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_AUTOCRLF, modeForCommitting);
- config.save();
+ try (Git git = new Git(db)) {
+ FileBasedConfig config = db.getConfig();
+ config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF, modeForCommitting);
+ config.save();
- String joinedCrlf = "a\r\nb\r\nc\r\n";
- File trashFile = writeTrashFile("file.txt", joinedCrlf);
- git.add().addFilepattern("file.txt").call();
- RevCommit commit = git.commit().setMessage("create file").call();
+ String joinedCrlf = "a\r\nb\r\nc\r\n";
+ File trashFile = writeTrashFile("file.txt", joinedCrlf);
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit = git.commit().setMessage("create file").call();
- // re-create file from the repo
- trashFile.delete();
- config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_AUTOCRLF, modeForReset);
- config.save();
- git.reset().setMode(ResetType.HARD).call();
+ // re-create file from the repo
+ trashFile.delete();
+ config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF, modeForReset);
+ config.save();
+ git.reset().setMode(ResetType.HARD).call();
- BlameCommand command = new BlameCommand(db);
- command.setFilePath("file.txt");
- BlameResult lines = command.call();
+ BlameCommand command = new BlameCommand(db);
+ command.setFilePath("file.txt");
+ BlameResult lines = command.call();
- assertEquals(3, lines.getResultContents().size());
- assertEquals(commit, lines.getSourceCommit(0));
- assertEquals(commit, lines.getSourceCommit(1));
- assertEquals(commit, lines.getSourceCommit(2));
+ assertEquals(3, lines.getResultContents().size());
+ assertEquals(commit, lines.getSourceCommit(0));
+ assertEquals(commit, lines.getSourceCommit(1));
+ assertEquals(commit, lines.getSourceCommit(2));
+ }
}
@Test
public void testConflictingMerge1() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ RevCommit base = commitFile("file.txt", join("0", "1", "2", "3", "4"),
+ "master");
- RevCommit base = commitFile("file.txt", join("0", "1", "2", "3", "4"),
- "master");
+ git.checkout().setName("side").setCreateBranch(true)
+ .setStartPoint(base).call();
+ RevCommit side = commitFile("file.txt",
+ join("0", "1 side", "2", "3 on side", "4"), "side");
- git.checkout().setName("side").setCreateBranch(true)
- .setStartPoint(base).call();
- RevCommit side = commitFile("file.txt",
- join("0", "1 side", "2", "3 on side", "4"), "side");
+ commitFile("file.txt", join("0", "1", "2"), "master");
- commitFile("file.txt", join("0", "1", "2"), "master");
+ checkoutBranch("refs/heads/master");
+ git.merge().include(side).call();
- checkoutBranch("refs/heads/master");
- git.merge().include(side).call();
+ // The merge results in a conflict, which we resolve using mostly the
+ // side branch contents. Especially the "4" survives.
+ RevCommit merge = commitFile("file.txt",
+ join("0", "1 side", "2", "3 resolved", "4"), "master");
- // The merge results in a conflict, which we resolve using mostly the
- // side branch contents. Especially the "4" survives.
- RevCommit merge = commitFile("file.txt",
- join("0", "1 side", "2", "3 resolved", "4"), "master");
+ BlameCommand command = new BlameCommand(db);
+ command.setFilePath("file.txt");
+ BlameResult lines = command.call();
- BlameCommand command = new BlameCommand(db);
- command.setFilePath("file.txt");
- BlameResult lines = command.call();
-
- assertEquals(5, lines.getResultContents().size());
- assertEquals(base, lines.getSourceCommit(0));
- assertEquals(side, lines.getSourceCommit(1));
- assertEquals(base, lines.getSourceCommit(2));
- assertEquals(merge, lines.getSourceCommit(3));
- assertEquals(base, lines.getSourceCommit(4));
+ assertEquals(5, lines.getResultContents().size());
+ assertEquals(base, lines.getSourceCommit(0));
+ assertEquals(side, lines.getSourceCommit(1));
+ assertEquals(base, lines.getSourceCommit(2));
+ assertEquals(merge, lines.getSourceCommit(3));
+ assertEquals(base, lines.getSourceCommit(4));
+ }
}
// this test inverts the order of the master and side commit and is
// otherwise identical to testConflictingMerge1
@Test
public void testConflictingMerge2() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ RevCommit base = commitFile("file.txt", join("0", "1", "2", "3", "4"),
+ "master");
- RevCommit base = commitFile("file.txt", join("0", "1", "2", "3", "4"),
- "master");
+ commitFile("file.txt", join("0", "1", "2"), "master");
- commitFile("file.txt", join("0", "1", "2"), "master");
+ git.checkout().setName("side").setCreateBranch(true)
+ .setStartPoint(base).call();
+ RevCommit side = commitFile("file.txt",
+ join("0", "1 side", "2", "3 on side", "4"), "side");
- git.checkout().setName("side").setCreateBranch(true)
- .setStartPoint(base).call();
- RevCommit side = commitFile("file.txt",
- join("0", "1 side", "2", "3 on side", "4"), "side");
+ checkoutBranch("refs/heads/master");
+ git.merge().include(side).call();
- checkoutBranch("refs/heads/master");
- git.merge().include(side).call();
+ // The merge results in a conflict, which we resolve using mostly the
+ // side branch contents. Especially the "4" survives.
+ RevCommit merge = commitFile("file.txt",
+ join("0", "1 side", "2", "3 resolved", "4"), "master");
- // The merge results in a conflict, which we resolve using mostly the
- // side branch contents. Especially the "4" survives.
- RevCommit merge = commitFile("file.txt",
- join("0", "1 side", "2", "3 resolved", "4"), "master");
+ BlameCommand command = new BlameCommand(db);
+ command.setFilePath("file.txt");
+ BlameResult lines = command.call();
- BlameCommand command = new BlameCommand(db);
- command.setFilePath("file.txt");
- BlameResult lines = command.call();
-
- assertEquals(5, lines.getResultContents().size());
- assertEquals(base, lines.getSourceCommit(0));
- assertEquals(side, lines.getSourceCommit(1));
- assertEquals(base, lines.getSourceCommit(2));
- assertEquals(merge, lines.getSourceCommit(3));
- assertEquals(base, lines.getSourceCommit(4));
+ assertEquals(5, lines.getResultContents().size());
+ assertEquals(base, lines.getSourceCommit(0));
+ assertEquals(side, lines.getSourceCommit(1));
+ assertEquals(base, lines.getSourceCommit(2));
+ assertEquals(merge, lines.getSourceCommit(3));
+ assertEquals(base, lines.getSourceCommit(4));
+ }
}
@Test
public void testWhitespaceMerge() throws Exception {
- Git git = new Git(db);
- RevCommit base = commitFile("file.txt", join("0", "1", "2"), "master");
- RevCommit side = commitFile("file.txt", join("0", "1", " 2 side "),
- "side");
+ try (Git git = new Git(db)) {
+ RevCommit base = commitFile("file.txt", join("0", "1", "2"), "master");
+ RevCommit side = commitFile("file.txt", join("0", "1", " 2 side "),
+ "side");
- checkoutBranch("refs/heads/master");
- git.merge().setFastForward(FastForwardMode.NO_FF).include(side).call();
+ checkoutBranch("refs/heads/master");
+ git.merge().setFastForward(FastForwardMode.NO_FF).include(side).call();
- // change whitespace, so the merge content is not identical to side, but
- // is the same when ignoring whitespace
- writeTrashFile("file.txt", join("0", "1", "2 side"));
- RevCommit merge = git.commit().setAll(true).setMessage("merge")
- .setAmend(true)
- .call();
+ // change whitespace, so the merge content is not identical to side, but
+ // is the same when ignoring whitespace
+ writeTrashFile("file.txt", join("0", "1", "2 side"));
+ RevCommit merge = git.commit().setAll(true).setMessage("merge")
+ .setAmend(true)
+ .call();
- BlameCommand command = new BlameCommand(db);
- command.setFilePath("file.txt")
- .setTextComparator(RawTextComparator.WS_IGNORE_ALL)
- .setStartCommit(merge.getId());
- BlameResult lines = command.call();
+ BlameCommand command = new BlameCommand(db);
+ command.setFilePath("file.txt")
+ .setTextComparator(RawTextComparator.WS_IGNORE_ALL)
+ .setStartCommit(merge.getId());
+ BlameResult lines = command.call();
- assertEquals(3, lines.getResultContents().size());
- assertEquals(base, lines.getSourceCommit(0));
- assertEquals(base, lines.getSourceCommit(1));
- assertEquals(side, lines.getSourceCommit(2));
+ assertEquals(3, lines.getResultContents().size());
+ assertEquals(base, lines.getSourceCommit(0));
+ assertEquals(base, lines.getSourceCommit(1));
+ assertEquals(side, lines.getSourceCommit(2));
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java
index 910a645..2fe40b9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java
@@ -104,37 +104,38 @@
private Git setUpRepoWithRemote() throws Exception {
Repository remoteRepository = createWorkRepository();
- Git remoteGit = new Git(remoteRepository);
- // commit something
- writeTrashFile("Test.txt", "Hello world");
- remoteGit.add().addFilepattern("Test.txt").call();
- initialCommit = remoteGit.commit().setMessage("Initial commit").call();
- writeTrashFile("Test.txt", "Some change");
- remoteGit.add().addFilepattern("Test.txt").call();
- secondCommit = remoteGit.commit().setMessage("Second commit").call();
- // create a master branch
- RefUpdate rup = remoteRepository.updateRef("refs/heads/master");
- rup.setNewObjectId(initialCommit.getId());
- rup.forceUpdate();
+ try (Git remoteGit = new Git(remoteRepository)) {
+ // commit something
+ writeTrashFile("Test.txt", "Hello world");
+ remoteGit.add().addFilepattern("Test.txt").call();
+ initialCommit = remoteGit.commit().setMessage("Initial commit").call();
+ writeTrashFile("Test.txt", "Some change");
+ remoteGit.add().addFilepattern("Test.txt").call();
+ secondCommit = remoteGit.commit().setMessage("Second commit").call();
+ // create a master branch
+ RefUpdate rup = remoteRepository.updateRef("refs/heads/master");
+ rup.setNewObjectId(initialCommit.getId());
+ rup.forceUpdate();
- Repository localRepository = createWorkRepository();
- Git localGit = new Git(localRepository);
- StoredConfig config = localRepository.getConfig();
- RemoteConfig rc = new RemoteConfig(config, "origin");
- rc.addURI(new URIish(remoteRepository.getDirectory().getAbsolutePath()));
- rc.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
- rc.update(config);
- config.save();
- FetchResult res = localGit.fetch().setRemote("origin").call();
- assertFalse(res.getTrackingRefUpdates().isEmpty());
- rup = localRepository.updateRef("refs/heads/master");
- rup.setNewObjectId(initialCommit.getId());
- rup.forceUpdate();
- rup = localRepository.updateRef(Constants.HEAD);
- rup.link("refs/heads/master");
- rup.setNewObjectId(initialCommit.getId());
- rup.update();
- return localGit;
+ Repository localRepository = createWorkRepository();
+ Git localGit = new Git(localRepository);
+ StoredConfig config = localRepository.getConfig();
+ RemoteConfig rc = new RemoteConfig(config, "origin");
+ rc.addURI(new URIish(remoteRepository.getDirectory().getAbsolutePath()));
+ rc.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
+ rc.update(config);
+ config.save();
+ FetchResult res = localGit.fetch().setRemote("origin").call();
+ assertFalse(res.getTrackingRefUpdates().isEmpty());
+ rup = localRepository.updateRef("refs/heads/master");
+ rup.setNewObjectId(initialCommit.getId());
+ rup.forceUpdate();
+ rup = localRepository.updateRef(Constants.HEAD);
+ rup.link("refs/heads/master");
+ rup.setNewObjectId(initialCommit.getId());
+ rup.update();
+ return localGit;
+ }
}
@Test
@@ -192,8 +193,7 @@
@Test
public void testListAllBranchesShouldNotDie() throws Exception {
- Git git = setUpRepoWithRemote();
- git.branchList().setListMode(ListMode.ALL).call();
+ setUpRepoWithRemote().branchList().setListMode(ListMode.ALL).call();
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
index f7a50df..362d7ac 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
@@ -43,6 +43,8 @@
*/
package org.eclipse.jgit.api;
+import static org.eclipse.jgit.lib.Constants.MASTER;
+import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
@@ -70,12 +72,14 @@
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.Sets;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.storage.file.FileBasedConfig;
@@ -84,6 +88,7 @@
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.FileUtils;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
public class CheckoutCommandTest extends RepositoryTestCase {
@@ -134,7 +139,7 @@
@Test
public void testCreateBranchOnCheckout() throws Exception {
git.checkout().setCreateBranch(true).setName("test2").call();
- assertNotNull(db.getRef("test2"));
+ assertNotNull(db.exactRef("refs/heads/test2"));
}
@Test
@@ -237,8 +242,8 @@
.setStartPoint("origin/test")
.setUpstreamMode(SetupUpstreamMode.TRACK).call();
- assertEquals("refs/heads/test", db2.getRef(Constants.HEAD).getTarget()
- .getName());
+ assertEquals("refs/heads/test",
+ db2.exactRef(Constants.HEAD).getTarget().getName());
StoredConfig config = db2.getConfig();
assertEquals("origin", config.getString(
ConfigConstants.CONFIG_BRANCH_SECTION, "test",
@@ -345,7 +350,7 @@
CheckoutCommand co = git.checkout();
co.setName("master").call();
- String commitId = db.getRef(Constants.MASTER).getObjectId().name();
+ String commitId = db.exactRef(R_HEADS + MASTER).getObjectId().name();
co = git.checkout();
co.setName(commitId).call();
@@ -412,20 +417,20 @@
InvalidRemoteException, TransportException {
// create second repository
Repository db2 = createWorkRepository();
- Git git2 = new Git(db2);
+ try (Git git2 = new Git(db2)) {
+ // setup the second repository to fetch from the first repository
+ final StoredConfig config = db2.getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "origin");
+ URIish uri = new URIish(db.getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.update(config);
+ config.save();
- // setup the second repository to fetch from the first repository
- final StoredConfig config = db2.getConfig();
- RemoteConfig remoteConfig = new RemoteConfig(config, "origin");
- URIish uri = new URIish(db.getDirectory().toURI().toURL());
- remoteConfig.addURI(uri);
- remoteConfig.update(config);
- config.save();
-
- // fetch from first repository
- RefSpec spec = new RefSpec("+refs/heads/*:refs/remotes/origin/*");
- git2.fetch().setRemote("origin").setRefSpecs(spec).call();
- return db2;
+ // fetch from first repository
+ RefSpec spec = new RefSpec("+refs/heads/*:refs/remotes/origin/*");
+ git2.fetch().setRemote("origin").setRefSpecs(spec).call();
+ return db2;
+ }
}
private CheckoutCommand newOrphanBranchCommand() {
@@ -443,7 +448,7 @@
}
private void assertHeadDetached() throws IOException {
- Ref head = db.getRef(Constants.HEAD);
+ Ref head = db.exactRef(Constants.HEAD);
assertFalse(head.isSymbolic());
assertSame(head, head.getTarget());
}
@@ -554,4 +559,126 @@
}
org.junit.Assume.assumeTrue(foundUnsmudged);
}
+
+ @Test
+ public void testSmudgeFilter_modifyExisting() throws IOException, GitAPIException {
+ File script = writeTempFile("sed s/o/e/g");
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "tstFilter", "smudge",
+ "sh " + slashify(script.getPath()));
+ config.save();
+
+ writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+ git.add().addFilepattern(".gitattributes").call();
+ git.commit().setMessage("add filter").call();
+
+ writeTrashFile("src/a.tmp", "x");
+ // Caution: we need a trailing '\n' since sed on mac always appends
+ // linefeeds if missing
+ writeTrashFile("src/a.txt", "x\n");
+ git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
+ .call();
+ RevCommit content1 = git.commit().setMessage("add content").call();
+
+ writeTrashFile("src/a.tmp", "foo");
+ writeTrashFile("src/a.txt", "foo\n");
+ git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
+ .call();
+ RevCommit content2 = git.commit().setMessage("changed content").call();
+
+ git.checkout().setName(content1.getName()).call();
+ git.checkout().setName(content2.getName()).call();
+
+ assertEquals(
+ "[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
+ indexState(CONTENT));
+ assertEquals(Sets.of("src/a.txt"), git.status().call().getModified());
+ assertEquals("foo", read("src/a.tmp"));
+ assertEquals("fee\n", read("src/a.txt"));
+ }
+
+ @Test
+ public void testSmudgeFilter_createNew()
+ throws IOException, GitAPIException {
+ File script = writeTempFile("sed s/o/e/g");
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "tstFilter", "smudge",
+ "sh " + slashify(script.getPath()));
+ config.save();
+
+ writeTrashFile("foo", "foo");
+ git.add().addFilepattern("foo").call();
+ RevCommit initial = git.commit().setMessage("initial").call();
+
+ writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+ git.add().addFilepattern(".gitattributes").call();
+ git.commit().setMessage("add filter").call();
+
+ writeTrashFile("src/a.tmp", "foo");
+ // Caution: we need a trailing '\n' since sed on mac always appends
+ // linefeeds if missing
+ writeTrashFile("src/a.txt", "foo\n");
+ git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
+ .call();
+ RevCommit content = git.commit().setMessage("added content").call();
+
+ git.checkout().setName(initial.getName()).call();
+ git.checkout().setName(content.getName()).call();
+
+ assertEquals(
+ "[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
+ indexState(CONTENT));
+ assertEquals("foo", read("src/a.tmp"));
+ assertEquals("fee\n", read("src/a.txt"));
+ }
+
+ @Test
+ @Ignore
+ public void testSmudgeAndClean() throws IOException, GitAPIException {
+ // @TODO: fix this test
+ File clean_filter = writeTempFile("sed s/V1/@version/g -");
+ File smudge_filter = writeTempFile("sed s/@version/V1/g -");
+
+ try (Git git2 = new Git(db)) {
+ StoredConfig config = git.getRepository().getConfig();
+ config.setString("filter", "tstFilter", "smudge",
+ "sh " + slashify(smudge_filter.getPath()));
+ config.setString("filter", "tstFilter", "clean",
+ "sh " + slashify(clean_filter.getPath()));
+ config.save();
+ writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
+ git2.add().addFilepattern(".gitattributes").call();
+ git2.commit().setMessage("add attributes").call();
+
+ writeTrashFile("filterTest.txt", "hello world, V1");
+ git2.add().addFilepattern("filterTest.txt").call();
+ git2.commit().setMessage("add filterText.txt").call();
+ assertEquals(
+ "[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some other change][filterTest.txt, mode:100644, content:hello world, @version]",
+ indexState(CONTENT));
+
+ git2.checkout().setCreateBranch(true).setName("test2").call();
+ writeTrashFile("filterTest.txt", "bon giorno world, V1");
+ git2.add().addFilepattern("filterTest.txt").call();
+ git2.commit().setMessage("modified filterText.txt").call();
+
+ assertTrue(git2.status().call().isClean());
+ assertEquals(
+ "[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some other change][filterTest.txt, mode:100644, content:bon giorno world, @version]",
+ indexState(CONTENT));
+
+ git2.checkout().setName("refs/heads/test").call();
+ assertTrue(git2.status().call().isClean());
+ assertEquals(
+ "[.gitattributes, mode:100644, content:*.txt filter=tstFilter][Test.txt, mode:100644, content:Some other change][filterTest.txt, mode:100644, content:hello world, @version]",
+ indexState(CONTENT));
+ assertEquals("hello world, V1", read("filterTest.txt"));
+ }
+ }
+
+ private File writeTempFile(String body) throws IOException {
+ File f = File.createTempFile("AddCommandTest_", "");
+ JGitTestUtil.write(f, body);
+ return f;
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java
index a999337..354b9c6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java
@@ -88,136 +88,139 @@
private void doTestCherryPick(boolean noCommit) throws IOException,
JGitInternalException,
GitAPIException {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "first line\nsec. line\nthird line\n");
+ git.add().addFilepattern("a").call();
+ RevCommit firstCommit = git.commit().setMessage("create a").call();
- writeTrashFile("a", "first line\nsec. line\nthird line\n");
- git.add().addFilepattern("a").call();
- RevCommit firstCommit = git.commit().setMessage("create a").call();
+ writeTrashFile("b", "content\n");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("create b").call();
- writeTrashFile("b", "content\n");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("create b").call();
+ writeTrashFile("a", "first line\nsec. line\nthird line\nfourth line\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("enlarged a").call();
- writeTrashFile("a", "first line\nsec. line\nthird line\nfourth line\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("enlarged a").call();
+ writeTrashFile("a",
+ "first line\nsecond line\nthird line\nfourth line\n");
+ git.add().addFilepattern("a").call();
+ RevCommit fixingA = git.commit().setMessage("fixed a").call();
- writeTrashFile("a",
- "first line\nsecond line\nthird line\nfourth line\n");
- git.add().addFilepattern("a").call();
- RevCommit fixingA = git.commit().setMessage("fixed a").call();
+ git.branchCreate().setName("side").setStartPoint(firstCommit).call();
+ checkoutBranch("refs/heads/side");
- git.branchCreate().setName("side").setStartPoint(firstCommit).call();
- checkoutBranch("refs/heads/side");
+ writeTrashFile("a", "first line\nsec. line\nthird line\nfeature++\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("enhanced a").call();
- writeTrashFile("a", "first line\nsec. line\nthird line\nfeature++\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("enhanced a").call();
+ CherryPickResult pickResult = git.cherryPick().include(fixingA)
+ .setNoCommit(noCommit).call();
- CherryPickResult pickResult = git.cherryPick().include(fixingA)
- .setNoCommit(noCommit).call();
-
- assertEquals(CherryPickStatus.OK, pickResult.getStatus());
- assertFalse(new File(db.getWorkTree(), "b").exists());
- checkFile(new File(db.getWorkTree(), "a"),
- "first line\nsecond line\nthird line\nfeature++\n");
- Iterator<RevCommit> history = git.log().call().iterator();
- if (!noCommit)
- assertEquals("fixed a", history.next().getFullMessage());
- assertEquals("enhanced a", history.next().getFullMessage());
- assertEquals("create a", history.next().getFullMessage());
- assertFalse(history.hasNext());
+ assertEquals(CherryPickStatus.OK, pickResult.getStatus());
+ assertFalse(new File(db.getWorkTree(), "b").exists());
+ checkFile(new File(db.getWorkTree(), "a"),
+ "first line\nsecond line\nthird line\nfeature++\n");
+ Iterator<RevCommit> history = git.log().call().iterator();
+ if (!noCommit)
+ assertEquals("fixed a", history.next().getFullMessage());
+ assertEquals("enhanced a", history.next().getFullMessage());
+ assertEquals("create a", history.next().getFullMessage());
+ assertFalse(history.hasNext());
+ }
}
@Test
public void testSequentialCherryPick() throws IOException, JGitInternalException,
GitAPIException {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "first line\nsec. line\nthird line\n");
+ git.add().addFilepattern("a").call();
+ RevCommit firstCommit = git.commit().setMessage("create a").call();
- writeTrashFile("a", "first line\nsec. line\nthird line\n");
- git.add().addFilepattern("a").call();
- RevCommit firstCommit = git.commit().setMessage("create a").call();
+ writeTrashFile("a", "first line\nsec. line\nthird line\nfourth line\n");
+ git.add().addFilepattern("a").call();
+ RevCommit enlargingA = git.commit().setMessage("enlarged a").call();
- writeTrashFile("a", "first line\nsec. line\nthird line\nfourth line\n");
- git.add().addFilepattern("a").call();
- RevCommit enlargingA = git.commit().setMessage("enlarged a").call();
+ writeTrashFile("a",
+ "first line\nsecond line\nthird line\nfourth line\n");
+ git.add().addFilepattern("a").call();
+ RevCommit fixingA = git.commit().setMessage("fixed a").call();
- writeTrashFile("a",
- "first line\nsecond line\nthird line\nfourth line\n");
- git.add().addFilepattern("a").call();
- RevCommit fixingA = git.commit().setMessage("fixed a").call();
+ git.branchCreate().setName("side").setStartPoint(firstCommit).call();
+ checkoutBranch("refs/heads/side");
- git.branchCreate().setName("side").setStartPoint(firstCommit).call();
- checkoutBranch("refs/heads/side");
+ writeTrashFile("b", "nothing to do with a");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("create b").call();
- writeTrashFile("b", "nothing to do with a");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("create b").call();
+ CherryPickResult result = git.cherryPick().include(enlargingA).include(fixingA).call();
+ assertEquals(CherryPickResult.CherryPickStatus.OK, result.getStatus());
- CherryPickResult result = git.cherryPick().include(enlargingA).include(fixingA).call();
- assertEquals(CherryPickResult.CherryPickStatus.OK, result.getStatus());
-
- Iterator<RevCommit> history = git.log().call().iterator();
- assertEquals("fixed a", history.next().getFullMessage());
- assertEquals("enlarged a", history.next().getFullMessage());
- assertEquals("create b", history.next().getFullMessage());
- assertEquals("create a", history.next().getFullMessage());
- assertFalse(history.hasNext());
+ Iterator<RevCommit> history = git.log().call().iterator();
+ assertEquals("fixed a", history.next().getFullMessage());
+ assertEquals("enlarged a", history.next().getFullMessage());
+ assertEquals("create b", history.next().getFullMessage());
+ assertEquals("create a", history.next().getFullMessage());
+ assertFalse(history.hasNext());
+ }
}
@Test
public void testCherryPickDirtyIndex() throws Exception {
- Git git = new Git(db);
- RevCommit sideCommit = prepareCherryPick(git);
+ try (Git git = new Git(db)) {
+ RevCommit sideCommit = prepareCherryPick(git);
- // modify and add file a
- writeTrashFile("a", "a(modified)");
- git.add().addFilepattern("a").call();
- // do not commit
+ // modify and add file a
+ writeTrashFile("a", "a(modified)");
+ git.add().addFilepattern("a").call();
+ // do not commit
- doCherryPickAndCheckResult(git, sideCommit,
- MergeFailureReason.DIRTY_INDEX);
+ doCherryPickAndCheckResult(git, sideCommit,
+ MergeFailureReason.DIRTY_INDEX);
+ }
}
@Test
public void testCherryPickDirtyWorktree() throws Exception {
- Git git = new Git(db);
- RevCommit sideCommit = prepareCherryPick(git);
+ try (Git git = new Git(db)) {
+ RevCommit sideCommit = prepareCherryPick(git);
- // modify file a
- writeTrashFile("a", "a(modified)");
- // do not add and commit
+ // modify file a
+ writeTrashFile("a", "a(modified)");
+ // do not add and commit
- doCherryPickAndCheckResult(git, sideCommit,
- MergeFailureReason.DIRTY_WORKTREE);
+ doCherryPickAndCheckResult(git, sideCommit,
+ MergeFailureReason.DIRTY_WORKTREE);
+ }
}
@Test
public void testCherryPickConflictResolution() throws Exception {
- Git git = new Git(db);
- RevCommit sideCommit = prepareCherryPick(git);
+ try (Git git = new Git(db)) {
+ RevCommit sideCommit = prepareCherryPick(git);
- CherryPickResult result = git.cherryPick().include(sideCommit.getId())
- .call();
+ CherryPickResult result = git.cherryPick().include(sideCommit.getId())
+ .call();
- assertEquals(CherryPickStatus.CONFLICTING, result.getStatus());
- assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists());
- assertEquals("side\n\nConflicts:\n\ta\n", db.readMergeCommitMsg());
- assertTrue(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD)
- .exists());
- assertEquals(sideCommit.getId(), db.readCherryPickHead());
- assertEquals(RepositoryState.CHERRY_PICKING, db.getRepositoryState());
+ assertEquals(CherryPickStatus.CONFLICTING, result.getStatus());
+ assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists());
+ assertEquals("side\n\nConflicts:\n\ta\n", db.readMergeCommitMsg());
+ assertTrue(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD)
+ .exists());
+ assertEquals(sideCommit.getId(), db.readCherryPickHead());
+ assertEquals(RepositoryState.CHERRY_PICKING, db.getRepositoryState());
- // Resolve
- writeTrashFile("a", "a");
- git.add().addFilepattern("a").call();
+ // Resolve
+ writeTrashFile("a", "a");
+ git.add().addFilepattern("a").call();
- assertEquals(RepositoryState.CHERRY_PICKING_RESOLVED,
- db.getRepositoryState());
+ assertEquals(RepositoryState.CHERRY_PICKING_RESOLVED,
+ db.getRepositoryState());
- git.commit().setOnly("a").setMessage("resolve").call();
+ git.commit().setOnly("a").setMessage("resolve").call();
- assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ }
}
@Test
@@ -251,85 +254,88 @@
@Test
public void testCherryPickConflictReset() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ RevCommit sideCommit = prepareCherryPick(git);
- RevCommit sideCommit = prepareCherryPick(git);
+ CherryPickResult result = git.cherryPick().include(sideCommit.getId())
+ .call();
- CherryPickResult result = git.cherryPick().include(sideCommit.getId())
- .call();
+ assertEquals(CherryPickStatus.CONFLICTING, result.getStatus());
+ assertEquals(RepositoryState.CHERRY_PICKING, db.getRepositoryState());
+ assertTrue(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD)
+ .exists());
- assertEquals(CherryPickStatus.CONFLICTING, result.getStatus());
- assertEquals(RepositoryState.CHERRY_PICKING, db.getRepositoryState());
- assertTrue(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD)
- .exists());
+ git.reset().setMode(ResetType.MIXED).setRef("HEAD").call();
- git.reset().setMode(ResetType.MIXED).setRef("HEAD").call();
-
- assertEquals(RepositoryState.SAFE, db.getRepositoryState());
- assertFalse(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD)
- .exists());
+ assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ assertFalse(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD)
+ .exists());
+ }
}
@Test
public void testCherryPickOverExecutableChangeOnNonExectuableFileSystem()
throws Exception {
- Git git = new Git(db);
- File file = writeTrashFile("test.txt", "a");
- assertNotNull(git.add().addFilepattern("test.txt").call());
- assertNotNull(git.commit().setMessage("commit1").call());
+ try (Git git = new Git(db)) {
+ File file = writeTrashFile("test.txt", "a");
+ assertNotNull(git.add().addFilepattern("test.txt").call());
+ assertNotNull(git.commit().setMessage("commit1").call());
- assertNotNull(git.checkout().setCreateBranch(true).setName("a").call());
+ assertNotNull(git.checkout().setCreateBranch(true).setName("a").call());
- writeTrashFile("test.txt", "b");
- assertNotNull(git.add().addFilepattern("test.txt").call());
- RevCommit commit2 = git.commit().setMessage("commit2").call();
- assertNotNull(commit2);
+ writeTrashFile("test.txt", "b");
+ assertNotNull(git.add().addFilepattern("test.txt").call());
+ RevCommit commit2 = git.commit().setMessage("commit2").call();
+ assertNotNull(commit2);
- assertNotNull(git.checkout().setName(Constants.MASTER).call());
+ assertNotNull(git.checkout().setName(Constants.MASTER).call());
- DirCache cache = db.lockDirCache();
- cache.getEntry("test.txt").setFileMode(FileMode.EXECUTABLE_FILE);
- cache.write();
- assertTrue(cache.commit());
- cache.unlock();
+ DirCache cache = db.lockDirCache();
+ cache.getEntry("test.txt").setFileMode(FileMode.EXECUTABLE_FILE);
+ cache.write();
+ assertTrue(cache.commit());
+ cache.unlock();
- assertNotNull(git.commit().setMessage("commit3").call());
+ assertNotNull(git.commit().setMessage("commit3").call());
- db.getFS().setExecute(file, false);
- git.getRepository()
- .getConfig()
- .setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_FILEMODE, false);
+ db.getFS().setExecute(file, false);
+ git.getRepository()
+ .getConfig()
+ .setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_FILEMODE, false);
- CherryPickResult result = git.cherryPick().include(commit2).call();
- assertNotNull(result);
- assertEquals(CherryPickStatus.OK, result.getStatus());
+ CherryPickResult result = git.cherryPick().include(commit2).call();
+ assertNotNull(result);
+ assertEquals(CherryPickStatus.OK, result.getStatus());
+ }
}
@Test
public void testCherryPickConflictMarkers() throws Exception {
- Git git = new Git(db);
- RevCommit sideCommit = prepareCherryPick(git);
+ try (Git git = new Git(db)) {
+ RevCommit sideCommit = prepareCherryPick(git);
- CherryPickResult result = git.cherryPick().include(sideCommit.getId())
- .call();
- assertEquals(CherryPickStatus.CONFLICTING, result.getStatus());
+ CherryPickResult result = git.cherryPick().include(sideCommit.getId())
+ .call();
+ assertEquals(CherryPickStatus.CONFLICTING, result.getStatus());
- String expected = "<<<<<<< master\na(master)\n=======\na(side)\n>>>>>>> 527460a side\n";
- checkFile(new File(db.getWorkTree(), "a"), expected);
+ String expected = "<<<<<<< master\na(master)\n=======\na(side)\n>>>>>>> 527460a side\n";
+ checkFile(new File(db.getWorkTree(), "a"), expected);
+ }
}
@Test
public void testCherryPickOurCommitName() throws Exception {
- Git git = new Git(db);
- RevCommit sideCommit = prepareCherryPick(git);
+ try (Git git = new Git(db)) {
+ RevCommit sideCommit = prepareCherryPick(git);
- CherryPickResult result = git.cherryPick().include(sideCommit.getId())
- .setOurCommitName("custom name").call();
- assertEquals(CherryPickStatus.CONFLICTING, result.getStatus());
+ CherryPickResult result = git.cherryPick().include(sideCommit.getId())
+ .setOurCommitName("custom name").call();
+ assertEquals(CherryPickStatus.CONFLICTING, result.getStatus());
- String expected = "<<<<<<< custom name\na(master)\n=======\na(side)\n>>>>>>> 527460a side\n";
- checkFile(new File(db.getWorkTree(), "a"), expected);
+ String expected = "<<<<<<< custom name\na(master)\n=======\na(side)\n>>>>>>> 527460a side\n";
+ checkFile(new File(db.getWorkTree(), "a"), expected);
+ }
}
private RevCommit prepareCherryPick(final Git git) throws Exception {
@@ -399,43 +405,43 @@
*/
@Test
public void testCherryPickMerge() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ commitFile("file", "1\n2\n3\n", "master");
+ commitFile("file", "1\n2\n3\n", "side");
+ checkoutBranch("refs/heads/side");
+ RevCommit commitD = commitFile("file", "1\n2\n3\n4\n5\n", "side2");
+ commitFile("file", "a\n2\n3\n", "side");
+ MergeResult mergeResult = git.merge().include(commitD).call();
+ ObjectId commitM = mergeResult.getNewHead();
+ checkoutBranch("refs/heads/master");
+ RevCommit commitT = commitFile("another", "t", "master");
- commitFile("file", "1\n2\n3\n", "master");
- commitFile("file", "1\n2\n3\n", "side");
- checkoutBranch("refs/heads/side");
- RevCommit commitD = commitFile("file", "1\n2\n3\n4\n5\n", "side2");
- commitFile("file", "a\n2\n3\n", "side");
- MergeResult mergeResult = git.merge().include(commitD).call();
- ObjectId commitM = mergeResult.getNewHead();
- checkoutBranch("refs/heads/master");
- RevCommit commitT = commitFile("another", "t", "master");
+ try {
+ git.cherryPick().include(commitM).call();
+ fail("merges should not be cherry-picked by default");
+ } catch (MultipleParentsNotAllowedException e) {
+ // expected
+ }
+ try {
+ git.cherryPick().include(commitM).setMainlineParentNumber(3).call();
+ fail("specifying a non-existent parent should fail");
+ } catch (JGitInternalException e) {
+ // expected
+ assertTrue(e.getMessage().endsWith(
+ "does not have a parent number 3."));
+ }
- try {
- git.cherryPick().include(commitM).call();
- fail("merges should not be cherry-picked by default");
- } catch (MultipleParentsNotAllowedException e) {
- // expected
+ CherryPickResult result = git.cherryPick().include(commitM)
+ .setMainlineParentNumber(1).call();
+ assertEquals(CherryPickStatus.OK, result.getStatus());
+ checkFile(new File(db.getWorkTree(), "file"), "1\n2\n3\n4\n5\n");
+
+ git.reset().setMode(ResetType.HARD).setRef(commitT.getName()).call();
+
+ CherryPickResult result2 = git.cherryPick().include(commitM)
+ .setMainlineParentNumber(2).call();
+ assertEquals(CherryPickStatus.OK, result2.getStatus());
+ checkFile(new File(db.getWorkTree(), "file"), "a\n2\n3\n");
}
- try {
- git.cherryPick().include(commitM).setMainlineParentNumber(3).call();
- fail("specifying a non-existent parent should fail");
- } catch (JGitInternalException e) {
- // expected
- assertTrue(e.getMessage().endsWith(
- "does not have a parent number 3."));
- }
-
- CherryPickResult result = git.cherryPick().include(commitM)
- .setMainlineParentNumber(1).call();
- assertEquals(CherryPickStatus.OK, result.getStatus());
- checkFile(new File(db.getWorkTree(), "file"), "1\n2\n3\n4\n5\n");
-
- git.reset().setMode(ResetType.HARD).setRef(commitT.getName()).call();
-
- CherryPickResult result2 = git.cherryPick().include(commitM)
- .setMainlineParentNumber(2).call();
- assertEquals(CherryPickStatus.OK, result2.getStatus());
- checkFile(new File(db.getWorkTree(), "file"), "a\n2\n3\n");
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java
index 7b3d4f6..1d5c674 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java
@@ -46,6 +46,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
import java.io.File;
import java.io.IOException;
@@ -78,96 +79,96 @@
GitAPIException {
// do 4 commits
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
- git.commit().setMessage("second commit").setCommitter(committer).call();
- git.commit().setMessage("third commit").setAuthor(author).call();
- git.commit().setMessage("fourth commit").setAuthor(author)
- .setCommitter(committer).call();
- Iterable<RevCommit> commits = git.log().call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ git.commit().setMessage("second commit").setCommitter(committer).call();
+ git.commit().setMessage("third commit").setAuthor(author).call();
+ git.commit().setMessage("fourth commit").setAuthor(author)
+ .setCommitter(committer).call();
+ Iterable<RevCommit> commits = git.log().call();
- // check that all commits came in correctly
- PersonIdent defaultCommitter = new PersonIdent(db);
- PersonIdent expectedAuthors[] = new PersonIdent[] { defaultCommitter,
- committer, author, author };
- PersonIdent expectedCommitters[] = new PersonIdent[] {
- defaultCommitter, committer, defaultCommitter, committer };
- String expectedMessages[] = new String[] { "initial commit",
- "second commit", "third commit", "fourth commit" };
- int l = expectedAuthors.length - 1;
- for (RevCommit c : commits) {
- assertEquals(expectedAuthors[l].getName(), c.getAuthorIdent()
- .getName());
- assertEquals(expectedCommitters[l].getName(), c.getCommitterIdent()
- .getName());
- assertEquals(c.getFullMessage(), expectedMessages[l]);
- l--;
+ // check that all commits came in correctly
+ PersonIdent defaultCommitter = new PersonIdent(db);
+ PersonIdent expectedAuthors[] = new PersonIdent[] { defaultCommitter,
+ committer, author, author };
+ PersonIdent expectedCommitters[] = new PersonIdent[] {
+ defaultCommitter, committer, defaultCommitter, committer };
+ String expectedMessages[] = new String[] { "initial commit",
+ "second commit", "third commit", "fourth commit" };
+ int l = expectedAuthors.length - 1;
+ for (RevCommit c : commits) {
+ assertEquals(expectedAuthors[l].getName(), c.getAuthorIdent()
+ .getName());
+ assertEquals(expectedCommitters[l].getName(), c.getCommitterIdent()
+ .getName());
+ assertEquals(c.getFullMessage(), expectedMessages[l]);
+ l--;
+ }
+ assertEquals(l, -1);
+ ReflogReader reader = db.getReflogReader(Constants.HEAD);
+ assertTrue(reader.getLastEntry().getComment().startsWith("commit:"));
+ reader = db.getReflogReader(db.getBranch());
+ assertTrue(reader.getLastEntry().getComment().startsWith("commit:"));
}
- assertEquals(l, -1);
- ReflogReader reader = db.getReflogReader(Constants.HEAD);
- assertTrue(reader.getLastEntry().getComment().startsWith("commit:"));
- reader = db.getReflogReader(db.getBranch());
- assertTrue(reader.getLastEntry().getComment().startsWith("commit:"));
}
@Test
public void testLogWithFilter() throws IOException, JGitInternalException,
GitAPIException {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ // create first file
+ File file = new File(db.getWorkTree(), "a.txt");
+ FileUtils.createNewFile(file);
+ PrintWriter writer = new PrintWriter(file);
+ writer.print("content1");
+ writer.close();
- // create first file
- File file = new File(db.getWorkTree(), "a.txt");
- FileUtils.createNewFile(file);
- PrintWriter writer = new PrintWriter(file);
- writer.print("content1");
- writer.close();
+ // First commit - a.txt file
+ git.add().addFilepattern("a.txt").call();
+ git.commit().setMessage("commit1").setCommitter(committer).call();
- // First commit - a.txt file
- git.add().addFilepattern("a.txt").call();
- git.commit().setMessage("commit1").setCommitter(committer).call();
+ // create second file
+ file = new File(db.getWorkTree(), "b.txt");
+ FileUtils.createNewFile(file);
+ writer = new PrintWriter(file);
+ writer.print("content2");
+ writer.close();
- // create second file
- file = new File(db.getWorkTree(), "b.txt");
- FileUtils.createNewFile(file);
- writer = new PrintWriter(file);
- writer.print("content2");
- writer.close();
+ // Second commit - b.txt file
+ git.add().addFilepattern("b.txt").call();
+ git.commit().setMessage("commit2").setCommitter(committer).call();
- // Second commit - b.txt file
- git.add().addFilepattern("b.txt").call();
- git.commit().setMessage("commit2").setCommitter(committer).call();
+ // First log - a.txt filter
+ int count = 0;
+ for (RevCommit c : git.log().addPath("a.txt").call()) {
+ assertEquals("commit1", c.getFullMessage());
+ count++;
+ }
+ assertEquals(1, count);
- // First log - a.txt filter
- int count = 0;
- for (RevCommit c : git.log().addPath("a.txt").call()) {
- assertEquals("commit1", c.getFullMessage());
- count++;
+ // Second log - b.txt filter
+ count = 0;
+ for (RevCommit c : git.log().addPath("b.txt").call()) {
+ assertEquals("commit2", c.getFullMessage());
+ count++;
+ }
+ assertEquals(1, count);
+
+ // Third log - without filter
+ count = 0;
+ for (RevCommit c : git.log().call()) {
+ assertEquals(committer, c.getCommitterIdent());
+ count++;
+ }
+ assertEquals(2, count);
}
- assertEquals(1, count);
-
- // Second log - b.txt filter
- count = 0;
- for (RevCommit c : git.log().addPath("b.txt").call()) {
- assertEquals("commit2", c.getFullMessage());
- count++;
- }
- assertEquals(1, count);
-
- // Third log - without filter
- count = 0;
- for (RevCommit c : git.log().call()) {
- assertEquals(committer, c.getCommitterIdent());
- count++;
- }
- assertEquals(2, count);
}
// try to do a commit without specifying a message. Should fail!
@Test
public void testWrongParams() throws GitAPIException {
- Git git = new Git(db);
- try {
+ try (Git git = new Git(db)) {
git.commit().setAuthor(author).call();
fail("Didn't get the expected exception");
} catch (NoMessageException e) {
@@ -179,48 +180,50 @@
// exceptions
@Test
public void testMultipleInvocations() throws GitAPIException {
- Git git = new Git(db);
- CommitCommand commitCmd = git.commit();
- commitCmd.setMessage("initial commit").call();
- try {
- // check that setters can't be called after invocation
- commitCmd.setAuthor(author);
- fail("didn't catch the expected exception");
- } catch (IllegalStateException e) {
- // expected
- }
- LogCommand logCmd = git.log();
- logCmd.call();
- try {
- // check that call can't be called twice
+ try (Git git = new Git(db)) {
+ CommitCommand commitCmd = git.commit();
+ commitCmd.setMessage("initial commit").call();
+ try {
+ // check that setters can't be called after invocation
+ commitCmd.setAuthor(author);
+ fail("didn't catch the expected exception");
+ } catch (IllegalStateException e) {
+ // expected
+ }
+ LogCommand logCmd = git.log();
logCmd.call();
- fail("didn't catch the expected exception");
- } catch (IllegalStateException e) {
- // expected
+ try {
+ // check that call can't be called twice
+ logCmd.call();
+ fail("didn't catch the expected exception");
+ } catch (IllegalStateException e) {
+ // expected
+ }
}
}
@Test
public void testMergeEmptyBranches() throws IOException,
JGitInternalException, GitAPIException {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
- RefUpdate r = db.updateRef("refs/heads/side");
- r.setNewObjectId(db.resolve(Constants.HEAD));
- assertEquals(r.forceUpdate(), RefUpdate.Result.NEW);
- RevCommit second = git.commit().setMessage("second commit").setCommitter(committer).call();
- db.updateRef(Constants.HEAD).link("refs/heads/side");
- RevCommit firstSide = git.commit().setMessage("first side commit").setAuthor(author).call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ RefUpdate r = db.updateRef("refs/heads/side");
+ r.setNewObjectId(db.resolve(Constants.HEAD));
+ assertEquals(r.forceUpdate(), RefUpdate.Result.NEW);
+ RevCommit second = git.commit().setMessage("second commit").setCommitter(committer).call();
+ db.updateRef(Constants.HEAD).link("refs/heads/side");
+ RevCommit firstSide = git.commit().setMessage("first side commit").setAuthor(author).call();
- write(new File(db.getDirectory(), Constants.MERGE_HEAD), ObjectId
- .toString(db.resolve("refs/heads/master")));
- write(new File(db.getDirectory(), Constants.MERGE_MSG), "merging");
+ write(new File(db.getDirectory(), Constants.MERGE_HEAD), ObjectId
+ .toString(db.resolve("refs/heads/master")));
+ write(new File(db.getDirectory(), Constants.MERGE_MSG), "merging");
- RevCommit commit = git.commit().call();
- RevCommit[] parents = commit.getParents();
- assertEquals(parents[0], firstSide);
- assertEquals(parents[1], second);
- assertEquals(2, parents.length);
+ RevCommit commit = git.commit().call();
+ RevCommit[] parents = commit.getParents();
+ assertEquals(parents[0], firstSide);
+ assertEquals(parents[1], second);
+ assertEquals(2, parents.length);
+ }
}
@Test
@@ -232,56 +235,56 @@
writer.print("content");
writer.close();
- Git git = new Git(db);
- git.add().addFilepattern("a.txt").call();
- RevCommit commit = git.commit().setMessage("initial commit").call();
- TreeWalk tw = TreeWalk.forPath(db, "a.txt", commit.getTree());
- assertEquals("6b584e8ece562ebffc15d38808cd6b98fc3d97ea",
- tw.getObjectId(0).getName());
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("a.txt").call();
+ RevCommit commit = git.commit().setMessage("initial commit").call();
+ TreeWalk tw = TreeWalk.forPath(db, "a.txt", commit.getTree());
+ assertEquals("6b584e8ece562ebffc15d38808cd6b98fc3d97ea",
+ tw.getObjectId(0).getName());
- writer = new PrintWriter(file);
- writer.print("content2");
- writer.close();
- commit = git.commit().setMessage("second commit").call();
- tw = TreeWalk.forPath(db, "a.txt", commit.getTree());
- assertEquals("6b584e8ece562ebffc15d38808cd6b98fc3d97ea",
- tw.getObjectId(0).getName());
+ writer = new PrintWriter(file);
+ writer.print("content2");
+ writer.close();
+ commit = git.commit().setMessage("second commit").call();
+ tw = TreeWalk.forPath(db, "a.txt", commit.getTree());
+ assertEquals("6b584e8ece562ebffc15d38808cd6b98fc3d97ea",
+ tw.getObjectId(0).getName());
- commit = git.commit().setAll(true).setMessage("third commit")
- .setAll(true).call();
- tw = TreeWalk.forPath(db, "a.txt", commit.getTree());
- assertEquals("db00fd65b218578127ea51f3dffac701f12f486a",
- tw.getObjectId(0).getName());
+ commit = git.commit().setAll(true).setMessage("third commit")
+ .setAll(true).call();
+ tw = TreeWalk.forPath(db, "a.txt", commit.getTree());
+ assertEquals("db00fd65b218578127ea51f3dffac701f12f486a",
+ tw.getObjectId(0).getName());
+ }
}
@Test
public void testModeChange() throws IOException, GitAPIException {
- if (System.getProperty("os.name").startsWith("Windows"))
- return; // SKIP
- Git git = new Git(db);
+ assumeFalse(System.getProperty("os.name").startsWith("Windows"));// SKIP
+ try (Git git = new Git(db)) {
+ // create file
+ File file = new File(db.getWorkTree(), "a.txt");
+ FileUtils.createNewFile(file);
+ PrintWriter writer = new PrintWriter(file);
+ writer.print("content1");
+ writer.close();
- // create file
- File file = new File(db.getWorkTree(), "a.txt");
- FileUtils.createNewFile(file);
- PrintWriter writer = new PrintWriter(file);
- writer.print("content1");
- writer.close();
+ // First commit - a.txt file
+ git.add().addFilepattern("a.txt").call();
+ git.commit().setMessage("commit1").setCommitter(committer).call();
- // First commit - a.txt file
- git.add().addFilepattern("a.txt").call();
- git.commit().setMessage("commit1").setCommitter(committer).call();
+ // pure mode change should be committable
+ FS fs = db.getFS();
+ fs.setExecute(file, true);
+ git.add().addFilepattern("a.txt").call();
+ git.commit().setMessage("mode change").setCommitter(committer).call();
- // pure mode change should be committable
- FS fs = db.getFS();
- fs.setExecute(file, true);
- git.add().addFilepattern("a.txt").call();
- git.commit().setMessage("mode change").setCommitter(committer).call();
-
- // pure mode change should be committable with -o option
- fs.setExecute(file, false);
- git.add().addFilepattern("a.txt").call();
- git.commit().setMessage("mode change").setCommitter(committer)
- .setOnly("a.txt").call();
+ // pure mode change should be committable with -o option
+ fs.setExecute(file, false);
+ git.add().addFilepattern("a.txt").call();
+ git.commit().setMessage("mode change").setCommitter(committer)
+ .setOnly("a.txt").call();
+ }
}
@Test
@@ -289,112 +292,115 @@
JGitInternalException, MissingObjectException,
IncorrectObjectTypeException {
// do 4 commits and set the range to the second and fourth one
- Git git = new Git(db);
- git.commit().setMessage("first commit").call();
- RevCommit second = git.commit().setMessage("second commit")
- .setCommitter(committer).call();
- git.commit().setMessage("third commit").setAuthor(author).call();
- RevCommit last = git.commit().setMessage("fourth commit").setAuthor(
- author)
- .setCommitter(committer).call();
- Iterable<RevCommit> commits = git.log().addRange(second.getId(),
- last.getId()).call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("first commit").call();
+ RevCommit second = git.commit().setMessage("second commit")
+ .setCommitter(committer).call();
+ git.commit().setMessage("third commit").setAuthor(author).call();
+ RevCommit last = git.commit().setMessage("fourth commit").setAuthor(
+ author)
+ .setCommitter(committer).call();
+ Iterable<RevCommit> commits = git.log().addRange(second.getId(),
+ last.getId()).call();
- // check that we have the third and fourth commit
- PersonIdent defaultCommitter = new PersonIdent(db);
- PersonIdent expectedAuthors[] = new PersonIdent[] { author, author };
- PersonIdent expectedCommitters[] = new PersonIdent[] {
- defaultCommitter, committer };
- String expectedMessages[] = new String[] { "third commit",
- "fourth commit" };
- int l = expectedAuthors.length - 1;
- for (RevCommit c : commits) {
- assertEquals(expectedAuthors[l].getName(), c.getAuthorIdent()
- .getName());
- assertEquals(expectedCommitters[l].getName(), c.getCommitterIdent()
- .getName());
- assertEquals(c.getFullMessage(), expectedMessages[l]);
- l--;
+ // check that we have the third and fourth commit
+ PersonIdent defaultCommitter = new PersonIdent(db);
+ PersonIdent expectedAuthors[] = new PersonIdent[] { author, author };
+ PersonIdent expectedCommitters[] = new PersonIdent[] {
+ defaultCommitter, committer };
+ String expectedMessages[] = new String[] { "third commit",
+ "fourth commit" };
+ int l = expectedAuthors.length - 1;
+ for (RevCommit c : commits) {
+ assertEquals(expectedAuthors[l].getName(), c.getAuthorIdent()
+ .getName());
+ assertEquals(expectedCommitters[l].getName(), c.getCommitterIdent()
+ .getName());
+ assertEquals(c.getFullMessage(), expectedMessages[l]);
+ l--;
+ }
+ assertEquals(l, -1);
}
- assertEquals(l, -1);
}
@Test
public void testCommitAmend() throws JGitInternalException, IOException,
GitAPIException {
- Git git = new Git(db);
- git.commit().setMessage("first comit").call(); // typo
- git.commit().setAmend(true).setMessage("first commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("first comit").call(); // typo
+ git.commit().setAmend(true).setMessage("first commit").call();
- Iterable<RevCommit> commits = git.log().call();
- int c = 0;
- for (RevCommit commit : commits) {
- assertEquals("first commit", commit.getFullMessage());
- c++;
+ Iterable<RevCommit> commits = git.log().call();
+ int c = 0;
+ for (RevCommit commit : commits) {
+ assertEquals("first commit", commit.getFullMessage());
+ c++;
+ }
+ assertEquals(1, c);
+ ReflogReader reader = db.getReflogReader(Constants.HEAD);
+ assertTrue(reader.getLastEntry().getComment()
+ .startsWith("commit (amend):"));
+ reader = db.getReflogReader(db.getBranch());
+ assertTrue(reader.getLastEntry().getComment()
+ .startsWith("commit (amend):"));
}
- assertEquals(1, c);
- ReflogReader reader = db.getReflogReader(Constants.HEAD);
- assertTrue(reader.getLastEntry().getComment()
- .startsWith("commit (amend):"));
- reader = db.getReflogReader(db.getBranch());
- assertTrue(reader.getLastEntry().getComment()
- .startsWith("commit (amend):"));
}
@Test
public void testInsertChangeId() throws JGitInternalException,
GitAPIException {
- Git git = new Git(db);
- String messageHeader = "Some header line\n\nSome detail explanation\n";
- String changeIdTemplate = "\nChange-Id: I"
- + ObjectId.zeroId().getName() + "\n";
- String messageFooter = "Some foooter lines\nAnother footer line\n";
- RevCommit commit = git.commit().setMessage(
- messageHeader + messageFooter)
- .setInsertChangeId(true).call();
- // we should find a real change id (at the end of the file)
- byte[] chars = commit.getFullMessage().getBytes();
- int lastLineBegin = RawParseUtils.prevLF(chars, chars.length - 2);
- String lastLine = RawParseUtils.decode(chars, lastLineBegin + 1,
- chars.length);
- assertTrue(lastLine.contains("Change-Id:"));
- assertFalse(lastLine.contains(
- "Change-Id: I" + ObjectId.zeroId().getName()));
+ try (Git git = new Git(db)) {
+ String messageHeader = "Some header line\n\nSome detail explanation\n";
+ String changeIdTemplate = "\nChange-Id: I"
+ + ObjectId.zeroId().getName() + "\n";
+ String messageFooter = "Some foooter lines\nAnother footer line\n";
+ RevCommit commit = git.commit().setMessage(
+ messageHeader + messageFooter)
+ .setInsertChangeId(true).call();
+ // we should find a real change id (at the end of the file)
+ byte[] chars = commit.getFullMessage().getBytes();
+ int lastLineBegin = RawParseUtils.prevLF(chars, chars.length - 2);
+ String lastLine = RawParseUtils.decode(chars, lastLineBegin + 1,
+ chars.length);
+ assertTrue(lastLine.contains("Change-Id:"));
+ assertFalse(lastLine.contains(
+ "Change-Id: I" + ObjectId.zeroId().getName()));
- commit = git.commit().setMessage(
- messageHeader + changeIdTemplate + messageFooter)
- .setInsertChangeId(true).call();
- // we should find a real change id (in the line as dictated by the
- // template)
- chars = commit.getFullMessage().getBytes();
- int lineStart = 0;
- int lineEnd = 0;
- for (int i = 0; i < 4; i++) {
- lineStart = RawParseUtils.nextLF(chars, lineStart);
+ commit = git.commit().setMessage(
+ messageHeader + changeIdTemplate + messageFooter)
+ .setInsertChangeId(true).call();
+ // we should find a real change id (in the line as dictated by the
+ // template)
+ chars = commit.getFullMessage().getBytes();
+ int lineStart = 0;
+ int lineEnd = 0;
+ for (int i = 0; i < 4; i++) {
+ lineStart = RawParseUtils.nextLF(chars, lineStart);
+ }
+ lineEnd = RawParseUtils.nextLF(chars, lineStart);
+
+ String line = RawParseUtils.decode(chars, lineStart, lineEnd);
+
+ assertTrue(line.contains("Change-Id:"));
+ assertFalse(line.contains(
+ "Change-Id: I" + ObjectId.zeroId().getName()));
+
+ commit = git.commit().setMessage(
+ messageHeader + changeIdTemplate + messageFooter)
+ .setInsertChangeId(false).call();
+ // we should find the untouched template
+ chars = commit.getFullMessage().getBytes();
+ lineStart = 0;
+ lineEnd = 0;
+ for (int i = 0; i < 4; i++) {
+ lineStart = RawParseUtils.nextLF(chars, lineStart);
+ }
+ lineEnd = RawParseUtils.nextLF(chars, lineStart);
+
+ line = RawParseUtils.decode(chars, lineStart, lineEnd);
+
+ assertTrue(commit.getFullMessage().contains(
+ "Change-Id: I" + ObjectId.zeroId().getName()));
}
- lineEnd = RawParseUtils.nextLF(chars, lineStart);
-
- String line = RawParseUtils.decode(chars, lineStart, lineEnd);
-
- assertTrue(line.contains("Change-Id:"));
- assertFalse(line.contains(
- "Change-Id: I" + ObjectId.zeroId().getName()));
-
- commit = git.commit().setMessage(
- messageHeader + changeIdTemplate + messageFooter)
- .setInsertChangeId(false).call();
- // we should find the untouched template
- chars = commit.getFullMessage().getBytes();
- lineStart = 0;
- lineEnd = 0;
- for (int i = 0; i < 4; i++) {
- lineStart = RawParseUtils.nextLF(chars, lineStart);
- }
- lineEnd = RawParseUtils.nextLF(chars, lineStart);
-
- line = RawParseUtils.decode(chars, lineStart, lineEnd);
-
- assertTrue(commit.getFullMessage().contains(
- "Change-Id: I" + ObjectId.zeroId().getName()));
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
index 060a5b65c..9d87f0c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
@@ -46,12 +46,15 @@
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;
@@ -183,295 +186,330 @@
@Test
public void commitNewSubmodule() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- RevCommit commit = git.commit().setMessage("create file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit = git.commit().setMessage("create file").call();
- SubmoduleAddCommand command = new SubmoduleAddCommand(db);
- String path = "sub";
- command.setPath(path);
- String uri = db.getDirectory().toURI().toString();
- command.setURI(uri);
- Repository repo = command.call();
- assertNotNull(repo);
- addRepoToClose(repo);
+ SubmoduleAddCommand command = new SubmoduleAddCommand(db);
+ String path = "sub";
+ command.setPath(path);
+ String uri = db.getDirectory().toURI().toString();
+ command.setURI(uri);
+ Repository repo = command.call();
+ assertNotNull(repo);
+ addRepoToClose(repo);
- SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
- assertTrue(generator.next());
- assertEquals(path, generator.getPath());
- assertEquals(commit, generator.getObjectId());
- assertEquals(uri, generator.getModulesUrl());
- assertEquals(path, generator.getModulesPath());
- assertEquals(uri, generator.getConfigUrl());
- Repository subModRepo = generator.getRepository();
- assertNotNull(subModRepo);
- subModRepo.close();
- assertEquals(commit, repo.resolve(Constants.HEAD));
+ SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertEquals(path, generator.getPath());
+ assertEquals(commit, generator.getObjectId());
+ assertEquals(uri, generator.getModulesUrl());
+ assertEquals(path, generator.getModulesPath());
+ assertEquals(uri, generator.getConfigUrl());
+ Repository subModRepo = generator.getRepository();
+ assertNotNull(subModRepo);
+ subModRepo.close();
+ assertEquals(commit, repo.resolve(Constants.HEAD));
- RevCommit submoduleCommit = git.commit().setMessage("submodule add")
- .setOnly(path).call();
- assertNotNull(submoduleCommit);
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(commit.getTree());
- walk.addTree(submoduleCommit.getTree());
- walk.setFilter(TreeFilter.ANY_DIFF);
- List<DiffEntry> diffs = DiffEntry.scan(walk);
- assertEquals(1, diffs.size());
- DiffEntry subDiff = diffs.get(0);
- assertEquals(FileMode.MISSING, subDiff.getOldMode());
- assertEquals(FileMode.GITLINK, subDiff.getNewMode());
- assertEquals(ObjectId.zeroId(), subDiff.getOldId().toObjectId());
- assertEquals(commit, subDiff.getNewId().toObjectId());
- assertEquals(path, subDiff.getNewPath());
+ RevCommit submoduleCommit = git.commit().setMessage("submodule add")
+ .setOnly(path).call();
+ assertNotNull(submoduleCommit);
+ try (TreeWalk walk = new TreeWalk(db)) {
+ walk.addTree(commit.getTree());
+ walk.addTree(submoduleCommit.getTree());
+ walk.setFilter(TreeFilter.ANY_DIFF);
+ List<DiffEntry> diffs = DiffEntry.scan(walk);
+ assertEquals(1, diffs.size());
+ DiffEntry subDiff = diffs.get(0);
+ assertEquals(FileMode.MISSING, subDiff.getOldMode());
+ assertEquals(FileMode.GITLINK, subDiff.getNewMode());
+ assertEquals(ObjectId.zeroId(), subDiff.getOldId().toObjectId());
+ assertEquals(commit, subDiff.getNewId().toObjectId());
+ assertEquals(path, subDiff.getNewPath());
+ }
+ }
}
@Test
public void commitSubmoduleUpdate() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- RevCommit commit = git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", "content2");
- git.add().addFilepattern("file.txt").call();
- RevCommit commit2 = git.commit().setMessage("edit file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit = git.commit().setMessage("create file").call();
+ writeTrashFile("file.txt", "content2");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit2 = git.commit().setMessage("edit file").call();
- SubmoduleAddCommand command = new SubmoduleAddCommand(db);
- String path = "sub";
- command.setPath(path);
- String uri = db.getDirectory().toURI().toString();
- command.setURI(uri);
- Repository repo = command.call();
- assertNotNull(repo);
- addRepoToClose(repo);
+ SubmoduleAddCommand command = new SubmoduleAddCommand(db);
+ String path = "sub";
+ command.setPath(path);
+ String uri = db.getDirectory().toURI().toString();
+ command.setURI(uri);
+ Repository repo = command.call();
+ assertNotNull(repo);
+ addRepoToClose(repo);
- SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
- assertTrue(generator.next());
- assertEquals(path, generator.getPath());
- assertEquals(commit2, generator.getObjectId());
- assertEquals(uri, generator.getModulesUrl());
- assertEquals(path, generator.getModulesPath());
- assertEquals(uri, generator.getConfigUrl());
- Repository subModRepo = generator.getRepository();
- assertNotNull(subModRepo);
- subModRepo.close();
- assertEquals(commit2, repo.resolve(Constants.HEAD));
+ SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertEquals(path, generator.getPath());
+ assertEquals(commit2, generator.getObjectId());
+ assertEquals(uri, generator.getModulesUrl());
+ assertEquals(path, generator.getModulesPath());
+ assertEquals(uri, generator.getConfigUrl());
+ Repository subModRepo = generator.getRepository();
+ assertNotNull(subModRepo);
+ subModRepo.close();
+ assertEquals(commit2, repo.resolve(Constants.HEAD));
- RevCommit submoduleAddCommit = git.commit().setMessage("submodule add")
- .setOnly(path).call();
- assertNotNull(submoduleAddCommit);
+ RevCommit submoduleAddCommit = git.commit().setMessage("submodule add")
+ .setOnly(path).call();
+ assertNotNull(submoduleAddCommit);
- RefUpdate update = repo.updateRef(Constants.HEAD);
- update.setNewObjectId(commit);
- assertEquals(Result.FORCED, update.forceUpdate());
+ RefUpdate update = repo.updateRef(Constants.HEAD);
+ update.setNewObjectId(commit);
+ assertEquals(Result.FORCED, update.forceUpdate());
- RevCommit submoduleEditCommit = git.commit()
- .setMessage("submodule add").setOnly(path).call();
- assertNotNull(submoduleEditCommit);
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(submoduleAddCommit.getTree());
- walk.addTree(submoduleEditCommit.getTree());
- walk.setFilter(TreeFilter.ANY_DIFF);
- List<DiffEntry> diffs = DiffEntry.scan(walk);
- assertEquals(1, diffs.size());
- DiffEntry subDiff = diffs.get(0);
- assertEquals(FileMode.GITLINK, subDiff.getOldMode());
- assertEquals(FileMode.GITLINK, subDiff.getNewMode());
- assertEquals(commit2, subDiff.getOldId().toObjectId());
- assertEquals(commit, subDiff.getNewId().toObjectId());
- assertEquals(path, subDiff.getNewPath());
- assertEquals(path, subDiff.getOldPath());
+ RevCommit submoduleEditCommit = git.commit()
+ .setMessage("submodule add").setOnly(path).call();
+ assertNotNull(submoduleEditCommit);
+ try (TreeWalk walk = new TreeWalk(db)) {
+ walk.addTree(submoduleAddCommit.getTree());
+ walk.addTree(submoduleEditCommit.getTree());
+ walk.setFilter(TreeFilter.ANY_DIFF);
+ List<DiffEntry> diffs = DiffEntry.scan(walk);
+ assertEquals(1, diffs.size());
+ DiffEntry subDiff = diffs.get(0);
+ assertEquals(FileMode.GITLINK, subDiff.getOldMode());
+ assertEquals(FileMode.GITLINK, subDiff.getNewMode());
+ assertEquals(commit2, subDiff.getOldId().toObjectId());
+ assertEquals(commit, subDiff.getNewId().toObjectId());
+ assertEquals(path, subDiff.getNewPath());
+ assertEquals(path, subDiff.getOldPath());
+ }
+ }
}
@Test
public void commitUpdatesSmudgedEntries() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ File file1 = writeTrashFile("file1.txt", "content1");
+ assertTrue(file1.setLastModified(file1.lastModified() - 5000));
+ File file2 = writeTrashFile("file2.txt", "content2");
+ assertTrue(file2.setLastModified(file2.lastModified() - 5000));
+ File file3 = writeTrashFile("file3.txt", "content3");
+ assertTrue(file3.setLastModified(file3.lastModified() - 5000));
- File file1 = writeTrashFile("file1.txt", "content1");
- assertTrue(file1.setLastModified(file1.lastModified() - 5000));
- File file2 = writeTrashFile("file2.txt", "content2");
- assertTrue(file2.setLastModified(file2.lastModified() - 5000));
- File file3 = writeTrashFile("file3.txt", "content3");
- assertTrue(file3.setLastModified(file3.lastModified() - 5000));
+ assertNotNull(git.add().addFilepattern("file1.txt")
+ .addFilepattern("file2.txt").addFilepattern("file3.txt").call());
+ RevCommit commit = git.commit().setMessage("add files").call();
+ assertNotNull(commit);
- assertNotNull(git.add().addFilepattern("file1.txt")
- .addFilepattern("file2.txt").addFilepattern("file3.txt").call());
- RevCommit commit = git.commit().setMessage("add files").call();
- assertNotNull(commit);
+ DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
+ int file1Size = cache.getEntry("file1.txt").getLength();
+ int file2Size = cache.getEntry("file2.txt").getLength();
+ int file3Size = cache.getEntry("file3.txt").getLength();
+ ObjectId file2Id = cache.getEntry("file2.txt").getObjectId();
+ ObjectId file3Id = cache.getEntry("file3.txt").getObjectId();
+ assertTrue(file1Size > 0);
+ assertTrue(file2Size > 0);
+ assertTrue(file3Size > 0);
- DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
- int file1Size = cache.getEntry("file1.txt").getLength();
- int file2Size = cache.getEntry("file2.txt").getLength();
- int file3Size = cache.getEntry("file3.txt").getLength();
- ObjectId file2Id = cache.getEntry("file2.txt").getObjectId();
- ObjectId file3Id = cache.getEntry("file3.txt").getObjectId();
- assertTrue(file1Size > 0);
- assertTrue(file2Size > 0);
- assertTrue(file3Size > 0);
+ // Smudge entries
+ cache = DirCache.lock(db.getIndexFile(), db.getFS());
+ cache.getEntry("file1.txt").setLength(0);
+ cache.getEntry("file2.txt").setLength(0);
+ cache.getEntry("file3.txt").setLength(0);
+ cache.write();
+ assertTrue(cache.commit());
- // Smudge entries
- cache = DirCache.lock(db.getIndexFile(), db.getFS());
- cache.getEntry("file1.txt").setLength(0);
- cache.getEntry("file2.txt").setLength(0);
- cache.getEntry("file3.txt").setLength(0);
- cache.write();
- assertTrue(cache.commit());
+ // Verify entries smudged
+ cache = DirCache.read(db.getIndexFile(), db.getFS());
+ assertEquals(0, cache.getEntry("file1.txt").getLength());
+ assertEquals(0, cache.getEntry("file2.txt").getLength());
+ assertEquals(0, cache.getEntry("file3.txt").getLength());
- // Verify entries smudged
- cache = DirCache.read(db.getIndexFile(), db.getFS());
- assertEquals(0, cache.getEntry("file1.txt").getLength());
- assertEquals(0, cache.getEntry("file2.txt").getLength());
- assertEquals(0, cache.getEntry("file3.txt").getLength());
+ long indexTime = db.getIndexFile().lastModified();
+ db.getIndexFile().setLastModified(indexTime - 5000);
- long indexTime = db.getIndexFile().lastModified();
- db.getIndexFile().setLastModified(indexTime - 5000);
+ write(file1, "content4");
+ assertTrue(file1.setLastModified(file1.lastModified() + 2500));
+ assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
+ .call());
- write(file1, "content4");
- assertTrue(file1.setLastModified(file1.lastModified() + 2500));
- assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
- .call());
-
- cache = db.readDirCache();
- assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
- assertEquals(file2Size, cache.getEntry("file2.txt").getLength());
- assertEquals(file3Size, cache.getEntry("file3.txt").getLength());
- assertEquals(file2Id, cache.getEntry("file2.txt").getObjectId());
- assertEquals(file3Id, cache.getEntry("file3.txt").getObjectId());
+ cache = db.readDirCache();
+ assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
+ assertEquals(file2Size, cache.getEntry("file2.txt").getLength());
+ assertEquals(file3Size, cache.getEntry("file3.txt").getLength());
+ assertEquals(file2Id, cache.getEntry("file2.txt").getObjectId());
+ assertEquals(file3Id, cache.getEntry("file3.txt").getObjectId());
+ }
}
@Test
public void commitIgnoresSmudgedEntryWithDifferentId() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ File file1 = writeTrashFile("file1.txt", "content1");
+ assertTrue(file1.setLastModified(file1.lastModified() - 5000));
+ File file2 = writeTrashFile("file2.txt", "content2");
+ assertTrue(file2.setLastModified(file2.lastModified() - 5000));
- File file1 = writeTrashFile("file1.txt", "content1");
- assertTrue(file1.setLastModified(file1.lastModified() - 5000));
- File file2 = writeTrashFile("file2.txt", "content2");
- assertTrue(file2.setLastModified(file2.lastModified() - 5000));
+ assertNotNull(git.add().addFilepattern("file1.txt")
+ .addFilepattern("file2.txt").call());
+ RevCommit commit = git.commit().setMessage("add files").call();
+ assertNotNull(commit);
- assertNotNull(git.add().addFilepattern("file1.txt")
- .addFilepattern("file2.txt").call());
- RevCommit commit = git.commit().setMessage("add files").call();
- assertNotNull(commit);
+ DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
+ int file1Size = cache.getEntry("file1.txt").getLength();
+ int file2Size = cache.getEntry("file2.txt").getLength();
+ assertTrue(file1Size > 0);
+ assertTrue(file2Size > 0);
- DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
- int file1Size = cache.getEntry("file1.txt").getLength();
- int file2Size = cache.getEntry("file2.txt").getLength();
- assertTrue(file1Size > 0);
- assertTrue(file2Size > 0);
+ writeTrashFile("file2.txt", "content3");
+ assertNotNull(git.add().addFilepattern("file2.txt").call());
+ writeTrashFile("file2.txt", "content4");
- writeTrashFile("file2.txt", "content3");
- assertNotNull(git.add().addFilepattern("file2.txt").call());
- writeTrashFile("file2.txt", "content4");
+ // Smudge entries
+ cache = DirCache.lock(db.getIndexFile(), db.getFS());
+ cache.getEntry("file1.txt").setLength(0);
+ cache.getEntry("file2.txt").setLength(0);
+ cache.write();
+ assertTrue(cache.commit());
- // Smudge entries
- cache = DirCache.lock(db.getIndexFile(), db.getFS());
- cache.getEntry("file1.txt").setLength(0);
- cache.getEntry("file2.txt").setLength(0);
- cache.write();
- assertTrue(cache.commit());
+ // Verify entries smudged
+ cache = db.readDirCache();
+ assertEquals(0, cache.getEntry("file1.txt").getLength());
+ assertEquals(0, cache.getEntry("file2.txt").getLength());
- // Verify entries smudged
- cache = db.readDirCache();
- assertEquals(0, cache.getEntry("file1.txt").getLength());
- assertEquals(0, cache.getEntry("file2.txt").getLength());
+ long indexTime = db.getIndexFile().lastModified();
+ db.getIndexFile().setLastModified(indexTime - 5000);
- long indexTime = db.getIndexFile().lastModified();
- db.getIndexFile().setLastModified(indexTime - 5000);
+ write(file1, "content5");
+ assertTrue(file1.setLastModified(file1.lastModified() + 1000));
- write(file1, "content5");
- assertTrue(file1.setLastModified(file1.lastModified() + 1000));
+ assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
+ .call());
- assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
- .call());
-
- cache = db.readDirCache();
- assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
- assertEquals(0, cache.getEntry("file2.txt").getLength());
+ cache = db.readDirCache();
+ assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
+ assertEquals(0, cache.getEntry("file2.txt").getLength());
+ }
}
@Test
public void commitAfterSquashMerge() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("file1", "file1");
+ git.add().addFilepattern("file1").call();
+ RevCommit first = git.commit().setMessage("initial commit").call();
- writeTrashFile("file1", "file1");
- git.add().addFilepattern("file1").call();
- RevCommit first = git.commit().setMessage("initial commit").call();
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ createBranch(first, "refs/heads/branch1");
+ checkoutBranch("refs/heads/branch1");
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- createBranch(first, "refs/heads/branch1");
- checkoutBranch("refs/heads/branch1");
+ writeTrashFile("file2", "file2");
+ git.add().addFilepattern("file2").call();
+ git.commit().setMessage("second commit").call();
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
- writeTrashFile("file2", "file2");
- git.add().addFilepattern("file2").call();
- git.commit().setMessage("second commit").call();
- assertTrue(new File(db.getWorkTree(), "file2").exists());
+ checkoutBranch("refs/heads/master");
- checkoutBranch("refs/heads/master");
+ MergeResult result = git.merge()
+ .include(db.exactRef("refs/heads/branch1"))
+ .setSquash(true)
+ .call();
- MergeResult result = git.merge().include(db.getRef("branch1"))
- .setSquash(true).call();
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
+ assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
+ result.getMergeStatus());
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- assertTrue(new File(db.getWorkTree(), "file2").exists());
- assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
- result.getMergeStatus());
+ // comment not set, should be inferred from SQUASH_MSG
+ RevCommit squashedCommit = git.commit().call();
- // comment not set, should be inferred from SQUASH_MSG
- RevCommit squashedCommit = git.commit().call();
-
- assertEquals(1, squashedCommit.getParentCount());
- assertNull(db.readSquashCommitMsg());
- assertEquals("commit: Squashed commit of the following:", db
- .getReflogReader(Constants.HEAD).getLastEntry().getComment());
- assertEquals("commit: Squashed commit of the following:", db
- .getReflogReader(db.getBranch()).getLastEntry().getComment());
+ assertEquals(1, squashedCommit.getParentCount());
+ assertNull(db.readSquashCommitMsg());
+ assertEquals("commit: Squashed commit of the following:", db
+ .getReflogReader(Constants.HEAD).getLastEntry().getComment());
+ assertEquals("commit: Squashed commit of the following:", db
+ .getReflogReader(db.getBranch()).getLastEntry().getComment());
+ }
}
@Test(expected = WrongRepositoryStateException.class)
public void commitAmendOnInitialShouldFail() throws Exception {
- Git git = new Git(db);
- git.commit().setAmend(true).setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setAmend(true).setMessage("initial commit").call();
+ }
}
@Test
public void commitAmendWithoutAuthorShouldSetOriginalAuthorAndAuthorTime()
throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("file1", "file1");
+ git.add().addFilepattern("file1").call();
- writeTrashFile("file1", "file1");
- git.add().addFilepattern("file1").call();
+ final String authorName = "First Author";
+ final String authorEmail = "author@example.org";
+ final Date authorDate = new Date(1349621117000L);
+ PersonIdent firstAuthor = new PersonIdent(authorName, authorEmail,
+ authorDate, TimeZone.getTimeZone("UTC"));
+ git.commit().setMessage("initial commit").setAuthor(firstAuthor).call();
- final String authorName = "First Author";
- final String authorEmail = "author@example.org";
- final Date authorDate = new Date(1349621117000L);
- PersonIdent firstAuthor = new PersonIdent(authorName, authorEmail,
- authorDate, TimeZone.getTimeZone("UTC"));
- git.commit().setMessage("initial commit").setAuthor(firstAuthor).call();
+ RevCommit amended = git.commit().setAmend(true)
+ .setMessage("amend commit").call();
- RevCommit amended = git.commit().setAmend(true)
- .setMessage("amend commit").call();
-
- PersonIdent amendedAuthor = amended.getAuthorIdent();
- assertEquals(authorName, amendedAuthor.getName());
- assertEquals(authorEmail, amendedAuthor.getEmailAddress());
- assertEquals(authorDate.getTime(), amendedAuthor.getWhen().getTime());
+ PersonIdent amendedAuthor = amended.getAuthorIdent();
+ assertEquals(authorName, amendedAuthor.getName());
+ assertEquals(authorEmail, amendedAuthor.getEmailAddress());
+ assertEquals(authorDate.getTime(), amendedAuthor.getWhen().getTime());
+ }
}
@Test
public void commitAmendWithAuthorShouldUseIt() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("file1", "file1");
+ git.add().addFilepattern("file1").call();
+ git.commit().setMessage("initial commit").call();
- writeTrashFile("file1", "file1");
- git.add().addFilepattern("file1").call();
- git.commit().setMessage("initial commit").call();
+ RevCommit amended = git.commit().setAmend(true)
+ .setAuthor("New Author", "newauthor@example.org")
+ .setMessage("amend commit").call();
- RevCommit amended = git.commit().setAmend(true)
- .setAuthor("New Author", "newauthor@example.org")
- .setMessage("amend commit").call();
+ PersonIdent amendedAuthor = amended.getAuthorIdent();
+ assertEquals("New Author", amendedAuthor.getName());
+ assertEquals("newauthor@example.org", amendedAuthor.getEmailAddress());
+ }
+ }
- PersonIdent amendedAuthor = amended.getAuthorIdent();
- assertEquals("New Author", amendedAuthor.getName());
- 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
@@ -499,18 +537,19 @@
+ "[unmerged2, mode:100644, stage:3]",
indexState(0));
- Git git = new Git(db);
- RevCommit commit = git.commit().setOnly("unmerged1")
- .setMessage("Only one file").call();
+ try (Git git = new Git(db)) {
+ RevCommit commit = git.commit().setOnly("unmerged1")
+ .setMessage("Only one file").call();
- assertEquals("[other, mode:100644]" + "[unmerged1, mode:100644]"
- + "[unmerged2, mode:100644, stage:1]"
- + "[unmerged2, mode:100644, stage:2]"
- + "[unmerged2, mode:100644, stage:3]",
- indexState(0));
+ assertEquals("[other, mode:100644]" + "[unmerged1, mode:100644]"
+ + "[unmerged2, mode:100644, stage:1]"
+ + "[unmerged2, mode:100644, stage:2]"
+ + "[unmerged2, mode:100644, stage:3]",
+ indexState(0));
- try (TreeWalk walk = TreeWalk.forPath(db, "unmerged1", commit.getTree())) {
- assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0));
+ try (TreeWalk walk = TreeWalk.forPath(db, "unmerged1", commit.getTree())) {
+ assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0));
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java
index 336a335..5f7434b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitOnlyTest.java
@@ -1294,10 +1294,12 @@
try {
final Repository repo = git.getRepository();
final ObjectId headId = repo.resolve(Constants.HEAD + "^{commit}");
- final TreeWalk tw = TreeWalk.forPath(repo, path,
- new RevWalk(repo).parseTree(headId));
- return new String(tw.getObjectReader().open(tw.getObjectId(0))
- .getBytes());
+ try (RevWalk rw = new RevWalk(repo)) {
+ final TreeWalk tw = TreeWalk.forPath(repo, path,
+ rw.parseTree(headId));
+ return new String(tw.getObjectReader().open(tw.getObjectId(0))
+ .getBytes());
+ }
} catch (Exception e) {
return "";
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
index 4ad01cf..4f5b50d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
@@ -70,32 +70,33 @@
File folder = new File(db.getWorkTree(), "folder");
folder.mkdir();
write(new File(folder, "folder.txt"), "folder");
- Git git = new Git(db);
- git.add().addFilepattern(".").call();
- git.commit().setMessage("Initial commit").call();
- write(new File(folder, "folder.txt"), "folder change");
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("Initial commit").call();
+ write(new File(folder, "folder.txt"), "folder change");
- OutputStream out = new ByteArrayOutputStream();
- List<DiffEntry> entries = git.diff().setOutputStream(out).call();
- assertEquals(1, entries.size());
- assertEquals(ChangeType.MODIFY, entries.get(0)
- .getChangeType());
- assertEquals("folder/folder.txt", entries.get(0)
- .getOldPath());
- assertEquals("folder/folder.txt", entries.get(0)
- .getNewPath());
+ OutputStream out = new ByteArrayOutputStream();
+ List<DiffEntry> entries = git.diff().setOutputStream(out).call();
+ assertEquals(1, entries.size());
+ assertEquals(ChangeType.MODIFY, entries.get(0)
+ .getChangeType());
+ assertEquals("folder/folder.txt", entries.get(0)
+ .getOldPath());
+ assertEquals("folder/folder.txt", entries.get(0)
+ .getNewPath());
- String actual = out.toString();
- String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
- + "index 0119635..95c4c65 100644\n"
- + "--- a/folder/folder.txt\n"
- + "+++ b/folder/folder.txt\n"
- + "@@ -1 +1 @@\n"
- + "-folder\n"
- + "\\ No newline at end of file\n"
- + "+folder change\n"
- + "\\ No newline at end of file\n";
- assertEquals(expected.toString(), actual);
+ String actual = out.toString();
+ String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+ + "index 0119635..95c4c65 100644\n"
+ + "--- a/folder/folder.txt\n"
+ + "+++ b/folder/folder.txt\n"
+ + "@@ -1 +1 @@\n"
+ + "-folder\n"
+ + "\\ No newline at end of file\n"
+ + "+folder change\n"
+ + "\\ No newline at end of file\n";
+ assertEquals(expected.toString(), actual);
+ }
}
@Test
@@ -103,33 +104,34 @@
write(new File(db.getWorkTree(), "test.txt"), "test");
File folder = new File(db.getWorkTree(), "folder");
folder.mkdir();
- Git git = new Git(db);
- git.add().addFilepattern(".").call();
- git.commit().setMessage("Initial commit").call();
- write(new File(folder, "folder.txt"), "folder");
- git.add().addFilepattern(".").call();
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("Initial commit").call();
+ write(new File(folder, "folder.txt"), "folder");
+ git.add().addFilepattern(".").call();
- OutputStream out = new ByteArrayOutputStream();
- List<DiffEntry> entries = git.diff().setOutputStream(out)
- .setCached(true).call();
- assertEquals(1, entries.size());
- assertEquals(ChangeType.ADD, entries.get(0)
- .getChangeType());
- assertEquals("/dev/null", entries.get(0)
- .getOldPath());
- assertEquals("folder/folder.txt", entries.get(0)
- .getNewPath());
+ OutputStream out = new ByteArrayOutputStream();
+ List<DiffEntry> entries = git.diff().setOutputStream(out)
+ .setCached(true).call();
+ assertEquals(1, entries.size());
+ assertEquals(ChangeType.ADD, entries.get(0)
+ .getChangeType());
+ assertEquals("/dev/null", entries.get(0)
+ .getOldPath());
+ assertEquals("folder/folder.txt", entries.get(0)
+ .getNewPath());
- String actual = out.toString();
- String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
- + "new file mode 100644\n"
- + "index 0000000..0119635\n"
- + "--- /dev/null\n"
- + "+++ b/folder/folder.txt\n"
- + "@@ -0,0 +1 @@\n"
- + "+folder\n"
- + "\\ No newline at end of file\n";
- assertEquals(expected.toString(), actual);
+ String actual = out.toString();
+ String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+ + "new file mode 100644\n"
+ + "index 0000000..0119635\n"
+ + "--- /dev/null\n"
+ + "+++ b/folder/folder.txt\n"
+ + "@@ -0,0 +1 @@\n"
+ + "+folder\n"
+ + "\\ No newline at end of file\n";
+ assertEquals(expected.toString(), actual);
+ }
}
@Test
@@ -138,107 +140,109 @@
File folder = new File(db.getWorkTree(), "folder");
folder.mkdir();
write(new File(folder, "folder.txt"), "folder");
- Git git = new Git(db);
- git.add().addFilepattern(".").call();
- git.commit().setMessage("Initial commit").call();
- write(new File(folder, "folder.txt"), "folder change");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("second commit").call();
- write(new File(folder, "folder.txt"), "second folder change");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("third commit").call();
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("Initial commit").call();
+ write(new File(folder, "folder.txt"), "folder change");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("second commit").call();
+ write(new File(folder, "folder.txt"), "second folder change");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("third commit").call();
- // bad filter
- DiffCommand diff = git.diff().setShowNameAndStatusOnly(true)
- .setPathFilter(PathFilter.create("test.txt"))
- .setOldTree(getTreeIterator("HEAD^^"))
- .setNewTree(getTreeIterator("HEAD^"));
- List<DiffEntry> entries = diff.call();
- assertEquals(0, entries.size());
+ // bad filter
+ DiffCommand diff = git.diff().setShowNameAndStatusOnly(true)
+ .setPathFilter(PathFilter.create("test.txt"))
+ .setOldTree(getTreeIterator("HEAD^^"))
+ .setNewTree(getTreeIterator("HEAD^"));
+ List<DiffEntry> entries = diff.call();
+ assertEquals(0, entries.size());
- // no filter, two commits
- OutputStream out = new ByteArrayOutputStream();
- diff = git.diff().setOutputStream(out)
- .setOldTree(getTreeIterator("HEAD^^"))
- .setNewTree(getTreeIterator("HEAD^"));
- entries = diff.call();
- assertEquals(1, entries.size());
- assertEquals(ChangeType.MODIFY, entries.get(0).getChangeType());
- assertEquals("folder/folder.txt", entries.get(0).getOldPath());
- assertEquals("folder/folder.txt", entries.get(0).getNewPath());
+ // no filter, two commits
+ OutputStream out = new ByteArrayOutputStream();
+ diff = git.diff().setOutputStream(out)
+ .setOldTree(getTreeIterator("HEAD^^"))
+ .setNewTree(getTreeIterator("HEAD^"));
+ entries = diff.call();
+ assertEquals(1, entries.size());
+ assertEquals(ChangeType.MODIFY, entries.get(0).getChangeType());
+ assertEquals("folder/folder.txt", entries.get(0).getOldPath());
+ assertEquals("folder/folder.txt", entries.get(0).getNewPath());
- String actual = out.toString();
- String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
- + "index 0119635..95c4c65 100644\n"
- + "--- a/folder/folder.txt\n"
- + "+++ b/folder/folder.txt\n"
- + "@@ -1 +1 @@\n"
- + "-folder\n"
- + "\\ No newline at end of file\n"
- + "+folder change\n"
- + "\\ No newline at end of file\n";
- assertEquals(expected.toString(), actual);
+ String actual = out.toString();
+ String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+ + "index 0119635..95c4c65 100644\n"
+ + "--- a/folder/folder.txt\n"
+ + "+++ b/folder/folder.txt\n"
+ + "@@ -1 +1 @@\n"
+ + "-folder\n"
+ + "\\ No newline at end of file\n"
+ + "+folder change\n"
+ + "\\ No newline at end of file\n";
+ assertEquals(expected.toString(), actual);
+ }
}
@Test
public void testDiffWithPrefixes() throws Exception {
write(new File(db.getWorkTree(), "test.txt"), "test");
- Git git = new Git(db);
- git.add().addFilepattern(".").call();
- git.commit().setMessage("Initial commit").call();
- write(new File(db.getWorkTree(), "test.txt"), "test change");
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("Initial commit").call();
+ write(new File(db.getWorkTree(), "test.txt"), "test change");
- OutputStream out = new ByteArrayOutputStream();
- git.diff().setOutputStream(out).setSourcePrefix("old/")
- .setDestinationPrefix("new/")
- .call();
+ OutputStream out = new ByteArrayOutputStream();
+ git.diff().setOutputStream(out).setSourcePrefix("old/")
+ .setDestinationPrefix("new/").call();
- String actual = out.toString();
- String expected = "diff --git old/test.txt new/test.txt\n"
- + "index 30d74d2..4dba797 100644\n" + "--- old/test.txt\n"
- + "+++ new/test.txt\n" + "@@ -1 +1 @@\n" + "-test\n"
- + "\\ No newline at end of file\n" + "+test change\n"
- + "\\ No newline at end of file\n";
- assertEquals(expected.toString(), actual);
+ String actual = out.toString();
+ String expected = "diff --git old/test.txt new/test.txt\n"
+ + "index 30d74d2..4dba797 100644\n" + "--- old/test.txt\n"
+ + "+++ new/test.txt\n" + "@@ -1 +1 @@\n" + "-test\n"
+ + "\\ No newline at end of file\n" + "+test change\n"
+ + "\\ No newline at end of file\n";
+ assertEquals(expected.toString(), actual);
+ }
}
@Test
public void testDiffWithNegativeLineCount() throws Exception {
write(new File(db.getWorkTree(), "test.txt"),
"0\n1\n2\n3\n4\n5\n6\n7\n8\n9");
- Git git = new Git(db);
- git.add().addFilepattern(".").call();
- git.commit().setMessage("Initial commit").call();
- write(new File(db.getWorkTree(), "test.txt"),
- "0\n1\n2\n3\n4a\n5\n6\n7\n8\n9");
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("Initial commit").call();
+ write(new File(db.getWorkTree(), "test.txt"),
+ "0\n1\n2\n3\n4a\n5\n6\n7\n8\n9");
- OutputStream out = new ByteArrayOutputStream();
- git.diff().setOutputStream(out).setContextLines(1)
- .call();
+ OutputStream out = new ByteArrayOutputStream();
+ git.diff().setOutputStream(out).setContextLines(1).call();
- String actual = out.toString();
- String expected = "diff --git a/test.txt b/test.txt\n"
- + "index f55b5c9..c5ec8fd 100644\n" + "--- a/test.txt\n"
- + "+++ b/test.txt\n" + "@@ -4,3 +4,3 @@\n" + " 3\n" + "-4\n"
- + "+4a\n" + " 5\n";
- assertEquals(expected.toString(), actual);
+ String actual = out.toString();
+ String expected = "diff --git a/test.txt b/test.txt\n"
+ + "index f55b5c9..c5ec8fd 100644\n" + "--- a/test.txt\n"
+ + "+++ b/test.txt\n" + "@@ -4,3 +4,3 @@\n" + " 3\n" + "-4\n"
+ + "+4a\n" + " 5\n";
+ assertEquals(expected.toString(), actual);
+ }
}
@Test
public void testNoOutputStreamSet() throws Exception {
File file = writeTrashFile("test.txt", "a");
assertTrue(file.setLastModified(file.lastModified() - 5000));
- Git git = new Git(db);
- git.add().addFilepattern(".").call();
- write(file, "b");
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(".").call();
+ write(file, "b");
- List<DiffEntry> diffs = git.diff().call();
- assertNotNull(diffs);
- assertEquals(1, diffs.size());
- DiffEntry diff = diffs.get(0);
- assertEquals(ChangeType.MODIFY, diff.getChangeType());
- assertEquals("test.txt", diff.getOldPath());
- assertEquals("test.txt", diff.getNewPath());
+ List<DiffEntry> diffs = git.diff().call();
+ assertNotNull(diffs);
+ assertEquals(1, diffs.size());
+ DiffEntry diff = diffs.get(0);
+ assertEquals(ChangeType.MODIFY, diff.getChangeType());
+ assertEquals("test.txt", diff.getOldPath());
+ assertEquals("test.txt", diff.getNewPath());
+ }
}
private AbstractTreeIterator getTreeIterator(String name)
@@ -247,8 +251,9 @@
if (id == null)
throw new IllegalArgumentException(name);
final CanonicalTreeParser p = new CanonicalTreeParser();
- try (ObjectReader or = db.newObjectReader()) {
- p.reset(or, new RevWalk(db).parseTree(id));
+ try (ObjectReader or = db.newObjectReader();
+ RevWalk rw = new RevWalk(db)) {
+ p.reset(or, rw.parseTree(id));
return p;
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java
index 2220a53..3bff8f2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java
@@ -66,11 +66,12 @@
@Before
public void setUp() throws Exception {
super.setUp();
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
- writeTrashFile("Test.txt", "Hello world");
- git.add().addFilepattern("Test.txt").call();
- git.commit().setMessage("Initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ writeTrashFile("Test.txt", "Hello world");
+ git.add().addFilepattern("Test.txt").call();
+ git.commit().setMessage("Initial commit").call();
+ }
bareRepo = Git.cloneRepository().setBare(true)
.setURI(db.getDirectory().toURI().toString())
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/HugeFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/HugeFileTest.java
index 5449d02..4208f4d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/HugeFileTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/HugeFileTest.java
@@ -51,6 +51,8 @@
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -60,12 +62,26 @@
private long lastt = t;
+ private Git git;
+
private void measure(String name) {
long c = System.currentTimeMillis();
System.out.println(name + ", dt=" + (c - lastt) / 1000.0 + "s");
lastt = c;
}
+ @Before
+ public void before() {
+ git = new Git(db);
+ }
+
+ @After
+ public void after() {
+ if (git != null) {
+ git.close();
+ }
+ }
+
@Ignore("Test takes way too long (~10 minutes) to be part of the standard suite")
@Test
public void testAddHugeFile() throws Exception {
@@ -75,7 +91,6 @@
rf.setLength(4429185024L);
rf.close();
measure("Created file");
- Git git = new Git(db);
git.add().addFilepattern("a.txt").call();
measure("Added file");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
index 0c0c6e5..cb3dbf1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
@@ -43,11 +43,14 @@
*/
package org.eclipse.jgit.api;
+import static org.eclipse.jgit.lib.Constants.MASTER;
+import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import java.io.File;
import java.util.Iterator;
@@ -94,11 +97,12 @@
@Test
public void testMergeInItself() throws Exception {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
- MergeResult result = git.merge().include(db.getRef(Constants.HEAD)).call();
- assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus());
+ MergeResult result = git.merge().include(db.exactRef(Constants.HEAD)).call();
+ assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus());
+ }
// no reflog entry written by merge
assertEquals("commit (initial): initial commit",
db
@@ -110,14 +114,15 @@
@Test
public void testAlreadyUpToDate() throws Exception {
- Git git = new Git(db);
- RevCommit first = git.commit().setMessage("initial commit").call();
- createBranch(first, "refs/heads/branch1");
+ try (Git git = new Git(db)) {
+ RevCommit first = git.commit().setMessage("initial commit").call();
+ createBranch(first, "refs/heads/branch1");
- RevCommit second = git.commit().setMessage("second commit").call();
- MergeResult result = git.merge().include(db.getRef("refs/heads/branch1")).call();
- assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus());
- assertEquals(second, result.getNewHead());
+ RevCommit second = git.commit().setMessage("second commit").call();
+ MergeResult result = git.merge().include(db.exactRef("refs/heads/branch1")).call();
+ assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus());
+ assertEquals(second, result.getNewHead());
+ }
// no reflog entry written by merge
assertEquals("commit: second commit", db
.getReflogReader(Constants.HEAD).getLastEntry().getComment());
@@ -127,18 +132,19 @@
@Test
public void testFastForward() throws Exception {
- Git git = new Git(db);
- RevCommit first = git.commit().setMessage("initial commit").call();
- createBranch(first, "refs/heads/branch1");
+ try (Git git = new Git(db)) {
+ RevCommit first = git.commit().setMessage("initial commit").call();
+ createBranch(first, "refs/heads/branch1");
- RevCommit second = git.commit().setMessage("second commit").call();
+ RevCommit second = git.commit().setMessage("second commit").call();
- checkoutBranch("refs/heads/branch1");
+ checkoutBranch("refs/heads/branch1");
- MergeResult result = git.merge().include(db.getRef(Constants.MASTER)).call();
+ MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)).call();
- assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus());
- assertEquals(second, result.getNewHead());
+ assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus());
+ assertEquals(second, result.getNewHead());
+ }
assertEquals("merge refs/heads/master: Fast-forward",
db.getReflogReader(Constants.HEAD).getLastEntry().getComment());
assertEquals("merge refs/heads/master: Fast-forward",
@@ -147,20 +153,21 @@
@Test
public void testFastForwardNoCommit() throws Exception {
- Git git = new Git(db);
- RevCommit first = git.commit().setMessage("initial commit").call();
- createBranch(first, "refs/heads/branch1");
+ try (Git git = new Git(db)) {
+ RevCommit first = git.commit().setMessage("initial commit").call();
+ createBranch(first, "refs/heads/branch1");
- RevCommit second = git.commit().setMessage("second commit").call();
+ RevCommit second = git.commit().setMessage("second commit").call();
- checkoutBranch("refs/heads/branch1");
+ checkoutBranch("refs/heads/branch1");
- MergeResult result = git.merge().include(db.getRef(Constants.MASTER))
- .setCommit(false).call();
+ MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER))
+ .setCommit(false).call();
- assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
- result.getMergeStatus());
- assertEquals(second, result.getNewHead());
+ assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
+ result.getMergeStatus());
+ assertEquals(second, result.getNewHead());
+ }
assertEquals("merge refs/heads/master: Fast-forward", db
.getReflogReader(Constants.HEAD).getLastEntry().getComment());
assertEquals("merge refs/heads/master: Fast-forward", db
@@ -169,29 +176,29 @@
@Test
public void testFastForwardWithFiles() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("file1", "file1");
+ git.add().addFilepattern("file1").call();
+ RevCommit first = git.commit().setMessage("initial commit").call();
- writeTrashFile("file1", "file1");
- git.add().addFilepattern("file1").call();
- RevCommit first = git.commit().setMessage("initial commit").call();
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ createBranch(first, "refs/heads/branch1");
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- createBranch(first, "refs/heads/branch1");
+ writeTrashFile("file2", "file2");
+ git.add().addFilepattern("file2").call();
+ RevCommit second = git.commit().setMessage("second commit").call();
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
- writeTrashFile("file2", "file2");
- git.add().addFilepattern("file2").call();
- RevCommit second = git.commit().setMessage("second commit").call();
- assertTrue(new File(db.getWorkTree(), "file2").exists());
+ checkoutBranch("refs/heads/branch1");
+ assertFalse(new File(db.getWorkTree(), "file2").exists());
- checkoutBranch("refs/heads/branch1");
- assertFalse(new File(db.getWorkTree(), "file2").exists());
+ MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)).call();
- MergeResult result = git.merge().include(db.getRef(Constants.MASTER)).call();
-
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- assertTrue(new File(db.getWorkTree(), "file2").exists());
- assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus());
- assertEquals(second, result.getNewHead());
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
+ assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus());
+ assertEquals(second, result.getNewHead());
+ }
assertEquals("merge refs/heads/master: Fast-forward",
db.getReflogReader(Constants.HEAD).getLastEntry().getComment());
assertEquals("merge refs/heads/master: Fast-forward",
@@ -200,56 +207,56 @@
@Test
public void testMultipleHeads() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("file1", "file1");
+ git.add().addFilepattern("file1").call();
+ RevCommit first = git.commit().setMessage("initial commit").call();
+ createBranch(first, "refs/heads/branch1");
- writeTrashFile("file1", "file1");
- git.add().addFilepattern("file1").call();
- RevCommit first = git.commit().setMessage("initial commit").call();
- createBranch(first, "refs/heads/branch1");
+ writeTrashFile("file2", "file2");
+ git.add().addFilepattern("file2").call();
+ RevCommit second = git.commit().setMessage("second commit").call();
- writeTrashFile("file2", "file2");
- git.add().addFilepattern("file2").call();
- RevCommit second = git.commit().setMessage("second commit").call();
+ writeTrashFile("file3", "file3");
+ git.add().addFilepattern("file3").call();
+ git.commit().setMessage("third commit").call();
- writeTrashFile("file3", "file3");
- git.add().addFilepattern("file3").call();
- git.commit().setMessage("third commit").call();
+ checkoutBranch("refs/heads/branch1");
+ assertFalse(new File(db.getWorkTree(), "file2").exists());
+ assertFalse(new File(db.getWorkTree(), "file3").exists());
- checkoutBranch("refs/heads/branch1");
- assertFalse(new File(db.getWorkTree(), "file2").exists());
- assertFalse(new File(db.getWorkTree(), "file3").exists());
-
- MergeCommand merge = git.merge();
- merge.include(second.getId());
- merge.include(db.getRef(Constants.MASTER));
- try {
- merge.call();
- fail("Expected exception not thrown when merging multiple heads");
- } catch (InvalidMergeHeadsException e) {
- // expected this exception
+ MergeCommand merge = git.merge();
+ merge.include(second.getId());
+ merge.include(db.exactRef(R_HEADS + MASTER));
+ try {
+ merge.call();
+ fail("Expected exception not thrown when merging multiple heads");
+ } catch (InvalidMergeHeadsException e) {
+ // expected this exception
+ }
}
}
@Theory
public void testMergeSuccessAllStrategies(MergeStrategy mergeStrategy)
throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ RevCommit first = git.commit().setMessage("first").call();
+ createBranch(first, "refs/heads/side");
- RevCommit first = git.commit().setMessage("first").call();
- createBranch(first, "refs/heads/side");
+ writeTrashFile("a", "a");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("second").call();
- writeTrashFile("a", "a");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("second").call();
+ checkoutBranch("refs/heads/side");
+ writeTrashFile("b", "b");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("third").call();
- checkoutBranch("refs/heads/side");
- writeTrashFile("b", "b");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("third").call();
-
- MergeResult result = git.merge().setStrategy(mergeStrategy)
- .include(db.getRef(Constants.MASTER)).call();
- assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ MergeResult result = git.merge().setStrategy(mergeStrategy)
+ .include(db.exactRef(R_HEADS + MASTER)).call();
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ }
assertEquals(
"merge refs/heads/master: Merge made by "
+ mergeStrategy.getName() + ".",
@@ -263,604 +270,604 @@
@Theory
public void testMergeSuccessAllStrategiesNoCommit(
MergeStrategy mergeStrategy) throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ RevCommit first = git.commit().setMessage("first").call();
+ createBranch(first, "refs/heads/side");
- RevCommit first = git.commit().setMessage("first").call();
- createBranch(first, "refs/heads/side");
+ writeTrashFile("a", "a");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("second").call();
- writeTrashFile("a", "a");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("second").call();
+ checkoutBranch("refs/heads/side");
+ writeTrashFile("b", "b");
+ git.add().addFilepattern("b").call();
+ RevCommit thirdCommit = git.commit().setMessage("third").call();
- checkoutBranch("refs/heads/side");
- writeTrashFile("b", "b");
- git.add().addFilepattern("b").call();
- RevCommit thirdCommit = git.commit().setMessage("third").call();
-
- MergeResult result = git.merge().setStrategy(mergeStrategy)
- .setCommit(false)
- .include(db.getRef(Constants.MASTER)).call();
- assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
- assertEquals(db.getRef(Constants.HEAD).getTarget().getObjectId(),
- thirdCommit.getId());
+ MergeResult result = git.merge().setStrategy(mergeStrategy)
+ .setCommit(false)
+ .include(db.exactRef(R_HEADS + MASTER)).call();
+ assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
+ assertEquals(db.exactRef(Constants.HEAD).getTarget().getObjectId(),
+ thirdCommit.getId());
+ }
}
@Test
public void testContentMerge() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ writeTrashFile("c/c/c", "1\nc\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b")
+ .addFilepattern("c/c/c").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- writeTrashFile("c/c/c", "1\nc\n3\n");
- git.add().addFilepattern("a").addFilepattern("b")
- .addFilepattern("c/c/c").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("a", "1\na(side)\n3\n");
+ writeTrashFile("b", "1\nb(side)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- writeTrashFile("a", "1\na(side)\n3\n");
- writeTrashFile("b", "1\nb(side)\n3\n");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
+ checkoutBranch("refs/heads/master");
+ assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
- checkoutBranch("refs/heads/master");
- assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
+ writeTrashFile("a", "1\na(main)\n3\n");
+ writeTrashFile("c/c/c", "1\nc(main)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("c/c/c").call();
+ git.commit().setMessage("main").call();
- writeTrashFile("a", "1\na(main)\n3\n");
- writeTrashFile("c/c/c", "1\nc(main)\n3\n");
- git.add().addFilepattern("a").addFilepattern("c/c/c").call();
- git.commit().setMessage("main").call();
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ assertEquals(
+ "1\n<<<<<<< HEAD\na(main)\n=======\na(side)\n>>>>>>> 86503e7e397465588cc267b65d778538bffccb83\n3\n",
+ read(new File(db.getWorkTree(), "a")));
+ assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
+ assertEquals("1\nc(main)\n3\n",
+ read(new File(db.getWorkTree(), "c/c/c")));
- assertEquals(
- "1\n<<<<<<< HEAD\na(main)\n=======\na(side)\n>>>>>>> 86503e7e397465588cc267b65d778538bffccb83\n3\n",
- read(new File(db.getWorkTree(), "a")));
- assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("1\nc(main)\n3\n",
- read(new File(db.getWorkTree(), "c/c/c")));
+ assertEquals(1, result.getConflicts().size());
+ assertEquals(3, result.getConflicts().get("a")[0].length);
- assertEquals(1, result.getConflicts().size());
- assertEquals(3, result.getConflicts().get("a")[0].length);
-
- assertEquals(RepositoryState.MERGING, db.getRepositoryState());
+ assertEquals(RepositoryState.MERGING, db.getRepositoryState());
+ }
}
@Test
public void testMergeTag() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "a");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "a");
- git.add().addFilepattern("a").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("b", "b");
+ git.add().addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
+ Ref tag = git.tag().setAnnotated(true).setMessage("my tag 01")
+ .setName("tag01").setObjectId(secondCommit).call();
- writeTrashFile("b", "b");
- git.add().addFilepattern("b").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
- Ref tag = git.tag().setAnnotated(true).setMessage("my tag 01")
- .setName("tag01").setObjectId(secondCommit).call();
+ checkoutBranch("refs/heads/master");
- checkoutBranch("refs/heads/master");
+ writeTrashFile("a", "a2");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("main").call();
- writeTrashFile("a", "a2");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("main").call();
-
- MergeResult result = git.merge().include(tag).setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ MergeResult result = git.merge().include(tag).setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ }
}
@Test
public void testMergeMessage() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- git.add().addFilepattern("a").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("a", "1\na(side)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("side").call();
- writeTrashFile("a", "1\na(side)\n3\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("side").call();
+ checkoutBranch("refs/heads/master");
- checkoutBranch("refs/heads/master");
+ writeTrashFile("a", "1\na(main)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("main").call();
- writeTrashFile("a", "1\na(main)\n3\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("main").call();
+ Ref sideBranch = db.exactRef("refs/heads/side");
- Ref sideBranch = db.getRef("side");
+ git.merge().include(sideBranch)
+ .setStrategy(MergeStrategy.RESOLVE).call();
- git.merge().include(sideBranch)
- .setStrategy(MergeStrategy.RESOLVE).call();
-
- assertEquals("Merge branch 'side'\n\nConflicts:\n\ta\n",
- db.readMergeCommitMsg());
+ assertEquals("Merge branch 'side'\n\nConflicts:\n\ta\n",
+ db.readMergeCommitMsg());
+ }
}
@Test
public void testMergeNonVersionedPaths() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ writeTrashFile("c/c/c", "1\nc\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b")
+ .addFilepattern("c/c/c").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- writeTrashFile("c/c/c", "1\nc\n3\n");
- git.add().addFilepattern("a").addFilepattern("b")
- .addFilepattern("c/c/c").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("a", "1\na(side)\n3\n");
+ writeTrashFile("b", "1\nb(side)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- writeTrashFile("a", "1\na(side)\n3\n");
- writeTrashFile("b", "1\nb(side)\n3\n");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
+ checkoutBranch("refs/heads/master");
+ assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
- checkoutBranch("refs/heads/master");
- assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
+ writeTrashFile("a", "1\na(main)\n3\n");
+ writeTrashFile("c/c/c", "1\nc(main)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("c/c/c").call();
+ git.commit().setMessage("main").call();
- writeTrashFile("a", "1\na(main)\n3\n");
- writeTrashFile("c/c/c", "1\nc(main)\n3\n");
- git.add().addFilepattern("a").addFilepattern("c/c/c").call();
- git.commit().setMessage("main").call();
+ writeTrashFile("d", "1\nd\n3\n");
+ assertTrue(new File(db.getWorkTree(), "e").mkdir());
- writeTrashFile("d", "1\nd\n3\n");
- assertTrue(new File(db.getWorkTree(), "e").mkdir());
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ assertEquals(
+ "1\n<<<<<<< HEAD\na(main)\n=======\na(side)\n>>>>>>> 86503e7e397465588cc267b65d778538bffccb83\n3\n",
+ read(new File(db.getWorkTree(), "a")));
+ assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
+ assertEquals("1\nc(main)\n3\n",
+ read(new File(db.getWorkTree(), "c/c/c")));
+ assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
+ File dir = new File(db.getWorkTree(), "e");
+ assertTrue(dir.isDirectory());
- assertEquals(
- "1\n<<<<<<< HEAD\na(main)\n=======\na(side)\n>>>>>>> 86503e7e397465588cc267b65d778538bffccb83\n3\n",
- read(new File(db.getWorkTree(), "a")));
- assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("1\nc(main)\n3\n",
- read(new File(db.getWorkTree(), "c/c/c")));
- assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
- File dir = new File(db.getWorkTree(), "e");
- assertTrue(dir.isDirectory());
+ assertEquals(1, result.getConflicts().size());
+ assertEquals(3, result.getConflicts().get("a")[0].length);
- assertEquals(1, result.getConflicts().size());
- assertEquals(3, result.getConflicts().get("a")[0].length);
-
- assertEquals(RepositoryState.MERGING, db.getRepositoryState());
+ assertEquals(RepositoryState.MERGING, db.getRepositoryState());
+ }
}
@Test
public void testMultipleCreations() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- git.add().addFilepattern("a").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("b", "1\nb(side)\n3\n");
+ git.add().addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- writeTrashFile("b", "1\nb(side)\n3\n");
- git.add().addFilepattern("b").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ checkoutBranch("refs/heads/master");
- checkoutBranch("refs/heads/master");
+ writeTrashFile("b", "1\nb(main)\n3\n");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("main").call();
- writeTrashFile("b", "1\nb(main)\n3\n");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("main").call();
-
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ }
}
@Test
public void testMultipleCreationsSameContent() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- git.add().addFilepattern("a").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("b", "1\nb(1)\n3\n");
+ git.add().addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- writeTrashFile("b", "1\nb(1)\n3\n");
- git.add().addFilepattern("b").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ checkoutBranch("refs/heads/master");
- checkoutBranch("refs/heads/master");
+ writeTrashFile("b", "1\nb(1)\n3\n");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("main").call();
- writeTrashFile("b", "1\nb(1)\n3\n");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("main").call();
-
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.MERGED, result.getMergeStatus());
- assertEquals("1\nb(1)\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("merge " + secondCommit.getId().getName()
- + ": Merge made by resolve.", db
- .getReflogReader(Constants.HEAD)
- .getLastEntry().getComment());
- assertEquals("merge " + secondCommit.getId().getName()
- + ": Merge made by resolve.", db
- .getReflogReader(db.getBranch())
- .getLastEntry().getComment());
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ assertEquals("1\nb(1)\n3\n", read(new File(db.getWorkTree(), "b")));
+ assertEquals("merge " + secondCommit.getId().getName()
+ + ": Merge made by resolve.", db
+ .getReflogReader(Constants.HEAD)
+ .getLastEntry().getComment());
+ assertEquals("merge " + secondCommit.getId().getName()
+ + ": Merge made by resolve.", db
+ .getReflogReader(db.getBranch())
+ .getLastEntry().getComment());
+ }
}
@Test
public void testSuccessfulContentMerge() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ writeTrashFile("c/c/c", "1\nc\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b")
+ .addFilepattern("c/c/c").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- writeTrashFile("c/c/c", "1\nc\n3\n");
- git.add().addFilepattern("a").addFilepattern("b")
- .addFilepattern("c/c/c").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("a", "1(side)\na\n3\n");
+ writeTrashFile("b", "1\nb(side)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- writeTrashFile("a", "1(side)\na\n3\n");
- writeTrashFile("b", "1\nb(side)\n3\n");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
+ checkoutBranch("refs/heads/master");
+ assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
- checkoutBranch("refs/heads/master");
- assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
+ writeTrashFile("a", "1\na\n3(main)\n");
+ writeTrashFile("c/c/c", "1\nc(main)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("c/c/c").call();
+ RevCommit thirdCommit = git.commit().setMessage("main").call();
- writeTrashFile("a", "1\na\n3(main)\n");
- writeTrashFile("c/c/c", "1\nc(main)\n3\n");
- git.add().addFilepattern("a").addFilepattern("c/c/c").call();
- RevCommit thirdCommit = git.commit().setMessage("main").call();
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
+ "a")));
+ assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
+ assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(),
+ "c/c/c")));
- assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
- "a")));
- assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(),
- "c/c/c")));
+ assertEquals(null, result.getConflicts());
- assertEquals(null, result.getConflicts());
+ assertEquals(2, result.getMergedCommits().length);
+ assertEquals(thirdCommit, result.getMergedCommits()[0]);
+ assertEquals(secondCommit, result.getMergedCommits()[1]);
- assertEquals(2, result.getMergedCommits().length);
- assertEquals(thirdCommit, result.getMergedCommits()[0]);
- assertEquals(secondCommit, result.getMergedCommits()[1]);
-
- Iterator<RevCommit> it = git.log().call().iterator();
- RevCommit newHead = it.next();
- assertEquals(newHead, result.getNewHead());
- assertEquals(2, newHead.getParentCount());
- assertEquals(thirdCommit, newHead.getParent(0));
- assertEquals(secondCommit, newHead.getParent(1));
- assertEquals(
- "Merge commit '3fa334456d236a92db020289fe0bf481d91777b4'",
- newHead.getFullMessage());
- // @TODO fix me
- assertEquals(RepositoryState.SAFE, db.getRepositoryState());
- // test index state
+ Iterator<RevCommit> it = git.log().call().iterator();
+ RevCommit newHead = it.next();
+ assertEquals(newHead, result.getNewHead());
+ assertEquals(2, newHead.getParentCount());
+ assertEquals(thirdCommit, newHead.getParent(0));
+ assertEquals(secondCommit, newHead.getParent(1));
+ assertEquals(
+ "Merge commit '3fa334456d236a92db020289fe0bf481d91777b4'",
+ newHead.getFullMessage());
+ // @TODO fix me
+ assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ // test index state
+ }
}
@Test
public void testSuccessfulContentMergeNoCommit() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ writeTrashFile("c/c/c", "1\nc\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b")
+ .addFilepattern("c/c/c").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- writeTrashFile("c/c/c", "1\nc\n3\n");
- git.add().addFilepattern("a").addFilepattern("b")
- .addFilepattern("c/c/c").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("a", "1(side)\na\n3\n");
+ writeTrashFile("b", "1\nb(side)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- writeTrashFile("a", "1(side)\na\n3\n");
- writeTrashFile("b", "1\nb(side)\n3\n");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
+ checkoutBranch("refs/heads/master");
+ assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
- checkoutBranch("refs/heads/master");
- assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
+ writeTrashFile("a", "1\na\n3(main)\n");
+ writeTrashFile("c/c/c", "1\nc(main)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("c/c/c").call();
+ RevCommit thirdCommit = git.commit().setMessage("main").call();
- writeTrashFile("a", "1\na\n3(main)\n");
- writeTrashFile("c/c/c", "1\nc(main)\n3\n");
- git.add().addFilepattern("a").addFilepattern("c/c/c").call();
- RevCommit thirdCommit = git.commit().setMessage("main").call();
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setCommit(false)
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
+ assertEquals(db.exactRef(Constants.HEAD).getTarget().getObjectId(),
+ thirdCommit.getId());
- MergeResult result = git.merge().include(secondCommit.getId())
- .setCommit(false)
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
- assertEquals(db.getRef(Constants.HEAD).getTarget().getObjectId(),
- thirdCommit.getId());
+ assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
+ "a")));
+ assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
+ assertEquals("1\nc(main)\n3\n",
+ read(new File(db.getWorkTree(), "c/c/c")));
- assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
- "a")));
- assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("1\nc(main)\n3\n",
- read(new File(db.getWorkTree(), "c/c/c")));
+ assertEquals(null, result.getConflicts());
- assertEquals(null, result.getConflicts());
-
- assertEquals(2, result.getMergedCommits().length);
- assertEquals(thirdCommit, result.getMergedCommits()[0]);
- assertEquals(secondCommit, result.getMergedCommits()[1]);
- assertNull(result.getNewHead());
- assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState());
+ assertEquals(2, result.getMergedCommits().length);
+ assertEquals(thirdCommit, result.getMergedCommits()[0]);
+ assertEquals(secondCommit, result.getMergedCommits()[1]);
+ assertNull(result.getNewHead());
+ assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState());
+ }
}
@Test
public void testSuccessfulContentMergeAndDirtyworkingTree()
throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ writeTrashFile("d", "1\nd\n3\n");
+ writeTrashFile("c/c/c", "1\nc\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b")
+ .addFilepattern("c/c/c").addFilepattern("d").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- writeTrashFile("d", "1\nd\n3\n");
- writeTrashFile("c/c/c", "1\nc\n3\n");
- git.add().addFilepattern("a").addFilepattern("b")
- .addFilepattern("c/c/c").addFilepattern("d").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("a", "1(side)\na\n3\n");
+ writeTrashFile("b", "1\nb(side)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- writeTrashFile("a", "1(side)\na\n3\n");
- writeTrashFile("b", "1\nb(side)\n3\n");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
+ checkoutBranch("refs/heads/master");
+ assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
- checkoutBranch("refs/heads/master");
- assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
+ writeTrashFile("a", "1\na\n3(main)\n");
+ writeTrashFile("c/c/c", "1\nc(main)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("c/c/c").call();
+ RevCommit thirdCommit = git.commit().setMessage("main").call();
- writeTrashFile("a", "1\na\n3(main)\n");
- writeTrashFile("c/c/c", "1\nc(main)\n3\n");
- git.add().addFilepattern("a").addFilepattern("c/c/c").call();
- RevCommit thirdCommit = git.commit().setMessage("main").call();
+ writeTrashFile("d", "--- dirty ---");
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
- writeTrashFile("d", "--- dirty ---");
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
+ "a")));
+ assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
+ assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(),
+ "c/c/c")));
+ assertEquals("--- dirty ---", read(new File(db.getWorkTree(), "d")));
- assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
- "a")));
- assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(),
- "c/c/c")));
- assertEquals("--- dirty ---", read(new File(db.getWorkTree(), "d")));
+ assertEquals(null, result.getConflicts());
- assertEquals(null, result.getConflicts());
+ assertEquals(2, result.getMergedCommits().length);
+ assertEquals(thirdCommit, result.getMergedCommits()[0]);
+ assertEquals(secondCommit, result.getMergedCommits()[1]);
- assertEquals(2, result.getMergedCommits().length);
- assertEquals(thirdCommit, result.getMergedCommits()[0]);
- assertEquals(secondCommit, result.getMergedCommits()[1]);
+ Iterator<RevCommit> it = git.log().call().iterator();
+ RevCommit newHead = it.next();
+ assertEquals(newHead, result.getNewHead());
+ assertEquals(2, newHead.getParentCount());
+ assertEquals(thirdCommit, newHead.getParent(0));
+ assertEquals(secondCommit, newHead.getParent(1));
+ assertEquals(
+ "Merge commit '064d54d98a4cdb0fed1802a21c656bfda67fe879'",
+ newHead.getFullMessage());
- Iterator<RevCommit> it = git.log().call().iterator();
- RevCommit newHead = it.next();
- assertEquals(newHead, result.getNewHead());
- assertEquals(2, newHead.getParentCount());
- assertEquals(thirdCommit, newHead.getParent(0));
- assertEquals(secondCommit, newHead.getParent(1));
- assertEquals(
- "Merge commit '064d54d98a4cdb0fed1802a21c656bfda67fe879'",
- newHead.getFullMessage());
-
- assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ }
}
@Test
public void testSingleDeletion() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ writeTrashFile("d", "1\nd\n3\n");
+ writeTrashFile("c/c/c", "1\nc\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b")
+ .addFilepattern("c/c/c").addFilepattern("d").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- writeTrashFile("d", "1\nd\n3\n");
- writeTrashFile("c/c/c", "1\nc\n3\n");
- git.add().addFilepattern("a").addFilepattern("b")
- .addFilepattern("c/c/c").addFilepattern("d").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ assertTrue(new File(db.getWorkTree(), "b").delete());
+ git.add().addFilepattern("b").setUpdate(true).call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- assertTrue(new File(db.getWorkTree(), "b").delete());
- git.add().addFilepattern("b").setUpdate(true).call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ assertFalse(new File(db.getWorkTree(), "b").exists());
+ checkoutBranch("refs/heads/master");
+ assertTrue(new File(db.getWorkTree(), "b").exists());
- assertFalse(new File(db.getWorkTree(), "b").exists());
- checkoutBranch("refs/heads/master");
- assertTrue(new File(db.getWorkTree(), "b").exists());
+ writeTrashFile("a", "1\na\n3(main)\n");
+ writeTrashFile("c/c/c", "1\nc(main)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("c/c/c").call();
+ RevCommit thirdCommit = git.commit().setMessage("main").call();
- writeTrashFile("a", "1\na\n3(main)\n");
- writeTrashFile("c/c/c", "1\nc(main)\n3\n");
- git.add().addFilepattern("a").addFilepattern("c/c/c").call();
- RevCommit thirdCommit = git.commit().setMessage("main").call();
+ // We are merging a deletion into our branch
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
- // We are merging a deletion into our branch
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a")));
+ assertFalse(new File(db.getWorkTree(), "b").exists());
+ assertEquals("1\nc(main)\n3\n",
+ read(new File(db.getWorkTree(), "c/c/c")));
+ assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
- assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a")));
- assertFalse(new File(db.getWorkTree(), "b").exists());
- assertEquals("1\nc(main)\n3\n",
- read(new File(db.getWorkTree(), "c/c/c")));
- assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
+ // Do the opposite, be on a branch where we have deleted a file and
+ // merge in a old commit where this file was not deleted
+ checkoutBranch("refs/heads/side");
+ assertFalse(new File(db.getWorkTree(), "b").exists());
- // Do the opposite, be on a branch where we have deleted a file and
- // merge in a old commit where this file was not deleted
- checkoutBranch("refs/heads/side");
- assertFalse(new File(db.getWorkTree(), "b").exists());
+ result = git.merge().include(thirdCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
- result = git.merge().include(thirdCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.MERGED, result.getMergeStatus());
-
- assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a")));
- assertFalse(new File(db.getWorkTree(), "b").exists());
- assertEquals("1\nc(main)\n3\n",
- read(new File(db.getWorkTree(), "c/c/c")));
- assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
+ assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a")));
+ assertFalse(new File(db.getWorkTree(), "b").exists());
+ assertEquals("1\nc(main)\n3\n",
+ read(new File(db.getWorkTree(), "c/c/c")));
+ assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
+ }
}
@Test
public void testMultipleDeletions() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- git.add().addFilepattern("a").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ assertTrue(new File(db.getWorkTree(), "a").delete());
+ git.add().addFilepattern("a").setUpdate(true).call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- assertTrue(new File(db.getWorkTree(), "a").delete());
- git.add().addFilepattern("a").setUpdate(true).call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ assertFalse(new File(db.getWorkTree(), "a").exists());
+ checkoutBranch("refs/heads/master");
+ assertTrue(new File(db.getWorkTree(), "a").exists());
- assertFalse(new File(db.getWorkTree(), "a").exists());
- checkoutBranch("refs/heads/master");
- assertTrue(new File(db.getWorkTree(), "a").exists());
+ assertTrue(new File(db.getWorkTree(), "a").delete());
+ git.add().addFilepattern("a").setUpdate(true).call();
+ git.commit().setMessage("main").call();
- assertTrue(new File(db.getWorkTree(), "a").delete());
- git.add().addFilepattern("a").setUpdate(true).call();
- git.commit().setMessage("main").call();
-
- // We are merging a deletion into our branch
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ // We are merging a deletion into our branch
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ }
}
@Test
public void testDeletionAndConflict() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ writeTrashFile("d", "1\nd\n3\n");
+ writeTrashFile("c/c/c", "1\nc\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b")
+ .addFilepattern("c/c/c").addFilepattern("d").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- writeTrashFile("d", "1\nd\n3\n");
- writeTrashFile("c/c/c", "1\nc\n3\n");
- git.add().addFilepattern("a").addFilepattern("b")
- .addFilepattern("c/c/c").addFilepattern("d").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ assertTrue(new File(db.getWorkTree(), "b").delete());
+ writeTrashFile("a", "1\na\n3(side)\n");
+ git.add().addFilepattern("b").setUpdate(true).call();
+ git.add().addFilepattern("a").setUpdate(true).call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- assertTrue(new File(db.getWorkTree(), "b").delete());
- writeTrashFile("a", "1\na\n3(side)\n");
- git.add().addFilepattern("b").setUpdate(true).call();
- git.add().addFilepattern("a").setUpdate(true).call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ assertFalse(new File(db.getWorkTree(), "b").exists());
+ checkoutBranch("refs/heads/master");
+ assertTrue(new File(db.getWorkTree(), "b").exists());
- assertFalse(new File(db.getWorkTree(), "b").exists());
- checkoutBranch("refs/heads/master");
- assertTrue(new File(db.getWorkTree(), "b").exists());
+ writeTrashFile("a", "1\na\n3(main)\n");
+ writeTrashFile("c/c/c", "1\nc(main)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("c/c/c").call();
+ git.commit().setMessage("main").call();
- writeTrashFile("a", "1\na\n3(main)\n");
- writeTrashFile("c/c/c", "1\nc(main)\n3\n");
- git.add().addFilepattern("a").addFilepattern("c/c/c").call();
- git.commit().setMessage("main").call();
+ // We are merging a deletion into our branch
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- // We are merging a deletion into our branch
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
-
- assertEquals(
- "1\na\n<<<<<<< HEAD\n3(main)\n=======\n3(side)\n>>>>>>> 54ffed45d62d252715fc20e41da92d44c48fb0ff\n",
- read(new File(db.getWorkTree(), "a")));
- assertFalse(new File(db.getWorkTree(), "b").exists());
- assertEquals("1\nc(main)\n3\n",
- read(new File(db.getWorkTree(), "c/c/c")));
- assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
+ assertEquals(
+ "1\na\n<<<<<<< HEAD\n3(main)\n=======\n3(side)\n>>>>>>> 54ffed45d62d252715fc20e41da92d44c48fb0ff\n",
+ read(new File(db.getWorkTree(), "a")));
+ assertFalse(new File(db.getWorkTree(), "b").exists());
+ assertEquals("1\nc(main)\n3\n",
+ read(new File(db.getWorkTree(), "c/c/c")));
+ assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
+ }
}
@Test
public void testDeletionOnMasterConflict() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ // create side branch and modify "a"
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ writeTrashFile("a", "1\na(side)\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- // create side branch and modify "a"
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
- writeTrashFile("a", "1\na(side)\n3\n");
- git.add().addFilepattern("a").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ // delete a on master to generate conflict
+ checkoutBranch("refs/heads/master");
+ git.rm().addFilepattern("a").call();
+ git.commit().setMessage("main").call();
- // delete a on master to generate conflict
- checkoutBranch("refs/heads/master");
- git.rm().addFilepattern("a").call();
- git.commit().setMessage("main").call();
+ // merge side with master
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- // merge side with master
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
-
- // result should be 'a' conflicting with workspace content from side
- assertTrue(new File(db.getWorkTree(), "a").exists());
- assertEquals("1\na(side)\n3\n", read(new File(db.getWorkTree(), "a")));
- assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
+ // result should be 'a' conflicting with workspace content from side
+ assertTrue(new File(db.getWorkTree(), "a").exists());
+ assertEquals("1\na(side)\n3\n", read(new File(db.getWorkTree(), "a")));
+ assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
+ }
}
@Test
public void testDeletionOnSideConflict() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ // create side branch and delete "a"
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ git.rm().addFilepattern("a").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- // create side branch and delete "a"
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
- git.rm().addFilepattern("a").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ // update a on master to generate conflict
+ checkoutBranch("refs/heads/master");
+ writeTrashFile("a", "1\na(main)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("main").call();
- // update a on master to generate conflict
- checkoutBranch("refs/heads/master");
- writeTrashFile("a", "1\na(main)\n3\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("main").call();
+ // merge side with master
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- // merge side with master
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ assertTrue(new File(db.getWorkTree(), "a").exists());
+ assertEquals("1\na(main)\n3\n", read(new File(db.getWorkTree(), "a")));
+ assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
- assertTrue(new File(db.getWorkTree(), "a").exists());
- assertEquals("1\na(main)\n3\n", read(new File(db.getWorkTree(), "a")));
- assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
-
- assertEquals(1, result.getConflicts().size());
- assertEquals(3, result.getConflicts().get("a")[0].length);
+ assertEquals(1, result.getConflicts().size());
+ assertEquals(3, result.getConflicts().get("a")[0].length);
+ }
}
@Test
@@ -868,262 +875,262 @@
// this test is essentially the same as testDeletionOnSideConflict,
// however if once rename support is added this test should result in a
// successful merge instead of a conflict
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("x", "add x");
+ git.add().addFilepattern("x").call();
+ RevCommit initial = git.commit().setMessage("add x").call();
- writeTrashFile("x", "add x");
- git.add().addFilepattern("x").call();
- RevCommit initial = git.commit().setMessage("add x").call();
+ createBranch(initial, "refs/heads/d1");
+ createBranch(initial, "refs/heads/d2");
- createBranch(initial, "refs/heads/d1");
- createBranch(initial, "refs/heads/d2");
+ // rename x to y on d1
+ checkoutBranch("refs/heads/d1");
+ new File(db.getWorkTree(), "x")
+ .renameTo(new File(db.getWorkTree(), "y"));
+ git.rm().addFilepattern("x").call();
+ git.add().addFilepattern("y").call();
+ RevCommit d1Commit = git.commit().setMessage("d1 rename x -> y").call();
- // rename x to y on d1
- checkoutBranch("refs/heads/d1");
- new File(db.getWorkTree(), "x")
- .renameTo(new File(db.getWorkTree(), "y"));
- git.rm().addFilepattern("x").call();
- git.add().addFilepattern("y").call();
- RevCommit d1Commit = git.commit().setMessage("d1 rename x -> y").call();
+ checkoutBranch("refs/heads/d2");
+ writeTrashFile("x", "d2 change");
+ git.add().addFilepattern("x").call();
+ RevCommit d2Commit = git.commit().setMessage("d2 change in x").call();
- checkoutBranch("refs/heads/d2");
- writeTrashFile("x", "d2 change");
- git.add().addFilepattern("x").call();
- RevCommit d2Commit = git.commit().setMessage("d2 change in x").call();
+ checkoutBranch("refs/heads/master");
+ MergeResult d1Merge = git.merge().include(d1Commit).call();
+ assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
+ d1Merge.getMergeStatus());
- checkoutBranch("refs/heads/master");
- MergeResult d1Merge = git.merge().include(d1Commit).call();
- assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
- d1Merge.getMergeStatus());
-
- MergeResult d2Merge = git.merge().include(d2Commit).call();
- assertEquals(MergeResult.MergeStatus.CONFLICTING,
- d2Merge.getMergeStatus());
- assertEquals(1, d2Merge.getConflicts().size());
- assertEquals(3, d2Merge.getConflicts().get("x")[0].length);
+ MergeResult d2Merge = git.merge().include(d2Commit).call();
+ assertEquals(MergeResult.MergeStatus.CONFLICTING,
+ d2Merge.getMergeStatus());
+ assertEquals(1, d2Merge.getConflicts().size());
+ assertEquals(3, d2Merge.getConflicts().get("x")[0].length);
+ }
}
@Test
public void testMergeFailingWithDirtyWorkingTree() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("a", "1(side)\na\n3\n");
+ writeTrashFile("b", "1\nb(side)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- writeTrashFile("a", "1(side)\na\n3\n");
- writeTrashFile("b", "1\nb(side)\n3\n");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
+ checkoutBranch("refs/heads/master");
+ assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
- checkoutBranch("refs/heads/master");
- assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
+ writeTrashFile("a", "1\na\n3(main)\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("main").call();
- writeTrashFile("a", "1\na\n3(main)\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("main").call();
+ writeTrashFile("a", "--- dirty ---");
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
- writeTrashFile("a", "--- dirty ---");
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.FAILED, result.getMergeStatus());
- assertEquals(MergeStatus.FAILED, result.getMergeStatus());
+ assertEquals("--- dirty ---", read(new File(db.getWorkTree(), "a")));
+ assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("--- dirty ---", read(new File(db.getWorkTree(), "a")));
- assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
+ assertEquals(null, result.getConflicts());
- assertEquals(null, result.getConflicts());
-
- assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ }
}
@Test
public void testMergeConflictFileFolder() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("c/c/c", "1\nc(side)\n3\n");
+ writeTrashFile("d", "1\nd(side)\n3\n");
+ git.add().addFilepattern("c/c/c").addFilepattern("d").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- writeTrashFile("c/c/c", "1\nc(side)\n3\n");
- writeTrashFile("d", "1\nd(side)\n3\n");
- git.add().addFilepattern("c/c/c").addFilepattern("d").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ checkoutBranch("refs/heads/master");
- checkoutBranch("refs/heads/master");
+ writeTrashFile("c", "1\nc(main)\n3\n");
+ writeTrashFile("d/d/d", "1\nd(main)\n3\n");
+ git.add().addFilepattern("c").addFilepattern("d/d/d").call();
+ git.commit().setMessage("main").call();
- writeTrashFile("c", "1\nc(main)\n3\n");
- writeTrashFile("d/d/d", "1\nd(main)\n3\n");
- git.add().addFilepattern("c").addFilepattern("d/d/d").call();
- git.commit().setMessage("main").call();
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ assertEquals("1\na\n3\n", read(new File(db.getWorkTree(), "a")));
+ assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
+ assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(), "c")));
+ assertEquals("1\nd(main)\n3\n", read(new File(db.getWorkTree(), "d/d/d")));
- assertEquals("1\na\n3\n", read(new File(db.getWorkTree(), "a")));
- assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
- assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(), "c")));
- assertEquals("1\nd(main)\n3\n", read(new File(db.getWorkTree(), "d/d/d")));
+ assertEquals(null, result.getConflicts());
- assertEquals(null, result.getConflicts());
-
- assertEquals(RepositoryState.MERGING, db.getRepositoryState());
+ assertEquals(RepositoryState.MERGING, db.getRepositoryState());
+ }
}
@Test
public void testSuccessfulMergeFailsDueToDirtyIndex() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ File fileA = writeTrashFile("a", "a");
+ RevCommit initialCommit = addAllAndCommit(git);
- File fileA = writeTrashFile("a", "a");
- RevCommit initialCommit = addAllAndCommit(git);
+ // switch branch
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ // modify file a
+ write(fileA, "a(side)");
+ writeTrashFile("b", "b");
+ RevCommit sideCommit = addAllAndCommit(git);
- // switch branch
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
- // modify file a
- write(fileA, "a(side)");
- writeTrashFile("b", "b");
- RevCommit sideCommit = addAllAndCommit(git);
+ // switch branch
+ checkoutBranch("refs/heads/master");
+ writeTrashFile("c", "c");
+ addAllAndCommit(git);
- // switch branch
- checkoutBranch("refs/heads/master");
- writeTrashFile("c", "c");
- addAllAndCommit(git);
+ // modify and add file a
+ write(fileA, "a(modified)");
+ git.add().addFilepattern("a").call();
+ // do not commit
- // modify and add file a
- write(fileA, "a(modified)");
- git.add().addFilepattern("a").call();
- // do not commit
+ // get current index state
+ String indexState = indexState(CONTENT);
- // get current index state
- String indexState = indexState(CONTENT);
+ // merge
+ MergeResult result = git.merge().include(sideCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
- // merge
- MergeResult result = git.merge().include(sideCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
-
- checkMergeFailedResult(result, MergeFailureReason.DIRTY_INDEX,
- indexState, fileA);
+ checkMergeFailedResult(result, MergeFailureReason.DIRTY_INDEX,
+ indexState, fileA);
+ }
}
@Test
public void testConflictingMergeFailsDueToDirtyIndex() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ File fileA = writeTrashFile("a", "a");
+ RevCommit initialCommit = addAllAndCommit(git);
- File fileA = writeTrashFile("a", "a");
- RevCommit initialCommit = addAllAndCommit(git);
+ // switch branch
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ // modify file a
+ write(fileA, "a(side)");
+ writeTrashFile("b", "b");
+ RevCommit sideCommit = addAllAndCommit(git);
- // switch branch
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
- // modify file a
- write(fileA, "a(side)");
- writeTrashFile("b", "b");
- RevCommit sideCommit = addAllAndCommit(git);
+ // switch branch
+ checkoutBranch("refs/heads/master");
+ // modify file a - this will cause a conflict during merge
+ write(fileA, "a(master)");
+ writeTrashFile("c", "c");
+ addAllAndCommit(git);
- // switch branch
- checkoutBranch("refs/heads/master");
- // modify file a - this will cause a conflict during merge
- write(fileA, "a(master)");
- writeTrashFile("c", "c");
- addAllAndCommit(git);
+ // modify and add file a
+ write(fileA, "a(modified)");
+ git.add().addFilepattern("a").call();
+ // do not commit
- // modify and add file a
- write(fileA, "a(modified)");
- git.add().addFilepattern("a").call();
- // do not commit
+ // get current index state
+ String indexState = indexState(CONTENT);
- // get current index state
- String indexState = indexState(CONTENT);
+ // merge
+ MergeResult result = git.merge().include(sideCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
- // merge
- MergeResult result = git.merge().include(sideCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
-
- checkMergeFailedResult(result, MergeFailureReason.DIRTY_INDEX,
- indexState, fileA);
+ checkMergeFailedResult(result, MergeFailureReason.DIRTY_INDEX,
+ indexState, fileA);
+ }
}
@Test
public void testSuccessfulMergeFailsDueToDirtyWorktree() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ File fileA = writeTrashFile("a", "a");
+ RevCommit initialCommit = addAllAndCommit(git);
- File fileA = writeTrashFile("a", "a");
- RevCommit initialCommit = addAllAndCommit(git);
+ // switch branch
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ // modify file a
+ write(fileA, "a(side)");
+ writeTrashFile("b", "b");
+ RevCommit sideCommit = addAllAndCommit(git);
- // switch branch
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
- // modify file a
- write(fileA, "a(side)");
- writeTrashFile("b", "b");
- RevCommit sideCommit = addAllAndCommit(git);
+ // switch branch
+ checkoutBranch("refs/heads/master");
+ writeTrashFile("c", "c");
+ addAllAndCommit(git);
- // switch branch
- checkoutBranch("refs/heads/master");
- writeTrashFile("c", "c");
- addAllAndCommit(git);
+ // modify file a
+ write(fileA, "a(modified)");
+ // do not add and commit
- // modify file a
- write(fileA, "a(modified)");
- // do not add and commit
+ // get current index state
+ String indexState = indexState(CONTENT);
- // get current index state
- String indexState = indexState(CONTENT);
+ // merge
+ MergeResult result = git.merge().include(sideCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
- // merge
- MergeResult result = git.merge().include(sideCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
-
- checkMergeFailedResult(result, MergeFailureReason.DIRTY_WORKTREE,
- indexState, fileA);
+ checkMergeFailedResult(result, MergeFailureReason.DIRTY_WORKTREE,
+ indexState, fileA);
+ }
}
@Test
public void testConflictingMergeFailsDueToDirtyWorktree() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ File fileA = writeTrashFile("a", "a");
+ RevCommit initialCommit = addAllAndCommit(git);
- File fileA = writeTrashFile("a", "a");
- RevCommit initialCommit = addAllAndCommit(git);
+ // switch branch
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ // modify file a
+ write(fileA, "a(side)");
+ writeTrashFile("b", "b");
+ RevCommit sideCommit = addAllAndCommit(git);
- // switch branch
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
- // modify file a
- write(fileA, "a(side)");
- writeTrashFile("b", "b");
- RevCommit sideCommit = addAllAndCommit(git);
+ // switch branch
+ checkoutBranch("refs/heads/master");
+ // modify file a - this will cause a conflict during merge
+ write(fileA, "a(master)");
+ writeTrashFile("c", "c");
+ addAllAndCommit(git);
- // switch branch
- checkoutBranch("refs/heads/master");
- // modify file a - this will cause a conflict during merge
- write(fileA, "a(master)");
- writeTrashFile("c", "c");
- addAllAndCommit(git);
+ // modify file a
+ write(fileA, "a(modified)");
+ // do not add and commit
- // modify file a
- write(fileA, "a(modified)");
- // do not add and commit
+ // get current index state
+ String indexState = indexState(CONTENT);
- // get current index state
- String indexState = indexState(CONTENT);
+ // merge
+ MergeResult result = git.merge().include(sideCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
- // merge
- MergeResult result = git.merge().include(sideCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
-
- checkMergeFailedResult(result, MergeFailureReason.DIRTY_WORKTREE,
- indexState, fileA);
+ checkMergeFailedResult(result, MergeFailureReason.DIRTY_WORKTREE,
+ indexState, fileA);
+ }
}
@Test
@@ -1141,29 +1148,30 @@
file = new File(folder2, "file2.txt");
write(file, "folder2--file2.txt");
- Git git = new Git(db);
- git.add().addFilepattern(folder1.getName())
- .addFilepattern(folder2.getName()).call();
- RevCommit commit1 = git.commit().setMessage("adding folders").call();
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(folder1.getName())
+ .addFilepattern(folder2.getName()).call();
+ RevCommit commit1 = git.commit().setMessage("adding folders").call();
- recursiveDelete(folder1);
- recursiveDelete(folder2);
- git.rm().addFilepattern("folder1/file1.txt")
- .addFilepattern("folder1/file2.txt")
- .addFilepattern("folder2/file1.txt")
- .addFilepattern("folder2/file2.txt").call();
- RevCommit commit2 = git.commit()
- .setMessage("removing folders on 'branch'").call();
+ recursiveDelete(folder1);
+ recursiveDelete(folder2);
+ git.rm().addFilepattern("folder1/file1.txt")
+ .addFilepattern("folder1/file2.txt")
+ .addFilepattern("folder2/file1.txt")
+ .addFilepattern("folder2/file2.txt").call();
+ RevCommit commit2 = git.commit()
+ .setMessage("removing folders on 'branch'").call();
- git.checkout().setName(commit1.name()).call();
+ git.checkout().setName(commit1.name()).call();
- MergeResult result = git.merge().include(commit2.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
- result.getMergeStatus());
- assertEquals(commit2, result.getNewHead());
- assertFalse(folder1.exists());
- assertFalse(folder2.exists());
+ MergeResult result = git.merge().include(commit2.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
+ result.getMergeStatus());
+ assertEquals(commit2, result.getNewHead());
+ assertFalse(folder1.exists());
+ assertFalse(folder2.exists());
+ }
}
@Test
@@ -1181,360 +1189,369 @@
file = new File(folder2, "file2.txt");
write(file, "folder2--file2.txt");
- Git git = new Git(db);
- git.add().addFilepattern(folder1.getName())
- .addFilepattern(folder2.getName()).call();
- RevCommit base = git.commit().setMessage("adding folders").call();
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(folder1.getName())
+ .addFilepattern(folder2.getName()).call();
+ RevCommit base = git.commit().setMessage("adding folders").call();
- recursiveDelete(folder1);
- recursiveDelete(folder2);
- git.rm().addFilepattern("folder1/file1.txt")
- .addFilepattern("folder1/file2.txt")
- .addFilepattern("folder2/file1.txt")
- .addFilepattern("folder2/file2.txt").call();
- RevCommit other = git.commit()
- .setMessage("removing folders on 'branch'").call();
+ recursiveDelete(folder1);
+ recursiveDelete(folder2);
+ git.rm().addFilepattern("folder1/file1.txt")
+ .addFilepattern("folder1/file2.txt")
+ .addFilepattern("folder2/file1.txt")
+ .addFilepattern("folder2/file2.txt").call();
+ RevCommit other = git.commit()
+ .setMessage("removing folders on 'branch'").call();
- git.checkout().setName(base.name()).call();
+ git.checkout().setName(base.name()).call();
- file = new File(folder2, "file3.txt");
- write(file, "folder2--file3.txt");
+ file = new File(folder2, "file3.txt");
+ write(file, "folder2--file3.txt");
- git.add().addFilepattern(folder2.getName()).call();
- git.commit().setMessage("adding another file").call();
+ git.add().addFilepattern(folder2.getName()).call();
+ git.commit().setMessage("adding another file").call();
- MergeResult result = git.merge().include(other.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
+ MergeResult result = git.merge().include(other.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeResult.MergeStatus.MERGED,
- result.getMergeStatus());
- assertFalse(folder1.exists());
+ assertEquals(MergeResult.MergeStatus.MERGED,
+ result.getMergeStatus());
+ assertFalse(folder1.exists());
+ }
}
@Test
public void testFileModeMerge() throws Exception {
- if (!FS.DETECTED.supportsExecute())
- return;
// Only Java6
- Git git = new Git(db);
+ assumeTrue(FS.DETECTED.supportsExecute());
+ try (Git git = new Git(db)) {
+ writeTrashFile("mergeableMode", "a");
+ setExecutable(git, "mergeableMode", false);
+ writeTrashFile("conflictingModeWithBase", "a");
+ setExecutable(git, "conflictingModeWithBase", false);
+ RevCommit initialCommit = addAllAndCommit(git);
- writeTrashFile("mergeableMode", "a");
- setExecutable(git, "mergeableMode", false);
- writeTrashFile("conflictingModeWithBase", "a");
- setExecutable(git, "conflictingModeWithBase", false);
- RevCommit initialCommit = addAllAndCommit(git);
+ // switch branch
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ setExecutable(git, "mergeableMode", true);
+ writeTrashFile("conflictingModeNoBase", "b");
+ setExecutable(git, "conflictingModeNoBase", true);
+ RevCommit sideCommit = addAllAndCommit(git);
- // switch branch
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
- setExecutable(git, "mergeableMode", true);
- writeTrashFile("conflictingModeNoBase", "b");
- setExecutable(git, "conflictingModeNoBase", true);
- RevCommit sideCommit = addAllAndCommit(git);
+ // switch branch
+ createBranch(initialCommit, "refs/heads/side2");
+ checkoutBranch("refs/heads/side2");
+ setExecutable(git, "mergeableMode", false);
+ assertFalse(new File(git.getRepository().getWorkTree(),
+ "conflictingModeNoBase").exists());
+ writeTrashFile("conflictingModeNoBase", "b");
+ setExecutable(git, "conflictingModeNoBase", false);
+ addAllAndCommit(git);
- // switch branch
- createBranch(initialCommit, "refs/heads/side2");
- checkoutBranch("refs/heads/side2");
- setExecutable(git, "mergeableMode", false);
- assertFalse(new File(git.getRepository().getWorkTree(),
- "conflictingModeNoBase").exists());
- writeTrashFile("conflictingModeNoBase", "b");
- setExecutable(git, "conflictingModeNoBase", false);
- addAllAndCommit(git);
-
- // merge
- MergeResult result = git.merge().include(sideCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- assertTrue(canExecute(git, "mergeableMode"));
- assertFalse(canExecute(git, "conflictingModeNoBase"));
+ // merge
+ MergeResult result = git.merge().include(sideCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ assertTrue(canExecute(git, "mergeableMode"));
+ assertFalse(canExecute(git, "conflictingModeNoBase"));
+ }
}
@Test
public void testFileModeMergeWithDirtyWorkTree() throws Exception {
- if (!FS.DETECTED.supportsExecute())
- return;
// Only Java6 (or set x bit in index)
+ assumeTrue(FS.DETECTED.supportsExecute());
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("mergeableButDirty", "a");
+ setExecutable(git, "mergeableButDirty", false);
+ RevCommit initialCommit = addAllAndCommit(git);
- writeTrashFile("mergeableButDirty", "a");
- setExecutable(git, "mergeableButDirty", false);
- RevCommit initialCommit = addAllAndCommit(git);
+ // switch branch
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ setExecutable(git, "mergeableButDirty", true);
+ RevCommit sideCommit = addAllAndCommit(git);
- // switch branch
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
- setExecutable(git, "mergeableButDirty", true);
- RevCommit sideCommit = addAllAndCommit(git);
+ // switch branch
+ createBranch(initialCommit, "refs/heads/side2");
+ checkoutBranch("refs/heads/side2");
+ setExecutable(git, "mergeableButDirty", false);
+ addAllAndCommit(git);
- // switch branch
- createBranch(initialCommit, "refs/heads/side2");
- checkoutBranch("refs/heads/side2");
- setExecutable(git, "mergeableButDirty", false);
- addAllAndCommit(git);
+ writeTrashFile("mergeableButDirty", "b");
- writeTrashFile("mergeableButDirty", "b");
-
- // merge
- MergeResult result = git.merge().include(sideCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.FAILED, result.getMergeStatus());
- assertFalse(canExecute(git, "mergeableButDirty"));
+ // merge
+ MergeResult result = git.merge().include(sideCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.FAILED, result.getMergeStatus());
+ assertFalse(canExecute(git, "mergeableButDirty"));
+ }
}
@Test
public void testSquashFastForward() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("file1", "file1");
+ git.add().addFilepattern("file1").call();
+ RevCommit first = git.commit().setMessage("initial commit").call();
- writeTrashFile("file1", "file1");
- git.add().addFilepattern("file1").call();
- RevCommit first = git.commit().setMessage("initial commit").call();
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ createBranch(first, "refs/heads/branch1");
+ checkoutBranch("refs/heads/branch1");
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- createBranch(first, "refs/heads/branch1");
- checkoutBranch("refs/heads/branch1");
+ writeTrashFile("file2", "file2");
+ git.add().addFilepattern("file2").call();
+ RevCommit second = git.commit().setMessage("second commit").call();
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
- writeTrashFile("file2", "file2");
- git.add().addFilepattern("file2").call();
- RevCommit second = git.commit().setMessage("second commit").call();
- assertTrue(new File(db.getWorkTree(), "file2").exists());
+ writeTrashFile("file3", "file3");
+ git.add().addFilepattern("file3").call();
+ RevCommit third = git.commit().setMessage("third commit").call();
+ assertTrue(new File(db.getWorkTree(), "file3").exists());
- writeTrashFile("file3", "file3");
- git.add().addFilepattern("file3").call();
- RevCommit third = git.commit().setMessage("third commit").call();
- assertTrue(new File(db.getWorkTree(), "file3").exists());
+ checkoutBranch("refs/heads/master");
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ assertFalse(new File(db.getWorkTree(), "file2").exists());
+ assertFalse(new File(db.getWorkTree(), "file3").exists());
- checkoutBranch("refs/heads/master");
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- assertFalse(new File(db.getWorkTree(), "file2").exists());
- assertFalse(new File(db.getWorkTree(), "file3").exists());
+ MergeResult result = git.merge()
+ .include(db.exactRef("refs/heads/branch1"))
+ .setSquash(true)
+ .call();
- MergeResult result = git.merge().include(db.getRef("branch1"))
- .setSquash(true).call();
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
+ assertTrue(new File(db.getWorkTree(), "file3").exists());
+ assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
+ result.getMergeStatus());
+ assertEquals(first, result.getNewHead()); // HEAD didn't move
+ assertEquals(first, db.resolve(Constants.HEAD + "^{commit}"));
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- assertTrue(new File(db.getWorkTree(), "file2").exists());
- assertTrue(new File(db.getWorkTree(), "file3").exists());
- assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
- result.getMergeStatus());
- assertEquals(first, result.getNewHead()); // HEAD didn't move
- assertEquals(first, db.resolve(Constants.HEAD + "^{commit}"));
+ assertEquals(
+ "Squashed commit of the following:\n\ncommit "
+ + third.getName()
+ + "\nAuthor: "
+ + third.getAuthorIdent().getName()
+ + " <"
+ + third.getAuthorIdent().getEmailAddress()
+ + ">\nDate: "
+ + dateFormatter.formatDate(third
+ .getAuthorIdent())
+ + "\n\n\tthird commit\n\ncommit "
+ + second.getName()
+ + "\nAuthor: "
+ + second.getAuthorIdent().getName()
+ + " <"
+ + second.getAuthorIdent().getEmailAddress()
+ + ">\nDate: "
+ + dateFormatter.formatDate(second
+ .getAuthorIdent()) + "\n\n\tsecond commit\n",
+ db.readSquashCommitMsg());
+ assertNull(db.readMergeCommitMsg());
- assertEquals(
- "Squashed commit of the following:\n\ncommit "
- + third.getName()
- + "\nAuthor: "
- + third.getAuthorIdent().getName()
- + " <"
- + third.getAuthorIdent().getEmailAddress()
- + ">\nDate: "
- + dateFormatter.formatDate(third
- .getAuthorIdent())
- + "\n\n\tthird commit\n\ncommit "
- + second.getName()
- + "\nAuthor: "
- + second.getAuthorIdent().getName()
- + " <"
- + second.getAuthorIdent().getEmailAddress()
- + ">\nDate: "
- + dateFormatter.formatDate(second
- .getAuthorIdent()) + "\n\n\tsecond commit\n",
- db.readSquashCommitMsg());
- assertNull(db.readMergeCommitMsg());
-
- Status stat = git.status().call();
- assertEquals(Sets.of("file2", "file3"), stat.getAdded());
+ Status stat = git.status().call();
+ assertEquals(Sets.of("file2", "file3"), stat.getAdded());
+ }
}
@Test
public void testSquashMerge() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("file1", "file1");
+ git.add().addFilepattern("file1").call();
+ RevCommit first = git.commit().setMessage("initial commit").call();
- writeTrashFile("file1", "file1");
- git.add().addFilepattern("file1").call();
- RevCommit first = git.commit().setMessage("initial commit").call();
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ createBranch(first, "refs/heads/branch1");
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- createBranch(first, "refs/heads/branch1");
+ writeTrashFile("file2", "file2");
+ git.add().addFilepattern("file2").call();
+ RevCommit second = git.commit().setMessage("second commit").call();
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
- writeTrashFile("file2", "file2");
- git.add().addFilepattern("file2").call();
- RevCommit second = git.commit().setMessage("second commit").call();
- assertTrue(new File(db.getWorkTree(), "file2").exists());
+ checkoutBranch("refs/heads/branch1");
- checkoutBranch("refs/heads/branch1");
+ writeTrashFile("file3", "file3");
+ git.add().addFilepattern("file3").call();
+ RevCommit third = git.commit().setMessage("third commit").call();
+ assertTrue(new File(db.getWorkTree(), "file3").exists());
- writeTrashFile("file3", "file3");
- git.add().addFilepattern("file3").call();
- RevCommit third = git.commit().setMessage("third commit").call();
- assertTrue(new File(db.getWorkTree(), "file3").exists());
+ checkoutBranch("refs/heads/master");
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
+ assertFalse(new File(db.getWorkTree(), "file3").exists());
- checkoutBranch("refs/heads/master");
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- assertTrue(new File(db.getWorkTree(), "file2").exists());
- assertFalse(new File(db.getWorkTree(), "file3").exists());
+ MergeResult result = git.merge()
+ .include(db.exactRef("refs/heads/branch1"))
+ .setSquash(true)
+ .call();
- MergeResult result = git.merge().include(db.getRef("branch1"))
- .setSquash(true).call();
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
+ assertTrue(new File(db.getWorkTree(), "file3").exists());
+ assertEquals(MergeResult.MergeStatus.MERGED_SQUASHED,
+ result.getMergeStatus());
+ assertEquals(second, result.getNewHead()); // HEAD didn't move
+ assertEquals(second, db.resolve(Constants.HEAD + "^{commit}"));
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- assertTrue(new File(db.getWorkTree(), "file2").exists());
- assertTrue(new File(db.getWorkTree(), "file3").exists());
- assertEquals(MergeResult.MergeStatus.MERGED_SQUASHED,
- result.getMergeStatus());
- assertEquals(second, result.getNewHead()); // HEAD didn't move
- assertEquals(second, db.resolve(Constants.HEAD + "^{commit}"));
+ assertEquals(
+ "Squashed commit of the following:\n\ncommit "
+ + third.getName()
+ + "\nAuthor: "
+ + third.getAuthorIdent().getName()
+ + " <"
+ + third.getAuthorIdent().getEmailAddress()
+ + ">\nDate: "
+ + dateFormatter.formatDate(third
+ .getAuthorIdent()) + "\n\n\tthird commit\n",
+ db.readSquashCommitMsg());
+ assertNull(db.readMergeCommitMsg());
- assertEquals(
- "Squashed commit of the following:\n\ncommit "
- + third.getName()
- + "\nAuthor: "
- + third.getAuthorIdent().getName()
- + " <"
- + third.getAuthorIdent().getEmailAddress()
- + ">\nDate: "
- + dateFormatter.formatDate(third
- .getAuthorIdent()) + "\n\n\tthird commit\n",
- db.readSquashCommitMsg());
- assertNull(db.readMergeCommitMsg());
-
- Status stat = git.status().call();
- assertEquals(Sets.of("file3"), stat.getAdded());
+ Status stat = git.status().call();
+ assertEquals(Sets.of("file3"), stat.getAdded());
+ }
}
@Test
public void testSquashMergeConflict() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("file1", "file1");
+ git.add().addFilepattern("file1").call();
+ RevCommit first = git.commit().setMessage("initial commit").call();
- writeTrashFile("file1", "file1");
- git.add().addFilepattern("file1").call();
- RevCommit first = git.commit().setMessage("initial commit").call();
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ createBranch(first, "refs/heads/branch1");
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- createBranch(first, "refs/heads/branch1");
+ writeTrashFile("file2", "master");
+ git.add().addFilepattern("file2").call();
+ RevCommit second = git.commit().setMessage("second commit").call();
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
- writeTrashFile("file2", "master");
- git.add().addFilepattern("file2").call();
- RevCommit second = git.commit().setMessage("second commit").call();
- assertTrue(new File(db.getWorkTree(), "file2").exists());
+ checkoutBranch("refs/heads/branch1");
- checkoutBranch("refs/heads/branch1");
+ writeTrashFile("file2", "branch");
+ git.add().addFilepattern("file2").call();
+ RevCommit third = git.commit().setMessage("third commit").call();
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
- writeTrashFile("file2", "branch");
- git.add().addFilepattern("file2").call();
- RevCommit third = git.commit().setMessage("third commit").call();
- assertTrue(new File(db.getWorkTree(), "file2").exists());
+ checkoutBranch("refs/heads/master");
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
- checkoutBranch("refs/heads/master");
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- assertTrue(new File(db.getWorkTree(), "file2").exists());
+ MergeResult result = git.merge()
+ .include(db.exactRef("refs/heads/branch1"))
+ .setSquash(true)
+ .call();
- MergeResult result = git.merge().include(db.getRef("branch1"))
- .setSquash(true).call();
+ assertTrue(new File(db.getWorkTree(), "file1").exists());
+ assertTrue(new File(db.getWorkTree(), "file2").exists());
+ assertEquals(MergeResult.MergeStatus.CONFLICTING,
+ result.getMergeStatus());
+ assertNull(result.getNewHead());
+ assertEquals(second, db.resolve(Constants.HEAD + "^{commit}"));
- assertTrue(new File(db.getWorkTree(), "file1").exists());
- assertTrue(new File(db.getWorkTree(), "file2").exists());
- assertEquals(MergeResult.MergeStatus.CONFLICTING,
- result.getMergeStatus());
- assertNull(result.getNewHead());
- assertEquals(second, db.resolve(Constants.HEAD + "^{commit}"));
+ assertEquals(
+ "Squashed commit of the following:\n\ncommit "
+ + third.getName()
+ + "\nAuthor: "
+ + third.getAuthorIdent().getName()
+ + " <"
+ + third.getAuthorIdent().getEmailAddress()
+ + ">\nDate: "
+ + dateFormatter.formatDate(third
+ .getAuthorIdent()) + "\n\n\tthird commit\n",
+ db.readSquashCommitMsg());
+ assertEquals("\nConflicts:\n\tfile2\n", db.readMergeCommitMsg());
- assertEquals(
- "Squashed commit of the following:\n\ncommit "
- + third.getName()
- + "\nAuthor: "
- + third.getAuthorIdent().getName()
- + " <"
- + third.getAuthorIdent().getEmailAddress()
- + ">\nDate: "
- + dateFormatter.formatDate(third
- .getAuthorIdent()) + "\n\n\tthird commit\n",
- db.readSquashCommitMsg());
- assertEquals("\nConflicts:\n\tfile2\n", db.readMergeCommitMsg());
-
- Status stat = git.status().call();
- assertEquals(Sets.of("file2"), stat.getConflicting());
+ Status stat = git.status().call();
+ assertEquals(Sets.of("file2"), stat.getConflicting());
+ }
}
@Test
public void testFastForwardOnly() throws Exception {
- Git git = new Git(db);
- RevCommit initialCommit = git.commit().setMessage("initial commit")
- .call();
- createBranch(initialCommit, "refs/heads/branch1");
- git.commit().setMessage("second commit").call();
- checkoutBranch("refs/heads/branch1");
+ try (Git git = new Git(db)) {
+ RevCommit initialCommit = git.commit().setMessage("initial commit")
+ .call();
+ createBranch(initialCommit, "refs/heads/branch1");
+ git.commit().setMessage("second commit").call();
+ checkoutBranch("refs/heads/branch1");
- MergeCommand merge = git.merge();
- merge.setFastForward(FastForwardMode.FF_ONLY);
- merge.include(db.getRef(Constants.MASTER));
- MergeResult result = merge.call();
+ MergeCommand merge = git.merge();
+ merge.setFastForward(FastForwardMode.FF_ONLY);
+ merge.include(db.exactRef(R_HEADS + MASTER));
+ MergeResult result = merge.call();
- assertEquals(MergeStatus.FAST_FORWARD, result.getMergeStatus());
+ assertEquals(MergeStatus.FAST_FORWARD, result.getMergeStatus());
+ }
}
@Test
public void testNoFastForward() throws Exception {
- Git git = new Git(db);
- RevCommit initialCommit = git.commit().setMessage("initial commit")
- .call();
- createBranch(initialCommit, "refs/heads/branch1");
- git.commit().setMessage("second commit").call();
- checkoutBranch("refs/heads/branch1");
+ try (Git git = new Git(db)) {
+ RevCommit initialCommit = git.commit().setMessage("initial commit")
+ .call();
+ createBranch(initialCommit, "refs/heads/branch1");
+ git.commit().setMessage("second commit").call();
+ checkoutBranch("refs/heads/branch1");
- MergeCommand merge = git.merge();
- merge.setFastForward(FastForwardMode.NO_FF);
- merge.include(db.getRef(Constants.MASTER));
- MergeResult result = merge.call();
+ MergeCommand merge = git.merge();
+ merge.setFastForward(FastForwardMode.NO_FF);
+ merge.include(db.exactRef(R_HEADS + MASTER));
+ MergeResult result = merge.call();
- assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ }
}
@Test
public void testNoFastForwardNoCommit() throws Exception {
// given
- Git git = new Git(db);
- RevCommit initialCommit = git.commit().setMessage("initial commit")
- .call();
- createBranch(initialCommit, "refs/heads/branch1");
- RevCommit secondCommit = git.commit().setMessage("second commit")
- .call();
- checkoutBranch("refs/heads/branch1");
+ try (Git git = new Git(db)) {
+ RevCommit initialCommit = git.commit().setMessage("initial commit")
+ .call();
+ createBranch(initialCommit, "refs/heads/branch1");
+ RevCommit secondCommit = git.commit().setMessage("second commit")
+ .call();
+ checkoutBranch("refs/heads/branch1");
- // when
- MergeCommand merge = git.merge();
- merge.setFastForward(FastForwardMode.NO_FF);
- merge.include(db.getRef(Constants.MASTER));
- merge.setCommit(false);
- MergeResult result = merge.call();
+ // when
+ MergeCommand merge = git.merge();
+ merge.setFastForward(FastForwardMode.NO_FF);
+ merge.include(db.exactRef(R_HEADS + MASTER));
+ merge.setCommit(false);
+ MergeResult result = merge.call();
- // then
- assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
- assertEquals(2, result.getMergedCommits().length);
- assertEquals(initialCommit, result.getMergedCommits()[0]);
- assertEquals(secondCommit, result.getMergedCommits()[1]);
- assertNull(result.getNewHead());
- assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState());
+ // then
+ assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
+ assertEquals(2, result.getMergedCommits().length);
+ assertEquals(initialCommit, result.getMergedCommits()[0]);
+ assertEquals(secondCommit, result.getMergedCommits()[1]);
+ assertNull(result.getNewHead());
+ assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState());
+ }
}
@Test
public void testFastForwardOnlyNotPossible() throws Exception {
- Git git = new Git(db);
- RevCommit initialCommit = git.commit().setMessage("initial commit")
- .call();
- createBranch(initialCommit, "refs/heads/branch1");
- git.commit().setMessage("second commit").call();
- checkoutBranch("refs/heads/branch1");
- writeTrashFile("file1", "branch1");
- git.add().addFilepattern("file").call();
- git.commit().setMessage("second commit on branch1").call();
- MergeCommand merge = git.merge();
- merge.setFastForward(FastForwardMode.FF_ONLY);
- merge.include(db.getRef(Constants.MASTER));
- MergeResult result = merge.call();
+ try (Git git = new Git(db)) {
+ RevCommit initialCommit = git.commit().setMessage("initial commit")
+ .call();
+ createBranch(initialCommit, "refs/heads/branch1");
+ git.commit().setMessage("second commit").call();
+ checkoutBranch("refs/heads/branch1");
+ writeTrashFile("file1", "branch1");
+ git.add().addFilepattern("file").call();
+ git.commit().setMessage("second commit on branch1").call();
+ MergeCommand merge = git.merge();
+ merge.setFastForward(FastForwardMode.FF_ONLY);
+ merge.include(db.exactRef(R_HEADS + MASTER));
+ MergeResult result = merge.call();
- assertEquals(MergeStatus.ABORTED, result.getMergeStatus());
+ assertEquals(MergeStatus.ABORTED, result.getMergeStatus());
+ }
}
@Test
@@ -1569,65 +1586,65 @@
@Test
public void testMergeWithMessageOption() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- git.add().addFilepattern("a").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("b", "1\nb\n3\n");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("side").call();
- writeTrashFile("b", "1\nb\n3\n");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("side").call();
+ checkoutBranch("refs/heads/master");
- checkoutBranch("refs/heads/master");
+ writeTrashFile("c", "1\nc\n3\n");
+ git.add().addFilepattern("c").call();
+ git.commit().setMessage("main").call();
- writeTrashFile("c", "1\nc\n3\n");
- git.add().addFilepattern("c").call();
- git.commit().setMessage("main").call();
+ Ref sideBranch = db.exactRef("refs/heads/side");
- Ref sideBranch = db.getRef("side");
+ git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
+ .setMessage("user message").call();
- git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
- .setMessage("user message").call();
+ assertNull(db.readMergeCommitMsg());
- assertNull(db.readMergeCommitMsg());
-
- Iterator<RevCommit> it = git.log().call().iterator();
- RevCommit newHead = it.next();
- assertEquals("user message", newHead.getFullMessage());
+ Iterator<RevCommit> it = git.log().call().iterator();
+ RevCommit newHead = it.next();
+ assertEquals("user message", newHead.getFullMessage());
+ }
}
@Test
public void testMergeConflictWithMessageOption() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- git.add().addFilepattern("a").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("a", "1\na(side)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("side").call();
- writeTrashFile("a", "1\na(side)\n3\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("side").call();
+ checkoutBranch("refs/heads/master");
- checkoutBranch("refs/heads/master");
+ writeTrashFile("a", "1\na(main)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("main").call();
- writeTrashFile("a", "1\na(main)\n3\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("main").call();
+ Ref sideBranch = db.exactRef("refs/heads/side");
- Ref sideBranch = db.getRef("side");
+ git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
+ .setMessage("user message").call();
- git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
- .setMessage("user message").call();
-
- assertEquals("user message\n\nConflicts:\n\ta\n",
- db.readMergeCommitMsg());
+ assertEquals("user message\n\nConflicts:\n\ta\n",
+ db.readMergeCommitMsg());
+ }
}
private static void setExecutable(Git git, String path, boolean executable) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NameRevCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NameRevCommandTest.java
index 4915954..bd62200 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NameRevCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/NameRevCommandTest.java
@@ -95,9 +95,9 @@
tr.update("refs/heads/master", c);
tr.update("refs/tags/tag", c);
assertOneResult("master",
- git.nameRev().addRef(db.getRef("refs/heads/master")), c);
+ git.nameRev().addRef(db.exactRef("refs/heads/master")), c);
assertOneResult("tag",
- git.nameRev().addRef(db.getRef("refs/tags/tag")), c);
+ git.nameRev().addRef(db.exactRef("refs/tags/tag")), c);
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
index db811cd..3343af0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
@@ -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.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 @@
private static final String FILE3 = "Test3.txt";
+ private static final String LINK = "link";
+
Git git;
RevCommit initialCommit;
@@ -99,6 +106,64 @@
}
@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();
File written = writeTrashFile(FILE1, "");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
index 57888e7..ff7066e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
@@ -140,11 +140,12 @@
ObjectId[] mergedCommits = mergeResult.getMergedCommits();
assertEquals(targetCommit.getId(), mergedCommits[0]);
assertEquals(sourceCommit.getId(), mergedCommits[1]);
- RevCommit mergeCommit = new RevWalk(dbTarget).parseCommit(mergeResult
- .getNewHead());
- String message = "Merge branch 'master' of "
- + db.getWorkTree().getAbsolutePath();
- assertEquals(message, mergeCommit.getShortMessage());
+ try (RevWalk rw = new RevWalk(dbTarget)) {
+ RevCommit mergeCommit = rw.parseCommit(mergeResult.getNewHead());
+ String message = "Merge branch 'master' of "
+ + db.getWorkTree().getAbsolutePath();
+ assertEquals(message, mergeCommit.getShortMessage());
+ }
}
@Test
@@ -259,11 +260,12 @@
ObjectId[] mergedCommits = mergeResult.getMergedCommits();
assertEquals(targetCommit.getId(), mergedCommits[0]);
assertEquals(sourceCommit.getId(), mergedCommits[1]);
- RevCommit mergeCommit = new RevWalk(dbTarget).parseCommit(mergeResult
- .getNewHead());
- String message = "Merge branch 'other' of "
- + db.getWorkTree().getAbsolutePath();
- assertEquals(message, mergeCommit.getShortMessage());
+ try (RevWalk rw = new RevWalk(dbTarget)) {
+ RevCommit mergeCommit = rw.parseCommit(mergeResult.getNewHead());
+ String message = "Merge branch 'other' of "
+ + db.getWorkTree().getAbsolutePath();
+ assertEquals(message, mergeCommit.getShortMessage());
+ }
}
@Test
@@ -293,11 +295,12 @@
ObjectId[] mergedCommits = mergeResult.getMergedCommits();
assertEquals(targetCommit.getId(), mergedCommits[0]);
assertEquals(sourceCommit.getId(), mergedCommits[1]);
- RevCommit mergeCommit = new RevWalk(dbTarget).parseCommit(mergeResult
- .getNewHead());
- String message = "Merge branch 'other' of "
- + db.getWorkTree().getAbsolutePath() + " into other";
- assertEquals(message, mergeCommit.getShortMessage());
+ try (RevWalk rw = new RevWalk(dbTarget)) {
+ RevCommit mergeCommit = rw.parseCommit(mergeResult.getNewHead());
+ String message = "Merge branch 'other' of "
+ + db.getWorkTree().getAbsolutePath() + " into other";
+ assertEquals(message, mergeCommit.getShortMessage());
+ }
}
private enum TestPullMode {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java
index 9ad845b..b405f6a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandWithRebaseTest.java
@@ -273,26 +273,27 @@
// Get the HEAD and HEAD~1 commits
Repository targetRepo = target.getRepository();
- RevWalk revWalk = new RevWalk(targetRepo);
- ObjectId headId = targetRepo.resolve(Constants.HEAD);
- RevCommit root = revWalk.parseCommit(headId);
- revWalk.markStart(root);
- // HEAD
- RevCommit head = revWalk.next();
- // HEAD~1
- RevCommit beforeHead = revWalk.next();
+ try (RevWalk revWalk = new RevWalk(targetRepo)) {
+ ObjectId headId = targetRepo.resolve(Constants.HEAD);
+ RevCommit root = revWalk.parseCommit(headId);
+ revWalk.markStart(root);
+ // HEAD
+ RevCommit head = revWalk.next();
+ // HEAD~1
+ RevCommit beforeHead = revWalk.next();
- // verify the commit message on the HEAD commit
- assertEquals(TARGET_COMMIT_MESSAGE, head.getFullMessage());
- // verify the commit just before HEAD
- assertEquals(SOURCE_COMMIT_MESSAGE, beforeHead.getFullMessage());
+ // verify the commit message on the HEAD commit
+ assertEquals(TARGET_COMMIT_MESSAGE, head.getFullMessage());
+ // verify the commit just before HEAD
+ assertEquals(SOURCE_COMMIT_MESSAGE, beforeHead.getFullMessage());
- // verify file states
- assertFileContentsEqual(sourceFile, SOURCE_FILE_CONTENTS);
- assertFileContentsEqual(newFile, NEW_FILE_CONTENTS);
- // verify repository state
- assertEquals(RepositoryState.SAFE, target
- .getRepository().getRepositoryState());
+ // verify file states
+ assertFileContentsEqual(sourceFile, SOURCE_FILE_CONTENTS);
+ assertFileContentsEqual(newFile, NEW_FILE_CONTENTS);
+ // verify repository state
+ assertEquals(RepositoryState.SAFE, target
+ .getRepository().getRepositoryState());
+ }
}
@Override
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
index 19f074e..2a32540 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
@@ -47,6 +47,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Properties;
@@ -55,7 +56,10 @@
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.hooks.PrePushHook;
+import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
@@ -66,6 +70,7 @@
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.TrackingRefUpdate;
import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.util.FS;
import org.junit.Test;
public class PushCommandTest extends RepositoryTestCase {
@@ -85,29 +90,71 @@
remoteConfig.update(config);
config.save();
- Git git1 = new Git(db);
- // create some refs via commits and tag
- RevCommit commit = git1.commit().setMessage("initial commit").call();
- Ref tagRef = git1.tag().setName("tag").call();
+ try (Git git1 = new Git(db)) {
+ // create some refs via commits and tag
+ RevCommit commit = git1.commit().setMessage("initial commit").call();
+ Ref tagRef = git1.tag().setName("tag").call();
- try {
- db2.resolve(commit.getId().getName() + "^{commit}");
- fail("id shouldn't exist yet");
- } catch (MissingObjectException e) {
- // we should get here
+ try {
+ db2.resolve(commit.getId().getName() + "^{commit}");
+ fail("id shouldn't exist yet");
+ } catch (MissingObjectException e) {
+ // we should get here
+ }
+
+ RefSpec spec = new RefSpec("refs/heads/master:refs/heads/x");
+ git1.push().setRemote("test").setRefSpecs(spec)
+ .call();
+
+ assertEquals(commit.getId(),
+ db2.resolve(commit.getId().getName() + "^{commit}"));
+ assertEquals(tagRef.getObjectId(),
+ db2.resolve(tagRef.getObjectId().getName()));
}
-
- RefSpec spec = new RefSpec("refs/heads/master:refs/heads/x");
- git1.push().setRemote("test").setRefSpecs(spec)
- .call();
-
- assertEquals(commit.getId(),
- db2.resolve(commit.getId().getName() + "^{commit}"));
- assertEquals(tagRef.getObjectId(),
- db2.resolve(tagRef.getObjectId().getName()));
}
@Test
+ public void testPrePushHook() throws JGitInternalException, IOException,
+ GitAPIException, URISyntaxException {
+
+ // create other repository
+ Repository db2 = createWorkRepository();
+
+ // setup the first repository
+ final StoredConfig config = db.getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(db2.getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.update(config);
+ config.save();
+
+ File hookOutput = new File(getTemporaryDirectory(), "hookOutput");
+ writeHookFile(PrePushHook.NAME, "#!/bin/sh\necho 1:$1, 2:$2, 3:$3 >\""
+ + hookOutput.toPath() + "\"\ncat - >>\"" + hookOutput.toPath()
+ + "\"\nexit 0");
+
+ try (Git git1 = new Git(db)) {
+ // create some refs via commits and tag
+ RevCommit commit = git1.commit().setMessage("initial commit").call();
+
+ RefSpec spec = new RefSpec("refs/heads/master:refs/heads/x");
+ git1.push().setRemote("test").setRefSpecs(spec).call();
+ assertEquals("1:test, 2:" + uri + ", 3:\n" + "refs/heads/master "
+ + commit.getName() + " refs/heads/x "
+ + ObjectId.zeroId().name(), read(hookOutput));
+ }
+ }
+
+ private File writeHookFile(final String name, final String data)
+ throws IOException {
+ File path = new File(db.getWorkTree() + "/.git/hooks/", name);
+ JGitTestUtil.write(path, data);
+ FS.DETECTED.setExecute(path, true);
+ return path;
+ }
+
+
+ @Test
public void testTrackingUpdate() throws Exception {
Repository db2 = createBareRepository();
@@ -115,45 +162,45 @@
String branch = "refs/heads/master";
String trackingBranch = "refs/remotes/" + remote + "/master";
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ RevCommit commit1 = git.commit().setMessage("Initial commit")
+ .call();
- RevCommit commit1 = git.commit().setMessage("Initial commit")
- .call();
+ RefUpdate branchRefUpdate = db.updateRef(branch);
+ branchRefUpdate.setNewObjectId(commit1.getId());
+ branchRefUpdate.update();
- RefUpdate branchRefUpdate = db.updateRef(branch);
- branchRefUpdate.setNewObjectId(commit1.getId());
- branchRefUpdate.update();
+ RefUpdate trackingBranchRefUpdate = db.updateRef(trackingBranch);
+ trackingBranchRefUpdate.setNewObjectId(commit1.getId());
+ trackingBranchRefUpdate.update();
- RefUpdate trackingBranchRefUpdate = db.updateRef(trackingBranch);
- trackingBranchRefUpdate.setNewObjectId(commit1.getId());
- trackingBranchRefUpdate.update();
-
- final StoredConfig config = db.getConfig();
- RemoteConfig remoteConfig = new RemoteConfig(config, remote);
- URIish uri = new URIish(db2.getDirectory().toURI().toURL());
- remoteConfig.addURI(uri);
- remoteConfig.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/"
- + remote + "/*"));
- remoteConfig.update(config);
- config.save();
+ final StoredConfig config = db.getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, remote);
+ URIish uri = new URIish(db2.getDirectory().toURI().toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/"
+ + remote + "/*"));
+ remoteConfig.update(config);
+ config.save();
- RevCommit commit2 = git.commit().setMessage("Commit to push").call();
+ RevCommit commit2 = git.commit().setMessage("Commit to push").call();
- RefSpec spec = new RefSpec(branch + ":" + branch);
- Iterable<PushResult> resultIterable = git.push().setRemote(remote)
- .setRefSpecs(spec).call();
+ RefSpec spec = new RefSpec(branch + ":" + branch);
+ Iterable<PushResult> resultIterable = git.push().setRemote(remote)
+ .setRefSpecs(spec).call();
- PushResult result = resultIterable.iterator().next();
- TrackingRefUpdate trackingRefUpdate = result
- .getTrackingRefUpdate(trackingBranch);
+ PushResult result = resultIterable.iterator().next();
+ TrackingRefUpdate trackingRefUpdate = result
+ .getTrackingRefUpdate(trackingBranch);
- assertNotNull(trackingRefUpdate);
- assertEquals(trackingBranch, trackingRefUpdate.getLocalName());
- assertEquals(branch, trackingRefUpdate.getRemoteName());
- assertEquals(commit2.getId(), trackingRefUpdate.getNewObjectId());
- assertEquals(commit2.getId(), db.resolve(trackingBranch));
- assertEquals(commit2.getId(), db2.resolve(branch));
+ assertNotNull(trackingRefUpdate);
+ assertEquals(trackingBranch, trackingRefUpdate.getLocalName());
+ assertEquals(branch, trackingRefUpdate.getRemoteName());
+ assertEquals(commit2.getId(), trackingRefUpdate.getNewObjectId());
+ assertEquals(commit2.getId(), db.resolve(trackingBranch));
+ assertEquals(commit2.getId(), db2.resolve(branch));
+ }
}
/**
@@ -163,40 +210,38 @@
*/
@Test
public void testPushRefUpdate() throws Exception {
- Git git = new Git(db);
- Git git2 = new Git(createBareRepository());
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ final StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(git2.getRepository().getDirectory().toURI()
+ .toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addPushRefSpec(new RefSpec("+refs/heads/*:refs/heads/*"));
+ remoteConfig.update(config);
+ config.save();
- final StoredConfig config = git.getRepository().getConfig();
- RemoteConfig remoteConfig = new RemoteConfig(config, "test");
- URIish uri = new URIish(git2.getRepository().getDirectory().toURI()
- .toURL());
- remoteConfig.addURI(uri);
- remoteConfig.addPushRefSpec(new RefSpec("+refs/heads/*:refs/heads/*"));
- remoteConfig.update(config);
- config.save();
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ RevCommit commit = git.commit().setMessage("adding f").call();
- writeTrashFile("f", "content of f");
- git.add().addFilepattern("f").call();
- RevCommit commit = git.commit().setMessage("adding f").call();
-
- assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
- git.push().setRemote("test").call();
- assertEquals(commit.getId(),
- git2.getRepository().resolve("refs/heads/master"));
-
- git.branchCreate().setName("refs/heads/test").call();
- git.checkout().setName("refs/heads/test").call();
-
-
- for (int i = 0; i < 6; i++) {
- writeTrashFile("f" + i, "content of f" + i);
- git.add().addFilepattern("f" + i).call();
- commit = git.commit().setMessage("adding f" + i).call();
+ assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
git.push().setRemote("test").call();
- git2.getRepository().getAllRefs();
- assertEquals("failed to update on attempt " + i, commit.getId(),
- git2.getRepository().resolve("refs/heads/test"));
+ assertEquals(commit.getId(),
+ git2.getRepository().resolve("refs/heads/master"));
+ git.branchCreate().setName("refs/heads/test").call();
+ git.checkout().setName("refs/heads/test").call();
+
+ for (int i = 0; i < 6; i++) {
+ writeTrashFile("f" + i, "content of f" + i);
+ git.add().addFilepattern("f" + i).call();
+ commit = git.commit().setMessage("adding f" + i).call();
+ git.push().setRemote("test").call();
+ git2.getRepository().getAllRefs();
+ assertEquals("failed to update on attempt " + i, commit.getId(),
+ git2.getRepository().resolve("refs/heads/test"));
+ }
}
}
@@ -207,28 +252,26 @@
*/
@Test
public void testPushWithRefSpecFromConfig() throws Exception {
- Git git = new Git(db);
- Git git2 = new Git(createBareRepository());
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ final StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(git2.getRepository().getDirectory().toURI()
+ .toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addPushRefSpec(new RefSpec("HEAD:refs/heads/newbranch"));
+ remoteConfig.update(config);
+ config.save();
- final StoredConfig config = git.getRepository().getConfig();
- RemoteConfig remoteConfig = new RemoteConfig(config, "test");
- URIish uri = new URIish(git2.getRepository().getDirectory().toURI()
- .toURL());
- remoteConfig.addURI(uri);
- remoteConfig.addPushRefSpec(new RefSpec("HEAD:refs/heads/newbranch"));
- remoteConfig.update(config);
- config.save();
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ RevCommit commit = git.commit().setMessage("adding f").call();
- writeTrashFile("f", "content of f");
- git.add().addFilepattern("f").call();
- RevCommit commit = git.commit().setMessage("adding f").call();
-
- assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
- git.push().setRemote("test").call();
- assertEquals(commit.getId(),
- git2.getRepository().resolve("refs/heads/newbranch"));
-
-
+ assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
+ git.push().setRemote("test").call();
+ assertEquals(commit.getId(),
+ git2.getRepository().resolve("refs/heads/newbranch"));
+ }
}
/**
@@ -238,38 +281,37 @@
*/
@Test
public void testPushWithoutPushRefSpec() throws Exception {
- Git git = new Git(db);
- Git git2 = new Git(createBareRepository());
+ try (Git git = new Git(db);
+ Git git2 = new Git(createBareRepository())) {
+ final StoredConfig config = git.getRepository().getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+ URIish uri = new URIish(git2.getRepository().getDirectory().toURI()
+ .toURL());
+ remoteConfig.addURI(uri);
+ remoteConfig.addFetchRefSpec(new RefSpec(
+ "+refs/heads/*:refs/remotes/origin/*"));
+ remoteConfig.update(config);
+ config.save();
- final StoredConfig config = git.getRepository().getConfig();
- RemoteConfig remoteConfig = new RemoteConfig(config, "test");
- URIish uri = new URIish(git2.getRepository().getDirectory().toURI()
- .toURL());
- remoteConfig.addURI(uri);
- remoteConfig.addFetchRefSpec(new RefSpec(
- "+refs/heads/*:refs/remotes/origin/*"));
- remoteConfig.update(config);
- config.save();
+ writeTrashFile("f", "content of f");
+ git.add().addFilepattern("f").call();
+ RevCommit commit = git.commit().setMessage("adding f").call();
- writeTrashFile("f", "content of f");
- git.add().addFilepattern("f").call();
- RevCommit commit = git.commit().setMessage("adding f").call();
+ git.checkout().setName("not-pushed").setCreateBranch(true).call();
+ git.checkout().setName("branchtopush").setCreateBranch(true).call();
- git.checkout().setName("not-pushed").setCreateBranch(true).call();
- git.checkout().setName("branchtopush").setCreateBranch(true).call();
-
- assertEquals(null,
- git2.getRepository().resolve("refs/heads/branchtopush"));
- assertEquals(null, git2.getRepository()
- .resolve("refs/heads/not-pushed"));
- assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
- git.push().setRemote("test").call();
- assertEquals(commit.getId(),
- git2.getRepository().resolve("refs/heads/branchtopush"));
- assertEquals(null, git2.getRepository()
- .resolve("refs/heads/not-pushed"));
- assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
-
+ assertEquals(null,
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null, git2.getRepository()
+ .resolve("refs/heads/not-pushed"));
+ assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
+ git.push().setRemote("test").call();
+ assertEquals(commit.getId(),
+ git2.getRepository().resolve("refs/heads/branchtopush"));
+ assertEquals(null, git2.getRepository()
+ .resolve("refs/heads/not-pushed"));
+ assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
+ }
}
/**
@@ -290,51 +332,51 @@
remoteConfig.update(config);
config.save();
- Git git1 = new Git(db);
- Git git2 = new Git(db2);
+ try (Git git1 = new Git(db);
+ Git git2 = new Git(db2)) {
+ // push master (with a new commit) to the remote
+ git1.commit().setMessage("initial commit").call();
- // push master (with a new commit) to the remote
- git1.commit().setMessage("initial commit").call();
-
- RefSpec spec = new RefSpec("refs/heads/*:refs/heads/*");
- git1.push().setRemote("test").setRefSpecs(spec).call();
-
- // create an unrelated ref and a commit on our remote
- git2.branchCreate().setName("refs/heads/other").call();
- git2.checkout().setName("refs/heads/other").call();
-
- writeTrashFile("a", "content of a");
- git2.add().addFilepattern("a").call();
- RevCommit commit2 = git2.commit().setMessage("adding a").call();
-
- // run a gc to ensure we have a bitmap index
- Properties res = git1.gc().setExpire(null).call();
- assertEquals(7, res.size());
-
- // create another commit so we have something else to push
- writeTrashFile("b", "content of b");
- git1.add().addFilepattern("b").call();
- RevCommit commit3 = git1.commit().setMessage("adding b").call();
-
- try {
- // Re-run the push. Failure may happen here.
+ RefSpec spec = new RefSpec("refs/heads/*:refs/heads/*");
git1.push().setRemote("test").setRefSpecs(spec).call();
- } catch (TransportException e) {
- assertTrue("should be caused by a MissingObjectException", e
- .getCause().getCause() instanceof MissingObjectException);
- fail("caught MissingObjectException for a change we don't have");
- }
- // Remote will have both a and b. Master will have only b
- try {
- db.resolve(commit2.getId().getName() + "^{commit}");
- fail("id shouldn't exist locally");
- } catch (MissingObjectException e) {
- // we should get here
+ // create an unrelated ref and a commit on our remote
+ git2.branchCreate().setName("refs/heads/other").call();
+ git2.checkout().setName("refs/heads/other").call();
+
+ writeTrashFile("a", "content of a");
+ git2.add().addFilepattern("a").call();
+ RevCommit commit2 = git2.commit().setMessage("adding a").call();
+
+ // run a gc to ensure we have a bitmap index
+ Properties res = git1.gc().setExpire(null).call();
+ assertEquals(7, res.size());
+
+ // create another commit so we have something else to push
+ writeTrashFile("b", "content of b");
+ git1.add().addFilepattern("b").call();
+ RevCommit commit3 = git1.commit().setMessage("adding b").call();
+
+ try {
+ // Re-run the push. Failure may happen here.
+ git1.push().setRemote("test").setRefSpecs(spec).call();
+ } catch (TransportException e) {
+ assertTrue("should be caused by a MissingObjectException", e
+ .getCause().getCause() instanceof MissingObjectException);
+ fail("caught MissingObjectException for a change we don't have");
+ }
+
+ // Remote will have both a and b. Master will have only b
+ try {
+ db.resolve(commit2.getId().getName() + "^{commit}");
+ fail("id shouldn't exist locally");
+ } catch (MissingObjectException e) {
+ // we should get here
+ }
+ assertEquals(commit2.getId(),
+ db2.resolve(commit2.getId().getName() + "^{commit}"));
+ assertEquals(commit3.getId(),
+ db2.resolve(commit3.getId().getName() + "^{commit}"));
}
- assertEquals(commit2.getId(),
- db2.resolve(commit2.getId().getName() + "^{commit}"));
- assertEquals(commit3.getId(),
- db2.resolve(commit3.getId().getName() + "^{commit}"));
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
index 8b0ed5f..24cb522 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
@@ -288,13 +288,14 @@
RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
assertEquals(Status.OK, res.getStatus());
- RevWalk rw = new RevWalk(db);
- rw.markStart(rw.parseCommit(db.resolve("refs/heads/topic")));
- assertDerivedFrom(rw.next(), e);
- assertDerivedFrom(rw.next(), d);
- assertDerivedFrom(rw.next(), c);
- assertEquals(b, rw.next());
- assertEquals(a, rw.next());
+ try (RevWalk rw = new RevWalk(db)) {
+ rw.markStart(rw.parseCommit(db.resolve("refs/heads/topic")));
+ assertDerivedFrom(rw.next(), e);
+ assertDerivedFrom(rw.next(), d);
+ assertDerivedFrom(rw.next(), c);
+ assertEquals(b, rw.next());
+ assertEquals(a, rw.next());
+ }
List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
.getReverseEntries();
@@ -354,8 +355,6 @@
*/
private void doTestRebasePreservingMerges(boolean testConflict)
throws Exception {
- RevWalk rw = new RevWalk(db);
-
// create file1 on master
writeTrashFile(FILE1, FILE1);
git.add().addFilepattern(FILE1).call();
@@ -409,7 +408,9 @@
f = git.commit().setMessage("commit f").call();
} else {
assertEquals(MergeStatus.MERGED, result.getMergeStatus());
- f = rw.parseCommit(result.getNewHead());
+ try (RevWalk rw = new RevWalk(db)) {
+ f = rw.parseCommit(result.getNewHead());
+ }
}
RebaseResult res = git.rebase().setUpstream("refs/heads/master")
@@ -453,23 +454,25 @@
assertEquals("file2", read("file2"));
assertEquals("more change", read("file3"));
- rw.markStart(rw.parseCommit(db.resolve("refs/heads/topic")));
- RevCommit newF = rw.next();
- assertDerivedFrom(newF, f);
- assertEquals(2, newF.getParentCount());
- RevCommit newD = rw.next();
- assertDerivedFrom(newD, d);
- if (testConflict)
- assertEquals("d new", readFile("conflict", newD));
- RevCommit newE = rw.next();
- assertDerivedFrom(newE, e);
- if (testConflict)
- assertEquals("e new", readFile("conflict", newE));
- assertEquals(newD, newF.getParent(0));
- assertEquals(newE, newF.getParent(1));
- assertDerivedFrom(rw.next(), c);
- assertEquals(b, rw.next());
- assertEquals(a, rw.next());
+ try (RevWalk rw = new RevWalk(db)) {
+ rw.markStart(rw.parseCommit(db.resolve("refs/heads/topic")));
+ RevCommit newF = rw.next();
+ assertDerivedFrom(newF, f);
+ assertEquals(2, newF.getParentCount());
+ RevCommit newD = rw.next();
+ assertDerivedFrom(newD, d);
+ if (testConflict)
+ assertEquals("d new", readFile("conflict", newD));
+ RevCommit newE = rw.next();
+ assertDerivedFrom(newE, e);
+ if (testConflict)
+ assertEquals("e new", readFile("conflict", newE));
+ assertEquals(newD, newF.getParent(0));
+ assertEquals(newE, newF.getParent(1));
+ assertDerivedFrom(rw.next(), c);
+ assertEquals(b, rw.next());
+ assertEquals(a, rw.next());
+ }
}
private String readFile(String path, RevCommit commit) throws IOException {
@@ -517,88 +520,89 @@
*/
private void doTestRebasePreservingMergesWithUnrelatedSide(
boolean testConflict) throws Exception {
- RevWalk rw = new RevWalk(db);
- rw.sort(RevSort.TOPO);
+ try (RevWalk rw = new RevWalk(db)) {
+ rw.sort(RevSort.TOPO);
- writeTrashFile(FILE1, FILE1);
- git.add().addFilepattern(FILE1).call();
- RevCommit a = git.commit().setMessage("commit a").call();
+ writeTrashFile(FILE1, FILE1);
+ git.add().addFilepattern(FILE1).call();
+ RevCommit a = git.commit().setMessage("commit a").call();
- writeTrashFile("file2", "blah");
- git.add().addFilepattern("file2").call();
- RevCommit b = git.commit().setMessage("commit b").call();
+ writeTrashFile("file2", "blah");
+ git.add().addFilepattern("file2").call();
+ RevCommit b = git.commit().setMessage("commit b").call();
- // create a topic branch
- createBranch(b, "refs/heads/topic");
- checkoutBranch("refs/heads/topic");
+ // create a topic branch
+ createBranch(b, "refs/heads/topic");
+ checkoutBranch("refs/heads/topic");
- writeTrashFile("file3", "more changess");
- writeTrashFile(FILE1, "preparing conflict");
- git.add().addFilepattern("file3").addFilepattern(FILE1).call();
- RevCommit c = git.commit().setMessage("commit c").call();
+ writeTrashFile("file3", "more changess");
+ writeTrashFile(FILE1, "preparing conflict");
+ git.add().addFilepattern("file3").addFilepattern(FILE1).call();
+ RevCommit c = git.commit().setMessage("commit c").call();
- createBranch(a, "refs/heads/side");
- checkoutBranch("refs/heads/side");
- writeTrashFile("conflict", "e");
- writeTrashFile(FILE1, FILE1 + "\n" + "line 2");
- git.add().addFilepattern(".").call();
- RevCommit e = git.commit().setMessage("commit e").call();
-
- // switch back to topic and merge in side, creating d
- checkoutBranch("refs/heads/topic");
- MergeResult result = git.merge().include(e)
- .setStrategy(MergeStrategy.RESOLVE).call();
-
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- assertEquals(result.getConflicts().keySet(),
- Collections.singleton(FILE1));
- writeTrashFile(FILE1, "merge resolution");
- git.add().addFilepattern(FILE1).call();
- RevCommit d = git.commit().setMessage("commit d").call();
-
- RevCommit f = commitFile("file2", "new content two", "topic");
-
- checkoutBranch("refs/heads/master");
- writeTrashFile("fileg", "fileg");
- if (testConflict)
- writeTrashFile("conflict", "g");
- git.add().addFilepattern(".").call();
- RevCommit g = git.commit().setMessage("commit g").call();
-
- checkoutBranch("refs/heads/topic");
- RebaseResult res = git.rebase().setUpstream("refs/heads/master")
- .setPreserveMerges(true).call();
- if (testConflict) {
- assertEquals(Status.STOPPED, res.getStatus());
- assertEquals(Collections.singleton("conflict"), git.status().call()
- .getConflicting());
- // resolve
+ createBranch(a, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
writeTrashFile("conflict", "e");
- git.add().addFilepattern("conflict").call();
- res = git.rebase().setOperation(Operation.CONTINUE).call();
+ writeTrashFile(FILE1, FILE1 + "\n" + "line 2");
+ git.add().addFilepattern(".").call();
+ RevCommit e = git.commit().setMessage("commit e").call();
+
+ // switch back to topic and merge in side, creating d
+ checkoutBranch("refs/heads/topic");
+ MergeResult result = git.merge().include(e)
+ .setStrategy(MergeStrategy.RESOLVE).call();
+
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ assertEquals(result.getConflicts().keySet(),
+ Collections.singleton(FILE1));
+ writeTrashFile(FILE1, "merge resolution");
+ git.add().addFilepattern(FILE1).call();
+ RevCommit d = git.commit().setMessage("commit d").call();
+
+ RevCommit f = commitFile("file2", "new content two", "topic");
+
+ checkoutBranch("refs/heads/master");
+ writeTrashFile("fileg", "fileg");
+ if (testConflict)
+ writeTrashFile("conflict", "g");
+ git.add().addFilepattern(".").call();
+ RevCommit g = git.commit().setMessage("commit g").call();
+
+ checkoutBranch("refs/heads/topic");
+ RebaseResult res = git.rebase().setUpstream("refs/heads/master")
+ .setPreserveMerges(true).call();
+ if (testConflict) {
+ assertEquals(Status.STOPPED, res.getStatus());
+ assertEquals(Collections.singleton("conflict"), git.status().call()
+ .getConflicting());
+ // resolve
+ writeTrashFile("conflict", "e");
+ git.add().addFilepattern("conflict").call();
+ res = git.rebase().setOperation(Operation.CONTINUE).call();
+ }
+ assertEquals(Status.OK, res.getStatus());
+
+ assertEquals("merge resolution", read(FILE1));
+ assertEquals("new content two", read("file2"));
+ assertEquals("more changess", read("file3"));
+ assertEquals("fileg", read("fileg"));
+
+ rw.markStart(rw.parseCommit(db.resolve("refs/heads/topic")));
+ RevCommit newF = rw.next();
+ assertDerivedFrom(newF, f);
+ RevCommit newD = rw.next();
+ assertDerivedFrom(newD, d);
+ assertEquals(2, newD.getParentCount());
+ RevCommit newC = rw.next();
+ assertDerivedFrom(newC, c);
+ RevCommit newE = rw.next();
+ assertEquals(e, newE);
+ assertEquals(newC, newD.getParent(0));
+ assertEquals(e, newD.getParent(1));
+ assertEquals(g, rw.next());
+ assertEquals(b, rw.next());
+ assertEquals(a, rw.next());
}
- assertEquals(Status.OK, res.getStatus());
-
- assertEquals("merge resolution", read(FILE1));
- assertEquals("new content two", read("file2"));
- assertEquals("more changess", read("file3"));
- assertEquals("fileg", read("fileg"));
-
- rw.markStart(rw.parseCommit(db.resolve("refs/heads/topic")));
- RevCommit newF = rw.next();
- assertDerivedFrom(newF, f);
- RevCommit newD = rw.next();
- assertDerivedFrom(newD, d);
- assertEquals(2, newD.getParentCount());
- RevCommit newC = rw.next();
- assertDerivedFrom(newC, c);
- RevCommit newE = rw.next();
- assertEquals(e, newE);
- assertEquals(newC, newD.getParent(0));
- assertEquals(e, newD.getParent(1));
- assertEquals(g, rw.next());
- assertEquals(b, rw.next());
- assertEquals(a, rw.next());
}
@Test
@@ -687,8 +691,10 @@
checkFile(theFile, "1master\n2\n3\ntopic\n");
// our old branch should be checked out again
assertEquals("refs/heads/topic", db.getFullBranch());
- assertEquals(lastMasterChange, new RevWalk(db).parseCommit(
- db.resolve(Constants.HEAD)).getParent(0));
+ try (RevWalk rw = new RevWalk(db)) {
+ assertEquals(lastMasterChange, rw.parseCommit(
+ db.resolve(Constants.HEAD)).getParent(0));
+ }
assertEquals(origHead, db.readOrigHead());
List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
.getReverseEntries();
@@ -737,8 +743,10 @@
RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
assertEquals(Status.OK, res.getStatus());
checkFile(theFile, "1master\n2\n3\ntopic\n");
- assertEquals(lastMasterChange, new RevWalk(db).parseCommit(
- db.resolve(Constants.HEAD)).getParent(0));
+ try (RevWalk rw = new RevWalk(db)) {
+ assertEquals(lastMasterChange, rw.parseCommit(
+ db.resolve(Constants.HEAD)).getParent(0));
+ }
List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
.getReverseEntries();
@@ -785,8 +793,10 @@
// our old branch should be checked out again
assertEquals("refs/heads/file3", db.getFullBranch());
- assertEquals(addFile2, new RevWalk(db).parseCommit(
- db.resolve(Constants.HEAD)).getParent(0));
+ try (RevWalk rw = new RevWalk(db)) {
+ assertEquals(addFile2, rw.parseCommit(
+ db.resolve(Constants.HEAD)).getParent(0));
+ }
checkoutBranch("refs/heads/file2");
assertTrue(new File(db.getWorkTree(), FILE1).exists());
@@ -846,9 +856,10 @@
assertEquals(res.getStatus(), Status.ABORTED);
assertEquals("refs/heads/topic", db.getFullBranch());
checkFile(FILE1, "1topic", "2", "3", "topic4");
- RevWalk rw = new RevWalk(db);
- assertEquals(lastTopicCommit, rw
- .parseCommit(db.resolve(Constants.HEAD)));
+ try (RevWalk rw = new RevWalk(db)) {
+ assertEquals(lastTopicCommit,
+ rw.parseCommit(db.resolve(Constants.HEAD)));
+ }
assertEquals(RepositoryState.SAFE, db.getRepositoryState());
// rebase- dir in .git must be deleted
@@ -909,9 +920,10 @@
assertEquals(res.getStatus(), Status.ABORTED);
assertEquals(lastTopicCommit.getName(), db.getFullBranch());
checkFile(FILE1, "1topic", "2", "3", "topic4");
- RevWalk rw = new RevWalk(db);
- assertEquals(lastTopicCommit,
- rw.parseCommit(db.resolve(Constants.HEAD)));
+ try (RevWalk rw = new RevWalk(db)) {
+ assertEquals(lastTopicCommit,
+ rw.parseCommit(db.resolve(Constants.HEAD)));
+ }
assertEquals(RepositoryState.SAFE, db.getRepositoryState());
// rebase- dir in .git must be deleted
@@ -966,11 +978,12 @@
assertEquals(RepositoryState.SAFE, db.getRepositoryState());
ObjectId headId = db.resolve(Constants.HEAD);
- RevWalk rw = new RevWalk(db);
- RevCommit rc = rw.parseCommit(headId);
- RevCommit parent = rw.parseCommit(rc.getParent(0));
- assertEquals("change file1 in topic\n\nThis is conflicting", parent
- .getFullMessage());
+ try (RevWalk rw = new RevWalk(db)) {
+ RevCommit rc = rw.parseCommit(headId);
+ RevCommit parent = rw.parseCommit(rc.getParent(0));
+ assertEquals("change file1 in topic\n\nThis is conflicting", parent
+ .getFullMessage());
+ }
}
@Test
@@ -1017,9 +1030,10 @@
git.rebase().setOperation(Operation.SKIP).call();
ObjectId headId = db.resolve(Constants.HEAD);
- RevWalk rw = new RevWalk(db);
- RevCommit rc = rw.parseCommit(headId);
- assertEquals("change file1 in master", rc.getFullMessage());
+ try (RevWalk rw = new RevWalk(db)) {
+ RevCommit rc = rw.parseCommit(headId);
+ assertEquals("change file1 in master", rc.getFullMessage());
+ }
}
@Test
@@ -1308,10 +1322,11 @@
git.rebase().setOperation(Operation.SKIP).call();
ObjectId headId = db.resolve(Constants.HEAD);
- RevWalk rw = new RevWalk(db);
- RevCommit rc = rw.parseCommit(headId);
- RevCommit parent = rw.parseCommit(rc.getParent(0));
- assertEquals("A different commit message", parent.getFullMessage());
+ try (RevWalk rw = new RevWalk(db)) {
+ RevCommit rc = rw.parseCommit(headId);
+ RevCommit parent = rw.parseCommit(rc.getParent(0));
+ assertEquals("A different commit message", parent.getFullMessage());
+ }
}
private RevCommit writeFileAndCommit(String fileName, String commitMessage,
@@ -1420,9 +1435,10 @@
res = git.rebase().setOperation(Operation.ABORT).call();
assertEquals(res.getStatus(), Status.ABORTED);
assertEquals("refs/heads/topic", db.getFullBranch());
- RevWalk rw = new RevWalk(db);
- assertEquals(conflicting, rw.parseCommit(db.resolve(Constants.HEAD)));
- assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ try (RevWalk rw = new RevWalk(db)) {
+ assertEquals(conflicting, rw.parseCommit(db.resolve(Constants.HEAD)));
+ assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ }
// rebase- dir in .git must be deleted
assertFalse(new File(db.getDirectory(), "rebase-merge").exists());
@@ -2286,14 +2302,15 @@
assertEquals(RebaseResult.Status.OK, res2.getStatus());
ObjectId headId = db.resolve(Constants.HEAD);
- RevWalk rw = new RevWalk(db);
- RevCommit rc = rw.parseCommit(headId);
+ try (RevWalk rw = new RevWalk(db)) {
+ RevCommit rc = rw.parseCommit(headId);
- ObjectId head1Id = db.resolve(Constants.HEAD + "~1");
- RevCommit rc1 = rw.parseCommit(head1Id);
+ ObjectId head1Id = db.resolve(Constants.HEAD + "~1");
+ RevCommit rc1 = rw.parseCommit(head1Id);
- assertEquals(rc.getFullMessage(), c4.getFullMessage());
- assertEquals(rc1.getFullMessage(), c2.getFullMessage());
+ assertEquals(rc.getFullMessage(), c4.getFullMessage());
+ assertEquals(rc1.getFullMessage(), c2.getFullMessage());
+ }
}
@Test
@@ -2643,15 +2660,16 @@
}
}).call();
- RevWalk walk = new RevWalk(db);
- ObjectId headId = db.resolve(Constants.HEAD);
- RevCommit headCommit = walk.parseCommit(headId);
- assertEquals(headCommit.getFullMessage(),
- "update file2 on master\nnew line");
+ try (RevWalk walk = new RevWalk(db)) {
+ ObjectId headId = db.resolve(Constants.HEAD);
+ RevCommit headCommit = walk.parseCommit(headId);
+ assertEquals(headCommit.getFullMessage(),
+ "update file2 on master\nnew line");
- ObjectId head2Id = db.resolve(Constants.HEAD + "^1");
- RevCommit head1Commit = walk.parseCommit(head2Id);
- assertEquals("changed", head1Commit.getFullMessage());
+ ObjectId head2Id = db.resolve(Constants.HEAD + "^1");
+ RevCommit head1Commit = walk.parseCommit(head2Id);
+ assertEquals("changed", head1Commit.getFullMessage());
+ }
}
@Test
@@ -2722,17 +2740,18 @@
}
}).call();
- RevWalk walk = new RevWalk(db);
- ObjectId headId = db.resolve(Constants.HEAD);
- RevCommit headCommit = walk.parseCommit(headId);
- assertEquals(headCommit.getFullMessage(),
- "update file2 on master\nnew line");
+ try (RevWalk walk = new RevWalk(db)) {
+ ObjectId headId = db.resolve(Constants.HEAD);
+ RevCommit headCommit = walk.parseCommit(headId);
+ assertEquals(headCommit.getFullMessage(),
+ "update file2 on master\nnew line");
- ObjectId head2Id = db.resolve(Constants.HEAD + "^1");
- RevCommit head1Commit = walk.parseCommit(head2Id);
- assertEquals(
- "Add file1\nnew line\nAdd file2\nnew line\nupdated file1 on master\nnew line",
- head1Commit.getFullMessage());
+ ObjectId head2Id = db.resolve(Constants.HEAD + "^1");
+ RevCommit head1Commit = walk.parseCommit(head2Id);
+ assertEquals(
+ "Add file1\nnew line\nAdd file2\nnew line\nupdated file1 on master\nnew line",
+ head1Commit.getFullMessage());
+ }
}
@Test
@@ -2804,15 +2823,16 @@
}
}).call();
- RevWalk walk = new RevWalk(db);
- ObjectId headId = db.resolve(Constants.HEAD);
- RevCommit headCommit = walk.parseCommit(headId);
- assertEquals(headCommit.getFullMessage(),
- "update file2 on master\nnew line");
+ try (RevWalk walk = new RevWalk(db)) {
+ ObjectId headId = db.resolve(Constants.HEAD);
+ RevCommit headCommit = walk.parseCommit(headId);
+ assertEquals(headCommit.getFullMessage(),
+ "update file2 on master\nnew line");
- ObjectId head2Id = db.resolve(Constants.HEAD + "^1");
- RevCommit head1Commit = walk.parseCommit(head2Id);
- assertEquals("changed", head1Commit.getFullMessage());
+ ObjectId head2Id = db.resolve(Constants.HEAD + "^1");
+ RevCommit head1Commit = walk.parseCommit(head2Id);
+ assertEquals("changed", head1Commit.getFullMessage());
+ }
}
@Test
@@ -2855,16 +2875,17 @@
}
}).call();
- RevWalk walk = new RevWalk(db);
- ObjectId headId = db.resolve(Constants.HEAD);
- RevCommit headCommit = walk.parseCommit(headId);
- assertEquals("update file2 on master\nnew line",
- headCommit.getFullMessage());
+ try (RevWalk walk = new RevWalk(db)) {
+ ObjectId headId = db.resolve(Constants.HEAD);
+ RevCommit headCommit = walk.parseCommit(headId);
+ assertEquals("update file2 on master\nnew line",
+ headCommit.getFullMessage());
- ObjectId head1Id = db.resolve(Constants.HEAD + "^1");
- RevCommit head1Commit = walk.parseCommit(head1Id);
- assertEquals("Add file2\nnew line",
- head1Commit.getFullMessage());
+ ObjectId head1Id = db.resolve(Constants.HEAD + "^1");
+ RevCommit head1Commit = walk.parseCommit(head1Id);
+ assertEquals("Add file2\nnew line",
+ head1Commit.getFullMessage());
+ }
}
@Test
@@ -2903,11 +2924,12 @@
}
}).call();
- RevWalk walk = new RevWalk(db);
- ObjectId headId = db.resolve(Constants.HEAD);
- RevCommit headCommit = walk.parseCommit(headId);
- assertEquals("Add file2",
- headCommit.getFullMessage());
+ try (RevWalk walk = new RevWalk(db)) {
+ ObjectId headId = db.resolve(Constants.HEAD);
+ RevCommit headCommit = walk.parseCommit(headId);
+ assertEquals("Add file2",
+ headCommit.getFullMessage());
+ }
}
@Test(expected = InvalidRebaseStepException.class)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteAddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteAddCommandTest.java
new file mode 100644
index 0000000..ed09446
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteAddCommandTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.RemoteConfig;
+import org.eclipse.jgit.transport.URIish;
+import org.junit.Test;
+
+public class RemoteAddCommandTest extends AbstractRemoteCommandTest {
+
+ @Test
+ public void testAdd() throws Exception {
+ // create another repository
+ Repository remoteRepository = createWorkRepository();
+ URIish uri = new URIish(
+ remoteRepository.getDirectory().toURI().toURL());
+
+ // execute the command to add a new remote
+ RemoteAddCommand cmd = Git.wrap(db).remoteAdd();
+ cmd.setName(REMOTE_NAME);
+ cmd.setUri(uri);
+ RemoteConfig remote = cmd.call();
+
+ // assert that the added remote represents the remote repository
+ assertEquals(REMOTE_NAME, remote.getName());
+ assertArrayEquals(new URIish[] { uri }, remote.getURIs().toArray());
+ assertEquals(1, remote.getFetchRefSpecs().size());
+ assertEquals(
+ String.format("+refs/heads/*:refs/remotes/%s/*", REMOTE_NAME),
+ remote.getFetchRefSpecs().get(0).toString());
+
+ // assert that the added remote is available in the git configuration
+ assertRemoteConfigEquals(remote,
+ new RemoteConfig(db.getConfig(), REMOTE_NAME));
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java
new file mode 100644
index 0000000..7055daf
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteDeleteCommandTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.jgit.transport.RemoteConfig;
+import org.junit.Test;
+
+public class RemoteDeleteCommandTest extends AbstractRemoteCommandTest {
+
+ @Test
+ public void testDelete() throws Exception {
+ // setup an initial remote
+ RemoteConfig remoteConfig = setupRemote();
+
+ // execute the command to remove the remote
+ RemoteRemoveCommand cmd = Git.wrap(db).remoteRemove();
+ cmd.setName(REMOTE_NAME);
+ RemoteConfig remote = cmd.call();
+
+ // assert that the removed remote is the initial remote
+ assertRemoteConfigEquals(remoteConfig, remote);
+ // assert that there are no remotes left
+ assertTrue(RemoteConfig.getAllRemoteConfigs(db.getConfig()).isEmpty());
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteListCommandTest.java
similarity index 60%
copy from org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
copy to org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteListCommandTest.java
index c7e41bc..cf522ff 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteListCommandTest.java
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006-2007, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -41,45 +40,29 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+package org.eclipse.jgit.api;
-package org.eclipse.jgit.lib;
+import static org.junit.Assert.assertEquals;
-/**
- * A tree entry representing a symbolic link.
- *
- * Note. Java cannot really handle these as file system objects.
- *
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
- */
-@Deprecated
-public class SymlinkTreeEntry extends TreeEntry {
+import java.util.List;
- /**
- * Construct a {@link SymlinkTreeEntry} with the specified name and SHA-1 in
- * the specified parent
- *
- * @param parent
- * @param id
- * @param nameUTF8
- */
- public SymlinkTreeEntry(final Tree parent, final ObjectId id,
- final byte[] nameUTF8) {
- super(parent, id, nameUTF8);
+import org.eclipse.jgit.transport.RemoteConfig;
+import org.junit.Test;
+
+public class RemoteListCommandTest extends AbstractRemoteCommandTest {
+
+ @Test
+ public void testList() throws Exception {
+ // setup an initial remote
+ RemoteConfig remoteConfig = setupRemote();
+
+ // execute the command to list the remotes
+ List<RemoteConfig> remotes = Git.wrap(db).remoteList().call();
+
+ // assert that there is only one remote
+ assertEquals(1, remotes.size());
+ // assert that the available remote is the initial remote
+ assertRemoteConfigEquals(remoteConfig, remotes.get(0));
}
- public FileMode getMode() {
- return FileMode.SYMLINK;
- }
-
- public String toString() {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(getId()));
- r.append(" S "); //$NON-NLS-1$
- r.append(getFullName());
- return r.toString();
- }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java
new file mode 100644
index 0000000..6969c3d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RemoteSetUrlCommandTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import org.eclipse.jgit.transport.RemoteConfig;
+import org.eclipse.jgit.transport.URIish;
+import org.junit.Test;
+
+public class RemoteSetUrlCommandTest extends AbstractRemoteCommandTest {
+
+ @Test
+ public void testSetUrl() throws Exception {
+ // setup an initial remote
+ setupRemote();
+
+ // execute the command to change the fetch url
+ RemoteSetUrlCommand cmd = Git.wrap(db).remoteSetUrl();
+ cmd.setName(REMOTE_NAME);
+ URIish newUri = new URIish("git://test.com/test");
+ cmd.setUri(newUri);
+ RemoteConfig remote = cmd.call();
+
+ // assert that the changed remote has the new fetch url
+ assertEquals(REMOTE_NAME, remote.getName());
+ assertArrayEquals(new URIish[] { newUri }, remote.getURIs().toArray());
+
+ // assert that the changed remote is available in the git configuration
+ assertRemoteConfigEquals(remote,
+ new RemoteConfig(db.getConfig(), REMOTE_NAME));
+ }
+
+ @Test
+ public void testSetPushUrl() throws Exception {
+ // setup an initial remote
+ RemoteConfig remoteConfig = setupRemote();
+
+ // execute the command to change the push url
+ RemoteSetUrlCommand cmd = Git.wrap(db).remoteSetUrl();
+ cmd.setName(REMOTE_NAME);
+ URIish newUri = new URIish("git://test.com/test");
+ cmd.setUri(newUri);
+ cmd.setPush(true);
+ RemoteConfig remote = cmd.call();
+
+ // assert that the changed remote has the old fetch url and the new push
+ // url
+ assertEquals(REMOTE_NAME, remote.getName());
+ assertEquals(remoteConfig.getURIs(), remote.getURIs());
+ assertArrayEquals(new URIish[] { newUri },
+ remote.getPushURIs().toArray());
+
+ // assert that the changed remote is available in the git configuration
+ assertRemoteConfigEquals(remote,
+ new RemoteConfig(db.getConfig(), REMOTE_NAME));
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
index 9997c8c..40d8458 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
@@ -65,6 +65,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
+ "[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 @@
// '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 @@
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 @@
// '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 @@
+ "[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 @@
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 @@
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 @@
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 @@
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);
@@ -460,31 +463,34 @@
@Test
public void testHardResetAfterSquashMerge() throws Exception {
- Git g = new Git(db);
+ git = new Git(db);
writeTrashFile("file1", "file1");
- g.add().addFilepattern("file1").call();
- RevCommit first = g.commit().setMessage("initial commit").call();
+ git.add().addFilepattern("file1").call();
+ RevCommit first = git.commit().setMessage("initial commit").call();
assertTrue(new File(db.getWorkTree(), "file1").exists());
createBranch(first, "refs/heads/branch1");
checkoutBranch("refs/heads/branch1");
writeTrashFile("file2", "file2");
- g.add().addFilepattern("file2").call();
- g.commit().setMessage("second commit").call();
+ git.add().addFilepattern("file2").call();
+ git.commit().setMessage("second commit").call();
assertTrue(new File(db.getWorkTree(), "file2").exists());
checkoutBranch("refs/heads/master");
- MergeResult result = g.merge().include(db.getRef("branch1"))
- .setSquash(true).call();
+ MergeResult result = git.merge()
+ .include(db.exactRef("refs/heads/branch1"))
+ .setSquash(true)
+ .call();
assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
result.getMergeStatus());
assertNotNull(db.readSquashCommitMsg());
- g.reset().setMode(ResetType.HARD).setRef(first.getName()).call();
+ assertSameAsHead(git.reset().setMode(ResetType.HARD)
+ .setRef(first.getName()).call());
assertNull(db.readSquashCommitMsg());
}
@@ -495,7 +501,7 @@
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");
@@ -556,4 +562,14 @@
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());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java
index 060168c..ea63104 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RevertCommandTest.java
@@ -74,303 +74,309 @@
@Test
public void testRevert() throws IOException, JGitInternalException,
GitAPIException {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "first line\nsec. line\nthird line\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("create a").call();
- writeTrashFile("a", "first line\nsec. line\nthird line\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("create a").call();
+ writeTrashFile("b", "content\n");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("create b").call();
- writeTrashFile("b", "content\n");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("create b").call();
+ writeTrashFile("a", "first line\nsec. line\nthird line\nfourth line\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("enlarged a").call();
- writeTrashFile("a", "first line\nsec. line\nthird line\nfourth line\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("enlarged a").call();
+ writeTrashFile("a",
+ "first line\nsecond line\nthird line\nfourth line\n");
+ git.add().addFilepattern("a").call();
+ RevCommit fixingA = git.commit().setMessage("fixed a").call();
- writeTrashFile("a",
- "first line\nsecond line\nthird line\nfourth line\n");
- git.add().addFilepattern("a").call();
- RevCommit fixingA = git.commit().setMessage("fixed a").call();
+ writeTrashFile("b", "first line\n");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("fixed b").call();
- writeTrashFile("b", "first line\n");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("fixed b").call();
+ git.revert().include(fixingA).call();
- git.revert().include(fixingA).call();
+ assertEquals(RepositoryState.SAFE, db.getRepositoryState());
- assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ assertTrue(new File(db.getWorkTree(), "b").exists());
+ checkFile(new File(db.getWorkTree(), "a"),
+ "first line\nsec. line\nthird line\nfourth line\n");
+ Iterator<RevCommit> history = git.log().call().iterator();
+ RevCommit revertCommit = history.next();
+ String expectedMessage = "Revert \"fixed a\"\n\n"
+ + "This reverts commit " + fixingA.getId().getName() + ".\n";
+ assertEquals(expectedMessage, revertCommit.getFullMessage());
+ assertEquals("fixed b", history.next().getFullMessage());
+ assertEquals("fixed a", history.next().getFullMessage());
+ assertEquals("enlarged a", history.next().getFullMessage());
+ assertEquals("create b", history.next().getFullMessage());
+ assertEquals("create a", history.next().getFullMessage());
+ assertFalse(history.hasNext());
- assertTrue(new File(db.getWorkTree(), "b").exists());
- checkFile(new File(db.getWorkTree(), "a"),
- "first line\nsec. line\nthird line\nfourth line\n");
- Iterator<RevCommit> history = git.log().call().iterator();
- RevCommit revertCommit = history.next();
- String expectedMessage = "Revert \"fixed a\"\n\n"
- + "This reverts commit " + fixingA.getId().getName() + ".\n";
- assertEquals(expectedMessage, revertCommit.getFullMessage());
- assertEquals("fixed b", history.next().getFullMessage());
- assertEquals("fixed a", history.next().getFullMessage());
- assertEquals("enlarged a", history.next().getFullMessage());
- assertEquals("create b", history.next().getFullMessage());
- assertEquals("create a", history.next().getFullMessage());
- assertFalse(history.hasNext());
-
- ReflogReader reader = db.getReflogReader(Constants.HEAD);
- assertTrue(reader.getLastEntry().getComment()
- .startsWith("revert: Revert \""));
- reader = db.getReflogReader(db.getBranch());
- assertTrue(reader.getLastEntry().getComment()
- .startsWith("revert: Revert \""));
+ ReflogReader reader = db.getReflogReader(Constants.HEAD);
+ assertTrue(reader.getLastEntry().getComment()
+ .startsWith("revert: Revert \""));
+ reader = db.getReflogReader(db.getBranch());
+ assertTrue(reader.getLastEntry().getComment()
+ .startsWith("revert: Revert \""));
+ }
}
@Test
public void testRevertMultiple() throws IOException, JGitInternalException,
GitAPIException {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "first\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("add first").call();
- writeTrashFile("a", "first\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("add first").call();
+ writeTrashFile("a", "first\nsecond\n");
+ git.add().addFilepattern("a").call();
+ RevCommit secondCommit = git.commit().setMessage("add second").call();
- writeTrashFile("a", "first\nsecond\n");
- git.add().addFilepattern("a").call();
- RevCommit secondCommit = git.commit().setMessage("add second").call();
+ writeTrashFile("a", "first\nsecond\nthird\n");
+ git.add().addFilepattern("a").call();
+ RevCommit thirdCommit = git.commit().setMessage("add third").call();
- writeTrashFile("a", "first\nsecond\nthird\n");
- git.add().addFilepattern("a").call();
- RevCommit thirdCommit = git.commit().setMessage("add third").call();
+ git.revert().include(thirdCommit).include(secondCommit).call();
- git.revert().include(thirdCommit).include(secondCommit).call();
+ assertEquals(RepositoryState.SAFE, db.getRepositoryState());
- assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ checkFile(new File(db.getWorkTree(), "a"), "first\n");
+ Iterator<RevCommit> history = git.log().call().iterator();
+ RevCommit revertCommit = history.next();
+ String expectedMessage = "Revert \"add second\"\n\n"
+ + "This reverts commit "
+ + secondCommit.getId().getName() + ".\n";
+ assertEquals(expectedMessage, revertCommit.getFullMessage());
+ revertCommit = history.next();
+ expectedMessage = "Revert \"add third\"\n\n"
+ + "This reverts commit " + thirdCommit.getId().getName()
+ + ".\n";
+ assertEquals(expectedMessage, revertCommit.getFullMessage());
+ assertEquals("add third", history.next().getFullMessage());
+ assertEquals("add second", history.next().getFullMessage());
+ assertEquals("add first", history.next().getFullMessage());
+ assertFalse(history.hasNext());
- checkFile(new File(db.getWorkTree(), "a"), "first\n");
- Iterator<RevCommit> history = git.log().call().iterator();
- RevCommit revertCommit = history.next();
- String expectedMessage = "Revert \"add second\"\n\n"
- + "This reverts commit "
- + secondCommit.getId().getName() + ".\n";
- assertEquals(expectedMessage, revertCommit.getFullMessage());
- revertCommit = history.next();
- expectedMessage = "Revert \"add third\"\n\n"
- + "This reverts commit " + thirdCommit.getId().getName()
- + ".\n";
- assertEquals(expectedMessage, revertCommit.getFullMessage());
- assertEquals("add third", history.next().getFullMessage());
- assertEquals("add second", history.next().getFullMessage());
- assertEquals("add first", history.next().getFullMessage());
- assertFalse(history.hasNext());
-
- ReflogReader reader = db.getReflogReader(Constants.HEAD);
- assertTrue(reader.getLastEntry().getComment()
- .startsWith("revert: Revert \""));
- reader = db.getReflogReader(db.getBranch());
- assertTrue(reader.getLastEntry().getComment()
- .startsWith("revert: Revert \""));
+ ReflogReader reader = db.getReflogReader(Constants.HEAD);
+ assertTrue(reader.getLastEntry().getComment()
+ .startsWith("revert: Revert \""));
+ reader = db.getReflogReader(db.getBranch());
+ assertTrue(reader.getLastEntry().getComment()
+ .startsWith("revert: Revert \""));
+ }
}
@Test
public void testRevertMultipleWithFail() throws IOException,
JGitInternalException, GitAPIException {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "first\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("add first").call();
- writeTrashFile("a", "first\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("add first").call();
+ writeTrashFile("a", "first\nsecond\n");
+ git.add().addFilepattern("a").call();
+ RevCommit secondCommit = git.commit().setMessage("add second").call();
- writeTrashFile("a", "first\nsecond\n");
- git.add().addFilepattern("a").call();
- RevCommit secondCommit = git.commit().setMessage("add second").call();
+ writeTrashFile("a", "first\nsecond\nthird\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("add third").call();
- writeTrashFile("a", "first\nsecond\nthird\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("add third").call();
+ writeTrashFile("a", "first\nsecond\nthird\nfourth\n");
+ git.add().addFilepattern("a").call();
+ RevCommit fourthCommit = git.commit().setMessage("add fourth").call();
- writeTrashFile("a", "first\nsecond\nthird\nfourth\n");
- git.add().addFilepattern("a").call();
- RevCommit fourthCommit = git.commit().setMessage("add fourth").call();
+ git.revert().include(fourthCommit).include(secondCommit).call();
- git.revert().include(fourthCommit).include(secondCommit).call();
+ // not SAFE because it failed
+ assertEquals(RepositoryState.REVERTING, db.getRepositoryState());
- // not SAFE because it failed
- assertEquals(RepositoryState.REVERTING, db.getRepositoryState());
+ checkFile(new File(db.getWorkTree(), "a"), "first\n"
+ + "<<<<<<< master\n" + "second\n" + "third\n" + "=======\n"
+ + ">>>>>>> " + secondCommit.getId().abbreviate(7).name()
+ + " add second\n");
+ Iterator<RevCommit> history = git.log().call().iterator();
+ RevCommit revertCommit = history.next();
+ String expectedMessage = "Revert \"add fourth\"\n\n"
+ + "This reverts commit " + fourthCommit.getId().getName()
+ + ".\n";
+ assertEquals(expectedMessage, revertCommit.getFullMessage());
+ assertEquals("add fourth", history.next().getFullMessage());
+ assertEquals("add third", history.next().getFullMessage());
+ assertEquals("add second", history.next().getFullMessage());
+ assertEquals("add first", history.next().getFullMessage());
+ assertFalse(history.hasNext());
- checkFile(new File(db.getWorkTree(), "a"), "first\n"
- + "<<<<<<< master\n" + "second\n" + "third\n" + "=======\n"
- + ">>>>>>> " + secondCommit.getId().abbreviate(7).name()
- + " add second\n");
- Iterator<RevCommit> history = git.log().call().iterator();
- RevCommit revertCommit = history.next();
- String expectedMessage = "Revert \"add fourth\"\n\n"
- + "This reverts commit " + fourthCommit.getId().getName()
- + ".\n";
- assertEquals(expectedMessage, revertCommit.getFullMessage());
- assertEquals("add fourth", history.next().getFullMessage());
- assertEquals("add third", history.next().getFullMessage());
- assertEquals("add second", history.next().getFullMessage());
- assertEquals("add first", history.next().getFullMessage());
- assertFalse(history.hasNext());
-
- ReflogReader reader = db.getReflogReader(Constants.HEAD);
- assertTrue(reader.getLastEntry().getComment()
- .startsWith("revert: Revert \""));
- reader = db.getReflogReader(db.getBranch());
- assertTrue(reader.getLastEntry().getComment()
- .startsWith("revert: Revert \""));
+ ReflogReader reader = db.getReflogReader(Constants.HEAD);
+ assertTrue(reader.getLastEntry().getComment()
+ .startsWith("revert: Revert \""));
+ reader = db.getReflogReader(db.getBranch());
+ assertTrue(reader.getLastEntry().getComment()
+ .startsWith("revert: Revert \""));
+ }
}
@Test
public void testRevertDirtyIndex() throws Exception {
- Git git = new Git(db);
- RevCommit sideCommit = prepareRevert(git);
+ try (Git git = new Git(db)) {
+ RevCommit sideCommit = prepareRevert(git);
- // modify and add file a
- writeTrashFile("a", "a(modified)");
- git.add().addFilepattern("a").call();
- // do not commit
+ // modify and add file a
+ writeTrashFile("a", "a(modified)");
+ git.add().addFilepattern("a").call();
+ // do not commit
- doRevertAndCheckResult(git, sideCommit,
- MergeFailureReason.DIRTY_INDEX);
+ doRevertAndCheckResult(git, sideCommit,
+ MergeFailureReason.DIRTY_INDEX);
+ }
}
@Test
public void testRevertDirtyWorktree() throws Exception {
- Git git = new Git(db);
- RevCommit sideCommit = prepareRevert(git);
+ try (Git git = new Git(db)) {
+ RevCommit sideCommit = prepareRevert(git);
- // modify file a
- writeTrashFile("a", "a(modified)");
- // do not add and commit
+ // modify file a
+ writeTrashFile("a", "a(modified)");
+ // do not add and commit
- doRevertAndCheckResult(git, sideCommit,
- MergeFailureReason.DIRTY_WORKTREE);
+ doRevertAndCheckResult(git, sideCommit,
+ MergeFailureReason.DIRTY_WORKTREE);
+ }
}
@Test
public void testRevertConflictResolution() throws Exception {
- Git git = new Git(db);
- RevCommit sideCommit = prepareRevert(git);
+ try (Git git = new Git(db)) {
+ RevCommit sideCommit = prepareRevert(git);
- RevertCommand revert = git.revert();
- RevCommit newHead = revert.include(sideCommit.getId()).call();
- assertNull(newHead);
- MergeResult result = revert.getFailingResult();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists());
- assertEquals("Revert \"" + sideCommit.getShortMessage()
- + "\"\n\nThis reverts commit " + sideCommit.getId().getName()
- + ".\n\nConflicts:\n\ta\n",
- db.readMergeCommitMsg());
- assertTrue(new File(db.getDirectory(), Constants.REVERT_HEAD)
- .exists());
- assertEquals(sideCommit.getId(), db.readRevertHead());
- assertEquals(RepositoryState.REVERTING, db.getRepositoryState());
+ RevertCommand revert = git.revert();
+ RevCommit newHead = revert.include(sideCommit.getId()).call();
+ assertNull(newHead);
+ MergeResult result = revert.getFailingResult();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists());
+ assertEquals("Revert \"" + sideCommit.getShortMessage()
+ + "\"\n\nThis reverts commit " + sideCommit.getId().getName()
+ + ".\n\nConflicts:\n\ta\n",
+ db.readMergeCommitMsg());
+ assertTrue(new File(db.getDirectory(), Constants.REVERT_HEAD)
+ .exists());
+ assertEquals(sideCommit.getId(), db.readRevertHead());
+ assertEquals(RepositoryState.REVERTING, db.getRepositoryState());
- // Resolve
- writeTrashFile("a", "a");
- git.add().addFilepattern("a").call();
+ // Resolve
+ writeTrashFile("a", "a");
+ git.add().addFilepattern("a").call();
- assertEquals(RepositoryState.REVERTING_RESOLVED,
- db.getRepositoryState());
+ assertEquals(RepositoryState.REVERTING_RESOLVED,
+ db.getRepositoryState());
- git.commit().setOnly("a").setMessage("resolve").call();
+ git.commit().setOnly("a").setMessage("resolve").call();
- assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ }
}
@Test
public void testRevertkConflictReset() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ RevCommit sideCommit = prepareRevert(git);
- RevCommit sideCommit = prepareRevert(git);
+ RevertCommand revert = git.revert();
+ RevCommit newHead = revert.include(sideCommit.getId()).call();
+ assertNull(newHead);
+ MergeResult result = revert.getFailingResult();
- RevertCommand revert = git.revert();
- RevCommit newHead = revert.include(sideCommit.getId()).call();
- assertNull(newHead);
- MergeResult result = revert.getFailingResult();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ assertEquals(RepositoryState.REVERTING, db.getRepositoryState());
+ assertTrue(new File(db.getDirectory(), Constants.REVERT_HEAD)
+ .exists());
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- assertEquals(RepositoryState.REVERTING, db.getRepositoryState());
- assertTrue(new File(db.getDirectory(), Constants.REVERT_HEAD)
- .exists());
+ git.reset().setMode(ResetType.MIXED).setRef("HEAD").call();
- git.reset().setMode(ResetType.MIXED).setRef("HEAD").call();
-
- assertEquals(RepositoryState.SAFE, db.getRepositoryState());
- assertFalse(new File(db.getDirectory(), Constants.REVERT_HEAD)
- .exists());
+ assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+ assertFalse(new File(db.getDirectory(), Constants.REVERT_HEAD)
+ .exists());
+ }
}
@Test
public void testRevertOverExecutableChangeOnNonExectuableFileSystem()
throws Exception {
- Git git = new Git(db);
- File file = writeTrashFile("test.txt", "a");
- assertNotNull(git.add().addFilepattern("test.txt").call());
- assertNotNull(git.commit().setMessage("commit1").call());
+ try (Git git = new Git(db)) {
+ File file = writeTrashFile("test.txt", "a");
+ assertNotNull(git.add().addFilepattern("test.txt").call());
+ assertNotNull(git.commit().setMessage("commit1").call());
- assertNotNull(git.checkout().setCreateBranch(true).setName("a").call());
+ assertNotNull(git.checkout().setCreateBranch(true).setName("a").call());
- writeTrashFile("test.txt", "b");
- assertNotNull(git.add().addFilepattern("test.txt").call());
- RevCommit commit2 = git.commit().setMessage("commit2").call();
- assertNotNull(commit2);
+ writeTrashFile("test.txt", "b");
+ assertNotNull(git.add().addFilepattern("test.txt").call());
+ RevCommit commit2 = git.commit().setMessage("commit2").call();
+ assertNotNull(commit2);
- assertNotNull(git.checkout().setName(Constants.MASTER).call());
+ assertNotNull(git.checkout().setName(Constants.MASTER).call());
- DirCache cache = db.lockDirCache();
- cache.getEntry("test.txt").setFileMode(FileMode.EXECUTABLE_FILE);
- cache.write();
- assertTrue(cache.commit());
- cache.unlock();
+ DirCache cache = db.lockDirCache();
+ cache.getEntry("test.txt").setFileMode(FileMode.EXECUTABLE_FILE);
+ cache.write();
+ assertTrue(cache.commit());
+ cache.unlock();
- assertNotNull(git.commit().setMessage("commit3").call());
+ assertNotNull(git.commit().setMessage("commit3").call());
- db.getFS().setExecute(file, false);
- git.getRepository()
- .getConfig()
- .setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_FILEMODE, false);
+ db.getFS().setExecute(file, false);
+ git.getRepository()
+ .getConfig()
+ .setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_FILEMODE, false);
- RevertCommand revert = git.revert();
- RevCommit newHead = revert.include(commit2).call();
- assertNotNull(newHead);
+ RevertCommand revert = git.revert();
+ RevCommit newHead = revert.include(commit2).call();
+ assertNotNull(newHead);
+ }
}
@Test
public void testRevertConflictMarkers() throws Exception {
- Git git = new Git(db);
- RevCommit sideCommit = prepareRevert(git);
+ try (Git git = new Git(db)) {
+ RevCommit sideCommit = prepareRevert(git);
- RevertCommand revert = git.revert();
- RevCommit newHead = revert.include(sideCommit.getId())
- .call();
- assertNull(newHead);
- MergeResult result = revert.getFailingResult();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ RevertCommand revert = git.revert();
+ RevCommit newHead = revert.include(sideCommit.getId())
+ .call();
+ assertNull(newHead);
+ MergeResult result = revert.getFailingResult();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- String expected = "<<<<<<< master\na(latest)\n=======\na\n>>>>>>> ca96c31 second master\n";
- checkFile(new File(db.getWorkTree(), "a"), expected);
+ String expected = "<<<<<<< master\na(latest)\n=======\na\n>>>>>>> ca96c31 second master\n";
+ checkFile(new File(db.getWorkTree(), "a"), expected);
+ }
}
@Test
public void testRevertOurCommitName() throws Exception {
- Git git = new Git(db);
- RevCommit sideCommit = prepareRevert(git);
+ try (Git git = new Git(db)) {
+ RevCommit sideCommit = prepareRevert(git);
- RevertCommand revert = git.revert();
- RevCommit newHead = revert.include(sideCommit.getId())
- .setOurCommitName("custom name").call();
- assertNull(newHead);
- MergeResult result = revert.getFailingResult();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ RevertCommand revert = git.revert();
+ RevCommit newHead = revert.include(sideCommit.getId())
+ .setOurCommitName("custom name").call();
+ assertNull(newHead);
+ MergeResult result = revert.getFailingResult();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- String expected = "<<<<<<< custom name\na(latest)\n=======\na\n>>>>>>> ca96c31 second master\n";
- checkFile(new File(db.getWorkTree(), "a"), expected);
+ String expected = "<<<<<<< custom name\na(latest)\n=======\na\n>>>>>>> ca96c31 second master\n";
+ checkFile(new File(db.getWorkTree(), "a"), expected);
+ }
}
private RevCommit prepareRevert(final Git git) throws Exception {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java
index c317e3b..ae8551e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java
@@ -110,7 +110,7 @@
int parentCount)
throws IOException {
assertNotNull(commit);
- Ref stashRef = db.getRef(Constants.R_STASH);
+ Ref stashRef = db.exactRef(Constants.R_STASH);
assertNotNull(stashRef);
assertEquals(commit, stashRef.getObjectId());
assertNotNull(commit.getAuthorIdent());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java
index cfad817..859277e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashDropCommandTest.java
@@ -96,13 +96,13 @@
@Test
public void dropWithInvalidLogIndex() throws Exception {
write(committedFile, "content2");
- Ref stashRef = git.getRepository().getRef(Constants.R_STASH);
+ Ref stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef);
RevCommit stashed = git.stashCreate().call();
assertNotNull(stashed);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
- assertEquals(stashed, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
+ assertEquals(stashed,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
try {
assertNull(git.stashDrop().setStashRef(100).call());
fail("Exception not thrown");
@@ -115,15 +115,15 @@
@Test
public void dropSingleStashedCommit() throws Exception {
write(committedFile, "content2");
- Ref stashRef = git.getRepository().getRef(Constants.R_STASH);
+ Ref stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef);
RevCommit stashed = git.stashCreate().call();
assertNotNull(stashed);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
- assertEquals(stashed, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
+ assertEquals(stashed,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
assertNull(git.stashDrop().call());
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef);
ReflogReader reader = git.getRepository().getReflogReader(
@@ -134,25 +134,25 @@
@Test
public void dropAll() throws Exception {
write(committedFile, "content2");
- Ref stashRef = git.getRepository().getRef(Constants.R_STASH);
+ Ref stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef);
RevCommit firstStash = git.stashCreate().call();
assertNotNull(firstStash);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
- assertEquals(firstStash, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ assertEquals(firstStash,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content3");
RevCommit secondStash = git.stashCreate().call();
assertNotNull(secondStash);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
- assertEquals(secondStash, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ assertEquals(secondStash,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
assertNull(git.stashDrop().setAll(true).call());
- assertNull(git.getRepository().getRef(Constants.R_STASH));
+ assertNull(git.getRepository().exactRef(Constants.R_STASH));
ReflogReader reader = git.getRepository().getReflogReader(
Constants.R_STASH);
@@ -162,25 +162,25 @@
@Test
public void dropFirstStashedCommit() throws Exception {
write(committedFile, "content2");
- Ref stashRef = git.getRepository().getRef(Constants.R_STASH);
+ Ref stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef);
RevCommit firstStash = git.stashCreate().call();
assertNotNull(firstStash);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
- assertEquals(firstStash, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ assertEquals(firstStash,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content3");
RevCommit secondStash = git.stashCreate().call();
assertNotNull(secondStash);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
- assertEquals(secondStash, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ assertEquals(secondStash,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
assertEquals(firstStash, git.stashDrop().call());
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
assertEquals(firstStash, stashRef.getObjectId());
@@ -196,33 +196,33 @@
@Test
public void dropMiddleStashCommit() throws Exception {
write(committedFile, "content2");
- Ref stashRef = git.getRepository().getRef(Constants.R_STASH);
+ Ref stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef);
RevCommit firstStash = git.stashCreate().call();
assertNotNull(firstStash);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
- assertEquals(firstStash, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ assertEquals(firstStash,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content3");
RevCommit secondStash = git.stashCreate().call();
assertNotNull(secondStash);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
- assertEquals(secondStash, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ assertEquals(secondStash,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content4");
RevCommit thirdStash = git.stashCreate().call();
assertNotNull(thirdStash);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
- assertEquals(thirdStash, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ assertEquals(thirdStash,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
assertEquals(thirdStash, git.stashDrop().setStashRef(1).call());
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
assertEquals(thirdStash, stashRef.getObjectId());
@@ -241,46 +241,46 @@
@Test
public void dropBoundaryStashedCommits() throws Exception {
write(committedFile, "content2");
- Ref stashRef = git.getRepository().getRef(Constants.R_STASH);
+ Ref stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNull(stashRef);
RevCommit firstStash = git.stashCreate().call();
assertNotNull(firstStash);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
- assertEquals(firstStash, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ assertEquals(firstStash,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content3");
RevCommit secondStash = git.stashCreate().call();
assertNotNull(secondStash);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
- assertEquals(secondStash, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ assertEquals(secondStash,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content4");
RevCommit thirdStash = git.stashCreate().call();
assertNotNull(thirdStash);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
- assertEquals(thirdStash, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ assertEquals(thirdStash,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
write(committedFile, "content5");
RevCommit fourthStash = git.stashCreate().call();
assertNotNull(fourthStash);
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
- assertEquals(fourthStash, git.getRepository().getRef(Constants.R_STASH)
- .getObjectId());
+ assertEquals(fourthStash,
+ git.getRepository().exactRef(Constants.R_STASH).getObjectId());
assertEquals(thirdStash, git.stashDrop().call());
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
assertEquals(thirdStash, stashRef.getObjectId());
assertEquals(thirdStash, git.stashDrop().setStashRef(2).call());
- stashRef = git.getRepository().getRef(Constants.R_STASH);
+ stashRef = git.getRepository().exactRef(Constants.R_STASH);
assertNotNull(stashRef);
assertEquals(thirdStash, stashRef.getObjectId());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java
index c70604e..f3ac65c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java
@@ -61,109 +61,111 @@
@Test
public void testEmptyStatus() throws NoWorkTreeException,
GitAPIException {
- Git git = new Git(db);
-
- Status stat = git.status().call();
- assertEquals(0, stat.getAdded().size());
- assertEquals(0, stat.getChanged().size());
- assertEquals(0, stat.getMissing().size());
- assertEquals(0, stat.getModified().size());
- assertEquals(0, stat.getRemoved().size());
- assertEquals(0, stat.getUntracked().size());
+ try (Git git = new Git(db)) {
+ Status stat = git.status().call();
+ assertEquals(0, stat.getAdded().size());
+ assertEquals(0, stat.getChanged().size());
+ assertEquals(0, stat.getMissing().size());
+ assertEquals(0, stat.getModified().size());
+ assertEquals(0, stat.getRemoved().size());
+ assertEquals(0, stat.getUntracked().size());
+ }
}
@Test
public void testDifferentStates() throws IOException,
NoFilepatternException, GitAPIException {
- Git git = new Git(db);
- writeTrashFile("a", "content of a");
- writeTrashFile("b", "content of b");
- writeTrashFile("c", "content of c");
- git.add().addFilepattern("a").addFilepattern("b").call();
- Status stat = git.status().call();
- assertEquals(Sets.of("a", "b"), stat.getAdded());
- assertEquals(0, stat.getChanged().size());
- assertEquals(0, stat.getMissing().size());
- assertEquals(0, stat.getModified().size());
- assertEquals(0, stat.getRemoved().size());
- assertEquals(Sets.of("c"), stat.getUntracked());
- git.commit().setMessage("initial").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "content of a");
+ writeTrashFile("b", "content of b");
+ writeTrashFile("c", "content of c");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ Status stat = git.status().call();
+ assertEquals(Sets.of("a", "b"), stat.getAdded());
+ assertEquals(0, stat.getChanged().size());
+ assertEquals(0, stat.getMissing().size());
+ assertEquals(0, stat.getModified().size());
+ assertEquals(0, stat.getRemoved().size());
+ assertEquals(Sets.of("c"), stat.getUntracked());
+ git.commit().setMessage("initial").call();
- writeTrashFile("a", "modified content of a");
- writeTrashFile("b", "modified content of b");
- writeTrashFile("d", "content of d");
- git.add().addFilepattern("a").addFilepattern("d").call();
- writeTrashFile("a", "again modified content of a");
- stat = git.status().call();
- assertEquals(Sets.of("d"), stat.getAdded());
- assertEquals(Sets.of("a"), stat.getChanged());
- assertEquals(0, stat.getMissing().size());
- assertEquals(Sets.of("b", "a"), stat.getModified());
- assertEquals(0, stat.getRemoved().size());
- assertEquals(Sets.of("c"), stat.getUntracked());
- git.add().addFilepattern(".").call();
- git.commit().setMessage("second").call();
+ writeTrashFile("a", "modified content of a");
+ writeTrashFile("b", "modified content of b");
+ writeTrashFile("d", "content of d");
+ git.add().addFilepattern("a").addFilepattern("d").call();
+ writeTrashFile("a", "again modified content of a");
+ stat = git.status().call();
+ assertEquals(Sets.of("d"), stat.getAdded());
+ assertEquals(Sets.of("a"), stat.getChanged());
+ assertEquals(0, stat.getMissing().size());
+ assertEquals(Sets.of("b", "a"), stat.getModified());
+ assertEquals(0, stat.getRemoved().size());
+ assertEquals(Sets.of("c"), stat.getUntracked());
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("second").call();
- stat = git.status().call();
- assertEquals(0, stat.getAdded().size());
- assertEquals(0, stat.getChanged().size());
- assertEquals(0, stat.getMissing().size());
- assertEquals(0, stat.getModified().size());
- assertEquals(0, stat.getRemoved().size());
- assertEquals(0, stat.getUntracked().size());
+ stat = git.status().call();
+ assertEquals(0, stat.getAdded().size());
+ assertEquals(0, stat.getChanged().size());
+ assertEquals(0, stat.getMissing().size());
+ assertEquals(0, stat.getModified().size());
+ assertEquals(0, stat.getRemoved().size());
+ assertEquals(0, stat.getUntracked().size());
- deleteTrashFile("a");
- assertFalse(new File(git.getRepository().getWorkTree(), "a").exists());
- git.add().addFilepattern("a").setUpdate(true).call();
- writeTrashFile("a", "recreated content of a");
- stat = git.status().call();
- assertEquals(0, stat.getAdded().size());
- assertEquals(0, stat.getChanged().size());
- assertEquals(0, stat.getMissing().size());
- assertEquals(0, stat.getModified().size());
- assertEquals(Sets.of("a"), stat.getRemoved());
- assertEquals(Sets.of("a"), stat.getUntracked());
- git.commit().setMessage("t").call();
+ deleteTrashFile("a");
+ assertFalse(new File(git.getRepository().getWorkTree(), "a").exists());
+ git.add().addFilepattern("a").setUpdate(true).call();
+ writeTrashFile("a", "recreated content of a");
+ stat = git.status().call();
+ assertEquals(0, stat.getAdded().size());
+ assertEquals(0, stat.getChanged().size());
+ assertEquals(0, stat.getMissing().size());
+ assertEquals(0, stat.getModified().size());
+ assertEquals(Sets.of("a"), stat.getRemoved());
+ assertEquals(Sets.of("a"), stat.getUntracked());
+ git.commit().setMessage("t").call();
- writeTrashFile("sub/a", "sub-file");
- stat = git.status().call();
- assertEquals(1, stat.getUntrackedFolders().size());
- assertTrue(stat.getUntrackedFolders().contains("sub"));
+ writeTrashFile("sub/a", "sub-file");
+ stat = git.status().call();
+ assertEquals(1, stat.getUntrackedFolders().size());
+ assertTrue(stat.getUntrackedFolders().contains("sub"));
+ }
}
@Test
public void testDifferentStatesWithPaths() throws IOException,
NoFilepatternException, GitAPIException {
- Git git = new Git(db);
- writeTrashFile("a", "content of a");
- writeTrashFile("D/b", "content of b");
- writeTrashFile("D/c", "content of c");
- writeTrashFile("D/D/d", "content of d");
- git.add().addFilepattern(".").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "content of a");
+ writeTrashFile("D/b", "content of b");
+ writeTrashFile("D/c", "content of c");
+ writeTrashFile("D/D/d", "content of d");
+ git.add().addFilepattern(".").call();
- writeTrashFile("a", "new content of a");
- writeTrashFile("D/b", "new content of b");
- writeTrashFile("D/D/d", "new content of d");
+ writeTrashFile("a", "new content of a");
+ writeTrashFile("D/b", "new content of b");
+ writeTrashFile("D/D/d", "new content of d");
- // filter on an not existing path
- Status stat = git.status().addPath("x").call();
- assertEquals(0, stat.getModified().size());
+ // filter on an not existing path
+ Status stat = git.status().addPath("x").call();
+ assertEquals(0, stat.getModified().size());
- // filter on an existing file
- stat = git.status().addPath("a").call();
- assertEquals(Sets.of("a"), stat.getModified());
+ // filter on an existing file
+ stat = git.status().addPath("a").call();
+ assertEquals(Sets.of("a"), stat.getModified());
- // filter on an existing folder
- stat = git.status().addPath("D").call();
- assertEquals(Sets.of("D/b", "D/D/d"), stat.getModified());
+ // filter on an existing folder
+ stat = git.status().addPath("D").call();
+ assertEquals(Sets.of("D/b", "D/D/d"), stat.getModified());
- // filter on an existing folder and file
- stat = git.status().addPath("D/D").addPath("a").call();
- assertEquals(Sets.of("a", "D/D/d"), stat.getModified());
+ // filter on an existing folder and file
+ stat = git.status().addPath("D/D").addPath("a").call();
+ assertEquals(Sets.of("a", "D/D/d"), stat.getModified());
- // do not filter at all
- stat = git.status().call();
- assertEquals(Sets.of("a", "D/b", "D/D/d"), stat.getModified());
+ // do not filter at all
+ stat = git.status().call();
+ assertEquals(Sets.of("a", "D/b", "D/D/d"), stat.getModified());
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java
index 061d29f..87098b6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java
@@ -62,171 +62,185 @@
@Test
public void testTaggingOnHead() throws GitAPIException, IOException {
- Git git = new Git(db);
- RevCommit commit = git.commit().setMessage("initial commit").call();
- Ref tagRef = git.tag().setName("tag").call();
- assertEquals(commit.getId(), db.peel(tagRef).getPeeledObjectId());
- RevWalk walk = new RevWalk(db);
- assertEquals("tag", walk.parseTag(tagRef.getObjectId()).getTagName());
+ try (Git git = new Git(db);
+ RevWalk walk = new RevWalk(db)) {
+ RevCommit commit = git.commit().setMessage("initial commit").call();
+ Ref tagRef = git.tag().setName("tag").call();
+ assertEquals(commit.getId(), db.peel(tagRef).getPeeledObjectId());
+ assertEquals("tag", walk.parseTag(tagRef.getObjectId()).getTagName());
+ }
}
@Test
public void testTagging() throws GitAPIException, JGitInternalException {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
- RevCommit commit = git.commit().setMessage("second commit").call();
- git.commit().setMessage("third commit").call();
- Ref tagRef = git.tag().setObjectId(commit).setName("tag").call();
- assertEquals(commit.getId(), db.peel(tagRef).getPeeledObjectId());
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ RevCommit commit = git.commit().setMessage("second commit").call();
+ git.commit().setMessage("third commit").call();
+ Ref tagRef = git.tag().setObjectId(commit).setName("tag").call();
+ assertEquals(commit.getId(), db.peel(tagRef).getPeeledObjectId());
+ }
}
@Test
public void testUnannotatedTagging() throws GitAPIException,
JGitInternalException {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
- RevCommit commit = git.commit().setMessage("second commit").call();
- git.commit().setMessage("third commit").call();
- Ref tagRef = git.tag().setObjectId(commit).setName("tag")
- .setAnnotated(false).call();
- assertEquals(commit.getId(), tagRef.getObjectId());
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ RevCommit commit = git.commit().setMessage("second commit").call();
+ git.commit().setMessage("third commit").call();
+ Ref tagRef = git.tag().setObjectId(commit).setName("tag")
+ .setAnnotated(false).call();
+ assertEquals(commit.getId(), tagRef.getObjectId());
+ }
}
@Test
public void testEmptyTagName() throws GitAPIException {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
- try {
- // forget to tag name
- git.tag().setMessage("some message").call();
- fail("We should have failed without a tag name");
- } catch (InvalidTagNameException e) {
- // should hit here
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ try {
+ // forget to tag name
+ git.tag().setMessage("some message").call();
+ fail("We should have failed without a tag name");
+ } catch (InvalidTagNameException e) {
+ // should hit here
+ }
}
}
@Test
public void testInvalidTagName() throws GitAPIException {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
- try {
- git.tag().setName("bad~tag~name").setMessage("some message").call();
- fail("We should have failed due to a bad tag name");
- } catch (InvalidTagNameException e) {
- // should hit here
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ try {
+ git.tag().setName("bad~tag~name").setMessage("some message").call();
+ fail("We should have failed due to a bad tag name");
+ } catch (InvalidTagNameException e) {
+ // should hit here
+ }
}
}
@Test
public void testFailureOnSignedTags() throws GitAPIException {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
- try {
- git.tag().setSigned(true).setName("tag").call();
- fail("We should have failed with an UnsupportedOperationException due to signed tag");
- } catch (UnsupportedOperationException e) {
- // should hit here
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ try {
+ git.tag().setSigned(true).setName("tag").call();
+ fail("We should have failed with an UnsupportedOperationException due to signed tag");
+ } catch (UnsupportedOperationException e) {
+ // should hit here
+ }
}
}
@Test
public void testDelete() throws Exception {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
- Ref tagRef = git.tag().setName("tag").call();
- assertEquals(1, db.getTags().size());
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ Ref tagRef = git.tag().setName("tag").call();
+ assertEquals(1, db.getTags().size());
- List<String> deleted = git.tagDelete().setTags(tagRef.getName())
- .call();
- assertEquals(1, deleted.size());
- assertEquals(tagRef.getName(), deleted.get(0));
- assertEquals(0, db.getTags().size());
+ List<String> deleted = git.tagDelete().setTags(tagRef.getName())
+ .call();
+ assertEquals(1, deleted.size());
+ assertEquals(tagRef.getName(), deleted.get(0));
+ assertEquals(0, db.getTags().size());
- Ref tagRef1 = git.tag().setName("tag1").call();
- Ref tagRef2 = git.tag().setName("tag2").call();
- assertEquals(2, db.getTags().size());
- deleted = git.tagDelete().setTags(tagRef1.getName(), tagRef2.getName())
- .call();
- assertEquals(2, deleted.size());
- assertEquals(0, db.getTags().size());
+ Ref tagRef1 = git.tag().setName("tag1").call();
+ Ref tagRef2 = git.tag().setName("tag2").call();
+ assertEquals(2, db.getTags().size());
+ deleted = git.tagDelete().setTags(tagRef1.getName(), tagRef2.getName())
+ .call();
+ assertEquals(2, deleted.size());
+ assertEquals(0, db.getTags().size());
+ }
}
@Test
public void testDeleteFullName() throws Exception {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
- Ref tagRef = git.tag().setName("tag").call();
- assertEquals(1, db.getTags().size());
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
+ Ref tagRef = git.tag().setName("tag").call();
+ assertEquals(1, db.getTags().size());
- List<String> deleted = git.tagDelete()
- .setTags(Repository.shortenRefName(tagRef.getName())).call();
- assertEquals(1, deleted.size());
- assertEquals(tagRef.getName(), deleted.get(0));
- assertEquals(0, db.getTags().size());
+ List<String> deleted = git.tagDelete()
+ .setTags(Repository.shortenRefName(tagRef.getName())).call();
+ assertEquals(1, deleted.size());
+ assertEquals(tagRef.getName(), deleted.get(0));
+ assertEquals(0, db.getTags().size());
+ }
}
@Test
public void testDeleteEmptyTagNames() throws Exception {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
- List<String> deleted = git.tagDelete().setTags().call();
- assertEquals(0, deleted.size());
+ List<String> deleted = git.tagDelete().setTags().call();
+ assertEquals(0, deleted.size());
+ }
}
@Test
public void testDeleteNonExisting() throws Exception {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
- List<String> deleted = git.tagDelete().setTags("tag").call();
- assertEquals(0, deleted.size());
+ List<String> deleted = git.tagDelete().setTags("tag").call();
+ assertEquals(0, deleted.size());
+ }
}
@Test
public void testDeleteBadName() throws Exception {
- Git git = new Git(db);
- git.commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("initial commit").call();
- List<String> deleted = git.tagDelete().setTags("bad~tag~name")
- .call();
- assertEquals(0, deleted.size());
+ List<String> deleted = git.tagDelete().setTags("bad~tag~name")
+ .call();
+ assertEquals(0, deleted.size());
+ }
}
@Test
public void testShouldNotBlowUpIfThereAreNoTagsInRepository()
throws Exception {
- Git git = new Git(db);
- git.add().addFilepattern("*").call();
- git.commit().setMessage("initial commit").call();
- List<Ref> list = git.tagList().call();
- assertEquals(0, list.size());
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("*").call();
+ git.commit().setMessage("initial commit").call();
+ List<Ref> list = git.tagList().call();
+ assertEquals(0, list.size());
+ }
}
@Test
public void testShouldNotBlowUpIfThereAreNoCommitsInRepository()
throws Exception {
- Git git = new Git(db);
- List<Ref> list = git.tagList().call();
- assertEquals(0, list.size());
+ try (Git git = new Git(db)) {
+ List<Ref> list = git.tagList().call();
+ assertEquals(0, list.size());
+ }
}
@Test
public void testListAllTagsInRepositoryInOrder() throws Exception {
- Git git = new Git(db);
- git.add().addFilepattern("*").call();
- git.commit().setMessage("initial commit").call();
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("*").call();
+ git.commit().setMessage("initial commit").call();
- git.tag().setName("v3").call();
- git.tag().setName("v2").call();
- git.tag().setName("v10").call();
+ git.tag().setName("v3").call();
+ git.tag().setName("v2").call();
+ git.tag().setName("v10").call();
- List<Ref> list = git.tagList().call();
+ List<Ref> list = git.tagList().call();
- assertEquals(3, list.size());
- assertEquals("refs/tags/v10", list.get(0).getName());
- assertEquals("refs/tags/v2", list.get(1).getName());
- assertEquals("refs/tags/v3", list.get(2).getName());
+ assertEquals(3, list.size());
+ assertEquals("refs/tags/v10", list.get(0).getName());
+ assertEquals("refs/tags/v2", list.get(1).getName());
+ assertEquals("refs/tags/v3", list.get(2).getName());
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java
index 42909f0..fa9848b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java
@@ -58,141 +58,142 @@
public class BlameGeneratorTest extends RepositoryTestCase {
@Test
public void testBoundLineDelete() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ String[] content1 = new String[] { "first", "second" };
+ writeTrashFile("file.txt", join(content1));
+ git.add().addFilepattern("file.txt").call();
+ RevCommit c1 = git.commit().setMessage("create file").call();
- String[] content1 = new String[] { "first", "second" };
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
- RevCommit c1 = git.commit().setMessage("create file").call();
+ String[] content2 = new String[] { "third", "first", "second" };
+ writeTrashFile("file.txt", join(content2));
+ git.add().addFilepattern("file.txt").call();
+ RevCommit c2 = git.commit().setMessage("create file").call();
- String[] content2 = new String[] { "third", "first", "second" };
- writeTrashFile("file.txt", join(content2));
- git.add().addFilepattern("file.txt").call();
- RevCommit c2 = git.commit().setMessage("create file").call();
+ try (BlameGenerator generator = new BlameGenerator(db, "file.txt")) {
+ generator.push(null, db.resolve(Constants.HEAD));
+ assertEquals(3, generator.getResultContents().size());
- try (BlameGenerator generator = new BlameGenerator(db, "file.txt")) {
- generator.push(null, db.resolve(Constants.HEAD));
- assertEquals(3, generator.getResultContents().size());
+ assertTrue(generator.next());
+ assertEquals(c2, generator.getSourceCommit());
+ assertEquals(1, generator.getRegionLength());
+ assertEquals(0, generator.getResultStart());
+ assertEquals(1, generator.getResultEnd());
+ assertEquals(0, generator.getSourceStart());
+ assertEquals(1, generator.getSourceEnd());
+ assertEquals("file.txt", generator.getSourcePath());
- assertTrue(generator.next());
- assertEquals(c2, generator.getSourceCommit());
- assertEquals(1, generator.getRegionLength());
- assertEquals(0, generator.getResultStart());
- assertEquals(1, generator.getResultEnd());
- assertEquals(0, generator.getSourceStart());
- assertEquals(1, generator.getSourceEnd());
- assertEquals("file.txt", generator.getSourcePath());
+ assertTrue(generator.next());
+ assertEquals(c1, generator.getSourceCommit());
+ assertEquals(2, generator.getRegionLength());
+ assertEquals(1, generator.getResultStart());
+ assertEquals(3, generator.getResultEnd());
+ assertEquals(0, generator.getSourceStart());
+ assertEquals(2, generator.getSourceEnd());
+ assertEquals("file.txt", generator.getSourcePath());
- assertTrue(generator.next());
- assertEquals(c1, generator.getSourceCommit());
- assertEquals(2, generator.getRegionLength());
- assertEquals(1, generator.getResultStart());
- assertEquals(3, generator.getResultEnd());
- assertEquals(0, generator.getSourceStart());
- assertEquals(2, generator.getSourceEnd());
- assertEquals("file.txt", generator.getSourcePath());
-
- assertFalse(generator.next());
+ assertFalse(generator.next());
+ }
}
}
@Test
public void testRenamedBoundLineDelete() throws Exception {
- Git git = new Git(db);
- final String FILENAME_1 = "subdir/file1.txt";
- final String FILENAME_2 = "subdir/file2.txt";
+ try (Git git = new Git(db)) {
+ final String FILENAME_1 = "subdir/file1.txt";
+ final String FILENAME_2 = "subdir/file2.txt";
- String[] content1 = new String[] { "first", "second" };
- writeTrashFile(FILENAME_1, join(content1));
- git.add().addFilepattern(FILENAME_1).call();
- RevCommit c1 = git.commit().setMessage("create file1").call();
+ String[] content1 = new String[] { "first", "second" };
+ writeTrashFile(FILENAME_1, join(content1));
+ git.add().addFilepattern(FILENAME_1).call();
+ RevCommit c1 = git.commit().setMessage("create file1").call();
- // rename it
- writeTrashFile(FILENAME_2, join(content1));
- git.add().addFilepattern(FILENAME_2).call();
- deleteTrashFile(FILENAME_1);
- git.rm().addFilepattern(FILENAME_1).call();
- git.commit().setMessage("rename file1.txt to file2.txt").call();
+ // rename it
+ writeTrashFile(FILENAME_2, join(content1));
+ git.add().addFilepattern(FILENAME_2).call();
+ deleteTrashFile(FILENAME_1);
+ git.rm().addFilepattern(FILENAME_1).call();
+ git.commit().setMessage("rename file1.txt to file2.txt").call();
- // and change the new file
- String[] content2 = new String[] { "third", "first", "second" };
- writeTrashFile(FILENAME_2, join(content2));
- git.add().addFilepattern(FILENAME_2).call();
- RevCommit c2 = git.commit().setMessage("change file2").call();
+ // and change the new file
+ String[] content2 = new String[] { "third", "first", "second" };
+ writeTrashFile(FILENAME_2, join(content2));
+ git.add().addFilepattern(FILENAME_2).call();
+ RevCommit c2 = git.commit().setMessage("change file2").call();
- try (BlameGenerator generator = new BlameGenerator(db, FILENAME_2)) {
- generator.push(null, db.resolve(Constants.HEAD));
- assertEquals(3, generator.getResultContents().size());
+ try (BlameGenerator generator = new BlameGenerator(db, FILENAME_2)) {
+ generator.push(null, db.resolve(Constants.HEAD));
+ assertEquals(3, generator.getResultContents().size());
- assertTrue(generator.next());
- assertEquals(c2, generator.getSourceCommit());
- assertEquals(1, generator.getRegionLength());
- assertEquals(0, generator.getResultStart());
- assertEquals(1, generator.getResultEnd());
- assertEquals(0, generator.getSourceStart());
- assertEquals(1, generator.getSourceEnd());
- assertEquals(FILENAME_2, generator.getSourcePath());
+ assertTrue(generator.next());
+ assertEquals(c2, generator.getSourceCommit());
+ assertEquals(1, generator.getRegionLength());
+ assertEquals(0, generator.getResultStart());
+ assertEquals(1, generator.getResultEnd());
+ assertEquals(0, generator.getSourceStart());
+ assertEquals(1, generator.getSourceEnd());
+ assertEquals(FILENAME_2, generator.getSourcePath());
- assertTrue(generator.next());
- assertEquals(c1, generator.getSourceCommit());
- assertEquals(2, generator.getRegionLength());
- assertEquals(1, generator.getResultStart());
- assertEquals(3, generator.getResultEnd());
- assertEquals(0, generator.getSourceStart());
- assertEquals(2, generator.getSourceEnd());
- assertEquals(FILENAME_1, generator.getSourcePath());
+ assertTrue(generator.next());
+ assertEquals(c1, generator.getSourceCommit());
+ assertEquals(2, generator.getRegionLength());
+ assertEquals(1, generator.getResultStart());
+ assertEquals(3, generator.getResultEnd());
+ assertEquals(0, generator.getSourceStart());
+ assertEquals(2, generator.getSourceEnd());
+ assertEquals(FILENAME_1, generator.getSourcePath());
- assertFalse(generator.next());
- }
+ assertFalse(generator.next());
+ }
- // and test again with other BlameGenerator API:
- try (BlameGenerator generator = new BlameGenerator(db, FILENAME_2)) {
- generator.push(null, db.resolve(Constants.HEAD));
- BlameResult result = generator.computeBlameResult();
+ // and test again with other BlameGenerator API:
+ try (BlameGenerator generator = new BlameGenerator(db, FILENAME_2)) {
+ generator.push(null, db.resolve(Constants.HEAD));
+ BlameResult result = generator.computeBlameResult();
- assertEquals(3, result.getResultContents().size());
+ assertEquals(3, result.getResultContents().size());
- assertEquals(c2, result.getSourceCommit(0));
- assertEquals(FILENAME_2, result.getSourcePath(0));
+ assertEquals(c2, result.getSourceCommit(0));
+ assertEquals(FILENAME_2, result.getSourcePath(0));
- assertEquals(c1, result.getSourceCommit(1));
- assertEquals(FILENAME_1, result.getSourcePath(1));
+ assertEquals(c1, result.getSourceCommit(1));
+ assertEquals(FILENAME_1, result.getSourcePath(1));
- assertEquals(c1, result.getSourceCommit(2));
- assertEquals(FILENAME_1, result.getSourcePath(2));
+ assertEquals(c1, result.getSourceCommit(2));
+ assertEquals(FILENAME_1, result.getSourcePath(2));
+ }
}
}
@Test
public void testLinesAllDeletedShortenedWalk() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ String[] content1 = new String[] { "first", "second", "third" };
- String[] content1 = new String[] { "first", "second", "third" };
+ writeTrashFile("file.txt", join(content1));
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("create file").call();
+ String[] content2 = new String[] { "" };
- String[] content2 = new String[] { "" };
+ writeTrashFile("file.txt", join(content2));
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", join(content2));
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("create file").call();
+ writeTrashFile("file.txt", join(content1));
+ git.add().addFilepattern("file.txt").call();
+ RevCommit c3 = git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
- RevCommit c3 = git.commit().setMessage("create file").call();
+ try (BlameGenerator generator = new BlameGenerator(db, "file.txt")) {
+ generator.push(null, db.resolve(Constants.HEAD));
+ assertEquals(3, generator.getResultContents().size());
- try (BlameGenerator generator = new BlameGenerator(db, "file.txt")) {
- generator.push(null, db.resolve(Constants.HEAD));
- assertEquals(3, generator.getResultContents().size());
+ assertTrue(generator.next());
+ assertEquals(c3, generator.getSourceCommit());
+ assertEquals(0, generator.getResultStart());
+ assertEquals(3, generator.getResultEnd());
- assertTrue(generator.next());
- assertEquals(c3, generator.getSourceCommit());
- assertEquals(0, generator.getResultStart());
- assertEquals(3, generator.getResultEnd());
-
- assertFalse(generator.next());
+ assertFalse(generator.next());
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
index 49279e6..0e595e6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java
@@ -52,9 +52,7 @@
import java.io.IOException;
import java.util.Collections;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.attributes.Attribute.State;
@@ -243,27 +241,29 @@
DirCacheIterator itr = walk.getTree(0, DirCacheIterator.class);
assertNotNull("has tree", itr);
- AttributesNode attributeNode = itr.getEntryAttributesNode(db
+ AttributesNode attributesNode = itr.getEntryAttributesNode(db
.newObjectReader());
- assertAttributeNode(pathName, attributeNode, nodeAttrs);
+ assertAttributesNode(pathName, attributesNode, nodeAttrs);
if (D.equals(type))
walk.enterSubtree();
}
- private void assertAttributeNode(String pathName,
- AttributesNode attributeNode, List<Attribute> nodeAttrs) {
- if (attributeNode == null)
+ private void assertAttributesNode(String pathName,
+ AttributesNode attributesNode, List<Attribute> nodeAttrs) {
+ if (attributesNode == null)
assertTrue(nodeAttrs == null || nodeAttrs.isEmpty());
else {
- Map<String, Attribute> entryAttributes = new LinkedHashMap<String, Attribute>();
- attributeNode.getAttributes(pathName, false, entryAttributes);
+ Attributes entryAttributes = new Attributes();
+ attributesNode.getAttributes(pathName,
+ false, entryAttributes);
if (nodeAttrs != null && !nodeAttrs.isEmpty()) {
for (Attribute attribute : nodeAttrs) {
- assertThat(entryAttributes.values(), hasItem(attribute));
+ assertThat(entryAttributes.getAll(),
+ hasItem(attribute));
}
} else {
assertTrue(
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeNodeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java
similarity index 86%
rename from org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeNodeTest.java
rename to org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java
index ea25036..d478a7c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributeNodeTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeTest.java
@@ -49,10 +49,6 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
import org.junit.After;
import org.junit.Test;
@@ -60,7 +56,7 @@
/**
* Test {@link AttributesNode}
*/
-public class AttributeNodeTest {
+public class AttributesNodeTest {
private static final Attribute A_SET_ATTR = new Attribute("A", SET);
@@ -104,8 +100,8 @@
is = new ByteArrayInputStream(attributeFileContent.getBytes());
AttributesNode node = new AttributesNode();
node.parse(is);
- assertAttribute("file.type1", node, Collections.<Attribute> emptySet());
- assertAttribute("file.type2", node, Collections.<Attribute> emptySet());
+ assertAttribute("file.type1", node, new Attributes());
+ assertAttribute("file.type2", node, new Attributes());
}
@Test
@@ -115,7 +111,7 @@
is = new ByteArrayInputStream(attributeFileContent.getBytes());
AttributesNode node = new AttributesNode();
node.parse(is);
- assertAttribute("file.type1", node, Collections.<Attribute> emptySet());
+ assertAttribute("file.type1", node, new Attributes());
assertAttribute("file.type2", node, asSet(A_UNSET_ATTR));
}
@@ -127,8 +123,8 @@
is = new ByteArrayInputStream(attributeFileContent.getBytes());
AttributesNode node = new AttributesNode();
node.parse(is);
- assertAttribute("file.type1", node, Collections.<Attribute> emptySet());
- assertAttribute("file.type2", node, Collections.<Attribute> emptySet());
+ assertAttribute("file.type1", node, new Attributes());
+ assertAttribute("file.type2", node, new Attributes());
assertAttribute("file.type3", node, asSet(new Attribute("attr", "")));
}
@@ -166,17 +162,14 @@
}
private void assertAttribute(String path, AttributesNode node,
- Set<Attribute> attrs) {
- HashMap<String, Attribute> attributes = new HashMap<String, Attribute>();
+ Attributes attrs) {
+ Attributes attributes = new Attributes();
node.getAttributes(path, false, attributes);
- assertEquals(attrs, new HashSet<Attribute>(attributes.values()));
+ assertEquals(attrs, attributes);
}
- static Set<Attribute> asSet(Attribute... attrs) {
- Set<Attribute> result = new HashSet<Attribute>();
- for (Attribute attr : attrs)
- result.add(attr);
- return result;
+ static Attributes asSet(Attribute... attrs) {
+ return new Attributes(attrs);
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java
index 64b0535..4215ba2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java
@@ -53,12 +53,9 @@
import java.io.File;
import java.io.IOException;
import java.util.Collections;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
import org.eclipse.jgit.attributes.Attribute.State;
-import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.FileMode;
@@ -76,14 +73,10 @@
private static final FileMode F = FileMode.REGULAR_FILE;
- private static Attribute EOL_CRLF = new Attribute("eol", "crlf");
-
private static Attribute EOL_LF = new Attribute("eol", "lf");
private static Attribute DELTA_UNSET = new Attribute("delta", State.UNSET);
- private static Attribute CUSTOM_VALUE = new Attribute("custom", "value");
-
private TreeWalk walk;
@Test
@@ -112,25 +105,19 @@
walk = beginWalk();
assertIteration(F, ".gitattributes");
- assertIteration(F, "global.txt", asList(EOL_LF), null,
- asList(CUSTOM_VALUE));
- assertIteration(F, "readme.txt", asList(EOL_LF), null,
- asList(CUSTOM_VALUE));
+ assertIteration(F, "global.txt", asList(EOL_LF));
+ assertIteration(F, "readme.txt", asList(EOL_LF));
assertIteration(D, "src");
assertIteration(D, "src/config");
assertIteration(F, "src/config/.gitattributes");
- assertIteration(F, "src/config/readme.txt", asList(DELTA_UNSET), null,
- asList(CUSTOM_VALUE));
- assertIteration(F, "src/config/windows.file", null, asList(EOL_CRLF),
- null);
- assertIteration(F, "src/config/windows.txt", asList(DELTA_UNSET),
- asList(EOL_CRLF), asList(CUSTOM_VALUE));
+ assertIteration(F, "src/config/readme.txt", asList(DELTA_UNSET));
+ assertIteration(F, "src/config/windows.file", null);
+ assertIteration(F, "src/config/windows.txt", asList(DELTA_UNSET));
- assertIteration(F, "windows.file", null, asList(EOL_CRLF), null);
- assertIteration(F, "windows.txt", asList(EOL_LF), asList(EOL_CRLF),
- asList(CUSTOM_VALUE));
+ assertIteration(F, "windows.file", null);
+ assertIteration(F, "windows.txt", asList(EOL_LF));
endWalk();
}
@@ -212,14 +199,11 @@
private void assertIteration(FileMode type, String pathName)
throws IOException {
- assertIteration(type, pathName, Collections.<Attribute> emptyList(),
- Collections.<Attribute> emptyList(),
- Collections.<Attribute> emptyList());
+ assertIteration(type, pathName, Collections.<Attribute> emptyList());
}
private void assertIteration(FileMode type, String pathName,
- List<Attribute> nodeAttrs, List<Attribute> infoAttrs,
- List<Attribute> globalAttrs)
+ List<Attribute> nodeAttrs)
throws IOException {
assertTrue("walk has entry", walk.next());
assertEquals(pathName, walk.getPathString());
@@ -227,29 +211,27 @@
WorkingTreeIterator itr = walk.getTree(0, WorkingTreeIterator.class);
assertNotNull("has tree", itr);
- AttributesNode attributeNode = itr.getEntryAttributesNode();
- assertAttributeNode(pathName, attributeNode, nodeAttrs);
- AttributesNode infoAttributeNode = itr.getInfoAttributesNode();
- assertAttributeNode(pathName, infoAttributeNode, infoAttrs);
- AttributesNode globalAttributeNode = itr.getGlobalAttributesNode();
- assertAttributeNode(pathName, globalAttributeNode, globalAttrs);
+ AttributesNode attributesNode = itr.getEntryAttributesNode();
+ assertAttributesNode(pathName, attributesNode, nodeAttrs);
if (D.equals(type))
walk.enterSubtree();
}
- private void assertAttributeNode(String pathName,
- AttributesNode attributeNode, List<Attribute> nodeAttrs) {
- if (attributeNode == null)
+ private void assertAttributesNode(String pathName,
+ AttributesNode attributesNode, List<Attribute> nodeAttrs) {
+ if (attributesNode == null)
assertTrue(nodeAttrs == null || nodeAttrs.isEmpty());
else {
- Map<String, Attribute> entryAttributes = new LinkedHashMap<String, Attribute>();
- attributeNode.getAttributes(pathName, false, entryAttributes);
+ Attributes entryAttributes = new Attributes();
+ attributesNode.getAttributes(pathName,
+ false, entryAttributes);
if (nodeAttrs != null && !nodeAttrs.isEmpty()) {
for (Attribute attribute : nodeAttrs) {
- assertThat(entryAttributes.values(), hasItem(attribute));
+ assertThat(entryAttributes.getAll(),
+ hasItem(attribute));
}
} else {
assertTrue(
@@ -270,7 +252,7 @@
writeTrashFile(name, data.toString());
}
- private TreeWalk beginWalk() throws CorruptObjectException {
+ private TreeWalk beginWalk() {
TreeWalk newWalk = new TreeWalk(db);
newWalk.addTree(new FileTreeIterator(db));
return newWalk;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java
new file mode 100644
index 0000000..b044c01
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java
@@ -0,0 +1,866 @@
+/*
+ * Copyright (C) 2014, Obeo.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.attributes;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.NoFilepatternException;
+import org.eclipse.jgit.attributes.Attribute.State;
+import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.errors.NoWorkTreeException;
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests the attributes are correctly computed in a {@link TreeWalk}.
+ *
+ * @see TreeWalk#getAttributes()
+ */
+public class TreeWalkAttributeTest extends RepositoryTestCase {
+
+ private static final FileMode M = FileMode.MISSING;
+
+ private static final FileMode D = FileMode.TREE;
+
+ private static final FileMode F = FileMode.REGULAR_FILE;
+
+ private static Attribute EOL_CRLF = new Attribute("eol", "crlf");
+
+ private static Attribute EOL_LF = new Attribute("eol", "lf");
+
+ private static Attribute TEXT_SET = new Attribute("text", State.SET);
+
+ private static Attribute TEXT_UNSET = new Attribute("text", State.UNSET);
+
+ private static Attribute DELTA_UNSET = new Attribute("delta", State.UNSET);
+
+ private static Attribute DELTA_SET = new Attribute("delta", State.SET);
+
+ private static Attribute CUSTOM_GLOBAL = new Attribute("custom", "global");
+
+ private static Attribute CUSTOM_INFO = new Attribute("custom", "info");
+
+ private static Attribute CUSTOM_ROOT = new Attribute("custom", "root");
+
+ private static Attribute CUSTOM_PARENT = new Attribute("custom", "parent");
+
+ private static Attribute CUSTOM_CURRENT = new Attribute("custom", "current");
+
+ private static Attribute CUSTOM2_UNSET = new Attribute("custom2",
+ State.UNSET);
+
+ private static Attribute CUSTOM2_SET = new Attribute("custom2", State.SET);
+
+ private TreeWalk walk;
+
+ private TreeWalk ci_walk;
+
+ private Git git;
+
+ private File customAttributeFile;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ git = new Git(db);
+ }
+
+ @Override
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ if (customAttributeFile != null)
+ customAttributeFile.delete();
+ }
+
+ /**
+ * Checks that the attributes are computed correctly depending on the
+ * operation type.
+ * <p>
+ * In this test we changed the content of the attribute files in the working
+ * tree compared to the one in the index.
+ * </p>
+ *
+ * @throws IOException
+ * @throws NoFilepatternException
+ * @throws GitAPIException
+ */
+ @Test
+ public void testCheckinCheckoutDifferences() throws IOException,
+ NoFilepatternException, GitAPIException {
+
+ writeGlobalAttributeFile("globalAttributesFile", "*.txt -custom2");
+ writeAttributesFile(".git/info/attributes", "*.txt eol=crlf");
+ writeAttributesFile(".gitattributes", "*.txt custom=root");
+ writeAttributesFile("level1/.gitattributes", "*.txt text");
+ writeAttributesFile("level1/level2/.gitattributes", "*.txt -delta");
+
+ writeTrashFile("l0.txt", "");
+
+ writeTrashFile("level1/l1.txt", "");
+
+ writeTrashFile("level1/level2/l2.txt", "");
+
+ git.add().addFilepattern(".").call();
+
+ beginWalk();
+
+ // Modify all attributes
+ writeGlobalAttributeFile("globalAttributesFile", "*.txt custom2");
+ writeAttributesFile(".git/info/attributes", "*.txt eol=lf");
+ writeAttributesFile(".gitattributes", "*.txt custom=info");
+ writeAttributesFile("level1/.gitattributes", "*.txt -text");
+ writeAttributesFile("level1/level2/.gitattributes", "*.txt delta");
+
+ assertEntry(F, ".gitattributes");
+ assertEntry(F, "l0.txt", asSet(EOL_LF, CUSTOM_INFO, CUSTOM2_SET),
+ asSet(EOL_LF, CUSTOM_ROOT, CUSTOM2_SET));
+
+ assertEntry(D, "level1");
+ assertEntry(F, "level1/.gitattributes");
+ assertEntry(F, "level1/l1.txt",
+ asSet(EOL_LF, CUSTOM_INFO, CUSTOM2_SET, TEXT_UNSET),
+ asSet(EOL_LF, CUSTOM_ROOT, CUSTOM2_SET, TEXT_SET));
+
+ assertEntry(D, "level1/level2");
+ assertEntry(F, "level1/level2/.gitattributes");
+ assertEntry(F, "level1/level2/l2.txt",
+ asSet(EOL_LF, CUSTOM_INFO, CUSTOM2_SET, TEXT_UNSET, DELTA_SET),
+ asSet(EOL_LF, CUSTOM_ROOT, CUSTOM2_SET, TEXT_SET, DELTA_UNSET));
+
+ endWalk();
+ }
+
+ /**
+ * Checks that the index is used as fallback when the git attributes file
+ * are missing in the working tree.
+ *
+ * @throws IOException
+ * @throws NoFilepatternException
+ * @throws GitAPIException
+ */
+ @Test
+ public void testIndexOnly() throws IOException, NoFilepatternException,
+ GitAPIException {
+ List<File> attrFiles = new ArrayList<File>();
+ attrFiles.add(writeGlobalAttributeFile("globalAttributesFile",
+ "*.txt -custom2"));
+ attrFiles.add(writeAttributesFile(".git/info/attributes",
+ "*.txt eol=crlf"));
+ attrFiles
+ .add(writeAttributesFile(".gitattributes", "*.txt custom=root"));
+ attrFiles
+ .add(writeAttributesFile("level1/.gitattributes", "*.txt text"));
+ attrFiles.add(writeAttributesFile("level1/level2/.gitattributes",
+ "*.txt -delta"));
+
+ writeTrashFile("l0.txt", "");
+
+ writeTrashFile("level1/l1.txt", "");
+
+ writeTrashFile("level1/level2/l2.txt", "");
+
+ git.add().addFilepattern(".").call();
+
+ // Modify all attributes
+ for (File attrFile : attrFiles)
+ attrFile.delete();
+
+ beginWalk();
+
+ assertEntry(M, ".gitattributes");
+ assertEntry(F, "l0.txt", asSet(CUSTOM_ROOT));
+
+ assertEntry(D, "level1");
+ assertEntry(M, "level1/.gitattributes");
+ assertEntry(F, "level1/l1.txt",
+
+ asSet(CUSTOM_ROOT, TEXT_SET));
+
+ assertEntry(D, "level1/level2");
+ assertEntry(M, "level1/level2/.gitattributes");
+ assertEntry(F, "level1/level2/l2.txt",
+
+ asSet(CUSTOM_ROOT, TEXT_SET, DELTA_UNSET));
+
+ endWalk();
+ }
+
+ /**
+ * Check that we search in the working tree for attributes although the file
+ * we are currently inspecting does not exist anymore in the working tree.
+ *
+ * @throws IOException
+ * @throws NoFilepatternException
+ * @throws GitAPIException
+ */
+ @Test
+ public void testIndexOnly2()
+ throws IOException, NoFilepatternException, GitAPIException {
+ File l2 = writeTrashFile("level1/level2/l2.txt", "");
+ writeTrashFile("level1/level2/l1.txt", "");
+
+ git.add().addFilepattern(".").call();
+
+ writeAttributesFile(".gitattributes", "*.txt custom=root");
+ assertTrue(l2.delete());
+
+ beginWalk();
+
+ assertEntry(F, ".gitattributes");
+ assertEntry(D, "level1");
+ assertEntry(D, "level1/level2");
+ assertEntry(F, "level1/level2/l1.txt", asSet(CUSTOM_ROOT));
+ assertEntry(M, "level1/level2/l2.txt", asSet(CUSTOM_ROOT));
+
+ endWalk();
+ }
+
+ /**
+ * Basic test for git attributes.
+ * <p>
+ * In this use case files are present in both the working tree and the index
+ * </p>
+ *
+ * @throws IOException
+ * @throws NoFilepatternException
+ * @throws GitAPIException
+ */
+ @Test
+ public void testRules() throws IOException, NoFilepatternException,
+ GitAPIException {
+ writeAttributesFile(".git/info/attributes", "windows* eol=crlf");
+
+ writeAttributesFile(".gitattributes", "*.txt eol=lf");
+ writeTrashFile("windows.file", "");
+ writeTrashFile("windows.txt", "");
+ writeTrashFile("readme.txt", "");
+
+ writeAttributesFile("src/config/.gitattributes", "*.txt -delta");
+ writeTrashFile("src/config/readme.txt", "");
+ writeTrashFile("src/config/windows.file", "");
+ writeTrashFile("src/config/windows.txt", "");
+
+ beginWalk();
+
+ git.add().addFilepattern(".").call();
+
+ assertEntry(F, ".gitattributes");
+ assertEntry(F, "readme.txt", asSet(EOL_LF));
+
+ assertEntry(D, "src");
+ assertEntry(D, "src/config");
+ assertEntry(F, "src/config/.gitattributes");
+ assertEntry(F, "src/config/readme.txt", asSet(DELTA_UNSET, EOL_LF));
+ assertEntry(F, "src/config/windows.file", asSet(EOL_CRLF));
+ assertEntry(F, "src/config/windows.txt", asSet(DELTA_UNSET, EOL_CRLF));
+
+ assertEntry(F, "windows.file", asSet(EOL_CRLF));
+ assertEntry(F, "windows.txt", asSet(EOL_CRLF));
+
+ endWalk();
+ }
+
+ /**
+ * Checks that if there is no .gitattributes file in the repository
+ * everything still work fine.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testNoAttributes() throws IOException {
+ writeTrashFile("l0.txt", "");
+ writeTrashFile("level1/l1.txt", "");
+ writeTrashFile("level1/level2/l2.txt", "");
+
+ beginWalk();
+
+ assertEntry(F, "l0.txt");
+
+ assertEntry(D, "level1");
+ assertEntry(F, "level1/l1.txt");
+
+ assertEntry(D, "level1/level2");
+ assertEntry(F, "level1/level2/l2.txt");
+
+ endWalk();
+ }
+
+ /**
+ * Checks that an empty .gitattribute file does not return incorrect value.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testEmptyGitAttributeFile() throws IOException {
+ writeAttributesFile(".git/info/attributes", "");
+ writeTrashFile("l0.txt", "");
+ writeAttributesFile(".gitattributes", "");
+ writeTrashFile("level1/l1.txt", "");
+ writeTrashFile("level1/level2/l2.txt", "");
+
+ beginWalk();
+
+ assertEntry(F, ".gitattributes");
+ assertEntry(F, "l0.txt");
+
+ assertEntry(D, "level1");
+ assertEntry(F, "level1/l1.txt");
+
+ assertEntry(D, "level1/level2");
+ assertEntry(F, "level1/level2/l2.txt");
+
+ endWalk();
+ }
+
+ @Test
+ public void testNoMatchingAttributes() throws IOException {
+ writeAttributesFile(".git/info/attributes", "*.java delta");
+ writeAttributesFile(".gitattributes", "*.java -delta");
+ writeAttributesFile("levelA/.gitattributes", "*.java eol=lf");
+ writeAttributesFile("levelB/.gitattributes", "*.txt eol=lf");
+
+ writeTrashFile("levelA/lA.txt", "");
+
+ beginWalk();
+
+ assertEntry(F, ".gitattributes");
+
+ assertEntry(D, "levelA");
+ assertEntry(F, "levelA/.gitattributes");
+ assertEntry(F, "levelA/lA.txt");
+
+ assertEntry(D, "levelB");
+ assertEntry(F, "levelB/.gitattributes");
+
+ endWalk();
+ }
+
+ /**
+ * Checks that $GIT_DIR/info/attributes file has the highest precedence.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testPrecedenceInfo() throws IOException {
+ writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global");
+ writeAttributesFile(".git/info/attributes", "*.txt custom=info");
+ writeAttributesFile(".gitattributes", "*.txt custom=root");
+ writeAttributesFile("level1/.gitattributes", "*.txt custom=parent");
+ writeAttributesFile("level1/level2/.gitattributes",
+ "*.txt custom=current");
+
+ writeTrashFile("level1/level2/file.txt", "");
+
+ beginWalk();
+
+ assertEntry(F, ".gitattributes");
+
+ assertEntry(D, "level1");
+ assertEntry(F, "level1/.gitattributes");
+
+ assertEntry(D, "level1/level2");
+ assertEntry(F, "level1/level2/.gitattributes");
+ assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_INFO));
+
+ endWalk();
+ }
+
+ /**
+ * Checks that a subfolder ".gitattributes" file has precedence over its
+ * parent.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testPrecedenceCurrent() throws IOException {
+ writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global");
+ writeAttributesFile(".gitattributes", "*.txt custom=root");
+ writeAttributesFile("level1/.gitattributes", "*.txt custom=parent");
+ writeAttributesFile("level1/level2/.gitattributes",
+ "*.txt custom=current");
+
+ writeTrashFile("level1/level2/file.txt", "");
+
+ beginWalk();
+
+ assertEntry(F, ".gitattributes");
+
+ assertEntry(D, "level1");
+ assertEntry(F, "level1/.gitattributes");
+
+ assertEntry(D, "level1/level2");
+ assertEntry(F, "level1/level2/.gitattributes");
+ assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_CURRENT));
+
+ endWalk();
+ }
+
+ /**
+ * Checks that the parent ".gitattributes" file is used as fallback.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testPrecedenceParent() throws IOException {
+ writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global");
+ writeAttributesFile(".gitattributes", "*.txt custom=root");
+ writeAttributesFile("level1/.gitattributes", "*.txt custom=parent");
+
+ writeTrashFile("level1/level2/file.txt", "");
+
+ beginWalk();
+
+ assertEntry(F, ".gitattributes");
+
+ assertEntry(D, "level1");
+ assertEntry(F, "level1/.gitattributes");
+
+ assertEntry(D, "level1/level2");
+ assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_PARENT));
+
+ endWalk();
+ }
+
+ /**
+ * Checks that the grand parent ".gitattributes" file is used as fallback.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testPrecedenceRoot() throws IOException {
+ writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global");
+ writeAttributesFile(".gitattributes", "*.txt custom=root");
+
+ writeTrashFile("level1/level2/file.txt", "");
+
+ beginWalk();
+
+ assertEntry(F, ".gitattributes");
+
+ assertEntry(D, "level1");
+
+ assertEntry(D, "level1/level2");
+ assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_ROOT));
+
+ endWalk();
+ }
+
+ /**
+ * Checks that the global attribute file is used as fallback.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testPrecedenceGlobal() throws IOException {
+ writeGlobalAttributeFile("globalAttributesFile", "*.txt custom=global");
+
+ writeTrashFile("level1/level2/file.txt", "");
+
+ beginWalk();
+
+ assertEntry(D, "level1");
+
+ assertEntry(D, "level1/level2");
+ assertEntry(F, "level1/level2/file.txt", asSet(CUSTOM_GLOBAL));
+
+ endWalk();
+ }
+
+ /**
+ * Checks the precedence on a hierarchy with multiple attributes.
+ * <p>
+ * In this test all file are present in both the working tree and the index.
+ * </p>
+ *
+ * @throws IOException
+ * @throws GitAPIException
+ * @throws NoFilepatternException
+ */
+ @Test
+ public void testHierarchyBothIterator() throws IOException,
+ NoFilepatternException, GitAPIException {
+ writeAttributesFile(".git/info/attributes", "*.global eol=crlf");
+ writeAttributesFile(".gitattributes", "*.local eol=lf");
+ writeAttributesFile("level1/.gitattributes", "*.local text");
+ writeAttributesFile("level1/level2/.gitattributes", "*.local -text");
+
+ writeTrashFile("l0.global", "");
+ writeTrashFile("l0.local", "");
+
+ writeTrashFile("level1/l1.global", "");
+ writeTrashFile("level1/l1.local", "");
+
+ writeTrashFile("level1/level2/l2.global", "");
+ writeTrashFile("level1/level2/l2.local", "");
+
+ beginWalk();
+
+ git.add().addFilepattern(".").call();
+
+ assertEntry(F, ".gitattributes");
+ assertEntry(F, "l0.global", asSet(EOL_CRLF));
+ assertEntry(F, "l0.local", asSet(EOL_LF));
+
+ assertEntry(D, "level1");
+ assertEntry(F, "level1/.gitattributes");
+ assertEntry(F, "level1/l1.global", asSet(EOL_CRLF));
+ assertEntry(F, "level1/l1.local", asSet(EOL_LF, TEXT_SET));
+
+ assertEntry(D, "level1/level2");
+ assertEntry(F, "level1/level2/.gitattributes");
+ assertEntry(F, "level1/level2/l2.global", asSet(EOL_CRLF));
+ assertEntry(F, "level1/level2/l2.local", asSet(EOL_LF, TEXT_UNSET));
+
+ endWalk();
+
+ }
+
+ /**
+ * Checks the precedence on a hierarchy with multiple attributes.
+ * <p>
+ * In this test all file are present only in the working tree.
+ * </p>
+ *
+ * @throws IOException
+ * @throws GitAPIException
+ * @throws NoFilepatternException
+ */
+ @Test
+ public void testHierarchyWorktreeOnly()
+ throws IOException, NoFilepatternException, GitAPIException {
+ writeAttributesFile(".git/info/attributes", "*.global eol=crlf");
+ writeAttributesFile(".gitattributes", "*.local eol=lf");
+ writeAttributesFile("level1/.gitattributes", "*.local text");
+ writeAttributesFile("level1/level2/.gitattributes", "*.local -text");
+
+ writeTrashFile("l0.global", "");
+ writeTrashFile("l0.local", "");
+
+ writeTrashFile("level1/l1.global", "");
+ writeTrashFile("level1/l1.local", "");
+
+ writeTrashFile("level1/level2/l2.global", "");
+ writeTrashFile("level1/level2/l2.local", "");
+
+ beginWalk();
+
+ assertEntry(F, ".gitattributes");
+ assertEntry(F, "l0.global", asSet(EOL_CRLF));
+ assertEntry(F, "l0.local", asSet(EOL_LF));
+
+ assertEntry(D, "level1");
+ assertEntry(F, "level1/.gitattributes");
+ assertEntry(F, "level1/l1.global", asSet(EOL_CRLF));
+ assertEntry(F, "level1/l1.local", asSet(EOL_LF, TEXT_SET));
+
+ assertEntry(D, "level1/level2");
+ assertEntry(F, "level1/level2/.gitattributes");
+ assertEntry(F, "level1/level2/l2.global", asSet(EOL_CRLF));
+ assertEntry(F, "level1/level2/l2.local", asSet(EOL_LF, TEXT_UNSET));
+
+ endWalk();
+
+ }
+
+ /**
+ * Checks that the list of attributes is an aggregation of all the
+ * attributes from the attributes files hierarchy.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testAggregation() throws IOException {
+ writeGlobalAttributeFile("globalAttributesFile", "*.txt -custom2");
+ writeAttributesFile(".git/info/attributes", "*.txt eol=crlf");
+ writeAttributesFile(".gitattributes", "*.txt custom=root");
+ writeAttributesFile("level1/.gitattributes", "*.txt text");
+ writeAttributesFile("level1/level2/.gitattributes", "*.txt -delta");
+
+ writeTrashFile("l0.txt", "");
+
+ writeTrashFile("level1/l1.txt", "");
+
+ writeTrashFile("level1/level2/l2.txt", "");
+
+ beginWalk();
+
+ assertEntry(F, ".gitattributes");
+ assertEntry(F, "l0.txt", asSet(EOL_CRLF, CUSTOM_ROOT, CUSTOM2_UNSET));
+
+ assertEntry(D, "level1");
+ assertEntry(F, "level1/.gitattributes");
+ assertEntry(F, "level1/l1.txt",
+ asSet(EOL_CRLF, CUSTOM_ROOT, TEXT_SET, CUSTOM2_UNSET));
+
+ assertEntry(D, "level1/level2");
+ assertEntry(F, "level1/level2/.gitattributes");
+ assertEntry(
+ F,
+ "level1/level2/l2.txt",
+ asSet(EOL_CRLF, CUSTOM_ROOT, TEXT_SET, DELTA_UNSET,
+ CUSTOM2_UNSET));
+
+ endWalk();
+
+ }
+
+ /**
+ * Checks that the last entry in .gitattributes is used if 2 lines match the
+ * same attribute
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testOverriding() throws IOException {
+ writeAttributesFile(".git/info/attributes",//
+ //
+ "*.txt custom=current",//
+ "*.txt custom=parent",//
+ "*.txt custom=root",//
+ "*.txt custom=info",
+ //
+ "*.txt delta",//
+ "*.txt -delta",
+ //
+ "*.txt eol=lf",//
+ "*.txt eol=crlf",
+ //
+ "*.txt text",//
+ "*.txt -text");
+
+ writeTrashFile("l0.txt", "");
+ beginWalk();
+
+ assertEntry(F, "l0.txt",
+ asSet(TEXT_UNSET, EOL_CRLF, DELTA_UNSET, CUSTOM_INFO));
+
+ endWalk();
+ }
+
+ /**
+ * Checks that the last value of an attribute is used if in the same line an
+ * attribute is defined several time.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testOverriding2() throws IOException {
+ writeAttributesFile(".git/info/attributes",
+ "*.txt custom=current custom=parent custom=root custom=info",//
+ "*.txt delta -delta",//
+ "*.txt eol=lf eol=crlf",//
+ "*.txt text -text");
+ writeTrashFile("l0.txt", "");
+ beginWalk();
+
+ assertEntry(F, "l0.txt",
+ asSet(TEXT_UNSET, EOL_CRLF, DELTA_UNSET, CUSTOM_INFO));
+
+ endWalk();
+ }
+
+ @Test
+ public void testRulesInherited() throws Exception {
+ writeAttributesFile(".gitattributes", "**/*.txt eol=lf");
+ writeTrashFile("src/config/readme.txt", "");
+ writeTrashFile("src/config/windows.file", "");
+
+ beginWalk();
+
+ assertEntry(F, ".gitattributes");
+ assertEntry(D, "src");
+ assertEntry(D, "src/config");
+
+ assertEntry(F, "src/config/readme.txt", asSet(EOL_LF));
+ assertEntry(F, "src/config/windows.file",
+ Collections.<Attribute> emptySet());
+
+ endWalk();
+ }
+
+ private void beginWalk() throws NoWorkTreeException, IOException {
+ walk = new TreeWalk(db);
+ walk.addTree(new FileTreeIterator(db));
+ walk.addTree(new DirCacheIterator(db.readDirCache()));
+
+ ci_walk = new TreeWalk(db);
+ ci_walk.setOperationType(OperationType.CHECKIN_OP);
+ ci_walk.addTree(new FileTreeIterator(db));
+ ci_walk.addTree(new DirCacheIterator(db.readDirCache()));
+ }
+
+ /**
+ * Assert an entry in which checkin and checkout attributes are expected to
+ * be the same.
+ *
+ * @param type
+ * @param pathName
+ * @param forBothOperaiton
+ * @throws IOException
+ */
+ private void assertEntry(FileMode type, String pathName,
+ Set<Attribute> forBothOperaiton) throws IOException {
+ assertEntry(type, pathName, forBothOperaiton, forBothOperaiton);
+ }
+
+ /**
+ * Assert an entry with no attribute expected.
+ *
+ * @param type
+ * @param pathName
+ * @throws IOException
+ */
+ private void assertEntry(FileMode type, String pathName) throws IOException {
+ assertEntry(type, pathName, Collections.<Attribute> emptySet(),
+ Collections.<Attribute> emptySet());
+ }
+
+ /**
+ * Assert that an entry;
+ * <ul>
+ * <li>Has the correct type</li>
+ * <li>Exist in the tree walk</li>
+ * <li>Has the expected attributes on a checkin operation</li>
+ * <li>Has the expected attributes on a checkout operation</li>
+ * </ul>
+ *
+ * @param type
+ * @param pathName
+ * @param checkinAttributes
+ * @param checkoutAttributes
+ * @throws IOException
+ */
+ private void assertEntry(FileMode type, String pathName,
+ Set<Attribute> checkinAttributes, Set<Attribute> checkoutAttributes)
+ throws IOException {
+ assertTrue("walk has entry", walk.next());
+ assertTrue("walk has entry", ci_walk.next());
+ assertEquals(pathName, walk.getPathString());
+ assertEquals(type, walk.getFileMode(0));
+
+ assertEquals(checkinAttributes,
+ asSet(ci_walk.getAttributes().getAll()));
+ assertEquals(checkoutAttributes,
+ asSet(walk.getAttributes().getAll()));
+
+ if (D.equals(type)) {
+ walk.enterSubtree();
+ ci_walk.enterSubtree();
+ }
+ }
+
+ private static Set<Attribute> asSet(Collection<Attribute> attributes) {
+ Set<Attribute> ret = new HashSet<Attribute>();
+ for (Attribute a : attributes) {
+ ret.add(a);
+ }
+ return (ret);
+ }
+
+ private File writeAttributesFile(String name, String... rules)
+ throws IOException {
+ StringBuilder data = new StringBuilder();
+ for (String line : rules)
+ data.append(line + "\n");
+ return writeTrashFile(name, data.toString());
+ }
+
+ /**
+ * Creates an attributes file and set its location in the git configuration.
+ *
+ * @param fileName
+ * @param attributes
+ * @return The attribute file
+ * @throws IOException
+ * @see Repository#getConfig()
+ */
+ private File writeGlobalAttributeFile(String fileName, String... attributes)
+ throws IOException {
+ customAttributeFile = File.createTempFile("tmp_", fileName, null);
+ customAttributeFile.deleteOnExit();
+ StringBuilder attributesFileContent = new StringBuilder();
+ for (String attr : attributes) {
+ attributesFileContent.append(attr).append("\n");
+ }
+ JGitTestUtil.write(customAttributeFile,
+ attributesFileContent.toString());
+ db.getConfig().setString("core", null, "attributesfile",
+ customAttributeFile.getAbsolutePath());
+ return customAttributeFile;
+ }
+
+ static Set<Attribute> asSet(Attribute... attrs) {
+ HashSet<Attribute> result = new HashSet<Attribute>();
+ for (Attribute attr : attrs)
+ result.add(attr);
+ return result;
+ }
+
+ private void endWalk() throws IOException {
+ assertFalse("Not all files tested", walk.next());
+ assertFalse("Not all files tested", ci_walk.next());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java
index 5694e83..443c956 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffEntryTest.java
@@ -77,260 +77,268 @@
public void shouldListAddedFileInInitialCommit() throws Exception {
// given
writeTrashFile("a.txt", "content");
- Git git = new Git(db);
- git.add().addFilepattern("a.txt").call();
- RevCommit c = git.commit().setMessage("initial commit").call();
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ git.add().addFilepattern("a.txt").call();
+ RevCommit c = git.commit().setMessage("initial commit").call();
- // when
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(new EmptyTreeIterator());
- walk.addTree(c.getTree());
- List<DiffEntry> result = DiffEntry.scan(walk);
+ // when
+ walk.addTree(new EmptyTreeIterator());
+ walk.addTree(c.getTree());
+ List<DiffEntry> result = DiffEntry.scan(walk);
- // then
- assertThat(result, notNullValue());
- assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
+ // then
+ assertThat(result, notNullValue());
+ assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
- DiffEntry entry = result.get(0);
- assertThat(entry.getChangeType(), is(ChangeType.ADD));
- assertThat(entry.getNewPath(), is("a.txt"));
- assertThat(entry.getOldPath(), is(DEV_NULL));
+ DiffEntry entry = result.get(0);
+ assertThat(entry.getChangeType(), is(ChangeType.ADD));
+ assertThat(entry.getNewPath(), is("a.txt"));
+ assertThat(entry.getOldPath(), is(DEV_NULL));
+ }
}
@Test
public void shouldListAddedFileBetweenTwoCommits() throws Exception {
// given
- Git git = new Git(db);
- RevCommit c1 = git.commit().setMessage("initial commit").call();
- writeTrashFile("a.txt", "content");
- git.add().addFilepattern("a.txt").call();
- RevCommit c2 = git.commit().setMessage("second commit").call();
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ RevCommit c1 = git.commit().setMessage("initial commit").call();
+ writeTrashFile("a.txt", "content");
+ git.add().addFilepattern("a.txt").call();
+ RevCommit c2 = git.commit().setMessage("second commit").call();
- // when
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(c1.getTree());
- walk.addTree(c2.getTree());
- List<DiffEntry> result = DiffEntry.scan(walk);
+ // when
+ walk.addTree(c1.getTree());
+ walk.addTree(c2.getTree());
+ List<DiffEntry> result = DiffEntry.scan(walk);
- // then
- assertThat(result, notNullValue());
- assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
+ // then
+ assertThat(result, notNullValue());
+ assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
- DiffEntry entry = result.get(0);
- assertThat(entry.getChangeType(), is(ChangeType.ADD));
- assertThat(entry.getNewPath(), is("a.txt"));
- assertThat(entry.getOldPath(), is(DEV_NULL));
+ DiffEntry entry = result.get(0);
+ assertThat(entry.getChangeType(), is(ChangeType.ADD));
+ assertThat(entry.getNewPath(), is("a.txt"));
+ assertThat(entry.getOldPath(), is(DEV_NULL));
+ }
}
@Test
public void shouldListModificationBetweenTwoCommits() throws Exception {
// given
- Git git = new Git(db);
- File file = writeTrashFile("a.txt", "content");
- git.add().addFilepattern("a.txt").call();
- RevCommit c1 = git.commit().setMessage("initial commit").call();
- write(file, "new content");
- RevCommit c2 = git.commit().setAll(true).setMessage("second commit")
- .call();
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ File file = writeTrashFile("a.txt", "content");
+ git.add().addFilepattern("a.txt").call();
+ RevCommit c1 = git.commit().setMessage("initial commit").call();
+ write(file, "new content");
+ RevCommit c2 = git.commit().setAll(true).setMessage("second commit")
+ .call();
- // when
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(c1.getTree());
- walk.addTree(c2.getTree());
- List<DiffEntry> result = DiffEntry.scan(walk);
+ // when
+ walk.addTree(c1.getTree());
+ walk.addTree(c2.getTree());
+ List<DiffEntry> result = DiffEntry.scan(walk);
- // then
- assertThat(result, notNullValue());
- assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
+ // then
+ assertThat(result, notNullValue());
+ assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
- DiffEntry entry = result.get(0);
- assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
- assertThat(entry.getNewPath(), is("a.txt"));
+ DiffEntry entry = result.get(0);
+ assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
+ assertThat(entry.getNewPath(), is("a.txt"));
+ }
}
@Test
public void shouldListDeletionBetweenTwoCommits() throws Exception {
// given
- Git git = new Git(db);
- File file = writeTrashFile("a.txt", "content");
- git.add().addFilepattern("a.txt").call();
- RevCommit c1 = git.commit().setMessage("initial commit").call();
- delete(file);
- RevCommit c2 = git.commit().setAll(true).setMessage("delete a.txt")
- .call();
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ File file = writeTrashFile("a.txt", "content");
+ git.add().addFilepattern("a.txt").call();
+ RevCommit c1 = git.commit().setMessage("initial commit").call();
+ delete(file);
+ RevCommit c2 = git.commit().setAll(true).setMessage("delete a.txt")
+ .call();
- // when
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(c1.getTree());
- walk.addTree(c2.getTree());
- List<DiffEntry> result = DiffEntry.scan(walk);
+ // when
+ walk.addTree(c1.getTree());
+ walk.addTree(c2.getTree());
+ List<DiffEntry> result = DiffEntry.scan(walk);
- // then
- assertThat(result, notNullValue());
- assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
+ // then
+ assertThat(result, notNullValue());
+ assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
- DiffEntry entry = result.get(0);
- assertThat(entry.getOldPath(), is("a.txt"));
- assertThat(entry.getNewPath(), is(DEV_NULL));
- assertThat(entry.getChangeType(), is(ChangeType.DELETE));
+ DiffEntry entry = result.get(0);
+ assertThat(entry.getOldPath(), is("a.txt"));
+ assertThat(entry.getNewPath(), is(DEV_NULL));
+ assertThat(entry.getChangeType(), is(ChangeType.DELETE));
+ }
}
@Test
public void shouldListModificationInDirWithoutModifiedTrees()
throws Exception {
// given
- Git git = new Git(db);
- File tree = new File(new File(db.getWorkTree(), "a"), "b");
- FileUtils.mkdirs(tree);
- File file = new File(tree, "c.txt");
- FileUtils.createNewFile(file);
- write(file, "content");
- git.add().addFilepattern("a").call();
- RevCommit c1 = git.commit().setMessage("initial commit").call();
- write(file, "new line");
- RevCommit c2 = git.commit().setAll(true).setMessage("second commit")
- .call();
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ File tree = new File(new File(db.getWorkTree(), "a"), "b");
+ FileUtils.mkdirs(tree);
+ File file = new File(tree, "c.txt");
+ FileUtils.createNewFile(file);
+ write(file, "content");
+ git.add().addFilepattern("a").call();
+ RevCommit c1 = git.commit().setMessage("initial commit").call();
+ write(file, "new line");
+ RevCommit c2 = git.commit().setAll(true).setMessage("second commit")
+ .call();
- // when
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(c1.getTree());
- walk.addTree(c2.getTree());
- walk.setRecursive(true);
- List<DiffEntry> result = DiffEntry.scan(walk);
+ // when
+ walk.addTree(c1.getTree());
+ walk.addTree(c2.getTree());
+ walk.setRecursive(true);
+ List<DiffEntry> result = DiffEntry.scan(walk);
- // then
- assertThat(result, notNullValue());
- assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
+ // then
+ assertThat(result, notNullValue());
+ assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
- DiffEntry entry = result.get(0);
- assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
- assertThat(entry.getNewPath(), is("a/b/c.txt"));
+ DiffEntry entry = result.get(0);
+ assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
+ assertThat(entry.getNewPath(), is("a/b/c.txt"));
+ }
}
@Test
public void shouldListModificationInDirWithModifiedTrees() throws Exception {
// given
- Git git = new Git(db);
- File tree = new File(new File(db.getWorkTree(), "a"), "b");
- FileUtils.mkdirs(tree);
- File file = new File(tree, "c.txt");
- FileUtils.createNewFile(file);
- write(file, "content");
- git.add().addFilepattern("a").call();
- RevCommit c1 = git.commit().setMessage("initial commit").call();
- write(file, "new line");
- RevCommit c2 = git.commit().setAll(true).setMessage("second commit")
- .call();
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ File tree = new File(new File(db.getWorkTree(), "a"), "b");
+ FileUtils.mkdirs(tree);
+ File file = new File(tree, "c.txt");
+ FileUtils.createNewFile(file);
+ write(file, "content");
+ git.add().addFilepattern("a").call();
+ RevCommit c1 = git.commit().setMessage("initial commit").call();
+ write(file, "new line");
+ RevCommit c2 = git.commit().setAll(true).setMessage("second commit")
+ .call();
- // when
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(c1.getTree());
- walk.addTree(c2.getTree());
- List<DiffEntry> result = DiffEntry.scan(walk, true);
+ // when
+ walk.addTree(c1.getTree());
+ walk.addTree(c2.getTree());
+ List<DiffEntry> result = DiffEntry.scan(walk, true);
- // then
- assertThat(result, notNullValue());
- assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(3)));
+ // then
+ assertThat(result, notNullValue());
+ assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(3)));
- DiffEntry entry = result.get(0);
- assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
- assertThat(entry.getNewPath(), is("a"));
+ DiffEntry entry = result.get(0);
+ assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
+ assertThat(entry.getNewPath(), is("a"));
- entry = result.get(1);
- assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
- assertThat(entry.getNewPath(), is("a/b"));
+ entry = result.get(1);
+ assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
+ assertThat(entry.getNewPath(), is("a/b"));
- entry = result.get(2);
- assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
- assertThat(entry.getNewPath(), is("a/b/c.txt"));
+ entry = result.get(2);
+ assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
+ assertThat(entry.getNewPath(), is("a/b/c.txt"));
+ }
}
@Test
public void shouldListChangesInWorkingTree() throws Exception {
// given
writeTrashFile("a.txt", "content");
- Git git = new Git(db);
- git.add().addFilepattern("a.txt").call();
- RevCommit c = git.commit().setMessage("initial commit").call();
- writeTrashFile("b.txt", "new line");
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ git.add().addFilepattern("a.txt").call();
+ RevCommit c = git.commit().setMessage("initial commit").call();
+ writeTrashFile("b.txt", "new line");
- // when
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(c.getTree());
- walk.addTree(new FileTreeIterator(db));
- List<DiffEntry> result = DiffEntry.scan(walk, true);
+ // when
+ walk.addTree(c.getTree());
+ walk.addTree(new FileTreeIterator(db));
+ List<DiffEntry> result = DiffEntry.scan(walk, true);
- // then
- assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
- DiffEntry entry = result.get(0);
+ // then
+ assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
+ DiffEntry entry = result.get(0);
- assertThat(entry.getChangeType(), is(ChangeType.ADD));
- assertThat(entry.getNewPath(), is("b.txt"));
+ assertThat(entry.getChangeType(), is(ChangeType.ADD));
+ assertThat(entry.getNewPath(), is("b.txt"));
+ }
}
@Test
public void shouldMarkEntriesWhenGivenMarkTreeFilter() throws Exception {
// given
- Git git = new Git(db);
- RevCommit c1 = git.commit().setMessage("initial commit").call();
- FileUtils.mkdir(new File(db.getWorkTree(), "b"));
- writeTrashFile("a.txt", "a");
- writeTrashFile("b/1.txt", "b1");
- writeTrashFile("b/2.txt", "b2");
- writeTrashFile("c.txt", "c");
- git.add().addFilepattern("a.txt").addFilepattern("b")
- .addFilepattern("c.txt").call();
- RevCommit c2 = git.commit().setMessage("second commit").call();
- TreeFilter filterA = PathFilterGroup.createFromStrings("a.txt");
- TreeFilter filterB = PathFilterGroup.createFromStrings("b");
- TreeFilter filterB2 = PathFilterGroup.createFromStrings("b/2.txt");
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ RevCommit c1 = git.commit().setMessage("initial commit").call();
+ FileUtils.mkdir(new File(db.getWorkTree(), "b"));
+ writeTrashFile("a.txt", "a");
+ writeTrashFile("b/1.txt", "b1");
+ writeTrashFile("b/2.txt", "b2");
+ writeTrashFile("c.txt", "c");
+ git.add().addFilepattern("a.txt").addFilepattern("b")
+ .addFilepattern("c.txt").call();
+ RevCommit c2 = git.commit().setMessage("second commit").call();
+ TreeFilter filterA = PathFilterGroup.createFromStrings("a.txt");
+ TreeFilter filterB = PathFilterGroup.createFromStrings("b");
+ TreeFilter filterB2 = PathFilterGroup.createFromStrings("b/2.txt");
- // when
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(c1.getTree());
- walk.addTree(c2.getTree());
- List<DiffEntry> result = DiffEntry.scan(walk, true, new TreeFilter[] {
- filterA, filterB, filterB2 });
+ // when
+ walk.addTree(c1.getTree());
+ walk.addTree(c2.getTree());
+ List<DiffEntry> result = DiffEntry.scan(walk, true, new TreeFilter[] {
+ filterA, filterB, filterB2 });
- // then
- assertThat(result, notNullValue());
- assertEquals(5, result.size());
+ // then
+ assertThat(result, notNullValue());
+ assertEquals(5, result.size());
- DiffEntry entryA = result.get(0);
- DiffEntry entryB = result.get(1);
- DiffEntry entryB1 = result.get(2);
- DiffEntry entryB2 = result.get(3);
- DiffEntry entryC = result.get(4);
+ DiffEntry entryA = result.get(0);
+ DiffEntry entryB = result.get(1);
+ DiffEntry entryB1 = result.get(2);
+ DiffEntry entryB2 = result.get(3);
+ DiffEntry entryC = result.get(4);
- assertThat(entryA.getNewPath(), is("a.txt"));
- assertTrue(entryA.isMarked(0));
- assertFalse(entryA.isMarked(1));
- assertFalse(entryA.isMarked(2));
- assertEquals(1, entryA.getTreeFilterMarks());
+ assertThat(entryA.getNewPath(), is("a.txt"));
+ assertTrue(entryA.isMarked(0));
+ assertFalse(entryA.isMarked(1));
+ assertFalse(entryA.isMarked(2));
+ assertEquals(1, entryA.getTreeFilterMarks());
- assertThat(entryB.getNewPath(), is("b"));
- assertFalse(entryB.isMarked(0));
- assertTrue(entryB.isMarked(1));
- assertTrue(entryB.isMarked(2));
- assertEquals(6, entryB.getTreeFilterMarks());
+ assertThat(entryB.getNewPath(), is("b"));
+ assertFalse(entryB.isMarked(0));
+ assertTrue(entryB.isMarked(1));
+ assertTrue(entryB.isMarked(2));
+ assertEquals(6, entryB.getTreeFilterMarks());
- assertThat(entryB1.getNewPath(), is("b/1.txt"));
- assertFalse(entryB1.isMarked(0));
- assertTrue(entryB1.isMarked(1));
- assertFalse(entryB1.isMarked(2));
- assertEquals(2, entryB1.getTreeFilterMarks());
+ assertThat(entryB1.getNewPath(), is("b/1.txt"));
+ assertFalse(entryB1.isMarked(0));
+ assertTrue(entryB1.isMarked(1));
+ assertFalse(entryB1.isMarked(2));
+ assertEquals(2, entryB1.getTreeFilterMarks());
- assertThat(entryB2.getNewPath(), is("b/2.txt"));
- assertFalse(entryB2.isMarked(0));
- assertTrue(entryB2.isMarked(1));
- assertTrue(entryB2.isMarked(2));
- assertEquals(6, entryB2.getTreeFilterMarks());
+ assertThat(entryB2.getNewPath(), is("b/2.txt"));
+ assertFalse(entryB2.isMarked(0));
+ assertTrue(entryB2.isMarked(1));
+ assertTrue(entryB2.isMarked(2));
+ assertEquals(6, entryB2.getTreeFilterMarks());
- assertThat(entryC.getNewPath(), is("c.txt"));
- assertFalse(entryC.isMarked(0));
- assertFalse(entryC.isMarked(1));
- assertFalse(entryC.isMarked(2));
- assertEquals(0, entryC.getTreeFilterMarks());
+ assertThat(entryC.getNewPath(), is("c.txt"));
+ assertFalse(entryC.isMarked(0));
+ assertFalse(entryC.isMarked(1));
+ assertFalse(entryC.isMarked(2));
+ assertEquals(0, entryC.getTreeFilterMarks());
+ }
}
@Test(expected = IllegalArgumentException.class)
@@ -339,9 +347,10 @@
// given - we don't need anything here
// when
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(new EmptyTreeIterator());
- DiffEntry.scan(walk);
+ try (TreeWalk walk = new TreeWalk(db)) {
+ walk.addTree(new EmptyTreeIterator());
+ DiffEntry.scan(walk);
+ }
}
@Test(expected = IllegalArgumentException.class)
@@ -350,11 +359,12 @@
// given - we don't need anything here
// when
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(new EmptyTreeIterator());
- walk.addTree(new EmptyTreeIterator());
- walk.addTree(new EmptyTreeIterator());
- DiffEntry.scan(walk);
+ try (TreeWalk walk = new TreeWalk(db)) {
+ walk.addTree(new EmptyTreeIterator());
+ walk.addTree(new EmptyTreeIterator());
+ walk.addTree(new EmptyTreeIterator());
+ DiffEntry.scan(walk);
+ }
}
@Test(expected = IllegalArgumentException.class)
@@ -363,46 +373,47 @@
// given - we don't need anything here
// when
- TreeWalk walk = new TreeWalk(db);
- walk.addTree(new EmptyTreeIterator());
- walk.addTree(new EmptyTreeIterator());
- walk.setRecursive(true);
- DiffEntry.scan(walk, true);
+ try (TreeWalk walk = new TreeWalk(db)) {
+ walk.addTree(new EmptyTreeIterator());
+ walk.addTree(new EmptyTreeIterator());
+ walk.setRecursive(true);
+ DiffEntry.scan(walk, true);
+ }
}
@Test
public void shouldReportFileModeChange() throws Exception {
writeTrashFile("a.txt", "content");
- Git git = new Git(db);
- git.add().addFilepattern("a.txt").call();
- RevCommit c1 = git.commit().setMessage("initial commit").call();
- DirCache cache = db.lockDirCache();
- DirCacheEditor editor = cache.editor();
- final TreeWalk walk = new TreeWalk(db);
- walk.addTree(c1.getTree());
- walk.setRecursive(true);
- assertTrue(walk.next());
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ git.add().addFilepattern("a.txt").call();
+ RevCommit c1 = git.commit().setMessage("initial commit").call();
+ DirCache cache = db.lockDirCache();
+ DirCacheEditor editor = cache.editor();
+ walk.addTree(c1.getTree());
+ walk.setRecursive(true);
+ assertTrue(walk.next());
- editor.add(new PathEdit("a.txt") {
-
- public void apply(DirCacheEntry ent) {
- ent.setFileMode(FileMode.EXECUTABLE_FILE);
- ent.setObjectId(walk.getObjectId(0));
- }
- });
- assertTrue(editor.commit());
- RevCommit c2 = git.commit().setMessage("second commit").call();
- walk.reset();
- walk.addTree(c1.getTree());
- walk.addTree(c2.getTree());
- List<DiffEntry> diffs = DiffEntry.scan(walk, false);
- assertEquals(1, diffs.size());
- DiffEntry diff = diffs.get(0);
- assertEquals(ChangeType.MODIFY,diff.getChangeType());
- assertEquals(diff.getOldId(), diff.getNewId());
- assertEquals("a.txt", diff.getOldPath());
- assertEquals(diff.getOldPath(), diff.getNewPath());
- assertEquals(FileMode.EXECUTABLE_FILE, diff.getNewMode());
- assertEquals(FileMode.REGULAR_FILE, diff.getOldMode());
+ editor.add(new PathEdit("a.txt") {
+ public void apply(DirCacheEntry ent) {
+ ent.setFileMode(FileMode.EXECUTABLE_FILE);
+ ent.setObjectId(walk.getObjectId(0));
+ }
+ });
+ assertTrue(editor.commit());
+ RevCommit c2 = git.commit().setMessage("second commit").call();
+ walk.reset();
+ walk.addTree(c1.getTree());
+ walk.addTree(c2.getTree());
+ List<DiffEntry> diffs = DiffEntry.scan(walk, false);
+ assertEquals(1, diffs.size());
+ DiffEntry diff = diffs.get(0);
+ assertEquals(ChangeType.MODIFY,diff.getChangeType());
+ assertEquals(diff.getOldId(), diff.getNewId());
+ assertEquals("a.txt", diff.getOldPath());
+ assertEquals(diff.getOldPath(), diff.getNewPath());
+ assertEquals(FileMode.EXECUTABLE_FILE, diff.getNewMode());
+ assertEquals(FileMode.REGULAR_FILE, diff.getOldMode());
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
index 58348d5..638a163 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
@@ -379,30 +379,31 @@
File folder = new File(db.getDirectory().getParent(), "folder");
FileUtils.mkdir(folder);
write(new File(folder, "folder.txt"), "folder");
- Git git = new Git(db);
- git.add().addFilepattern(".").call();
- git.commit().setMessage("Initial commit").call();
- write(new File(folder, "folder.txt"), "folder change");
+ try (Git git = new Git(db);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os))) {
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("Initial commit").call();
+ write(new File(folder, "folder.txt"), "folder change");
+ dfmt.setRepository(db);
+ dfmt.setPathFilter(PathFilter.create("folder"));
+ DirCacheIterator oldTree = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator newTree = new FileTreeIterator(db);
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os));
- dfmt.setRepository(db);
- dfmt.setPathFilter(PathFilter.create("folder"));
- DirCacheIterator oldTree = new DirCacheIterator(db.readDirCache());
- FileTreeIterator newTree = new FileTreeIterator(db);
- dfmt.format(oldTree, newTree);
- dfmt.flush();
+ dfmt.format(oldTree, newTree);
+ dfmt.flush();
- String actual = os.toString("UTF-8");
- String expected =
- "diff --git a/folder/folder.txt b/folder/folder.txt\n"
- + "index 0119635..95c4c65 100644\n"
- + "--- a/folder/folder.txt\n" + "+++ b/folder/folder.txt\n"
- + "@@ -1 +1 @@\n" + "-folder\n"
- + "\\ No newline at end of file\n" + "+folder change\n"
- + "\\ No newline at end of file\n";
+ String actual = os.toString("UTF-8");
+ String expected =
+ "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+ + "index 0119635..95c4c65 100644\n"
+ + "--- a/folder/folder.txt\n" + "+++ b/folder/folder.txt\n"
+ + "@@ -1 +1 @@\n" + "-folder\n"
+ + "\\ No newline at end of file\n" + "+folder change\n"
+ + "\\ No newline at end of file\n";
- assertEquals(expected, actual);
+ assertEquals(expected, actual);
+ }
}
@Test
@@ -411,29 +412,30 @@
File folder = new File(db.getDirectory().getParent(), "folder");
FileUtils.mkdir(folder);
write(new File(folder, "folder.txt"), "folder");
- Git git = new Git(db);
- git.add().addFilepattern(".").call();
- RevCommit commit = git.commit().setMessage("Initial commit").call();
- write(new File(folder, "folder.txt"), "folder change");
+ try (Git git = new Git(db);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os))) {
+ git.add().addFilepattern(".").call();
+ RevCommit commit = git.commit().setMessage("Initial commit").call();
+ write(new File(folder, "folder.txt"), "folder change");
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os));
- dfmt.setRepository(db);
- dfmt.setPathFilter(PathFilter.create("folder"));
- dfmt.format(null, commit.getTree().getId());
- dfmt.flush();
+ dfmt.setRepository(db);
+ dfmt.setPathFilter(PathFilter.create("folder"));
+ dfmt.format(null, commit.getTree().getId());
+ dfmt.flush();
- String actual = os.toString("UTF-8");
- String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
- + "new file mode 100644\n"
- + "index 0000000..0119635\n"
- + "--- /dev/null\n"
- + "+++ b/folder/folder.txt\n"
- + "@@ -0,0 +1 @@\n"
- + "+folder\n"
- + "\\ No newline at end of file\n";
+ String actual = os.toString("UTF-8");
+ String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+ + "new file mode 100644\n"
+ + "index 0000000..0119635\n"
+ + "--- /dev/null\n"
+ + "+++ b/folder/folder.txt\n"
+ + "@@ -0,0 +1 @@\n"
+ + "+folder\n"
+ + "\\ No newline at end of file\n";
- assertEquals(expected, actual);
+ assertEquals(expected, actual);
+ }
}
@Test
@@ -442,43 +444,45 @@
File folder = new File(db.getDirectory().getParent(), "folder");
FileUtils.mkdir(folder);
write(new File(folder, "folder.txt"), "folder");
- Git git = new Git(db);
- git.add().addFilepattern(".").call();
- RevCommit commit = git.commit().setMessage("Initial commit").call();
- write(new File(folder, "folder.txt"), "folder change");
+ try (Git git = new Git(db);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os));) {
+ git.add().addFilepattern(".").call();
+ RevCommit commit = git.commit().setMessage("Initial commit").call();
+ write(new File(folder, "folder.txt"), "folder change");
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os));
- dfmt.setRepository(db);
- dfmt.setPathFilter(PathFilter.create("folder"));
- dfmt.format(commit.getTree().getId(), null);
- dfmt.flush();
+ dfmt.setRepository(db);
+ dfmt.setPathFilter(PathFilter.create("folder"));
+ dfmt.format(commit.getTree().getId(), null);
+ dfmt.flush();
- String actual = os.toString("UTF-8");
- String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
- + "deleted file mode 100644\n"
- + "index 0119635..0000000\n"
- + "--- a/folder/folder.txt\n"
- + "+++ /dev/null\n"
- + "@@ -1 +0,0 @@\n"
- + "-folder\n"
- + "\\ No newline at end of file\n";
+ String actual = os.toString("UTF-8");
+ String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+ + "deleted file mode 100644\n"
+ + "index 0119635..0000000\n"
+ + "--- a/folder/folder.txt\n"
+ + "+++ /dev/null\n"
+ + "@@ -1 +0,0 @@\n"
+ + "-folder\n"
+ + "\\ No newline at end of file\n";
- assertEquals(expected, actual);
+ assertEquals(expected, actual);
+ }
}
@Test
public void testDiffNullToNull() throws Exception {
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os));
- dfmt.setRepository(db);
- dfmt.format((AnyObjectId) null, null);
- dfmt.flush();
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream();
+ DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os))) {
+ dfmt.setRepository(db);
+ dfmt.format((AnyObjectId) null, null);
+ dfmt.flush();
- String actual = os.toString("UTF-8");
- String expected = "";
+ String actual = os.toString("UTF-8");
+ String expected = "";
- assertEquals(expected, actual);
+ assertEquals(expected, actual);
+ }
}
private static String makeDiffHeader(String pathA, String pathB,
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/PatchIdDiffFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/PatchIdDiffFormatterTest.java
index ce283ae..024aaa3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/PatchIdDiffFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/PatchIdDiffFormatterTest.java
@@ -61,21 +61,22 @@
File folder = new File(db.getDirectory().getParent(), "folder");
folder.mkdir();
write(new File(folder, "folder.txt"), "folder");
- Git git = new Git(db);
- git.add().addFilepattern(".").call();
- git.commit().setMessage("Initial commit").call();
- write(new File(folder, "folder.txt"), "folder change");
+ try (Git git = new Git(db);
+ PatchIdDiffFormatter df = new PatchIdDiffFormatter()) {
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("Initial commit").call();
+ write(new File(folder, "folder.txt"), "folder change");
- PatchIdDiffFormatter df = new PatchIdDiffFormatter();
- df.setRepository(db);
- df.setPathFilter(PathFilter.create("folder"));
- DirCacheIterator oldTree = new DirCacheIterator(db.readDirCache());
- FileTreeIterator newTree = new FileTreeIterator(db);
- df.format(oldTree, newTree);
- df.flush();
+ df.setRepository(db);
+ df.setPathFilter(PathFilter.create("folder"));
+ DirCacheIterator oldTree = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator newTree = new FileTreeIterator(db);
+ df.format(oldTree, newTree);
+ df.flush();
- assertEquals("1ff64e0f9333e9b81967c3e8d7a81362b14d5441", df
- .getCalulatedPatchId().name());
+ assertEquals("1ff64e0f9333e9b81967c3e8d7a81362b14d5441", df
+ .getCalulatedPatchId().name());
+ }
}
@Test
@@ -84,37 +85,40 @@
File folder = new File(db.getDirectory().getParent(), "folder");
folder.mkdir();
write(new File(folder, "folder.txt"), "\n\n\n\nfolder");
- Git git = new Git(db);
- git.add().addFilepattern(".").call();
- git.commit().setMessage("Initial commit").call();
- write(new File(folder, "folder.txt"), "\n\n\n\nfolder change");
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("Initial commit").call();
+ write(new File(folder, "folder.txt"), "\n\n\n\nfolder change");
- PatchIdDiffFormatter df = new PatchIdDiffFormatter();
- df.setRepository(db);
- df.setPathFilter(PathFilter.create("folder"));
- DirCacheIterator oldTree = new DirCacheIterator(db.readDirCache());
- FileTreeIterator newTree = new FileTreeIterator(db);
- df.format(oldTree, newTree);
- df.flush();
+ try (PatchIdDiffFormatter df = new PatchIdDiffFormatter()) {
+ df.setRepository(db);
+ df.setPathFilter(PathFilter.create("folder"));
+ DirCacheIterator oldTree = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator newTree = new FileTreeIterator(db);
+ df.format(oldTree, newTree);
+ df.flush();
- assertEquals("08fca5ac531383eb1da8bf6b6f7cf44411281407", df
- .getCalulatedPatchId().name());
+ assertEquals("08fca5ac531383eb1da8bf6b6f7cf44411281407", df
+ .getCalulatedPatchId().name());
+ }
- write(new File(folder, "folder.txt"), "a\n\n\n\nfolder");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("Initial commit").call();
- write(new File(folder, "folder.txt"), "a\n\n\n\nfolder change");
+ write(new File(folder, "folder.txt"), "a\n\n\n\nfolder");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("Initial commit").call();
+ write(new File(folder, "folder.txt"), "a\n\n\n\nfolder change");
- df = new PatchIdDiffFormatter();
- df.setRepository(db);
- df.setPathFilter(PathFilter.create("folder"));
- oldTree = new DirCacheIterator(db.readDirCache());
- newTree = new FileTreeIterator(db);
- df.format(oldTree, newTree);
- df.flush();
+ try (PatchIdDiffFormatter df = new PatchIdDiffFormatter()) {
+ df.setRepository(db);
+ df.setPathFilter(PathFilter.create("folder"));
+ DirCacheIterator oldTree = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator newTree = new FileTreeIterator(db);
+ df.format(oldTree, newTree);
+ df.flush();
- assertEquals("08fca5ac531383eb1da8bf6b6f7cf44411281407", df
- .getCalulatedPatchId().name());
+ assertEquals("08fca5ac531383eb1da8bf6b6f7cf44411281407", df
+ .getCalulatedPatchId().name());
+ }
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java
index e83ef77..4315be9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java
@@ -48,6 +48,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.util.Arrays;
import java.util.List;
import org.eclipse.jgit.diff.DiffEntry.ChangeType;
@@ -227,6 +228,19 @@
}
@Test
+ public void testExactRename_UnstagedFile() throws Exception {
+ ObjectId aId = blob("foo");
+ DiffEntry a = DiffEntry.delete(PATH_A, aId);
+ DiffEntry b = DiffEntry.add(PATH_B, aId);
+
+ rd.addAll(Arrays.asList(a, b));
+ List<DiffEntry> entries = rd.compute();
+
+ assertEquals(1, entries.size());
+ assertRename(a, b, 100, entries.get(0));
+ }
+
+ @Test
public void testInexactRename_OnePair() throws Exception {
ObjectId aId = blob("foo\nbar\nbaz\nblarg\n");
ObjectId bId = blob("foo\nbar\nbaz\nblah\n");
@@ -430,6 +444,23 @@
}
@Test
+ public void testNoRenames_UntrackedFile() throws Exception {
+ ObjectId aId = blob("foo");
+ ObjectId bId = ObjectId
+ .fromString("3049eb6eee7e1318f4e78e799bf33f1e54af9cbf");
+
+ DiffEntry a = DiffEntry.delete(PATH_A, aId);
+ DiffEntry b = DiffEntry.add(PATH_B, bId);
+
+ rd.addAll(Arrays.asList(a, b));
+ List<DiffEntry> entries = rd.compute();
+
+ assertEquals(2, entries.size());
+ assertSame(a, entries.get(0));
+ assertSame(b, entries.get(1));
+ }
+
+ @Test
public void testBreakModify_BreakAll() throws Exception {
ObjectId aId = blob("foo");
ObjectId bId = blob("bar");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java
index 0c1baab..014406e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java
@@ -255,9 +255,11 @@
DirCacheBuilder b = dc.builder();
DirCacheEntry e = new DirCacheEntry(path);
e.setFileMode(FileMode.REGULAR_FILE);
- e.setObjectId(new ObjectInserter.Formatter().idFor(
- Constants.OBJ_BLOB,
- Constants.encode(path)));
+ try (ObjectInserter.Formatter formatter = new ObjectInserter.Formatter()) {
+ e.setObjectId(formatter.idFor(
+ Constants.OBJ_BLOB,
+ Constants.encode(path)));
+ }
b.add(e);
b.commit();
db.readDirCache();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java
index 8561fdf..2b10887 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java
@@ -78,23 +78,24 @@
final int expIdx = 2;
final DirCacheBuilder b = dc.builder();
- final TreeWalk tw = new TreeWalk(db);
- tw.addTree(new DirCacheBuildIterator(b));
- tw.setRecursive(true);
- tw.setFilter(PathFilterGroup.createFromStrings(Collections
- .singleton(paths[expIdx])));
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.addTree(new DirCacheBuildIterator(b));
+ tw.setRecursive(true);
+ tw.setFilter(PathFilterGroup.createFromStrings(Collections
+ .singleton(paths[expIdx])));
- assertTrue("found " + paths[expIdx], tw.next());
- final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
- assertNotNull(c);
- assertEquals(expIdx, c.ptr);
- assertSame(ents[expIdx], c.getDirCacheEntry());
- assertEquals(paths[expIdx], tw.getPathString());
- assertEquals(mode.getBits(), tw.getRawMode(0));
- assertSame(mode, tw.getFileMode(0));
- b.add(c.getDirCacheEntry());
+ assertTrue("found " + paths[expIdx], tw.next());
+ final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
+ assertNotNull(c);
+ assertEquals(expIdx, c.ptr);
+ assertSame(ents[expIdx], c.getDirCacheEntry());
+ assertEquals(paths[expIdx], tw.getPathString());
+ assertEquals(mode.getBits(), tw.getRawMode(0));
+ assertSame(mode, tw.getFileMode(0));
+ b.add(c.getDirCacheEntry());
- assertFalse("no more entries", tw.next());
+ assertFalse("no more entries", tw.next());
+ }
b.finish();
assertEquals(ents.length, dc.getEntryCount());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
index 7f58a1c..3e78046 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
@@ -98,17 +98,18 @@
assertEquals(ls.size(), dc.getEntryCount());
{
final Iterator<CGitIndexRecord> rItr = ls.values().iterator();
- final TreeWalk tw = new TreeWalk(db);
- tw.setRecursive(true);
- tw.addTree(new DirCacheIterator(dc));
- while (rItr.hasNext()) {
- final DirCacheIterator dcItr;
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.setRecursive(true);
+ tw.addTree(new DirCacheIterator(dc));
+ while (rItr.hasNext()) {
+ final DirCacheIterator dcItr;
- assertTrue(tw.next());
- dcItr = tw.getTree(0, DirCacheIterator.class);
- assertNotNull(dcItr);
+ assertTrue(tw.next());
+ dcItr = tw.getTree(0, DirCacheIterator.class);
+ assertNotNull(dcItr);
- assertEqual(rItr.next(), dcItr.getDirCacheEntry());
+ assertEqual(rItr.next(), dcItr.getDirCacheEntry());
+ }
}
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
index e159ed9..05fa007 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
@@ -69,15 +69,17 @@
assertFalse(isValidPath("a\u0000b"));
}
- private static boolean isValidPath(final String path) {
+ @SuppressWarnings("unused")
+ private static boolean isValidPath(String path) {
try {
- DirCacheCheckout.checkValidPath(path);
+ new DirCacheEntry(path);
return true;
} catch (InvalidPathException e) {
return false;
}
}
+ @SuppressWarnings("unused")
@Test
public void testCreate_ByStringPath() {
assertEquals("a", new DirCacheEntry("a").getPathString());
@@ -91,6 +93,7 @@
}
}
+ @SuppressWarnings("unused")
@Test
public void testCreate_ByStringPathAndStage() {
DirCacheEntry e;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java
index af1c8a3..dd242e5 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java
@@ -76,9 +76,10 @@
final DirCache dc = DirCache.newInCore();
assertEquals(0, dc.getEntryCount());
- final TreeWalk tw = new TreeWalk(db);
- tw.addTree(new DirCacheIterator(dc));
- assertFalse(tw.next());
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.addTree(new DirCacheIterator(dc));
+ assertFalse(tw.next());
+ }
}
@Test
@@ -125,19 +126,20 @@
b.finish();
final DirCacheIterator i = new DirCacheIterator(dc);
- final TreeWalk tw = new TreeWalk(db);
- tw.addTree(i);
- int pathIdx = 0;
- while (tw.next()) {
- assertSame(i, tw.getTree(0, DirCacheIterator.class));
- assertEquals(pathIdx, i.ptr);
- assertSame(ents[pathIdx], i.getDirCacheEntry());
- assertEquals(paths[pathIdx], tw.getPathString());
- assertEquals(modes[pathIdx].getBits(), tw.getRawMode(0));
- assertSame(modes[pathIdx], tw.getFileMode(0));
- pathIdx++;
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.addTree(i);
+ int pathIdx = 0;
+ while (tw.next()) {
+ assertSame(i, tw.getTree(0, DirCacheIterator.class));
+ assertEquals(pathIdx, i.ptr);
+ assertSame(ents[pathIdx], i.getDirCacheEntry());
+ assertEquals(paths[pathIdx], tw.getPathString());
+ assertEquals(modes[pathIdx].getBits(), tw.getRawMode(0));
+ assertSame(modes[pathIdx], tw.getFileMode(0));
+ pathIdx++;
+ }
+ assertEquals(paths.length, pathIdx);
}
- assertEquals(paths.length, pathIdx);
}
@Test
@@ -162,26 +164,27 @@
final int expPos[] = { 0, -1, 4 };
final DirCacheIterator i = new DirCacheIterator(dc);
- final TreeWalk tw = new TreeWalk(db);
- tw.addTree(i);
- tw.setRecursive(false);
- int pathIdx = 0;
- while (tw.next()) {
- assertSame(i, tw.getTree(0, DirCacheIterator.class));
- assertEquals(expModes[pathIdx].getBits(), tw.getRawMode(0));
- assertSame(expModes[pathIdx], tw.getFileMode(0));
- assertEquals(expPaths[pathIdx], tw.getPathString());
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.addTree(i);
+ tw.setRecursive(false);
+ int pathIdx = 0;
+ while (tw.next()) {
+ assertSame(i, tw.getTree(0, DirCacheIterator.class));
+ assertEquals(expModes[pathIdx].getBits(), tw.getRawMode(0));
+ assertSame(expModes[pathIdx], tw.getFileMode(0));
+ assertEquals(expPaths[pathIdx], tw.getPathString());
- if (expPos[pathIdx] >= 0) {
- assertEquals(expPos[pathIdx], i.ptr);
- assertSame(ents[expPos[pathIdx]], i.getDirCacheEntry());
- } else {
- assertSame(FileMode.TREE, tw.getFileMode(0));
+ if (expPos[pathIdx] >= 0) {
+ assertEquals(expPos[pathIdx], i.ptr);
+ assertSame(ents[expPos[pathIdx]], i.getDirCacheEntry());
+ } else {
+ assertSame(FileMode.TREE, tw.getFileMode(0));
+ }
+
+ pathIdx++;
}
-
- pathIdx++;
+ assertEquals(expPaths.length, pathIdx);
}
- assertEquals(expPaths.length, pathIdx);
}
@Test
@@ -202,21 +205,22 @@
b.finish();
final DirCacheIterator i = new DirCacheIterator(dc);
- final TreeWalk tw = new TreeWalk(db);
- tw.addTree(i);
- tw.setRecursive(true);
- int pathIdx = 0;
- while (tw.next()) {
- final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
- assertNotNull(c);
- assertEquals(pathIdx, c.ptr);
- assertSame(ents[pathIdx], c.getDirCacheEntry());
- assertEquals(paths[pathIdx], tw.getPathString());
- assertEquals(mode.getBits(), tw.getRawMode(0));
- assertSame(mode, tw.getFileMode(0));
- pathIdx++;
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.addTree(i);
+ tw.setRecursive(true);
+ int pathIdx = 0;
+ while (tw.next()) {
+ final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
+ assertNotNull(c);
+ assertEquals(pathIdx, c.ptr);
+ assertSame(ents[pathIdx], c.getDirCacheEntry());
+ assertEquals(paths[pathIdx], tw.getPathString());
+ assertEquals(mode.getBits(), tw.getRawMode(0));
+ assertSame(mode, tw.getFileMode(0));
+ pathIdx++;
+ }
+ assertEquals(paths.length, pathIdx);
}
- assertEquals(paths.length, pathIdx);
}
@Test
@@ -236,21 +240,22 @@
b.add(ents[i]);
b.finish();
- final TreeWalk tw = new TreeWalk(db);
- tw.addTree(new DirCacheIterator(dc));
- tw.setRecursive(true);
- int pathIdx = 0;
- while (tw.next()) {
- final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
- assertNotNull(c);
- assertEquals(pathIdx, c.ptr);
- assertSame(ents[pathIdx], c.getDirCacheEntry());
- assertEquals(paths[pathIdx], tw.getPathString());
- assertEquals(mode.getBits(), tw.getRawMode(0));
- assertSame(mode, tw.getFileMode(0));
- pathIdx++;
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.addTree(new DirCacheIterator(dc));
+ tw.setRecursive(true);
+ int pathIdx = 0;
+ while (tw.next()) {
+ final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
+ assertNotNull(c);
+ assertEquals(pathIdx, c.ptr);
+ assertSame(ents[pathIdx], c.getDirCacheEntry());
+ assertEquals(paths[pathIdx], tw.getPathString());
+ assertEquals(mode.getBits(), tw.getRawMode(0));
+ assertSame(mode, tw.getFileMode(0));
+ pathIdx++;
+ }
+ assertEquals(paths.length, pathIdx);
}
- assertEquals(paths.length, pathIdx);
}
@Test
@@ -397,22 +402,23 @@
b.add(ents[i]);
b.finish();
- final TreeWalk tw = new TreeWalk(db);
- for (int victimIdx = 0; victimIdx < paths.length; victimIdx++) {
- tw.reset();
- tw.addTree(new DirCacheIterator(dc));
- tw.setFilter(PathFilterGroup.createFromStrings(Collections
- .singleton(paths[victimIdx])));
- tw.setRecursive(tw.getFilter().shouldBeRecursive());
- assertTrue(tw.next());
- final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
- assertNotNull(c);
- assertEquals(victimIdx, c.ptr);
- assertSame(ents[victimIdx], c.getDirCacheEntry());
- assertEquals(paths[victimIdx], tw.getPathString());
- assertEquals(mode.getBits(), tw.getRawMode(0));
- assertSame(mode, tw.getFileMode(0));
- assertFalse(tw.next());
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ for (int victimIdx = 0; victimIdx < paths.length; victimIdx++) {
+ tw.reset();
+ tw.addTree(new DirCacheIterator(dc));
+ tw.setFilter(PathFilterGroup.createFromStrings(Collections
+ .singleton(paths[victimIdx])));
+ tw.setRecursive(tw.getFilter().shouldBeRecursive());
+ assertTrue(tw.next());
+ final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
+ assertNotNull(c);
+ assertEquals(victimIdx, c.ptr);
+ assertSame(ents[victimIdx], c.getDirCacheEntry());
+ assertEquals(paths[victimIdx], tw.getPathString());
+ assertEquals(mode.getBits(), tw.getRawMode(0));
+ assertSame(mode, tw.getFileMode(0));
+ assertFalse(tw.next());
+ }
}
}
@@ -424,18 +430,19 @@
final DirCache dc = DirCache.read(path, FS.DETECTED);
assertEquals(2, dc.getEntryCount());
- final TreeWalk tw = new TreeWalk(db);
- tw.setRecursive(true);
- tw.addTree(new DirCacheIterator(dc));
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.setRecursive(true);
+ tw.addTree(new DirCacheIterator(dc));
- assertTrue(tw.next());
- assertEquals("a/a", tw.getPathString());
- assertSame(FileMode.REGULAR_FILE, tw.getFileMode(0));
+ assertTrue(tw.next());
+ assertEquals("a/a", tw.getPathString());
+ assertSame(FileMode.REGULAR_FILE, tw.getFileMode(0));
- assertTrue(tw.next());
- assertEquals("q", tw.getPathString());
- assertSame(FileMode.REGULAR_FILE, tw.getFileMode(0));
+ assertTrue(tw.next());
+ assertEquals("q", tw.getPathString());
+ assertSame(FileMode.REGULAR_FILE, tw.getFileMode(0));
- assertFalse(tw.next());
+ assertFalse(tw.next());
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java
index 63ec858..c85e156 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCachePathEditTest.java
@@ -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 @@
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);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
index 5ed4268..30b3df1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
@@ -43,8 +43,9 @@
package org.eclipse.jgit.gitrepo;
import static org.junit.Assert.assertTrue;
+import static java.nio.charset.StandardCharsets.UTF_8;
-import java.io.StringBufferInputStream;
+import java.io.ByteArrayInputStream;
import java.util.HashSet;
import java.util.Set;
@@ -77,7 +78,7 @@
ManifestParser parser = new ManifestParser(
null, null, "master", baseUrl, null, null);
- parser.read(new StringBufferInputStream(xmlContent.toString()));
+ parser.read(new ByteArrayInputStream(xmlContent.toString().getBytes(UTF_8)));
// Unfiltered projects should have them all.
results.clear();
results.add("foo");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
index 66e7256..77ef1a6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
@@ -56,6 +56,8 @@
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
import org.junit.Test;
public class RepoCommandTest extends RepositoryTestCase {
@@ -80,38 +82,42 @@
super.setUp();
defaultDb = createWorkRepository();
- Git git = new Git(defaultDb);
- JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "branch world");
- git.add().addFilepattern("hello.txt").call();
- oldCommitId = git.commit().setMessage("Initial commit").call().getId();
- git.checkout().setName(BRANCH).setCreateBranch(true).call();
- git.checkout().setName("master").call();
- git.tag().setName(TAG).call();
- JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "master world");
- git.add().addFilepattern("hello.txt").call();
- git.commit().setMessage("Second commit").call();
- addRepoToClose(defaultDb);
+ try (Git git = new Git(defaultDb)) {
+ JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "branch world");
+ git.add().addFilepattern("hello.txt").call();
+ oldCommitId = git.commit().setMessage("Initial commit").call().getId();
+ git.checkout().setName(BRANCH).setCreateBranch(true).call();
+ git.checkout().setName("master").call();
+ git.tag().setName(TAG).call();
+ JGitTestUtil.writeTrashFile(defaultDb, "hello.txt", "master world");
+ git.add().addFilepattern("hello.txt").call();
+ git.commit().setMessage("Second commit").call();
+ addRepoToClose(defaultDb);
+ }
notDefaultDb = createWorkRepository();
- git = new Git(notDefaultDb);
- JGitTestUtil.writeTrashFile(notDefaultDb, "world.txt", "hello");
- git.add().addFilepattern("world.txt").call();
- git.commit().setMessage("Initial commit").call();
- addRepoToClose(notDefaultDb);
+ try (Git git = new Git(notDefaultDb)) {
+ JGitTestUtil.writeTrashFile(notDefaultDb, "world.txt", "hello");
+ git.add().addFilepattern("world.txt").call();
+ git.commit().setMessage("Initial commit").call();
+ addRepoToClose(notDefaultDb);
+ }
groupADb = createWorkRepository();
- git = new Git(groupADb);
- JGitTestUtil.writeTrashFile(groupADb, "a.txt", "world");
- git.add().addFilepattern("a.txt").call();
- git.commit().setMessage("Initial commit").call();
- addRepoToClose(groupADb);
+ try (Git git = new Git(groupADb)) {
+ JGitTestUtil.writeTrashFile(groupADb, "a.txt", "world");
+ git.add().addFilepattern("a.txt").call();
+ git.commit().setMessage("Initial commit").call();
+ addRepoToClose(groupADb);
+ }
groupBDb = createWorkRepository();
- git = new Git(groupBDb);
- JGitTestUtil.writeTrashFile(groupBDb, "b.txt", "world");
- git.add().addFilepattern("b.txt").call();
- git.commit().setMessage("Initial commit").call();
- addRepoToClose(groupBDb);
+ try (Git git = new Git(groupBDb)) {
+ JGitTestUtil.writeTrashFile(groupBDb, "b.txt", "world");
+ git.add().addFilepattern("b.txt").call();
+ git.commit().setMessage("Initial commit").call();
+ addRepoToClose(groupBDb);
+ }
resolveRelativeUris();
}
@@ -407,6 +413,7 @@
.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());
@@ -421,8 +428,12 @@
.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();
@@ -692,6 +703,54 @@
}
}
+ @Test
+ public void testRecordRemoteBranch() throws Exception {
+ try (
+ Repository remoteDb = createBareRepository();
+ Repository tempDb = createWorkRepository()) {
+ StringBuilder xmlContent = new StringBuilder();
+ xmlContent
+ .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+ .append("<manifest>")
+ .append("<remote name=\"remote1\" fetch=\".\" />")
+ .append("<default revision=\"master\" remote=\"remote1\" />")
+ .append("<project path=\"with-branch\" ")
+ .append("revision=\"master\" ")
+ .append("name=\"").append(notDefaultUri).append("\" />")
+ .append("<project path=\"with-long-branch\" ")
+ .append("revision=\"refs/heads/master\" ")
+ .append("name=\"").append(defaultUri).append("\" />")
+ .append("</manifest>");
+ JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
+ xmlContent.toString());
+
+ RepoCommand command = new RepoCommand(remoteDb);
+ command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
+ .setURI(rootUri)
+ .setRecordRemoteBranch(true)
+ .call();
+ // Clone it
+ File directory = createTempDirectory("testBareRepo");
+ try (Repository localDb = Git.cloneRepository()
+ .setDirectory(directory)
+ .setURI(remoteDb.getDirectory().toURI().toString()).call()
+ .getRepository();) {
+ // The .gitmodules file should exist
+ File gitmodules = new File(localDb.getWorkTree(),
+ ".gitmodules");
+ assertTrue("The .gitmodules file should exist",
+ gitmodules.exists());
+ FileBasedConfig c = new FileBasedConfig(gitmodules,
+ FS.DETECTED);
+ c.load();
+ assertEquals("standard branches work", "master",
+ c.getString("submodule", "with-branch", "branch"));
+ assertEquals("long branches work", "refs/heads/master",
+ c.getString("submodule", "with-long-branch", "branch"));
+ }
+ }
+ }
+
private void resolveRelativeUris() {
// Find the longest common prefix ends with "/" as rootUri.
defaultUri = defaultDb.getDirectory().toURI().toString();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java
index 2c04787..480e326 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java
@@ -54,6 +54,7 @@
@Test
public void testSimpleCharClass() {
+ assertMatched("][a]", "]a");
assertMatched("[a]", "a");
assertMatched("][a]", "]a");
assertMatched("[a]", "a/");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java
index 9722ac6..c026efc 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java
@@ -55,7 +55,6 @@
import java.util.ArrayList;
import java.util.Arrays;
-import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.ignore.IgnoreNode.MatchResult;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.FileMode;
@@ -63,6 +62,7 @@
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.WorkingTreeIterator;
import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.SystemReader;
import org.junit.Test;
/**
@@ -468,6 +468,9 @@
@Test
public void testTrailingSpaces() throws IOException {
+ // Windows can't create files with trailing spaces
+ // If this assumption fails the test is halted and ignored.
+ org.junit.Assume.assumeFalse(SystemReader.getInstance().isWindows());
writeTrashFile("a /a", "");
writeTrashFile("a /a ", "");
writeTrashFile("a /a ", "");
@@ -505,7 +508,7 @@
.toString());
}
- private void beginWalk() throws CorruptObjectException {
+ private void beginWalk() {
walk = new TreeWalk(db);
walk.addTree(new FileTreeIterator(db));
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreRuleSpecialCasesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreRuleSpecialCasesTest.java
index f8eb126..567f3d8 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreRuleSpecialCasesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreRuleSpecialCasesTest.java
@@ -768,7 +768,7 @@
@Test
public void testSpecialGroupCase9() throws Exception {
- assertMatch("][", "][", true);
+ assertMatch("][", "][", false);
}
@Test
@@ -968,6 +968,59 @@
assertMatch("[a{}()b][a{}()b]?[a{}()b][a{}()b]", "{}x()", true);
assertMatch("x*{x}3", "xa{x}3", true);
assertMatch("a*{x}3", "axxx", false);
+
+ assertMatch("?", "[", true);
+ assertMatch("*", "[", true);
+
+ // Escaped bracket matches, but see weird things below...
+ assertMatch("\\[", "[", true);
+ }
+
+ /**
+ * The ignore rules here <b>do not match</b> any paths because single '['
+ * begins character group and the entire rule cannot be parsed due the
+ * invalid glob pattern. See
+ * http://article.gmane.org/gmane.comp.version-control.git/278699.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBracketsUnmatched1() throws Exception {
+ assertMatch("[", "[", false);
+ assertMatch("[*", "[", false);
+ assertMatch("*[", "[", false);
+ assertMatch("*[", "a[", false);
+ assertMatch("[a][", "a[", false);
+ assertMatch("*[", "a", false);
+ assertMatch("[a", "a", false);
+ assertMatch("[*", "a", false);
+ assertMatch("[*a", "a", false);
+ }
+
+ /**
+ * Single ']' is treated here literally, not as an and of a character group
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testBracketsUnmatched2() throws Exception {
+ assertMatch("*]", "a", false);
+ assertMatch("]a", "a", false);
+ assertMatch("]*", "a", false);
+ assertMatch("]*a", "a", false);
+
+ assertMatch("]", "]", true);
+ assertMatch("]*", "]", true);
+ assertMatch("]*", "]a", true);
+ assertMatch("*]", "]", true);
+ assertMatch("*]", "a]", true);
+ }
+
+ @Test
+ public void testBracketsRandom() throws Exception {
+ assertMatch("[\\]", "[$0+//r4a\\d]", false);
+ assertMatch("[:]]sZX]", "[:]]sZX]", false);
+ assertMatch("[:]]:]]]", "[:]]:]]]", false);
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java
index fc8cbaa..11a0924 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java
@@ -51,9 +51,12 @@
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.zip.Deflater;
+import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
import org.eclipse.jgit.internal.storage.pack.PackExt;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.TestRng;
@@ -161,6 +164,56 @@
assertEquals(id2, objs.iterator().next());
}
+ @Test
+ public void testGarbageSelectivelyVisible() throws IOException {
+ ObjectInserter ins = db.newObjectInserter();
+ ObjectId fooId = ins.insert(Constants.OBJ_BLOB, Constants.encode("foo"));
+ ins.flush();
+ assertEquals(1, db.getObjectDatabase().listPacks().size());
+
+ // Make pack 0 garbage.
+ db.getObjectDatabase().listPacks().get(0).setPackSource(PackSource.UNREACHABLE_GARBAGE);
+
+ // Default behavior should be that the database has foo, because we allow garbage objects.
+ assertTrue(db.getObjectDatabase().has(fooId));
+ // But we should not be able to see it if we pass the right args.
+ assertFalse(db.getObjectDatabase().has(fooId, true));
+ }
+
+ @Test
+ public void testInserterIgnoresUnreachable() throws IOException {
+ ObjectInserter ins = db.newObjectInserter();
+ ObjectId fooId = ins.insert(Constants.OBJ_BLOB, Constants.encode("foo"));
+ ins.flush();
+ assertEquals(1, db.getObjectDatabase().listPacks().size());
+
+ // Make pack 0 garbage.
+ db.getObjectDatabase().listPacks().get(0).setPackSource(PackSource.UNREACHABLE_GARBAGE);
+
+ // We shouldn't be able to see foo because it's garbage.
+ assertFalse(db.getObjectDatabase().has(fooId, true));
+
+ // But if we re-insert foo, it should become visible again.
+ ins.insert(Constants.OBJ_BLOB, Constants.encode("foo"));
+ ins.flush();
+ assertTrue(db.getObjectDatabase().has(fooId, true));
+
+ // Verify that we have a foo in both packs, and 1 of them is garbage.
+ DfsReader reader = new DfsReader(db.getObjectDatabase());
+ DfsPackFile packs[] = db.getObjectDatabase().getPacks();
+ Set<PackSource> pack_sources = new HashSet<PackSource>();
+
+ assertEquals(2, packs.length);
+
+ pack_sources.add(packs[0].getPackDescription().getPackSource());
+ pack_sources.add(packs[1].getPackDescription().getPackSource());
+
+ assertTrue(packs[0].hasObject(reader, fooId));
+ assertTrue(packs[1].hasObject(reader, fooId));
+ assertTrue(pack_sources.contains(PackSource.UNREACHABLE_GARBAGE));
+ assertTrue(pack_sources.contains(PackSource.INSERT));
+ }
+
private static String readString(ObjectLoader loader) throws IOException {
return RawParseUtils.decode(readStream(loader));
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
index 514e00f..9d7a482 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
@@ -81,15 +81,14 @@
public void setUp() throws Exception {
WindowCacheConfig windowCacheConfig = new WindowCacheConfig();
windowCacheConfig.setPackedGitOpenFiles(1);
- WindowCache.reconfigure(windowCacheConfig);
+ windowCacheConfig.install();
super.setUp();
}
@After
public void tearDown() throws Exception {
super.tearDown();
- WindowCacheConfig windowCacheConfig = new WindowCacheConfig();
- WindowCache.reconfigure(windowCacheConfig);
+ new WindowCacheConfig().install();
}
@Test
@@ -206,12 +205,14 @@
private static void whackCache() {
final WindowCacheConfig config = new WindowCacheConfig();
config.setPackedGitOpenFiles(1);
- WindowCache.reconfigure(config);
+ config.install();
}
private RevObject parse(final AnyObjectId id)
throws MissingObjectException, IOException {
- return new RevWalk(db).parseAny(id);
+ try (RevWalk rw = new RevWalk(db)) {
+ return rw.parseAny(id);
+ }
}
private File[] pack(final Repository src, final RevObject... list)
@@ -280,7 +281,6 @@
private RevObject writeBlob(final Repository repo, final String data)
throws IOException {
- final RevWalk revWalk = new RevWalk(repo);
final byte[] bytes = Constants.encode(data);
final ObjectId id;
try (ObjectInserter inserter = repo.newObjectInserter()) {
@@ -293,6 +293,8 @@
} catch (MissingObjectException e) {
// Ok
}
- return revWalk.lookupBlob(id);
+ try (RevWalk revWalk = new RevWalk(repo)) {
+ return revWalk.lookupBlob(id);
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileRepositoryBuilderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileRepositoryBuilderTest.java
index 280d604..deffa04 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileRepositoryBuilderTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileRepositoryBuilderTest.java
@@ -80,7 +80,9 @@
ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, "");
config.save();
- new FileRepository(r.getDirectory());
+ try (FileRepository repo = new FileRepository(r.getDirectory())) {
+ // Unused
+ }
}
@Test
@@ -91,8 +93,7 @@
ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, "notanumber");
config.save();
- try {
- new FileRepository(r.getDirectory());
+ try (FileRepository repo = new FileRepository(r.getDirectory())) {
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
@@ -104,78 +105,78 @@
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 {
- new FileRepository(r.getDirectory());
+ try (FileRepository repo = new FileRepository(r.getDirectory())) {
fail("IOException not thrown");
} catch (IOException e) {
assertNotNull(e.getMessage());
}
}
- @SuppressWarnings("resource" /* java 7 */)
@Test
public void absoluteGitDirRef() throws Exception {
Repository repo1 = createWorkRepository();
File dir = createTempDirectory("dir");
File dotGit = new File(dir, Constants.DOT_GIT);
- new FileWriter(dotGit).append(
- "gitdir: " + repo1.getDirectory().getAbsolutePath()).close();
- FileRepositoryBuilder builder = new FileRepositoryBuilder();
+ try (FileWriter writer = new FileWriter(dotGit)) {
+ writer.append("gitdir: " + repo1.getDirectory().getAbsolutePath()).close();
+ FileRepositoryBuilder builder = new FileRepositoryBuilder();
- builder.setWorkTree(dir);
- builder.setMustExist(true);
- Repository repo2 = builder.build();
+ builder.setWorkTree(dir);
+ builder.setMustExist(true);
+ Repository repo2 = builder.build();
- assertEquals(repo1.getDirectory().getAbsolutePath(), repo2
- .getDirectory().getAbsolutePath());
- assertEquals(dir, repo2.getWorkTree());
+ assertEquals(repo1.getDirectory().getAbsolutePath(), repo2
+ .getDirectory().getAbsolutePath());
+ assertEquals(dir, repo2.getWorkTree());
+ }
}
- @SuppressWarnings("resource" /* java 7 */)
@Test
public void relativeGitDirRef() throws Exception {
Repository repo1 = createWorkRepository();
File dir = new File(repo1.getWorkTree(), "dir");
assertTrue(dir.mkdir());
File dotGit = new File(dir, Constants.DOT_GIT);
- new FileWriter(dotGit).append("gitdir: ../" + Constants.DOT_GIT)
- .close();
+ try (FileWriter writer = new FileWriter(dotGit)) {
+ writer.append("gitdir: ../" + Constants.DOT_GIT).close();
- FileRepositoryBuilder builder = new FileRepositoryBuilder();
- builder.setWorkTree(dir);
- builder.setMustExist(true);
- Repository repo2 = builder.build();
+ FileRepositoryBuilder builder = new FileRepositoryBuilder();
+ builder.setWorkTree(dir);
+ builder.setMustExist(true);
+ Repository repo2 = builder.build();
- // The tmp directory may be a symlink so the actual path
- // may not
- assertEquals(repo1.getDirectory().getCanonicalPath(), repo2
- .getDirectory().getCanonicalPath());
- assertEquals(dir, repo2.getWorkTree());
+ // The tmp directory may be a symlink so the actual path
+ // may not
+ assertEquals(repo1.getDirectory().getCanonicalPath(), repo2
+ .getDirectory().getCanonicalPath());
+ assertEquals(dir, repo2.getWorkTree());
+ }
}
- @SuppressWarnings("resource" /* java 7 */)
@Test
public void scanWithGitDirRef() throws Exception {
Repository repo1 = createWorkRepository();
File dir = createTempDirectory("dir");
File dotGit = new File(dir, Constants.DOT_GIT);
- new FileWriter(dotGit).append(
- "gitdir: " + repo1.getDirectory().getAbsolutePath()).close();
- FileRepositoryBuilder builder = new FileRepositoryBuilder();
+ try (FileWriter writer = new FileWriter(dotGit)) {
+ writer.append(
+ "gitdir: " + repo1.getDirectory().getAbsolutePath()).close();
+ FileRepositoryBuilder builder = new FileRepositoryBuilder();
- builder.setWorkTree(dir);
- builder.findGitDir(dir);
- assertEquals(repo1.getDirectory().getAbsolutePath(), builder
- .getGitDir().getAbsolutePath());
- builder.setMustExist(true);
- Repository repo2 = builder.build();
+ builder.setWorkTree(dir);
+ builder.findGitDir(dir);
+ assertEquals(repo1.getDirectory().getAbsolutePath(), builder
+ .getGitDir().getAbsolutePath());
+ builder.setMustExist(true);
+ Repository repo2 = builder.build();
- // The tmp directory may be a symlink
- assertEquals(repo1.getDirectory().getCanonicalPath(), repo2
- .getDirectory().getCanonicalPath());
- assertEquals(dir, repo2.getWorkTree());
+ // The tmp directory may be a symlink
+ assertEquals(repo1.getDirectory().getCanonicalPath(), repo2
+ .getDirectory().getCanonicalPath());
+ assertEquals(dir, repo2.getWorkTree());
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
index bbd4123..f549fb5 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
@@ -85,6 +85,7 @@
assertEquals(4, stats.numberOfLooseObjects);
assertEquals(0, stats.numberOfPackedObjects);
assertEquals(0, stats.numberOfPackFiles);
+ assertEquals(0, stats.numberOfBitmaps);
}
@Theory
@@ -102,6 +103,7 @@
assertEquals(0, stats.numberOfLooseObjects);
assertEquals(8, stats.numberOfPackedObjects);
assertEquals(1, stats.numberOfPackFiles);
+ assertEquals(2, stats.numberOfBitmaps);
}
@Theory
@@ -118,6 +120,7 @@
assertEquals(0, stats.numberOfLooseObjects);
assertEquals(4, stats.numberOfPackedObjects);
assertEquals(1, stats.numberOfPackFiles);
+ assertEquals(1, stats.numberOfBitmaps);
// Do the gc again and check that it hasn't changed anything
gc.gc();
@@ -125,10 +128,12 @@
assertEquals(0, stats.numberOfLooseObjects);
assertEquals(4, stats.numberOfPackedObjects);
assertEquals(1, stats.numberOfPackFiles);
+ assertEquals(1, stats.numberOfBitmaps);
}
@Theory
- public void testPackCommitsAndLooseOne(boolean aggressive) throws Exception {
+ public void testPackCommitsAndLooseOne(boolean aggressive)
+ throws Exception {
BranchBuilder bb = tr.branch("refs/heads/master");
RevCommit first = bb.commit().add("A", "A").add("B", "B").create();
bb.commit().add("A", "A2").add("B", "B2").create();
@@ -143,6 +148,7 @@
assertEquals(0, stats.numberOfLooseObjects);
assertEquals(8, stats.numberOfPackedObjects);
assertEquals(2, stats.numberOfPackFiles);
+ assertEquals(1, stats.numberOfBitmaps);
}
@Theory
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
index c7336da..48ea13b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
@@ -77,7 +77,7 @@
tr.lightweightTag("t", a);
gc.packRefs();
- assertSame(repo.getRef("t").getStorage(), Storage.PACKED);
+ assertSame(repo.exactRef("refs/tags/t").getStorage(), Storage.PACKED);
}
@Test
@@ -118,7 +118,7 @@
tr.lightweightTag("t1", a);
tr.lightweightTag("t2", a);
LockFile refLock = new LockFile(new File(repo.getDirectory(),
- "refs/tags/t1"), repo.getFS());
+ "refs/tags/t1"));
try {
refLock.lock();
gc.packRefs();
@@ -126,8 +126,8 @@
refLock.unlock();
}
- assertSame(repo.getRef("refs/tags/t1").getStorage(), Storage.LOOSE);
- assertSame(repo.getRef("refs/tags/t2").getStorage(), Storage.PACKED);
+ assertSame(repo.exactRef("refs/tags/t1").getStorage(), Storage.LOOSE);
+ assertSame(repo.exactRef("refs/tags/t2").getStorage(), Storage.PACKED);
}
@Test
@@ -146,7 +146,7 @@
public Result call() throws Exception {
RefUpdate update = new RefDirectoryUpdate(
(RefDirectory) repo.getRefDatabase(),
- repo.getRef("refs/tags/t")) {
+ repo.exactRef("refs/tags/t")) {
@Override
public boolean isForceUpdate() {
try {
@@ -182,7 +182,7 @@
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
}
- assertEquals(repo.getRef("refs/tags/t").getObjectId(), b);
+ assertEquals(repo.exactRef("refs/tags/t").getObjectId(), b);
}
@Test
@@ -194,23 +194,23 @@
// check for the unborn branch master. HEAD should point to master and
// master doesn't exist.
- assertEquals(repo.getRef("HEAD").getTarget().getName(),
+ assertEquals(repo.exactRef("HEAD").getTarget().getName(),
"refs/heads/master");
- assertNull(repo.getRef("HEAD").getTarget().getObjectId());
+ assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
gc.packRefs();
- assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE);
- assertEquals(repo.getRef("HEAD").getTarget().getName(),
+ assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
+ assertEquals(repo.exactRef("HEAD").getTarget().getName(),
"refs/heads/master");
- assertNull(repo.getRef("HEAD").getTarget().getObjectId());
+ assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
git.checkout().setName("refs/heads/side").call();
gc.packRefs();
- assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE);
+ assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
// check for detached HEAD
git.checkout().setName(first.getName()).call();
gc.packRefs();
- assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE);
+ assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
}
@Test
@@ -229,20 +229,20 @@
// check for the unborn branch master. HEAD should point to master and
// master doesn't exist.
- assertEquals(repo.getRef("HEAD").getTarget().getName(),
+ assertEquals(repo.exactRef("HEAD").getTarget().getName(),
"refs/heads/master");
- assertNull(repo.getRef("HEAD").getTarget().getObjectId());
+ assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
gc.packRefs();
- assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE);
- assertEquals(repo.getRef("HEAD").getTarget().getName(),
+ assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
+ assertEquals(repo.exactRef("HEAD").getTarget().getName(),
"refs/heads/master");
- assertNull(repo.getRef("HEAD").getTarget().getObjectId());
+ assertNull(repo.exactRef("HEAD").getTarget().getObjectId());
// check for non-detached HEAD
repo.updateRef(Constants.HEAD).link("refs/heads/side");
gc.packRefs();
- assertSame(repo.getRef("HEAD").getStorage(), Storage.LOOSE);
- assertEquals(repo.getRef("HEAD").getTarget().getObjectId(),
+ assertSame(repo.exactRef("HEAD").getStorage(), Storage.LOOSE);
+ assertEquals(repo.exactRef("HEAD").getTarget().getObjectId(),
second.getId());
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java
index 2a096fd..3c781a9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java
@@ -75,6 +75,7 @@
tr.blob("x");
stats = gc.getStatistics();
assertEquals(9, stats.numberOfLooseObjects);
+ fsTick();
gc.prune(Collections.<ObjectId> emptySet());
stats = gc.getStatistics();
assertEquals(8, stats.numberOfLooseObjects);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
index a764f0f..5abf625 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java
@@ -52,6 +52,7 @@
import org.eclipse.jgit.junit.TestRepository.CommitBuilder;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
import org.junit.After;
import org.junit.Before;
@@ -65,7 +66,8 @@
public void setUp() throws Exception {
super.setUp();
repo = createWorkRepository();
- tr = new TestRepository<FileRepository>((repo));
+ tr = new TestRepository<FileRepository>(repo, new RevWalk(repo),
+ mockSystemReader);
gc = new GC(repo);
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/LockFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/LockFileTest.java
index 1a3a567..f1bc7c8 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/LockFileTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/LockFileTest.java
@@ -61,25 +61,26 @@
@Test
public void lockFailedExceptionRecovery() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- RevCommit commit1 = git.commit().setMessage("create file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit1 = git.commit().setMessage("create file").call();
- assertNotNull(commit1);
- writeTrashFile("file.txt", "content2");
- git.add().addFilepattern("file.txt").call();
- assertNotNull(git.commit().setMessage("edit file").call());
+ assertNotNull(commit1);
+ writeTrashFile("file.txt", "content2");
+ git.add().addFilepattern("file.txt").call();
+ assertNotNull(git.commit().setMessage("edit file").call());
- LockFile lf = new LockFile(db.getIndexFile(), db.getFS());
- assertTrue(lf.lock());
- try {
- git.checkout().setName(commit1.name()).call();
- fail("JGitInternalException not thrown");
- } catch (JGitInternalException e) {
- assertTrue(e.getCause() instanceof LockFailedException);
- lf.unlock();
- git.checkout().setName(commit1.name()).call();
+ LockFile lf = new LockFile(db.getIndexFile());
+ assertTrue(lf.lock());
+ try {
+ git.checkout().setName(commit1.name()).call();
+ fail("JGitInternalException not thrown");
+ } catch (JGitInternalException e) {
+ assertTrue(e.getCause() instanceof LockFailedException);
+ lf.unlock();
+ git.checkout().setName(commit1.name()).call();
+ }
}
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
index 3226f42..923f283 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ObjectDirectoryTest.java
@@ -62,18 +62,18 @@
throws Exception {
ExecutorService e = Executors.newCachedThreadPool();
for (int i=0; i < 100; ++i) {
- ObjectDirectory db = createBareRepository().getObjectDatabase();
- for (Future f : e.invokeAll(blobInsertersForTheSameFanOutDir(db))) {
+ ObjectDirectory dir = createBareRepository().getObjectDatabase();
+ for (Future f : e.invokeAll(blobInsertersForTheSameFanOutDir(dir))) {
f.get();
}
}
}
private Collection<Callable<ObjectId>> blobInsertersForTheSameFanOutDir(
- final ObjectDirectory db) {
+ final ObjectDirectory dir) {
Callable<ObjectId> callable = new Callable<ObjectId>() {
public ObjectId call() throws Exception {
- return db.newInserter().insert(Constants.OBJ_BLOB, new byte[0]);
+ return dir.newInserter().insert(Constants.OBJ_BLOB, new byte[0]);
}
};
return Collections.nCopies(4, callable);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
index cb80768..ba07d68 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
@@ -191,119 +191,122 @@
@Test
public void testDelta_SmallObjectChain() throws Exception {
- ObjectInserter.Formatter fmt = new ObjectInserter.Formatter();
- byte[] data0 = new byte[512];
- Arrays.fill(data0, (byte) 0xf3);
- ObjectId id0 = fmt.idFor(Constants.OBJ_BLOB, data0);
+ try (ObjectInserter.Formatter fmt = new ObjectInserter.Formatter()) {
+ byte[] data0 = new byte[512];
+ Arrays.fill(data0, (byte) 0xf3);
+ ObjectId id0 = fmt.idFor(Constants.OBJ_BLOB, data0);
- TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64 * 1024);
- packHeader(pack, 4);
- objectHeader(pack, Constants.OBJ_BLOB, data0.length);
- deflate(pack, data0);
+ TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64 * 1024);
+ packHeader(pack, 4);
+ objectHeader(pack, Constants.OBJ_BLOB, data0.length);
+ deflate(pack, data0);
- byte[] data1 = clone(0x01, data0);
- byte[] delta1 = delta(data0, data1);
- ObjectId id1 = fmt.idFor(Constants.OBJ_BLOB, data1);
- objectHeader(pack, Constants.OBJ_REF_DELTA, delta1.length);
- id0.copyRawTo(pack);
- deflate(pack, delta1);
+ byte[] data1 = clone(0x01, data0);
+ byte[] delta1 = delta(data0, data1);
+ ObjectId id1 = fmt.idFor(Constants.OBJ_BLOB, data1);
+ objectHeader(pack, Constants.OBJ_REF_DELTA, delta1.length);
+ id0.copyRawTo(pack);
+ deflate(pack, delta1);
- byte[] data2 = clone(0x02, data1);
- byte[] delta2 = delta(data1, data2);
- ObjectId id2 = fmt.idFor(Constants.OBJ_BLOB, data2);
- objectHeader(pack, Constants.OBJ_REF_DELTA, delta2.length);
- id1.copyRawTo(pack);
- deflate(pack, delta2);
+ byte[] data2 = clone(0x02, data1);
+ byte[] delta2 = delta(data1, data2);
+ ObjectId id2 = fmt.idFor(Constants.OBJ_BLOB, data2);
+ objectHeader(pack, Constants.OBJ_REF_DELTA, delta2.length);
+ id1.copyRawTo(pack);
+ deflate(pack, delta2);
- byte[] data3 = clone(0x03, data2);
- byte[] delta3 = delta(data2, data3);
- ObjectId id3 = fmt.idFor(Constants.OBJ_BLOB, data3);
- objectHeader(pack, Constants.OBJ_REF_DELTA, delta3.length);
- id2.copyRawTo(pack);
- deflate(pack, delta3);
+ byte[] data3 = clone(0x03, data2);
+ byte[] delta3 = delta(data2, data3);
+ ObjectId id3 = fmt.idFor(Constants.OBJ_BLOB, data3);
+ objectHeader(pack, Constants.OBJ_REF_DELTA, delta3.length);
+ id2.copyRawTo(pack);
+ deflate(pack, delta3);
- digest(pack);
- PackParser ip = index(pack.toByteArray());
- ip.setAllowThin(true);
- ip.parse(NullProgressMonitor.INSTANCE);
+ digest(pack);
+ PackParser ip = index(pack.toByteArray());
+ ip.setAllowThin(true);
+ ip.parse(NullProgressMonitor.INSTANCE);
- assertTrue("has blob", wc.has(id3));
+ assertTrue("has blob", wc.has(id3));
- ObjectLoader ol = wc.open(id3);
- assertNotNull("created loader", ol);
- assertEquals(Constants.OBJ_BLOB, ol.getType());
- assertEquals(data3.length, ol.getSize());
- assertFalse("is large", ol.isLarge());
- assertNotNull(ol.getCachedBytes());
- assertArrayEquals(data3, ol.getCachedBytes());
+ ObjectLoader ol = wc.open(id3);
+ assertNotNull("created loader", ol);
+ assertEquals(Constants.OBJ_BLOB, ol.getType());
+ assertEquals(data3.length, ol.getSize());
+ assertFalse("is large", ol.isLarge());
+ assertNotNull(ol.getCachedBytes());
+ assertArrayEquals(data3, ol.getCachedBytes());
- ObjectStream in = ol.openStream();
- assertNotNull("have stream", in);
- assertEquals(Constants.OBJ_BLOB, in.getType());
- assertEquals(data3.length, in.getSize());
- byte[] act = new byte[data3.length];
- IO.readFully(in, act, 0, data3.length);
- assertTrue("same content", Arrays.equals(act, data3));
- assertEquals("stream at EOF", -1, in.read());
- in.close();
+ ObjectStream in = ol.openStream();
+ assertNotNull("have stream", in);
+ assertEquals(Constants.OBJ_BLOB, in.getType());
+ assertEquals(data3.length, in.getSize());
+ byte[] act = new byte[data3.length];
+ IO.readFully(in, act, 0, data3.length);
+ assertTrue("same content", Arrays.equals(act, data3));
+ assertEquals("stream at EOF", -1, in.read());
+ in.close();
+ }
}
@Test
public void testDelta_FailsOver2GiB() throws Exception {
- ObjectInserter.Formatter fmt = new ObjectInserter.Formatter();
- byte[] base = new byte[] { 'a' };
- ObjectId idA = fmt.idFor(Constants.OBJ_BLOB, base);
- ObjectId idB = fmt.idFor(Constants.OBJ_BLOB, new byte[] { 'b' });
+ try (ObjectInserter.Formatter fmt = new ObjectInserter.Formatter()) {
+ byte[] base = new byte[] { 'a' };
+ ObjectId idA = fmt.idFor(Constants.OBJ_BLOB, base);
+ ObjectId idB = fmt.idFor(Constants.OBJ_BLOB, new byte[] { 'b' });
- PackedObjectInfo a = new PackedObjectInfo(idA);
- PackedObjectInfo b = new PackedObjectInfo(idB);
+ PackedObjectInfo a = new PackedObjectInfo(idA);
+ PackedObjectInfo b = new PackedObjectInfo(idB);
- TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64 * 1024);
- packHeader(pack, 2);
- a.setOffset(pack.length());
- objectHeader(pack, Constants.OBJ_BLOB, base.length);
- deflate(pack, base);
+ TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64 * 1024);
+ packHeader(pack, 2);
+ a.setOffset(pack.length());
+ objectHeader(pack, Constants.OBJ_BLOB, base.length);
+ deflate(pack, base);
- ByteArrayOutputStream tmp = new ByteArrayOutputStream();
- DeltaEncoder de = new DeltaEncoder(tmp, base.length, 3L << 30);
- de.copy(0, 1);
- byte[] delta = tmp.toByteArray();
- b.setOffset(pack.length());
- objectHeader(pack, Constants.OBJ_REF_DELTA, delta.length);
- idA.copyRawTo(pack);
- deflate(pack, delta);
- byte[] footer = digest(pack);
+ ByteArrayOutputStream tmp = new ByteArrayOutputStream();
+ DeltaEncoder de = new DeltaEncoder(tmp, base.length, 3L << 30);
+ de.copy(0, 1);
+ byte[] delta = tmp.toByteArray();
+ b.setOffset(pack.length());
+ objectHeader(pack, Constants.OBJ_REF_DELTA, delta.length);
+ idA.copyRawTo(pack);
+ deflate(pack, delta);
+ byte[] footer = digest(pack);
- File dir = new File(repo.getObjectDatabase().getDirectory(), "pack");
- File packName = new File(dir, idA.name() + ".pack");
- File idxName = new File(dir, idA.name() + ".idx");
+ File dir = new File(repo.getObjectDatabase().getDirectory(),
+ "pack");
+ File packName = new File(dir, idA.name() + ".pack");
+ File idxName = new File(dir, idA.name() + ".idx");
- FileOutputStream f = new FileOutputStream(packName);
- try {
- f.write(pack.toByteArray());
- } finally {
- f.close();
- }
+ FileOutputStream f = new FileOutputStream(packName);
+ try {
+ f.write(pack.toByteArray());
+ } finally {
+ f.close();
+ }
- f = new FileOutputStream(idxName);
- try {
- List<PackedObjectInfo> list = new ArrayList<PackedObjectInfo>();
- list.add(a);
- list.add(b);
- Collections.sort(list);
- new PackIndexWriterV1(f).write(list, footer);
- } finally {
- f.close();
- }
+ f = new FileOutputStream(idxName);
+ try {
+ List<PackedObjectInfo> list = new ArrayList<PackedObjectInfo>();
+ list.add(a);
+ list.add(b);
+ Collections.sort(list);
+ new PackIndexWriterV1(f).write(list, footer);
+ } finally {
+ f.close();
+ }
- PackFile packFile = new PackFile(packName, PackExt.INDEX.getBit());
- try {
- packFile.get(wc, b);
- fail("expected LargeObjectException.ExceedsByteArrayLimit");
- } catch (LargeObjectException.ExceedsByteArrayLimit bad) {
- assertNull(bad.getObjectId());
- } finally {
- packFile.close();
+ PackFile packFile = new PackFile(packName, PackExt.INDEX.getBit());
+ try {
+ packFile.get(wc, b);
+ fail("expected LargeObjectException.ExceedsByteArrayLimit");
+ } catch (LargeObjectException.ExceedsByteArrayLimit bad) {
+ assertNull(bad.getObjectId());
+ } finally {
+ packFile.close();
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
index bc880a1..63a3072 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
@@ -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 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 @@
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 @@
*/
@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 @@
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 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 @@
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
}
@@ -343,12 +342,13 @@
ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327"),
ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259"),
ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3") };
- final RevWalk parser = new RevWalk(db);
- final RevObject forcedOrderRevs[] = new RevObject[forcedOrder.length];
- for (int i = 0; i < forcedOrder.length; i++)
- forcedOrderRevs[i] = parser.parseAny(forcedOrder[i]);
+ try (final RevWalk parser = new RevWalk(db)) {
+ final RevObject forcedOrderRevs[] = new RevObject[forcedOrder.length];
+ for (int i = 0; i < forcedOrder.length; i++)
+ forcedOrderRevs[i] = parser.parseAny(forcedOrder[i]);
- createVerifyOpenPack(Arrays.asList(forcedOrderRevs));
+ createVerifyOpenPack(Arrays.asList(forcedOrderRevs));
+ }
assertEquals(forcedOrder.length, writer.getObjectCount());
verifyObjectsOrder(forcedOrder);
@@ -438,6 +438,38 @@
}
@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);
writeVerifyPack4(false);
@@ -494,7 +526,7 @@
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 +551,7 @@
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 +574,7 @@
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 +730,4 @@
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);
- }
- };
- }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
index d66753d..ef5dfcd 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
@@ -858,6 +858,36 @@
}
@Test
+ public void testGetRef_CycleInSymbolicRef() throws IOException {
+ Ref r;
+
+ writeLooseRef("refs/1", "ref: refs/2\n");
+ writeLooseRef("refs/2", "ref: refs/3\n");
+ writeLooseRef("refs/3", "ref: refs/4\n");
+ writeLooseRef("refs/4", "ref: refs/5\n");
+ writeLooseRef("refs/5", "ref: refs/end\n");
+ writeLooseRef("refs/end", A);
+
+ r = refdir.getRef("1");
+ assertEquals("refs/1", r.getName());
+ assertEquals(A, r.getObjectId());
+ assertTrue(r.isSymbolic());
+
+ writeLooseRef("refs/5", "ref: refs/6\n");
+ writeLooseRef("refs/6", "ref: refs/end\n");
+
+ r = refdir.getRef("1");
+ assertNull("missing 1 due to cycle", r);
+
+ writeLooseRef("refs/heads/1", B);
+
+ r = refdir.getRef("1");
+ assertEquals("refs/heads/1", r.getName());
+ assertEquals(B, r.getObjectId());
+ assertFalse(r.isSymbolic());
+ }
+
+ @Test
public void testGetRefs_PackedNotPeeled_Sorted() throws IOException {
Map<String, Ref> all;
@@ -1414,8 +1444,8 @@
// empty
}
- public void beginTask(String title, int totalWork) {
- this.totalWork = totalWork;
+ public void beginTask(String title, int total) {
+ this.totalWork = total;
lastWork = 0;
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java
index 098b31f..7adf074 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java
@@ -347,7 +347,7 @@
Result update = updateRef.update();
assertEquals(Result.FORCED, update);
assertEquals(ppid, db.resolve("HEAD"));
- Ref ref = db.getRef("HEAD");
+ Ref ref = db.exactRef("HEAD");
assertEquals("HEAD", ref.getName());
assertTrue("is detached", !ref.isSymbolic());
@@ -377,7 +377,7 @@
Result update = updateRef.update();
assertEquals(Result.NEW, update);
assertEquals(ppid, db.resolve("HEAD"));
- Ref ref = db.getRef("HEAD");
+ Ref ref = db.exactRef("HEAD");
assertEquals("HEAD", ref.getName());
assertTrue("is detached", !ref.isSymbolic());
@@ -558,13 +558,15 @@
assertEquals(ppid, db.resolve("refs/heads/master"));
// real test
- RevCommit old = new RevWalk(db).parseCommit(ppid);
- RefUpdate updateRef2 = db.updateRef("refs/heads/master");
- updateRef2.setExpectedOldObjectId(old);
- updateRef2.setNewObjectId(pid);
- Result update2 = updateRef2.update();
- assertEquals(Result.FAST_FORWARD, update2);
- assertEquals(pid, db.resolve("refs/heads/master"));
+ try (RevWalk rw = new RevWalk(db)) {
+ RevCommit old = rw.parseCommit(ppid);
+ RefUpdate updateRef2 = db.updateRef("refs/heads/master");
+ updateRef2.setExpectedOldObjectId(old);
+ updateRef2.setNewObjectId(pid);
+ Result update2 = updateRef2.update();
+ assertEquals(Result.FAST_FORWARD, update2);
+ assertEquals(pid, db.resolve("refs/heads/master"));
+ }
}
/**
@@ -579,14 +581,13 @@
RefUpdate updateRef = db.updateRef("refs/heads/master");
updateRef.setNewObjectId(pid);
LockFile lockFile1 = new LockFile(new File(db.getDirectory(),
- "refs/heads/master"), db.getFS());
+ "refs/heads/master"));
try {
assertTrue(lockFile1.lock()); // precondition to test
Result update = updateRef.update();
assertEquals(Result.LOCK_FAILURE, update);
assertEquals(opid, db.resolve("refs/heads/master"));
- LockFile lockFile2 = new LockFile(new File(db.getDirectory(),"refs/heads/master"),
- db.getFS());
+ LockFile lockFile2 = new LockFile(new File(db.getDirectory(),"refs/heads/master"));
assertFalse(lockFile2.lock()); // was locked, still is
} finally {
lockFile1.unlock();
@@ -681,13 +682,13 @@
public void testRenameBranchAlsoInPack() throws IOException {
ObjectId rb = db.resolve("refs/heads/b");
ObjectId rb2 = db.resolve("refs/heads/b~1");
- assertEquals(Ref.Storage.PACKED, db.getRef("refs/heads/b").getStorage());
+ assertEquals(Ref.Storage.PACKED, db.exactRef("refs/heads/b").getStorage());
RefUpdate updateRef = db.updateRef("refs/heads/b");
updateRef.setNewObjectId(rb2);
updateRef.setForceUpdate(true);
Result update = updateRef.update();
assertEquals("internal check new ref is loose", Result.FORCED, update);
- assertEquals(Ref.Storage.LOOSE, db.getRef("refs/heads/b").getStorage());
+ assertEquals(Ref.Storage.LOOSE, db.exactRef("refs/heads/b").getStorage());
writeReflog(db, rb, "Just a message", "refs/heads/b");
assertTrue("log on old branch", new File(db.getDirectory(),
"logs/refs/heads/b").exists());
@@ -707,9 +708,10 @@
// Create new Repository instance, to reread caches and make sure our
// assumptions are persistent.
- Repository ndb = new FileRepository(db.getDirectory());
- assertEquals(rb2, ndb.resolve("refs/heads/new/name"));
- assertNull(ndb.resolve("refs/heads/b"));
+ try (Repository ndb = new FileRepository(db.getDirectory())) {
+ assertEquals(rb2, ndb.resolve("refs/heads/new/name"));
+ assertNull(ndb.resolve("refs/heads/b"));
+ }
}
public void tryRenameWhenLocked(String toLock, String fromName,
@@ -728,8 +730,7 @@
"logs/" + fromName).exists());
// "someone" has branch X locked
- LockFile lockFile = new LockFile(new File(db.getDirectory(), toLock),
- db.getFS());
+ LockFile lockFile = new LockFile(new File(db.getDirectory(), toLock));
try {
assertTrue(lockFile.lock());
@@ -751,7 +752,7 @@
assertNull(db.resolve(toName));
assertEquals(oldFromLog.toString(), db.getReflogReader(fromName)
.getReverseEntries().toString());
- if (oldHeadId != null)
+ if (oldHeadId != null && oldHeadLog != null)
assertEquals(oldHeadLog.toString(), db.getReflogReader(
Constants.HEAD).getReverseEntries().toString());
} finally {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RepositorySetupWorkDirTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RepositorySetupWorkDirTest.java
index 295ef45..84c2543 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RepositorySetupWorkDirTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RepositorySetupWorkDirTest.java
@@ -73,13 +73,14 @@
public void testIsBare_CreateRepositoryFromArbitraryGitDir()
throws Exception {
File gitDir = getFile("workdir");
- assertTrue(new FileRepository(gitDir).isBare());
+ Repository repo = new FileRepositoryBuilder().setGitDir(gitDir).build();
+ assertTrue(repo.isBare());
}
@Test
public void testNotBare_CreateRepositoryFromDotGitGitDir() throws Exception {
File gitDir = getFile("workdir", Constants.DOT_GIT);
- Repository repo = new FileRepository(gitDir);
+ Repository repo = new FileRepositoryBuilder().setGitDir(gitDir).build();
assertFalse(repo.isBare());
assertWorkdirPath(repo, "workdir");
assertGitdirPath(repo, "workdir", Constants.DOT_GIT);
@@ -89,7 +90,7 @@
public void testWorkdirIsParentDir_CreateRepositoryFromDotGitGitDir()
throws Exception {
File gitDir = getFile("workdir", Constants.DOT_GIT);
- Repository repo = new FileRepository(gitDir);
+ Repository repo = new FileRepositoryBuilder().setGitDir(gitDir).build();
String workdir = repo.getWorkTree().getName();
assertEquals(workdir, "workdir");
}
@@ -157,8 +158,8 @@
@Test
public void testExceptionThrown_BareRepoGetWorkDir() throws Exception {
File gitDir = getFile("workdir");
- try {
- new FileRepository(gitDir).getWorkTree();
+ try (Repository repo = new FileRepository(gitDir)) {
+ repo.getWorkTree();
fail("Expected NoWorkTreeException missing");
} catch (NoWorkTreeException e) {
// expected
@@ -168,8 +169,8 @@
@Test
public void testExceptionThrown_BareRepoGetIndex() throws Exception {
File gitDir = getFile("workdir");
- try {
- new FileRepository(gitDir).readDirCache();
+ try (Repository repo = new FileRepository(gitDir)) {
+ repo.readDirCache();
fail("Expected NoWorkTreeException missing");
} catch (NoWorkTreeException e) {
// expected
@@ -179,8 +180,8 @@
@Test
public void testExceptionThrown_BareRepoGetIndexFile() throws Exception {
File gitDir = getFile("workdir");
- try {
- new FileRepository(gitDir).getIndexFile();
+ try (Repository repo = new FileRepository(gitDir)) {
+ repo.getIndexFile();
fail("Expected NoWorkTreeException missing");
} catch (NoWorkTreeException e) {
// expected
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
index 5670a96..b6ad22b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
@@ -67,7 +67,6 @@
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.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;
@@ -86,7 +84,6 @@
import org.eclipse.jgit.util.FileUtils;
import org.junit.Test;
-@SuppressWarnings("deprecation")
public class T0003_BasicTest extends SampleDataRepositoryTestCase {
@Test
@@ -357,11 +354,12 @@
@Test
public void test007_Open() throws IOException {
- final FileRepository db2 = new FileRepository(db.getDirectory());
- assertEquals(db.getDirectory(), db2.getDirectory());
- assertEquals(db.getObjectDatabase().getDirectory(), db2
- .getObjectDatabase().getDirectory());
- assertNotSame(db.getConfig(), db2.getConfig());
+ try (final FileRepository db2 = new FileRepository(db.getDirectory())) {
+ assertEquals(db.getDirectory(), db2.getDirectory());
+ assertEquals(db.getObjectDatabase().getDirectory(), db2
+ .getObjectDatabase().getDirectory());
+ assertNotSame(db.getConfig(), db2.getConfig());
+ }
}
@Test
@@ -372,8 +370,7 @@
+ badvers + "\n";
write(cfg, configStr);
- try {
- new FileRepository(db.getDirectory());
+ try (FileRepository unused = new FileRepository(db.getDirectory())) {
fail("incorrectly opened a bad repository");
} catch (IllegalArgumentException ioe) {
assertNotNull(ioe.getMessage());
@@ -419,29 +416,6 @@
}
@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();
final TagBuilder t = new TagBuilder();
@@ -464,9 +438,8 @@
@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);
@@ -488,9 +461,8 @@
@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,
@@ -520,9 +492,8 @@
@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);
@@ -542,9 +513,8 @@
@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);
@@ -562,9 +532,10 @@
public void test025_computeSha1NoStore() throws IOException {
byte[] data = "test025 some data, more than 16 bytes to get good coverage"
.getBytes("ISO-8859-1");
- final ObjectId id = new ObjectInserter.Formatter().idFor(
- Constants.OBJ_BLOB, data);
- assertEquals("4f561df5ecf0dfbd53a0dc0f37262fef075d9dde", id.name());
+ try (ObjectInserter.Formatter formatter = new ObjectInserter.Formatter()) {
+ final ObjectId id = formatter.idFor(Constants.OBJ_BLOB, data);
+ assertEquals("4f561df5ecf0dfbd53a0dc0f37262fef075d9dde", id.name());
+ }
}
@Test
@@ -746,14 +717,6 @@
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);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/UnpackedObjectTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/UnpackedObjectTest.java
index 8c8c6c6..c6653bf 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/UnpackedObjectTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/UnpackedObjectTest.java
@@ -143,7 +143,7 @@
public void testStandardFormat_LargeObject() throws Exception {
final int type = Constants.OBJ_BLOB;
byte[] data = getRng().nextBytes(streamThreshold + 5);
- ObjectId id = new ObjectInserter.Formatter().idFor(type, data);
+ ObjectId id = getId(type, data);
write(id, compressStandardFormat(type, data));
ObjectLoader ol;
@@ -306,7 +306,7 @@
throws Exception {
final int type = Constants.OBJ_BLOB;
byte[] data = getRng().nextBytes(streamThreshold + 5);
- ObjectId id = new ObjectInserter.Formatter().idFor(type, data);
+ ObjectId id = getId(type, data);
byte[] gz = compressStandardFormat(type, data);
gz[gz.length - 1] = 0;
gz[gz.length - 2] = 0;
@@ -344,7 +344,7 @@
throws Exception {
final int type = Constants.OBJ_BLOB;
byte[] data = getRng().nextBytes(streamThreshold + 5);
- ObjectId id = new ObjectInserter.Formatter().idFor(type, data);
+ ObjectId id = getId(type, data);
byte[] gz = compressStandardFormat(type, data);
byte[] tr = new byte[gz.length - 1];
System.arraycopy(gz, 0, tr, 0, tr.length);
@@ -379,7 +379,7 @@
throws Exception {
final int type = Constants.OBJ_BLOB;
byte[] data = getRng().nextBytes(streamThreshold + 5);
- ObjectId id = new ObjectInserter.Formatter().idFor(type, data);
+ ObjectId id = getId(type, data);
byte[] gz = compressStandardFormat(type, data);
byte[] tr = new byte[gz.length + 1];
System.arraycopy(gz, 0, tr, 0, gz.length);
@@ -438,7 +438,7 @@
public void testPackFormat_LargeObject() throws Exception {
final int type = Constants.OBJ_BLOB;
byte[] data = getRng().nextBytes(streamThreshold + 5);
- ObjectId id = new ObjectInserter.Formatter().idFor(type, data);
+ ObjectId id = getId(type, data);
write(id, compressPackFormat(type, data));
ObjectLoader ol;
@@ -578,4 +578,10 @@
out.close();
}
}
+
+ private ObjectId getId(int type, byte[] data) {
+ try (ObjectInserter.Formatter formatter = new ObjectInserter.Formatter()) {
+ return formatter.idFor(type, data);
+ }
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java
new file mode 100644
index 0000000..5fda070
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java
@@ -0,0 +1,271 @@
+/*
+ * 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.internal.storage.pack;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jgit.internal.storage.file.GcTestCase;
+import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder;
+import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
+import org.eclipse.jgit.internal.storage.pack.PackWriterBitmapPreparer;
+import org.eclipse.jgit.internal.storage.pack.PackWriterBitmapPreparer.BitmapCommit;
+import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
+import org.eclipse.jgit.junit.TestRepository.CommitBuilder;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.storage.pack.PackConfig;
+import org.junit.Test;
+
+public class GcCommitSelectionTest extends GcTestCase {
+
+ @Test
+ public void testBitmapSpansNoMerges() throws Exception {
+ /*
+ * Commit counts -> expected bitmap counts for history without merges.
+ * The top 100 contiguous commits should always have bitmaps, and the
+ * "recent" bitmaps beyond that are spaced out every 100-200 commits.
+ * (Starting at 100, the next 100 commits are searched for a merge
+ * commit. Since one is not found, the spacing between commits is 200.
+ */
+ int[][] bitmapCounts = { //
+ { 1, 1 }, { 50, 50 }, { 99, 99 }, { 100, 100 }, { 101, 100 },
+ { 200, 100 }, { 201, 100 }, { 299, 100 }, { 300, 101 },
+ { 301, 101 }, { 401, 101 }, { 499, 101 }, { 500, 102 }, };
+ int currentCommits = 0;
+ BranchBuilder bb = tr.branch("refs/heads/main");
+
+ for (int[] counts : bitmapCounts) {
+ int nextCommitCount = counts[0];
+ int expectedBitmapCount = counts[1];
+ assertTrue(nextCommitCount > currentCommits); // programming error
+ for (int i = currentCommits; i < nextCommitCount; i++) {
+ String str = "A" + i;
+ bb.commit().message(str).add(str, str).create();
+ }
+ currentCommits = nextCommitCount;
+
+ gc.setExpireAgeMillis(0); // immediately delete old packs
+ gc.gc();
+ assertEquals(currentCommits * 3, // commit/tree/object
+ gc.getStatistics().numberOfPackedObjects);
+ assertEquals(currentCommits + " commits: ", expectedBitmapCount,
+ gc.getStatistics().numberOfBitmaps);
+ }
+ }
+
+ @Test
+ public void testBitmapSpansWithMerges() throws Exception {
+ /*
+ * Commits that are merged. Since 55 is in the oldest history it is
+ * never considered. Searching goes from oldest to newest so 115 is the
+ * first merge commit found. After that the range 116-216 is ignored so
+ * 175 is never considered.
+ */
+ List<Integer> merges = Arrays.asList(Integer.valueOf(55),
+ Integer.valueOf(115), Integer.valueOf(175),
+ Integer.valueOf(235));
+ /*
+ * Commit counts -> expected bitmap counts for history with merges. The
+ * top 100 contiguous commits should always have bitmaps, and the
+ * "recent" bitmaps beyond that are spaced out every 100-200 commits.
+ * Merges in the < 100 range have no effect and merges in the > 100
+ * range will only be considered for commit counts > 200.
+ */
+ int[][] bitmapCounts = { //
+ { 1, 1 }, { 55, 55 }, { 56, 57 }, // +1 bitmap from branch A55
+ { 99, 100 }, // still +1 branch @55
+ { 100, 100 }, // 101 commits, only 100 newest
+ { 116, 100 }, // @55 still in 100 newest bitmaps
+ { 176, 101 }, // @55 branch tip is not in 100 newest
+ { 213, 101 }, // 216 commits, @115&@175 in 100 newest
+ { 214, 102 }, // @55 branch tip, merge @115, @177 in newest
+ { 236, 102 }, // all 4 merge points in history
+ { 273, 102 }, // 277 commits, @175&@235 in newest
+ { 274, 103 }, // @55, @115, merge @175, @235 in newest
+ { 334, 103 }, // @55,@115,@175, @235 in newest
+ { 335, 104 }, // @55,@115,@175, merge @235
+ { 435, 104 }, // @55,@115,@175,@235 tips
+ { 436, 104 }, // force @236
+ };
+
+ int currentCommits = 0;
+ BranchBuilder bb = tr.branch("refs/heads/main");
+
+ for (int[] counts : bitmapCounts) {
+ int nextCommitCount = counts[0];
+ int expectedBitmapCount = counts[1];
+ assertTrue(nextCommitCount > currentCommits); // programming error
+ for (int i = currentCommits; i < nextCommitCount; i++) {
+ String str = "A" + i;
+ if (!merges.contains(Integer.valueOf(i))) {
+ bb.commit().message(str).add(str, str).create();
+ } else {
+ BranchBuilder bbN = tr.branch("refs/heads/A" + i);
+ bb.commit().message(str).add(str, str)
+ .parent(bbN.commit().create()).create();
+ }
+ }
+ currentCommits = nextCommitCount;
+
+ gc.setExpireAgeMillis(0); // immediately delete old packs
+ gc.gc();
+ assertEquals(currentCommits + " commits: ", expectedBitmapCount,
+ gc.getStatistics().numberOfBitmaps);
+ }
+ }
+
+ @Test
+ public void testBitmapsForExcessiveBranches() throws Exception {
+ int oneDayInSeconds = 60 * 60 * 24;
+
+ // All of branch A is committed on day1
+ BranchBuilder bbA = tr.branch("refs/heads/A");
+ for (int i = 0; i < 1001; i++) {
+ String msg = "A" + i;
+ bbA.commit().message(msg).add(msg, msg).create();
+ }
+ // All of in branch B is committed on day91
+ tr.tick(oneDayInSeconds * 90);
+ BranchBuilder bbB = tr.branch("refs/heads/B");
+ for (int i = 0; i < 1001; i++) {
+ String msg = "B" + i;
+ bbB.commit().message(msg).add(msg, msg).create();
+ }
+ // Create 100 other branches with a single commit
+ for (int i = 0; i < 100; i++) {
+ BranchBuilder bb = tr.branch("refs/heads/N" + i);
+ String msg = "singlecommit" + i;
+ bb.commit().message(msg).add(msg, msg).create();
+ }
+ // now is day92
+ tr.tick(oneDayInSeconds);
+
+ // Since there are no merges, commits in recent history are selected
+ // every 200 commits.
+ final int commitsForSparseBranch = 1 + (1001 / 200);
+ final int commitsForFullBranch = 100 + (901 / 200);
+ final int commitsForShallowBranches = 100;
+
+ // Excessive branch history pruning, one old branch.
+ gc.setExpireAgeMillis(0); // immediately delete old packs
+ gc.gc();
+ assertEquals(
+ commitsForSparseBranch + commitsForFullBranch
+ + commitsForShallowBranches,
+ gc.getStatistics().numberOfBitmaps);
+ }
+
+ @Test
+ public void testSelectionOrderingWithChains() throws Exception {
+ /*-
+ * Create a history like this, where 'N' is the number of seconds from
+ * the first commit in the branch:
+ *
+ * ---o---o---o commits b3,b5,b7
+ * / \
+ * o--o--o---o---o---o--o commits m0,m1,m2,m4,m6,m8,m9
+ */
+ BranchBuilder bb = tr.branch("refs/heads/main");
+ RevCommit m0 = addCommit(bb, "m0");
+ RevCommit m1 = addCommit(bb, "m1", m0);
+ RevCommit m2 = addCommit(bb, "m2", m1);
+ RevCommit b3 = addCommit(bb, "b3", m1);
+ RevCommit m4 = addCommit(bb, "m4", m2);
+ RevCommit b5 = addCommit(bb, "m5", b3);
+ RevCommit m6 = addCommit(bb, "m6", m4);
+ RevCommit b7 = addCommit(bb, "m7", b5);
+ RevCommit m8 = addCommit(bb, "m8", m6, b7);
+ RevCommit m9 = addCommit(bb, "m9", m8);
+
+ List<RevCommit> commits = Arrays.asList(m0, m1, m2, b3, m4, b5, m6, b7,
+ m8, m9);
+ PackWriterBitmapPreparer preparer = newPeparer(m9, commits);
+ List<BitmapCommit> selection = new ArrayList<>(
+ preparer.selectCommits(commits.size()));
+
+ // Verify that the output is ordered by the separate "chains"
+ String[] expected = { m0.name(), m1.name(), m2.name(), m4.name(),
+ m6.name(), m8.name(), m9.name(), b3.name(), b5.name(),
+ b7.name() };
+ assertEquals(expected.length, selection.size());
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals("Entry " + i, expected[i], selection.get(i).getName());
+ }
+ }
+
+ private RevCommit addCommit(BranchBuilder bb, String msg,
+ RevCommit... parents) throws Exception {
+ CommitBuilder commit = bb.commit().message(msg).add(msg, msg).tick(1)
+ .noParents();
+ for (RevCommit parent : parents) {
+ commit.parent(parent);
+ }
+ return commit.create();
+ }
+
+ private PackWriterBitmapPreparer newPeparer(RevCommit want,
+ List<RevCommit> commits)
+ throws IOException {
+ List<ObjectToPack> objects = new ArrayList<>(commits.size());
+ for (RevCommit commit : commits) {
+ objects.add(new ObjectToPack(commit, Constants.OBJ_COMMIT));
+ }
+ Set<ObjectId> wants = Collections.singleton((ObjectId) want);
+ PackConfig config = new PackConfig();
+ PackBitmapIndexBuilder builder = new PackBitmapIndexBuilder(objects);
+ return new PackWriterBitmapPreparer(
+ tr.getRepository().newObjectReader(), builder,
+ NullProgressMonitor.INSTANCE, wants, config);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparerTest.java
new file mode 100644
index 0000000..b0f92ff
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparerTest.java
@@ -0,0 +1,136 @@
+package org.eclipse.jgit.internal.storage.pack;
+
+import static org.eclipse.jgit.storage.pack.PackConfig.DEFAULT_BITMAP_DISTANT_COMMIT_SPAN;
+import static org.eclipse.jgit.storage.pack.PackConfig.DEFAULT_BITMAP_RECENT_COMMIT_COUNT;
+import static org.eclipse.jgit.storage.pack.PackConfig.DEFAULT_BITMAP_RECENT_COMMIT_SPAN;
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder;
+import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.storage.pack.PackConfig;
+import org.junit.Test;
+
+/** Tests for the {@link PackWriterBitmapPreparer}. */
+public class PackWriterBitmapPreparerTest {
+ private static class StubObjectReader extends ObjectReader {
+ @Override
+ public ObjectReader newReader() {
+ return null;
+ }
+
+ @Override
+ public Collection<ObjectId> resolve(AbbreviatedObjectId id)
+ throws IOException {
+ return null;
+ }
+
+ @Override
+ public ObjectLoader open(AnyObjectId objectId, int typeHint)
+ throws MissingObjectException, IncorrectObjectTypeException,
+ IOException {
+ return null;
+ }
+
+ @Override
+ public Set<ObjectId> getShallowCommits() throws IOException {
+ return null;
+ }
+
+ @Override
+ public void close() {
+ // stub
+ }
+ }
+
+ @Test
+ public void testNextSelectionDistanceForActiveBranch() throws Exception {
+ PackWriterBitmapPreparer preparer = newPeparer(
+ DEFAULT_BITMAP_RECENT_COMMIT_COUNT, // 20000
+ DEFAULT_BITMAP_RECENT_COMMIT_SPAN, // 100
+ DEFAULT_BITMAP_DISTANT_COMMIT_SPAN); // 5000
+ int[][] distancesAndSpans = { { 0, 100 }, { 100, 100 }, { 10000, 100 },
+ { 20000, 100 }, { 20100, 100 }, { 20102, 102 }, { 20200, 200 },
+ { 22200, 2200 }, { 24999, 4999 }, { 25000, 5000 },
+ { 50000, 5000 }, { 1000000, 5000 }, };
+
+ for (int[] pair : distancesAndSpans) {
+ assertEquals(pair[1], preparer.nextSpan(pair[0]));
+ }
+ }
+
+ @Test
+ public void testNextSelectionDistanceWithFewerRecentCommits()
+ throws Exception {
+ PackWriterBitmapPreparer preparer = newPeparer(1000,
+ DEFAULT_BITMAP_RECENT_COMMIT_SPAN, // 100
+ DEFAULT_BITMAP_DISTANT_COMMIT_SPAN); // 5000
+ int[][] distancesAndSpans = { { 0, 100 }, { 100, 100 }, { 1000, 100 },
+ { 1100, 100 }, { 1111, 111 }, { 2000, 1000 }, { 5999, 4999 },
+ { 6000, 5000 }, { 10000, 5000 }, { 50000, 5000 },
+ { 1000000, 5000 } };
+
+ for (int[] pair : distancesAndSpans) {
+ assertEquals(pair[1], preparer.nextSpan(pair[0]));
+ }
+ }
+
+ @Test
+ public void testNextSelectionDistanceWithSmallerRecentSpan()
+ throws Exception {
+ PackWriterBitmapPreparer preparer = newPeparer(
+ DEFAULT_BITMAP_RECENT_COMMIT_COUNT, // 20000
+ 10, // recent span
+ DEFAULT_BITMAP_DISTANT_COMMIT_SPAN); // 5000
+ int[][] distancesAndSpans = { { 0, 10 }, { 100, 10 }, { 10000, 10 },
+ { 20000, 10 }, { 20010, 10 }, { 20012, 12 }, { 20050, 50 },
+ { 20200, 200 }, { 22200, 2200 }, { 24999, 4999 },
+ { 25000, 5000 }, { 50000, 5000 }, { 1000000, 5000 } };
+
+ for (int[] pair : distancesAndSpans) {
+ assertEquals(pair[1], preparer.nextSpan(pair[0]));
+ }
+ }
+
+ @Test
+ public void testNextSelectionDistanceWithSmallerDistantSpan()
+ throws Exception {
+ PackWriterBitmapPreparer preparer = newPeparer(
+ DEFAULT_BITMAP_RECENT_COMMIT_COUNT, // 20000
+ DEFAULT_BITMAP_RECENT_COMMIT_SPAN, // 100
+ 1000);
+ int[][] distancesAndSpans = { { 0, 100 }, { 100, 100 }, { 10000, 100 },
+ { 20000, 100 }, { 20100, 100 }, { 20102, 102 }, { 20200, 200 },
+ { 20999, 999 }, { 21000, 1000 }, { 22000, 1000 },
+ { 25000, 1000 }, { 50000, 1000 }, { 1000000, 1000 } };
+
+ for (int[] pair : distancesAndSpans) {
+ assertEquals(pair[1], preparer.nextSpan(pair[0]));
+ }
+ }
+
+ private PackWriterBitmapPreparer newPeparer(int recentCount, int recentSpan,
+ int distantSpan) throws IOException {
+ List<ObjectToPack> objects = Collections.emptyList();
+ Set<ObjectId> wants = Collections.emptySet();
+ PackConfig config = new PackConfig();
+ config.setBitmapRecentCommitCount(recentCount);
+ config.setBitmapRecentCommitSpan(recentSpan);
+ config.setBitmapDistantCommitSpan(distantSpan);
+ PackBitmapIndexBuilder indexBuilder = new PackBitmapIndexBuilder(
+ objects);
+ return new PackWriterBitmapPreparer(new StubObjectReader(),
+ indexBuilder, null, wants, config);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java
new file mode 100644
index 0000000..020d1b1
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java
@@ -0,0 +1,685 @@
+/*
+ * Copyright (C) 2010, 2013, 2016 Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.storage.reftree;
+
+import static org.eclipse.jgit.lib.Constants.HEAD;
+import static org.eclipse.jgit.lib.Constants.R_HEADS;
+import static org.eclipse.jgit.lib.Constants.R_TAGS;
+import static org.eclipse.jgit.lib.Ref.Storage.LOOSE;
+import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
+import static org.eclipse.jgit.lib.RefDatabase.ALL;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.OK;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_NONFASTFORWARD;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.BatchRefUpdate;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.SymbolicRef;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTag;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RefTreeDatabaseTest {
+ private InMemRefTreeRepo repo;
+ private RefTreeDatabase refdb;
+ private RefDatabase bootstrap;
+
+ private TestRepository<InMemRefTreeRepo> testRepo;
+ private RevCommit A;
+ private RevCommit B;
+ private RevTag v1_0;
+
+ @Before
+ public void setUp() throws Exception {
+ repo = new InMemRefTreeRepo(new DfsRepositoryDescription("test"));
+ bootstrap = refdb.getBootstrap();
+
+ testRepo = new TestRepository<>(repo);
+ A = testRepo.commit().create();
+ B = testRepo.commit(testRepo.getRevWalk().parseCommit(A));
+ v1_0 = testRepo.tag("v1_0", B);
+ testRepo.getRevWalk().parseBody(v1_0);
+ }
+
+ @Test
+ public void testSupportsAtomic() {
+ assertTrue(refdb.performsAtomicTransactions());
+ }
+
+ @Test
+ public void testGetRefs_EmptyDatabase() throws IOException {
+ assertTrue("no references", refdb.getRefs(ALL).isEmpty());
+ assertTrue("no references", refdb.getRefs(R_HEADS).isEmpty());
+ assertTrue("no references", refdb.getRefs(R_TAGS).isEmpty());
+ }
+
+ @Test
+ public void testGetRefs_HeadOnOneBranch() throws IOException {
+ symref(HEAD, "refs/heads/master");
+ update("refs/heads/master", A);
+
+ Map<String, Ref> all = refdb.getRefs(ALL);
+ assertEquals(2, all.size());
+ assertTrue("has HEAD", all.containsKey(HEAD));
+ assertTrue("has master", all.containsKey("refs/heads/master"));
+
+ Ref head = all.get(HEAD);
+ Ref master = all.get("refs/heads/master");
+
+ assertEquals(HEAD, head.getName());
+ assertTrue(head.isSymbolic());
+ assertSame(LOOSE, head.getStorage());
+ assertSame("uses same ref as target", master, head.getTarget());
+
+ assertEquals("refs/heads/master", master.getName());
+ assertFalse(master.isSymbolic());
+ assertSame(PACKED, master.getStorage());
+ assertEquals(A, master.getObjectId());
+ }
+
+ @Test
+ public void testGetRefs_DetachedHead() throws IOException {
+ update(HEAD, A);
+
+ Map<String, Ref> all = refdb.getRefs(ALL);
+ assertEquals(1, all.size());
+ assertTrue("has HEAD", all.containsKey(HEAD));
+
+ Ref head = all.get(HEAD);
+ assertEquals(HEAD, head.getName());
+ assertFalse(head.isSymbolic());
+ assertSame(PACKED, head.getStorage());
+ assertEquals(A, head.getObjectId());
+ }
+
+ @Test
+ public void testGetRefs_DeeplyNestedBranch() throws IOException {
+ String name = "refs/heads/a/b/c/d/e/f/g/h/i/j/k";
+ update(name, A);
+
+ Map<String, Ref> all = refdb.getRefs(ALL);
+ assertEquals(1, all.size());
+
+ Ref r = all.get(name);
+ assertEquals(name, r.getName());
+ assertFalse(r.isSymbolic());
+ assertSame(PACKED, r.getStorage());
+ assertEquals(A, r.getObjectId());
+ }
+
+ @Test
+ public void testGetRefs_HeadBranchNotBorn() throws IOException {
+ update("refs/heads/A", A);
+ update("refs/heads/B", B);
+
+ Map<String, Ref> all = refdb.getRefs(ALL);
+ assertEquals(2, all.size());
+ assertFalse("no HEAD", all.containsKey(HEAD));
+
+ Ref a = all.get("refs/heads/A");
+ Ref b = all.get("refs/heads/B");
+
+ assertEquals(A, a.getObjectId());
+ assertEquals(B, b.getObjectId());
+
+ assertEquals("refs/heads/A", a.getName());
+ assertEquals("refs/heads/B", b.getName());
+ }
+
+ @Test
+ public void testGetRefs_HeadsOnly() throws IOException {
+ update("refs/heads/A", A);
+ update("refs/heads/B", B);
+ update("refs/tags/v1.0", v1_0);
+
+ Map<String, Ref> heads = refdb.getRefs(R_HEADS);
+ assertEquals(2, heads.size());
+
+ Ref a = heads.get("A");
+ Ref b = heads.get("B");
+
+ assertEquals("refs/heads/A", a.getName());
+ assertEquals("refs/heads/B", b.getName());
+
+ assertEquals(A, a.getObjectId());
+ assertEquals(B, b.getObjectId());
+ }
+
+ @Test
+ public void testGetRefs_TagsOnly() throws IOException {
+ update("refs/heads/A", A);
+ update("refs/heads/B", B);
+ update("refs/tags/v1.0", v1_0);
+
+ Map<String, Ref> tags = refdb.getRefs(R_TAGS);
+ assertEquals(1, tags.size());
+
+ Ref a = tags.get("v1.0");
+ assertEquals("refs/tags/v1.0", a.getName());
+ assertEquals(v1_0, a.getObjectId());
+ assertTrue(a.isPeeled());
+ assertEquals(v1_0.getObject(), a.getPeeledObjectId());
+ }
+
+ @Test
+ public void testGetRefs_HeadsSymref() throws IOException {
+ symref("refs/heads/other", "refs/heads/master");
+ update("refs/heads/master", A);
+
+ Map<String, Ref> heads = refdb.getRefs(R_HEADS);
+ assertEquals(2, heads.size());
+
+ Ref master = heads.get("master");
+ Ref other = heads.get("other");
+
+ assertEquals("refs/heads/master", master.getName());
+ assertEquals(A, master.getObjectId());
+
+ assertEquals("refs/heads/other", other.getName());
+ assertEquals(A, other.getObjectId());
+ assertSame(master, other.getTarget());
+ }
+
+ @Test
+ public void testGetRefs_InvalidPrefixes() throws IOException {
+ update("refs/heads/A", A);
+
+ assertTrue("empty refs/heads", refdb.getRefs("refs/heads").isEmpty());
+ assertTrue("empty objects", refdb.getRefs("objects").isEmpty());
+ assertTrue("empty objects/", refdb.getRefs("objects/").isEmpty());
+ }
+
+ @Test
+ public void testGetRefs_DiscoversNew() throws IOException {
+ update("refs/heads/master", A);
+ Map<String, Ref> orig = refdb.getRefs(ALL);
+
+ update("refs/heads/next", B);
+ Map<String, Ref> next = refdb.getRefs(ALL);
+
+ assertEquals(1, orig.size());
+ assertEquals(2, next.size());
+
+ assertFalse(orig.containsKey("refs/heads/next"));
+ assertTrue(next.containsKey("refs/heads/next"));
+
+ assertEquals(A, next.get("refs/heads/master").getObjectId());
+ assertEquals(B, next.get("refs/heads/next").getObjectId());
+ }
+
+ @Test
+ public void testGetRefs_DiscoversModified() throws IOException {
+ symref(HEAD, "refs/heads/master");
+ update("refs/heads/master", A);
+
+ Map<String, Ref> all = refdb.getRefs(ALL);
+ assertEquals(A, all.get(HEAD).getObjectId());
+
+ update("refs/heads/master", B);
+ all = refdb.getRefs(ALL);
+ assertEquals(B, all.get(HEAD).getObjectId());
+ assertEquals(B, refdb.exactRef(HEAD).getObjectId());
+ }
+
+ @Test
+ public void testGetRefs_CycleInSymbolicRef() throws IOException {
+ symref("refs/1", "refs/2");
+ symref("refs/2", "refs/3");
+ symref("refs/3", "refs/4");
+ symref("refs/4", "refs/5");
+ symref("refs/5", "refs/end");
+ update("refs/end", A);
+
+ Map<String, Ref> all = refdb.getRefs(ALL);
+ Ref r = all.get("refs/1");
+ assertNotNull("has 1", r);
+
+ assertEquals("refs/1", r.getName());
+ assertEquals(A, r.getObjectId());
+ assertTrue(r.isSymbolic());
+
+ r = r.getTarget();
+ assertEquals("refs/2", r.getName());
+ assertEquals(A, r.getObjectId());
+ assertTrue(r.isSymbolic());
+
+ r = r.getTarget();
+ assertEquals("refs/3", r.getName());
+ assertEquals(A, r.getObjectId());
+ assertTrue(r.isSymbolic());
+
+ r = r.getTarget();
+ assertEquals("refs/4", r.getName());
+ assertEquals(A, r.getObjectId());
+ assertTrue(r.isSymbolic());
+
+ r = r.getTarget();
+ assertEquals("refs/5", r.getName());
+ assertEquals(A, r.getObjectId());
+ assertTrue(r.isSymbolic());
+
+ r = r.getTarget();
+ assertEquals("refs/end", r.getName());
+ assertEquals(A, r.getObjectId());
+ assertFalse(r.isSymbolic());
+
+ symref("refs/5", "refs/6");
+ symref("refs/6", "refs/end");
+ all = refdb.getRefs(ALL);
+ assertNull("mising 1 due to cycle", all.get("refs/1"));
+ assertEquals(A, all.get("refs/2").getObjectId());
+ assertEquals(A, all.get("refs/3").getObjectId());
+ assertEquals(A, all.get("refs/4").getObjectId());
+ assertEquals(A, all.get("refs/5").getObjectId());
+ assertEquals(A, all.get("refs/6").getObjectId());
+ assertEquals(A, all.get("refs/end").getObjectId());
+ }
+
+ @Test
+ public void testGetRef_NonExistingBranchConfig() throws IOException {
+ assertNull("find branch config", refdb.getRef("config"));
+ assertNull("find branch config", refdb.getRef("refs/heads/config"));
+ }
+
+ @Test
+ public void testGetRef_FindBranchConfig() throws IOException {
+ update("refs/heads/config", A);
+
+ for (String t : new String[] { "config", "refs/heads/config" }) {
+ Ref r = refdb.getRef(t);
+ assertNotNull("find branch config (" + t + ")", r);
+ assertEquals("for " + t, "refs/heads/config", r.getName());
+ assertEquals("for " + t, A, r.getObjectId());
+ }
+ }
+
+ @Test
+ public void testFirstExactRef() throws IOException {
+ update("refs/heads/A", A);
+ update("refs/tags/v1.0", v1_0);
+
+ Ref a = refdb.firstExactRef("refs/heads/A", "refs/tags/v1.0");
+ Ref one = refdb.firstExactRef("refs/tags/v1.0", "refs/heads/A");
+
+ assertEquals("refs/heads/A", a.getName());
+ assertEquals("refs/tags/v1.0", one.getName());
+
+ assertEquals(A, a.getObjectId());
+ assertEquals(v1_0, one.getObjectId());
+ }
+
+ @Test
+ public void testExactRef_DiscoversModified() throws IOException {
+ symref(HEAD, "refs/heads/master");
+ update("refs/heads/master", A);
+ assertEquals(A, refdb.exactRef(HEAD).getObjectId());
+
+ update("refs/heads/master", B);
+ assertEquals(B, refdb.exactRef(HEAD).getObjectId());
+ }
+
+ @Test
+ public void testIsNameConflicting() throws IOException {
+ update("refs/heads/a/b", A);
+ update("refs/heads/q", B);
+
+ // new references cannot replace an existing container
+ assertTrue(refdb.isNameConflicting("refs"));
+ assertTrue(refdb.isNameConflicting("refs/heads"));
+ assertTrue(refdb.isNameConflicting("refs/heads/a"));
+
+ // existing reference is not conflicting
+ assertFalse(refdb.isNameConflicting("refs/heads/a/b"));
+
+ // new references are not conflicting
+ assertFalse(refdb.isNameConflicting("refs/heads/a/d"));
+ assertFalse(refdb.isNameConflicting("refs/heads/master"));
+
+ // existing reference must not be used as a container
+ assertTrue(refdb.isNameConflicting("refs/heads/a/b/c"));
+ assertTrue(refdb.isNameConflicting("refs/heads/q/master"));
+
+ // refs/txn/ names always conflict.
+ assertTrue(refdb.isNameConflicting(refdb.getTxnCommitted()));
+ assertTrue(refdb.isNameConflicting("refs/txn/foo"));
+ }
+
+ @Test
+ public void testUpdate_RefusesRefsTxnNamespace() throws IOException {
+ ObjectId txnId = getTxnCommitted();
+
+ RefUpdate u = refdb.newUpdate("refs/txn/tmp", false);
+ u.setNewObjectId(B);
+ assertEquals(RefUpdate.Result.LOCK_FAILURE, u.update());
+ assertEquals(txnId, getTxnCommitted());
+
+ ReceiveCommand cmd = command(null, B, "refs/txn/tmp");
+ BatchRefUpdate batch = refdb.newBatchUpdate();
+ batch.addCommand(cmd);
+ batch.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE);
+
+ assertEquals(REJECTED_OTHER_REASON, cmd.getResult());
+ assertEquals(MessageFormat.format(JGitText.get().invalidRefName,
+ "refs/txn/tmp"), cmd.getMessage());
+ assertEquals(txnId, getTxnCommitted());
+ }
+
+ @Test
+ public void testUpdate_RefusesDotLockInRefName() throws IOException {
+ ObjectId txnId = getTxnCommitted();
+
+ RefUpdate u = refdb.newUpdate("refs/heads/pu.lock", false);
+ u.setNewObjectId(B);
+ assertEquals(RefUpdate.Result.REJECTED, u.update());
+ assertEquals(txnId, getTxnCommitted());
+
+ ReceiveCommand cmd = command(null, B, "refs/heads/pu.lock");
+ BatchRefUpdate batch = refdb.newBatchUpdate();
+ batch.addCommand(cmd);
+ batch.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE);
+
+ assertEquals(REJECTED_OTHER_REASON, cmd.getResult());
+ assertEquals(JGitText.get().funnyRefname, cmd.getMessage());
+ assertEquals(txnId, getTxnCommitted());
+ }
+
+ @Test
+ public void testBatchRefUpdate_NonFastForwardAborts() throws IOException {
+ update("refs/heads/master", A);
+ update("refs/heads/masters", B);
+ ObjectId txnId = getTxnCommitted();
+
+ List<ReceiveCommand> commands = Arrays.asList(
+ command(A, B, "refs/heads/master"),
+ command(B, A, "refs/heads/masters"));
+ BatchRefUpdate batchUpdate = refdb.newBatchUpdate();
+ batchUpdate.addCommand(commands);
+ batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE);
+ assertEquals(txnId, getTxnCommitted());
+
+ assertEquals(REJECTED_NONFASTFORWARD,
+ commands.get(1).getResult());
+ assertEquals(REJECTED_OTHER_REASON,
+ commands.get(0).getResult());
+ assertEquals(JGitText.get().transactionAborted,
+ commands.get(0).getMessage());
+ }
+
+ @Test
+ public void testBatchRefUpdate_ForceUpdate() throws IOException {
+ update("refs/heads/master", A);
+ update("refs/heads/masters", B);
+ ObjectId txnId = getTxnCommitted();
+
+ List<ReceiveCommand> commands = Arrays.asList(
+ command(A, B, "refs/heads/master"),
+ command(B, A, "refs/heads/masters"));
+ BatchRefUpdate batchUpdate = refdb.newBatchUpdate();
+ batchUpdate.setAllowNonFastForwards(true);
+ batchUpdate.addCommand(commands);
+ batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE);
+ assertNotEquals(txnId, getTxnCommitted());
+
+ Map<String, Ref> refs = refdb.getRefs(ALL);
+ assertEquals(OK, commands.get(0).getResult());
+ assertEquals(OK, commands.get(1).getResult());
+ assertEquals(
+ "[refs/heads/master, refs/heads/masters]",
+ refs.keySet().toString());
+ assertEquals(B.getId(), refs.get("refs/heads/master").getObjectId());
+ assertEquals(A.getId(), refs.get("refs/heads/masters").getObjectId());
+ }
+
+ @Test
+ public void testBatchRefUpdate_NonFastForwardDoesNotDoExpensiveMergeCheck()
+ throws IOException {
+ update("refs/heads/master", B);
+ ObjectId txnId = getTxnCommitted();
+
+ List<ReceiveCommand> commands = Arrays.asList(
+ command(B, A, "refs/heads/master"));
+ BatchRefUpdate batchUpdate = refdb.newBatchUpdate();
+ batchUpdate.setAllowNonFastForwards(true);
+ batchUpdate.addCommand(commands);
+ batchUpdate.execute(new RevWalk(repo) {
+ @Override
+ public boolean isMergedInto(RevCommit base, RevCommit tip) {
+ fail("isMergedInto() should not be called");
+ return false;
+ }
+ }, NullProgressMonitor.INSTANCE);
+ assertNotEquals(txnId, getTxnCommitted());
+
+ Map<String, Ref> refs = refdb.getRefs(ALL);
+ assertEquals(OK, commands.get(0).getResult());
+ assertEquals(A.getId(), refs.get("refs/heads/master").getObjectId());
+ }
+
+ @Test
+ public void testBatchRefUpdate_ConflictCausesAbort() throws IOException {
+ update("refs/heads/master", A);
+ update("refs/heads/masters", B);
+ ObjectId txnId = getTxnCommitted();
+
+ List<ReceiveCommand> commands = Arrays.asList(
+ command(A, B, "refs/heads/master"),
+ command(null, A, "refs/heads/master/x"),
+ command(null, A, "refs/heads"));
+ BatchRefUpdate batchUpdate = refdb.newBatchUpdate();
+ batchUpdate.setAllowNonFastForwards(true);
+ batchUpdate.addCommand(commands);
+ batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE);
+ assertEquals(txnId, getTxnCommitted());
+
+ assertEquals(LOCK_FAILURE, commands.get(0).getResult());
+
+ assertEquals(REJECTED_OTHER_REASON, commands.get(1).getResult());
+ assertEquals(JGitText.get().transactionAborted,
+ commands.get(1).getMessage());
+
+ assertEquals(REJECTED_OTHER_REASON, commands.get(2).getResult());
+ assertEquals(JGitText.get().transactionAborted,
+ commands.get(2).getMessage());
+ }
+
+ @Test
+ public void testBatchRefUpdate_NoConflictIfDeleted() throws IOException {
+ update("refs/heads/master", A);
+ update("refs/heads/masters", B);
+ ObjectId txnId = getTxnCommitted();
+
+ List<ReceiveCommand> commands = Arrays.asList(
+ command(A, B, "refs/heads/master"),
+ command(null, A, "refs/heads/masters/x"),
+ command(B, null, "refs/heads/masters"));
+ BatchRefUpdate batchUpdate = refdb.newBatchUpdate();
+ batchUpdate.setAllowNonFastForwards(true);
+ batchUpdate.addCommand(commands);
+ batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE);
+ assertNotEquals(txnId, getTxnCommitted());
+
+ assertEquals(OK, commands.get(0).getResult());
+ assertEquals(OK, commands.get(1).getResult());
+ assertEquals(OK, commands.get(2).getResult());
+
+ Map<String, Ref> refs = refdb.getRefs(ALL);
+ assertEquals(
+ "[refs/heads/master, refs/heads/masters/x]",
+ refs.keySet().toString());
+ assertEquals(A.getId(), refs.get("refs/heads/masters/x").getObjectId());
+ }
+
+ private ObjectId getTxnCommitted() throws IOException {
+ Ref r = bootstrap.exactRef(refdb.getTxnCommitted());
+ if (r != null && r.getObjectId() != null) {
+ return r.getObjectId();
+ }
+ return ObjectId.zeroId();
+ }
+
+ private static ReceiveCommand command(AnyObjectId a, AnyObjectId b,
+ String name) {
+ return new ReceiveCommand(
+ a != null ? a.copy() : ObjectId.zeroId(),
+ b != null ? b.copy() : ObjectId.zeroId(),
+ name);
+ }
+
+ private void symref(final String name, final String dst)
+ throws IOException {
+ commit(new Function() {
+ @Override
+ public boolean apply(ObjectReader reader, RefTree tree)
+ throws IOException {
+ Ref old = tree.exactRef(reader, name);
+ Command n = new Command(
+ old,
+ new SymbolicRef(
+ name,
+ new ObjectIdRef.Unpeeled(Ref.Storage.NEW, dst, null)));
+ return tree.apply(Collections.singleton(n));
+ }
+ });
+ }
+
+ private void update(final String name, final ObjectId id)
+ throws IOException {
+ commit(new Function() {
+ @Override
+ public boolean apply(ObjectReader reader, RefTree tree)
+ throws IOException {
+ Ref old = tree.exactRef(reader, name);
+ Command n;
+ try (RevWalk rw = new RevWalk(repo)) {
+ n = new Command(old, Command.toRef(rw, id, name, true));
+ }
+ return tree.apply(Collections.singleton(n));
+ }
+ });
+ }
+
+ interface Function {
+ boolean apply(ObjectReader reader, RefTree tree) throws IOException;
+ }
+
+ private void commit(Function fun) throws IOException {
+ try (ObjectReader reader = repo.newObjectReader();
+ ObjectInserter inserter = repo.newObjectInserter();
+ RevWalk rw = new RevWalk(reader)) {
+ RefUpdate u = bootstrap.newUpdate(refdb.getTxnCommitted(), false);
+ CommitBuilder cb = new CommitBuilder();
+ testRepo.setAuthorAndCommitter(cb);
+
+ Ref ref = bootstrap.exactRef(refdb.getTxnCommitted());
+ RefTree tree;
+ if (ref != null && ref.getObjectId() != null) {
+ tree = RefTree.read(reader, rw.parseTree(ref.getObjectId()));
+ cb.setParentId(ref.getObjectId());
+ u.setExpectedOldObjectId(ref.getObjectId());
+ } else {
+ tree = RefTree.newEmptyTree();
+ u.setExpectedOldObjectId(ObjectId.zeroId());
+ }
+
+ assertTrue(fun.apply(reader, tree));
+ cb.setTreeId(tree.writeTree(inserter));
+ u.setNewObjectId(inserter.insert(cb));
+ inserter.flush();
+ switch (u.update(rw)) {
+ case NEW:
+ case FAST_FORWARD:
+ break;
+ default:
+ fail("Expected " + u.getName() + " to update");
+ }
+ }
+ }
+
+ private class InMemRefTreeRepo extends InMemoryRepository {
+ private final RefTreeDatabase refs;
+
+ InMemRefTreeRepo(DfsRepositoryDescription repoDesc) {
+ super(repoDesc);
+ refs = new RefTreeDatabase(this, super.getRefDatabase(),
+ "refs/txn/committed");
+ RefTreeDatabaseTest.this.refdb = refs;
+ }
+
+ public RefDatabase getRefDatabase() {
+ return refs;
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeTest.java
new file mode 100644
index 0000000..8e0f38c
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeTest.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2016, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.internal.storage.reftree;
+
+import static org.eclipse.jgit.lib.Constants.HEAD;
+import static org.eclipse.jgit.lib.Constants.R_HEADS;
+import static org.eclipse.jgit.lib.Constants.R_TAGS;
+import static org.eclipse.jgit.lib.Ref.Storage.LOOSE;
+import static org.eclipse.jgit.lib.Ref.Storage.NEW;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.SymbolicRef;
+import org.eclipse.jgit.revwalk.RevBlob;
+import org.eclipse.jgit.revwalk.RevTag;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RefTreeTest {
+ private static final String R_MASTER = R_HEADS + "master";
+ private InMemoryRepository repo;
+ private TestRepository<InMemoryRepository> git;
+
+ @Before
+ public void setUp() throws IOException {
+ repo = new InMemoryRepository(new DfsRepositoryDescription("RefTree"));
+ git = new TestRepository<>(repo);
+ }
+
+ @Test
+ public void testEmptyTree() throws IOException {
+ RefTree tree = RefTree.newEmptyTree();
+ try (ObjectReader reader = repo.newObjectReader()) {
+ assertNull(HEAD, tree.exactRef(reader, HEAD));
+ assertNull("master", tree.exactRef(reader, R_MASTER));
+ }
+ }
+
+ @Test
+ public void testApplyThenReadMaster() throws Exception {
+ RefTree tree = RefTree.newEmptyTree();
+ RevBlob id = git.blob("A");
+ Command cmd = new Command(null, ref(R_MASTER, id));
+ assertTrue(tree.apply(Collections.singletonList(cmd)));
+ assertSame(NOT_ATTEMPTED, cmd.getResult());
+
+ try (ObjectReader reader = repo.newObjectReader()) {
+ Ref m = tree.exactRef(reader, R_MASTER);
+ assertNotNull(R_MASTER, m);
+ assertEquals(R_MASTER, m.getName());
+ assertEquals(id, m.getObjectId());
+ assertTrue("peeled", m.isPeeled());
+ }
+ }
+
+ @Test
+ public void testUpdateMaster() throws Exception {
+ RefTree tree = RefTree.newEmptyTree();
+ RevBlob id1 = git.blob("A");
+ Command cmd1 = new Command(null, ref(R_MASTER, id1));
+ assertTrue(tree.apply(Collections.singletonList(cmd1)));
+ assertSame(NOT_ATTEMPTED, cmd1.getResult());
+
+ RevBlob id2 = git.blob("B");
+ Command cmd2 = new Command(ref(R_MASTER, id1), ref(R_MASTER, id2));
+ assertTrue(tree.apply(Collections.singletonList(cmd2)));
+ assertSame(NOT_ATTEMPTED, cmd2.getResult());
+
+ try (ObjectReader reader = repo.newObjectReader()) {
+ Ref m = tree.exactRef(reader, R_MASTER);
+ assertNotNull(R_MASTER, m);
+ assertEquals(R_MASTER, m.getName());
+ assertEquals(id2, m.getObjectId());
+ assertTrue("peeled", m.isPeeled());
+ }
+ }
+
+ @Test
+ public void testHeadSymref() throws Exception {
+ RefTree tree = RefTree.newEmptyTree();
+ RevBlob id = git.blob("A");
+ Command cmd1 = new Command(null, ref(R_MASTER, id));
+ Command cmd2 = new Command(null, symref(HEAD, R_MASTER));
+ assertTrue(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 })));
+ assertSame(NOT_ATTEMPTED, cmd1.getResult());
+ assertSame(NOT_ATTEMPTED, cmd2.getResult());
+
+ try (ObjectReader reader = repo.newObjectReader()) {
+ Ref m = tree.exactRef(reader, HEAD);
+ assertNotNull(HEAD, m);
+ assertEquals(HEAD, m.getName());
+ assertTrue("symbolic", m.isSymbolic());
+ assertNotNull(m.getTarget());
+ assertEquals(R_MASTER, m.getTarget().getName());
+ assertEquals(id, m.getTarget().getObjectId());
+ }
+
+ // Writing flushes some buffers, re-read from blob.
+ ObjectId newId = write(tree);
+ try (ObjectReader reader = repo.newObjectReader();
+ RevWalk rw = new RevWalk(reader)) {
+ tree = RefTree.read(reader, rw.parseTree(newId));
+ Ref m = tree.exactRef(reader, HEAD);
+ assertEquals(R_MASTER, m.getTarget().getName());
+ }
+ }
+
+ @Test
+ public void testTagIsPeeled() throws Exception {
+ String name = "v1.0";
+ RefTree tree = RefTree.newEmptyTree();
+ RevBlob id = git.blob("A");
+ RevTag tag = git.tag(name, id);
+
+ String ref = R_TAGS + name;
+ Command cmd = create(ref, tag);
+ assertTrue(tree.apply(Collections.singletonList(cmd)));
+ assertSame(NOT_ATTEMPTED, cmd.getResult());
+
+ try (ObjectReader reader = repo.newObjectReader()) {
+ Ref m = tree.exactRef(reader, ref);
+ assertNotNull(ref, m);
+ assertEquals(ref, m.getName());
+ assertEquals(tag, m.getObjectId());
+ assertTrue("peeled", m.isPeeled());
+ assertEquals(id, m.getPeeledObjectId());
+ }
+ }
+
+ @Test
+ public void testApplyAlreadyExists() throws Exception {
+ RefTree tree = RefTree.newEmptyTree();
+ RevBlob a = git.blob("A");
+ Command cmd = new Command(null, ref(R_MASTER, a));
+ assertTrue(tree.apply(Collections.singletonList(cmd)));
+ ObjectId treeId = write(tree);
+
+ RevBlob b = git.blob("B");
+ Command cmd1 = create(R_MASTER, b);
+ Command cmd2 = create(R_MASTER, b);
+ assertFalse(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 })));
+ assertSame(LOCK_FAILURE, cmd1.getResult());
+ assertSame(REJECTED_OTHER_REASON, cmd2.getResult());
+ assertEquals(JGitText.get().transactionAborted, cmd2.getMessage());
+ assertEquals(treeId, write(tree));
+ }
+
+ @Test
+ public void testApplyWrongOldId() throws Exception {
+ RefTree tree = RefTree.newEmptyTree();
+ RevBlob a = git.blob("A");
+ Command cmd = new Command(null, ref(R_MASTER, a));
+ assertTrue(tree.apply(Collections.singletonList(cmd)));
+ ObjectId treeId = write(tree);
+
+ RevBlob b = git.blob("B");
+ RevBlob c = git.blob("C");
+ Command cmd1 = update(R_MASTER, b, c);
+ Command cmd2 = create(R_MASTER, b);
+ assertFalse(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 })));
+ assertSame(LOCK_FAILURE, cmd1.getResult());
+ assertSame(REJECTED_OTHER_REASON, cmd2.getResult());
+ assertEquals(JGitText.get().transactionAborted, cmd2.getMessage());
+ assertEquals(treeId, write(tree));
+ }
+
+ @Test
+ public void testApplyWrongOldIdButAlreadyCurrentIsNoOp() throws Exception {
+ RefTree tree = RefTree.newEmptyTree();
+ RevBlob a = git.blob("A");
+ Command cmd = new Command(null, ref(R_MASTER, a));
+ assertTrue(tree.apply(Collections.singletonList(cmd)));
+ ObjectId treeId = write(tree);
+
+ RevBlob b = git.blob("B");
+ cmd = update(R_MASTER, b, a);
+ assertTrue(tree.apply(Collections.singletonList(cmd)));
+ assertEquals(treeId, write(tree));
+ }
+
+ @Test
+ public void testApplyCannotCreateSubdirectory() throws Exception {
+ RefTree tree = RefTree.newEmptyTree();
+ RevBlob a = git.blob("A");
+ Command cmd = new Command(null, ref(R_MASTER, a));
+ assertTrue(tree.apply(Collections.singletonList(cmd)));
+ ObjectId treeId = write(tree);
+
+ RevBlob b = git.blob("B");
+ Command cmd1 = create(R_MASTER + "/fail", b);
+ assertFalse(tree.apply(Collections.singletonList(cmd1)));
+ assertSame(LOCK_FAILURE, cmd1.getResult());
+ assertEquals(treeId, write(tree));
+ }
+
+ @Test
+ public void testApplyCannotCreateParentRef() throws Exception {
+ RefTree tree = RefTree.newEmptyTree();
+ RevBlob a = git.blob("A");
+ Command cmd = new Command(null, ref(R_MASTER, a));
+ assertTrue(tree.apply(Collections.singletonList(cmd)));
+ ObjectId treeId = write(tree);
+
+ RevBlob b = git.blob("B");
+ Command cmd1 = create("refs/heads", b);
+ assertFalse(tree.apply(Collections.singletonList(cmd1)));
+ assertSame(LOCK_FAILURE, cmd1.getResult());
+ assertEquals(treeId, write(tree));
+ }
+
+ private static Ref ref(String name, ObjectId id) {
+ return new ObjectIdRef.PeeledNonTag(LOOSE, name, id);
+ }
+
+ private static Ref symref(String name, String dest) {
+ Ref d = new ObjectIdRef.PeeledNonTag(NEW, dest, null);
+ return new SymbolicRef(name, d);
+ }
+
+ private Command create(String name, ObjectId id)
+ throws MissingObjectException, IOException {
+ return update(name, ObjectId.zeroId(), id);
+ }
+
+ private Command update(String name, ObjectId oldId, ObjectId newId)
+ throws MissingObjectException, IOException {
+ try (RevWalk rw = new RevWalk(repo)) {
+ return new Command(rw, new ReceiveCommand(oldId, newId, name));
+ }
+ }
+
+ private ObjectId write(RefTree tree) throws IOException {
+ try (ObjectInserter ins = repo.newObjectInserter()) {
+ ObjectId id = tree.writeTree(ins);
+ ins.flush();
+ return id;
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
index fbb9eec..8b54dab 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
@@ -127,25 +127,25 @@
@Test
public void resetFromSymref() throws Exception {
repo.updateRef("HEAD").link("refs/heads/master");
- Ref head = repo.getRef("HEAD");
+ Ref head = repo.exactRef("HEAD");
RevCommit master = tr.branch("master").commit().create();
RevCommit branch = tr.branch("branch").commit().create();
RevCommit detached = tr.commit().create();
assertTrue(head.isSymbolic());
assertEquals("refs/heads/master", head.getTarget().getName());
- assertEquals(master, repo.getRef("refs/heads/master").getObjectId());
- assertEquals(branch, repo.getRef("refs/heads/branch").getObjectId());
+ assertEquals(master, repo.exactRef("refs/heads/master").getObjectId());
+ assertEquals(branch, repo.exactRef("refs/heads/branch").getObjectId());
// Reset to branches preserves symref.
tr.reset("master");
- head = repo.getRef("HEAD");
+ head = repo.exactRef("HEAD");
assertEquals(master, head.getObjectId());
assertTrue(head.isSymbolic());
assertEquals("refs/heads/master", head.getTarget().getName());
tr.reset("branch");
- head = repo.getRef("HEAD");
+ head = repo.exactRef("HEAD");
assertEquals(branch, head.getObjectId());
assertTrue(head.isSymbolic());
assertEquals("refs/heads/master", head.getTarget().getName());
@@ -153,50 +153,50 @@
// Reset to a SHA-1 detaches.
tr.reset(detached);
- head = repo.getRef("HEAD");
+ head = repo.exactRef("HEAD");
assertEquals(detached, head.getObjectId());
assertFalse(head.isSymbolic());
tr.reset(detached.name());
- head = repo.getRef("HEAD");
+ head = repo.exactRef("HEAD");
assertEquals(detached, head.getObjectId());
assertFalse(head.isSymbolic());
// Reset back to a branch remains detached.
tr.reset("master");
- head = repo.getRef("HEAD");
+ head = repo.exactRef("HEAD");
assertEquals(lastHeadBeforeDetach, head.getObjectId());
assertFalse(head.isSymbolic());
}
@Test
public void resetFromDetachedHead() throws Exception {
- Ref head = repo.getRef("HEAD");
+ Ref head = repo.exactRef("HEAD");
RevCommit master = tr.branch("master").commit().create();
RevCommit branch = tr.branch("branch").commit().create();
RevCommit detached = tr.commit().create();
assertNull(head);
- assertEquals(master, repo.getRef("refs/heads/master").getObjectId());
- assertEquals(branch, repo.getRef("refs/heads/branch").getObjectId());
+ assertEquals(master, repo.exactRef("refs/heads/master").getObjectId());
+ assertEquals(branch, repo.exactRef("refs/heads/branch").getObjectId());
tr.reset("master");
- head = repo.getRef("HEAD");
+ head = repo.exactRef("HEAD");
assertEquals(master, head.getObjectId());
assertFalse(head.isSymbolic());
tr.reset("branch");
- head = repo.getRef("HEAD");
+ head = repo.exactRef("HEAD");
assertEquals(branch, head.getObjectId());
assertFalse(head.isSymbolic());
tr.reset(detached);
- head = repo.getRef("HEAD");
+ head = repo.exactRef("HEAD");
assertEquals(detached, head.getObjectId());
assertFalse(head.isSymbolic());
tr.reset(detached.name());
- head = repo.getRef("HEAD");
+ head = repo.exactRef("HEAD");
assertEquals(detached, head.getObjectId());
assertFalse(head.isSymbolic());
}
@@ -222,7 +222,7 @@
.tick(3)
.add("bar", "fixed bar contents")
.create();
- assertEquals(amended, repo.getRef("refs/heads/master").getObjectId());
+ assertEquals(amended, repo.exactRef("refs/heads/master").getObjectId());
rw.parseBody(amended);
assertEquals(1, amended.getParentCount());
@@ -257,7 +257,7 @@
.add("foo", "fixed foo contents")
.create();
- Ref head = repo.getRef(Constants.HEAD);
+ Ref head = repo.exactRef(Constants.HEAD);
assertEquals(amended, head.getObjectId());
assertTrue(head.isSymbolic());
assertEquals("refs/heads/master", head.getTarget().getName());
@@ -291,7 +291,7 @@
public void commitToUnbornHead() throws Exception {
repo.updateRef("HEAD").link("refs/heads/master");
RevCommit root = tr.branch("HEAD").commit().create();
- Ref ref = repo.getRef(Constants.HEAD);
+ Ref ref = repo.exactRef(Constants.HEAD);
assertEquals(root, ref.getObjectId());
assertTrue(ref.isSymbolic());
assertEquals("refs/heads/master", ref.getTarget().getName());
@@ -307,16 +307,16 @@
RevCommit toPick = tr.commit()
.parent(tr.commit().create()) // Can't cherry-pick root.
.author(new PersonIdent("Cherrypick Author", "cpa@example.com",
- tr.getClock(), tr.getTimeZone()))
+ tr.getDate(), tr.getTimeZone()))
.author(new PersonIdent("Cherrypick Committer", "cpc@example.com",
- tr.getClock(), tr.getTimeZone()))
+ tr.getDate(), tr.getTimeZone()))
.message("message to cherry-pick")
.add("bar", "bar contents\n")
.create();
RevCommit result = tr.cherryPick(toPick);
rw.parseBody(result);
- Ref headRef = tr.getRepository().getRef("HEAD");
+ Ref headRef = tr.getRepository().exactRef("HEAD");
assertEquals(result, headRef.getObjectId());
assertTrue(headRef.isSymbolic());
assertEquals("refs/heads/master", headRef.getLeaf().getName());
@@ -371,7 +371,7 @@
.create();
assertNotEquals(head, toPick);
assertNull(tr.cherryPick(toPick));
- assertEquals(head, repo.getRef("HEAD").getObjectId());
+ assertEquals(head, repo.exactRef("HEAD").getObjectId());
}
private String blobAsString(AnyObjectId treeish, String path)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java
index ca3e066..59a4699 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java
@@ -338,68 +338,69 @@
*/
private void testMaliciousPath(boolean good, boolean secondCheckout,
String... path) throws GitAPIException, IOException {
- Git git = new Git(db);
- ObjectInserter newObjectInserter;
- newObjectInserter = git.getRepository().newObjectInserter();
- ObjectId blobId = newObjectInserter.insert(Constants.OBJ_BLOB,
- "data".getBytes());
- newObjectInserter = git.getRepository().newObjectInserter();
- FileMode mode = FileMode.REGULAR_FILE;
- ObjectId insertId = blobId;
- for (int i = path.length - 1; i >= 0; --i) {
- TreeFormatter treeFormatter = new TreeFormatter();
- treeFormatter.append("goodpath", mode, insertId);
- insertId = newObjectInserter.insert(treeFormatter);
- mode = FileMode.TREE;
- }
- newObjectInserter = git.getRepository().newObjectInserter();
- CommitBuilder commitBuilder = new CommitBuilder();
- commitBuilder.setAuthor(author);
- commitBuilder.setCommitter(committer);
- commitBuilder.setMessage("foo#1");
- commitBuilder.setTreeId(insertId);
- ObjectId firstCommitId = newObjectInserter.insert(commitBuilder);
-
- newObjectInserter = git.getRepository().newObjectInserter();
- mode = FileMode.REGULAR_FILE;
- insertId = blobId;
- for (int i = path.length - 1; i >= 0; --i) {
- TreeFormatter treeFormatter = new TreeFormatter();
- treeFormatter.append(path[i], mode, insertId);
- insertId = newObjectInserter.insert(treeFormatter);
- mode = FileMode.TREE;
- }
-
- // Create another commit
- commitBuilder = new CommitBuilder();
- commitBuilder.setAuthor(author);
- commitBuilder.setCommitter(committer);
- commitBuilder.setMessage("foo#2");
- commitBuilder.setTreeId(insertId);
- commitBuilder.setParentId(firstCommitId);
- ObjectId commitId = newObjectInserter.insert(commitBuilder);
-
- RevWalk revWalk = new RevWalk(git.getRepository());
- if (!secondCheckout)
- git.checkout().setStartPoint(revWalk.parseCommit(firstCommitId))
- .setName("refs/heads/master").setCreateBranch(true).call();
- try {
- if (secondCheckout) {
- git.checkout().setStartPoint(revWalk.parseCommit(commitId))
- .setName("refs/heads/master").setCreateBranch(true)
- .call();
- } else {
- git.branchCreate().setName("refs/heads/next")
- .setStartPoint(commitId.name()).call();
- git.checkout().setName("refs/heads/next")
- .call();
+ try (Git git = new Git(db);
+ RevWalk revWalk = new RevWalk(git.getRepository())) {
+ ObjectInserter newObjectInserter;
+ newObjectInserter = git.getRepository().newObjectInserter();
+ ObjectId blobId = newObjectInserter.insert(Constants.OBJ_BLOB,
+ "data".getBytes());
+ newObjectInserter = git.getRepository().newObjectInserter();
+ FileMode mode = FileMode.REGULAR_FILE;
+ ObjectId insertId = blobId;
+ for (int i = path.length - 1; i >= 0; --i) {
+ TreeFormatter treeFormatter = new TreeFormatter();
+ treeFormatter.append("goodpath", mode, insertId);
+ insertId = newObjectInserter.insert(treeFormatter);
+ mode = FileMode.TREE;
}
- if (!good)
- fail("Checkout of Tree " + Arrays.asList(path) + " should fail");
- } catch (InvalidPathException e) {
- if (good)
- throw e;
- assertTrue(e.getMessage().startsWith("Invalid path"));
+ newObjectInserter = git.getRepository().newObjectInserter();
+ CommitBuilder commitBuilder = new CommitBuilder();
+ commitBuilder.setAuthor(author);
+ commitBuilder.setCommitter(committer);
+ commitBuilder.setMessage("foo#1");
+ commitBuilder.setTreeId(insertId);
+ ObjectId firstCommitId = newObjectInserter.insert(commitBuilder);
+
+ newObjectInserter = git.getRepository().newObjectInserter();
+ mode = FileMode.REGULAR_FILE;
+ insertId = blobId;
+ for (int i = path.length - 1; i >= 0; --i) {
+ TreeFormatter treeFormatter = new TreeFormatter();
+ treeFormatter.append(path[i], mode, insertId);
+ insertId = newObjectInserter.insert(treeFormatter);
+ mode = FileMode.TREE;
+ }
+
+ // Create another commit
+ commitBuilder = new CommitBuilder();
+ commitBuilder.setAuthor(author);
+ commitBuilder.setCommitter(committer);
+ commitBuilder.setMessage("foo#2");
+ commitBuilder.setTreeId(insertId);
+ commitBuilder.setParentId(firstCommitId);
+ ObjectId commitId = newObjectInserter.insert(commitBuilder);
+
+ if (!secondCheckout)
+ git.checkout().setStartPoint(revWalk.parseCommit(firstCommitId))
+ .setName("refs/heads/master").setCreateBranch(true).call();
+ try {
+ if (secondCheckout) {
+ git.checkout().setStartPoint(revWalk.parseCommit(commitId))
+ .setName("refs/heads/master").setCreateBranch(true)
+ .call();
+ } else {
+ git.branchCreate().setName("refs/heads/next")
+ .setStartPoint(commitId.name()).call();
+ git.checkout().setName("refs/heads/next")
+ .call();
+ }
+ if (!good)
+ fail("Checkout of Tree " + Arrays.asList(path) + " should fail");
+ } catch (InvalidPathException e) {
+ if (good)
+ throw e;
+ assertTrue(e.getMessage().startsWith("Invalid path"));
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
index 7a115e1..c1b882a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
@@ -78,6 +78,8 @@
import org.eclipse.jgit.treewalk.FileTreeIterator;
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 DirCacheCheckoutTest extends RepositoryTestCase {
@@ -111,7 +113,7 @@
return dco.getRemoved();
}
- private Map<String, ObjectId> getUpdated() {
+ private Map<String, String> getUpdated() {
return dco.getUpdated();
}
@@ -138,52 +140,53 @@
@Test
public void testResetHard() throws IOException, NoFilepatternException,
GitAPIException {
- Git git = new Git(db);
- writeTrashFile("f", "f()");
- writeTrashFile("D/g", "g()");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("inital").call();
- assertIndex(mkmap("f", "f()", "D/g", "g()"));
+ try (Git git = new Git(db)) {
+ writeTrashFile("f", "f()");
+ writeTrashFile("D/g", "g()");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("inital").call();
+ assertIndex(mkmap("f", "f()", "D/g", "g()"));
- git.branchCreate().setName("topic").call();
+ git.branchCreate().setName("topic").call();
- writeTrashFile("f", "f()\nmaster");
- writeTrashFile("D/g", "g()\ng2()");
- writeTrashFile("E/h", "h()");
- git.add().addFilepattern(".").call();
- RevCommit master = git.commit().setMessage("master-1").call();
- assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()"));
+ writeTrashFile("f", "f()\nmaster");
+ writeTrashFile("D/g", "g()\ng2()");
+ writeTrashFile("E/h", "h()");
+ git.add().addFilepattern(".").call();
+ RevCommit master = git.commit().setMessage("master-1").call();
+ assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()"));
- checkoutBranch("refs/heads/topic");
- assertIndex(mkmap("f", "f()", "D/g", "g()"));
+ checkoutBranch("refs/heads/topic");
+ assertIndex(mkmap("f", "f()", "D/g", "g()"));
- writeTrashFile("f", "f()\nside");
- assertTrue(new File(db.getWorkTree(), "D/g").delete());
- writeTrashFile("G/i", "i()");
- git.add().addFilepattern(".").call();
- git.add().addFilepattern(".").setUpdate(true).call();
- RevCommit topic = git.commit().setMessage("topic-1").call();
- assertIndex(mkmap("f", "f()\nside", "G/i", "i()"));
+ writeTrashFile("f", "f()\nside");
+ assertTrue(new File(db.getWorkTree(), "D/g").delete());
+ writeTrashFile("G/i", "i()");
+ git.add().addFilepattern(".").call();
+ git.add().addFilepattern(".").setUpdate(true).call();
+ RevCommit topic = git.commit().setMessage("topic-1").call();
+ assertIndex(mkmap("f", "f()\nside", "G/i", "i()"));
- writeTrashFile("untracked", "untracked");
+ writeTrashFile("untracked", "untracked");
- resetHard(master);
- assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()"));
- resetHard(topic);
- assertIndex(mkmap("f", "f()\nside", "G/i", "i()"));
- assertWorkDir(mkmap("f", "f()\nside", "G/i", "i()", "untracked",
- "untracked"));
+ resetHard(master);
+ assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()"));
+ resetHard(topic);
+ assertIndex(mkmap("f", "f()\nside", "G/i", "i()"));
+ assertWorkDir(mkmap("f", "f()\nside", "G/i", "i()", "untracked",
+ "untracked"));
- assertEquals(MergeStatus.CONFLICTING, git.merge().include(master)
- .call().getMergeStatus());
- assertEquals(
- "[D/g, mode:100644, stage:1][D/g, mode:100644, stage:3][E/h, mode:100644][G/i, mode:100644][f, mode:100644, stage:1][f, mode:100644, stage:2][f, mode:100644, stage:3]",
- indexState(0));
+ assertEquals(MergeStatus.CONFLICTING, git.merge().include(master)
+ .call().getMergeStatus());
+ assertEquals(
+ "[D/g, mode:100644, stage:1][D/g, mode:100644, stage:3][E/h, mode:100644][G/i, mode:100644][f, mode:100644, stage:1][f, mode:100644, stage:2][f, mode:100644, stage:3]",
+ indexState(0));
- resetHard(master);
- assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()"));
- assertWorkDir(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h",
- "h()", "untracked", "untracked"));
+ resetHard(master);
+ assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()"));
+ assertWorkDir(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h",
+ "h()", "untracked", "untracked"));
+ }
}
/**
@@ -198,21 +201,22 @@
@Test
public void testResetHardFromIndexEntryWithoutFileToTreeWithoutFile()
throws Exception {
- Git git = new Git(db);
- writeTrashFile("x", "x");
- git.add().addFilepattern("x").call();
- RevCommit id1 = git.commit().setMessage("c1").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("x", "x");
+ git.add().addFilepattern("x").call();
+ RevCommit id1 = git.commit().setMessage("c1").call();
- writeTrashFile("f/g", "f/g");
- git.rm().addFilepattern("x").call();
- git.add().addFilepattern("f/g").call();
- git.commit().setMessage("c2").call();
- deleteTrashFile("f/g");
- deleteTrashFile("f");
+ writeTrashFile("f/g", "f/g");
+ git.rm().addFilepattern("x").call();
+ git.add().addFilepattern("f/g").call();
+ git.commit().setMessage("c2").call();
+ deleteTrashFile("f/g");
+ deleteTrashFile("f");
- // The actual test
- git.reset().setMode(ResetType.HARD).setRef(id1.getName()).call();
- assertIndex(mkmap("x", "x"));
+ // The actual test
+ git.reset().setMode(ResetType.HARD).setRef(id1.getName()).call();
+ assertIndex(mkmap("x", "x"));
+ }
}
/**
@@ -222,14 +226,14 @@
*/
@Test
public void testInitialCheckout() throws Exception {
- Git git = new Git(db);
-
- TestRepository<Repository> db_t = new TestRepository<Repository>(db);
- BranchBuilder master = db_t.branch("master");
- master.commit().add("f", "1").message("m0").create();
- assertFalse(new File(db.getWorkTree(), "f").exists());
- git.checkout().setName("master").call();
- assertTrue(new File(db.getWorkTree(), "f").exists());
+ try (Git git = new Git(db)) {
+ TestRepository<Repository> db_t = new TestRepository<Repository>(db);
+ BranchBuilder master = db_t.branch("master");
+ master.commit().add("f", "1").message("m0").create();
+ assertFalse(new File(db.getWorkTree(), "f").exists());
+ git.checkout().setName("master").call();
+ assertTrue(new File(db.getWorkTree(), "f").exists());
+ }
}
private DirCacheCheckout resetHard(RevCommit commit)
@@ -266,8 +270,6 @@
@Test
public void testRules1thru3_NoIndexEntry() throws IOException {
ObjectId head = buildTree(mk("foo"));
- TreeWalk tw = TreeWalk.forPath(db, "foo", head);
- ObjectId objectId = tw.getObjectId(0);
ObjectId merge = db.newObjectInserter().insert(Constants.OBJ_TREE,
new byte[0]);
@@ -277,10 +279,9 @@
prescanTwoTrees(merge, head);
- assertEquals(objectId, getUpdated().get("foo"));
+ assertTrue(getUpdated().containsKey("foo"));
merge = buildTree(mkmap("foo", "a"));
- tw = TreeWalk.forPath(db, "foo", merge);
prescanTwoTrees(head, merge);
@@ -923,6 +924,301 @@
}
@Test
+ public void testCheckoutChangeLinkToEmptyDir() throws Exception {
+ Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
+ String fname = "was_file";
+ Git git = Git.wrap(db);
+
+ // Add a file
+ writeTrashFile(fname, "a");
+ git.add().addFilepattern(fname).call();
+
+ // Add a link to file
+ String linkName = "link";
+ File link = writeLink(linkName, fname).toFile();
+ git.add().addFilepattern(linkName).call();
+ git.commit().setMessage("Added file and link").call();
+
+ assertWorkDir(mkmap(linkName, "a", fname, "a"));
+
+ // replace link with empty directory
+ FileUtils.delete(link);
+ FileUtils.mkdir(link);
+ assertTrue("Link must be a directory now", link.isDirectory());
+
+ // modify file
+ writeTrashFile(fname, "b");
+ assertWorkDir(mkmap(fname, "b", linkName, "/"));
+
+ // revert both paths to HEAD state
+ git.checkout().setStartPoint(Constants.HEAD)
+ .addPath(fname).addPath(linkName).call();
+
+ assertWorkDir(mkmap(fname, "a", linkName, "a"));
+
+ Status st = git.status().call();
+ assertTrue(st.isClean());
+ }
+
+ @Test
+ public void testCheckoutChangeLinkToEmptyDirs() throws Exception {
+ Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
+ String fname = "was_file";
+ Git git = Git.wrap(db);
+
+ // Add a file
+ writeTrashFile(fname, "a");
+ git.add().addFilepattern(fname).call();
+
+ // Add a link to file
+ String linkName = "link";
+ File link = writeLink(linkName, fname).toFile();
+ git.add().addFilepattern(linkName).call();
+ git.commit().setMessage("Added file and link").call();
+
+ assertWorkDir(mkmap(linkName, "a", fname, "a"));
+
+ // replace link with directory containing only directories, no files
+ FileUtils.delete(link);
+ FileUtils.mkdirs(new File(link, "dummyDir"));
+ assertTrue("Link must be a directory now", link.isDirectory());
+
+ assertFalse("Must not delete non empty directory", link.delete());
+
+ // modify file
+ writeTrashFile(fname, "b");
+ assertWorkDir(mkmap(fname, "b", linkName + "/dummyDir", "/"));
+
+ // revert both paths to HEAD state
+ git.checkout().setStartPoint(Constants.HEAD)
+ .addPath(fname).addPath(linkName).call();
+
+ assertWorkDir(mkmap(fname, "a", linkName, "a"));
+
+ Status st = git.status().call();
+ assertTrue(st.isClean());
+ }
+
+ @Test
+ public void testCheckoutChangeLinkToNonEmptyDirs() throws Exception {
+ Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
+ String fname = "file";
+ Git git = Git.wrap(db);
+
+ // Add a file
+ writeTrashFile(fname, "a");
+ git.add().addFilepattern(fname).call();
+
+ // Add a link to file
+ String linkName = "link";
+ File link = writeLink(linkName, fname).toFile();
+ git.add().addFilepattern(linkName).call();
+ git.commit().setMessage("Added file and link").call();
+
+ assertWorkDir(mkmap(linkName, "a", fname, "a"));
+
+ // replace link with directory containing only directories, no files
+ FileUtils.delete(link);
+
+ // create but do not add a file in the new directory to the index
+ writeTrashFile(linkName + "/dir1", "file1", "c");
+
+ // create but do not add a file in the new directory to the index
+ writeTrashFile(linkName + "/dir2", "file2", "d");
+
+ assertTrue("File must be a directory now", link.isDirectory());
+ assertFalse("Must not delete non empty directory", link.delete());
+
+ // 2 extra files are created
+ assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c",
+ linkName + "/dir2/file2", "d"));
+
+ // revert path to HEAD state
+ git.checkout().setStartPoint(Constants.HEAD).addPath(linkName).call();
+
+ // expect only the one added to the index
+ assertWorkDir(mkmap(linkName, "a", fname, "a"));
+
+ Status st = git.status().call();
+ assertTrue(st.isClean());
+ }
+
+ @Test
+ public void testCheckoutChangeLinkToNonEmptyDirsAndNewIndexEntry()
+ throws Exception {
+ Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
+ String fname = "file";
+ Git git = Git.wrap(db);
+
+ // Add a file
+ writeTrashFile(fname, "a");
+ git.add().addFilepattern(fname).call();
+
+ // Add a link to file
+ String linkName = "link";
+ File link = writeLink(linkName, fname).toFile();
+ git.add().addFilepattern(linkName).call();
+ git.commit().setMessage("Added file and link").call();
+
+ assertWorkDir(mkmap(linkName, "a", fname, "a"));
+
+ // replace link with directory containing only directories, no files
+ FileUtils.delete(link);
+
+ // create and add a file in the new directory to the index
+ writeTrashFile(linkName + "/dir1", "file1", "c");
+ git.add().addFilepattern(linkName + "/dir1/file1").call();
+
+ // create but do not add a file in the new directory to the index
+ writeTrashFile(linkName + "/dir2", "file2", "d");
+
+ assertTrue("File must be a directory now", link.isDirectory());
+ assertFalse("Must not delete non empty directory", link.delete());
+
+ // 2 extra files are created
+ assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c",
+ linkName + "/dir2/file2", "d"));
+
+ // revert path to HEAD state
+ git.checkout().setStartPoint(Constants.HEAD).addPath(linkName).call();
+
+ // original file and link
+ assertWorkDir(mkmap(linkName, "a", fname, "a"));
+
+ Status st = git.status().call();
+ assertTrue(st.isClean());
+ }
+
+ @Test
+ public void testCheckoutChangeFileToEmptyDir() throws Exception {
+ String fname = "was_file";
+ Git git = Git.wrap(db);
+
+ // Add a file
+ File file = writeTrashFile(fname, "a");
+ git.add().addFilepattern(fname).call();
+ git.commit().setMessage("Added file").call();
+
+ // replace file with empty directory
+ FileUtils.delete(file);
+ FileUtils.mkdir(file);
+ assertTrue("File must be a directory now", file.isDirectory());
+
+ assertWorkDir(mkmap(fname, "/"));
+
+ // revert path to HEAD state
+ git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call();
+
+ assertWorkDir(mkmap(fname, "a"));
+
+ Status st = git.status().call();
+ assertTrue(st.isClean());
+ }
+
+ @Test
+ public void testCheckoutChangeFileToEmptyDirs() throws Exception {
+ String fname = "was_file";
+ Git git = Git.wrap(db);
+
+ // Add a file
+ File file = writeTrashFile(fname, "a");
+ git.add().addFilepattern(fname).call();
+ git.commit().setMessage("Added file").call();
+
+ // replace file with directory containing only directories, no files
+ FileUtils.delete(file);
+ FileUtils.mkdirs(new File(file, "dummyDir"));
+ assertTrue("File must be a directory now", file.isDirectory());
+ assertFalse("Must not delete non empty directory", file.delete());
+
+ assertWorkDir(mkmap(fname + "/dummyDir", "/"));
+
+ // revert path to HEAD state
+ git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call();
+
+ assertWorkDir(mkmap(fname, "a"));
+
+ Status st = git.status().call();
+ assertTrue(st.isClean());
+ }
+
+ @Test
+ public void testCheckoutChangeFileToNonEmptyDirs() throws Exception {
+ String fname = "was_file";
+ Git git = Git.wrap(db);
+
+ // Add a file
+ File file = writeTrashFile(fname, "a");
+ git.add().addFilepattern(fname).call();
+ git.commit().setMessage("Added file").call();
+
+ assertWorkDir(mkmap(fname, "a"));
+
+ // replace file with directory containing only directories, no files
+ FileUtils.delete(file);
+
+ // create but do not add a file in the new directory to the index
+ writeTrashFile(fname + "/dir1", "file1", "c");
+
+ // create but do not add a file in the new directory to the index
+ writeTrashFile(fname + "/dir2", "file2", "d");
+
+ assertTrue("File must be a directory now", file.isDirectory());
+ assertFalse("Must not delete non empty directory", file.delete());
+
+ // 2 extra files are created
+ assertWorkDir(
+ mkmap(fname + "/dir1/file1", "c", fname + "/dir2/file2", "d"));
+
+ // revert path to HEAD state
+ git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call();
+
+ // expect only the one added to the index
+ assertWorkDir(mkmap(fname, "a"));
+
+ Status st = git.status().call();
+ assertTrue(st.isClean());
+ }
+
+ @Test
+ public void testCheckoutChangeFileToNonEmptyDirsAndNewIndexEntry()
+ throws Exception {
+ String fname = "was_file";
+ Git git = Git.wrap(db);
+
+ // Add a file
+ File file = writeTrashFile(fname, "a");
+ git.add().addFilepattern(fname).call();
+ git.commit().setMessage("Added file").call();
+
+ assertWorkDir(mkmap(fname, "a"));
+
+ // replace file with directory containing only directories, no files
+ FileUtils.delete(file);
+
+ // create and add a file in the new directory to the index
+ writeTrashFile(fname + "/dir", "file1", "c");
+ git.add().addFilepattern(fname + "/dir/file1").call();
+
+ // create but do not add a file in the new directory to the index
+ writeTrashFile(fname + "/dir", "file2", "d");
+
+ assertTrue("File must be a directory now", file.isDirectory());
+ assertFalse("Must not delete non empty directory", file.delete());
+
+ // 2 extra files are created
+ assertWorkDir(
+ mkmap(fname + "/dir/file1", "c", fname + "/dir/file2", "d"));
+
+ // revert path to HEAD state
+ git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call();
+ assertWorkDir(mkmap(fname, "a"));
+
+ Status st = git.status().call();
+ assertTrue(st.isClean());
+ }
+
+ @Test
public void testCheckoutOutChangesAutoCRLFfalse() throws IOException {
setupCase(mk("foo"), mkmap("foo/bar", "foo\nbar"), mk("foo"));
checkout();
@@ -983,6 +1279,14 @@
}
@Test
+ public void testDontOverwriteEmptyFolder() throws IOException {
+ setupCase(mk("foo"), mk("foo"), mk("foo"));
+ FileUtils.mkdir(new File(db.getWorkTree(), "d"));
+ checkout();
+ assertWorkDir(mkmap("foo", "foo", "d", "/"));
+ }
+
+ @Test
public void testOverwriteUntrackedIgnoredFile() throws IOException,
GitAPIException {
String fname="file.txt";
@@ -1015,6 +1319,103 @@
}
@Test
+ public void testOverwriteUntrackedFileModeChange()
+ throws IOException, GitAPIException {
+ String fname = "file.txt";
+ Git git = Git.wrap(db);
+
+ // Add a file
+ File file = writeTrashFile(fname, "a");
+ git.add().addFilepattern(fname).call();
+ git.commit().setMessage("create file").call();
+ assertWorkDir(mkmap(fname, "a"));
+
+ // Create branch
+ git.branchCreate().setName("side").call();
+
+ // Switch branches
+ git.checkout().setName("side").call();
+
+ // replace file with directory containing files
+ FileUtils.delete(file);
+
+ // create and add a file in the new directory to the index
+ writeTrashFile(fname + "/dir1", "file1", "c");
+ git.add().addFilepattern(fname + "/dir1/file1").call();
+
+ // create but do not add a file in the new directory to the index
+ writeTrashFile(fname + "/dir2", "file2", "d");
+
+ assertTrue("File must be a directory now", file.isDirectory());
+ assertFalse("Must not delete non empty directory", file.delete());
+
+ // 2 extra files are created
+ assertWorkDir(
+ mkmap(fname + "/dir1/file1", "c", fname + "/dir2/file2", "d"));
+
+ try {
+ git.checkout().setName("master").call();
+ fail("did not throw exception");
+ } catch (Exception e) {
+ // 2 extra files are still there
+ assertWorkDir(mkmap(fname + "/dir1/file1", "c",
+ fname + "/dir2/file2", "d"));
+ }
+ }
+
+ @Test
+ public void testOverwriteUntrackedLinkModeChange()
+ throws Exception {
+ Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
+ String fname = "file.txt";
+ Git git = Git.wrap(db);
+
+ // Add a file
+ writeTrashFile(fname, "a");
+ git.add().addFilepattern(fname).call();
+
+ // Add a link to file
+ String linkName = "link";
+ File link = writeLink(linkName, fname).toFile();
+ git.add().addFilepattern(linkName).call();
+ git.commit().setMessage("Added file and link").call();
+
+ assertWorkDir(mkmap(linkName, "a", fname, "a"));
+
+ // Create branch
+ git.branchCreate().setName("side").call();
+
+ // Switch branches
+ git.checkout().setName("side").call();
+
+ // replace link with directory containing files
+ FileUtils.delete(link);
+
+ // create and add a file in the new directory to the index
+ writeTrashFile(linkName + "/dir1", "file1", "c");
+ git.add().addFilepattern(linkName + "/dir1/file1").call();
+
+ // create but do not add a file in the new directory to the index
+ writeTrashFile(linkName + "/dir2", "file2", "d");
+
+ assertTrue("Link must be a directory now", link.isDirectory());
+ assertFalse("Must not delete non empty directory", link.delete());
+
+ // 2 extra files are created
+ assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c",
+ linkName + "/dir2/file2", "d"));
+
+ try {
+ git.checkout().setName("master").call();
+ fail("did not throw exception");
+ } catch (Exception e) {
+ // 2 extra files are still there
+ assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c",
+ linkName + "/dir2/file2", "d"));
+ }
+ }
+
+ @Test
public void testFileModeChangeWithNoContentChangeUpdate() throws Exception {
if (!FS.DETECTED.supportsExecute())
return;
@@ -1210,39 +1611,50 @@
assertNotNull(git.checkout().setName(Constants.MASTER).call());
}
- public void assertWorkDir(HashMap<String, String> i) throws CorruptObjectException,
+ public void assertWorkDir(Map<String, String> i)
+ throws CorruptObjectException,
IOException {
- TreeWalk walk = new TreeWalk(db);
- walk.setRecursive(true);
- walk.addTree(new FileTreeIterator(db));
- String expectedValue;
- String path;
- int nrFiles = 0;
- FileTreeIterator ft;
- while (walk.next()) {
- ft = walk.getTree(0, FileTreeIterator.class);
- path = ft.getEntryPathString();
- expectedValue = i.get(path);
- assertNotNull("found unexpected file for path " + path
- + " in workdir", expectedValue);
- File file = new File(db.getWorkTree(), path);
- assertTrue(file.exists());
- if (file.isFile()) {
- FileInputStream is = new FileInputStream(file);
- byte[] buffer = new byte[(int) file.length()];
- int offset = 0;
- int numRead = 0;
- while (offset < buffer.length
- && (numRead = is.read(buffer, offset, buffer.length
- - offset)) >= 0) {
- offset += numRead;
+ try (TreeWalk walk = new TreeWalk(db)) {
+ walk.setRecursive(false);
+ walk.addTree(new FileTreeIterator(db));
+ String expectedValue;
+ String path;
+ int nrFiles = 0;
+ FileTreeIterator ft;
+ while (walk.next()) {
+ ft = walk.getTree(0, FileTreeIterator.class);
+ path = ft.getEntryPathString();
+ expectedValue = i.get(path);
+ File file = new File(db.getWorkTree(), path);
+ assertTrue(file.exists());
+ if (file.isFile()) {
+ assertNotNull("found unexpected file for path " + path
+ + " in workdir", expectedValue);
+ FileInputStream is = new FileInputStream(file);
+ byte[] buffer = new byte[(int) file.length()];
+ int offset = 0;
+ int numRead = 0;
+ while (offset < buffer.length
+ && (numRead = is.read(buffer, offset, buffer.length
+ - offset)) >= 0) {
+ offset += numRead;
+ }
+ is.close();
+ assertArrayEquals("unexpected content for path " + path
+ + " in workDir. ", buffer, i.get(path).getBytes());
+ nrFiles++;
+ } else if (file.isDirectory()) {
+ if (file.list().length == 0) {
+ assertEquals("found unexpected empty folder for path "
+ + path + " in workDir. ", "/", i.get(path));
+ nrFiles++;
+ }
}
- is.close();
- assertArrayEquals("unexpected content for path " + path
- + " in workDir. ", buffer, i.get(path).getBytes());
- nrFiles++;
+ if (walk.isSubtree()) {
+ walk.enterSubtree();
+ }
}
+ assertEquals("WorkDir has not the right size.", i.size(), nrFiles);
}
- assertEquals("WorkDir has not the right size.", i.size(), nrFiles);
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java
index 863d79d..3259f62 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java
@@ -87,7 +87,7 @@
.call();
submodule_db = (FileRepository) Git.wrap(db).submoduleAdd()
- .setPath("submodule")
+ .setPath("modules/submodule")
.setURI(submoduleStandalone.getDirectory().toURI().toString())
.call();
submoduleStandalone.close();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
index a5cd7b5..733f166 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
@@ -77,7 +77,6 @@
import org.eclipse.jgit.util.IO;
import org.junit.Test;
-@SuppressWarnings("deprecation")
public class IndexDiffTest extends RepositoryTestCase {
static PathEdit add(final Repository db, final File workdir,
@@ -99,8 +98,7 @@
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 +106,7 @@
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 +122,16 @@
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"));
@@ -152,21 +148,22 @@
writeTrashFile("file2", "file2");
writeTrashFile("dir/file3", "dir/file3");
- Git git = new Git(db);
- git.add().addFilepattern("file2").addFilepattern("dir/file3").call();
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("file2").addFilepattern("dir/file3").call();
+ }
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"));
- Tree tree2 = (Tree) tree.findTreeMember("dir");
- tree2.setId(insertTree(tree2));
- tree.setId(insertTree(tree));
+ TreeFormatter tree = new TreeFormatter();
+ tree.append("dir", FileMode.TREE, insertTree(dir));
+ tree.append("file2", FileMode.REGULAR_FILE, ObjectId.fromString("0123456789012345678901234567890123456789"));
+ 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.getChanged().size());
assertTrue(diff.getChanged().contains("file2"));
@@ -181,31 +178,31 @@
@Test
public void testConflicting() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ // create side branch with two modifications
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ writeTrashFile("a", "1\na(side)\n3\n");
+ writeTrashFile("b", "1\nb\n3\n(side)");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- // create side branch with two modifications
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
- writeTrashFile("a", "1\na(side)\n3\n");
- writeTrashFile("b", "1\nb\n3\n(side)");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ // update a on master to generate conflict
+ checkoutBranch("refs/heads/master");
+ writeTrashFile("a", "1\na(main)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("main").call();
- // update a on master to generate conflict
- checkoutBranch("refs/heads/master");
- writeTrashFile("a", "1\na(main)\n3\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("main").call();
-
- // merge side with master
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ // merge side with master
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ }
FileTreeIterator iterator = new FileTreeIterator(db);
IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
@@ -225,29 +222,29 @@
@Test
public void testConflictingDeletedAndModified() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- writeTrashFile("b", "1\nb\n3\n");
- git.add().addFilepattern("a").addFilepattern("b").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ // create side branch and delete "a"
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ git.rm().addFilepattern("a").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- // create side branch and delete "a"
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
- git.rm().addFilepattern("a").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ // update a on master to generate conflict
+ checkoutBranch("refs/heads/master");
+ writeTrashFile("a", "1\na(main)\n3\n");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("main").call();
- // update a on master to generate conflict
- checkoutBranch("refs/heads/master");
- writeTrashFile("a", "1\na(main)\n3\n");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("main").call();
-
- // merge side with master
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ // merge side with master
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ }
FileTreeIterator iterator = new FileTreeIterator(db);
IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
@@ -266,28 +263,28 @@
@Test
public void testConflictingFromMultipleCreations() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
- writeTrashFile("a", "1\na\n3\n");
- git.add().addFilepattern("a").call();
- RevCommit initialCommit = git.commit().setMessage("initial").call();
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
- createBranch(initialCommit, "refs/heads/side");
- checkoutBranch("refs/heads/side");
+ writeTrashFile("b", "1\nb(side)\n3\n");
+ git.add().addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
- writeTrashFile("b", "1\nb(side)\n3\n");
- git.add().addFilepattern("b").call();
- RevCommit secondCommit = git.commit().setMessage("side").call();
+ checkoutBranch("refs/heads/master");
- checkoutBranch("refs/heads/master");
+ writeTrashFile("b", "1\nb(main)\n3\n");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("main").call();
- writeTrashFile("b", "1\nb(main)\n3\n");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("main").call();
-
- MergeResult result = git.merge().include(secondCommit.getId())
- .setStrategy(MergeStrategy.RESOLVE).call();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ }
FileTreeIterator iterator = new FileTreeIterator(db);
IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
@@ -308,23 +305,23 @@
writeTrashFile("a.c", "a.c");
writeTrashFile("a=c", "a=c");
writeTrashFile("a=d", "a=d");
- Git git = new Git(db);
- git.add().addFilepattern("a.b").call();
- git.add().addFilepattern("a.c").call();
- git.add().addFilepattern("a=c").call();
- git.add().addFilepattern("a=d").call();
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("a.b").call();
+ git.add().addFilepattern("a.c").call();
+ 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());
@@ -343,7 +340,6 @@
*/
@Test
public void testUnchangedComplex() throws IOException, GitAPIException {
- Git git = new Git(db);
writeTrashFile("a.b", "a.b");
writeTrashFile("a.c", "a.c");
writeTrashFile("a/b.b/b", "a/b.b/b");
@@ -351,29 +347,34 @@
writeTrashFile("a/c", "a/c");
writeTrashFile("a=c", "a=c");
writeTrashFile("a=d", "a=d");
- git.add().addFilepattern("a.b").addFilepattern("a.c")
- .addFilepattern("a/b.b/b").addFilepattern("a/b")
- .addFilepattern("a/c").addFilepattern("a=c")
- .addFilepattern("a=d").call();
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern("a.b").addFilepattern("a.c")
+ .addFilepattern("a/b.b/b").addFilepattern("a/b")
+ .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"));
+ TreeFormatter bb = new TreeFormatter();
+ bb.append("b", FileMode.REGULAR_FILE, ObjectId.fromString("8d840bd4e2f3a48ff417c8e927d94996849933fd"));
- 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 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 +384,9 @@
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;
}
@@ -399,11 +400,12 @@
*/
@Test
public void testRemovedUntracked() throws Exception{
- Git git = new Git(db);
String path = "file";
- writeTrashFile(path, "content");
- git.add().addFilepattern(path).call();
- git.commit().setMessage("commit").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile(path, "content");
+ git.add().addFilepattern(path).call();
+ git.commit().setMessage("commit").call();
+ }
removeFromIndex(path);
FileTreeIterator iterator = new FileTreeIterator(db);
IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
@@ -419,51 +421,51 @@
*/
@Test
public void testUntrackedFolders() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ IndexDiff diff = new IndexDiff(db, Constants.HEAD,
+ new FileTreeIterator(db));
+ diff.diff();
+ assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders());
- IndexDiff diff = new IndexDiff(db, Constants.HEAD,
- new FileTreeIterator(db));
- diff.diff();
- assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders());
+ writeTrashFile("readme", "");
+ writeTrashFile("src/com/A.java", "");
+ writeTrashFile("src/com/B.java", "");
+ writeTrashFile("src/org/A.java", "");
+ writeTrashFile("src/org/B.java", "");
+ writeTrashFile("target/com/A.java", "");
+ writeTrashFile("target/com/B.java", "");
+ writeTrashFile("target/org/A.java", "");
+ writeTrashFile("target/org/B.java", "");
- writeTrashFile("readme", "");
- writeTrashFile("src/com/A.java", "");
- writeTrashFile("src/com/B.java", "");
- writeTrashFile("src/org/A.java", "");
- writeTrashFile("src/org/B.java", "");
- writeTrashFile("target/com/A.java", "");
- writeTrashFile("target/com/B.java", "");
- writeTrashFile("target/org/A.java", "");
- writeTrashFile("target/org/B.java", "");
+ git.add().addFilepattern("src").addFilepattern("readme").call();
+ git.commit().setMessage("initial").call();
- git.add().addFilepattern("src").addFilepattern("readme").call();
- git.commit().setMessage("initial").call();
+ diff = new IndexDiff(db, Constants.HEAD,
+ new FileTreeIterator(db));
+ diff.diff();
+ assertEquals(new HashSet<String>(Arrays.asList("target")),
+ diff.getUntrackedFolders());
- diff = new IndexDiff(db, Constants.HEAD,
- new FileTreeIterator(db));
- diff.diff();
- assertEquals(new HashSet<String>(Arrays.asList("target")),
- diff.getUntrackedFolders());
+ writeTrashFile("src/tst/A.java", "");
+ writeTrashFile("src/tst/B.java", "");
- writeTrashFile("src/tst/A.java", "");
- writeTrashFile("src/tst/B.java", "");
+ diff = new IndexDiff(db, Constants.HEAD, new FileTreeIterator(db));
+ diff.diff();
+ assertEquals(new HashSet<String>(Arrays.asList("target", "src/tst")),
+ diff.getUntrackedFolders());
- diff = new IndexDiff(db, Constants.HEAD, new FileTreeIterator(db));
- diff.diff();
- assertEquals(new HashSet<String>(Arrays.asList("target", "src/tst")),
- diff.getUntrackedFolders());
+ git.rm().addFilepattern("src/com/B.java").addFilepattern("src/org")
+ .call();
+ git.commit().setMessage("second").call();
+ writeTrashFile("src/org/C.java", "");
- git.rm().addFilepattern("src/com/B.java").addFilepattern("src/org")
- .call();
- git.commit().setMessage("second").call();
- writeTrashFile("src/org/C.java", "");
-
- diff = new IndexDiff(db, Constants.HEAD, new FileTreeIterator(db));
- diff.diff();
- assertEquals(
- new HashSet<String>(Arrays.asList("src/org", "src/tst",
- "target")),
- diff.getUntrackedFolders());
+ diff = new IndexDiff(db, Constants.HEAD, new FileTreeIterator(db));
+ diff.diff();
+ assertEquals(
+ new HashSet<String>(Arrays.asList("src/org", "src/tst",
+ "target")),
+ diff.getUntrackedFolders());
+ }
}
/**
@@ -473,85 +475,86 @@
*/
@Test
public void testUntrackedNotIgnoredFolders() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ IndexDiff diff = new IndexDiff(db, Constants.HEAD,
+ new FileTreeIterator(db));
+ diff.diff();
+ assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders());
- IndexDiff diff = new IndexDiff(db, Constants.HEAD,
- new FileTreeIterator(db));
- diff.diff();
- assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders());
+ writeTrashFile("readme", "");
+ writeTrashFile("sr/com/X.java", "");
+ writeTrashFile("src/com/A.java", "");
+ writeTrashFile("src/org/B.java", "");
+ writeTrashFile("srcs/org/Y.java", "");
+ writeTrashFile("target/com/A.java", "");
+ writeTrashFile("target/org/B.java", "");
+ writeTrashFile(".gitignore", "/target\n/sr");
- writeTrashFile("readme", "");
- writeTrashFile("sr/com/X.java", "");
- writeTrashFile("src/com/A.java", "");
- writeTrashFile("src/org/B.java", "");
- writeTrashFile("srcs/org/Y.java", "");
- writeTrashFile("target/com/A.java", "");
- writeTrashFile("target/org/B.java", "");
- writeTrashFile(".gitignore", "/target\n/sr");
+ git.add().addFilepattern("readme").addFilepattern(".gitignore")
+ .addFilepattern("srcs/").call();
+ git.commit().setMessage("initial").call();
- git.add().addFilepattern("readme").addFilepattern(".gitignore")
- .addFilepattern("srcs/").call();
- git.commit().setMessage("initial").call();
+ diff = new IndexDiff(db, Constants.HEAD, new FileTreeIterator(db));
+ diff.diff();
+ assertEquals(new HashSet<String>(Arrays.asList("src")),
+ diff.getUntrackedFolders());
- diff = new IndexDiff(db, Constants.HEAD, new FileTreeIterator(db));
- diff.diff();
- assertEquals(new HashSet<String>(Arrays.asList("src")),
- diff.getUntrackedFolders());
+ git.add().addFilepattern("src").call();
+ writeTrashFile("sr/com/X1.java", "");
+ writeTrashFile("src/tst/A.java", "");
+ writeTrashFile("src/tst/B.java", "");
+ writeTrashFile("srcs/com/Y1.java", "");
+ deleteTrashFile(".gitignore");
- git.add().addFilepattern("src").call();
- writeTrashFile("sr/com/X1.java", "");
- writeTrashFile("src/tst/A.java", "");
- writeTrashFile("src/tst/B.java", "");
- writeTrashFile("srcs/com/Y1.java", "");
- deleteTrashFile(".gitignore");
-
- diff = new IndexDiff(db, Constants.HEAD, new FileTreeIterator(db));
- diff.diff();
- assertEquals(
- new HashSet<String>(Arrays.asList("srcs/com", "sr", "src/tst",
- "target")),
- diff.getUntrackedFolders());
+ diff = new IndexDiff(db, Constants.HEAD, new FileTreeIterator(db));
+ diff.diff();
+ assertEquals(
+ new HashSet<String>(Arrays.asList("srcs/com", "sr", "src/tst",
+ "target")),
+ diff.getUntrackedFolders());
+ }
}
@Test
public void testAssumeUnchanged() throws Exception {
- Git git = new Git(db);
- String path = "file";
- writeTrashFile(path, "content");
- git.add().addFilepattern(path).call();
- String path2 = "file2";
- writeTrashFile(path2, "content");
- String path3 = "file3";
- writeTrashFile(path3, "some content");
- git.add().addFilepattern(path2).addFilepattern(path3).call();
- git.commit().setMessage("commit").call();
- assumeUnchanged(path2);
- assumeUnchanged(path3);
- writeTrashFile(path, "more content");
- deleteTrashFile(path3);
+ try (Git git = new Git(db)) {
+ String path = "file";
+ writeTrashFile(path, "content");
+ git.add().addFilepattern(path).call();
+ String path2 = "file2";
+ writeTrashFile(path2, "content");
+ String path3 = "file3";
+ writeTrashFile(path3, "some content");
+ git.add().addFilepattern(path2).addFilepattern(path3).call();
+ git.commit().setMessage("commit").call();
+ assumeUnchanged(path2);
+ assumeUnchanged(path3);
+ writeTrashFile(path, "more content");
+ deleteTrashFile(path3);
- FileTreeIterator iterator = new FileTreeIterator(db);
- IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
- diff.diff();
- assertEquals(2, diff.getAssumeUnchanged().size());
- assertEquals(1, diff.getModified().size());
- assertEquals(0, diff.getChanged().size());
- assertTrue(diff.getAssumeUnchanged().contains("file2"));
- assertTrue(diff.getAssumeUnchanged().contains("file3"));
- assertTrue(diff.getModified().contains("file"));
+ FileTreeIterator iterator = new FileTreeIterator(db);
+ IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
+ diff.diff();
+ assertEquals(2, diff.getAssumeUnchanged().size());
+ assertEquals(1, diff.getModified().size());
+ assertEquals(0, diff.getChanged().size());
+ assertTrue(diff.getAssumeUnchanged().contains("file2"));
+ assertTrue(diff.getAssumeUnchanged().contains("file3"));
+ assertTrue(diff.getModified().contains("file"));
- git.add().addFilepattern(".").call();
+ git.add().addFilepattern(".").call();
- iterator = new FileTreeIterator(db);
- diff = new IndexDiff(db, Constants.HEAD, iterator);
- diff.diff();
- assertEquals(2, diff.getAssumeUnchanged().size());
- assertEquals(0, diff.getModified().size());
- assertEquals(1, diff.getChanged().size());
- assertTrue(diff.getAssumeUnchanged().contains("file2"));
- assertTrue(diff.getAssumeUnchanged().contains("file3"));
- assertTrue(diff.getChanged().contains("file"));
- assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders());
+ iterator = new FileTreeIterator(db);
+ diff = new IndexDiff(db, Constants.HEAD, iterator);
+ diff.diff();
+ assertEquals(2, diff.getAssumeUnchanged().size());
+ assertEquals(0, diff.getModified().size());
+ assertEquals(1, diff.getChanged().size());
+ assertTrue(diff.getAssumeUnchanged().contains("file2"));
+ assertTrue(diff.getAssumeUnchanged().contains("file3"));
+ assertTrue(diff.getChanged().contains("file"));
+ assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders());
+ }
}
@Test
@@ -577,147 +580,148 @@
@Test
public void testStageState_mergeAndReset_bug() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "content");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial commit")
+ .call();
- writeTrashFile("a", "content");
- git.add().addFilepattern("a").call();
- RevCommit initialCommit = git.commit().setMessage("initial commit")
- .call();
+ // create branch and add a new file
+ final String branchName = Constants.R_HEADS + "branch";
+ createBranch(initialCommit, branchName);
+ checkoutBranch(branchName);
+ writeTrashFile("b", "second file content - branch");
+ git.add().addFilepattern("b").call();
+ RevCommit branchCommit = git.commit().setMessage("branch commit")
+ .call();
- // create branch and add a new file
- final String branchName = Constants.R_HEADS + "branch";
- createBranch(initialCommit, branchName);
- checkoutBranch(branchName);
- writeTrashFile("b", "second file content - branch");
- git.add().addFilepattern("b").call();
- RevCommit branchCommit = git.commit().setMessage("branch commit")
- .call();
+ // checkout master and add the same new file
+ checkoutBranch(Constants.R_HEADS + Constants.MASTER);
+ writeTrashFile("b", "second file content - master");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("master commit").call();
- // checkout master and add the same new file
- checkoutBranch(Constants.R_HEADS + Constants.MASTER);
- writeTrashFile("b", "second file content - master");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("master commit").call();
+ // try and merge
+ MergeResult result = git.merge().include(branchCommit).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
- // try and merge
- MergeResult result = git.merge().include(branchCommit).call();
- assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ FileTreeIterator iterator = new FileTreeIterator(db);
+ IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
+ diff.diff();
- FileTreeIterator iterator = new FileTreeIterator(db);
- IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
- diff.diff();
+ assertTrue(diff.getChanged().isEmpty());
+ assertTrue(diff.getAdded().isEmpty());
+ assertTrue(diff.getRemoved().isEmpty());
+ assertTrue(diff.getMissing().isEmpty());
+ assertTrue(diff.getModified().isEmpty());
+ assertEquals(1, diff.getConflicting().size());
+ assertTrue(diff.getConflicting().contains("b"));
+ assertEquals(StageState.BOTH_ADDED, diff.getConflictingStageStates()
+ .get("b"));
+ assertTrue(diff.getUntrackedFolders().isEmpty());
- assertTrue(diff.getChanged().isEmpty());
- assertTrue(diff.getAdded().isEmpty());
- assertTrue(diff.getRemoved().isEmpty());
- assertTrue(diff.getMissing().isEmpty());
- assertTrue(diff.getModified().isEmpty());
- assertEquals(1, diff.getConflicting().size());
- assertTrue(diff.getConflicting().contains("b"));
- assertEquals(StageState.BOTH_ADDED, diff.getConflictingStageStates()
- .get("b"));
- assertTrue(diff.getUntrackedFolders().isEmpty());
+ // reset file b to its master state without altering the index
+ writeTrashFile("b", "second file content - master");
- // reset file b to its master state without altering the index
- writeTrashFile("b", "second file content - master");
+ // we should have the same result
+ iterator = new FileTreeIterator(db);
+ diff = new IndexDiff(db, Constants.HEAD, iterator);
+ diff.diff();
- // we should have the same result
- iterator = new FileTreeIterator(db);
- diff = new IndexDiff(db, Constants.HEAD, iterator);
- diff.diff();
-
- assertTrue(diff.getChanged().isEmpty());
- assertTrue(diff.getAdded().isEmpty());
- assertTrue(diff.getRemoved().isEmpty());
- assertTrue(diff.getMissing().isEmpty());
- assertTrue(diff.getModified().isEmpty());
- assertEquals(1, diff.getConflicting().size());
- assertTrue(diff.getConflicting().contains("b"));
- assertEquals(StageState.BOTH_ADDED, diff.getConflictingStageStates()
- .get("b"));
- assertTrue(diff.getUntrackedFolders().isEmpty());
+ assertTrue(diff.getChanged().isEmpty());
+ assertTrue(diff.getAdded().isEmpty());
+ assertTrue(diff.getRemoved().isEmpty());
+ assertTrue(diff.getMissing().isEmpty());
+ assertTrue(diff.getModified().isEmpty());
+ assertEquals(1, diff.getConflicting().size());
+ assertTrue(diff.getConflicting().contains("b"));
+ assertEquals(StageState.BOTH_ADDED, diff.getConflictingStageStates()
+ .get("b"));
+ assertTrue(diff.getUntrackedFolders().isEmpty());
+ }
}
@Test
public void testStageState_simulated_bug() throws Exception {
- Git git = new Git(db);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "content");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial commit")
+ .call();
- writeTrashFile("a", "content");
- git.add().addFilepattern("a").call();
- RevCommit initialCommit = git.commit().setMessage("initial commit")
- .call();
+ // create branch and add a new file
+ final String branchName = Constants.R_HEADS + "branch";
+ createBranch(initialCommit, branchName);
+ checkoutBranch(branchName);
+ writeTrashFile("b", "second file content - branch");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("branch commit")
+ .call();
- // create branch and add a new file
- final String branchName = Constants.R_HEADS + "branch";
- createBranch(initialCommit, branchName);
- checkoutBranch(branchName);
- writeTrashFile("b", "second file content - branch");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("branch commit")
- .call();
+ // checkout master and add the same new file
+ checkoutBranch(Constants.R_HEADS + Constants.MASTER);
+ writeTrashFile("b", "second file content - master");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("master commit").call();
- // checkout master and add the same new file
- checkoutBranch(Constants.R_HEADS + Constants.MASTER);
- writeTrashFile("b", "second file content - master");
- git.add().addFilepattern("b").call();
- git.commit().setMessage("master commit").call();
+ // Simulate a failed merge of branch into master
+ DirCacheBuilder builder = db.lockDirCache().builder();
+ DirCacheEntry entry = createEntry("a", FileMode.REGULAR_FILE, 0,
+ "content");
+ builder.add(entry);
+ entry = createEntry("b", FileMode.REGULAR_FILE, 2,
+ "second file content - master");
+ builder.add(entry);
+ entry = createEntry("b", FileMode.REGULAR_FILE, 3,
+ "second file content - branch");
+ builder.add(entry);
+ builder.commit();
- // Simulate a failed merge of branch into master
- DirCacheBuilder builder = db.lockDirCache().builder();
- DirCacheEntry entry = createEntry("a", FileMode.REGULAR_FILE, 0,
- "content");
- builder.add(entry);
- entry = createEntry("b", FileMode.REGULAR_FILE, 2,
- "second file content - master");
- builder.add(entry);
- entry = createEntry("b", FileMode.REGULAR_FILE, 3,
- "second file content - branch");
- builder.add(entry);
- builder.commit();
+ FileTreeIterator iterator = new FileTreeIterator(db);
+ IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
+ diff.diff();
- FileTreeIterator iterator = new FileTreeIterator(db);
- IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
- diff.diff();
-
- assertTrue(diff.getChanged().isEmpty());
- assertTrue(diff.getAdded().isEmpty());
- assertTrue(diff.getRemoved().isEmpty());
- assertTrue(diff.getMissing().isEmpty());
- assertTrue(diff.getModified().isEmpty());
- assertEquals(1, diff.getConflicting().size());
- assertTrue(diff.getConflicting().contains("b"));
- assertEquals(StageState.BOTH_ADDED, diff.getConflictingStageStates()
- .get("b"));
- assertTrue(diff.getUntrackedFolders().isEmpty());
+ assertTrue(diff.getChanged().isEmpty());
+ assertTrue(diff.getAdded().isEmpty());
+ assertTrue(diff.getRemoved().isEmpty());
+ assertTrue(diff.getMissing().isEmpty());
+ assertTrue(diff.getModified().isEmpty());
+ assertEquals(1, diff.getConflicting().size());
+ assertTrue(diff.getConflicting().contains("b"));
+ assertEquals(StageState.BOTH_ADDED, diff.getConflictingStageStates()
+ .get("b"));
+ assertTrue(diff.getUntrackedFolders().isEmpty());
+ }
}
@Test
public void testAutoCRLFInput() throws Exception {
- Git git = new Git(db);
- FileBasedConfig config = db.getConfig();
+ try (Git git = new Git(db)) {
+ FileBasedConfig config = db.getConfig();
- // Make sure core.autocrlf is false before adding
- config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_AUTOCRLF, AutoCRLF.FALSE);
- config.save();
+ // Make sure core.autocrlf is false before adding
+ config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF, AutoCRLF.FALSE);
+ config.save();
- // File is already in repository with CRLF
- writeTrashFile("crlf.txt", "this\r\ncontains\r\ncrlf\r\n");
- git.add().addFilepattern("crlf.txt").call();
- git.commit().setMessage("Add crlf.txt").call();
+ // File is already in repository with CRLF
+ writeTrashFile("crlf.txt", "this\r\ncontains\r\ncrlf\r\n");
+ git.add().addFilepattern("crlf.txt").call();
+ git.commit().setMessage("Add crlf.txt").call();
- // Now set core.autocrlf to input
- config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_AUTOCRLF, AutoCRLF.INPUT);
- config.save();
+ // Now set core.autocrlf to input
+ config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF, AutoCRLF.INPUT);
+ config.save();
- FileTreeIterator iterator = new FileTreeIterator(db);
- IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
- diff.diff();
+ FileTreeIterator iterator = new FileTreeIterator(db);
+ IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
+ diff.diff();
- assertTrue(
- "Expected no modified files, but there were: "
- + diff.getModified(), diff.getModified().isEmpty());
+ assertTrue(
+ "Expected no modified files, but there were: "
+ + diff.getModified(), diff.getModified().isEmpty());
+ }
}
private void verifyStageState(StageState expected, int... stages)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexModificationTimesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexModificationTimesTest.java
index c6f02f4..b9bbbeb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexModificationTimesTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexModificationTimesTest.java
@@ -49,80 +49,81 @@
@Test
public void testLastModifiedTimes() throws Exception {
- Git git = new Git(db);
- String path = "file";
- writeTrashFile(path, "content");
- String path2 = "file2";
- writeTrashFile(path2, "content2");
+ try (Git git = new Git(db)) {
+ String path = "file";
+ writeTrashFile(path, "content");
+ String path2 = "file2";
+ writeTrashFile(path2, "content2");
- git.add().addFilepattern(path).call();
- git.add().addFilepattern(path2).call();
- git.commit().setMessage("commit").call();
+ git.add().addFilepattern(path).call();
+ git.add().addFilepattern(path2).call();
+ git.commit().setMessage("commit").call();
- DirCache dc = db.readDirCache();
- DirCacheEntry entry = dc.getEntry(path);
- DirCacheEntry entry2 = dc.getEntry(path);
+ DirCache dc = db.readDirCache();
+ DirCacheEntry entry = dc.getEntry(path);
+ DirCacheEntry entry2 = dc.getEntry(path);
- assertTrue("last modified shall not be zero!",
- entry.getLastModified() != 0);
+ assertTrue("last modified shall not be zero!",
+ entry.getLastModified() != 0);
- assertTrue("last modified shall not be zero!",
- entry2.getLastModified() != 0);
+ assertTrue("last modified shall not be zero!",
+ entry2.getLastModified() != 0);
- writeTrashFile(path, "new content");
- git.add().addFilepattern(path).call();
- git.commit().setMessage("commit2").call();
+ writeTrashFile(path, "new content");
+ git.add().addFilepattern(path).call();
+ git.commit().setMessage("commit2").call();
- dc = db.readDirCache();
- entry = dc.getEntry(path);
- entry2 = dc.getEntry(path);
+ dc = db.readDirCache();
+ entry = dc.getEntry(path);
+ entry2 = dc.getEntry(path);
- assertTrue("last modified shall not be zero!",
- entry.getLastModified() != 0);
+ assertTrue("last modified shall not be zero!",
+ entry.getLastModified() != 0);
- assertTrue("last modified shall not be zero!",
- entry2.getLastModified() != 0);
+ assertTrue("last modified shall not be zero!",
+ entry2.getLastModified() != 0);
+ }
}
@Test
public void testModify() throws Exception {
- Git git = new Git(db);
- String path = "file";
- writeTrashFile(path, "content");
+ try (Git git = new Git(db)) {
+ String path = "file";
+ writeTrashFile(path, "content");
- git.add().addFilepattern(path).call();
- git.commit().setMessage("commit").call();
+ git.add().addFilepattern(path).call();
+ git.commit().setMessage("commit").call();
- DirCache dc = db.readDirCache();
- DirCacheEntry entry = dc.getEntry(path);
+ DirCache dc = db.readDirCache();
+ DirCacheEntry entry = dc.getEntry(path);
- long masterLastMod = entry.getLastModified();
+ long masterLastMod = entry.getLastModified();
- git.checkout().setCreateBranch(true).setName("side").call();
+ git.checkout().setCreateBranch(true).setName("side").call();
- Thread.sleep(10);
- String path2 = "file2";
- writeTrashFile(path2, "side content");
- git.add().addFilepattern(path2).call();
- git.commit().setMessage("commit").call();
+ Thread.sleep(10);
+ String path2 = "file2";
+ writeTrashFile(path2, "side content");
+ git.add().addFilepattern(path2).call();
+ git.commit().setMessage("commit").call();
- dc = db.readDirCache();
- entry = dc.getEntry(path);
+ dc = db.readDirCache();
+ entry = dc.getEntry(path);
- long sideLastMode = entry.getLastModified();
+ long sideLastMode = entry.getLastModified();
- Thread.sleep(2000);
+ Thread.sleep(2000);
- writeTrashFile(path, "uncommitted content");
- git.checkout().setName("master").call();
+ writeTrashFile(path, "uncommitted content");
+ git.checkout().setName("master").call();
- dc = db.readDirCache();
- entry = dc.getEntry(path);
+ dc = db.readDirCache();
+ entry = dc.getEntry(path);
- assertTrue("shall have equal mod time!", masterLastMod == sideLastMode);
- assertTrue("shall not equal master timestamp!",
- entry.getLastModified() == masterLastMod);
-
+ assertTrue("shall have equal mod time!", masterLastMod == sideLastMode);
+ assertTrue("shall not equal master timestamp!",
+ entry.getLastModified() == masterLastMod);
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
index 3abe81c..43160fb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
@@ -45,8 +45,25 @@
package org.eclipse.jgit.lib;
import static java.lang.Integer.valueOf;
-import static java.lang.Long.valueOf;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
+import static org.eclipse.jgit.lib.Constants.OBJ_BAD;
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
+import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
+import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
+import static org.eclipse.jgit.lib.Constants.encode;
+import static org.eclipse.jgit.lib.Constants.encodeASCII;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.DUPLICATE_ENTRIES;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.EMPTY_NAME;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.FULL_PATHNAME;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOT;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOTDOT;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOTGIT;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.NULL_SHA1;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.TREE_NOT_SORTED;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import java.io.UnsupportedEncodingException;
@@ -67,15 +84,10 @@
@Test
public void testInvalidType() {
- try {
- checker.check(Constants.OBJ_BAD, new byte[0]);
- fail("Did not throw CorruptObjectException");
- } catch (CorruptObjectException e) {
- final String m = e.getMessage();
- assertEquals(MessageFormat.format(
- JGitText.get().corruptObjectInvalidType2,
- valueOf(Constants.OBJ_BAD)), m);
- }
+ String msg = MessageFormat.format(
+ JGitText.get().corruptObjectInvalidType2,
+ valueOf(OBJ_BAD));
+ assertCorrupt(msg, OBJ_BAD, new byte[0]);
}
@Test
@@ -84,13 +96,13 @@
checker.checkBlob(new byte[0]);
checker.checkBlob(new byte[1]);
- checker.check(Constants.OBJ_BLOB, new byte[0]);
- checker.check(Constants.OBJ_BLOB, new byte[1]);
+ checker.check(OBJ_BLOB, new byte[0]);
+ checker.check(OBJ_BLOB, new byte[1]);
}
@Test
public void testValidCommitNoParent() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
@@ -99,14 +111,14 @@
b.append("author A. U. Thor <author@localhost> 1 +0000\n");
b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
checker.checkCommit(data);
- checker.check(Constants.OBJ_COMMIT, data);
+ checker.check(OBJ_COMMIT, data);
}
@Test
public void testValidCommitBlankAuthor() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
@@ -115,9 +127,9 @@
b.append("author <> 0 +0000\n");
b.append("committer <> 0 +0000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
checker.checkCommit(data);
- checker.check(Constants.OBJ_COMMIT, data);
+ checker.check(OBJ_COMMIT, data);
}
@Test
@@ -127,15 +139,13 @@
b.append("author b <b@c> <b@c> 0 +0000\n");
b.append("committer <> 0 +0000\n");
- byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("invalid author", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("bad date", OBJ_COMMIT, data);
checker.setAllowInvalidPersonIdent(true);
checker.checkCommit(data);
+
+ checker.setAllowInvalidPersonIdent(false);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
@@ -145,20 +155,18 @@
b.append("author <> 0 +0000\n");
b.append("committer b <b@c> <b@c> 0 +0000\n");
- byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("invalid committer", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("bad date", OBJ_COMMIT, data);
checker.setAllowInvalidPersonIdent(true);
checker.checkCommit(data);
+
+ checker.setAllowInvalidPersonIdent(false);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
public void testValidCommit1Parent() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
@@ -171,14 +179,14 @@
b.append("author A. U. Thor <author@localhost> 1 +0000\n");
b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
checker.checkCommit(data);
- checker.check(Constants.OBJ_COMMIT, data);
+ checker.check(OBJ_COMMIT, data);
}
@Test
public void testValidCommit2Parent() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
@@ -195,14 +203,14 @@
b.append("author A. U. Thor <author@localhost> 1 +0000\n");
b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
checker.checkCommit(data);
- checker.check(Constants.OBJ_COMMIT, data);
+ checker.check(OBJ_COMMIT, data);
}
@Test
public void testValidCommit128Parent() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
@@ -217,15 +225,15 @@
b.append("author A. U. Thor <author@localhost> 1 +0000\n");
b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
checker.checkCommit(data);
- checker.check(Constants.OBJ_COMMIT, data);
+ checker.check(OBJ_COMMIT, data);
}
@Test
public void testValidCommitNormalTime() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
- final String when = "1222757360 -0730";
+ StringBuilder b = new StringBuilder();
+ String when = "1222757360 -0730";
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
@@ -234,843 +242,539 @@
b.append("author A. U. Thor <author@localhost> " + when + "\n");
b.append("committer A. U. Thor <author@localhost> " + when + "\n");
- final byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
checker.checkCommit(data);
- checker.check(Constants.OBJ_COMMIT, data);
+ checker.check(OBJ_COMMIT, data);
}
@Test
public void testInvalidCommitNoTree1() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("parent ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("no tree header", e.getMessage());
- }
+ assertCorrupt("no tree header", OBJ_COMMIT, b);
}
@Test
public void testInvalidCommitNoTree2() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("trie ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("no tree header", e.getMessage());
- }
+ assertCorrupt("no tree header", OBJ_COMMIT, b);
}
@Test
public void testInvalidCommitNoTree3() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("tree");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("no tree header", e.getMessage());
- }
+ assertCorrupt("no tree header", OBJ_COMMIT, b);
}
@Test
public void testInvalidCommitNoTree4() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("tree\t");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("no tree header", e.getMessage());
- }
+ assertCorrupt("no tree header", OBJ_COMMIT, b);
}
@Test
public void testInvalidCommitInvalidTree1() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("zzzzfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("invalid tree", e.getMessage());
- }
+ assertCorrupt("invalid tree", OBJ_COMMIT, b);
}
@Test
public void testInvalidCommitInvalidTree2() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append("z\n");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("invalid tree", e.getMessage());
- }
+ assertCorrupt("invalid tree", OBJ_COMMIT, b);
}
@Test
public void testInvalidCommitInvalidTree3() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9b");
b.append("\n");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("invalid tree", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid tree", OBJ_COMMIT, data);
}
@Test
public void testInvalidCommitInvalidTree4() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("invalid tree", e.getMessage());
- }
+ assertCorrupt("invalid tree", OBJ_COMMIT, b);
}
@Test
public void testInvalidCommitInvalidParent1() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("parent ");
b.append("\n");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("invalid parent", e.getMessage());
- }
+ assertCorrupt("invalid parent", OBJ_COMMIT, b);
}
@Test
public void testInvalidCommitInvalidParent2() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("parent ");
b.append("zzzzfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append("\n");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("invalid parent", e.getMessage());
- }
+ assertCorrupt("invalid parent", OBJ_COMMIT, b);
}
@Test
public void testInvalidCommitInvalidParent3() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("parent ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append("\n");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("invalid parent", e.getMessage());
- }
+ assertCorrupt("invalid parent", OBJ_COMMIT, b);
}
@Test
public void testInvalidCommitInvalidParent4() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("parent ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append("z\n");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- assertEquals("invalid parent", e.getMessage());
- }
+ assertCorrupt("invalid parent", OBJ_COMMIT, b);
}
@Test
public void testInvalidCommitInvalidParent5() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("parent\t");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append("\n");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- // Yes, really, we complain about author not being
- // found as the invalid parent line wasn't consumed.
- assertEquals("no author", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertCorrupt("no author", OBJ_COMMIT, data);
}
@Test
- public void testInvalidCommitNoAuthor() {
- final StringBuilder b = new StringBuilder();
-
+ public void testInvalidCommitNoAuthor() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- // Yes, really, we complain about author not being
- // found as the invalid parent line wasn't consumed.
- assertEquals("no author", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("no author", OBJ_COMMIT, data);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
- public void testInvalidCommitNoCommitter1() {
- final StringBuilder b = new StringBuilder();
-
+ public void testInvalidCommitNoCommitter1() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("author A. U. Thor <author@localhost> 1 +0000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- // Yes, really, we complain about author not being
- // found as the invalid parent line wasn't consumed.
- assertEquals("no committer", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("no committer", OBJ_COMMIT, data);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
- public void testInvalidCommitNoCommitter2() {
- final StringBuilder b = new StringBuilder();
-
+ public void testInvalidCommitNoCommitter2() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("author A. U. Thor <author@localhost> 1 +0000\n");
b.append("\n");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- // Yes, really, we complain about author not being
- // found as the invalid parent line wasn't consumed.
- assertEquals("no committer", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("no committer", OBJ_COMMIT, data);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
- public void testInvalidCommitInvalidAuthor1() {
- final StringBuilder b = new StringBuilder();
-
+ public void testInvalidCommitInvalidAuthor1()
+ throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("author A. U. Thor <foo 1 +0000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- // Yes, really, we complain about author not being
- // found as the invalid parent line wasn't consumed.
- assertEquals("invalid author", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("bad email", OBJ_COMMIT, data);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
- public void testInvalidCommitInvalidAuthor2() {
- final StringBuilder b = new StringBuilder();
-
+ public void testInvalidCommitInvalidAuthor2()
+ throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("author A. U. Thor foo> 1 +0000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- // Yes, really, we complain about author not being
- // found as the invalid parent line wasn't consumed.
- assertEquals("invalid author", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("missing email", OBJ_COMMIT, data);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
- public void testInvalidCommitInvalidAuthor3() {
- final StringBuilder b = new StringBuilder();
-
+ public void testInvalidCommitInvalidAuthor3()
+ throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("author 1 +0000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- // Yes, really, we complain about author not being
- // found as the invalid parent line wasn't consumed.
- assertEquals("invalid author", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("missing email", OBJ_COMMIT, data);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
- public void testInvalidCommitInvalidAuthor4() {
- final StringBuilder b = new StringBuilder();
-
+ public void testInvalidCommitInvalidAuthor4()
+ throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("author a <b> +0000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- // Yes, really, we complain about author not being
- // found as the invalid parent line wasn't consumed.
- assertEquals("invalid author", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("bad date", OBJ_COMMIT, data);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
- public void testInvalidCommitInvalidAuthor5() {
- final StringBuilder b = new StringBuilder();
-
+ public void testInvalidCommitInvalidAuthor5()
+ throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("author a <b>\n");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- // Yes, really, we complain about author not being
- // found as the invalid parent line wasn't consumed.
- assertEquals("invalid author", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("bad date", OBJ_COMMIT, data);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
- public void testInvalidCommitInvalidAuthor6() {
- final StringBuilder b = new StringBuilder();
-
+ public void testInvalidCommitInvalidAuthor6()
+ throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("author a <b> z");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- // Yes, really, we complain about author not being
- // found as the invalid parent line wasn't consumed.
- assertEquals("invalid author", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("bad date", OBJ_COMMIT, data);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
- public void testInvalidCommitInvalidAuthor7() {
- final StringBuilder b = new StringBuilder();
-
+ public void testInvalidCommitInvalidAuthor7()
+ throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("author a <b> 1 z");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- // Yes, really, we complain about author not being
- // found as the invalid parent line wasn't consumed.
- assertEquals("invalid author", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("bad time zone", OBJ_COMMIT, data);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
- public void testInvalidCommitInvalidCommitter() {
- final StringBuilder b = new StringBuilder();
-
+ public void testInvalidCommitInvalidCommitter()
+ throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
b.append("tree ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("author a <b> 1 +0000\n");
b.append("committer a <");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkCommit(data);
- fail("Did not catch corrupt object");
- } catch (CorruptObjectException e) {
- // Yes, really, we complain about author not being
- // found as the invalid parent line wasn't consumed.
- assertEquals("invalid committer", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("bad email", OBJ_COMMIT, data);
+ assertSkipListAccepts(OBJ_COMMIT, data);
}
@Test
public void testValidTag() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("type commit\n");
b.append("tag test-tag\n");
b.append("tagger A. U. Thor <author@localhost> 1 +0000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
checker.checkTag(data);
- checker.check(Constants.OBJ_TAG, data);
+ checker.check(OBJ_TAG, data);
}
@Test
public void testInvalidTagNoObject1() {
- final StringBuilder b = new StringBuilder();
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("no object header", e.getMessage());
- }
+ assertCorrupt("no object header", OBJ_TAG, new byte[0]);
}
@Test
public void testInvalidTagNoObject2() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object\t");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("no object header", e.getMessage());
- }
+ assertCorrupt("no object header", OBJ_TAG, b);
}
@Test
public void testInvalidTagNoObject3() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("obejct ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("no object header", e.getMessage());
- }
+ assertCorrupt("no object header", OBJ_TAG, b);
}
@Test
public void testInvalidTagNoObject4() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("zz9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("invalid object", e.getMessage());
- }
+ assertCorrupt("invalid object", OBJ_TAG, b);
}
@Test
public void testInvalidTagNoObject5() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append(" \n");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("invalid object", e.getMessage());
- }
+ assertCorrupt("invalid object", OBJ_TAG, b);
}
@Test
public void testInvalidTagNoObject6() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("invalid object", e.getMessage());
- }
+ assertCorrupt("invalid object", OBJ_TAG, b);
}
@Test
public void testInvalidTagNoType1() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("no type header", e.getMessage());
- }
+ assertCorrupt("no type header", OBJ_TAG, b);
}
@Test
public void testInvalidTagNoType2() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("type\tcommit\n");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("no type header", e.getMessage());
- }
+ assertCorrupt("no type header", OBJ_TAG, b);
}
@Test
public void testInvalidTagNoType3() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("tpye commit\n");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("no type header", e.getMessage());
- }
+ assertCorrupt("no type header", OBJ_TAG, b);
}
@Test
public void testInvalidTagNoType4() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("type commit");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("no tag header", e.getMessage());
- }
+ assertCorrupt("no tag header", OBJ_TAG, b);
}
@Test
public void testInvalidTagNoTagHeader1() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("type commit\n");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("no tag header", e.getMessage());
- }
+ assertCorrupt("no tag header", OBJ_TAG, b);
}
@Test
public void testInvalidTagNoTagHeader2() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("type commit\n");
b.append("tag\tfoo\n");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("no tag header", e.getMessage());
- }
+ assertCorrupt("no tag header", OBJ_TAG, b);
}
@Test
public void testInvalidTagNoTagHeader3() {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("type commit\n");
b.append("tga foo\n");
-
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("no tag header", e.getMessage());
- }
+ assertCorrupt("no tag header", OBJ_TAG, b);
}
@Test
public void testValidTagHasNoTaggerHeader() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("type commit\n");
b.append("tag foo\n");
-
- checker.checkTag(Constants.encodeASCII(b.toString()));
+ checker.checkTag(encodeASCII(b.toString()));
}
@Test
public void testInvalidTagInvalidTaggerHeader1()
throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
-
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("type commit\n");
b.append("tag foo\n");
b.append("tagger \n");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("invalid tagger", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("missing email", OBJ_TAG, data);
checker.setAllowInvalidPersonIdent(true);
checker.checkTag(data);
+
+ checker.setAllowInvalidPersonIdent(false);
+ assertSkipListAccepts(OBJ_TAG, data);
}
@Test
- public void testInvalidTagInvalidTaggerHeader3() {
- final StringBuilder b = new StringBuilder();
-
+ public void testInvalidTagInvalidTaggerHeader3()
+ throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
b.append("object ");
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
b.append('\n');
-
b.append("type commit\n");
b.append("tag foo\n");
b.append("tagger a < 1 +000\n");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTag(data);
- fail("incorrectly accepted invalid tag");
- } catch (CorruptObjectException e) {
- assertEquals("invalid tagger", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("bad email", OBJ_TAG, data);
+ assertSkipListAccepts(OBJ_TAG, data);
}
@Test
public void testValidEmptyTree() throws CorruptObjectException {
checker.checkTree(new byte[0]);
- checker.check(Constants.OBJ_TREE, new byte[0]);
+ checker.check(OBJ_TREE, new byte[0]);
}
@Test
public void testValidTree1() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "100644 regular-file");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testValidTree2() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "100755 executable");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testValidTree3() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "40000 tree");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testValidTree4() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "120000 symlink");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testValidTree5() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "160000 git link");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testValidTree6() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "100644 .a");
- final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(encodeASCII(b.toString()));
+ }
+
+ @Test
+ public void testNullSha1InTreeEntry() throws CorruptObjectException {
+ byte[] data = concat(
+ encodeASCII("100644 A"), new byte[] { '\0' },
+ new byte[OBJECT_ID_LENGTH]);
+ assertCorrupt("entry points to null SHA-1", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(NULL_SHA1, true);
checker.checkTree(data);
}
@@ -1084,357 +788,326 @@
@Test
public void testValidTreeSorting1() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "100644 fooaaa");
entry(b, "100755 foobar");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testValidTreeSorting2() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "100755 fooaaa");
entry(b, "100644 foobar");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testValidTreeSorting3() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "40000 a");
entry(b, "100644 b");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testValidTreeSorting4() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "100644 a");
entry(b, "40000 b");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testValidTreeSorting5() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "100644 a.c");
entry(b, "40000 a");
entry(b, "100644 a0c");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testValidTreeSorting6() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "40000 a");
entry(b, "100644 apple");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testValidTreeSorting7() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "40000 an orang");
entry(b, "40000 an orange");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testValidTreeSorting8() throws CorruptObjectException {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "100644 a");
entry(b, "100644 a0c");
entry(b, "100644 b");
- final byte[] data = Constants.encodeASCII(b.toString());
- checker.checkTree(data);
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
public void testAcceptTreeModeWithZero() throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "040000 a");
+ byte[] data = encodeASCII(b.toString());
checker.setAllowLeadingZeroFileMode(true);
- checker.checkTree(Constants.encodeASCII(b.toString()));
+ checker.checkTree(data);
+
+ checker.setAllowLeadingZeroFileMode(false);
+ assertSkipListAccepts(OBJ_TREE, data);
+
+ checker.setIgnore(ZERO_PADDED_FILEMODE, true);
+ checker.checkTree(data);
}
@Test
public void testInvalidTreeModeStartsWithZero1() {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "0 a");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("mode starts with '0'", e.getMessage());
- }
+ assertCorrupt("mode starts with '0'", OBJ_TREE, b);
}
@Test
public void testInvalidTreeModeStartsWithZero2() {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "0100644 a");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("mode starts with '0'", e.getMessage());
- }
+ assertCorrupt("mode starts with '0'", OBJ_TREE, b);
}
@Test
public void testInvalidTreeModeStartsWithZero3() {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "040000 a");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("mode starts with '0'", e.getMessage());
- }
+ assertCorrupt("mode starts with '0'", OBJ_TREE, b);
}
@Test
public void testInvalidTreeModeNotOctal1() {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "8 a");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid mode character", e.getMessage());
- }
+ assertCorrupt("invalid mode character", OBJ_TREE, b);
}
@Test
public void testInvalidTreeModeNotOctal2() {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "Z a");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid mode character", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid mode character", OBJ_TREE, data);
+ assertSkipListRejects("invalid mode character", OBJ_TREE, data);
}
@Test
public void testInvalidTreeModeNotSupportedMode1() {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "1 a");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid mode 1", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid mode 1", OBJ_TREE, data);
+ assertSkipListRejects("invalid mode 1", OBJ_TREE, data);
}
@Test
public void testInvalidTreeModeNotSupportedMode2() {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
entry(b, "170000 a");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid mode " + 0170000, e.getMessage());
- }
+ assertCorrupt("invalid mode " + 0170000, OBJ_TREE, b);
}
@Test
public void testInvalidTreeModeMissingName() {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
b.append("100644");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("truncated in mode", e.getMessage());
- }
+ assertCorrupt("truncated in mode", OBJ_TREE, b);
}
@Test
- public void testInvalidTreeNameContainsSlash() {
- final StringBuilder b = new StringBuilder();
+ public void testInvalidTreeNameContainsSlash()
+ throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
entry(b, "100644 a/b");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("name contains '/'", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("name contains '/'", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(FULL_PATHNAME, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsEmpty() {
- final StringBuilder b = new StringBuilder();
+ public void testInvalidTreeNameIsEmpty() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
entry(b, "100644 ");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("zero length name", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("zero length name", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(EMPTY_NAME, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsDot() {
- final StringBuilder b = new StringBuilder();
+ public void testInvalidTreeNameIsDot() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
entry(b, "100644 .");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid name '.'", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid name '.'", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOT, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsDotDot() {
- final StringBuilder b = new StringBuilder();
+ public void testInvalidTreeNameIsDotDot() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
entry(b, "100644 ..");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid name '..'", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid name '..'", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOTDOT, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsGit() {
+ public void testInvalidTreeNameIsGit() throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git");
- byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid name '.git'", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid name '.git'", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOTGIT, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsMixedCaseGit() {
+ public void testInvalidTreeNameIsMixedCaseGit()
+ throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .GiT");
- byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid name '.GiT'", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid name '.GiT'", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOTGIT, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsMacHFSGit() {
+ public void testInvalidTreeNameIsMacHFSGit() throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gi\u200Ct");
- byte[] data = Constants.encode(b.toString());
- try {
- checker.setSafeForMacOS(true);
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals(
- "invalid name '.gi\u200Ct' contains ignorable Unicode characters",
- e.getMessage());
- }
+ byte[] data = encode(b.toString());
+
+ // Fine on POSIX.
+ checker.checkTree(data);
+
+ // Rejected on Mac OS.
+ checker.setSafeForMacOS(true);
+ assertCorrupt(
+ "invalid name '.gi\u200Ct' contains ignorable Unicode characters",
+ OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOTGIT, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsMacHFSGit2() {
+ public void testInvalidTreeNameIsMacHFSGit2()
+ throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 \u206B.git");
- byte[] data = Constants.encode(b.toString());
- try {
- checker.setSafeForMacOS(true);
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals(
- "invalid name '\u206B.git' contains ignorable Unicode characters",
- e.getMessage());
- }
+ byte[] data = encode(b.toString());
+
+ // Fine on POSIX.
+ checker.checkTree(data);
+
+ // Rejected on Mac OS.
+ checker.setSafeForMacOS(true);
+ assertCorrupt(
+ "invalid name '\u206B.git' contains ignorable Unicode characters",
+ OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOTGIT, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsMacHFSGit3() {
+ public void testInvalidTreeNameIsMacHFSGit3()
+ throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git\uFEFF");
- byte[] data = Constants.encode(b.toString());
- try {
- checker.setSafeForMacOS(true);
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals(
- "invalid name '.git\uFEFF' contains ignorable Unicode characters",
- e.getMessage());
- }
+ byte[] data = encode(b.toString());
+
+ // Fine on POSIX.
+ checker.checkTree(data);
+
+ // Rejected on Mac OS.
+ checker.setSafeForMacOS(true);
+ assertCorrupt(
+ "invalid name '.git\uFEFF' contains ignorable Unicode characters",
+ OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOTGIT, true);
+ checker.checkTree(data);
}
- private static byte[] concat(byte[] b1, byte[] b2) {
- byte[] data = new byte[b1.length + b2.length];
- System.arraycopy(b1, 0, data, 0, b1.length);
- System.arraycopy(b2, 0, data, b1.length, b2.length);
+ private static byte[] concat(byte[]... b) {
+ int n = 0;
+ for (byte[] a : b) {
+ n += a.length;
+ }
+
+ byte[] data = new byte[n];
+ n = 0;
+ for (byte[] a : b) {
+ System.arraycopy(a, 0, data, n, a.length);
+ n += a.length;
+ }
return data;
}
@Test
- public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd() {
- byte[] data = concat(Constants.encode("100644 .git"),
+ public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd()
+ throws CorruptObjectException {
+ byte[] data = concat(encode("100644 .git"),
new byte[] { (byte) 0xef });
StringBuilder b = new StringBuilder();
entry(b, "");
- data = concat(data, Constants.encode(b.toString()));
- try {
- checker.setSafeForMacOS(true);
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals(
- "invalid name contains byte sequence '0xef' which is not a valid UTF-8 character",
- e.getMessage());
- }
+ data = concat(data, encode(b.toString()));
+
+ // Fine on POSIX.
+ checker.checkTree(data);
+
+ // Rejected on Mac OS.
+ checker.setSafeForMacOS(true);
+ assertCorrupt(
+ "invalid name contains byte sequence '0xef' which is not a valid UTF-8 character",
+ OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
}
@Test
- public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd2() {
- byte[] data = concat(Constants.encode("100644 .git"), new byte[] {
+ public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd2()
+ throws CorruptObjectException {
+ byte[] data = concat(encode("100644 .git"),
+ new byte[] {
(byte) 0xe2, (byte) 0xab });
StringBuilder b = new StringBuilder();
entry(b, "");
- data = concat(data, Constants.encode(b.toString()));
- try {
- checker.setSafeForMacOS(true);
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals(
- "invalid name contains byte sequence '0xe2ab' which is not a valid UTF-8 character",
- e.getMessage());
- }
+ data = concat(data, encode(b.toString()));
+
+ // Fine on POSIX.
+ checker.checkTree(data);
+
+ // Rejected on Mac OS.
+ checker.setSafeForMacOS(true);
+ assertCorrupt(
+ "invalid name contains byte sequence '0xe2ab' which is not a valid UTF-8 character",
+ OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
}
@Test
@@ -1442,7 +1115,7 @@
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git\u200Cx");
- byte[] data = Constants.encode(b.toString());
+ byte[] data = encode(b.toString());
checker.setSafeForMacOS(true);
checker.checkTree(data);
}
@@ -1452,7 +1125,7 @@
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .kit\u200C");
- byte[] data = Constants.encode(b.toString());
+ byte[] data = encode(b.toString());
checker.setSafeForMacOS(true);
checker.checkTree(data);
}
@@ -1462,21 +1135,19 @@
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git\u200C");
- byte[] data = Constants.encode(b.toString());
+ byte[] data = encode(b.toString());
checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsDotGitDot() {
+ public void testInvalidTreeNameIsDotGitDot() throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git.");
- byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid name '.git.'", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid name '.git.'", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOTGIT, true);
+ checker.checkTree(data);
}
@Test
@@ -1484,20 +1155,19 @@
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git..");
- checker.checkTree(Constants.encodeASCII(b.toString()));
+ checker.checkTree(encodeASCII(b.toString()));
}
@Test
- public void testInvalidTreeNameIsDotGitSpace() {
+ public void testInvalidTreeNameIsDotGitSpace()
+ throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git ");
- byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid name '.git '", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid name '.git '", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOTGIT, true);
+ checker.checkTree(data);
}
@Test
@@ -1505,7 +1175,7 @@
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gitfoobar");
- byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
checker.checkTree(data);
}
@@ -1514,7 +1184,7 @@
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gitfoo bar");
- byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
checker.checkTree(data);
}
@@ -1523,7 +1193,7 @@
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gitfoobar.");
- byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
checker.checkTree(data);
}
@@ -1532,251 +1202,236 @@
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gitfoobar..");
- byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsDotGitDotSpace() {
+ public void testInvalidTreeNameIsDotGitDotSpace()
+ throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git. ");
- byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid name '.git. '", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid name '.git. '", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOTGIT, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsDotGitSpaceDot() {
+ public void testInvalidTreeNameIsDotGitSpaceDot()
+ throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git . ");
- byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid name '.git . '", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid name '.git . '", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOTGIT, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsGITTilde1() {
+ public void testInvalidTreeNameIsGITTilde1() throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 GIT~1");
- byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid name 'GIT~1'", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid name 'GIT~1'", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOTGIT, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeNameIsGiTTilde1() {
+ public void testInvalidTreeNameIsGiTTilde1() throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 GiT~1");
- byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("invalid name 'GiT~1'", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("invalid name 'GiT~1'", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(HAS_DOTGIT, true);
+ checker.checkTree(data);
}
@Test
public void testValidTreeNameIsGitTilde11() throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 GIT~11");
- byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
checker.checkTree(data);
}
@Test
public void testInvalidTreeTruncatedInName() {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
b.append("100644 b");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("truncated in name", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("truncated in name", OBJ_TREE, data);
+ assertSkipListRejects("truncated in name", OBJ_TREE, data);
}
@Test
public void testInvalidTreeTruncatedInObjectId() {
- final StringBuilder b = new StringBuilder();
+ StringBuilder b = new StringBuilder();
b.append("100644 b\0\1\2");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("truncated in object id", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("truncated in object id", OBJ_TREE, data);
+ assertSkipListRejects("truncated in object id", OBJ_TREE, data);
}
@Test
- public void testInvalidTreeBadSorting1() {
- final StringBuilder b = new StringBuilder();
+ public void testInvalidTreeBadSorting1() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
entry(b, "100644 foobar");
entry(b, "100644 fooaaa");
- final byte[] data = Constants.encodeASCII(b.toString());
+ byte[] data = encodeASCII(b.toString());
+
+ assertCorrupt("incorrectly sorted", OBJ_TREE, data);
+
+ ObjectId id = idFor(OBJ_TREE, data);
try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
+ checker.check(id, OBJ_TREE, data);
+ fail("Did not throw CorruptObjectException");
} catch (CorruptObjectException e) {
- assertEquals("incorrectly sorted", e.getMessage());
+ assertSame(TREE_NOT_SORTED, e.getErrorType());
+ assertEquals("treeNotSorted: object " + id.name()
+ + ": incorrectly sorted", e.getMessage());
}
+
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(TREE_NOT_SORTED, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeBadSorting2() {
- final StringBuilder b = new StringBuilder();
+ public void testInvalidTreeBadSorting2() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
entry(b, "40000 a");
entry(b, "100644 a.c");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("incorrectly sorted", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("incorrectly sorted", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(TREE_NOT_SORTED, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeBadSorting3() {
- final StringBuilder b = new StringBuilder();
+ public void testInvalidTreeBadSorting3() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
entry(b, "100644 a0c");
entry(b, "40000 a");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("incorrectly sorted", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("incorrectly sorted", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(TREE_NOT_SORTED, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeDuplicateNames1() {
- final StringBuilder b = new StringBuilder();
+ public void testInvalidTreeDuplicateNames1_File()
+ throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
entry(b, "100644 a");
entry(b, "100644 a");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("duplicate entry names", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("duplicate entry names", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(DUPLICATE_ENTRIES, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeDuplicateNames2() {
- final StringBuilder b = new StringBuilder();
+ public void testInvalidTreeDuplicateNames1_Tree()
+ throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
+ entry(b, "40000 a");
+ entry(b, "40000 a");
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("duplicate entry names", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(DUPLICATE_ENTRIES, true);
+ checker.checkTree(data);
+ }
+
+ @Test
+ public void testInvalidTreeDuplicateNames2() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
entry(b, "100644 a");
entry(b, "100755 a");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("duplicate entry names", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("duplicate entry names", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(DUPLICATE_ENTRIES, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeDuplicateNames3() {
- final StringBuilder b = new StringBuilder();
+ public void testInvalidTreeDuplicateNames3() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
entry(b, "100644 a");
entry(b, "40000 a");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("duplicate entry names", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("duplicate entry names", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(DUPLICATE_ENTRIES, true);
+ checker.checkTree(data);
}
@Test
- public void testInvalidTreeDuplicateNames4() {
- final StringBuilder b = new StringBuilder();
+ public void testInvalidTreeDuplicateNames4() throws CorruptObjectException {
+ StringBuilder b = new StringBuilder();
entry(b, "100644 a");
entry(b, "100644 a.c");
entry(b, "100644 a.d");
entry(b, "100644 a.e");
entry(b, "40000 a");
entry(b, "100644 zoo");
- final byte[] data = Constants.encodeASCII(b.toString());
- try {
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("duplicate entry names", e.getMessage());
- }
+ byte[] data = encodeASCII(b.toString());
+ assertCorrupt("duplicate entry names", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(DUPLICATE_ENTRIES, true);
+ checker.checkTree(data);
}
@Test
public void testInvalidTreeDuplicateNames5()
- throws UnsupportedEncodingException {
+ throws UnsupportedEncodingException, CorruptObjectException {
StringBuilder b = new StringBuilder();
- entry(b, "100644 a");
entry(b, "100644 A");
+ entry(b, "100644 a");
byte[] data = b.toString().getBytes("UTF-8");
- try {
- checker.setSafeForWindows(true);
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("duplicate entry names", e.getMessage());
- }
+ checker.setSafeForWindows(true);
+ assertCorrupt("duplicate entry names", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(DUPLICATE_ENTRIES, true);
+ checker.checkTree(data);
}
@Test
public void testInvalidTreeDuplicateNames6()
- throws UnsupportedEncodingException {
+ throws UnsupportedEncodingException, CorruptObjectException {
StringBuilder b = new StringBuilder();
- entry(b, "100644 a");
entry(b, "100644 A");
+ entry(b, "100644 a");
byte[] data = b.toString().getBytes("UTF-8");
- try {
- checker.setSafeForMacOS(true);
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("duplicate entry names", e.getMessage());
- }
+ checker.setSafeForMacOS(true);
+ assertCorrupt("duplicate entry names", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(DUPLICATE_ENTRIES, true);
+ checker.checkTree(data);
}
@Test
public void testInvalidTreeDuplicateNames7()
- throws UnsupportedEncodingException {
- try {
- Class.forName("java.text.Normalizer");
- } catch (ClassNotFoundException e) {
- // Ignore this test on Java 5 platform.
- return;
- }
-
+ throws UnsupportedEncodingException, CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 \u0065\u0301");
entry(b, "100644 \u00e9");
byte[] data = b.toString().getBytes("UTF-8");
- try {
- checker.setSafeForMacOS(true);
- checker.checkTree(data);
- fail("incorrectly accepted an invalid tree");
- } catch (CorruptObjectException e) {
- assertEquals("duplicate entry names", e.getMessage());
- }
+ checker.setSafeForMacOS(true);
+ assertCorrupt("duplicate entry names", OBJ_TREE, data);
+ assertSkipListAccepts(OBJ_TREE, data);
+ checker.setIgnore(DUPLICATE_ENTRIES, true);
+ checker.checkTree(data);
}
@Test
@@ -1791,7 +1446,7 @@
@Test
public void testRejectNulInPathSegment() {
try {
- checker.checkPathSegment(Constants.encodeASCII("a\u0000b"), 0, 3);
+ checker.checkPathSegment(encodeASCII("a\u0000b"), 0, 3);
fail("incorrectly accepted NUL in middle of name");
} catch (CorruptObjectException e) {
assertEquals("name contains byte 0x00", e.getMessage());
@@ -1893,13 +1548,65 @@
private void checkOneName(String name) throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 " + name);
- checker.checkTree(Constants.encodeASCII(b.toString()));
+ checker.checkTree(encodeASCII(b.toString()));
}
- private static void entry(final StringBuilder b, final String modeName) {
+ private static void entry(StringBuilder b, final String modeName) {
b.append(modeName);
b.append('\0');
- for (int i = 0; i < Constants.OBJECT_ID_LENGTH; i++)
+ for (int i = 0; i < OBJECT_ID_LENGTH; i++)
b.append((char) i);
}
+
+ private void assertCorrupt(String msg, int type, StringBuilder b) {
+ assertCorrupt(msg, type, encodeASCII(b.toString()));
+ }
+
+ private void assertCorrupt(String msg, int type, byte[] data) {
+ try {
+ checker.check(type, data);
+ fail("Did not throw CorruptObjectException");
+ } catch (CorruptObjectException e) {
+ assertEquals(msg, e.getMessage());
+ }
+ }
+
+ private void assertSkipListAccepts(int type, byte[] data)
+ throws CorruptObjectException {
+ ObjectId id = idFor(type, data);
+ checker.setSkipList(set(id));
+ checker.check(id, type, data);
+ checker.setSkipList(null);
+ }
+
+ private void assertSkipListRejects(String msg, int type, byte[] data) {
+ ObjectId id = idFor(type, data);
+ checker.setSkipList(set(id));
+ try {
+ checker.check(id, type, data);
+ fail("Did not throw CorruptObjectException");
+ } catch (CorruptObjectException e) {
+ assertEquals(msg, e.getMessage());
+ }
+ checker.setSkipList(null);
+ }
+
+ private static ObjectIdSet set(final ObjectId... ids) {
+ return new ObjectIdSet() {
+ @Override
+ public boolean contains(AnyObjectId objectId) {
+ for (ObjectId id : ids) {
+ if (id.equals(objectId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+ }
+
+ @SuppressWarnings("resource")
+ private static ObjectId idFor(int type, byte[] raw) {
+ return new ObjectInserter.Formatter().idFor(type, raw);
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
index 99d6801..aa46d1a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
@@ -82,38 +82,42 @@
}
FileTreeIteratorWithTimeControl fileIt = new FileTreeIteratorWithTimeControl(
db, modTimes);
- NameConflictTreeWalk tw = new NameConflictTreeWalk(db);
- tw.addTree(fileIt);
- tw.setRecursive(true);
- FileTreeIterator t;
- long t0 = 0;
- for (int i = 0; i < 10; i++) {
- assertTrue(tw.next());
- t = tw.getTree(0, FileTreeIterator.class);
- if (i == 0)
- t0 = t.getEntryLastModified();
- else
- assertEquals(t0, t.getEntryLastModified());
- }
- long t1 = 0;
- for (int i = 0; i < 10; i++) {
- assertTrue(tw.next());
- t = tw.getTree(0, FileTreeIterator.class);
- if (i == 0) {
- t1 = t.getEntryLastModified();
- assertTrue(t1 > t0);
- } else
- assertEquals(t1, t.getEntryLastModified());
- }
- long t2 = 0;
- for (int i = 0; i < 10; i++) {
- assertTrue(tw.next());
- t = tw.getTree(0, FileTreeIterator.class);
- if (i == 0) {
- t2 = t.getEntryLastModified();
- assertTrue(t2 > t1);
- } else
- assertEquals(t2, t.getEntryLastModified());
+ try (NameConflictTreeWalk tw = new NameConflictTreeWalk(db)) {
+ tw.addTree(fileIt);
+ tw.setRecursive(true);
+ FileTreeIterator t;
+ long t0 = 0;
+ for (int i = 0; i < 10; i++) {
+ assertTrue(tw.next());
+ t = tw.getTree(0, FileTreeIterator.class);
+ if (i == 0) {
+ t0 = t.getEntryLastModified();
+ } else {
+ assertEquals(t0, t.getEntryLastModified());
+ }
+ }
+ long t1 = 0;
+ for (int i = 0; i < 10; i++) {
+ assertTrue(tw.next());
+ t = tw.getTree(0, FileTreeIterator.class);
+ if (i == 0) {
+ t1 = t.getEntryLastModified();
+ assertTrue(t1 > t0);
+ } else {
+ assertEquals(t1, t.getEntryLastModified());
+ }
+ }
+ long t2 = 0;
+ for (int i = 0; i < 10; i++) {
+ assertTrue(tw.next());
+ t = tw.getTree(0, FileTreeIterator.class);
+ if (i == 0) {
+ t2 = t.getEntryLastModified();
+ assertTrue(t2 > t1);
+ } else {
+ assertEquals(t2, t.getEntryLastModified());
+ }
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
index 109f401..707757b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
@@ -163,7 +163,7 @@
@Test
public void testReadSymRefToPacked() throws IOException {
writeSymref("HEAD", "refs/heads/b");
- Ref ref = db.getRef("HEAD");
+ Ref ref = db.exactRef("HEAD");
assertEquals(Ref.Storage.LOOSE, ref.getStorage());
assertTrue("is symref", ref.isSymbolic());
ref = ref.getTarget();
@@ -181,7 +181,7 @@
assertEquals(Result.FORCED, update); // internal
writeSymref("HEAD", "refs/heads/master");
- Ref ref = db.getRef("HEAD");
+ Ref ref = db.exactRef("HEAD");
assertEquals(Ref.Storage.LOOSE, ref.getStorage());
ref = ref.getTarget();
assertEquals("refs/heads/master", ref.getName());
@@ -194,13 +194,13 @@
updateRef.setNewObjectId(db.resolve("refs/heads/master"));
Result update = updateRef.update();
assertEquals(Result.NEW, update);
- Ref ref = db.getRef("ref/heads/new");
+ Ref ref = db.exactRef("ref/heads/new");
assertEquals(Storage.LOOSE, ref.getStorage());
}
@Test
public void testGetShortRef() throws IOException {
- Ref ref = db.getRef("master");
+ Ref ref = db.exactRef("refs/heads/master");
assertEquals("refs/heads/master", ref.getName());
assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
}
@@ -222,7 +222,7 @@
assertNull(db.getRefDatabase().exactRef("refs/foo/bar"));
- Ref ref = db.getRef("refs/foo/bar");
+ Ref ref = db.findRef("refs/foo/bar");
assertEquals("refs/heads/refs/foo/bar", ref.getName());
assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
}
@@ -237,7 +237,7 @@
assertEquals("refs/foo/bar", exactRef.getName());
assertEquals(masterId, exactRef.getObjectId());
- Ref ref = db.getRef("refs/foo/bar");
+ Ref ref = db.findRef("refs/foo/bar");
assertEquals("refs/foo/bar", ref.getName());
assertEquals(masterId, ref.getObjectId());
}
@@ -251,7 +251,7 @@
@Test
public void testReadLoosePackedRef() throws IOException,
InterruptedException {
- Ref ref = db.getRef("refs/heads/master");
+ Ref ref = db.exactRef("refs/heads/master");
assertEquals(Storage.PACKED, ref.getStorage());
FileOutputStream os = new FileOutputStream(new File(db.getDirectory(),
"refs/heads/master"));
@@ -259,7 +259,7 @@
os.write('\n');
os.close();
- ref = db.getRef("refs/heads/master");
+ ref = db.exactRef("refs/heads/master");
assertEquals(Storage.LOOSE, ref.getStorage());
}
@@ -271,7 +271,7 @@
*/
@Test
public void testReadSimplePackedRefSameRepo() throws IOException {
- Ref ref = db.getRef("refs/heads/master");
+ Ref ref = db.exactRef("refs/heads/master");
ObjectId pid = db.resolve("refs/heads/master^");
assertEquals(Storage.PACKED, ref.getStorage());
RefUpdate updateRef = db.updateRef("refs/heads/master");
@@ -280,19 +280,19 @@
Result update = updateRef.update();
assertEquals(Result.FORCED, update);
- ref = db.getRef("refs/heads/master");
+ ref = db.exactRef("refs/heads/master");
assertEquals(Storage.LOOSE, ref.getStorage());
}
@Test
public void testResolvedNamesBranch() throws IOException {
- Ref ref = db.getRef("a");
+ Ref ref = db.findRef("a");
assertEquals("refs/heads/a", ref.getName());
}
@Test
public void testResolvedSymRef() throws IOException {
- Ref ref = db.getRef(Constants.HEAD);
+ Ref ref = db.exactRef(Constants.HEAD);
assertEquals(Constants.HEAD, ref.getName());
assertTrue("is symbolic ref", ref.isSymbolic());
assertSame(Ref.Storage.LOOSE, ref.getStorage());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java
index 7b6d7d4..df1a52d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java
@@ -70,8 +70,7 @@
// do one commit and check that reflog size is 0: no reflogs should be
// written
- commit("A Commit\n", new PersonIdent(author, commitTime, tz),
- new PersonIdent(committer, commitTime, tz));
+ commit("A Commit\n", commitTime, tz);
commitTime += 60 * 1000;
assertTrue(
"Reflog for HEAD still contain no entry",
@@ -83,8 +82,7 @@
assertTrue(cfg.get(CoreConfig.KEY).isLogAllRefUpdates());
// do one commit and check that reflog size is increased to 1
- commit("A Commit\n", new PersonIdent(author, commitTime, tz),
- new PersonIdent(committer, commitTime, tz));
+ commit("A Commit\n", commitTime, tz);
commitTime += 60 * 1000;
assertTrue(
"Reflog for HEAD should contain one entry",
@@ -96,18 +94,17 @@
assertFalse(cfg.get(CoreConfig.KEY).isLogAllRefUpdates());
// do one commit and check that reflog size is 2
- commit("A Commit\n", new PersonIdent(author, commitTime, tz),
- new PersonIdent(committer, commitTime, tz));
+ commit("A Commit\n", commitTime, tz);
assertTrue(
"Reflog for HEAD should contain two entries",
db.getReflogReader(Constants.HEAD).getReverseEntries().size() == 2);
}
- private void commit(String commitMsg, PersonIdent author,
- PersonIdent committer) throws IOException {
+ private void commit(String commitMsg, long commitTime, int tz)
+ throws IOException {
final CommitBuilder commit = new CommitBuilder();
- commit.setAuthor(author);
- commit.setCommitter(committer);
+ commit.setAuthor(new PersonIdent(author, commitTime, tz));
+ commit.setCommitter(new PersonIdent(committer, commitTime, tz));
commit.setMessage(commitMsg);
ObjectId id;
try (ObjectInserter inserter = db.newObjectInserter()) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java
index 75d74fc..7db9f60 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java
@@ -60,117 +60,123 @@
@Test
public void resolveMasterCommits() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- RevCommit c1 = git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", "content2");
- git.add().addFilepattern("file.txt").call();
- RevCommit c2 = git.commit().setMessage("edit file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit c1 = git.commit().setMessage("create file").call();
+ writeTrashFile("file.txt", "content2");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit c2 = git.commit().setMessage("edit file").call();
- assertEquals(c2, db.resolve("master@{0}"));
- assertEquals(c1, db.resolve("master@{1}"));
+ assertEquals(c2, db.resolve("master@{0}"));
+ assertEquals(c1, db.resolve("master@{1}"));
+ }
}
@Test
public void resolveUnnamedCurrentBranchCommits() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- RevCommit c1 = git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", "content2");
- git.add().addFilepattern("file.txt").call();
- RevCommit c2 = git.commit().setMessage("edit file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit c1 = git.commit().setMessage("create file").call();
+ writeTrashFile("file.txt", "content2");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit c2 = git.commit().setMessage("edit file").call();
- assertEquals(c2, db.resolve("master@{0}"));
- assertEquals(c1, db.resolve("master@{1}"));
+ assertEquals(c2, db.resolve("master@{0}"));
+ assertEquals(c1, db.resolve("master@{1}"));
- git.checkout().setCreateBranch(true).setName("newbranch")
- .setStartPoint(c1).call();
+ git.checkout().setCreateBranch(true).setName("newbranch")
+ .setStartPoint(c1).call();
- // same as current branch, e.g. master
- assertEquals(c1, db.resolve("@{0}"));
- try {
+ // same as current branch, e.g. master
+ assertEquals(c1, db.resolve("@{0}"));
+ try {
+ assertEquals(c1, db.resolve("@{1}"));
+ fail(); // Looking at wrong ref, e.g HEAD
+ } catch (RevisionSyntaxException e) {
+ assertNotNull(e);
+ }
+
+ // detached head, read HEAD reflog
+ git.checkout().setName(c2.getName()).call();
+ assertEquals(c2, db.resolve("@{0}"));
assertEquals(c1, db.resolve("@{1}"));
- fail(); // Looking at wrong ref, e.g HEAD
- } catch (RevisionSyntaxException e) {
- assertNotNull(e);
+ assertEquals(c2, db.resolve("@{2}"));
}
-
- // detached head, read HEAD reflog
- git.checkout().setName(c2.getName()).call();
- assertEquals(c2, db.resolve("@{0}"));
- assertEquals(c1, db.resolve("@{1}"));
- assertEquals(c2, db.resolve("@{2}"));
}
@Test
public void resolveReflogParent() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- RevCommit c1 = git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", "content2");
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("edit file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit c1 = git.commit().setMessage("create file").call();
+ writeTrashFile("file.txt", "content2");
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("edit file").call();
- assertEquals(c1, db.resolve("master@{0}~1"));
+ assertEquals(c1, db.resolve("master@{0}~1"));
+ }
}
@Test
public void resolveNonExistingBranch() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("create file").call();
- assertNull(db.resolve("notabranch@{7}"));
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("create file").call();
+ assertNull(db.resolve("notabranch@{7}"));
+ }
}
@Test
public void resolvePreviousBranch() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- RevCommit c1 = git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", "content2");
- git.add().addFilepattern("file.txt").call();
- RevCommit c2 = git.commit().setMessage("edit file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit c1 = git.commit().setMessage("create file").call();
+ writeTrashFile("file.txt", "content2");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit c2 = git.commit().setMessage("edit file").call();
- git.checkout().setCreateBranch(true).setName("newbranch")
- .setStartPoint(c1).call();
+ git.checkout().setCreateBranch(true).setName("newbranch")
+ .setStartPoint(c1).call();
- git.checkout().setName(c1.getName()).call();
+ git.checkout().setName(c1.getName()).call();
- git.checkout().setName("master").call();
+ git.checkout().setName("master").call();
- assertEquals(c1.getName(), db.simplify("@{-1}"));
- assertEquals("newbranch", db.simplify("@{-2}"));
- assertEquals("master", db.simplify("@{-3}"));
+ assertEquals(c1.getName(), db.simplify("@{-1}"));
+ assertEquals("newbranch", db.simplify("@{-2}"));
+ assertEquals("master", db.simplify("@{-3}"));
- // chained expression
- try {
- // Cannot refer to reflog of detached head
- db.resolve("@{-1}@{0}");
- fail();
- } catch (RevisionSyntaxException e) {
- // good
+ // chained expression
+ try {
+ // Cannot refer to reflog of detached head
+ db.resolve("@{-1}@{0}");
+ fail();
+ } catch (RevisionSyntaxException e) {
+ // good
+ }
+ assertEquals(c1.getName(), db.resolve("@{-2}@{0}").getName());
+
+ assertEquals(c2.getName(), db.resolve("@{-3}@{0}").getName());
}
- assertEquals(c1.getName(), db.resolve("@{-2}@{0}").getName());
-
- assertEquals(c2.getName(), db.resolve("@{-3}@{0}").getName());
}
@Test
public void resolveDate() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("create file").call();
- try {
- db.resolve("master@{yesterday}");
- fail("Exception not thrown");
- } catch (RevisionSyntaxException e) {
- assertNotNull(e);
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("create file").call();
+ try {
+ db.resolve("master@{yesterday}");
+ fail("Exception not thrown");
+ } catch (RevisionSyntaxException e) {
+ assertNotNull(e);
+ }
}
}
}
\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java
index c9ea286..1d2a4e9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java
@@ -267,35 +267,37 @@
@Test
public void resolveExprSimple() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("create file").call();
- assertEquals("master", db.simplify("master"));
- assertEquals("refs/heads/master", db.simplify("refs/heads/master"));
- assertEquals("HEAD", db.simplify("HEAD"));
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("create file").call();
+ assertEquals("master", db.simplify("master"));
+ assertEquals("refs/heads/master", db.simplify("refs/heads/master"));
+ assertEquals("HEAD", db.simplify("HEAD"));
+ }
}
@Test
public void resolveUpstream() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- RevCommit c1 = git.commit().setMessage("create file").call();
- writeTrashFile("file2.txt", "content");
- RefUpdate updateRemoteRef = db.updateRef("refs/remotes/origin/main");
- updateRemoteRef.setNewObjectId(c1);
- updateRemoteRef.update();
- db.getConfig().setString("branch", "master", "remote", "origin");
- db.getConfig()
- .setString("branch", "master", "merge", "refs/heads/main");
- db.getConfig().setString("remote", "origin", "url",
- "git://example.com/here");
- db.getConfig().setString("remote", "origin", "fetch",
- "+refs/heads/*:refs/remotes/origin/*");
- git.add().addFilepattern("file2.txt").call();
- git.commit().setMessage("create file").call();
- assertEquals("refs/remotes/origin/main", db.simplify("@{upstream}"));
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit c1 = git.commit().setMessage("create file").call();
+ writeTrashFile("file2.txt", "content");
+ RefUpdate updateRemoteRef = db.updateRef("refs/remotes/origin/main");
+ updateRemoteRef.setNewObjectId(c1);
+ updateRemoteRef.update();
+ db.getConfig().setString("branch", "master", "remote", "origin");
+ db.getConfig()
+ .setString("branch", "master", "merge", "refs/heads/main");
+ db.getConfig().setString("remote", "origin", "url",
+ "git://example.com/here");
+ db.getConfig().setString("remote", "origin", "fetch",
+ "+refs/heads/*:refs/remotes/origin/*");
+ git.add().addFilepattern("file2.txt").call();
+ git.commit().setMessage("create file").call();
+ assertEquals("refs/remotes/origin/main", db.simplify("@{upstream}"));
+ }
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java
index 315c495..1515a07 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdentTest.java
@@ -75,11 +75,13 @@
p.toExternalString());
}
+ @SuppressWarnings("unused")
@Test(expected = IllegalArgumentException.class)
public void nullForNameShouldThrowIllegalArgumentException() {
new PersonIdent(null, "author@example.com");
}
+ @SuppressWarnings("unused")
@Test(expected = IllegalArgumentException.class)
public void nullForEmailShouldThrowIllegalArgumentException() {
new PersonIdent("A U Thor", null);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_TreeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_TreeTest.java
deleted file mode 100644
index 651e62c..0000000
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_TreeTest.java
+++ /dev/null
@@ -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());
- }
-}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java
index 21ef747..6c90f7d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java
@@ -84,44 +84,44 @@
@Test
public void testOneBranch() throws IOException {
- Ref a = db.getRef("refs/heads/a");
- Ref master = db.getRef("refs/heads/master");
+ Ref a = db.exactRef("refs/heads/a");
+ Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(a), master);
assertEquals("Merge branch 'a'", message);
}
@Test
public void testTwoBranches() throws IOException {
- Ref a = db.getRef("refs/heads/a");
- Ref b = db.getRef("refs/heads/b");
- Ref master = db.getRef("refs/heads/master");
+ Ref a = db.exactRef("refs/heads/a");
+ Ref b = db.exactRef("refs/heads/b");
+ Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(a, b), master);
assertEquals("Merge branches 'a' and 'b'", message);
}
@Test
public void testThreeBranches() throws IOException {
- Ref c = db.getRef("refs/heads/c");
- Ref b = db.getRef("refs/heads/b");
- Ref a = db.getRef("refs/heads/a");
- Ref master = db.getRef("refs/heads/master");
+ Ref c = db.exactRef("refs/heads/c");
+ Ref b = db.exactRef("refs/heads/b");
+ Ref a = db.exactRef("refs/heads/a");
+ Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(c, b, a), master);
assertEquals("Merge branches 'c', 'b' and 'a'", message);
}
@Test
public void testRemoteBranch() throws Exception {
- Ref remoteA = db.getRef("refs/remotes/origin/remote-a");
- Ref master = db.getRef("refs/heads/master");
+ Ref remoteA = db.exactRef("refs/remotes/origin/remote-a");
+ Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(remoteA), master);
assertEquals("Merge remote-tracking branch 'origin/remote-a'", message);
}
@Test
public void testMixed() throws IOException {
- Ref c = db.getRef("refs/heads/c");
- Ref remoteA = db.getRef("refs/remotes/origin/remote-a");
- Ref master = db.getRef("refs/heads/master");
+ Ref c = db.exactRef("refs/heads/c");
+ Ref remoteA = db.exactRef("refs/remotes/origin/remote-a");
+ Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(c, remoteA), master);
assertEquals("Merge branch 'c', remote-tracking branch 'origin/remote-a'",
message);
@@ -129,8 +129,8 @@
@Test
public void testTag() throws IOException {
- Ref tagA = db.getRef("refs/tags/A");
- Ref master = db.getRef("refs/heads/master");
+ Ref tagA = db.exactRef("refs/tags/A");
+ Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(tagA), master);
assertEquals("Merge tag 'A'", message);
}
@@ -141,7 +141,7 @@
.fromString("6db9c2ebf75590eef973081736730a9ea169a0c4");
Ref commit = new ObjectIdRef.Unpeeled(Storage.LOOSE,
objectId.getName(), objectId);
- Ref master = db.getRef("refs/heads/master");
+ Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(commit), master);
assertEquals("Merge commit '6db9c2ebf75590eef973081736730a9ea169a0c4'",
message);
@@ -154,7 +154,7 @@
.fromString("6db9c2ebf75590eef973081736730a9ea169a0c4");
Ref remoteBranch = new ObjectIdRef.Unpeeled(Storage.LOOSE, name,
objectId);
- Ref master = db.getRef("refs/heads/master");
+ Ref master = db.exactRef("refs/heads/master");
String message = formatter.format(Arrays.asList(remoteBranch), master);
assertEquals("Merge branch 'test' of http://egit.eclipse.org/jgit.git",
message);
@@ -162,16 +162,16 @@
@Test
public void testIntoOtherThanMaster() throws IOException {
- Ref a = db.getRef("refs/heads/a");
- Ref b = db.getRef("refs/heads/b");
+ Ref a = db.exactRef("refs/heads/a");
+ Ref b = db.exactRef("refs/heads/b");
String message = formatter.format(Arrays.asList(a), b);
assertEquals("Merge branch 'a' into b", message);
}
@Test
public void testIntoHeadOtherThanMaster() throws IOException {
- Ref a = db.getRef("refs/heads/a");
- Ref b = db.getRef("refs/heads/b");
+ Ref a = db.exactRef("refs/heads/a");
+ Ref b = db.exactRef("refs/heads/b");
SymbolicRef head = new SymbolicRef("HEAD", b);
String message = formatter.format(Arrays.asList(a), head);
assertEquals("Merge branch 'a' into b", message);
@@ -179,8 +179,8 @@
@Test
public void testIntoSymbolicRefHeadPointingToMaster() throws IOException {
- Ref a = db.getRef("refs/heads/a");
- Ref master = db.getRef("refs/heads/master");
+ Ref a = db.exactRef("refs/heads/a");
+ Ref master = db.exactRef("refs/heads/master");
SymbolicRef head = new SymbolicRef("HEAD", master);
String message = formatter.format(Arrays.asList(a), head);
assertEquals("Merge branch 'a'", message);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
index 7ef6448..0e7109c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
@@ -872,32 +872,31 @@
private String contentAsString(Repository r, ObjectId treeId, String path)
throws MissingObjectException, IOException {
- TreeWalk tw = new TreeWalk(r);
- tw.addTree(treeId);
- tw.setFilter(PathFilter.create(path));
- tw.setRecursive(true);
- if (!tw.next())
- return null;
- AnyObjectId blobId = tw.getObjectId(0);
+ AnyObjectId blobId;
+ try (TreeWalk tw = new TreeWalk(r)) {
+ tw.addTree(treeId);
+ tw.setFilter(PathFilter.create(path));
+ tw.setRecursive(true);
+ if (!tw.next()) {
+ return null;
+ }
+ blobId = tw.getObjectId(0);
+ }
StringBuilder result = new StringBuilder();
- BufferedReader br = null;
ObjectReader or = r.newObjectReader();
- try {
- br = new BufferedReader(new InputStreamReader(or.open(blobId)
- .openStream()));
+ try (BufferedReader br = new BufferedReader(
+ new InputStreamReader(or.open(blobId).openStream()))) {
String line;
boolean first = true;
while ((line = br.readLine()) != null) {
- if (!first)
+ if (!first) {
result.append('\n');
+ }
result.append(line);
first = false;
}
return result.toString();
- } finally {
- if (br != null)
- br.close();
}
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
index cd6a4be..55bb93a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/ResolveMergerTest.java
@@ -88,35 +88,36 @@
file = new File(folder1, "file2.txt");
write(file, "folder1--file2.txt");
- Git git = new Git(db);
- git.add().addFilepattern(folder1.getName()).call();
- RevCommit base = git.commit().setMessage("adding folder").call();
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(folder1.getName()).call();
+ RevCommit base = git.commit().setMessage("adding folder").call();
- recursiveDelete(folder1);
- git.rm().addFilepattern("folder1/file1.txt")
- .addFilepattern("folder1/file2.txt").call();
- RevCommit other = git.commit()
- .setMessage("removing folders on 'other'").call();
+ recursiveDelete(folder1);
+ git.rm().addFilepattern("folder1/file1.txt")
+ .addFilepattern("folder1/file2.txt").call();
+ RevCommit other = git.commit()
+ .setMessage("removing folders on 'other'").call();
- git.checkout().setName(base.name()).call();
+ git.checkout().setName(base.name()).call();
- file = new File(db.getWorkTree(), "unrelated.txt");
- write(file, "unrelated");
+ file = new File(db.getWorkTree(), "unrelated.txt");
+ write(file, "unrelated");
- git.add().addFilepattern("unrelated.txt").call();
- RevCommit head = git.commit().setMessage("Adding another file").call();
+ git.add().addFilepattern("unrelated.txt").call();
+ RevCommit head = git.commit().setMessage("Adding another file").call();
- // Untracked file to cause failing path for delete() of folder1
- // but that's ok.
- file = new File(folder1, "file3.txt");
- write(file, "folder1--file3.txt");
+ // Untracked file to cause failing path for delete() of folder1
+ // but that's ok.
+ file = new File(folder1, "file3.txt");
+ write(file, "folder1--file3.txt");
- ResolveMerger merger = (ResolveMerger) strategy.newMerger(db, false);
- merger.setCommitNames(new String[] { "BASE", "HEAD", "other" });
- merger.setWorkingTreeIterator(new FileTreeIterator(db));
- boolean ok = merger.merge(head.getId(), other.getId());
- assertTrue(ok);
- assertTrue(file.exists());
+ ResolveMerger merger = (ResolveMerger) strategy.newMerger(db, false);
+ merger.setCommitNames(new String[] { "BASE", "HEAD", "other" });
+ merger.setWorkingTreeIterator(new FileTreeIterator(db));
+ boolean ok = merger.merge(head.getId(), other.getId());
+ assertTrue(ok);
+ assertTrue(file.exists());
+ }
}
/**
@@ -630,7 +631,7 @@
// ResolveMerge
try {
MergeResult mergeResult = git.merge().setStrategy(strategy)
- .include(git.getRepository().getRef("refs/heads/side"))
+ .include(git.getRepository().exactRef("refs/heads/side"))
.call();
assertEquals(MergeStrategy.RECURSIVE, strategy);
assertEquals(MergeResult.MergeStatus.MERGED,
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SquashMessageFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SquashMessageFormatterTest.java
index b7b2291..7a2586d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SquashMessageFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SquashMessageFormatterTest.java
@@ -73,17 +73,18 @@
@Test
public void testCommit() throws Exception {
- Git git = new Git(db);
- revCommit = git.commit().setMessage("squash_me").call();
+ try (Git git = new Git(db)) {
+ revCommit = git.commit().setMessage("squash_me").call();
- Ref master = db.getRef("refs/heads/master");
- String message = msgFormatter.format(Arrays.asList(revCommit), master);
- assertEquals(
- "Squashed commit of the following:\n\ncommit "
- + revCommit.getName() + "\nAuthor: "
- + revCommit.getAuthorIdent().getName() + " <"
- + revCommit.getAuthorIdent().getEmailAddress()
- + ">\nDate: " + dateFormatter.formatDate(author)
- + "\n\n\tsquash_me\n", message);
+ Ref master = db.exactRef("refs/heads/master");
+ String message = msgFormatter.format(Arrays.asList(revCommit), master);
+ assertEquals(
+ "Squashed commit of the following:\n\ncommit "
+ + revCommit.getName() + "\nAuthor: "
+ + revCommit.getAuthorIdent().getName() + " <"
+ + revCommit.getAuthorIdent().getEmailAddress()
+ + ">\nDate: " + dateFormatter.formatDate(author)
+ + "\n\n\tsquash_me\n", message);
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java
index 4539a01..47b08a7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java
@@ -403,10 +403,12 @@
}
RevCommit n = commitNoteMap(map);
- TreeWalk tw = new TreeWalk(reader);
- tw.reset(n.getTree());
- while (tw.next())
- assertFalse("no fan-out subtree", tw.isSubtree());
+ try (TreeWalk tw = new TreeWalk(reader)) {
+ tw.reset(n.getTree());
+ while (tw.next()) {
+ assertFalse("no fan-out subtree", tw.isSubtree());
+ }
+ }
for (int i = 254; i < 256; i++) {
idBuf.setByte(Constants.OBJECT_ID_LENGTH - 1, i);
@@ -418,13 +420,15 @@
// The 00 bucket is fully split.
String path = fanout(38, idBuf.name());
- tw = TreeWalk.forPath(reader, path, n.getTree());
- assertNotNull("has " + path, tw);
+ try (TreeWalk tw = TreeWalk.forPath(reader, path, n.getTree())) {
+ assertNotNull("has " + path, tw);
+ }
// The other bucket is not.
path = fanout(2, data1.name());
- tw = TreeWalk.forPath(reader, path, n.getTree());
- assertNotNull("has " + path, tw);
+ try (TreeWalk tw = TreeWalk.forPath(reader, path, n.getTree())) {
+ assertNotNull("has " + path, tw);
+ }
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java
index 2a59f58..e5ad313 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java
@@ -47,14 +47,12 @@
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")
public class ObjectWalkTest extends RevWalkTestCase {
protected ObjectWalk objw;
@@ -220,28 +218,24 @@
.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);
+ try (ObjectInserter inserter = db.newObjectInserter()) {
+ ObjectId empty = inserter.insert(new TreeFormatter());
- Tree A_A = A.addTree("A");
- Tree A_B = A.addTree("B");
+ TreeFormatter A = new TreeFormatter();
+ A.append("A", FileMode.TREE, empty);
+ A.append("B", FileMode.TREE, empty);
+ ObjectId idA = inserter.insert(A);
- 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();
- }
+ 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 = 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()));
+ tree_root = objw.parseTree(idRoot);
+ tree_A = objw.parseTree(idA);
+ tree_AB = objw.parseTree(empty);
+ b = commit(tree_root);
}
markStart(b);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitListTest.java
index 5ec6eb3..4d75322 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitListTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitListTest.java
@@ -57,14 +57,15 @@
private RevCommitList<RevCommit> list;
public void setup(int count) throws Exception {
- Git git = new Git(db);
- for (int i = 0; i < count; i++)
- git.commit().setCommitter(committer).setAuthor(author)
- .setMessage("commit " + i).call();
- list = new RevCommitList<RevCommit>();
- RevWalk w = new RevWalk(db);
- w.markStart(w.lookupCommit(db.resolve(Constants.HEAD)));
- list.source(w);
+ try (Git git = new Git(db);
+ RevWalk w = new RevWalk(db);) {
+ for (int i = 0; i < count; i++)
+ git.commit().setCommitter(committer).setAuthor(author)
+ .setMessage("commit " + i).call();
+ list = new RevCommitList<RevCommit>();
+ w.markStart(w.lookupCommit(db.resolve(Constants.HEAD)));
+ list.source(w);
+ }
}
@Test
@@ -107,17 +108,18 @@
public void testFillToCommit() throws Exception {
setup(3);
- RevWalk w = new RevWalk(db);
- w.markStart(w.lookupCommit(db.resolve(Constants.HEAD)));
+ try (RevWalk w = new RevWalk(db)) {
+ w.markStart(w.lookupCommit(db.resolve(Constants.HEAD)));
- w.next();
- RevCommit c = w.next();
- assertNotNull("should have found 2. commit", c);
+ w.next();
+ RevCommit c = w.next();
+ assertNotNull("should have found 2. commit", c);
- list.fillTo(c, 5);
- assertEquals(2, list.size());
- assertEquals("commit 1", list.get(1).getFullMessage());
- assertNull(list.get(3));
+ list.fillTo(c, 5);
+ assertEquals(2, list.size());
+ assertEquals("commit 1", list.get(1).getFullMessage());
+ assertNull(list.get(3));
+ }
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java
index beda2a7..1a15842 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java
@@ -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;
@@ -304,6 +309,86 @@
}
@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 = "";
final RevCommit c = create(msg);
@@ -367,9 +452,10 @@
@Test
public void testParse_PublicParseMethod()
throws UnsupportedEncodingException {
- ObjectInserter.Formatter fmt = new ObjectInserter.Formatter();
CommitBuilder src = new CommitBuilder();
- src.setTreeId(fmt.idFor(Constants.OBJ_TREE, new byte[] {}));
+ try (ObjectInserter.Formatter fmt = new ObjectInserter.Formatter()) {
+ src.setTreeId(fmt.idFor(Constants.OBJ_TREE, new byte[] {}));
+ }
src.setAuthor(author);
src.setCommitter(committer);
src.setMessage("Test commit\n\nThis is a test.\n");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java
index a768bef..95e7ca6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java
@@ -73,9 +73,12 @@
assertTrue(a1.equals((Object) a1));
assertFalse(a1.equals(""));
- final RevWalk rw2 = new RevWalk(db);
- final RevCommit a2 = rw2.parseCommit(a1);
- final RevCommit b2 = rw2.parseCommit(b1);
+ final RevCommit a2;
+ final RevCommit b2;
+ try (final RevWalk rw2 = new RevWalk(db)) {
+ a2 = rw2.parseCommit(a1);
+ b2 = rw2.parseCommit(b1);
+ }
assertNotSame(a1, a2);
assertNotSame(b1, b2);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java
index 614f49b..f97043b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java
@@ -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;
@@ -362,6 +363,44 @@
}
@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 = "";
final RevTag c = create(msg);
@@ -424,10 +463,11 @@
@Test
public void testParse_PublicParseMethod() throws CorruptObjectException {
- ObjectInserter.Formatter fmt = new ObjectInserter.Formatter();
TagBuilder src = new TagBuilder();
- src.setObjectId(fmt.idFor(Constants.OBJ_TREE, new byte[] {}),
- Constants.OBJ_TREE);
+ try (ObjectInserter.Formatter fmt = new ObjectInserter.Formatter()) {
+ src.setObjectId(fmt.idFor(Constants.OBJ_TREE, new byte[] {}),
+ Constants.OBJ_TREE);
+ }
src.setTagger(committer);
src.setTag("a.test");
src.setMessage("Test tag\n\nThis is a test.\n");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java
index 643ba26..8ab9728 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java
@@ -250,14 +250,14 @@
final RevCommit b = commit(a);
tick(100);
- Date since = getClock();
+ Date since = getDate();
final RevCommit c1 = commit(b);
tick(100);
final RevCommit c2 = commit(b);
tick(100);
- Date until = getClock();
+ Date until = getDate();
final RevCommit d = commit(c1, c2);
tick(100);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java
index 881deb1..30586ee 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java
@@ -70,8 +70,8 @@
return new RevWalk(db);
}
- protected Date getClock() {
- return util.getClock();
+ protected Date getDate() {
+ return util.getDate();
}
protected void tick(final int secDelta) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
index b13c4cd..a131e5e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
@@ -119,36 +119,37 @@
@Test
public void addSubmodule() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- RevCommit commit = git.commit().setMessage("create file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit = git.commit().setMessage("create file").call();
- SubmoduleAddCommand command = new SubmoduleAddCommand(db);
- String path = "sub";
- command.setPath(path);
- String uri = db.getDirectory().toURI().toString();
- command.setURI(uri);
- Repository repo = command.call();
- assertNotNull(repo);
- ObjectId subCommit = repo.resolve(Constants.HEAD);
- repo.close();
+ SubmoduleAddCommand command = new SubmoduleAddCommand(db);
+ String path = "sub";
+ command.setPath(path);
+ String uri = db.getDirectory().toURI().toString();
+ command.setURI(uri);
+ Repository repo = command.call();
+ assertNotNull(repo);
+ ObjectId subCommit = repo.resolve(Constants.HEAD);
+ repo.close();
- SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
- assertTrue(generator.next());
- assertEquals(path, generator.getPath());
- assertEquals(commit, generator.getObjectId());
- assertEquals(uri, generator.getModulesUrl());
- assertEquals(path, generator.getModulesPath());
- assertEquals(uri, generator.getConfigUrl());
- Repository subModRepo = generator.getRepository();
- assertNotNull(subModRepo);
- assertEquals(subCommit, commit);
- subModRepo.close();
+ SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertEquals(path, generator.getPath());
+ assertEquals(commit, generator.getObjectId());
+ assertEquals(uri, generator.getModulesUrl());
+ assertEquals(path, generator.getModulesPath());
+ assertEquals(uri, generator.getConfigUrl());
+ Repository subModRepo = generator.getRepository();
+ assertNotNull(subModRepo);
+ assertEquals(subCommit, commit);
+ subModRepo.close();
- Status status = Git.wrap(db).status().call();
- assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES));
- assertTrue(status.getAdded().contains(path));
+ Status status = Git.wrap(db).status().call();
+ assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES));
+ assertTrue(status.getAdded().contains(path));
+ }
}
@Test
@@ -182,45 +183,47 @@
@Test
public void addSubmoduleWithRelativeUri() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- RevCommit commit = git.commit().setMessage("create file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit = git.commit().setMessage("create file").call();
- SubmoduleAddCommand command = new SubmoduleAddCommand(db);
- String path = "sub";
- String uri = "./.git";
- command.setPath(path);
- command.setURI(uri);
- Repository repo = command.call();
- assertNotNull(repo);
- addRepoToClose(repo);
+ SubmoduleAddCommand command = new SubmoduleAddCommand(db);
+ String path = "sub";
+ String uri = "./.git";
+ command.setPath(path);
+ command.setURI(uri);
+ Repository repo = command.call();
+ assertNotNull(repo);
+ addRepoToClose(repo);
- SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
- assertTrue(generator.next());
- assertEquals(path, generator.getPath());
- assertEquals(commit, generator.getObjectId());
- assertEquals(uri, generator.getModulesUrl());
- assertEquals(path, generator.getModulesPath());
- String fullUri = db.getDirectory().getAbsolutePath();
- if (File.separatorChar == '\\')
- fullUri = fullUri.replace('\\', '/');
- assertEquals(fullUri, generator.getConfigUrl());
- Repository subModRepo = generator.getRepository();
- assertNotNull(subModRepo);
- assertEquals(
- fullUri,
- subModRepo
- .getConfig()
- .getString(ConfigConstants.CONFIG_REMOTE_SECTION,
- Constants.DEFAULT_REMOTE_NAME,
- ConfigConstants.CONFIG_KEY_URL));
- subModRepo.close();
- assertEquals(commit, repo.resolve(Constants.HEAD));
+ SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertEquals(path, generator.getPath());
+ assertEquals(commit, generator.getObjectId());
+ assertEquals(uri, generator.getModulesUrl());
+ assertEquals(path, generator.getModulesPath());
+ String fullUri = db.getDirectory().getAbsolutePath();
+ if (File.separatorChar == '\\') {
+ fullUri = fullUri.replace('\\', '/');
+ }
+ assertEquals(fullUri, generator.getConfigUrl());
+ Repository subModRepo = generator.getRepository();
+ assertNotNull(subModRepo);
+ assertEquals(
+ fullUri,
+ subModRepo
+ .getConfig()
+ .getString(ConfigConstants.CONFIG_REMOTE_SECTION,
+ Constants.DEFAULT_REMOTE_NAME,
+ ConfigConstants.CONFIG_KEY_URL));
+ subModRepo.close();
+ assertEquals(commit, repo.resolve(Constants.HEAD));
- Status status = Git.wrap(db).status().call();
- assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES));
- assertTrue(status.getAdded().contains(path));
+ Status status = Git.wrap(db).status().call();
+ assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES));
+ assertTrue(status.getAdded().contains(path));
+ }
}
@Test
@@ -237,31 +240,32 @@
path1, ConfigConstants.CONFIG_KEY_URL, url1);
modulesConfig.save();
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- assertNotNull(git.commit().setMessage("create file").call());
+ try (Git git = new Git(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ assertNotNull(git.commit().setMessage("create file").call());
- SubmoduleAddCommand command = new SubmoduleAddCommand(db);
- command.setPath(path2);
- String url2 = db.getDirectory().toURI().toString();
- command.setURI(url2);
- Repository r = command.call();
- assertNotNull(r);
- addRepoToClose(r);
+ SubmoduleAddCommand command = new SubmoduleAddCommand(db);
+ command.setPath(path2);
+ String url2 = db.getDirectory().toURI().toString();
+ command.setURI(url2);
+ Repository r = command.call();
+ assertNotNull(r);
+ addRepoToClose(r);
- modulesConfig.load();
- assertEquals(path1, modulesConfig.getString(
- ConfigConstants.CONFIG_SUBMODULE_SECTION, path1,
- ConfigConstants.CONFIG_KEY_PATH));
- assertEquals(url1, modulesConfig.getString(
- ConfigConstants.CONFIG_SUBMODULE_SECTION, path1,
- ConfigConstants.CONFIG_KEY_URL));
- assertEquals(path2, modulesConfig.getString(
- ConfigConstants.CONFIG_SUBMODULE_SECTION, path2,
- ConfigConstants.CONFIG_KEY_PATH));
- assertEquals(url2, modulesConfig.getString(
- ConfigConstants.CONFIG_SUBMODULE_SECTION, path2,
- ConfigConstants.CONFIG_KEY_URL));
+ modulesConfig.load();
+ assertEquals(path1, modulesConfig.getString(
+ ConfigConstants.CONFIG_SUBMODULE_SECTION, path1,
+ ConfigConstants.CONFIG_KEY_PATH));
+ assertEquals(url1, modulesConfig.getString(
+ ConfigConstants.CONFIG_SUBMODULE_SECTION, path1,
+ ConfigConstants.CONFIG_KEY_URL));
+ assertEquals(path2, modulesConfig.getString(
+ ConfigConstants.CONFIG_SUBMODULE_SECTION, path2,
+ ConfigConstants.CONFIG_KEY_PATH));
+ assertEquals(url2, modulesConfig.getString(
+ ConfigConstants.CONFIG_SUBMODULE_SECTION, path2,
+ ConfigConstants.CONFIG_KEY_URL));
+ }
}
}
\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/symlinks/SymlinksTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/symlinks/SymlinksTest.java
index 3ddc3de..274fa53 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/symlinks/SymlinksTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/symlinks/SymlinksTest.java
@@ -75,26 +75,27 @@
*/
@Test
public void fileModeTestFileThenSymlink() throws Exception {
- Git git = new Git(db);
- writeTrashFile("a", "Hello world a");
- writeTrashFile("b", "Hello world b");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add files a & b").call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- git.rm().addFilepattern("a").call();
- FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "b");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("add symlink a").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "Hello world a");
+ writeTrashFile("b", "Hello world b");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add files a & b").call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ git.rm().addFilepattern("a").call();
+ FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "b");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("add symlink a").call();
- FileEntry entry = new FileTreeIterator.FileEntry(new File(
- db.getWorkTree(), "a"), db.getFS());
- assertEquals(FileMode.SYMLINK, entry.getMode());
+ FileEntry entry = new FileTreeIterator.FileEntry(new File(
+ db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.SYMLINK, entry.getMode());
- git.checkout().setName(branch_1.getName()).call();
+ git.checkout().setName(branch_1.getName()).call();
- entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
- db.getFS());
- assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
+ db.getFS());
+ assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ }
}
/**
@@ -108,26 +109,27 @@
*/
@Test
public void fileModeTestSymlinkThenFile() throws Exception {
- Git git = new Git(db);
- writeTrashFile("b", "Hello world b");
- FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "b");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add file b & symlink a").call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- git.rm().addFilepattern("a").call();
- writeTrashFile("a", "Hello world a");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("add file a").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("b", "Hello world b");
+ FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "b");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add file b & symlink a").call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ git.rm().addFilepattern("a").call();
+ writeTrashFile("a", "Hello world a");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("add file a").call();
- FileEntry entry = new FileTreeIterator.FileEntry(new File(
- db.getWorkTree(), "a"), db.getFS());
- assertEquals(FileMode.REGULAR_FILE, entry.getMode());
+ FileEntry entry = new FileTreeIterator.FileEntry(new File(
+ db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.REGULAR_FILE, entry.getMode());
- git.checkout().setName(branch_1.getName()).call();
+ git.checkout().setName(branch_1.getName()).call();
- entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
- db.getFS());
- assertEquals(FileMode.SYMLINK, entry.getMode());
+ entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
+ db.getFS());
+ assertEquals(FileMode.SYMLINK, entry.getMode());
+ }
}
/**
@@ -141,27 +143,28 @@
*/
@Test
public void fileModeTestFolderThenSymlink() throws Exception {
- Git git = new Git(db);
- FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
- writeTrashFile("a/b", "Hello world b");
- writeTrashFile("c", "Hello world c");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add folder a").call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- git.rm().addFilepattern("a").call();
- FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "c");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("add symlink a").call();
+ try (Git git = new Git(db)) {
+ FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
+ writeTrashFile("a/b", "Hello world b");
+ writeTrashFile("c", "Hello world c");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add folder a").call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ git.rm().addFilepattern("a").call();
+ FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "c");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("add symlink a").call();
- FileEntry entry = new FileTreeIterator.FileEntry(new File(
- db.getWorkTree(), "a"), db.getFS());
- assertEquals(FileMode.SYMLINK, entry.getMode());
+ FileEntry entry = new FileTreeIterator.FileEntry(new File(
+ db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.SYMLINK, entry.getMode());
- git.checkout().setName(branch_1.getName()).call();
+ git.checkout().setName(branch_1.getName()).call();
- entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
- db.getFS());
- assertEquals(FileMode.TREE, entry.getMode());
+ entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
+ db.getFS());
+ assertEquals(FileMode.TREE, entry.getMode());
+ }
}
/**
@@ -175,27 +178,28 @@
*/
@Test
public void fileModeTestSymlinkThenFolder() throws Exception {
- Git git = new Git(db);
- writeTrashFile("c", "Hello world c");
- FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "c");
- git.add().addFilepattern(".").call();
- git.commit().setMessage("add symlink a").call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- git.rm().addFilepattern("a").call();
- FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
- writeTrashFile("a/b", "Hello world b");
- git.add().addFilepattern("a").call();
- git.commit().setMessage("add folder a").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("c", "Hello world c");
+ FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "c");
+ git.add().addFilepattern(".").call();
+ git.commit().setMessage("add symlink a").call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ git.rm().addFilepattern("a").call();
+ FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
+ writeTrashFile("a/b", "Hello world b");
+ git.add().addFilepattern("a").call();
+ git.commit().setMessage("add folder a").call();
- FileEntry entry = new FileTreeIterator.FileEntry(new File(
- db.getWorkTree(), "a"), db.getFS());
- assertEquals(FileMode.TREE, entry.getMode());
+ FileEntry entry = new FileTreeIterator.FileEntry(new File(
+ db.getWorkTree(), "a"), db.getFS());
+ assertEquals(FileMode.TREE, entry.getMode());
- git.checkout().setName(branch_1.getName()).call();
+ git.checkout().setName(branch_1.getName()).call();
- entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
- db.getFS());
- assertEquals(FileMode.SYMLINK, entry.getMode());
+ entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
+ db.getFS());
+ assertEquals(FileMode.SYMLINK, entry.getMode());
+ }
}
/**
@@ -209,24 +213,25 @@
*/
@Test
public void fileModeTestMissingThenSymlink() throws Exception {
- Git git = new Git(db);
- writeTrashFile("b", "Hello world b");
- git.add().addFilepattern(".").call();
- RevCommit commit1 = git.commit().setMessage("add file b").call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "b");
- git.add().addFilepattern("a").call();
- RevCommit commit2 = git.commit().setMessage("add symlink a").call();
+ try (Git git = new Git(db);
+ TreeWalk tw = new TreeWalk(db);) {
+ writeTrashFile("b", "Hello world b");
+ git.add().addFilepattern(".").call();
+ RevCommit commit1 = git.commit().setMessage("add file b").call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "b");
+ git.add().addFilepattern("a").call();
+ RevCommit commit2 = git.commit().setMessage("add symlink a").call();
- git.checkout().setName(branch_1.getName()).call();
+ git.checkout().setName(branch_1.getName()).call();
- TreeWalk tw = new TreeWalk(db);
- tw.addTree(commit1.getTree());
- tw.addTree(commit2.getTree());
- List<DiffEntry> scan = DiffEntry.scan(tw);
- assertEquals(1, scan.size());
- assertEquals(FileMode.SYMLINK, scan.get(0).getNewMode());
- assertEquals(FileMode.MISSING, scan.get(0).getOldMode());
+ tw.addTree(commit1.getTree());
+ tw.addTree(commit2.getTree());
+ List<DiffEntry> scan = DiffEntry.scan(tw);
+ assertEquals(1, scan.size());
+ assertEquals(FileMode.SYMLINK, scan.get(0).getNewMode());
+ assertEquals(FileMode.MISSING, scan.get(0).getOldMode());
+ }
}
/**
@@ -240,97 +245,101 @@
*/
@Test
public void fileModeTestSymlinkThenMissing() throws Exception {
- Git git = new Git(db);
- writeTrashFile("b", "Hello world b");
- FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "b");
- git.add().addFilepattern(".").call();
- RevCommit commit1 = git.commit().setMessage("add file b & symlink a")
- .call();
- Ref branch_1 = git.branchCreate().setName("branch_1").call();
- git.rm().addFilepattern("a").call();
- RevCommit commit2 = git.commit().setMessage("delete symlink a").call();
+ try (Git git = new Git(db);
+ TreeWalk tw = new TreeWalk(db);) {
+ writeTrashFile("b", "Hello world b");
+ FileUtils.createSymLink(new File(db.getWorkTree(), "a"), "b");
+ git.add().addFilepattern(".").call();
+ RevCommit commit1 = git.commit().setMessage("add file b & symlink a")
+ .call();
+ Ref branch_1 = git.branchCreate().setName("branch_1").call();
+ git.rm().addFilepattern("a").call();
+ RevCommit commit2 = git.commit().setMessage("delete symlink a").call();
- git.checkout().setName(branch_1.getName()).call();
+ git.checkout().setName(branch_1.getName()).call();
- TreeWalk tw = new TreeWalk(db);
- tw.addTree(commit1.getTree());
- tw.addTree(commit2.getTree());
- List<DiffEntry> scan = DiffEntry.scan(tw);
- assertEquals(1, scan.size());
- assertEquals(FileMode.MISSING, scan.get(0).getNewMode());
- assertEquals(FileMode.SYMLINK, scan.get(0).getOldMode());
+ tw.addTree(commit1.getTree());
+ tw.addTree(commit2.getTree());
+ List<DiffEntry> scan = DiffEntry.scan(tw);
+ assertEquals(1, scan.size());
+ assertEquals(FileMode.MISSING, scan.get(0).getNewMode());
+ assertEquals(FileMode.SYMLINK, scan.get(0).getOldMode());
+ }
}
@Test
public void createSymlinkAfterTarget() throws Exception {
- Git git = new Git(db);
- writeTrashFile("a", "start");
- git.add().addFilepattern("a").call();
- RevCommit base = git.commit().setMessage("init").call();
- writeTrashFile("target", "someData");
- FileUtils.createSymLink(new File(db.getWorkTree(), "link"), "target");
- git.add().addFilepattern("target").addFilepattern("link").call();
- git.commit().setMessage("add target").call();
- assertEquals(4, db.getWorkTree().list().length); // self-check
- git.checkout().setName(base.name()).call();
- assertEquals(2, db.getWorkTree().list().length); // self-check
- git.checkout().setName("master").call();
- assertEquals(4, db.getWorkTree().list().length);
- String data = read(new File(db.getWorkTree(), "target"));
- assertEquals(8, new File(db.getWorkTree(), "target").length());
- assertEquals("someData", data);
- data = read(new File(db.getWorkTree(), "link"));
- assertEquals("target",
- FileUtils.readSymLink(new File(db.getWorkTree(), "link")));
- assertEquals("someData", data);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "start");
+ git.add().addFilepattern("a").call();
+ RevCommit base = git.commit().setMessage("init").call();
+ writeTrashFile("target", "someData");
+ FileUtils.createSymLink(new File(db.getWorkTree(), "link"), "target");
+ git.add().addFilepattern("target").addFilepattern("link").call();
+ git.commit().setMessage("add target").call();
+ assertEquals(4, db.getWorkTree().list().length); // self-check
+ git.checkout().setName(base.name()).call();
+ assertEquals(2, db.getWorkTree().list().length); // self-check
+ git.checkout().setName("master").call();
+ assertEquals(4, db.getWorkTree().list().length);
+ String data = read(new File(db.getWorkTree(), "target"));
+ assertEquals(8, new File(db.getWorkTree(), "target").length());
+ assertEquals("someData", data);
+ data = read(new File(db.getWorkTree(), "link"));
+ assertEquals("target",
+ FileUtils.readSymLink(new File(db.getWorkTree(), "link")));
+ assertEquals("someData", data);
+ }
}
@Test
public void createFileSymlinkBeforeTarget() throws Exception {
- Git git = new Git(db);
- writeTrashFile("a", "start");
- git.add().addFilepattern("a").call();
- RevCommit base = git.commit().setMessage("init").call();
- writeTrashFile("target", "someData");
- FileUtils.createSymLink(new File(db.getWorkTree(), "tlink"), "target");
- git.add().addFilepattern("target").addFilepattern("tlink").call();
- git.commit().setMessage("add target").call();
- assertEquals(4, db.getWorkTree().list().length); // self-check
- git.checkout().setName(base.name()).call();
- assertEquals(2, db.getWorkTree().list().length); // self-check
- git.checkout().setName("master").call();
- assertEquals(4, db.getWorkTree().list().length);
- String data = read(new File(db.getWorkTree(), "target"));
- assertEquals(8, new File(db.getWorkTree(), "target").length());
- assertEquals("someData", data);
- data = read(new File(db.getWorkTree(), "tlink"));
- assertEquals("target",
- FileUtils.readSymLink(new File(db.getWorkTree(), "tlink")));
- assertEquals("someData", data);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "start");
+ git.add().addFilepattern("a").call();
+ RevCommit base = git.commit().setMessage("init").call();
+ writeTrashFile("target", "someData");
+ FileUtils.createSymLink(new File(db.getWorkTree(), "tlink"), "target");
+ git.add().addFilepattern("target").addFilepattern("tlink").call();
+ git.commit().setMessage("add target").call();
+ assertEquals(4, db.getWorkTree().list().length); // self-check
+ git.checkout().setName(base.name()).call();
+ assertEquals(2, db.getWorkTree().list().length); // self-check
+ git.checkout().setName("master").call();
+ assertEquals(4, db.getWorkTree().list().length);
+ String data = read(new File(db.getWorkTree(), "target"));
+ assertEquals(8, new File(db.getWorkTree(), "target").length());
+ assertEquals("someData", data);
+ data = read(new File(db.getWorkTree(), "tlink"));
+ assertEquals("target",
+ FileUtils.readSymLink(new File(db.getWorkTree(), "tlink")));
+ assertEquals("someData", data);
+ }
}
@Test
public void createDirSymlinkBeforeTarget() throws Exception {
- Git git = new Git(db);
- writeTrashFile("a", "start");
- git.add().addFilepattern("a").call();
- RevCommit base = git.commit().setMessage("init").call();
- FileUtils.createSymLink(new File(db.getWorkTree(), "link"), "target");
- FileUtils.mkdir(new File(db.getWorkTree(), "target"));
- writeTrashFile("target/file", "someData");
- git.add().addFilepattern("target").addFilepattern("link").call();
- git.commit().setMessage("add target").call();
- assertEquals(4, db.getWorkTree().list().length); // self-check
- git.checkout().setName(base.name()).call();
- assertEquals(2, db.getWorkTree().list().length); // self-check
- git.checkout().setName("master").call();
- assertEquals(4, db.getWorkTree().list().length);
- String data = read(new File(db.getWorkTree(), "target/file"));
- assertEquals(8, new File(db.getWorkTree(), "target/file").length());
- assertEquals("someData", data);
- data = read(new File(db.getWorkTree(), "link/file"));
- assertEquals("target",
- FileUtils.readSymLink(new File(db.getWorkTree(), "link")));
- assertEquals("someData", data);
+ try (Git git = new Git(db)) {
+ writeTrashFile("a", "start");
+ git.add().addFilepattern("a").call();
+ RevCommit base = git.commit().setMessage("init").call();
+ FileUtils.createSymLink(new File(db.getWorkTree(), "link"), "target");
+ FileUtils.mkdir(new File(db.getWorkTree(), "target"));
+ writeTrashFile("target/file", "someData");
+ git.add().addFilepattern("target").addFilepattern("link").call();
+ git.commit().setMessage("add target").call();
+ assertEquals(4, db.getWorkTree().list().length); // self-check
+ git.checkout().setName(base.name()).call();
+ assertEquals(2, db.getWorkTree().list().length); // self-check
+ git.checkout().setName("master").call();
+ assertEquals(4, db.getWorkTree().list().length);
+ String data = read(new File(db.getWorkTree(), "target/file"));
+ assertEquals(8, new File(db.getWorkTree(), "target/file").length());
+ assertEquals("someData", data);
+ data = read(new File(db.getWorkTree(), "link/file"));
+ assertEquals("target",
+ FileUtils.readSymLink(new File(db.getWorkTree(), "link")));
+ assertEquals("someData", data);
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java
new file mode 100644
index 0000000..c1e078d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
+import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
+import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AtomicPushTest {
+ private URIish uri;
+ private TestProtocol<Object> testProtocol;
+ private Object ctx = new Object();
+ private InMemoryRepository server;
+ private InMemoryRepository client;
+ private ObjectId obj1;
+ private ObjectId obj2;
+
+ @Before
+ public void setUp() throws Exception {
+ server = newRepo("server");
+ client = newRepo("client");
+ testProtocol = new TestProtocol<>(
+ null,
+ new ReceivePackFactory<Object>() {
+ @Override
+ public ReceivePack create(Object req, Repository db)
+ throws ServiceNotEnabledException,
+ ServiceNotAuthorizedException {
+ return new ReceivePack(db);
+ }
+ });
+ uri = testProtocol.register(ctx, server);
+
+ try (ObjectInserter ins = client.newObjectInserter()) {
+ obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test"));
+ obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file"));
+ ins.flush();
+ }
+ }
+
+ @After
+ public void tearDown() {
+ Transport.unregister(testProtocol);
+ }
+
+ private static InMemoryRepository newRepo(String name) {
+ return new InMemoryRepository(new DfsRepositoryDescription(name));
+ }
+
+ @Test
+ public void pushNonAtomic() throws Exception {
+ PushResult r;
+ server.setPerformsAtomicTransactions(false);
+ try (Transport tn = testProtocol.open(uri, client, "server")) {
+ tn.setPushAtomic(false);
+ r = tn.push(NullProgressMonitor.INSTANCE, commands());
+ }
+
+ RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
+ RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
+ assertSame(RemoteRefUpdate.Status.OK, one.getStatus());
+ assertSame(
+ RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
+ two.getStatus());
+ }
+
+ @Test
+ public void pushAtomicClientGivesUpEarly() throws Exception {
+ PushResult r;
+ try (Transport tn = testProtocol.open(uri, client, "server")) {
+ tn.setPushAtomic(true);
+ r = tn.push(NullProgressMonitor.INSTANCE, commands());
+ }
+
+ RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one");
+ RemoteRefUpdate two = r.getRemoteUpdate("refs/heads/two");
+ assertSame(
+ RemoteRefUpdate.Status.REJECTED_OTHER_REASON,
+ one.getStatus());
+ assertSame(
+ RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
+ two.getStatus());
+ assertEquals(JGitText.get().transactionAborted, one.getMessage());
+ }
+
+ @Test
+ public void pushAtomicDisabled() throws Exception {
+ List<RemoteRefUpdate> cmds = new ArrayList<>();
+ cmds.add(new RemoteRefUpdate(
+ null, null,
+ obj1, "refs/heads/one",
+ true /* force update */,
+ null /* no local tracking ref */,
+ ObjectId.zeroId()));
+ cmds.add(new RemoteRefUpdate(
+ null, null,
+ obj2, "refs/heads/two",
+ true /* force update */,
+ null /* no local tracking ref */,
+ ObjectId.zeroId()));
+
+ server.setPerformsAtomicTransactions(false);
+ try (Transport tn = testProtocol.open(uri, client, "server")) {
+ tn.setPushAtomic(true);
+ tn.push(NullProgressMonitor.INSTANCE, cmds);
+ fail("did not throw TransportException");
+ } catch (TransportException e) {
+ assertEquals(
+ uri + ": " + JGitText.get().atomicPushNotSupported,
+ e.getMessage());
+ }
+ }
+
+ private List<RemoteRefUpdate> commands() throws IOException {
+ List<RemoteRefUpdate> cmds = new ArrayList<>();
+ cmds.add(new RemoteRefUpdate(
+ null, null,
+ obj1, "refs/heads/one",
+ true /* force update */,
+ null /* no local tracking ref */,
+ ObjectId.zeroId()));
+ cmds.add(new RemoteRefUpdate(
+ null, null,
+ obj2, "refs/heads/two",
+ true /* force update */,
+ null /* no local tracking ref */,
+ obj1));
+ return cmds;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
index ba89d2d..a83a993 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
@@ -126,24 +126,26 @@
assertNull(newRepo.resolve("refs/heads/a"));
// Next an incremental bundle
- bundle = makeBundle("refs/heads/cc", db.resolve("c").name(),
- new RevWalk(db).parseCommit(db.resolve("a").toObjectId()));
- fetchResult = fetchFromBundle(newRepo, bundle);
- advertisedRef = fetchResult.getAdvertisedRef("refs/heads/cc");
- assertEquals(db.resolve("c").name(), advertisedRef.getObjectId().name());
- assertEquals(db.resolve("c").name(), newRepo.resolve("refs/heads/cc")
- .name());
- assertNull(newRepo.resolve("refs/heads/c"));
- assertNull(newRepo.resolve("refs/heads/a")); // still unknown
+ try (RevWalk rw = new RevWalk(db)) {
+ bundle = makeBundle("refs/heads/cc", db.resolve("c").name(),
+ rw.parseCommit(db.resolve("a").toObjectId()));
+ fetchResult = fetchFromBundle(newRepo, bundle);
+ advertisedRef = fetchResult.getAdvertisedRef("refs/heads/cc");
+ assertEquals(db.resolve("c").name(), advertisedRef.getObjectId().name());
+ assertEquals(db.resolve("c").name(), newRepo.resolve("refs/heads/cc")
+ .name());
+ assertNull(newRepo.resolve("refs/heads/c"));
+ assertNull(newRepo.resolve("refs/heads/a")); // still unknown
- try {
- // Check that we actually needed the first bundle
- Repository newRepo2 = createBareRepository();
- fetchResult = fetchFromBundle(newRepo2, bundle);
- fail("We should not be able to fetch from bundle with prerequisites that are not fulfilled");
- } catch (MissingBundlePrerequisiteException e) {
- assertTrue(e.getMessage()
- .indexOf(db.resolve("refs/heads/a").name()) >= 0);
+ try {
+ // Check that we actually needed the first bundle
+ Repository newRepo2 = createBareRepository();
+ fetchResult = fetchFromBundle(newRepo2, bundle);
+ fail("We should not be able to fetch from bundle with prerequisites that are not fulfilled");
+ } catch (MissingBundlePrerequisiteException e) {
+ assertTrue(e.getMessage()
+ .indexOf(db.resolve("refs/heads/a").name()) >= 0);
+ }
}
}
@@ -166,8 +168,10 @@
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,
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
new file mode 100644
index 0000000..a3b4134
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import static org.eclipse.jgit.transport.RemoteRefUpdate.Status.REJECTED_OTHER_REASON;
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
+import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
+import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PushConnectionTest {
+ private URIish uri;
+ private TestProtocol<Object> testProtocol;
+ private Object ctx = new Object();
+ private InMemoryRepository server;
+ private InMemoryRepository client;
+ private ObjectId obj1;
+ private ObjectId obj2;
+ private ObjectId obj3;
+ private String refName = "refs/tags/blob";
+
+ @Before
+ public void setUp() throws Exception {
+ server = newRepo("server");
+ client = newRepo("client");
+ testProtocol = new TestProtocol<>(
+ null,
+ new ReceivePackFactory<Object>() {
+ @Override
+ public ReceivePack create(Object req, Repository db)
+ throws ServiceNotEnabledException,
+ ServiceNotAuthorizedException {
+ return new ReceivePack(db);
+ }
+ });
+ uri = testProtocol.register(ctx, server);
+
+ try (ObjectInserter ins = server.newObjectInserter()) {
+ obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test"));
+ obj3 = ins.insert(Constants.OBJ_BLOB, Constants.encode("not"));
+ ins.flush();
+
+ RefUpdate u = server.updateRef(refName);
+ u.setNewObjectId(obj1);
+ assertEquals(RefUpdate.Result.NEW, u.update());
+ }
+
+ try (ObjectInserter ins = client.newObjectInserter()) {
+ obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file"));
+ ins.flush();
+ }
+ }
+
+ @After
+ public void tearDown() {
+ Transport.unregister(testProtocol);
+ }
+
+ private static InMemoryRepository newRepo(String name) {
+ return new InMemoryRepository(new DfsRepositoryDescription(name));
+ }
+
+ @Test
+ public void testWrongOldIdDoesNotReplace() throws IOException {
+ RemoteRefUpdate rru = new RemoteRefUpdate(null, null, obj2, refName,
+ false, null, obj3);
+
+ Map<String, RemoteRefUpdate> updates = new HashMap<>();
+ updates.put(rru.getRemoteName(), rru);
+
+ Transport tn = testProtocol.open(uri, client, "server");
+ try {
+ PushConnection connection = tn.openPush();
+ try {
+ connection.push(NullProgressMonitor.INSTANCE, updates);
+ } finally {
+ connection.close();
+ }
+ } finally {
+ tn.close();
+ }
+
+ assertEquals(REJECTED_OTHER_REASON, rru.getStatus());
+ assertEquals("invalid old id sent", rru.getMessage());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
index aa5914f..94bc383 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
@@ -116,12 +116,9 @@
// 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 @@
@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 @@
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);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
index 3f5fcbb..4f83350 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
@@ -341,6 +341,41 @@
}
@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("*:*");
assertTrue(a.isWildcard());
@@ -404,21 +439,6 @@
}
@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"));
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java
index e9ae190..d2c3a0b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java
@@ -195,24 +195,31 @@
assertEquals(1, flushCnt[0]);
}
+ private void createSideBandOutputStream(int chan, int sz, OutputStream os)
+ throws Exception {
+ try (SideBandOutputStream s = new SideBandOutputStream(chan, sz, os)) {
+ // Unused
+ }
+ }
+
@Test
- public void testConstructor_RejectsBadChannel() {
+ public void testConstructor_RejectsBadChannel() throws Exception {
try {
- new SideBandOutputStream(-1, MAX_BUF, rawOut);
+ createSideBandOutputStream(-1, MAX_BUF, rawOut);
fail("Accepted -1 channel number");
} catch (IllegalArgumentException e) {
assertEquals("channel -1 must be in range [1, 255]", e.getMessage());
}
try {
- new SideBandOutputStream(0, MAX_BUF, rawOut);
+ createSideBandOutputStream(0, MAX_BUF, rawOut);
fail("Accepted 0 channel number");
} catch (IllegalArgumentException e) {
assertEquals("channel 0 must be in range [1, 255]", e.getMessage());
}
try {
- new SideBandOutputStream(256, MAX_BUF, rawOut);
+ createSideBandOutputStream(256, MAX_BUF, rawOut);
fail("Accepted 256 channel number");
} catch (IllegalArgumentException e) {
assertEquals("channel 256 must be in range [1, 255]", e
@@ -221,30 +228,30 @@
}
@Test
- public void testConstructor_RejectsBadBufferSize() {
+ public void testConstructor_RejectsBadBufferSize() throws Exception {
try {
- new SideBandOutputStream(CH_DATA, -1, rawOut);
+ createSideBandOutputStream(CH_DATA, -1, rawOut);
fail("Accepted -1 for buffer size");
} catch (IllegalArgumentException e) {
assertEquals("packet size -1 must be >= 5", e.getMessage());
}
try {
- new SideBandOutputStream(CH_DATA, 0, rawOut);
+ createSideBandOutputStream(CH_DATA, 0, rawOut);
fail("Accepted 0 for buffer size");
} catch (IllegalArgumentException e) {
assertEquals("packet size 0 must be >= 5", e.getMessage());
}
try {
- new SideBandOutputStream(CH_DATA, 1, rawOut);
+ createSideBandOutputStream(CH_DATA, 1, rawOut);
fail("Accepted 1 for buffer size");
} catch (IllegalArgumentException e) {
assertEquals("packet size 1 must be >= 5", e.getMessage());
}
try {
- new SideBandOutputStream(CH_DATA, Integer.MAX_VALUE, rawOut);
+ createSideBandOutputStream(CH_DATA, Integer.MAX_VALUE, rawOut);
fail("Accepted " + Integer.MAX_VALUE + " for buffer size");
} catch (IllegalArgumentException e) {
assertEquals(MessageFormat.format(
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java
index 7f86526..31b6418 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TestProtocolTest.java
@@ -125,7 +125,7 @@
.setRefSpecs(HEADS)
.call();
assertEquals(master,
- local.getRepository().getRef("master").getObjectId());
+ local.getRepository().exactRef("refs/heads/master").getObjectId());
}
}
@@ -142,7 +142,7 @@
.setRefSpecs(HEADS)
.call();
assertEquals(master,
- remote.getRepository().getRef("master").getObjectId());
+ remote.getRepository().exactRef("refs/heads/master").getObjectId());
}
}
@@ -177,7 +177,7 @@
// Expected.
}
assertEquals(1, rejected.get());
- assertNull(local.getRepository().getRef("master"));
+ assertNull(local.getRepository().exactRef("refs/heads/master"));
git.fetch()
.setRemote(user2Uri.toString())
@@ -185,7 +185,7 @@
.call();
assertEquals(1, rejected.get());
assertEquals(master,
- local.getRepository().getRef("master").getObjectId());
+ local.getRepository().exactRef("refs/heads/master").getObjectId());
}
}
@@ -222,7 +222,7 @@
JGitText.get().pushNotPermitted));
}
assertEquals(1, rejected.get());
- assertNull(remote.getRepository().getRef("master"));
+ assertNull(remote.getRepository().exactRef("refs/heads/master"));
git.push()
.setRemote(user2Uri.toString())
@@ -230,7 +230,7 @@
.call();
assertEquals(1, rejected.get());
assertEquals(master,
- remote.getRepository().getRef("master").getObjectId());
+ remote.getRepository().exactRef("refs/heads/master").getObjectId());
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java
index 55e1e44..5519f61 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java
@@ -61,13 +61,10 @@
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 @@
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 @@
@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 @@
@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 @@
*/
@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 @@
*/
@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 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 @@
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);
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
index 745c322..e55d373 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
@@ -51,7 +51,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
@@ -64,24 +63,16 @@
private static final String GIT_SCHEME = "git://";
- @Test
+ @SuppressWarnings("unused")
+ @Test(expected = URISyntaxException.class)
public void shouldRaiseErrorOnEmptyURI() throws Exception {
- try {
- new URIish("");
- fail("expecting an exception");
- } catch (URISyntaxException e) {
- // expected
- }
+ new URIish("");
}
- @Test
+ @SuppressWarnings("unused")
+ @Test(expected = URISyntaxException.class)
public void shouldRaiseErrorOnNullURI() throws Exception {
- try {
- new URIish((String) null);
- fail("expecting an exception");
- } catch (URISyntaxException e) {
- // expected
- }
+ new URIish((String) null);
}
@Test
@@ -469,6 +460,48 @@
}
@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";
URIish u = new URIish(str);
@@ -592,34 +625,19 @@
assertEquals(u, new URIish(str));
}
- @Test
+ @Test(expected = IllegalArgumentException.class)
public void testGetNullHumanishName() {
- try {
- new URIish().getHumanishName();
- fail("path must be not null");
- } catch (IllegalArgumentException e) {
- // expected
- }
+ new URIish().getHumanishName();
}
- @Test
+ @Test(expected = IllegalArgumentException.class)
public void testGetEmptyHumanishName() throws URISyntaxException {
- try {
- new URIish(GIT_SCHEME).getHumanishName();
- fail("empty path is useless");
- } catch (IllegalArgumentException e) {
- // expected
- }
+ new URIish(GIT_SCHEME).getHumanishName();
}
- @Test
+ @Test(expected = IllegalArgumentException.class)
public void testGetAbsEmptyHumanishName() {
- try {
- new URIish().getHumanishName();
- fail("empty path is useless");
- } catch (IllegalArgumentException e) {
- // expected
- }
+ new URIish().getHumanishName();
}
@Test
@@ -928,4 +946,19 @@
}
}
}
+
+ @Test
+ public void testStringConstructor() throws Exception {
+ String str = "http://example.com/";
+ URIish u = new URIish(str);
+ assertEquals("example.com", u.getHost());
+ assertEquals("/", u.getPath());
+ assertEquals(str, u.toString());
+
+ str = "http://example.com";
+ u = new URIish(str);
+ assertEquals("example.com", u.getHost());
+ assertEquals("", u.getPath());
+ assertEquals(str, u.toString());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java
new file mode 100644
index 0000000..ac2bfd1
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java
@@ -0,0 +1,1318 @@
+/*
+ * Copyright (C) 2015, Andrei Pozolotin.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.UTF_8;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.cryptoCipherListPBE;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.cryptoCipherListTrans;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.folderDelete;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.permitLongTests;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.policySetup;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.product;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.proxySetup;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.publicAddress;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.reportPolicy;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.securityProviderName;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.textWrite;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.transferStream;
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.verifyFileContent;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.UnknownHostException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKeyFactory;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
+import org.eclipse.jgit.util.FileUtils;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Suite;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Amazon S3 encryption pipeline test.
+ *
+ * See {@link AmazonS3} {@link WalkEncryption}
+ *
+ * Note: CI server must provide amazon credentials (access key, secret key,
+ * bucket name) via one of methods available in {@link Names}.
+ *
+ * Note: long running tests are activated by Maven profile "test.long". There is
+ * also a separate Eclipse m2e launcher for that. See 'pom.xml' and
+ * 'WalkEncryptionTest.launch'.
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({ //
+ WalkEncryptionTest.Required.class, //
+ WalkEncryptionTest.MinimalSet.class, //
+ WalkEncryptionTest.TestablePBE.class, //
+ WalkEncryptionTest.TestableTransformation.class, //
+})
+public class WalkEncryptionTest {
+
+ /**
+ * Logger setup: ${project_loc}/tst-rsrc/log4j.properties
+ */
+ static final Logger logger = LoggerFactory.getLogger(WalkEncryptionTest.class);
+
+ /**
+ * Property names used in test session.
+ */
+ interface Names {
+
+ // Names of discovered test properties.
+
+ String TEST_BUCKET = "test.bucket";
+
+ // Names of test environment variables for CI.
+
+ String ENV_ACCESS_KEY = "JGIT_S3_ACCESS_KEY";
+
+ String ENV_SECRET_KEY = "JGIT_S3_SECRET_KEY";
+
+ String ENV_BUCKET_NAME = "JGIT_S3_BUCKET_NAME";
+
+ // Name of test environment variable file path for CI.
+
+ String ENV_CONFIG_FILE = "JGIT_S3_CONFIG_FILE";
+
+ // Names of test system properties for CI.
+
+ String SYS_ACCESS_KEY = "jgit.s3.access.key";
+
+ String SYS_SECRET_KEY = "jgit.s3.secret.key";
+
+ String SYS_BUCKET_NAME = "jgit.s3.bucket.name";
+
+ // Name of test system property file path for CI.
+ String SYS_CONFIG_FILE = "jgit.s3.config.file";
+
+ // Hard coded name of test properties file for CI.
+ // File format follows AmazonS3.Keys:
+ // #
+ // # Required entries:
+ // #
+ // accesskey = your-amazon-access-key # default AmazonS3.Keys
+ // secretkey = your-amazon-secret-key # default AmazonS3.Keys
+ // test.bucket = your-bucket-for-testing # custom name, for this test
+ String CONFIG_FILE = "jgit-s3-config.properties";
+
+ // Test properties file in [user home] of CI.
+ String HOME_CONFIG_FILE = System.getProperty("user.home")
+ + File.separator + CONFIG_FILE;
+
+ // Test properties file in [project work directory] of CI.
+ String WORK_CONFIG_FILE = System.getProperty("user.dir")
+ + File.separator + CONFIG_FILE;
+
+ // Test properties file in [project test source directory] of CI.
+ String TEST_CONFIG_FILE = System.getProperty("user.dir")
+ + File.separator + "tst-rsrc" + File.separator + CONFIG_FILE;
+
+ }
+
+ /**
+ * Find test properties from various sources in order of priority.
+ */
+ static class Props implements WalkEncryptionTest.Names, AmazonS3.Keys {
+
+ static boolean haveEnvVar(String name) {
+ return System.getenv(name) != null;
+ }
+
+ static boolean haveEnvVarFile(String name) {
+ return haveEnvVar(name) && new File(name).exists();
+ }
+
+ static boolean haveSysProp(String name) {
+ return System.getProperty(name) != null;
+ }
+
+ static boolean haveSysPropFile(String name) {
+ return haveSysProp(name) && new File(name).exists();
+ }
+
+ static void loadEnvVar(String source, String target, Properties props) {
+ props.put(target, System.getenv(source));
+ }
+
+ static void loadSysProp(String source, String target,
+ Properties props) {
+ props.put(target, System.getProperty(source));
+ }
+
+ static boolean haveProp(String name, Properties props) {
+ return props.containsKey(name);
+ }
+
+ static boolean checkTestProps(Properties props) {
+ return haveProp(ACCESS_KEY, props) && haveProp(SECRET_KEY, props)
+ && haveProp(TEST_BUCKET, props);
+ }
+
+ static Properties fromEnvVars() {
+ if (haveEnvVar(ENV_ACCESS_KEY) && haveEnvVar(ENV_SECRET_KEY)
+ && haveEnvVar(ENV_BUCKET_NAME)) {
+ Properties props = new Properties();
+ loadEnvVar(ENV_ACCESS_KEY, ACCESS_KEY, props);
+ loadEnvVar(ENV_SECRET_KEY, SECRET_KEY, props);
+ loadEnvVar(ENV_BUCKET_NAME, TEST_BUCKET, props);
+ return props;
+ } else {
+ return null;
+ }
+ }
+
+ static Properties fromEnvFile() throws Exception {
+ if (haveEnvVarFile(ENV_CONFIG_FILE)) {
+ Properties props = new Properties();
+ props.load(new FileInputStream(ENV_CONFIG_FILE));
+ if (checkTestProps(props)) {
+ return props;
+ } else {
+ throw new Error("Environment config file is incomplete.");
+ }
+ } else {
+ return null;
+ }
+ }
+
+ static Properties fromSysProps() {
+ if (haveSysProp(SYS_ACCESS_KEY) && haveSysProp(SYS_SECRET_KEY)
+ && haveSysProp(SYS_BUCKET_NAME)) {
+ Properties props = new Properties();
+ loadSysProp(SYS_ACCESS_KEY, ACCESS_KEY, props);
+ loadSysProp(SYS_SECRET_KEY, SECRET_KEY, props);
+ loadSysProp(SYS_BUCKET_NAME, TEST_BUCKET, props);
+ return props;
+ } else {
+ return null;
+ }
+ }
+
+ static Properties fromSysFile() throws Exception {
+ if (haveSysPropFile(SYS_CONFIG_FILE)) {
+ Properties props = new Properties();
+ props.load(new FileInputStream(SYS_CONFIG_FILE));
+ if (checkTestProps(props)) {
+ return props;
+ } else {
+ throw new Error("System props config file is incomplete.");
+ }
+ } else {
+ return null;
+ }
+ }
+
+ static Properties fromConfigFile(String path) throws Exception {
+ File file = new File(path);
+ if (file.exists()) {
+ Properties props = new Properties();
+ props.load(new FileInputStream(file));
+ if (checkTestProps(props)) {
+ return props;
+ } else {
+ throw new Error("Props config file is incomplete: " + path);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Find test properties from various sources in order of priority.
+ *
+ * @return result
+ * @throws Exception
+ */
+ static Properties discover() throws Exception {
+ Properties props;
+ if ((props = fromEnvVars()) != null) {
+ logger.debug(
+ "Using test properties from environment variables.");
+ return props;
+ }
+ if ((props = fromEnvFile()) != null) {
+ logger.debug(
+ "Using test properties from environment variable config file.");
+ return props;
+ }
+ if ((props = fromSysProps()) != null) {
+ logger.debug("Using test properties from system properties.");
+ return props;
+ }
+ if ((props = fromSysFile()) != null) {
+ logger.debug(
+ "Using test properties from system property config file.");
+ return props;
+ }
+ if ((props = fromConfigFile(HOME_CONFIG_FILE)) != null) {
+ logger.debug(
+ "Using test properties from hard coded ${user.home} file.");
+ return props;
+ }
+ if ((props = fromConfigFile(WORK_CONFIG_FILE)) != null) {
+ logger.debug(
+ "Using test properties from hard coded ${user.dir} file.");
+ return props;
+ }
+ if ((props = fromConfigFile(TEST_CONFIG_FILE)) != null) {
+ logger.debug(
+ "Using test properties from hard coded ${project.source} file.");
+ return props;
+ }
+ throw new Error("Can not load test properties form any source.");
+ }
+
+ }
+
+ /**
+ * Collection of test utility methods.
+ */
+ static class Util {
+
+ static final Charset UTF_8 = Charset.forName("UTF-8");
+
+ /**
+ * Read UTF-8 encoded text file into string.
+ *
+ * @param file
+ * @return result
+ * @throws Exception
+ */
+ static String textRead(File file) throws Exception {
+ return new String(Files.readAllBytes(file.toPath()), UTF_8);
+ }
+
+ /**
+ * Write string into UTF-8 encoded file.
+ *
+ * @param file
+ * @param text
+ * @throws Exception
+ */
+ static void textWrite(File file, String text) throws Exception {
+ Files.write(file.toPath(), text.getBytes(UTF_8));
+ }
+
+ static void verifyFileContent(File fileOne, File fileTwo)
+ throws Exception {
+ assertTrue(fileOne.length() > 0);
+ assertTrue(fileTwo.length() > 0);
+ String textOne = textRead(fileOne);
+ String textTwo = textRead(fileTwo);
+ assertEquals(textOne, textTwo);
+ }
+
+ /**
+ * Create local folder.
+ *
+ * @param folder
+ * @throws Exception
+ */
+ static void folderCreate(String folder) throws Exception {
+ File path = new File(folder);
+ assertTrue(path.mkdirs());
+ }
+
+ /**
+ * Delete local folder.
+ *
+ * @param folder
+ * @throws Exception
+ */
+ static void folderDelete(String folder) throws Exception {
+ File path = new File(folder);
+ FileUtils.delete(path,
+ FileUtils.RECURSIVE | FileUtils.SKIP_MISSING);
+ }
+
+ /**
+ * Discover public address of CI server.
+ *
+ * @return result
+ * @throws Exception
+ */
+ static String publicAddress() throws Exception {
+ try {
+ String service = "http://checkip.amazonaws.com";
+ URL url = new URL(service);
+ URLConnection c = url.openConnection();
+ c.setConnectTimeout(500);
+ c.setReadTimeout(500);
+ BufferedReader reader = new BufferedReader(
+ new InputStreamReader(c.getInputStream()));
+ try {
+ return reader.readLine();
+ } finally {
+ reader.close();
+ }
+ } catch (UnknownHostException | SocketTimeoutException e) {
+ return "Can't reach http://checkip.amazonaws.com to"
+ + " determine public address";
+ }
+ }
+
+ /**
+ * Discover Password-Based Encryption (PBE) engines providing both
+ * [SecretKeyFactory] and [AlgorithmParameters].
+ *
+ * @return result
+ */
+ // https://www.bouncycastle.org/specifications.html
+ // https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
+ static List<String> cryptoCipherListPBE() {
+ return cryptoCipherList(WalkEncryption.Vals.REGEX_PBE);
+ }
+
+ // TODO returns inconsistent list.
+ static List<String> cryptoCipherListTrans() {
+ return cryptoCipherList(WalkEncryption.Vals.REGEX_TRANS);
+ }
+
+ static String securityProviderName(String algorithm) throws Exception {
+ return SecretKeyFactory.getInstance(algorithm).getProvider()
+ .getName();
+ }
+
+ static List<String> cryptoCipherList(String regex) {
+ Set<String> source = Security.getAlgorithms("Cipher");
+ Set<String> target = new TreeSet<String>();
+ for (String algo : source) {
+ algo = algo.toUpperCase();
+ if (algo.matches(regex)) {
+ target.add(algo);
+ }
+ }
+ return new ArrayList<String>(target);
+ }
+
+ /**
+ * Stream copy.
+ *
+ * @param from
+ * @param into
+ * @return count
+ * @throws IOException
+ */
+ static long transferStream(InputStream from, OutputStream into)
+ throws IOException {
+ byte[] array = new byte[1 * 1024];
+ long total = 0;
+ while (true) {
+ int count = from.read(array);
+ if (count == -1) {
+ break;
+ }
+ into.write(array, 0, count);
+ total += count;
+ }
+ return total;
+ }
+
+ /**
+ * Setup proxy during CI build.
+ *
+ * @throws Exception
+ */
+ // https://wiki.eclipse.org/Hudson#Accessing_the_Internet_using_Proxy
+ // http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html
+ static void proxySetup() throws Exception {
+ String keyNoProxy = "no_proxy";
+ String keyHttpProxy = "http_proxy";
+ String keyHttpsProxy = "https_proxy";
+
+ String no_proxy = System.getProperty(keyNoProxy,
+ System.getenv(keyNoProxy));
+ if (no_proxy != null) {
+ System.setProperty("http.nonProxyHosts", no_proxy);
+ logger.info("Proxy NOT: " + no_proxy);
+ }
+
+ String http_proxy = System.getProperty(keyHttpProxy,
+ System.getenv(keyHttpProxy));
+ if (http_proxy != null) {
+ URL url = new URL(http_proxy);
+ System.setProperty("http.proxyHost", url.getHost());
+ System.setProperty("http.proxyPort", "" + url.getPort());
+ logger.info("Proxy HTTP: " + http_proxy);
+ }
+
+ String https_proxy = System.getProperty(keyHttpsProxy,
+ System.getenv(keyHttpsProxy));
+ if (https_proxy != null) {
+ URL url = new URL(https_proxy);
+ System.setProperty("https.proxyHost", url.getHost());
+ System.setProperty("https.proxyPort", "" + url.getPort());
+ logger.info("Proxy HTTPS: " + https_proxy);
+ }
+
+ if (no_proxy == null && http_proxy == null && https_proxy == null) {
+ logger.info("Proxy not used.");
+ }
+
+ }
+
+ /**
+ * Permit long tests on CI or with manual activation.
+ *
+ * @return result
+ */
+ static boolean permitLongTests() {
+ return isBuildCI() || isProfileActive();
+ }
+
+ /**
+ * Using Maven profile activation, see pom.xml
+ *
+ * @return result
+ */
+ static boolean isProfileActive() {
+ return Boolean.parseBoolean(System.getProperty("jgit.test.long"));
+ }
+
+ /**
+ * Detect if build is running on CI.
+ *
+ * @return result
+ */
+ static boolean isBuildCI() {
+ return System.getenv("HUDSON_HOME") != null;
+ }
+
+ /**
+ * Setup JCE security policy restrictions. Can remove restrictions when
+ * restrictions are present, but can not impose them when restrictions
+ * are missing.
+ *
+ * @param restrictedOn
+ */
+ // http://www.docjar.com/html/api/javax/crypto/JceSecurity.java.html
+ static void policySetup(boolean restrictedOn) {
+ try {
+ java.lang.reflect.Field isRestricted = Class
+ .forName("javax.crypto.JceSecurity")
+ .getDeclaredField("isRestricted");
+ isRestricted.setAccessible(true);
+ isRestricted.set(null, new Boolean(restrictedOn));
+ } catch (Throwable e) {
+ logger.info(
+ "Could not setup JCE security policy restrictions.");
+ }
+ }
+
+ static void reportPolicy() {
+ try {
+ java.lang.reflect.Field isRestricted = Class
+ .forName("javax.crypto.JceSecurity")
+ .getDeclaredField("isRestricted");
+ isRestricted.setAccessible(true);
+ logger.info("JCE security policy restricted="
+ + isRestricted.get(null));
+ } catch (Throwable e) {
+ logger.info(
+ "Could not report JCE security policy restrictions.");
+ }
+ }
+
+ static List<Object[]> product(List<String> one, List<String> two) {
+ List<Object[]> result = new ArrayList<Object[]>();
+ for (String s1 : one) {
+ for (String s2 : two) {
+ result.add(new Object[] { s1, s2 });
+ }
+ }
+ return result;
+ }
+
+ }
+
+ /**
+ * Common base for encryption tests.
+ */
+ @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+ public abstract static class Base extends SampleDataRepositoryTestCase {
+
+ /**
+ * S3 URI user used by JGIT to discover connection configuration file.
+ */
+ static final String JGIT_USER = "tester-" + System.currentTimeMillis();
+
+ /**
+ * S3 content encoding password used for this test session.
+ */
+ static final String JGIT_PASS = "secret-" + System.currentTimeMillis();
+
+ /**
+ * S3 repository configuration file expected by {@link AmazonS3}.
+ */
+ static final String JGIT_CONF_FILE = System.getProperty("user.home")
+ + "/" + JGIT_USER;
+
+ /**
+ * Name representing remote or local JGIT repository.
+ */
+ static final String JGIT_REPO_DIR = JGIT_USER + ".jgit";
+
+ /**
+ * Local JGIT repository for this test session.
+ */
+ static final String JGIT_LOCAL_DIR = System.getProperty("user.dir")
+ + "/target/" + JGIT_REPO_DIR;
+
+ /**
+ * Remote JGIT repository for this test session.
+ */
+ static final String JGIT_REMOTE_DIR = JGIT_REPO_DIR;
+
+ /**
+ * Generate JGIT S3 connection configuration file.
+ *
+ * @param algorithm
+ * @throws Exception
+ */
+ static void configCreate(String algorithm) throws Exception {
+ Properties props = Props.discover();
+ props.put(AmazonS3.Keys.PASSWORD, JGIT_PASS);
+ props.put(AmazonS3.Keys.CRYPTO_ALG, algorithm);
+ PrintWriter writer = new PrintWriter(JGIT_CONF_FILE);
+ props.store(writer, "JGIT S3 connection configuration file.");
+ writer.close();
+ }
+
+ /**
+ * Generate JGIT S3 connection configuration file.
+ *
+ * @param source
+ * @throws Exception
+ */
+ static void configCreate(Properties source) throws Exception {
+ Properties target = Props.discover();
+ target.putAll(source);
+ PrintWriter writer = new PrintWriter(JGIT_CONF_FILE);
+ target.store(writer, "JGIT S3 connection configuration file.");
+ writer.close();
+ }
+
+ /**
+ * Remove JGIT connection configuration file.
+ *
+ * @throws Exception
+ */
+ static void configDelete() throws Exception {
+ File path = new File(JGIT_CONF_FILE);
+ FileUtils.delete(path, FileUtils.SKIP_MISSING);
+ }
+
+ /**
+ * Generate remote URI for the test session.
+ *
+ * @return result
+ * @throws Exception
+ */
+ static String amazonURI() throws Exception {
+ Properties props = Props.discover();
+ String bucket = props.getProperty(Names.TEST_BUCKET);
+ assertNotNull(bucket);
+ return TransportAmazonS3.S3_SCHEME + "://" + JGIT_USER + "@"
+ + bucket + "/" + JGIT_REPO_DIR;
+ }
+
+ /**
+ * Create S3 repository folder.
+ *
+ * @throws Exception
+ */
+ static void remoteCreate() throws Exception {
+ Properties props = Props.discover();
+ props.remove(AmazonS3.Keys.PASSWORD); // Disable encryption.
+ String bucket = props.getProperty(Names.TEST_BUCKET);
+ AmazonS3 s3 = new AmazonS3(props);
+ String path = JGIT_REMOTE_DIR + "/";
+ s3.put(bucket, path, new byte[0]);
+ logger.debug("remote create: " + JGIT_REMOTE_DIR);
+ }
+
+ /**
+ * Delete S3 repository folder.
+ *
+ * @throws Exception
+ */
+ static void remoteDelete() throws Exception {
+ Properties props = Props.discover();
+ props.remove(AmazonS3.Keys.PASSWORD); // Disable encryption.
+ String bucket = props.getProperty(Names.TEST_BUCKET);
+ AmazonS3 s3 = new AmazonS3(props);
+ List<String> list = s3.list(bucket, JGIT_REMOTE_DIR);
+ for (String path : list) {
+ path = JGIT_REMOTE_DIR + "/" + path;
+ s3.delete(bucket, path);
+ }
+ logger.debug("remote delete: " + JGIT_REMOTE_DIR);
+ }
+
+ /**
+ * Verify if we can create/delete remote file.
+ *
+ * @throws Exception
+ */
+ static void remoteVerify() throws Exception {
+ Properties props = Props.discover();
+ String bucket = props.getProperty(Names.TEST_BUCKET);
+ AmazonS3 s3 = new AmazonS3(props);
+ String file = JGIT_USER + "-" + UUID.randomUUID().toString();
+ String path = JGIT_REMOTE_DIR + "/" + file;
+ s3.put(bucket, path, file.getBytes(UTF_8));
+ s3.delete(bucket, path);
+ }
+
+ /**
+ * Verify if any security provider published the algorithm.
+ *
+ * @param algorithm
+ * @return result
+ */
+ static boolean isAlgorithmPresent(String algorithm) {
+ Set<String> cipherSet = Security.getAlgorithms("Cipher");
+ for (String source : cipherSet) {
+ // Standard names are not case-sensitive.
+ // http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
+ String target = algorithm.toUpperCase();
+ if (source.equalsIgnoreCase(target)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static boolean isAlgorithmPresent(Properties props) {
+ String profile = props.getProperty(AmazonS3.Keys.CRYPTO_ALG);
+ String version = props.getProperty(AmazonS3.Keys.CRYPTO_VER,
+ WalkEncryption.Vals.DEFAULT_VERS);
+ String crytoAlgo;
+ String keyAlgo;
+ switch (version) {
+ case WalkEncryption.Vals.DEFAULT_VERS:
+ case WalkEncryption.JGitV1.VERSION:
+ crytoAlgo = profile;
+ keyAlgo = profile;
+ break;
+ case WalkEncryption.JGitV2.VERSION:
+ crytoAlgo = props
+ .getProperty(profile + WalkEncryption.Keys.X_ALGO);
+ keyAlgo = props
+ .getProperty(profile + WalkEncryption.Keys.X_KEY_ALGO);
+ break;
+ default:
+ return false;
+ }
+ try {
+ Cipher.getInstance(crytoAlgo);
+ SecretKeyFactory.getInstance(keyAlgo);
+ return true;
+ } catch (Throwable e) {
+ return false;
+ }
+ }
+
+ /**
+ * Verify if JRE security policy allows the algorithm.
+ *
+ * @param algorithm
+ * @return result
+ */
+ static boolean isAlgorithmAllowed(String algorithm) {
+ try {
+ WalkEncryption crypto = new WalkEncryption.JetS3tV2(
+ algorithm, JGIT_PASS);
+ verifyCrypto(crypto);
+ return true;
+ } catch (IOException e) {
+ return false; // Encryption failure.
+ } catch (GeneralSecurityException e) {
+ throw new Error(e); // Construction failure.
+ }
+ }
+
+ static boolean isAlgorithmAllowed(Properties props) {
+ try {
+ WalkEncryption.instance(props);
+ return true;
+ } catch (GeneralSecurityException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Verify round trip encryption.
+ *
+ * @param crypto
+ * @throws IOException
+ */
+ static void verifyCrypto(WalkEncryption crypto) throws IOException {
+ String charset = "UTF-8";
+ String sourceText = "secret-message Свобода 老子";
+ String targetText;
+ byte[] cipherText;
+ {
+ byte[] origin = sourceText.getBytes(charset);
+ ByteArrayOutputStream target = new ByteArrayOutputStream();
+ OutputStream source = crypto.encrypt(target);
+ source.write(origin);
+ source.flush();
+ source.close();
+ cipherText = target.toByteArray();
+ }
+ {
+ InputStream source = new ByteArrayInputStream(cipherText);
+ InputStream target = crypto.decrypt(source);
+ ByteArrayOutputStream result = new ByteArrayOutputStream();
+ transferStream(target, result);
+ targetText = result.toString(charset);
+ }
+ assertEquals(sourceText, targetText);
+ }
+
+ /**
+ * Algorithm is testable when it is present and allowed by policy.
+ *
+ * @param algorithm
+ * @return result
+ */
+ static boolean isAlgorithmTestable(String algorithm) {
+ return isAlgorithmPresent(algorithm)
+ && isAlgorithmAllowed(algorithm);
+ }
+
+ static boolean isAlgorithmTestable(Properties props) {
+ return isAlgorithmPresent(props) && isAlgorithmAllowed(props);
+ }
+
+ /**
+ * Log algorithm, provider, testability.
+ *
+ * @param algorithm
+ * @throws Exception
+ */
+ static void reportAlgorithmStatus(String algorithm) throws Exception {
+ final boolean present = isAlgorithmPresent(algorithm);
+ final boolean allowed = present && isAlgorithmAllowed(algorithm);
+ final String provider = present ? securityProviderName(algorithm)
+ : "N/A";
+ String status = "Algorithm: " + algorithm + " @ " + provider + "; "
+ + "present/allowed : " + present + "/" + allowed;
+ if (allowed) {
+ logger.info("Testing " + status);
+ } else {
+ logger.warn("Missing " + status);
+ }
+ }
+
+ static void reportAlgorithmStatus(Properties props) throws Exception {
+ final boolean present = isAlgorithmPresent(props);
+ final boolean allowed = present && isAlgorithmAllowed(props);
+
+ String profile = props.getProperty(AmazonS3.Keys.CRYPTO_ALG);
+ String version = props.getProperty(AmazonS3.Keys.CRYPTO_VER);
+
+ StringBuilder status = new StringBuilder();
+ status.append(" Version: " + version);
+ status.append(" Profile: " + profile);
+ status.append(" Present: " + present);
+ status.append(" Allowed: " + allowed);
+
+ if (allowed) {
+ logger.info("Testing " + status);
+ } else {
+ logger.warn("Missing " + status);
+ }
+ }
+
+ /**
+ * Verify if we can perform remote tests.
+ *
+ * @return result
+ */
+ static boolean isTestConfigPresent() {
+ try {
+ Props.discover();
+ return true;
+ } catch (Throwable e) {
+ return false;
+ }
+ }
+
+ static void reportTestConfigPresent() {
+ if (isTestConfigPresent()) {
+ logger.info("Amazon S3 test configuration is present.");
+ } else {
+ logger.error(
+ "Amazon S3 test configuration is missing, tests will not run.");
+ }
+ }
+
+ /**
+ * Log public address of CI.
+ *
+ * @throws Exception
+ */
+ static void reportPublicAddress() throws Exception {
+ logger.info("Public address: " + publicAddress());
+ }
+
+ /**
+ * BouncyCastle provider class.
+ *
+ * Needs extra dependency, see pom.xml
+ */
+ // http://search.maven.org/#artifactdetails%7Corg.bouncycastle%7Cbcprov-jdk15on%7C1.52%7Cjar
+ static final String PROVIDER_BC = "org.bouncycastle.jce.provider.BouncyCastleProvider";
+
+ /**
+ * Load BouncyCastle provider if present.
+ */
+ static void loadBouncyCastle() {
+ try {
+ Class<?> provider = Class.forName(PROVIDER_BC);
+ Provider instance = (Provider) provider
+ .getConstructor(new Class[] {})
+ .newInstance(new Object[] {});
+ Security.addProvider(instance);
+ logger.info("Loaded " + PROVIDER_BC);
+ } catch (Throwable e) {
+ logger.warn("Failed to load " + PROVIDER_BC);
+ }
+ }
+
+ static void reportLongTests() {
+ if (permitLongTests()) {
+ logger.info("Long running tests are enabled.");
+ } else {
+ logger.warn("Long running tests are disabled.");
+ }
+ }
+
+ /**
+ * Non-PBE algorithm, for error check.
+ */
+ static final String ALGO_ERROR = "PBKDF2WithHmacSHA1";
+
+ /**
+ * Default JetS3t algorithm present in most JRE.
+ */
+ static final String ALGO_JETS3T = "PBEWithMD5AndDES";
+
+ /**
+ * Minimal strength AES based algorithm present in most JRE.
+ */
+ static final String ALGO_MINIMAL_AES = "PBEWithHmacSHA1AndAES_128";
+
+ /**
+ * Selected non-AES algorithm present in BouncyCastle provider.
+ */
+ static final String ALGO_BOUNCY_CASTLE_CBC = "PBEWithSHAAndTwofish-CBC";
+
+ //////////////////////////////////////////////////
+
+ @BeforeClass
+ public static void initialize() throws Exception {
+ Transport.register(TransportAmazonS3.PROTO_S3);
+ proxySetup();
+ reportPolicy();
+ reportLongTests();
+ reportPublicAddress();
+ reportTestConfigPresent();
+ loadBouncyCastle();
+ if (isTestConfigPresent()) {
+ remoteCreate();
+ }
+ }
+
+ @AfterClass
+ public static void terminate() throws Exception {
+ configDelete();
+ folderDelete(JGIT_LOCAL_DIR);
+ if (isTestConfigPresent()) {
+ remoteDelete();
+ }
+ }
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @After
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Optional encrypted amazon remote JGIT life cycle test.
+ *
+ * @param props
+ * @throws Exception
+ */
+ void cryptoTestIfCan(Properties props) throws Exception {
+ reportAlgorithmStatus(props);
+ assumeTrue(isTestConfigPresent());
+ assumeTrue(isAlgorithmTestable(props));
+ cryptoTest(props);
+ }
+
+ /**
+ * Required encrypted amazon remote JGIT life cycle test.
+ *
+ * @param props
+ * @throws Exception
+ */
+ void cryptoTest(Properties props) throws Exception {
+
+ remoteDelete();
+ configCreate(props);
+ folderDelete(JGIT_LOCAL_DIR);
+
+ String uri = amazonURI();
+
+ // Local repositories.
+ File dirOne = db.getWorkTree(); // Provided by setup.
+ File dirTwo = new File(JGIT_LOCAL_DIR);
+
+ // Local verification files.
+ String nameStatic = "master.txt"; // Provided by setup.
+ String nameDynamic = JGIT_USER + "-" + UUID.randomUUID().toString();
+
+ String remote = "remote";
+ RefSpec specs = new RefSpec("refs/heads/master:refs/heads/master");
+
+ { // Push into remote from local one.
+
+ StoredConfig config = db.getConfig();
+ RemoteConfig remoteConfig = new RemoteConfig(config, remote);
+ remoteConfig.addURI(new URIish(uri));
+ remoteConfig.update(config);
+ config.save();
+
+ Git git = Git.open(dirOne);
+ git.checkout().setName("master").call();
+ git.push().setRemote(remote).setRefSpecs(specs).call();
+ git.close();
+
+ File fileStatic = new File(dirOne, nameStatic);
+ assertTrue("Provided by setup", fileStatic.exists());
+
+ }
+
+ { // Clone from remote into local two.
+
+ File fileStatic = new File(dirTwo, nameStatic);
+ assertFalse("Not Provided by setup", fileStatic.exists());
+
+ Git git = Git.cloneRepository().setURI(uri).setDirectory(dirTwo)
+ .call();
+ git.close();
+
+ assertTrue("Provided by clone", fileStatic.exists());
+ }
+
+ { // Verify static file content.
+ File fileOne = new File(dirOne, nameStatic);
+ File fileTwo = new File(dirTwo, nameStatic);
+ verifyFileContent(fileOne, fileTwo);
+ }
+
+ { // Verify new file commit and push from local one.
+
+ File fileDynamic = new File(dirOne, nameDynamic);
+ assertFalse("Not Provided by setup", fileDynamic.exists());
+ FileUtils.createNewFile(fileDynamic);
+ textWrite(fileDynamic, nameDynamic);
+ assertTrue("Provided by create", fileDynamic.exists());
+ assertTrue("Need content to encrypt", fileDynamic.length() > 0);
+
+ Git git = Git.open(dirOne);
+ git.add().addFilepattern(nameDynamic).call();
+ git.commit().setMessage(nameDynamic).call();
+ git.push().setRemote(remote).setRefSpecs(specs).call();
+ git.close();
+
+ }
+
+ { // Verify new file pull from remote into local two.
+
+ File fileDynamic = new File(dirTwo, nameDynamic);
+ assertFalse("Not Provided by setup", fileDynamic.exists());
+
+ Git git = Git.open(dirTwo);
+ git.pull().call();
+ git.close();
+
+ assertTrue("Provided by pull", fileDynamic.exists());
+ }
+
+ { // Verify dynamic file content.
+ File fileOne = new File(dirOne, nameDynamic);
+ File fileTwo = new File(dirTwo, nameDynamic);
+ verifyFileContent(fileOne, fileTwo);
+ }
+
+ }
+
+ }
+
+ /**
+ * Verify prerequisites.
+ */
+ @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+ public static class Required extends Base {
+
+ @Test
+ public void test_A1_ValidURI() throws Exception {
+ assumeTrue(isTestConfigPresent());
+ URIish uri = new URIish(amazonURI());
+ assertTrue("uri=" + uri, TransportAmazonS3.PROTO_S3.canHandle(uri));
+ }
+
+ @Test(expected = Exception.class)
+ public void test_A2_CryptoError() throws Exception {
+ assumeTrue(isTestConfigPresent());
+ Properties props = new Properties();
+ props.put(AmazonS3.Keys.CRYPTO_ALG, ALGO_ERROR);
+ props.put(AmazonS3.Keys.PASSWORD, JGIT_PASS);
+ cryptoTest(props);
+ }
+
+ }
+
+ /**
+ * Test minimal set of algorithms.
+ */
+ @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+ public static class MinimalSet extends Base {
+
+ @Test
+ public void test_V0_Java7_JET() throws Exception {
+ assumeTrue(isTestConfigPresent());
+ Properties props = new Properties();
+ props.put(AmazonS3.Keys.CRYPTO_ALG, ALGO_JETS3T);
+ // Do not set version.
+ props.put(AmazonS3.Keys.PASSWORD, JGIT_PASS);
+ cryptoTestIfCan(props);
+ }
+
+ @Test
+ public void test_V1_Java7_GIT() throws Exception {
+ assumeTrue(isTestConfigPresent());
+ Properties props = new Properties();
+ props.put(AmazonS3.Keys.CRYPTO_ALG, ALGO_JETS3T);
+ props.put(AmazonS3.Keys.CRYPTO_VER, "1");
+ props.put(AmazonS3.Keys.PASSWORD, JGIT_PASS);
+ cryptoTestIfCan(props);
+ }
+
+ @Test
+ public void test_V2_Java7_AES() throws Exception {
+ assumeTrue(isTestConfigPresent());
+ // String profile = "default";
+ String profile = "AES/CBC/PKCS5Padding+PBKDF2WithHmacSHA1";
+ Properties props = new Properties();
+ props.put(AmazonS3.Keys.CRYPTO_ALG, profile);
+ props.put(AmazonS3.Keys.CRYPTO_VER, "2");
+ props.put(AmazonS3.Keys.PASSWORD, JGIT_PASS);
+ props.put(profile + WalkEncryption.Keys.X_ALGO, "AES/CBC/PKCS5Padding");
+ props.put(profile + WalkEncryption.Keys.X_KEY_ALGO, "PBKDF2WithHmacSHA1");
+ props.put(profile + WalkEncryption.Keys.X_KEY_SIZE, "128");
+ props.put(profile + WalkEncryption.Keys.X_KEY_ITER, "10000");
+ props.put(profile + WalkEncryption.Keys.X_KEY_SALT, "e2 55 89 67 8e 8d e8 4c");
+ cryptoTestIfCan(props);
+ }
+
+ @Test
+ public void test_V2_Java8_PBE_AES() throws Exception {
+ assumeTrue(isTestConfigPresent());
+ String profile = "PBEWithHmacSHA512AndAES_256";
+ Properties props = new Properties();
+ props.put(AmazonS3.Keys.CRYPTO_ALG, profile);
+ props.put(AmazonS3.Keys.CRYPTO_VER, "2");
+ props.put(AmazonS3.Keys.PASSWORD, JGIT_PASS);
+ props.put(profile + WalkEncryption.Keys.X_ALGO, "PBEWithHmacSHA512AndAES_256");
+ props.put(profile + WalkEncryption.Keys.X_KEY_ALGO, "PBEWithHmacSHA512AndAES_256");
+ props.put(profile + WalkEncryption.Keys.X_KEY_SIZE, "256");
+ props.put(profile + WalkEncryption.Keys.X_KEY_ITER, "10000");
+ props.put(profile + WalkEncryption.Keys.X_KEY_SALT, "e2 55 89 67 8e 8d e8 4c");
+ policySetup(false);
+ cryptoTestIfCan(props);
+ }
+
+ }
+
+ /**
+ * Test all present and allowed PBE algorithms.
+ */
+ // https://github.com/junit-team/junit/wiki/Parameterized-tests
+ @RunWith(Parameterized.class)
+ @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+ public static class TestablePBE extends Base {
+
+ @Parameters(name = "Profile: {0} Version: {1}")
+ public static Collection<Object[]> argsList() {
+ List<String> algorithmList = new ArrayList<String>();
+ algorithmList.addAll(cryptoCipherListPBE());
+
+ List<String> versionList = new ArrayList<String>();
+ versionList.add("0");
+ versionList.add("1");
+
+ return product(algorithmList, versionList);
+ }
+
+ final String profile;
+
+ final String version;
+
+ final String password = JGIT_PASS;
+
+ public TestablePBE(String profile, String version) {
+ this.profile = profile;
+ this.version = version;
+ }
+
+ @Test
+ public void testCrypto() throws Exception {
+ assumeTrue(permitLongTests());
+ Properties props = new Properties();
+ props.put(AmazonS3.Keys.CRYPTO_ALG, profile);
+ props.put(AmazonS3.Keys.CRYPTO_VER, version);
+ props.put(AmazonS3.Keys.PASSWORD, password);
+ cryptoTestIfCan(props);
+ }
+
+ }
+
+ /**
+ * Test all present and allowed transformation algorithms.
+ */
+ // https://github.com/junit-team/junit/wiki/Parameterized-tests
+ @RunWith(Parameterized.class)
+ @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+ public static class TestableTransformation extends Base {
+
+ @Parameters(name = "Profile: {0} Version: {1}")
+ public static Collection<Object[]> argsList() {
+ List<String> algorithmList = new ArrayList<String>();
+ algorithmList.addAll(cryptoCipherListTrans());
+
+ List<String> versionList = new ArrayList<String>();
+ versionList.add("1");
+
+ return product(algorithmList, versionList);
+ }
+
+ final String profile;
+
+ final String version;
+
+ final String password = JGIT_PASS;
+
+ public TestableTransformation(String profile, String version) {
+ this.profile = profile;
+ this.version = version;
+ }
+
+ @Test
+ public void testCrypto() throws Exception {
+ assumeTrue(permitLongTests());
+ Properties props = new Properties();
+ props.put(AmazonS3.Keys.CRYPTO_ALG, profile);
+ props.put(AmazonS3.Keys.CRYPTO_VER, version);
+ props.put(AmazonS3.Keys.PASSWORD, password);
+ cryptoTestIfCan(props);
+ }
+
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java
index 52da69e..f5e97c2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java
@@ -43,6 +43,8 @@
package org.eclipse.jgit.treewalk;
+import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE;
+import static org.eclipse.jgit.lib.FileMode.SYMLINK;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
@@ -50,9 +52,11 @@
import java.io.ByteArrayOutputStream;
+import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.TreeFormatter;
import org.eclipse.jgit.util.RawParseUtils;
import org.junit.Before;
import org.junit.Test;
@@ -369,4 +373,41 @@
assertEquals(name, RawParseUtils.decode(Constants.CHARSET, ctp.path,
ctp.pathOffset, ctp.pathLen));
}
+
+ @Test
+ public void testFindAttributesWhenFirst() throws CorruptObjectException {
+ TreeFormatter tree = new TreeFormatter();
+ tree.append(".gitattributes", REGULAR_FILE, hash_a);
+ ctp.reset(tree.toByteArray());
+
+ assertTrue(ctp.findFile(".gitattributes"));
+ assertEquals(REGULAR_FILE.getBits(), ctp.getEntryRawMode());
+ assertEquals(".gitattributes", ctp.getEntryPathString());
+ assertEquals(hash_a, ctp.getEntryObjectId());
+ }
+
+ @Test
+ public void testFindAttributesWhenSecond() throws CorruptObjectException {
+ TreeFormatter tree = new TreeFormatter();
+ tree.append(".config", SYMLINK, hash_a);
+ tree.append(".gitattributes", REGULAR_FILE, hash_foo);
+ ctp.reset(tree.toByteArray());
+
+ assertTrue(ctp.findFile(".gitattributes"));
+ assertEquals(REGULAR_FILE.getBits(), ctp.getEntryRawMode());
+ assertEquals(".gitattributes", ctp.getEntryPathString());
+ assertEquals(hash_foo, ctp.getEntryObjectId());
+ }
+
+ @Test
+ public void testFindAttributesWhenMissing() throws CorruptObjectException {
+ TreeFormatter tree = new TreeFormatter();
+ tree.append("src", REGULAR_FILE, hash_a);
+ tree.append("zoo", REGULAR_FILE, hash_foo);
+ ctp.reset(tree.toByteArray());
+
+ assertFalse(ctp.findFile(".gitattributes"));
+ assertEquals(11, ctp.idOffset()); // Did not walk the entire tree.
+ assertEquals("src", ctp.getEntryPathString());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java
index 8875410..cd55cba 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java
@@ -67,6 +67,7 @@
public class FileTreeIteratorJava7Test extends RepositoryTestCase {
@Test
public void testFileModeSymLinkIsNotATree() throws IOException {
+ org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
FS fs = db.getFS();
// mål = target in swedish, just to get som unicode in here
writeTrashFile("mål/data", "targetdata");
@@ -102,18 +103,20 @@
});
assertTrue(dce.commit());
}
- new Git(db).commit().setMessage("Adding link").call();
- new Git(db).reset().setMode(ResetType.HARD).call();
- DirCacheIterator dci = new DirCacheIterator(db.readDirCache());
- FileTreeIterator fti = new FileTreeIterator(db);
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("Adding link").call();
+ git.reset().setMode(ResetType.HARD).call();
+ DirCacheIterator dci = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator fti = new FileTreeIterator(db);
- // self-check
- assertEquals("link", fti.getEntryPathString());
- assertEquals("link", dci.getEntryPathString());
+ // self-check
+ assertEquals("link", fti.getEntryPathString());
+ assertEquals("link", dci.getEntryPathString());
- // test
- assertFalse(fti.isModified(dci.getDirCacheEntry(), true,
- db.newObjectReader()));
+ // test
+ assertFalse(fti.isModified(dci.getDirCacheEntry(), true,
+ db.newObjectReader()));
+ }
}
/**
@@ -141,18 +144,20 @@
});
assertTrue(dce.commit());
}
- new Git(db).commit().setMessage("Adding link").call();
- new Git(db).reset().setMode(ResetType.HARD).call();
- DirCacheIterator dci = new DirCacheIterator(db.readDirCache());
- FileTreeIterator fti = new FileTreeIterator(db);
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("Adding link").call();
+ git.reset().setMode(ResetType.HARD).call();
+ DirCacheIterator dci = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator fti = new FileTreeIterator(db);
- // self-check
- assertEquals("link", fti.getEntryPathString());
- assertEquals("link", dci.getEntryPathString());
+ // self-check
+ assertEquals("link", fti.getEntryPathString());
+ assertEquals("link", dci.getEntryPathString());
- // test
- assertFalse(fti.isModified(dci.getDirCacheEntry(), true,
- db.newObjectReader()));
+ // test
+ assertFalse(fti.isModified(dci.getDirCacheEntry(), true,
+ db.newObjectReader()));
+ }
}
/**
@@ -163,6 +168,7 @@
*/
@Test
public void testSymlinkActuallyModified() throws Exception {
+ org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
final String NORMALIZED = "target";
final byte[] NORMALIZED_BYTES = Constants.encode(NORMALIZED);
try (ObjectInserter oi = db.newObjectInserter()) {
@@ -180,20 +186,22 @@
});
assertTrue(dce.commit());
}
- new Git(db).commit().setMessage("Adding link").call();
- new Git(db).reset().setMode(ResetType.HARD).call();
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("Adding link").call();
+ git.reset().setMode(ResetType.HARD).call();
- FileUtils.delete(new File(trash, "link"), FileUtils.NONE);
- FS.DETECTED.createSymLink(new File(trash, "link"), "newtarget");
- DirCacheIterator dci = new DirCacheIterator(db.readDirCache());
- FileTreeIterator fti = new FileTreeIterator(db);
+ FileUtils.delete(new File(trash, "link"), FileUtils.NONE);
+ FS.DETECTED.createSymLink(new File(trash, "link"), "newtarget");
+ DirCacheIterator dci = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator fti = new FileTreeIterator(db);
- // self-check
- assertEquals("link", fti.getEntryPathString());
- assertEquals("link", dci.getEntryPathString());
+ // self-check
+ assertEquals("link", fti.getEntryPathString());
+ assertEquals("link", dci.getEntryPathString());
- // test
- assertTrue(fti.isModified(dci.getDirCacheEntry(), true,
- db.newObjectReader()));
+ // test
+ assertTrue(fti.isModified(dci.getDirCacheEntry(), true,
+ db.newObjectReader()));
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
index 767e13d..df17a3e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
@@ -255,10 +255,11 @@
@Test
public void testDirCacheMatchingId() throws Exception {
File f = writeTrashFile("file", "content");
- Git git = new Git(db);
- writeTrashFile("file", "content");
- fsTick(f);
- git.add().addFilepattern("file").call();
+ try (Git git = new Git(db)) {
+ writeTrashFile("file", "content");
+ fsTick(f);
+ git.add().addFilepattern("file").call();
+ }
DirCacheEntry dce = db.readDirCache().getEntry("file");
TreeWalk tw = new TreeWalk(db);
FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(), db
@@ -282,11 +283,12 @@
@Test
public void testIsModifiedSymlinkAsFile() throws Exception {
writeTrashFile("symlink", "content");
- Git git = new Git(db);
- db.getConfig().setString(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_SYMLINKS, "false");
- git.add().addFilepattern("symlink").call();
- git.commit().setMessage("commit").call();
+ try (Git git = new Git(db)) {
+ db.getConfig().setString(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_SYMLINKS, "false");
+ git.add().addFilepattern("symlink").call();
+ git.commit().setMessage("commit").call();
+ }
// Modify previously committed DirCacheEntry and write it back to disk
DirCacheEntry dce = db.readDirCache().getEntry("symlink");
@@ -305,20 +307,21 @@
@Test
public void testIsModifiedFileSmudged() throws Exception {
File f = writeTrashFile("file", "content");
- Git git = new Git(db);
- // The idea of this test is to check the smudged handling
- // Hopefully fsTick will make sure our entry gets smudged
- fsTick(f);
- writeTrashFile("file", "content");
- long lastModified = f.lastModified();
- git.add().addFilepattern("file").call();
- writeTrashFile("file", "conten2");
- f.setLastModified(lastModified);
- // We cannot trust this to go fast enough on
- // a system with less than one-second lastModified
- // resolution, so we force the index to have the
- // same timestamp as the file we look at.
- db.getIndexFile().setLastModified(lastModified);
+ try (Git git = new Git(db)) {
+ // The idea of this test is to check the smudged handling
+ // Hopefully fsTick will make sure our entry gets smudged
+ fsTick(f);
+ writeTrashFile("file", "content");
+ long lastModified = f.lastModified();
+ git.add().addFilepattern("file").call();
+ writeTrashFile("file", "conten2");
+ f.setLastModified(lastModified);
+ // We cannot trust this to go fast enough on
+ // a system with less than one-second lastModified
+ // resolution, so we force the index to have the
+ // same timestamp as the file we look at.
+ db.getIndexFile().setLastModified(lastModified);
+ }
DirCacheEntry dce = db.readDirCache().getEntry("file");
FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(), db
.getConfig().get(WorkingTreeOptions.KEY));
@@ -334,198 +337,204 @@
@Test
public void submoduleHeadMatchesIndex() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- final RevCommit id = git.commit().setMessage("create file").call();
- final String path = "sub";
- DirCache cache = db.lockDirCache();
- DirCacheEditor editor = cache.editor();
- editor.add(new PathEdit(path) {
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ final RevCommit id = git.commit().setMessage("create file").call();
+ final String path = "sub";
+ DirCache cache = db.lockDirCache();
+ DirCacheEditor editor = cache.editor();
+ editor.add(new PathEdit(path) {
+
+ public void apply(DirCacheEntry ent) {
+ ent.setFileMode(FileMode.GITLINK);
+ ent.setObjectId(id);
+ }
+ });
+ editor.commit();
- public void apply(DirCacheEntry ent) {
- ent.setFileMode(FileMode.GITLINK);
- ent.setObjectId(id);
- }
- });
- editor.commit();
+ Git.cloneRepository().setURI(db.getDirectory().toURI().toString())
+ .setDirectory(new File(db.getWorkTree(), path)).call()
+ .getRepository().close();
- Git.cloneRepository().setURI(db.getDirectory().toURI().toString())
- .setDirectory(new File(db.getWorkTree(), path)).call()
- .getRepository().close();
-
- TreeWalk walk = new TreeWalk(db);
- DirCacheIterator indexIter = new DirCacheIterator(db.readDirCache());
- FileTreeIterator workTreeIter = new FileTreeIterator(db);
- walk.addTree(indexIter);
- walk.addTree(workTreeIter);
- walk.setFilter(PathFilter.create(path));
-
- assertTrue(walk.next());
- assertTrue(indexIter.idEqual(workTreeIter));
+ DirCacheIterator indexIter = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator workTreeIter = new FileTreeIterator(db);
+ walk.addTree(indexIter);
+ walk.addTree(workTreeIter);
+ walk.setFilter(PathFilter.create(path));
+
+ assertTrue(walk.next());
+ assertTrue(indexIter.idEqual(workTreeIter));
+ }
}
@Test
public void submoduleWithNoGitDirectory() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- final RevCommit id = git.commit().setMessage("create file").call();
- final String path = "sub";
- DirCache cache = db.lockDirCache();
- DirCacheEditor editor = cache.editor();
- editor.add(new PathEdit(path) {
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ final RevCommit id = git.commit().setMessage("create file").call();
+ final String path = "sub";
+ DirCache cache = db.lockDirCache();
+ DirCacheEditor editor = cache.editor();
+ editor.add(new PathEdit(path) {
- public void apply(DirCacheEntry ent) {
- ent.setFileMode(FileMode.GITLINK);
- ent.setObjectId(id);
- }
- });
- editor.commit();
+ public void apply(DirCacheEntry ent) {
+ ent.setFileMode(FileMode.GITLINK);
+ ent.setObjectId(id);
+ }
+ });
+ editor.commit();
- File submoduleRoot = new File(db.getWorkTree(), path);
- assertTrue(submoduleRoot.mkdir());
- assertTrue(new File(submoduleRoot, Constants.DOT_GIT).mkdir());
+ File submoduleRoot = new File(db.getWorkTree(), path);
+ assertTrue(submoduleRoot.mkdir());
+ assertTrue(new File(submoduleRoot, Constants.DOT_GIT).mkdir());
- TreeWalk walk = new TreeWalk(db);
- DirCacheIterator indexIter = new DirCacheIterator(db.readDirCache());
- FileTreeIterator workTreeIter = new FileTreeIterator(db);
- walk.addTree(indexIter);
- walk.addTree(workTreeIter);
- walk.setFilter(PathFilter.create(path));
+ DirCacheIterator indexIter = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator workTreeIter = new FileTreeIterator(db);
+ walk.addTree(indexIter);
+ walk.addTree(workTreeIter);
+ walk.setFilter(PathFilter.create(path));
- assertTrue(walk.next());
- assertFalse(indexIter.idEqual(workTreeIter));
- assertEquals(ObjectId.zeroId(), workTreeIter.getEntryObjectId());
+ assertTrue(walk.next());
+ assertFalse(indexIter.idEqual(workTreeIter));
+ assertEquals(ObjectId.zeroId(), workTreeIter.getEntryObjectId());
+ }
}
@Test
public void submoduleWithNoHead() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- final RevCommit id = git.commit().setMessage("create file").call();
- final String path = "sub";
- DirCache cache = db.lockDirCache();
- DirCacheEditor editor = cache.editor();
- editor.add(new PathEdit(path) {
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ final RevCommit id = git.commit().setMessage("create file").call();
+ final String path = "sub";
+ DirCache cache = db.lockDirCache();
+ DirCacheEditor editor = cache.editor();
+ editor.add(new PathEdit(path) {
- public void apply(DirCacheEntry ent) {
- ent.setFileMode(FileMode.GITLINK);
- ent.setObjectId(id);
- }
- });
- editor.commit();
+ public void apply(DirCacheEntry ent) {
+ ent.setFileMode(FileMode.GITLINK);
+ ent.setObjectId(id);
+ }
+ });
+ editor.commit();
- assertNotNull(Git.init().setDirectory(new File(db.getWorkTree(), path))
- .call().getRepository());
+ assertNotNull(Git.init().setDirectory(new File(db.getWorkTree(), path))
+ .call().getRepository());
- TreeWalk walk = new TreeWalk(db);
- DirCacheIterator indexIter = new DirCacheIterator(db.readDirCache());
- FileTreeIterator workTreeIter = new FileTreeIterator(db);
- walk.addTree(indexIter);
- walk.addTree(workTreeIter);
- walk.setFilter(PathFilter.create(path));
+ DirCacheIterator indexIter = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator workTreeIter = new FileTreeIterator(db);
+ walk.addTree(indexIter);
+ walk.addTree(workTreeIter);
+ walk.setFilter(PathFilter.create(path));
- assertTrue(walk.next());
- assertFalse(indexIter.idEqual(workTreeIter));
- assertEquals(ObjectId.zeroId(), workTreeIter.getEntryObjectId());
+ assertTrue(walk.next());
+ assertFalse(indexIter.idEqual(workTreeIter));
+ assertEquals(ObjectId.zeroId(), workTreeIter.getEntryObjectId());
+ }
}
@Test
public void submoduleDirectoryIterator() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- final RevCommit id = git.commit().setMessage("create file").call();
- final String path = "sub";
- DirCache cache = db.lockDirCache();
- DirCacheEditor editor = cache.editor();
- editor.add(new PathEdit(path) {
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ final RevCommit id = git.commit().setMessage("create file").call();
+ final String path = "sub";
+ DirCache cache = db.lockDirCache();
+ DirCacheEditor editor = cache.editor();
+ editor.add(new PathEdit(path) {
- public void apply(DirCacheEntry ent) {
- ent.setFileMode(FileMode.GITLINK);
- ent.setObjectId(id);
- }
- });
- editor.commit();
+ public void apply(DirCacheEntry ent) {
+ ent.setFileMode(FileMode.GITLINK);
+ ent.setObjectId(id);
+ }
+ });
+ editor.commit();
- Git.cloneRepository().setURI(db.getDirectory().toURI().toString())
- .setDirectory(new File(db.getWorkTree(), path)).call()
- .getRepository().close();
+ Git.cloneRepository().setURI(db.getDirectory().toURI().toString())
+ .setDirectory(new File(db.getWorkTree(), path)).call()
+ .getRepository().close();
- TreeWalk walk = new TreeWalk(db);
- DirCacheIterator indexIter = new DirCacheIterator(db.readDirCache());
- FileTreeIterator workTreeIter = new FileTreeIterator(db.getWorkTree(),
- db.getFS(), db.getConfig().get(WorkingTreeOptions.KEY));
- walk.addTree(indexIter);
- walk.addTree(workTreeIter);
- walk.setFilter(PathFilter.create(path));
+ DirCacheIterator indexIter = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator workTreeIter = new FileTreeIterator(db.getWorkTree(),
+ db.getFS(), db.getConfig().get(WorkingTreeOptions.KEY));
+ walk.addTree(indexIter);
+ walk.addTree(workTreeIter);
+ walk.setFilter(PathFilter.create(path));
- assertTrue(walk.next());
- assertTrue(indexIter.idEqual(workTreeIter));
+ assertTrue(walk.next());
+ assertTrue(indexIter.idEqual(workTreeIter));
+ }
}
@Test
public void submoduleNestedWithHeadMatchingIndex() throws Exception {
- Git git = new Git(db);
- writeTrashFile("file.txt", "content");
- git.add().addFilepattern("file.txt").call();
- final RevCommit id = git.commit().setMessage("create file").call();
- final String path = "sub/dir1/dir2";
- DirCache cache = db.lockDirCache();
- DirCacheEditor editor = cache.editor();
- editor.add(new PathEdit(path) {
+ try (Git git = new Git(db);
+ TreeWalk walk = new TreeWalk(db)) {
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ final RevCommit id = git.commit().setMessage("create file").call();
+ final String path = "sub/dir1/dir2";
+ DirCache cache = db.lockDirCache();
+ DirCacheEditor editor = cache.editor();
+ editor.add(new PathEdit(path) {
- public void apply(DirCacheEntry ent) {
- ent.setFileMode(FileMode.GITLINK);
- ent.setObjectId(id);
- }
- });
- editor.commit();
+ public void apply(DirCacheEntry ent) {
+ ent.setFileMode(FileMode.GITLINK);
+ ent.setObjectId(id);
+ }
+ });
+ editor.commit();
- Git.cloneRepository().setURI(db.getDirectory().toURI().toString())
- .setDirectory(new File(db.getWorkTree(), path)).call()
- .getRepository().close();
+ Git.cloneRepository().setURI(db.getDirectory().toURI().toString())
+ .setDirectory(new File(db.getWorkTree(), path)).call()
+ .getRepository().close();
- TreeWalk walk = new TreeWalk(db);
- DirCacheIterator indexIter = new DirCacheIterator(db.readDirCache());
- FileTreeIterator workTreeIter = new FileTreeIterator(db);
- walk.addTree(indexIter);
- walk.addTree(workTreeIter);
- walk.setFilter(PathFilter.create(path));
+ DirCacheIterator indexIter = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator workTreeIter = new FileTreeIterator(db);
+ walk.addTree(indexIter);
+ walk.addTree(workTreeIter);
+ walk.setFilter(PathFilter.create(path));
- assertTrue(walk.next());
- assertTrue(indexIter.idEqual(workTreeIter));
+ assertTrue(walk.next());
+ assertTrue(indexIter.idEqual(workTreeIter));
+ }
}
@Test
public void idOffset() throws Exception {
- Git git = new Git(db);
- writeTrashFile("fileAinfsonly", "A");
- File fileBinindex = writeTrashFile("fileBinindex", "B");
- fsTick(fileBinindex);
- git.add().addFilepattern("fileBinindex").call();
- writeTrashFile("fileCinfsonly", "C");
- TreeWalk tw = new TreeWalk(db);
- DirCacheIterator indexIter = new DirCacheIterator(db.readDirCache());
- FileTreeIterator workTreeIter = new FileTreeIterator(db);
- tw.addTree(indexIter);
- tw.addTree(workTreeIter);
- workTreeIter.setDirCacheIterator(tw, 0);
- assertEntry("d46c305e85b630558ee19cc47e73d2e5c8c64cdc", "a,", tw);
- assertEntry("58ee403f98538ec02409538b3f80adf610accdec", "a,b", tw);
- assertEntry("0000000000000000000000000000000000000000", "a", tw);
- assertEntry("b8d30ff397626f0f1d3538d66067edf865e201d6", "a0b", tw);
- // The reason for adding this test. Check that the id is correct for
- // mixed
- assertEntry("8c7e5a667f1b771847fe88c01c3de34413a1b220",
- "fileAinfsonly", tw);
- assertEntry("7371f47a6f8bd23a8fa1a8b2a9479cdd76380e54", "fileBinindex",
- tw);
- assertEntry("96d80cd6c4e7158dbebd0849f4fb7ce513e5828c",
- "fileCinfsonly", tw);
- assertFalse(tw.next());
+ try (Git git = new Git(db);
+ TreeWalk tw = new TreeWalk(db)) {
+ writeTrashFile("fileAinfsonly", "A");
+ File fileBinindex = writeTrashFile("fileBinindex", "B");
+ fsTick(fileBinindex);
+ git.add().addFilepattern("fileBinindex").call();
+ writeTrashFile("fileCinfsonly", "C");
+ DirCacheIterator indexIter = new DirCacheIterator(db.readDirCache());
+ FileTreeIterator workTreeIter = new FileTreeIterator(db);
+ tw.addTree(indexIter);
+ tw.addTree(workTreeIter);
+ workTreeIter.setDirCacheIterator(tw, 0);
+ assertEntry("d46c305e85b630558ee19cc47e73d2e5c8c64cdc", "a,", tw);
+ assertEntry("58ee403f98538ec02409538b3f80adf610accdec", "a,b", tw);
+ assertEntry("0000000000000000000000000000000000000000", "a", tw);
+ assertEntry("b8d30ff397626f0f1d3538d66067edf865e201d6", "a0b", tw);
+ // The reason for adding this test. Check that the id is correct for
+ // mixed
+ assertEntry("8c7e5a667f1b771847fe88c01c3de34413a1b220",
+ "fileAinfsonly", tw);
+ assertEntry("7371f47a6f8bd23a8fa1a8b2a9479cdd76380e54", "fileBinindex",
+ tw);
+ assertEntry("96d80cd6c4e7158dbebd0849f4fb7ce513e5828c",
+ "fileCinfsonly", tw);
+ assertFalse(tw.next());
+ }
}
private static void assertEntry(String sha1string, String path, TreeWalk tw)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/ForPathTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/ForPathTest.java
index eaee8bb..3d9af35 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/ForPathTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/ForPathTest.java
@@ -84,21 +84,22 @@
ObjectId tree = tree0.writeTree(oi);
// Find the directories that were implicitly created above.
- TreeWalk tw = new TreeWalk(or);
- tw.addTree(tree);
ObjectId a = null;
ObjectId aSlashC = null;
- while (tw.next()) {
- if (tw.getPathString().equals("a")) {
- a = tw.getObjectId(0);
- tw.enterSubtree();
- while (tw.next()) {
- if (tw.getPathString().equals("a/c")) {
- aSlashC = tw.getObjectId(0);
- break;
+ try (TreeWalk tw = new TreeWalk(or)) {
+ tw.addTree(tree);
+ while (tw.next()) {
+ if (tw.getPathString().equals("a")) {
+ a = tw.getObjectId(0);
+ tw.enterSubtree();
+ while (tw.next()) {
+ if (tw.getPathString().equals("a/c")) {
+ aSlashC = tw.getObjectId(0);
+ break;
+ }
}
+ break;
}
- break;
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/PostOrderTreeWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/PostOrderTreeWalkTest.java
index acbbb39..6ad47c2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/PostOrderTreeWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/PostOrderTreeWalkTest.java
@@ -60,124 +60,124 @@
public class PostOrderTreeWalkTest extends RepositoryTestCase {
@Test
public void testInitialize_NoPostOrder() throws Exception {
- final TreeWalk tw = new TreeWalk(db);
- assertFalse(tw.isPostOrderTraversal());
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ assertFalse(tw.isPostOrderTraversal());
+ }
}
@Test
public void testInitialize_TogglePostOrder() throws Exception {
- final TreeWalk tw = new TreeWalk(db);
- assertFalse(tw.isPostOrderTraversal());
- tw.setPostOrderTraversal(true);
- assertTrue(tw.isPostOrderTraversal());
- tw.setPostOrderTraversal(false);
- assertFalse(tw.isPostOrderTraversal());
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ assertFalse(tw.isPostOrderTraversal());
+ tw.setPostOrderTraversal(true);
+ assertTrue(tw.isPostOrderTraversal());
+ tw.setPostOrderTraversal(false);
+ assertFalse(tw.isPostOrderTraversal());
+ }
}
@Test
public void testResetDoesNotAffectPostOrder() throws Exception {
- final TreeWalk tw = new TreeWalk(db);
- tw.setPostOrderTraversal(true);
- assertTrue(tw.isPostOrderTraversal());
- tw.reset();
- assertTrue(tw.isPostOrderTraversal());
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.setPostOrderTraversal(true);
+ assertTrue(tw.isPostOrderTraversal());
+ tw.reset();
+ assertTrue(tw.isPostOrderTraversal());
- tw.setPostOrderTraversal(false);
- assertFalse(tw.isPostOrderTraversal());
- tw.reset();
- assertFalse(tw.isPostOrderTraversal());
+ tw.setPostOrderTraversal(false);
+ assertFalse(tw.isPostOrderTraversal());
+ tw.reset();
+ assertFalse(tw.isPostOrderTraversal());
+ }
}
@Test
public void testNoPostOrder() throws Exception {
final DirCache tree = db.readDirCache();
- {
- final DirCacheBuilder b = tree.builder();
+ final DirCacheBuilder b = tree.builder();
- b.add(makeFile("a"));
- b.add(makeFile("b/c"));
- b.add(makeFile("b/d"));
- b.add(makeFile("q"));
+ b.add(makeFile("a"));
+ b.add(makeFile("b/c"));
+ b.add(makeFile("b/d"));
+ b.add(makeFile("q"));
- b.finish();
- assertEquals(4, tree.getEntryCount());
+ b.finish();
+ assertEquals(4, tree.getEntryCount());
+
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.setPostOrderTraversal(false);
+ tw.addTree(new DirCacheIterator(tree));
+
+ assertModes("a", REGULAR_FILE, tw);
+ assertModes("b", TREE, tw);
+ assertTrue(tw.isSubtree());
+ assertFalse(tw.isPostChildren());
+ tw.enterSubtree();
+ assertModes("b/c", REGULAR_FILE, tw);
+ assertModes("b/d", REGULAR_FILE, tw);
+ assertModes("q", REGULAR_FILE, tw);
}
-
- final TreeWalk tw = new TreeWalk(db);
- tw.setPostOrderTraversal(false);
- tw.addTree(new DirCacheIterator(tree));
-
- assertModes("a", REGULAR_FILE, tw);
- assertModes("b", TREE, tw);
- assertTrue(tw.isSubtree());
- assertFalse(tw.isPostChildren());
- tw.enterSubtree();
- assertModes("b/c", REGULAR_FILE, tw);
- assertModes("b/d", REGULAR_FILE, tw);
- assertModes("q", REGULAR_FILE, tw);
}
@Test
public void testWithPostOrder_EnterSubtree() throws Exception {
final DirCache tree = db.readDirCache();
- {
- final DirCacheBuilder b = tree.builder();
+ final DirCacheBuilder b = tree.builder();
- b.add(makeFile("a"));
- b.add(makeFile("b/c"));
- b.add(makeFile("b/d"));
- b.add(makeFile("q"));
+ b.add(makeFile("a"));
+ b.add(makeFile("b/c"));
+ b.add(makeFile("b/d"));
+ b.add(makeFile("q"));
- b.finish();
- assertEquals(4, tree.getEntryCount());
+ b.finish();
+ assertEquals(4, tree.getEntryCount());
+
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.setPostOrderTraversal(true);
+ tw.addTree(new DirCacheIterator(tree));
+
+ assertModes("a", REGULAR_FILE, tw);
+
+ assertModes("b", TREE, tw);
+ assertTrue(tw.isSubtree());
+ assertFalse(tw.isPostChildren());
+ tw.enterSubtree();
+ assertModes("b/c", REGULAR_FILE, tw);
+ assertModes("b/d", REGULAR_FILE, tw);
+
+ assertModes("b", TREE, tw);
+ assertTrue(tw.isSubtree());
+ assertTrue(tw.isPostChildren());
+
+ assertModes("q", REGULAR_FILE, tw);
}
-
- final TreeWalk tw = new TreeWalk(db);
- tw.setPostOrderTraversal(true);
- tw.addTree(new DirCacheIterator(tree));
-
- assertModes("a", REGULAR_FILE, tw);
-
- assertModes("b", TREE, tw);
- assertTrue(tw.isSubtree());
- assertFalse(tw.isPostChildren());
- tw.enterSubtree();
- assertModes("b/c", REGULAR_FILE, tw);
- assertModes("b/d", REGULAR_FILE, tw);
-
- assertModes("b", TREE, tw);
- assertTrue(tw.isSubtree());
- assertTrue(tw.isPostChildren());
-
- assertModes("q", REGULAR_FILE, tw);
}
@Test
public void testWithPostOrder_NoEnterSubtree() throws Exception {
final DirCache tree = db.readDirCache();
- {
- final DirCacheBuilder b = tree.builder();
+ final DirCacheBuilder b = tree.builder();
- b.add(makeFile("a"));
- b.add(makeFile("b/c"));
- b.add(makeFile("b/d"));
- b.add(makeFile("q"));
+ b.add(makeFile("a"));
+ b.add(makeFile("b/c"));
+ b.add(makeFile("b/d"));
+ b.add(makeFile("q"));
- b.finish();
- assertEquals(4, tree.getEntryCount());
+ b.finish();
+ assertEquals(4, tree.getEntryCount());
+
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.setPostOrderTraversal(true);
+ tw.addTree(new DirCacheIterator(tree));
+
+ assertModes("a", REGULAR_FILE, tw);
+
+ assertModes("b", TREE, tw);
+ assertTrue(tw.isSubtree());
+ assertFalse(tw.isPostChildren());
+
+ assertModes("q", REGULAR_FILE, tw);
}
-
- final TreeWalk tw = new TreeWalk(db);
- tw.setPostOrderTraversal(true);
- tw.addTree(new DirCacheIterator(tree));
-
- assertModes("a", REGULAR_FILE, tw);
-
- assertModes("b", TREE, tw);
- assertTrue(tw.isSubtree());
- assertFalse(tw.isPostChildren());
-
- assertModes("q", REGULAR_FILE, tw);
}
private DirCacheEntry makeFile(final String path) throws Exception {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java
index aca7c80..c3ff7df 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java
@@ -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.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 @@
// 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());
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java
index bb1f2a6..ba8f194 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkJava7Test.java
@@ -55,17 +55,19 @@
public class TreeWalkJava7Test extends RepositoryTestCase {
@Test
public void testSymlinkToDirNotRecursingViaSymlink() throws Exception {
+ org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
FS fs = db.getFS();
assertTrue(fs.supportsSymlinks());
writeTrashFile("target/data", "targetdata");
fs.createSymLink(new File(trash, "link"), "target");
- TreeWalk tw = new TreeWalk(db);
- tw.setRecursive(true);
- tw.addTree(new FileTreeIterator(db));
- assertTrue(tw.next());
- assertEquals("link", tw.getPathString());
- assertTrue(tw.next());
- assertEquals("target/data", tw.getPathString());
- assertFalse(tw.next());
+ try (TreeWalk tw = new TreeWalk(db)) {
+ tw.setRecursive(true);
+ tw.addTree(new FileTreeIterator(db));
+ assertTrue(tw.next());
+ assertEquals("link", tw.getPathString());
+ assertTrue(tw.next());
+ assertEquals("target/data", tw.getPathString());
+ assertFalse(tw.next());
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilterTest.java
index b3aa0ee..9f0f067 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/InterIndexDiffFilterTest.java
@@ -76,10 +76,11 @@
public void testEmpty() throws IOException {
DirCache dc1 = DirCache.newInCore();
DirCache dc2 = DirCache.newInCore();
- TreeWalk tw = new TreeWalk(db);
- tw.addTree(new DirCacheIterator(dc1));
- tw.addTree(new DirCacheIterator(dc2));
- assertFalse(tw.next());
+ try (TreeWalk tw = new TreeWalk(db)) {
+ tw.addTree(new DirCacheIterator(dc1));
+ tw.addTree(new DirCacheIterator(dc2));
+ assertFalse(tw.next());
+ }
}
static final class AddEdit extends PathEdit {
@@ -124,14 +125,15 @@
editor.add(new AddEdit("a/a", FileMode.REGULAR_FILE, id("a"), 1, false));
editor.finish();
- TreeWalk tw = new TreeWalk(db);
- tw.setRecursive(true);
- tw.addTree(new DirCacheIterator(dc1));
- tw.addTree(new DirCacheIterator(dc2));
- tw.setFilter(InterIndexDiffFilter.INSTANCE);
- assertTrue(tw.next());
- assertEquals("a/a", tw.getPathString());
- assertFalse(tw.next());
+ try (TreeWalk tw = new TreeWalk(db)) {
+ tw.setRecursive(true);
+ tw.addTree(new DirCacheIterator(dc1));
+ tw.addTree(new DirCacheIterator(dc2));
+ tw.setFilter(InterIndexDiffFilter.INSTANCE);
+ assertTrue(tw.next());
+ assertEquals("a/a", tw.getPathString());
+ assertFalse(tw.next());
+ }
}
@Test
@@ -145,13 +147,14 @@
ed2.add(new AddEdit("a/a", FileMode.REGULAR_FILE, id("a"), 1, false));
ed2.finish();
- TreeWalk tw = new TreeWalk(db);
- tw.setRecursive(true);
- tw.addTree(new DirCacheIterator(dc1));
- tw.addTree(new DirCacheIterator(dc2));
- tw.setFilter(InterIndexDiffFilter.INSTANCE);
+ try (TreeWalk tw = new TreeWalk(db)) {
+ tw.setRecursive(true);
+ tw.addTree(new DirCacheIterator(dc1));
+ tw.addTree(new DirCacheIterator(dc2));
+ tw.setFilter(InterIndexDiffFilter.INSTANCE);
- assertFalse(tw.next());
+ assertFalse(tw.next());
+ }
}
@Test
@@ -165,15 +168,16 @@
ed2.add(new AddEdit("a/a", FileMode.REGULAR_FILE, id("a"), 1, true));
ed2.finish();
- TreeWalk tw = new TreeWalk(db);
- tw.setRecursive(true);
- tw.addTree(new DirCacheIterator(dc1));
- tw.addTree(new DirCacheIterator(dc2));
- tw.setFilter(InterIndexDiffFilter.INSTANCE);
+ try (TreeWalk tw = new TreeWalk(db)) {
+ tw.setRecursive(true);
+ tw.addTree(new DirCacheIterator(dc1));
+ tw.addTree(new DirCacheIterator(dc2));
+ tw.setFilter(InterIndexDiffFilter.INSTANCE);
- assertTrue(tw.next());
- assertEquals("a/a", tw.getPathString());
- assertFalse(tw.next());
+ assertTrue(tw.next());
+ assertEquals("a/a", tw.getPathString());
+ assertFalse(tw.next());
+ }
}
@Test
@@ -188,12 +192,13 @@
ed2.add(new AddEdit("a/a", FileMode.REGULAR_FILE, id("b"), 1, true));
ed2.finish();
- TreeWalk tw = new TreeWalk(db);
- tw.setRecursive(true);
- tw.addTree(new DirCacheIterator(dc1));
- tw.addTree(new DirCacheIterator(dc2));
- tw.setFilter(InterIndexDiffFilter.INSTANCE);
+ try (TreeWalk tw = new TreeWalk(db)) {
+ tw.setRecursive(true);
+ tw.addTree(new DirCacheIterator(dc1));
+ tw.addTree(new DirCacheIterator(dc2));
+ tw.setFilter(InterIndexDiffFilter.INSTANCE);
- assertFalse(tw.next());
+ assertFalse(tw.next());
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java
index d0062e1..5edc192 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathFilterGroupTest.java
@@ -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.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 @@
private TreeFilter filter;
+ private Map<String, TreeFilter> singles;
+
@Before
public void setup() {
// @formatter:off
@@ -81,64 +91,75 @@
};
// @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 @@
// 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 @@
}
}
+ 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 @@
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;
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathSuffixFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathSuffixFilterTest.java
index d871c5e..3885c41 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathSuffixFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathSuffixFilterTest.java
@@ -113,15 +113,16 @@
private List<String> getMatchingPaths(String suffixFilter,
final ObjectId treeId, boolean recursiveWalk) throws IOException {
- final TreeWalk tw = new TreeWalk(db);
- tw.setFilter(PathSuffixFilter.create(suffixFilter));
- tw.setRecursive(recursiveWalk);
- tw.addTree(treeId);
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.setFilter(PathSuffixFilter.create(suffixFilter));
+ tw.setRecursive(recursiveWalk);
+ tw.addTree(treeId);
- List<String> paths = new ArrayList<String>();
- while (tw.next())
- paths.add(tw.getPathString());
- return paths;
+ List<String> paths = new ArrayList<String>();
+ while (tw.next())
+ paths.add(tw.getPathString());
+ return paths;
+ }
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/TreeFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/TreeFilterTest.java
index 09007e7..c3423b6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/TreeFilterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/TreeFilterTest.java
@@ -55,9 +55,10 @@
public class TreeFilterTest extends RepositoryTestCase {
@Test
public void testALL_IncludesAnything() throws Exception {
- final TreeWalk tw = new TreeWalk(db);
- tw.addTree(new EmptyTreeIterator());
- assertTrue(TreeFilter.ALL.include(tw));
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.addTree(new EmptyTreeIterator());
+ assertTrue(TreeFilter.ALL.include(tw));
+ }
}
@Test
@@ -72,16 +73,18 @@
@Test
public void testNotALL_IncludesNothing() throws Exception {
- final TreeWalk tw = new TreeWalk(db);
- tw.addTree(new EmptyTreeIterator());
- assertFalse(TreeFilter.ALL.negate().include(tw));
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.addTree(new EmptyTreeIterator());
+ assertFalse(TreeFilter.ALL.negate().include(tw));
+ }
}
@Test
public void testANY_DIFF_IncludesSingleTreeCase() throws Exception {
- final TreeWalk tw = new TreeWalk(db);
- tw.addTree(new EmptyTreeIterator());
- assertTrue(TreeFilter.ANY_DIFF.include(tw));
+ try (final TreeWalk tw = new TreeWalk(db)) {
+ tw.addTree(new EmptyTreeIterator());
+ assertTrue(TreeFilter.ANY_DIFF.include(tw));
+ }
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java
index 7273cdb..aaeb79c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java
@@ -45,7 +45,6 @@
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 @@
}
@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
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java
index e6a244e..53b6fec 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSJava7Test.java
@@ -57,6 +57,7 @@
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.junit.After;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
@@ -87,6 +88,7 @@
*/
@Test
public void testSymlinkAttributes() throws IOException, InterruptedException {
+ Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
FS fs = FS.DETECTED;
File link = new File(trash, "ä");
File target = new File(trash, "å");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java
index 0d7d31b..1f78e02 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java
@@ -54,6 +54,7 @@
import org.eclipse.jgit.junit.JGitTestUtil;
import org.junit.After;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
@@ -424,19 +425,28 @@
@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
String base = toOSPathString("c:\\Users\\jdoe\\eclipse\\git\\project");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java
index 4625f30..cc1fdc2 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtils7Test.java
@@ -73,6 +73,7 @@
@Test
public void testDeleteSymlinkToDirectoryDoesNotDeleteTarget()
throws IOException {
+ org.junit.Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
FS fs = FS.DETECTED;
File dir = new File(trash, "dir");
File file = new File(dir, "file");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java
index b14a9bf..e07076e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java
@@ -112,7 +112,8 @@
ByteArrayOutputStream out = new ByteArrayOutputStream();
git.commit().setMessage("commit")
.setHookOutputStream(new PrintStream(out)).call();
- assertEquals(".git/COMMIT_EDITMSG\n", out.toString("UTF-8"));
+ assertEquals(".git/COMMIT_EDITMSG\n",
+ out.toString("UTF-8"));
}
@Test
@@ -144,6 +145,7 @@
new String[] {
"arg1", "arg2" },
new PrintStream(out), new PrintStream(err), "stdin");
+
assertEquals("unexpected hook output", "test arg1 arg2\nstdin\n",
out.toString("UTF-8"));
assertEquals("unexpected output on stderr stream", "stderr\n",
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java
new file mode 100644
index 0000000..7542ec8
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2016, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import static org.eclipse.jgit.util.Paths.compare;
+import static org.eclipse.jgit.util.Paths.compareSameName;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.junit.Test;
+
+public class PathsTest {
+ @Test
+ public void testStripTrailingSeparator() {
+ assertNull(Paths.stripTrailingSeparator(null));
+ assertEquals("", Paths.stripTrailingSeparator(""));
+ assertEquals("a", Paths.stripTrailingSeparator("a"));
+ assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo"));
+ assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo/"));
+ assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo//"));
+ assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo///"));
+ }
+
+ @Test
+ public void testPathCompare() {
+ byte[] a = Constants.encode("afoo/bar.c");
+ byte[] b = Constants.encode("bfoo/bar.c");
+
+ assertEquals(0, compare(a, 1, a.length, 0, b, 1, b.length, 0));
+ assertEquals(-1, compare(a, 0, a.length, 0, b, 0, b.length, 0));
+ assertEquals(1, compare(b, 0, b.length, 0, a, 0, a.length, 0));
+
+ a = Constants.encode("a");
+ b = Constants.encode("aa");
+ assertEquals(-97, compare(a, 0, a.length, 0, b, 0, b.length, 0));
+ assertEquals(0, compare(a, 0, a.length, 0, b, 0, 1, 0));
+ assertEquals(0, compare(a, 0, a.length, 0, b, 1, 2, 0));
+ assertEquals(0, compareSameName(a, 0, a.length, b, 1, b.length, 0));
+ assertEquals(0, compareSameName(a, 0, a.length, b, 0, 1, 0));
+ assertEquals(-50, compareSameName(a, 0, a.length, b, 0, b.length, 0));
+ assertEquals(97, compareSameName(b, 0, b.length, a, 0, a.length, 0));
+
+ a = Constants.encode("a");
+ b = Constants.encode("a");
+ assertEquals(0, compare(
+ a, 0, a.length, FileMode.TREE.getBits(),
+ b, 0, b.length, FileMode.TREE.getBits()));
+ assertEquals(0, compare(
+ a, 0, a.length, FileMode.REGULAR_FILE.getBits(),
+ b, 0, b.length, FileMode.REGULAR_FILE.getBits()));
+ assertEquals(-47, compare(
+ a, 0, a.length, FileMode.REGULAR_FILE.getBits(),
+ b, 0, b.length, FileMode.TREE.getBits()));
+ assertEquals(47, compare(
+ a, 0, a.length, FileMode.TREE.getBits(),
+ b, 0, b.length, FileMode.REGULAR_FILE.getBits()));
+
+ assertEquals(0, compareSameName(
+ a, 0, a.length,
+ b, 0, b.length, FileMode.TREE.getBits()));
+ assertEquals(0, compareSameName(
+ a, 0, a.length,
+ b, 0, b.length, FileMode.REGULAR_FILE.getBits()));
+
+ a = Constants.encode("a.c");
+ b = Constants.encode("a");
+ byte[] c = Constants.encode("a0c");
+ assertEquals(-1, compare(
+ a, 0, a.length, FileMode.REGULAR_FILE.getBits(),
+ b, 0, b.length, FileMode.TREE.getBits()));
+ assertEquals(-1, compare(
+ b, 0, b.length, FileMode.TREE.getBits(),
+ c, 0, c.length, FileMode.REGULAR_FILE.getBits()));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java
new file mode 100644
index 0000000..7c0985e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.util.FS.ExecutionResult;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RunExternalScriptTest {
+ private static final String LF = "\n";
+
+ private ByteArrayOutputStream out;
+
+ private ByteArrayOutputStream err;
+
+ @Before
+ public void setUp() throws Exception {
+ out = new ByteArrayOutputStream();
+ err = new ByteArrayOutputStream();
+ }
+
+ @Test
+ public void testCopyStdIn() throws IOException, InterruptedException {
+ String inputStr = "a\nb\rc\r\nd";
+ File script = writeTempFile("cat -");
+ int rc = FS.DETECTED.runProcess(
+ new ProcessBuilder("sh", script.getPath()), out, err,
+ new ByteArrayInputStream(inputStr.getBytes()));
+ assertEquals(0, rc);
+ assertEquals(inputStr, new String(out.toByteArray()));
+ assertEquals("", new String(err.toByteArray()));
+ }
+
+ @Test
+ public void testCopyNullStdIn() throws IOException, InterruptedException {
+ File script = writeTempFile("cat -");
+ int rc = FS.DETECTED.runProcess(
+ new ProcessBuilder("sh", script.getPath()), out, err,
+ (InputStream) null);
+ assertEquals(0, rc);
+ assertEquals("", new String(out.toByteArray()));
+ assertEquals("", new String(err.toByteArray()));
+ }
+
+ @Test
+ public void testArguments() throws IOException, InterruptedException {
+ File script = writeTempFile("echo $#,$1,$2,$3,$4,$5,$6");
+ int rc = FS.DETECTED.runProcess(
+ new ProcessBuilder("sh",
+ script.getPath(), "a", "b", "c"), out, err, (InputStream) null);
+ assertEquals(0, rc);
+ assertEquals("3,a,b,c,,,\n", new String(out.toByteArray()));
+ assertEquals("", new String(err.toByteArray()));
+ }
+
+ @Test
+ public void testRc() throws IOException, InterruptedException {
+ File script = writeTempFile("exit 3");
+ int rc = FS.DETECTED.runProcess(
+ new ProcessBuilder("sh", script.getPath(), "a", "b", "c"),
+ out, err, (InputStream) null);
+ assertEquals(3, rc);
+ assertEquals("", new String(out.toByteArray()));
+ assertEquals("", new String(err.toByteArray()));
+ }
+
+ @Test
+ public void testNullStdout() throws IOException, InterruptedException {
+ File script = writeTempFile("echo hi");
+ int rc = FS.DETECTED.runProcess(
+ new ProcessBuilder("sh", script.getPath()), null, err,
+ (InputStream) null);
+ assertEquals(0, rc);
+ assertEquals("", new String(out.toByteArray()));
+ assertEquals("", new String(err.toByteArray()));
+ }
+
+ @Test
+ public void testStdErr() throws IOException, InterruptedException {
+ File script = writeTempFile("echo hi >&2");
+ int rc = FS.DETECTED.runProcess(
+ new ProcessBuilder("sh", script.getPath()), null, err,
+ (InputStream) null);
+ assertEquals(0, rc);
+ assertEquals("", new String(out.toByteArray()));
+ assertEquals("hi" + LF, new String(err.toByteArray()));
+ }
+
+ @Test
+ public void testAllTogetherBin() throws IOException, InterruptedException {
+ String inputStr = "a\nb\rc\r\nd";
+ File script = writeTempFile("echo $#,$1,$2,$3,$4,$5,$6 >&2 ; cat -; exit 5");
+ int rc = FS.DETECTED.runProcess(
+ new ProcessBuilder("sh", script.getPath(), "a", "b", "c"),
+ out, err, new ByteArrayInputStream(inputStr.getBytes()));
+ assertEquals(5, rc);
+ assertEquals(inputStr, new String(out.toByteArray()));
+ assertEquals("3,a,b,c,,," + LF, new String(err.toByteArray()));
+ }
+
+ @Test(expected = IOException.class)
+ public void testWrongSh() throws IOException, InterruptedException {
+ File script = writeTempFile("cat -");
+ FS.DETECTED.runProcess(
+ new ProcessBuilder("/bin/sh-foo", script.getPath(), "a", "b",
+ "c"), out, err, (InputStream) null);
+ }
+
+ @Test
+ public void testWrongScript() throws IOException, InterruptedException {
+ File script = writeTempFile("cat-foo -");
+ int rc = FS.DETECTED.runProcess(
+ new ProcessBuilder("sh", script.getPath(), "a", "b", "c"),
+ out, err, (InputStream) null);
+ assertEquals(127, rc);
+ }
+
+ @Test
+ public void testCopyStdInExecute()
+ throws IOException, InterruptedException {
+ String inputStr = "a\nb\rc\r\nd";
+ File script = writeTempFile("cat -");
+ ProcessBuilder pb = new ProcessBuilder("sh", script.getPath());
+ ExecutionResult res = FS.DETECTED.execute(pb,
+ new ByteArrayInputStream(inputStr.getBytes()));
+ assertEquals(0, res.getRc());
+ assertEquals(inputStr, new String(res.getStdout().toByteArray()));
+ assertEquals("", new String(res.getStderr().toByteArray()));
+ }
+
+ @Test
+ public void testStdErrExecute() throws IOException, InterruptedException {
+ File script = writeTempFile("echo hi >&2");
+ ProcessBuilder pb = new ProcessBuilder("sh", script.getPath());
+ ExecutionResult res = FS.DETECTED.execute(pb, null);
+ assertEquals(0, res.getRc());
+ assertEquals("", new String(res.getStdout().toByteArray()));
+ assertEquals("hi" + LF, new String(res.getStderr().toByteArray()));
+ }
+
+ @Test
+ public void testAllTogetherBinExecute()
+ throws IOException, InterruptedException {
+ String inputStr = "a\nb\rc\r\nd";
+ File script = writeTempFile(
+ "echo $#,$1,$2,$3,$4,$5,$6 >&2 ; cat -; exit 5");
+ ProcessBuilder pb = new ProcessBuilder("sh", script.getPath(), "a",
+ "b", "c");
+ ExecutionResult res = FS.DETECTED.execute(pb,
+ new ByteArrayInputStream(inputStr.getBytes()));
+ assertEquals(5, res.getRc());
+ assertEquals(inputStr, new String(res.getStdout().toByteArray()));
+ assertEquals("3,a,b,c,,," + LF,
+ new String(res.getStderr().toByteArray()));
+ }
+
+ private File writeTempFile(String body) throws IOException {
+ File f = File.createTempFile("RunProcessTestScript_", "");
+ JGitTestUtil.write(f, body);
+ return f;
+ }
+}
diff --git a/org.eclipse.jgit.ui/BUCK b/org.eclipse.jgit.ui/BUCK
new file mode 100644
index 0000000..fcd87cf
--- /dev/null
+++ b/org.eclipse.jgit.ui/BUCK
@@ -0,0 +1,7 @@
+java_library(
+ name = 'ui',
+ srcs = glob(['src/**']),
+ resources = glob(['resources/**']),
+ deps = ['//org.eclipse.jgit:jgit'],
+ visibility = ['PUBLIC'],
+)
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 3586cbc..f9e1a39 100644
--- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
@@ -3,14 +3,14 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.ui
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
Bundle-Vendor: %provider_name
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Export-Package: org.eclipse.jgit.awtui;version="4.1.2"
-Import-Package: org.eclipse.jgit.errors;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.lib;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.nls;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revplot;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.revwalk;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.transport;version="[4.1.2,4.2.0)",
- org.eclipse.jgit.util;version="[4.1.2,4.2.0)"
+Export-Package: org.eclipse.jgit.awtui;version="4.2.1"
+Import-Package: org.eclipse.jgit.errors;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.nls;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revplot;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.1,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.1,4.3.0)"
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index 776cb8b..c80f31f 100644
--- a/org.eclipse.jgit.ui/pom.xml
+++ b/org.eclipse.jgit.ui/pom.xml
@@ -52,7 +52,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ui</artifactId>
diff --git a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java
index fd26bfa..a9967ae 100644
--- a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java
+++ b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java
@@ -56,15 +56,20 @@
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
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index a1e79e2..36041f8 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -1,5 +1,75 @@
<?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>
+ <message_argument value="org.eclipse.jgit.attributes.AttributesNode"/>
+ <message_argument value="getAttributes(String, boolean, Map<String,Attribute>)"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/lib/BitmapIndex.java" type="org.eclipse.jgit.lib.BitmapIndex$BitmapBuilder">
+ <filter comment="interface is implemented by extenders but not clients of the API" id="403804204">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder"/>
+ <message_argument value="addObject(AnyObjectId, int)"/>
+ </message_arguments>
+ </filter>
+ <filter comment="interface is implemented by extenders but not clients of the API" id="403804204">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder"/>
+ <message_argument value="getBitmapIndex()"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/lib/Repository.java" type="org.eclipse.jgit.lib.Repository">
+ <filter comment="Only implementors of Repository are affected. That should be allowed" id="336695337">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.lib.Repository"/>
+ <message_argument value="createAttributesNodeProvider()"/>
+ </message_arguments>
+ </filter>
+ </resource>
<resource path="src/org/eclipse/jgit/transport/PushCertificate.java" type="org.eclipse.jgit.transport.PushCertificate">
<filter comment="PushCertificate wasn't really usable in 4.0" id="338722907">
<message_arguments>
@@ -21,4 +91,26 @@
</message_arguments>
</filter>
</resource>
+ <resource path="src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java" type="org.eclipse.jgit.treewalk.WorkingTreeIterator">
+ <filter comment="attributes weren't really usable in earlier versions" id="338792546">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.treewalk.WorkingTreeIterator"/>
+ <message_argument value="getGlobalAttributesNode()"/>
+ </message_arguments>
+ </filter>
+ <filter comment="attributes weren't really usable in earlier versions" id="338792546">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.treewalk.WorkingTreeIterator"/>
+ <message_argument value="getInfoAttributesNode()"/>
+ </message_arguments>
+ </filter>
+ </resource>
+ <resource path="src/org/eclipse/jgit/util/FileUtils.java" type="org.eclipse.jgit.util.FileUtils">
+ <filter id="338792546">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.util.FileUtils"/>
+ <message_argument value="createSymLink(File, String)"/>
+ </message_arguments>
+ </filter>
+ </resource>
</component>
diff --git a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
index 4e28e0b..45d6d2c 100644
--- a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
+++ b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs
@@ -1,9 +1,9 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
-org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
-org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
-org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jgit.annotations.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jgit.annotations.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jgit.annotations.Nullable
org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
diff --git a/org.eclipse.jgit/BUCK b/org.eclipse.jgit/BUCK
new file mode 100644
index 0000000..73e2080
--- /dev/null
+++ b/org.eclipse.jgit/BUCK
@@ -0,0 +1,20 @@
+SRCS = glob(['src/**'])
+RESOURCES = glob(['resources/**'])
+
+java_library(
+ name = 'jgit',
+ srcs = SRCS,
+ resources = RESOURCES,
+ deps = [
+ '//lib:javaewah',
+ '//lib:jsch',
+ '//lib:httpcomponents',
+ '//lib:slf4j-api',
+ ],
+ visibility = ['PUBLIC'],
+)
+
+java_sources(
+ name = 'jgit_src',
+ srcs = SRCS + RESOURCES,
+)
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index a51bee8..d0f03ff 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -2,11 +2,12 @@
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit
-Bundle-Version: 4.1.2.201602141800-r
+Bundle-Version: 4.2.1.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
-Export-Package: org.eclipse.jgit.api;version="4.1.2";
+Export-Package: org.eclipse.jgit.annotations;version="4.2.1",
+ org.eclipse.jgit.api;version="4.2.1";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff,
@@ -20,60 +21,55 @@
org.eclipse.jgit.submodule,
org.eclipse.jgit.transport,
org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="4.1.2";
- uses:="org.eclipse.jgit.lib,
- org.eclipse.jgit.errors",
- org.eclipse.jgit.attributes;version="4.1.2",
- org.eclipse.jgit.blame;version="4.1.2";
+ org.eclipse.jgit.api.errors;version="4.2.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors",
+ org.eclipse.jgit.attributes;version="4.2.1",
+ org.eclipse.jgit.blame;version="4.2.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff",
- org.eclipse.jgit.diff;version="4.1.2";
+ org.eclipse.jgit.diff;version="4.2.1";
uses:="org.eclipse.jgit.patch,
org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.util",
- org.eclipse.jgit.dircache;version="4.1.2";
+ org.eclipse.jgit.dircache;version="4.2.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.util,
org.eclipse.jgit.events,
org.eclipse.jgit.attributes",
- org.eclipse.jgit.errors;version="4.1.2";
+ org.eclipse.jgit.errors;version="4.2.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.internal.storage.pack,
org.eclipse.jgit.transport,
org.eclipse.jgit.dircache",
- org.eclipse.jgit.events;version="4.1.2";
- uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="4.1.2",
- org.eclipse.jgit.gitrepo;version="4.1.2";
+ org.eclipse.jgit.events;version="4.2.1";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.fnmatch;version="4.2.1",
+ org.eclipse.jgit.gitrepo;version="4.2.1";
uses:="org.eclipse.jgit.api,
org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.xml.sax.helpers,
org.xml.sax",
- org.eclipse.jgit.gitrepo.internal;version="4.1.2";x-internal:=true,
- org.eclipse.jgit.hooks;version="4.1.2";
- uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.ignore;version="4.1.2",
- org.eclipse.jgit.ignore.internal;version="4.1.2";x-friends:="org.eclipse.jgit.test",
- org.eclipse.jgit.internal;version="4.1.2";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
- org.eclipse.jgit.internal.storage.dfs;version="4.1.2";
- x-friends:="org.eclipse.jgit.test,
- org.eclipse.jgit.http.server",
- org.eclipse.jgit.internal.storage.file;version="4.1.2";
+ org.eclipse.jgit.gitrepo.internal;version="4.2.1";x-internal:=true,
+ org.eclipse.jgit.hooks;version="4.2.1";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.ignore;version="4.2.1",
+ org.eclipse.jgit.ignore.internal;version="4.2.1";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal;version="4.2.1";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.storage.dfs;version="4.2.1";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.server",
+ org.eclipse.jgit.internal.storage.file;version="4.2.1";
x-friends:="org.eclipse.jgit.test,
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.1.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
- org.eclipse.jgit.lib;version="4.1.2";
+ org.eclipse.jgit.internal.storage.pack;version="4.2.1";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.internal.storage.reftree;version="4.2.1";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.lib;version="4.2.1";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.util,
@@ -83,45 +79,32 @@
org.eclipse.jgit.treewalk,
org.eclipse.jgit.transport,
org.eclipse.jgit.submodule",
- org.eclipse.jgit.merge;version="4.1.2";
+ org.eclipse.jgit.merge;version="4.2.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.diff,
org.eclipse.jgit.dircache,
org.eclipse.jgit.api",
- org.eclipse.jgit.nls;version="4.1.2",
- org.eclipse.jgit.notes;version="4.1.2";
+ org.eclipse.jgit.nls;version="4.2.1",
+ org.eclipse.jgit.notes;version="4.2.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.merge",
- org.eclipse.jgit.patch;version="4.1.2";
- uses:="org.eclipse.jgit.lib,
- org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="4.1.2";
- uses:="org.eclipse.jgit.lib,
- org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="4.1.2";
+ org.eclipse.jgit.patch;version="4.2.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff",
+ org.eclipse.jgit.revplot;version="4.2.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk",
+ org.eclipse.jgit.revwalk;version="4.2.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff,
org.eclipse.jgit.revwalk.filter",
- org.eclipse.jgit.revwalk.filter;version="4.1.2";
- uses:="org.eclipse.jgit.revwalk,
- org.eclipse.jgit.lib,
- org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="4.1.2";
- uses:="org.eclipse.jgit.lib,
- org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="4.1.2";
- uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="4.1.2";
- uses:="org.eclipse.jgit.lib,
- org.eclipse.jgit.treewalk.filter,
- org.eclipse.jgit.treewalk",
- org.eclipse.jgit.transport;version="4.1.2";
+ org.eclipse.jgit.revwalk.filter;version="4.2.1";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.file;version="4.2.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util",
+ org.eclipse.jgit.storage.pack;version="4.2.1";uses:="org.eclipse.jgit.lib",
+ org.eclipse.jgit.submodule;version="4.2.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.transport;version="4.2.1";
uses:="org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.internal.storage.pack,
@@ -133,29 +116,24 @@
org.eclipse.jgit.transport.http,
org.eclipse.jgit.errors,
org.eclipse.jgit.storage.pack",
- org.eclipse.jgit.transport.http;version="4.1.2";
- uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="4.1.2";
- uses:="org.eclipse.jgit.lib,
- org.eclipse.jgit.transport",
- org.eclipse.jgit.treewalk;version="4.1.2";
+ org.eclipse.jgit.transport.http;version="4.2.1";uses:="javax.net.ssl",
+ org.eclipse.jgit.transport.resolver;version="4.2.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport",
+ org.eclipse.jgit.treewalk;version="4.2.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.attributes,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.util,
org.eclipse.jgit.dircache",
- org.eclipse.jgit.treewalk.filter;version="4.1.2";
- uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="4.1.2";
+ org.eclipse.jgit.treewalk.filter;version="4.2.1";uses:="org.eclipse.jgit.treewalk",
+ org.eclipse.jgit.util;version="4.2.1";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.transport.http,
org.eclipse.jgit.storage.file,
org.ietf.jgss",
- org.eclipse.jgit.util.io;version="4.1.2"
+ org.eclipse.jgit.util.io;version="4.2.1"
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)",
- org.eclipse.jdt.annotation;bundle-version="[1.1.0,2.0.0)";resolution:=optional
+Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)"
Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)",
javax.crypto,
javax.net.ssl,
diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
index c7d9753..98ede31 100644
--- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@
Bundle-Name: org.eclipse.jgit - Sources
Bundle-SymbolicName: org.eclipse.jgit.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.1.2.201602141800-r
-Eclipse-SourceBundle: org.eclipse.jgit;version="4.1.2.201602141800-r";roots="."
+Bundle-Version: 4.2.1.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="4.2.1.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index 945b135..e931990 100644
--- a/org.eclipse.jgit/pom.xml
+++ b/org.eclipse.jgit/pom.xml
@@ -53,7 +53,7 @@
<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit</artifactId>
@@ -88,12 +88,6 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
-
- <dependency>
- <groupId>org.eclipse.jdt</groupId>
- <artifactId>org.eclipse.jdt.annotation</artifactId>
- <version>1.1.0</version>
- </dependency>
</dependencies>
<build>
@@ -166,8 +160,45 @@
</plugin>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
+ <groupId>com.github.siom79.japicmp</groupId>
+ <artifactId>japicmp-maven-plugin</artifactId>
+ <version>${japicmp-version}</version>
+ <configuration>
+ <oldVersion>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${jgit-last-release-version}</version>
+ </dependency>
+ </oldVersion>
+ <newVersion>
+ <file>
+ <path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+ </file>
+ </newVersion>
+ <parameter>
+ <onlyModified>true</onlyModified>
+ <includes>
+ <include>org.eclipse.jgit.*</include>
+ </includes>
+ <accessModifier>public</accessModifier>
+ <breakBuildOnModifications>false</breakBuildOnModifications>
+ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
+ <onlyBinaryIncompatible>false</onlyBinaryIncompatible>
+ <includeSynthetic>false</includeSynthetic>
+ <ignoreMissingClasses>false</ignoreMissingClasses>
+ <skipPomModules>true</skipPomModules>
+ </parameter>
+ <skip>false</skip>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>cmp</goal>
+ </goals>
+ </execution>
+ </executions>
</plugin>
</plugins>
@@ -187,13 +218,44 @@
<reporting>
<plugins>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
- <version>${clirr-version}</version>
- <configuration>
- <comparisonVersion>${jgit-last-release-version}</comparisonVersion>
- <minSeverity>info</minSeverity>
- </configuration>
+ <groupId>com.github.siom79.japicmp</groupId>
+ <artifactId>japicmp-maven-plugin</artifactId>
+ <version>${japicmp-version}</version>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>cmp-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ <configuration>
+ <oldVersion>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${jgit-last-release-version}</version>
+ </dependency>
+ </oldVersion>
+ <newVersion>
+ <file>
+ <path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+ </file>
+ </newVersion>
+ <parameter>
+ <onlyModified>true</onlyModified>
+ <includes>
+ <include>org.eclipse.jgit.*</include>
+ </includes>
+ <accessModifier>public</accessModifier>
+ <breakBuildOnModifications>false</breakBuildOnModifications>
+ <breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
+ <onlyBinaryIncompatible>false</onlyBinaryIncompatible>
+ <includeSynthetic>false</includeSynthetic>
+ <ignoreMissingClasses>false</ignoreMissingClasses>
+ <skipPomModules>true</skipPomModules>
+ </parameter>
+ <skip>false</skip>
+ </configuration>
</plugin>
</plugins>
</reporting>
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index 34bbb41..992e10b 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -20,6 +20,7 @@
atLeastOnePathIsRequired=At least one path is required.
atLeastOnePatternIsRequired=At least one pattern is required.
atLeastTwoFiltersNeeded=At least two filters needed.
+atomicPushNotSupported=Atomic push not supported.
authenticationNotSupported=authentication not supported
badBase64InputCharacterAt=Bad Base64 input character at {0} : {1} (decimal)
badEntryDelimiter=Bad entry delimiter
@@ -45,6 +46,7 @@
cannotBeRecursiveWhenTreesAreIncluded=TreeWalk shouldn't be recursive when tree objects are included.
cannotChangeActionOnComment=Cannot change action on comment line in git-rebase-todo file, old action: {0}, new action: {1}.
cannotChangeToComment=Cannot change a non-comment line to a comment line.
+cannotCheckoutFromUnbornBranch=Cannot checkout from unborn branch
cannotCheckoutOursSwitchBranch=Checking out ours/theirs is only possible when checking out index, not when switching branches.
cannotCombineSquashWithNoff=Cannot combine --squash with --no-ff.
cannotCombineTreeFilterWithRevFilter=Cannot combine TreeFilter {0} with RevFilter {1}.
@@ -87,6 +89,7 @@
cannotReadCommit=Cannot read commit {0}
cannotReadFile=Cannot read file {0}
cannotReadHEAD=cannot read HEAD: {0} {1}
+cannotReadIndex=The index file {0} exists but cannot be read
cannotReadObject=Cannot read object
cannotReadObjectsPath=Cannot read {0}/{1}: {2}
cannotReadTree=Cannot read tree {0}
@@ -96,6 +99,7 @@
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.
@@ -122,14 +126,15 @@
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
@@ -148,11 +153,11 @@
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
@@ -178,6 +183,7 @@
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
@@ -228,6 +234,7 @@
emptyPathNotPermitted=Empty path not permitted.
emptyRef=Empty ref: {0}
encryptionError=Encryption error: {0}
+encryptionOnlyPBE=Encryption error: only password-based encryption (PBE) algorithms are supported.
endOfFileInEscape=End of file in escape
entryNotFoundByPath=Entry not found by path: {0}
enumValueNotSupported2=Invalid value: {0}.{1}={2}
@@ -278,6 +285,8 @@
fileIsTooBigForThisConvenienceMethod=File is too big for this convenience method ({0} bytes).
fileIsTooLarge=File is too large: {0}
fileModeNotSetForPath=FileMode not set for path {0}
+filterExecutionFailed=Execution of filter command ''{0}'' on file ''{1}'' failed
+filterExecutionFailedRc=Execution of filter command ''{0}'' on file ''{1}'' failed with return code ''{2}'', message on stderr: ''{3}''
findingGarbage=Finding garbage
flagIsDisposed={0} is disposed.
flagNotFromThis={0} not from this.
@@ -343,6 +352,7 @@
invalidReflogRevision=Invalid reflog revision: {0}
invalidRefName=Invalid ref name: {0}
invalidRemote=Invalid remote: {0}
+invalidRepositoryStateNoHead=Invalid repository --- cannot read HEAD
invalidShallowObject=invalid shallow object {0}, expected commit
invalidStageForPath=Invalid stage {0} for path {1}
invalidTagOption=Invalid tag option: {0}
@@ -425,6 +435,7 @@
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}.
@@ -449,6 +460,7 @@
packfileIsTruncatedNoParam=Packfile is truncated.
packHandleIsStale=Pack file {0} handle is stale, removing it from pack list
packHasUnresolvedDeltas=pack has unresolved deltas
+packInaccessible=Pack file {0} now inaccessible; removing it from pack list
packingCancelledDuringObjectsWriting=Packing cancelled during objects writing
packObjectCountMismatch=Pack object count mismatch: pack {0} index {1}: {2}
packRefs=Pack refs
@@ -587,6 +599,7 @@
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
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java
similarity index 60%
copy from org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
copy to org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java
index c7e41bc..08f81cb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/NonNull.java
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006-2007, Shawn O. Pearce <spearce@spearce.org>
+ * 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
@@ -42,44 +41,29 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package org.eclipse.jgit.lib;
+package org.eclipse.jgit.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
/**
- * A tree entry representing a symbolic link.
+ * JGit's replacement for the {@code javax.annotation.Nonnull}.
+ * <p>
+ * Denotes that a local variable, parameter, field, method return value expected
+ * to be non {@code null}.
*
- * Note. Java cannot really handle these as file system objects.
- *
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
+ * @since 4.2
*/
-@Deprecated
-public class SymlinkTreeEntry extends TreeEntry {
-
- /**
- * Construct a {@link SymlinkTreeEntry} with the specified name and SHA-1 in
- * the specified parent
- *
- * @param parent
- * @param id
- * @param nameUTF8
- */
- public SymlinkTreeEntry(final Tree parent, final ObjectId id,
- final byte[] nameUTF8) {
- super(parent, id, nameUTF8);
- }
-
- public FileMode getMode() {
- return FileMode.SYMLINK;
- }
-
- public String toString() {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(getId()));
- r.append(" S "); //$NON-NLS-1$
- r.append(getFullName());
- return r.toString();
- }
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({ FIELD, METHOD, PARAMETER, LOCAL_VARIABLE })
+public @interface NonNull {
+ // marker annotation with no members
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java
new file mode 100644
index 0000000..7b91567
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java
@@ -0,0 +1,100 @@
+/*
+ * 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.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks types that can hold the value {@code null} at run time.
+ * <p>
+ * Unlike {@code org.eclipse.jdt.annotation.Nullable}, this has run-time
+ * retention, allowing the annotation to be recognized by
+ * <a href="https://github.com/google/guice/wiki/UseNullable">Guice</a>. Unlike
+ * {@code javax.annotation.Nullable}, this does not involve importing new classes
+ * to a standard (Java EE) package, so it can be deployed in an OSGi container
+ * without running into
+ * <a href="http://wiki.osgi.org/wiki/Split_Packages">split-package</a>
+ * <a href="https://gerrit-review.googlesource.com/50112">problems</a>.
+ * <p>
+ * You can use this annotation to qualify a type in a method signature or local
+ * variable declaration. The entity whose type has this annotation is allowed to
+ * hold the value {@code null} at run time. This allows annotation based null
+ * analysis to infer that
+ * <ul>
+ * <li>Binding a {@code null} value to the entity is legal.
+ * <li>Dereferencing the entity is unsafe and can trigger a
+ * {@code NullPointerException}.
+ * </ul>
+ * <p>
+ * To avoid a dependency on Java 8, this annotation does not use
+ * {@link Target @Target} {@code TYPE_USE}. That may change when JGit starts
+ * requiring Java 8.
+ * <p>
+ * <b>Warning:</b> Please do not use this annotation on arrays. Different
+ * annotation processors treat {@code @Nullable Object[]} differently: some
+ * treat it as an array of nullable objects, for consistency with versions of
+ * {@code Nullable} defined with {@code @Target} {@code TYPE_USE}, while others
+ * treat it as a nullable array of objects. JGit therefore avoids using this
+ * annotation on arrays altogether.
+ *
+ * @see <a href=
+ * "http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html#faq-array-syntax-meaning">
+ * The checker-framework manual</a>
+ *
+ * @since 4.2
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ FIELD, METHOD, PARAMETER, LOCAL_VARIABLE })
+public @interface Nullable {
+ // marker annotation with no members
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
index de6c32a..3b94f16 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
@@ -43,11 +43,16 @@
*/
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;
import java.util.LinkedList;
+import org.eclipse.jgit.api.errors.FilterFailedException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
@@ -57,12 +62,13 @@
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;
@@ -133,81 +139,106 @@
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));
if (workingTreeIterator == null)
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;
}
- // 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());
- }
+ 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;
+ }
- } else if (c != null
- && (!update || FileMode.GITLINK == c
- .getEntryFileMode()))
- builder.add(c.getDirCacheEntry());
+ 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);
+ }
+ 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();
setCallable(false);
} catch (IOException e) {
+ Throwable cause = e.getCause();
+ if (cause != null && cause instanceof FilterFailedException)
+ throw (FilterFailedException) cause;
throw new JGitInternalException(
JGitText.get().exceptionCaughtDuringExecutionOfAddCommand, e);
} finally {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
index 6a945e4..676ae03 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
@@ -47,6 +47,7 @@
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 @@
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);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
index 8d8aada..4f918fa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -222,6 +222,12 @@
}
Ref headRef = repo.getRef(Constants.HEAD);
+ if (headRef == null) {
+ // TODO Git CLI supports checkout from unborn branch, we should
+ // also allow this
+ throw new UnsupportedOperationException(
+ JGitText.get().cannotCheckoutFromUnbornBranch);
+ }
String shortHeadRef = getShortBranchName(headRef);
String refLogMessage = "checkout: moving from " + shortHeadRef; //$NON-NLS-1$
ObjectId branch;
@@ -325,9 +331,16 @@
}
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();
}
/**
@@ -457,7 +470,7 @@
private void checkoutPath(DirCacheEntry entry, ObjectReader reader) {
try {
- DirCacheCheckout.checkoutEntry(repo, entry, reader);
+ DirCacheCheckout.checkoutEntry(repo, entry, reader, true);
} catch (IOException e) {
throw new JGitInternalException(MessageFormat.format(
JGitText.get().checkoutConflictWithFile,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
index b3bc319..2ac8729 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -61,6 +61,7 @@
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 @@
}
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 @@
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;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
index 6174d48..0abb8ba 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -53,6 +53,7 @@
import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
+import org.eclipse.jgit.api.errors.EmtpyCommitException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
@@ -86,6 +87,7 @@
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.eclipse.jgit.util.ChangeIdUtil;
/**
@@ -129,6 +131,8 @@
private PrintStream hookOutRedirect;
+ private Boolean allowEmpty;
+
/**
* @param repo
*/
@@ -178,7 +182,7 @@
processOptions(state, rw);
- if (all && !repo.isBare() && repo.getWorkTree() != null) {
+ if (all && !repo.isBare()) {
try (Git git = new Git(repo)) {
git.add()
.addFilepattern(".") //$NON-NLS-1$
@@ -230,6 +234,16 @@
if (insertChangeId)
insertChangeId(indexTreeId);
+ // Check for empty commits
+ if (headId != null && !allowEmpty.booleanValue()) {
+ RevCommit headCommit = rw.parseCommit(headId);
+ headCommit.getTree();
+ if (indexTreeId.equals(headCommit.getTree())) {
+ throw new EmtpyCommitException(
+ JGitText.get().emptyCommit);
+ }
+ }
+
// Create a Commit object, populate it and write it
CommitBuilder commit = new CommitBuilder();
commit.setCommitter(committer);
@@ -298,7 +312,7 @@
}
}
- private void insertChangeId(ObjectId treeId) throws IOException {
+ private void insertChangeId(ObjectId treeId) {
ObjectId firstParentId = null;
if (!parents.isEmpty())
firstParentId = parents.get(0);
@@ -328,9 +342,12 @@
boolean emptyCommit = true;
try (TreeWalk treeWalk = new TreeWalk(repo)) {
+ treeWalk.setOperationType(OperationType.CHECKIN_OP);
int dcIdx = treeWalk
.addTree(new DirCacheBuildIterator(existingBuilder));
- int fIdx = treeWalk.addTree(new FileTreeIterator(repo));
+ FileTreeIterator fti = new FileTreeIterator(repo);
+ fti.setDirCacheIterator(treeWalk, 0);
+ int fIdx = treeWalk.addTree(fti);
int hIdx = -1;
if (headId != null)
hIdx = treeWalk.addTree(rw.parseTree(headId));
@@ -453,6 +470,8 @@
// there must be at least one change
if (emptyCommit)
+ // Would like to throw a EmptyCommitException. But this would break the API
+ // TODO(ch): Change this in the next release
throw new JGitInternalException(JGitText.get().emptyCommit);
// update index
@@ -506,6 +525,12 @@
committer = new PersonIdent(repo);
if (author == null && !amend)
author = committer;
+ if (allowEmpty == null)
+ // JGit allows empty commits by default. Only when pathes are
+ // specified the commit should not be empty. This behaviour differs
+ // from native git but can only be adapted in the next release.
+ // TODO(ch) align the defaults with native git
+ allowEmpty = (only.isEmpty()) ? Boolean.TRUE : Boolean.FALSE;
// when doing a merge commit parse MERGE_HEAD and MERGE_MSG files
if (state == RepositoryState.MERGING_RESOLVED
@@ -575,6 +600,27 @@
}
/**
+ * @param allowEmpty
+ * whether it should be allowed to create a commit which has the
+ * same tree as it's sole predecessor (a commit which doesn't
+ * change anything). By default when creating standard commits
+ * (without specifying paths) JGit allows to create such commits.
+ * When this flag is set to false an attempt to create an "empty"
+ * standard commit will lead to an EmptyCommitException.
+ * <p>
+ * By default when creating a commit containing only specified
+ * paths an attempt to create an empty commit leads to a
+ * {@link JGitInternalException}. By setting this flag to
+ * <code>true</code> this exception will not be thrown.
+ * @return {@code this}
+ * @since 4.2
+ */
+ public CommitCommand setAllowEmpty(boolean allowEmpty) {
+ this.allowEmpty = Boolean.valueOf(allowEmpty);
+ return this;
+ }
+
+ /**
* @return the commit message used for the <code>commit</code>
*/
public String getMessage() {
@@ -677,7 +723,7 @@
*/
public CommitCommand setAll(boolean all) {
checkCallable();
- if (!only.isEmpty())
+ if (all && !only.isEmpty())
throw new JGitInternalException(MessageFormat.format(
JGitText.get().illegalCombinationOfArguments, "--all", //$NON-NLS-1$
"--only")); //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
index 9620089..de51276 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java
@@ -116,22 +116,17 @@
org.eclipse.jgit.api.errors.TransportException {
checkCallable();
- try {
- Transport transport = Transport.open(repo, remote);
- try {
- transport.setCheckFetchedObjects(checkFetchedObjects);
- transport.setRemoveDeletedRefs(isRemoveDeletedRefs());
- transport.setDryRun(dryRun);
- if (tagOption != null)
- transport.setTagOpt(tagOption);
- transport.setFetchThin(thin);
- configure(transport);
+ try (Transport transport = Transport.open(repo, remote)) {
+ transport.setCheckFetchedObjects(checkFetchedObjects);
+ transport.setRemoveDeletedRefs(isRemoveDeletedRefs());
+ transport.setDryRun(dryRun);
+ if (tagOption != null)
+ transport.setTagOpt(tagOption);
+ transport.setFetchThin(thin);
+ configure(transport);
- FetchResult result = transport.fetch(monitor, refSpecs);
- return result;
- } finally {
- transport.close();
- }
+ FetchResult result = transport.fetch(monitor, refSpecs);
+ return result;
} catch (NoRemoteRepositoryException e) {
throw new InvalidRemoteException(MessageFormat.format(
JGitText.get().invalidRemote, remote), e);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
index addca4c..2cd5f59 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
@@ -713,8 +713,48 @@
}
/**
- * @return the git repository this class is interacting with; see {@link
- * #close()} for notes on closing this repository.
+ * Return a command used to list the available remotes.
+ *
+ * @return a {@link RemoteListCommand}
+ * @since 4.2
+ */
+ public RemoteListCommand remoteList() {
+ return new RemoteListCommand(repo);
+ }
+
+ /**
+ * Return a command used to add a new remote.
+ *
+ * @return a {@link RemoteAddCommand}
+ * @since 4.2
+ */
+ public RemoteAddCommand remoteAdd() {
+ return new RemoteAddCommand(repo);
+ }
+
+ /**
+ * Return a command used to remove an existing remote.
+ *
+ * @return a {@link RemoteRemoveCommand}
+ * @since 4.2
+ */
+ public RemoteRemoveCommand remoteRemove() {
+ return new RemoteRemoveCommand(repo);
+ }
+
+ /**
+ * Return a command used to change the URL of an existing remote.
+ *
+ * @return a {@link RemoteSetUrlCommand}
+ * @since 4.2
+ */
+ public RemoteSetUrlCommand remoteSetUrl() {
+ return new RemoteSetUrlCommand(repo);
+ }
+
+ /**
+ * @return the git repository this class is interacting with; see
+ * {@link #close()} for notes on closing this repository.
*/
public Repository getRepository() {
return repo;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java
index 3363a0f..f3527fd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/LsRemoteCommand.java
@@ -182,13 +182,9 @@
org.eclipse.jgit.api.errors.TransportException {
checkCallable();
- Transport transport = null;
- FetchConnection fc = null;
- try {
- if (repo != null)
- transport = Transport.open(repo, remote);
- else
- transport = Transport.open(new URIish(remote));
+ try (Transport transport = repo != null
+ ? Transport.open(repo, remote)
+ : Transport.open(new URIish(remote))) {
transport.setOptionUploadPack(uploadPack);
configure(transport);
Collection<RefSpec> refSpecs = new ArrayList<RefSpec>(1);
@@ -199,19 +195,20 @@
refSpecs.add(new RefSpec("refs/heads/*:refs/remotes/origin/*")); //$NON-NLS-1$
Collection<Ref> refs;
Map<String, Ref> refmap = new HashMap<String, Ref>();
- fc = transport.openFetch();
- refs = fc.getRefs();
- if (refSpecs.isEmpty())
- for (Ref r : refs)
- refmap.put(r.getName(), r);
- else
- for (Ref r : refs)
- for (RefSpec rs : refSpecs)
- if (rs.matchSource(r)) {
- refmap.put(r.getName(), r);
- break;
- }
- return refmap;
+ try (FetchConnection fc = transport.openFetch()) {
+ refs = fc.getRefs();
+ if (refSpecs.isEmpty())
+ for (Ref r : refs)
+ refmap.put(r.getName(), r);
+ else
+ for (Ref r : refs)
+ for (RefSpec rs : refSpecs)
+ if (rs.matchSource(r)) {
+ refmap.put(r.getName(), r);
+ break;
+ }
+ return refmap;
+ }
} catch (URISyntaxException e) {
throw new InvalidRemoteException(MessageFormat.format(
JGitText.get().invalidRemote, remote));
@@ -223,11 +220,6 @@
throw new org.eclipse.jgit.api.errors.TransportException(
e.getMessage(),
e);
- } finally {
- if (fc != null)
- fc.close();
- if (transport != null)
- transport.close();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
index d2075a7..bfe90a3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
* Copyright (C) 2010-2014, Stefan Lay <stefan.lay@sap.com>
+ * Copyright (C) 2016, Laurent Delaigue <laurent.delaigue@obeo.fr>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -65,8 +66,10 @@
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Config.ConfigEnum;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Ref.Storage;
import org.eclipse.jgit.lib.RefUpdate;
@@ -106,6 +109,8 @@
private String message;
+ private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
+
/**
* The modes available for fast forward merges corresponding to the
* <code>--ff</code>, <code>--no-ff</code> and <code>--ff-only</code>
@@ -330,6 +335,7 @@
repo.writeSquashCommitMsg(squashMessage);
}
Merger merger = mergeStrategy.newMerger(repo);
+ merger.setProgressMonitor(monitor);
boolean noProblems;
Map<String, org.eclipse.jgit.merge.MergeResult<?>> lowLevelResults = null;
Map<String, MergeFailureReason> failingPaths = null;
@@ -586,4 +592,23 @@
this.message = message;
return this;
}
+
+ /**
+ * The progress monitor associated with the diff operation. By default, this
+ * is set to <code>NullProgressMonitor</code>
+ *
+ * @see NullProgressMonitor
+ *
+ * @param monitor
+ * A progress monitor
+ * @return this instance
+ * @since 4.2
+ */
+ public MergeCommand setProgressMonitor(ProgressMonitor monitor) {
+ if (monitor == null) {
+ monitor = NullProgressMonitor.INSTANCE;
+ }
+ this.monitor = monitor;
+ return this;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
index 2783edd..549ef6c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
+ * Copyright (C) 2016, Laurent Delaigue <laurent.delaigue@obeo.fr>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -326,6 +327,7 @@
MergeCommand merge = new MergeCommand(repo);
merge.include(upstreamName, commitToMerge);
merge.setStrategy(strategy);
+ merge.setProgressMonitor(monitor);
MergeResult mergeRes = merge.call();
monitor.update(1);
result = new PullResult(fetchRes, remote, mergeRes);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
index 227e322..f5b82bd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
@@ -89,9 +89,8 @@
private String receivePack = RemoteConfig.DEFAULT_RECEIVE_PACK;
private boolean dryRun;
-
+ private boolean atomic;
private boolean force;
-
private boolean thin = Transport.DEFAULT_PUSH_THIN;
private OutputStream out;
@@ -145,6 +144,7 @@
transports = Transport.openAll(repo, remote, Transport.Operation.PUSH);
for (final Transport transport : transports) {
transport.setPushThin(thin);
+ transport.setPushAtomic(atomic);
if (receivePack != null)
transport.setOptionReceivePack(receivePack);
transport.setDryRun(dryRun);
@@ -397,6 +397,29 @@
}
/**
+ * @return true if all-or-nothing behavior is requested.
+ * @since 4.2
+ */
+ public boolean isAtomic() {
+ return atomic;
+ }
+
+ /**
+ * Requests atomic push (all references updated, or no updates).
+ *
+ * Default setting is false.
+ *
+ * @param atomic
+ * @return {@code this}
+ * @since 4.2
+ */
+ public PushCommand setAtomic(boolean atomic) {
+ checkCallable();
+ this.atomic = atomic;
+ return this;
+ }
+
+ /**
* @return the force preference for push operation
*/
public boolean isForce() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
index ff29008..643ec7a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010, 2013 Mathias Kinzler <mathias.kinzler@sap.com>
+ * Copyright (C) 2016, Laurent Delaigue <laurent.delaigue@obeo.fr>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -560,6 +561,8 @@
lastStepWasForward = newHead != null;
if (!lastStepWasForward) {
ObjectId headId = getHead().getObjectId();
+ // getHead() checks for null
+ assert headId != null;
if (!AnyObjectId.equals(headId, newParents.get(0)))
checkoutCommit(headId.getName(), newParents.get(0));
@@ -609,6 +612,7 @@
// their non-first parents rewritten
MergeCommand merge = git.merge()
.setFastForward(MergeCommand.FastForwardMode.NO_FF)
+ .setProgressMonitor(monitor)
.setCommit(false);
for (int i = 1; i < commitToPick.getParentCount(); i++)
merge.include(newParents.get(i));
@@ -668,12 +672,15 @@
}
private void writeRewrittenHashes() throws RevisionSyntaxException,
- IOException {
+ IOException, RefNotFoundException {
File currentCommitFile = rebaseState.getFile(CURRENT_COMMIT);
if (!currentCommitFile.exists())
return;
- String head = repo.resolve(Constants.HEAD).getName();
+ ObjectId headId = getHead().getObjectId();
+ // getHead() checks for null
+ assert headId != null;
+ String head = headId.getName();
String currentCommits = rebaseState.readFile(CURRENT_COMMIT);
for (String current : currentCommits.split("\n")) //$NON-NLS-1$
RebaseState
@@ -743,8 +750,8 @@
private void resetSoftToParent() throws IOException,
GitAPIException, CheckoutConflictException {
- Ref orig_head = repo.getRef(Constants.ORIG_HEAD);
- ObjectId orig_headId = orig_head.getObjectId();
+ Ref ref = repo.getRef(Constants.ORIG_HEAD);
+ ObjectId orig_head = ref == null ? null : ref.getObjectId();
try {
// we have already commited the cherry-picked commit.
// what we need is to have changes introduced by this
@@ -755,7 +762,7 @@
} finally {
// set ORIG_HEAD back to where we started because soft
// reset moved it
- repo.writeOrigHead(orig_headId);
+ repo.writeOrigHead(orig_head);
}
}
@@ -980,6 +987,9 @@
try {
raw = IO.readFully(authorScriptFile);
} catch (FileNotFoundException notFound) {
+ if (authorScriptFile.exists()) {
+ throw notFound;
+ }
return null;
}
return parseAuthor(raw);
@@ -1069,11 +1079,12 @@
Ref head = getHead();
- String headName = getHeadName(head);
ObjectId headId = head.getObjectId();
- if (headId == null)
+ if (headId == null) {
throw new RefNotFoundException(MessageFormat.format(
JGitText.get().refNotResolved, Constants.HEAD));
+ }
+ String headName = getHeadName(head);
RevCommit headCommit = walk.lookupCommit(headId);
RevCommit upstream = walk.lookupCommit(upstreamCommit.getId());
@@ -1184,10 +1195,14 @@
private static String getHeadName(Ref head) {
String headName;
- if (head.isSymbolic())
+ if (head.isSymbolic()) {
headName = head.getTarget().getName();
- else
- headName = head.getObjectId().getName();
+ } else {
+ ObjectId headId = head.getObjectId();
+ // the callers are checking this already
+ assert headId != null;
+ headName = headId.getName();
+ }
return headName;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java
new file mode 100644
index 0000000..6795669
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteAddCommand.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.transport.RefSpec;
+import org.eclipse.jgit.transport.RemoteConfig;
+import org.eclipse.jgit.transport.URIish;
+
+/**
+ * Used to add a new remote.
+ *
+ * This class has setters for all supported options and arguments of this
+ * command and a {@link #call()} method to finally execute the command.
+ *
+ * @see <a href=
+ * "http://www.kernel.org/pub/software/scm/git/docs/git-remote.html" > Git
+ * documentation about Remote</a>
+ *
+ * @since 4.2
+ */
+public class RemoteAddCommand extends GitCommand<RemoteConfig> {
+
+ private String name;
+
+ private URIish uri;
+
+ /**
+ * @param repo
+ */
+ protected RemoteAddCommand(Repository repo) {
+ super(repo);
+ }
+
+ /**
+ * The name of the remote to add.
+ *
+ * @param name
+ * a remote name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * The URL of the repository for the new remote.
+ *
+ * @param uri
+ * an URL for the remote
+ */
+ public void setUri(URIish uri) {
+ this.uri = uri;
+ }
+
+ /**
+ * Executes the {@code remote add} command with all the options and
+ * parameters collected by the setter methods of this class.
+ *
+ * @return the {@link RemoteConfig} object of the added remote
+ */
+ @Override
+ public RemoteConfig call() throws GitAPIException {
+ checkCallable();
+
+ try {
+ StoredConfig config = repo.getConfig();
+ RemoteConfig remote = new RemoteConfig(config, name);
+
+ RefSpec refSpec = new RefSpec();
+ refSpec = refSpec.setForceUpdate(true);
+ refSpec = refSpec.setSourceDestination(Constants.R_HEADS + "*", //$NON-NLS-1$
+ Constants.R_REMOTES + name + "/*"); //$NON-NLS-1$
+ remote.addFetchRefSpec(refSpec);
+
+ remote.addURI(uri);
+
+ remote.update(config);
+ config.save();
+ return remote;
+ } catch (IOException | URISyntaxException e) {
+ throw new JGitInternalException(e.getMessage(), e);
+ }
+
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java
similarity index 60%
copy from org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
copy to org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java
index c7e41bc..f778eaa 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteListCommand.java
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006-2007, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -41,45 +40,52 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+package org.eclipse.jgit.api;
-package org.eclipse.jgit.lib;
+import java.net.URISyntaxException;
+import java.util.List;
+
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.RemoteConfig;
/**
- * A tree entry representing a symbolic link.
+ * Used to obtain the list of remotes.
*
- * Note. Java cannot really handle these as file system objects.
+ * This class has setters for all supported options and arguments of this
+ * command and a {@link #call()} method to finally execute the command.
*
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
+ * @see <a href=
+ * "http://www.kernel.org/pub/software/scm/git/docs/git-remote.html" > Git
+ * documentation about Remote</a>
+ *
+ * @since 4.2
*/
-@Deprecated
-public class SymlinkTreeEntry extends TreeEntry {
+public class RemoteListCommand extends GitCommand<List<RemoteConfig>> {
/**
- * Construct a {@link SymlinkTreeEntry} with the specified name and SHA-1 in
- * the specified parent
- *
- * @param parent
- * @param id
- * @param nameUTF8
+ * @param repo
*/
- public SymlinkTreeEntry(final Tree parent, final ObjectId id,
- final byte[] nameUTF8) {
- super(parent, id, nameUTF8);
+ protected RemoteListCommand(Repository repo) {
+ super(repo);
}
- public FileMode getMode() {
- return FileMode.SYMLINK;
+ /**
+ * Executes the {@code remote} command with all the options and parameters
+ * collected by the setter methods of this class.
+ *
+ * @return a list of {@link RemoteConfig} objects.
+ */
+ @Override
+ public List<RemoteConfig> call() throws GitAPIException {
+ checkCallable();
+
+ try {
+ return RemoteConfig.getAllRemoteConfigs(repo.getConfig());
+ } catch (URISyntaxException e) {
+ throw new JGitInternalException(e.getMessage(), e);
+ }
}
- public String toString() {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(getId()));
- r.append(" S "); //$NON-NLS-1$
- r.append(getFullName());
- return r.toString();
- }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
new file mode 100644
index 0000000..5782bf6
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteRemoveCommand.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.transport.RemoteConfig;
+
+/**
+ * Used to remove an existing remote.
+ *
+ * This class has setters for all supported options and arguments of this
+ * command and a {@link #call()} method to finally execute the command.
+ *
+ * @see <a href=
+ * "http://www.kernel.org/pub/software/scm/git/docs/git-remote.html" > Git
+ * documentation about Remote</a>
+ *
+ * @since 4.2
+ */
+public class RemoteRemoveCommand extends GitCommand<RemoteConfig> {
+
+ private String name;
+
+ /**
+ * @param repo
+ */
+ protected RemoteRemoveCommand(Repository repo) {
+ super(repo);
+ }
+
+ /**
+ * The name of the remote to remove.
+ *
+ * @param name
+ * a remote name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Executes the {@code remote} command with all the options and parameters
+ * collected by the setter methods of this class.
+ *
+ * @return the {@link RemoteConfig} object of the removed remote
+ */
+ @Override
+ public RemoteConfig call() throws GitAPIException {
+ checkCallable();
+
+ try {
+ StoredConfig config = repo.getConfig();
+ RemoteConfig remote = new RemoteConfig(config, name);
+ config.unsetSection(ConfigConstants.CONFIG_KEY_REMOTE, name);
+ config.save();
+ return remote;
+ } catch (IOException | URISyntaxException e) {
+ throw new JGitInternalException(e.getMessage(), e);
+ }
+
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
new file mode 100644
index 0000000..6bd2ac7
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoteSetUrlCommand.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2015, Kaloyan Raev <kaloyan.r@zend.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.transport.RemoteConfig;
+import org.eclipse.jgit.transport.URIish;
+
+/**
+ * Used to to change the URL of a remote.
+ *
+ * This class has setters for all supported options and arguments of this
+ * command and a {@link #call()} method to finally execute the command.
+ *
+ * @see <a href=
+ * "http://www.kernel.org/pub/software/scm/git/docs/git-remote.html" > Git
+ * documentation about Remote</a>
+ *
+ * @since 4.2
+ */
+public class RemoteSetUrlCommand extends GitCommand<RemoteConfig> {
+
+ private String name;
+
+ private URIish uri;
+
+ private boolean push;
+
+ /**
+ * @param repo
+ */
+ protected RemoteSetUrlCommand(Repository repo) {
+ super(repo);
+ }
+
+ /**
+ * The name of the remote to change the URL for.
+ *
+ * @param name
+ * a remote name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * The new URL for the remote.
+ *
+ * @param uri
+ * an URL for the remote
+ */
+ public void setUri(URIish uri) {
+ this.uri = uri;
+ }
+
+ /**
+ * Whether to change the push URL of the remote instead of the fetch URL.
+ *
+ * @param push
+ * <code>true</code> to set the push url, <code>false</code> to
+ * set the fetch url
+ */
+ public void setPush(boolean push) {
+ this.push = push;
+ }
+
+ /**
+ * Executes the {@code remote} command with all the options and parameters
+ * collected by the setter methods of this class.
+ *
+ * @return the {@link RemoteConfig} object of the modified remote
+ */
+ @Override
+ public RemoteConfig call() throws GitAPIException {
+ checkCallable();
+
+ try {
+ StoredConfig config = repo.getConfig();
+ RemoteConfig remote = new RemoteConfig(config, name);
+ if (push) {
+ List<URIish> uris = remote.getPushURIs();
+ if (uris.size() > 1) {
+ throw new JGitInternalException(
+ "remote.newtest.pushurl has multiple values"); //$NON-NLS-1$
+ } else if (uris.size() == 1) {
+ remote.removePushURI(uris.get(0));
+ }
+ remote.addPushURI(uri);
+ } else {
+ List<URIish> uris = remote.getURIs();
+ if (uris.size() > 1) {
+ throw new JGitInternalException(
+ "remote.newtest.url has multiple values"); //$NON-NLS-1$
+ } else if (uris.size() == 1) {
+ remote.removeURI(uris.get(0));
+ }
+ remote.addURI(uri);
+ }
+
+ remote.update(config);
+ config.save();
+ return remote;
+ } catch (IOException | URISyntaxException e) {
+ throw new JGitInternalException(e.getMessage(), e);
+ }
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
index 607253b..0731dd4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
@@ -51,6 +51,7 @@
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.api.errors.NoHeadException;
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.internal.JGitText;
@@ -121,6 +122,10 @@
fullOldName = ref.getName();
} else {
fullOldName = repo.getFullBranch();
+ if (fullOldName == null) {
+ throw new NoHeadException(
+ JGitText.get().invalidRepositoryStateNoHead);
+ }
if (ObjectId.isId(fullOldName))
throw new DetachedHeadException();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
index 8f4bc4f..4c91e6c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
@@ -190,10 +190,8 @@
ObjectId origHead = ru.getOldObjectId();
if (origHead != null)
repo.writeOrigHead(origHead);
- result = ru.getRef();
- } else {
- result = repo.getRef(Constants.HEAD);
}
+ result = repo.exactRef(Constants.HEAD);
if (mode == null)
mode = ResetType.MIXED;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
index 6de25a0..8ef5508 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
@@ -357,7 +357,7 @@
private void checkoutPath(DirCacheEntry entry, ObjectReader reader) {
try {
- DirCacheCheckout.checkoutEntry(repo, entry, reader);
+ DirCacheCheckout.checkoutEntry(repo, entry, reader, true);
} catch (IOException e) {
throw new JGitInternalException(MessageFormat.format(
JGitText.get().checkoutConflictWithFile,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
index 7923fd4..f6903be 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
@@ -46,6 +46,7 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.StandardCopyOption;
import java.text.MessageFormat;
import java.util.List;
@@ -220,12 +221,14 @@
entry.getWho(), entry.getComment());
entryId = entry.getNewId();
}
- if (!stashLockFile.renameTo(stashFile)) {
- FileUtils.delete(stashFile);
- if (!stashLockFile.renameTo(stashFile))
+ try {
+ FileUtils.rename(stashLockFile, stashFile,
+ StandardCopyOption.ATOMIC_MOVE);
+ } catch (IOException e) {
throw new JGitInternalException(MessageFormat.format(
JGitText.get().renameFileFailed,
- stashLockFile.getPath(), stashFile.getPath()));
+ stashLockFile.getPath(), stashFile.getPath()),
+ e);
}
} catch (IOException e) {
throw new JGitInternalException(JGitText.get().stashDropFailed, e);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
index e288d77..342d7f4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011, GitHub Inc.
+ * Copyright (C) 2016, Laurent Delaigue <laurent.delaigue@obeo.fr>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -178,11 +179,13 @@
if (ConfigConstants.CONFIG_KEY_MERGE.equals(update)) {
MergeCommand merge = new MergeCommand(submoduleRepo);
merge.include(commit);
+ merge.setProgressMonitor(monitor);
merge.setStrategy(strategy);
merge.call();
} else if (ConfigConstants.CONFIG_KEY_REBASE.equals(update)) {
RebaseCommand rebase = new RebaseCommand(submoduleRepo);
rebase.setUpstream(commit);
+ rebase.setProgressMonitor(monitor);
rebase.setStrategy(strategy);
rebase.call();
} else {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java
index 1aeb610..3d2e46b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/TransportCommand.java
@@ -79,6 +79,7 @@
*/
protected TransportCommand(final Repository repo) {
super(repo);
+ setCredentialsProvider(CredentialsProvider.getDefault());
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/EmtpyCommitException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/EmtpyCommitException.java
new file mode 100644
index 0000000..b3cc1bf
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/EmtpyCommitException.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v1.0 which accompanies this
+ * distribution, is reproduced below, and is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api.errors;
+
+/**
+ * Exception thrown when a newly created commit does not contain any changes
+ *
+ * @since 4.2
+ */
+public class EmtpyCommitException extends GitAPIException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public EmtpyCommitException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * @param message
+ */
+ public EmtpyCommitException(String message) {
+ super(message);
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java
new file mode 100644
index 0000000..fbc30ef
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/FilterFailedException.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com> and
+ * other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v1.0 which accompanies this
+ * distribution, is reproduced below, and is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.api.errors;
+
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.internal.JGitText;
+
+/**
+ * Exception thrown when the execution of a filter command failed
+ *
+ * @since 4.2
+ */
+public class FilterFailedException extends GitAPIException {
+ private static final long serialVersionUID = 1L;
+
+ private String filterCommand;
+
+ private String path;
+
+ private byte[] stdout;
+
+ private String stderr;
+
+ private int rc;
+
+ /**
+ * Thrown if during execution of filter command an exception occurred
+ *
+ * @param cause
+ * the exception
+ * @param filterCommand
+ * the command which failed
+ * @param path
+ * the path processed by the filter
+ */
+ public FilterFailedException(Exception cause, String filterCommand,
+ String path) {
+ super(MessageFormat.format(JGitText.get().filterExecutionFailed,
+ filterCommand, path), cause);
+ this.filterCommand = filterCommand;
+ this.path = path;
+ }
+
+ /**
+ * Thrown if a filter command returns a non-zero return code
+ *
+ * @param rc
+ * the return code
+ * @param filterCommand
+ * the command which failed
+ * @param path
+ * the path processed by the filter
+ * @param stdout
+ * the output the filter generated so far. This should be limited
+ * to reasonable size.
+ * @param stderr
+ * the stderr output of the filter
+ */
+ @SuppressWarnings("boxing")
+ public FilterFailedException(int rc, String filterCommand, String path,
+ byte[] stdout, String stderr) {
+ super(MessageFormat.format(JGitText.get().filterExecutionFailedRc,
+ filterCommand, path, rc, stderr));
+ this.rc = rc;
+ this.filterCommand = filterCommand;
+ this.path = path;
+ this.stdout = stdout;
+ this.stderr = stderr;
+ }
+
+ /**
+ * @return the filterCommand
+ */
+ public String getFilterCommand() {
+ return filterCommand;
+ }
+
+ /**
+ * @return the path of the file processed by the filter command
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * @return the output generated by the filter command. Might be truncated to
+ * limit memory consumption.
+ */
+ public byte[] getOutput() {
+ return stdout;
+ }
+
+ /**
+ * @return the error output returned by the filter command
+ */
+ public String getError() {
+ return stderr;
+ }
+
+ /**
+ * @return the return code returned by the filter command
+ */
+ public int getReturnCode() {
+ return rc;
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java
index d3ce685..905ad76 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attribute.java
@@ -50,8 +50,10 @@
* <li>Set - represented by {@link State#SET}</li>
* <li>Unset - represented by {@link State#UNSET}</li>
* <li>Set to a value - represented by {@link State#CUSTOM}</li>
- * <li>Unspecified - <code>null</code> is used instead of an instance of this
- * class</li>
+ * <li>Unspecified - used to revert an attribute . This is crucial in order to
+ * mark an attribute as unspecified in the attributes map and thus preventing
+ * following (with lower priority) nodes from setting the attribute to a value
+ * at all</li>
* </ul>
* </p>
*
@@ -61,6 +63,7 @@
/**
* The attribute value state
+ * see also https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
*/
public static enum State {
/** the attribute is set */
@@ -69,6 +72,13 @@
/** the attribute is unset */
UNSET,
+ /**
+ * the attribute appears as if it would not be defined at all
+ *
+ * @since 4.2
+ */
+ UNSPECIFIED,
+
/** the attribute is set to a custom value */
CUSTOM
}
@@ -176,6 +186,8 @@
return key;
case UNSET:
return "-" + key; //$NON-NLS-1$
+ case UNSPECIFIED:
+ return "!" + key; //$NON-NLS-1$
case CUSTOM:
default:
return key + "=" + value; //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java
new file mode 100644
index 0000000..0810e31
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/Attributes.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.attributes;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.eclipse.jgit.attributes.Attribute.State;
+
+/**
+ * Represents a set of attributes for a path
+ * <p>
+ *
+ * @since 4.2
+ */
+public final class Attributes {
+ private final Map<String, Attribute> map = new LinkedHashMap<>();
+
+ /**
+ * Creates a new instance
+ *
+ * @param attributes
+ */
+ public Attributes(Attribute... attributes) {
+ if (attributes != null) {
+ for (Attribute a : attributes) {
+ put(a);
+ }
+ }
+ }
+
+ /**
+ * @return true if the set does not contain any attributes
+ */
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ /**
+ * @param key
+ * @return the attribute or null
+ */
+ public Attribute get(String key) {
+ return map.get(key);
+ }
+
+ /**
+ * @return all attributes
+ */
+ public Collection<Attribute> getAll() {
+ return new ArrayList<>(map.values());
+ }
+
+ /**
+ * @param a
+ */
+ public void put(Attribute a) {
+ map.put(a.getKey(), a);
+ }
+
+ /**
+ * @param key
+ */
+ public void remove(String key) {
+ map.remove(key);
+ }
+
+ /**
+ * @param key
+ * @return true if the {@link Attributes} contains this key
+ */
+ public boolean containsKey(String key) {
+ return map.containsKey(key);
+ }
+
+ /**
+ * Returns the state.
+ *
+ * @param key
+ *
+ * @return the state (never returns <code>null</code>)
+ */
+ public Attribute.State getState(String key) {
+ Attribute a = map.get(key);
+ return a != null ? a.getState() : Attribute.State.UNSPECIFIED;
+ }
+
+ /**
+ * @param key
+ * @return true if the key is {@link State#SET}, false in all other cases
+ */
+ public boolean isSet(String key) {
+ return (getState(key) == State.SET);
+ }
+
+ /**
+ * @param key
+ * @return true if the key is {@link State#UNSET}, false in all other cases
+ */
+ public boolean isUnset(String key) {
+ return (getState(key) == State.UNSET);
+ }
+
+ /**
+ * @param key
+ * @return true if the key is {@link State#UNSPECIFIED}, false in all other
+ * cases
+ */
+ public boolean isUnspecified(String key) {
+ return (getState(key) == State.UNSPECIFIED);
+ }
+
+ /**
+ * @param key
+ * @return true if the key is {@link State#CUSTOM}, false in all other cases
+ * see {@link #getValue(String)} for the value of the key
+ */
+ public boolean isCustom(String key) {
+ return (getState(key) == State.CUSTOM);
+ }
+
+ /**
+ * @param key
+ * @return the attribute value (may be <code>null</code>)
+ */
+ public String getValue(String key) {
+ Attribute a = map.get(key);
+ return a != null ? a.getValue() : null;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+ buf.append(getClass().getSimpleName());
+ buf.append("["); //$NON-NLS-1$
+ buf.append(" "); //$NON-NLS-1$
+ for (Attribute a : map.values()) {
+ buf.append(a.toString());
+ buf.append(" "); //$NON-NLS-1$
+ }
+ buf.append("]"); //$NON-NLS-1$
+ return buf.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return map.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof Attributes))
+ return false;
+ Attributes other = (Attributes) obj;
+ return this.map.equals(other.map);
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java
index 70f56ff..5c0aba2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNode.java
@@ -50,7 +50,6 @@
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
-import java.util.Map;
import org.eclipse.jgit.lib.Constants;
@@ -134,11 +133,12 @@
* true if the target item is a directory.
* @param attributes
* Map that will hold the attributes matching this entry path. If
- * it is not empty, this method will NOT override any
- * existing entry.
+ * it is not empty, this method will NOT override any existing
+ * entry.
+ * @since 4.2
*/
- public void getAttributes(String entryPath, boolean isDirectory,
- Map<String, Attribute> attributes) {
+ public void getAttributes(String entryPath,
+ boolean isDirectory, Attributes attributes) {
// Parse rules in the reverse order that they were read since the last
// entry should be used
ListIterator<AttributesRule> ruleIterator = rules.listIterator(rules
@@ -153,7 +153,7 @@
while (attributeIte.hasPrevious()) {
Attribute attr = attributeIte.previous();
if (!attributes.containsKey(attr.getKey()))
- attributes.put(attr.getKey(), attr);
+ attributes.put(attr);
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java
similarity index 60%
copy from org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
copy to org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java
index c7e41bc..6f2ebad 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesNodeProvider.java
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006-2007, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2014, Arthur Daussy <arthur.daussy@obeo.fr>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -41,45 +40,42 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+package org.eclipse.jgit.attributes;
-package org.eclipse.jgit.lib;
+import java.io.IOException;
+
+import org.eclipse.jgit.lib.CoreConfig;
/**
- * A tree entry representing a symbolic link.
+ * An interface used to retrieve the global and info {@link AttributesNode}s.
*
- * Note. Java cannot really handle these as file system objects.
+ * @since 4.2
*
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
*/
-@Deprecated
-public class SymlinkTreeEntry extends TreeEntry {
+public interface AttributesNodeProvider {
/**
- * Construct a {@link SymlinkTreeEntry} with the specified name and SHA-1 in
- * the specified parent
+ * Retrieve the {@link AttributesNode} that holds the information located
+ * in $GIT_DIR/info/attributes file.
*
- * @param parent
- * @param id
- * @param nameUTF8
+ * @return the {@link AttributesNode} that holds the information located in
+ * $GIT_DIR/info/attributes file.
+ * @throws IOException
+ * if an error is raised while parsing the attributes file
*/
- public SymlinkTreeEntry(final Tree parent, final ObjectId id,
- final byte[] nameUTF8) {
- super(parent, id, nameUTF8);
- }
+ public AttributesNode getInfoAttributesNode() throws IOException;
- public FileMode getMode() {
- return FileMode.SYMLINK;
- }
+ /**
+ * Retrieve the {@link AttributesNode} that holds the information located
+ * in the global gitattributes file.
+ *
+ * @return the {@link AttributesNode} that holds the information located in
+ * the global gitattributes file.
+ * @throws IOException
+ * IOException if an error is raised while parsing the
+ * attributes file
+ * @see CoreConfig#getAttributesFile()
+ */
+ public AttributesNode getGlobalAttributesNode() throws IOException;
- public String toString() {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(getId()));
- r.append(" S "); //$NON-NLS-1$
- r.append(getFullName());
- return r.toString();
- }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java
similarity index 60%
copy from org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
copy to org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java
index c7e41bc..1037f69 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesProvider.java
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006-2007, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -41,45 +40,16 @@
* 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;
+package org.eclipse.jgit.attributes;
/**
- * A tree entry representing a symbolic link.
+ * Interface for classes which provide git attributes
*
- * Note. Java cannot really handle these as file system objects.
- *
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
+ * @since 4.2
*/
-@Deprecated
-public class SymlinkTreeEntry extends TreeEntry {
-
+public interface AttributesProvider {
/**
- * Construct a {@link SymlinkTreeEntry} with the specified name and SHA-1 in
- * the specified parent
- *
- * @param parent
- * @param id
- * @param nameUTF8
+ * @return the currently active attributes
*/
- public SymlinkTreeEntry(final Tree parent, final ObjectId id,
- final byte[] nameUTF8) {
- super(parent, id, nameUTF8);
- }
-
- public FileMode getMode() {
- return FileMode.SYMLINK;
- }
-
- public String toString() {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(getId()));
- r.append(" S "); //$NON-NLS-1$
- r.append(getFullName());
- return r.toString();
- }
+ public Attributes getAttributes();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java
index bcac14b..35d18c4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesRule.java
@@ -84,6 +84,13 @@
continue;
}
+ if (attribute.startsWith("!")) {//$NON-NLS-1$
+ if (attribute.length() > 1)
+ result.add(new Attribute(attribute.substring(1),
+ State.UNSPECIFIED));
+ continue;
+ }
+
final int equalsIndex = attribute.indexOf("="); //$NON-NLS-1$
if (equalsIndex == -1)
result.add(new Attribute(attribute, State.SET));
@@ -200,4 +207,16 @@
boolean match = matcher.matches(relativeTarget, isDirectory);
return match;
}
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(pattern);
+ for (Attribute a : attributes) {
+ sb.append(" "); //$NON-NLS-1$
+ sb.append(a);
+ }
+ return sb.toString();
+
+ }
}
\ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
index 3c780e7..444ab1c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
@@ -132,7 +132,11 @@
@Override
public long size(String path, ObjectId id) throws IOException {
- return reader.getObjectSize(id, Constants.OBJ_BLOB);
+ try {
+ return reader.getObjectSize(id, Constants.OBJ_BLOB);
+ } catch (MissingObjectException ignore) {
+ return 0;
+ }
}
@Override
@@ -148,7 +152,7 @@
private String current;
- private WorkingTreeIterator ptr;
+ WorkingTreeIterator ptr;
WorkingTreeSource(WorkingTreeIterator iterator) {
this.tw = new TreeWalk((ObjectReader) null);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiff.java
index e57faaf..2f5c9ea 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiff.java
@@ -94,7 +94,7 @@
*/
public class HistogramDiff extends LowLevelDiffAlgorithm {
/** Algorithm to use when there are too many element occurrences. */
- private DiffAlgorithm fallback = MyersDiff.INSTANCE;
+ DiffAlgorithm fallback = MyersDiff.INSTANCE;
/**
* Maximum number of positions to consider for a given element hash.
@@ -103,7 +103,7 @@
* size is capped to ensure search is linear time at O(len_A + len_B) rather
* than quadratic at O(len_A * len_B).
*/
- private int maxChainLength = 64;
+ int maxChainLength = 64;
/**
* Set the algorithm used when there are too many element occurrences.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/BaseDirCacheEditor.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/BaseDirCacheEditor.java
index 70f80ae..0fbc1f8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/BaseDirCacheEditor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/BaseDirCacheEditor.java
@@ -44,8 +44,13 @@
package org.eclipse.jgit.dircache;
+import static org.eclipse.jgit.lib.FileMode.TYPE_TREE;
+import static org.eclipse.jgit.util.Paths.compareSameName;
+
import java.io.IOException;
+import org.eclipse.jgit.errors.DirCacheNameConflictException;
+
/**
* Generic update/editing support for {@link DirCache}.
* <p>
@@ -168,6 +173,7 @@
* {@link #finish()}, and only after {@link #entries} is sorted.
*/
protected void replace() {
+ checkNameConflicts();
if (entryCnt < entries.length / 2) {
final DirCacheEntry[] n = new DirCacheEntry[entryCnt];
System.arraycopy(entries, 0, n, 0, entryCnt);
@@ -176,6 +182,76 @@
cache.replace(entries, entryCnt);
}
+ private void checkNameConflicts() {
+ int end = entryCnt - 1;
+ for (int eIdx = 0; eIdx < end; eIdx++) {
+ DirCacheEntry e = entries[eIdx];
+ if (e.getStage() != 0) {
+ continue;
+ }
+
+ byte[] ePath = e.path;
+ int prefixLen = lastSlash(ePath) + 1;
+
+ for (int nIdx = eIdx + 1; nIdx < entryCnt; nIdx++) {
+ DirCacheEntry n = entries[nIdx];
+ if (n.getStage() != 0) {
+ continue;
+ }
+
+ byte[] nPath = n.path;
+ if (!startsWith(ePath, nPath, prefixLen)) {
+ // Different prefix; this entry is in another directory.
+ break;
+ }
+
+ int s = nextSlash(nPath, prefixLen);
+ int m = s < nPath.length ? TYPE_TREE : n.getRawMode();
+ int cmp = compareSameName(
+ ePath, prefixLen, ePath.length,
+ nPath, prefixLen, s, m);
+ if (cmp < 0) {
+ break;
+ } else if (cmp == 0) {
+ throw new DirCacheNameConflictException(
+ e.getPathString(),
+ n.getPathString());
+ }
+ }
+ }
+ }
+
+ private static int lastSlash(byte[] path) {
+ for (int i = path.length - 1; i >= 0; i--) {
+ if (path[i] == '/') {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private static int nextSlash(byte[] b, int p) {
+ final int n = b.length;
+ for (; p < n; p++) {
+ if (b[p] == '/') {
+ return p;
+ }
+ }
+ return n;
+ }
+
+ private static boolean startsWith(byte[] a, byte[] b, int n) {
+ if (b.length < n) {
+ return false;
+ }
+ for (n--; n >= 0; n--) {
+ if (a[n] != b[n]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Finish, write, commit this change, and release the index lock.
* <p>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
index 6d9a32d..b9101c0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
@@ -63,6 +63,7 @@
import java.util.List;
import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.IndexReadException;
import org.eclipse.jgit.errors.LockFailedException;
import org.eclipse.jgit.errors.UnmergedPathException;
import org.eclipse.jgit.events.IndexChangedEvent;
@@ -70,12 +71,15 @@
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.FileSnapshot;
import org.eclipse.jgit.internal.storage.file.LockFile;
+import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.IO;
@@ -145,6 +149,28 @@
}
/**
+ * Create a new in memory index read from the contents of a tree.
+ *
+ * @param reader
+ * reader to access the tree objects from a repository.
+ * @param treeId
+ * tree to read. Must identify a tree, not a tree-ish.
+ * @return a new cache which has no backing store file, but contains the
+ * contents of {@code treeId}.
+ * @throws IOException
+ * one or more trees not available from the ObjectReader.
+ * @since 4.2
+ */
+ public static DirCache read(ObjectReader reader, AnyObjectId treeId)
+ throws IOException {
+ DirCache d = newInCore();
+ DirCacheBuilder b = d.builder();
+ b.addTree(null, DirCacheEntry.STAGE_0, reader, treeId);
+ b.finish();
+ return d;
+ }
+
+ /**
* Create a new in-core index representation and read an index from disk.
* <p>
* The new index will be read before it is returned to the caller. Read
@@ -318,9 +344,6 @@
/** Our active lock (if we hold it); null if we don't have it locked. */
private LockFile myLock;
- /** file system abstraction **/
- private final FS fs;
-
/** Keep track of whether the index has changed or not */
private FileSnapshot snapshot;
@@ -350,7 +373,6 @@
*/
public DirCache(final File indexLocation, final FS fs) {
liveFile = indexLocation;
- this.fs = fs;
clear();
}
@@ -417,6 +439,12 @@
}
}
} catch (FileNotFoundException fnfe) {
+ if (liveFile.exists()) {
+ // Panic: the index file exists but we can't read it
+ throw new IndexReadException(
+ MessageFormat.format(JGitText.get().cannotReadIndex,
+ liveFile.getAbsolutePath(), fnfe));
+ }
// Someone must have deleted it between our exists test
// and actually opening the path. That's fine, its empty.
//
@@ -579,7 +607,7 @@
public boolean lock() throws IOException {
if (liveFile == null)
throw new IOException(JGitText.get().dirCacheDoesNotHaveABackingFile);
- final LockFile tmp = new LockFile(liveFile, fs);
+ final LockFile tmp = new LockFile(liveFile);
if (tmp.lock()) {
tmp.setNeedStatInformation(true);
myLock = tmp;
@@ -768,8 +796,11 @@
* information. If < 0 the entry does not exist in the index.
* @since 3.4
*/
- public int findEntry(final byte[] p, final int pLen) {
- int low = 0;
+ public int findEntry(byte[] p, int pLen) {
+ return findEntry(0, p, pLen);
+ }
+
+ int findEntry(int low, byte[] p, int pLen) {
int high = entryCnt;
while (low < high) {
int mid = (low + high) >>> 1;
@@ -869,8 +900,8 @@
*/
public DirCacheEntry[] getEntriesWithin(String path) {
if (path.length() == 0) {
- final DirCacheEntry[] r = new DirCacheEntry[sortedEntries.length];
- System.arraycopy(sortedEntries, 0, r, 0, sortedEntries.length);
+ DirCacheEntry[] r = new DirCacheEntry[entryCnt];
+ System.arraycopy(sortedEntries, 0, r, 0, entryCnt);
return r;
}
if (!path.endsWith("/")) //$NON-NLS-1$
@@ -963,6 +994,7 @@
private void updateSmudgedEntries() throws IOException {
List<String> paths = new ArrayList<String>(128);
try (TreeWalk walk = new TreeWalk(repository)) {
+ walk.setOperationType(OperationType.CHECKIN_OP);
for (int i = 0; i < entryCnt; i++)
if (sortedEntries[i].isSmudged())
paths.add(sortedEntries[i].getPathString());
@@ -974,6 +1006,7 @@
FileTreeIterator fIter = new FileTreeIterator(repository);
walk.addTree(iIter);
walk.addTree(fIter);
+ fIter.setDirCacheIterator(walk, 0);
walk.setRecursive(true);
while (walk.next()) {
iIter = walk.getTree(0, DirCacheIterator.class);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuildIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuildIterator.java
index da55306..c10e416 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuildIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuildIterator.java
@@ -130,4 +130,9 @@
if (cur < cnt)
builder.keep(cur, cnt - cur);
}
+
+ @Override
+ protected boolean needsStopWalk() {
+ return ptr < cache.getEntryCount();
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java
index 6c7a70c..cfebe2d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheBuilder.java
@@ -44,6 +44,9 @@
package org.eclipse.jgit.dircache;
+import static org.eclipse.jgit.lib.FileMode.TYPE_MASK;
+import static org.eclipse.jgit.lib.FileMode.TYPE_TREE;
+
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Arrays;
@@ -51,9 +54,7 @@
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectReader;
-import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
-import org.eclipse.jgit.treewalk.TreeWalk;
/**
* Updates a {@link DirCache} by adding individual {@link DirCacheEntry}s.
@@ -102,8 +103,9 @@
*/
public void add(final DirCacheEntry newEntry) {
if (newEntry.getRawMode() == 0)
- throw new IllegalArgumentException(MessageFormat.format(JGitText.get().fileModeNotSetForPath
- , newEntry.getPathString()));
+ throw new IllegalArgumentException(MessageFormat.format(
+ JGitText.get().fileModeNotSetForPath,
+ newEntry.getPathString()));
beforeAdd(newEntry);
fastAdd(newEntry);
}
@@ -162,27 +164,56 @@
* @throws IOException
* a tree cannot be read to iterate through its entries.
*/
- public void addTree(final byte[] pathPrefix, final int stage,
- final ObjectReader reader, final AnyObjectId tree) throws IOException {
- final TreeWalk tw = new TreeWalk(reader);
- tw.addTree(new CanonicalTreeParser(pathPrefix, reader, tree
- .toObjectId()));
- tw.setRecursive(true);
- if (tw.next()) {
- final DirCacheEntry newEntry = toEntry(stage, tw);
- beforeAdd(newEntry);
- fastAdd(newEntry);
- while (tw.next())
- fastAdd(toEntry(stage, tw));
+ public void addTree(byte[] pathPrefix, int stage, ObjectReader reader,
+ AnyObjectId tree) throws IOException {
+ CanonicalTreeParser p = createTreeParser(pathPrefix, reader, tree);
+ while (!p.eof()) {
+ if (isTree(p)) {
+ p = enterTree(p, reader);
+ continue;
+ }
+
+ DirCacheEntry first = toEntry(stage, p);
+ beforeAdd(first);
+ fastAdd(first);
+ p = p.next();
+ break;
+ }
+
+ // Rest of tree entries are correctly sorted; use fastAdd().
+ while (!p.eof()) {
+ if (isTree(p)) {
+ p = enterTree(p, reader);
+ } else {
+ fastAdd(toEntry(stage, p));
+ p = p.next();
+ }
}
}
- private DirCacheEntry toEntry(final int stage, final TreeWalk tw) {
- final DirCacheEntry e = new DirCacheEntry(tw.getRawPath(), stage);
- final AbstractTreeIterator i;
+ private static CanonicalTreeParser createTreeParser(byte[] pathPrefix,
+ ObjectReader reader, AnyObjectId tree) throws IOException {
+ return new CanonicalTreeParser(pathPrefix, reader, tree);
+ }
- i = tw.getTree(0, AbstractTreeIterator.class);
- e.setFileMode(tw.getFileMode(0));
+ private static boolean isTree(CanonicalTreeParser p) {
+ return (p.getEntryRawMode() & TYPE_MASK) == TYPE_TREE;
+ }
+
+ private static CanonicalTreeParser enterTree(CanonicalTreeParser p,
+ ObjectReader reader) throws IOException {
+ p = p.createSubtreeIterator(reader);
+ return p.eof() ? p.next() : p;
+ }
+
+ private static DirCacheEntry toEntry(int stage, CanonicalTreeParser i) {
+ byte[] buf = i.getEntryPathBuffer();
+ int len = i.getEntryPathLength();
+ byte[] path = new byte[len];
+ System.arraycopy(buf, 0, path, 0, len);
+
+ DirCacheEntry e = new DirCacheEntry(path, stage);
+ e.setFileMode(i.getEntryRawMode());
e.setObjectIdFromRaw(i.idBuffer(), i.idOffset());
return e;
}
@@ -242,9 +273,9 @@
sorted = true;
}
- private static IllegalStateException bad(final DirCacheEntry a,
- final String msg) {
- return new IllegalStateException(msg + ": " + a.getStage() + " " //$NON-NLS-1$ //$NON-NLS-2$
- + a.getPathString());
+ private static IllegalStateException bad(DirCacheEntry a, String msg) {
+ return new IllegalStateException(String.format(
+ "%s: %d %s", //$NON-NLS-1$
+ msg, Integer.valueOf(a.getStage()), a.getPathString()));
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index 0025254..a1e1d15 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -46,21 +46,25 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.nio.file.StandardCopyOption;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.eclipse.jgit.api.errors.FilterFailedException;
import org.eclipse.jgit.errors.CheckoutConflictException;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.IndexWriteException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
import org.eclipse.jgit.lib.CoreConfig.SymLinks;
import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectChecker;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
@@ -76,6 +80,7 @@
import org.eclipse.jgit.treewalk.WorkingTreeOptions;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FS.ExecutionResult;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.SystemReader;
@@ -85,9 +90,10 @@
* This class handles checking out one or two trees merging with the index.
*/
public class DirCacheCheckout {
+ private static final int MAX_EXCEPTION_TEXT_SIZE = 10 * 1024;
private Repository repo;
- private HashMap<String, ObjectId> updated = new HashMap<String, ObjectId>();
+ private HashMap<String, String> updated = new HashMap<String, String>();
private ArrayList<String> conflicts = new ArrayList<String>();
@@ -112,9 +118,9 @@
private boolean emptyDirCache;
/**
- * @return a list of updated paths and objectIds
+ * @return a list of updated paths and smudgeFilterCommands
*/
- public Map<String, ObjectId> getUpdated() {
+ public Map<String, String> getUpdated() {
return updated;
}
@@ -447,7 +453,8 @@
for (String path : updated.keySet()) {
DirCacheEntry entry = dc.getEntry(path);
if (!FileMode.GITLINK.equals(entry.getRawMode()))
- checkoutEntry(repo, entry, objectReader);
+ checkoutEntry(repo, entry, objectReader, false,
+ updated.get(path));
}
// commit the index builder - a new index is persisted
@@ -996,9 +1003,12 @@
removed.add(path);
}
- private void update(String path, ObjectId mId, FileMode mode) {
+ private void update(String path, ObjectId mId, FileMode mode)
+ throws IOException {
if (!FileMode.TREE.equals(mode)) {
- updated.put(path, mId);
+ updated.put(path,
+ walk.getFilterCommand(Constants.ATTR_FILTER_TYPE_SMUDGE));
+
DirCacheEntry entry = new DirCacheEntry(path, DirCacheEntry.STAGE_0);
entry.setObjectId(mId);
entry.setFileMode(mode);
@@ -1127,6 +1137,13 @@
* final filename.
*
* <p>
+ * <b>Note:</b> if the entry path on local file system exists as a non-empty
+ * directory, and the target entry type is a link or file, the checkout will
+ * fail with {@link IOException} since existing non-empty directory cannot
+ * be renamed to file or link without deleting it recursively.
+ * </p>
+ *
+ * <p>
* TODO: this method works directly on File IO, we may need another
* abstraction (like WorkingTreeIterator). This way we could tell e.g.
* Eclipse that Files in the workspace got changed
@@ -1143,6 +1160,82 @@
*/
public static void checkoutEntry(Repository repo, DirCacheEntry entry,
ObjectReader or) throws IOException {
+ checkoutEntry(repo, entry, or, false, null);
+ }
+
+ /**
+ * Updates the file in the working tree with content and mode from an entry
+ * in the index. The new content is first written to a new temporary file in
+ * the same directory as the real file. Then that new file is renamed to the
+ * final filename.
+ *
+ * <p>
+ * <b>Note:</b> if the entry path on local file system exists as a file, it
+ * will be deleted and if it exists as a directory, it will be deleted
+ * recursively, independently if has any content.
+ * </p>
+ *
+ * <p>
+ * TODO: this method works directly on File IO, we may need another
+ * abstraction (like WorkingTreeIterator). This way we could tell e.g.
+ * Eclipse that Files in the workspace got changed
+ * </p>
+ *
+ * @param repo
+ * repository managing the destination work tree.
+ * @param entry
+ * the entry containing new mode and content
+ * @param or
+ * object reader to use for checkout
+ * @param deleteRecursive
+ * true to recursively delete final path if it exists on the file
+ * system
+ *
+ * @throws IOException
+ * @since 4.2
+ */
+ public static void checkoutEntry(Repository repo, DirCacheEntry entry,
+ ObjectReader or, boolean deleteRecursive) throws IOException {
+ checkoutEntry(repo, entry, or, deleteRecursive, null);
+ }
+
+ /**
+ * Updates the file in the working tree with content and mode from an entry
+ * in the index. The new content is first written to a new temporary file in
+ * the same directory as the real file. Then that new file is renamed to the
+ * final filename.
+ *
+ * <p>
+ * <b>Note:</b> if the entry path on local file system exists as a file, it
+ * will be deleted and if it exists as a directory, it will be deleted
+ * recursively, independently if has any content.
+ * </p>
+ *
+ * <p>
+ * TODO: this method works directly on File IO, we may need another
+ * abstraction (like WorkingTreeIterator). This way we could tell e.g.
+ * Eclipse that Files in the workspace got changed
+ * </p>
+ *
+ * @param repo
+ * repository managing the destination work tree.
+ * @param entry
+ * the entry containing new mode and content
+ * @param or
+ * object reader to use for checkout
+ * @param deleteRecursive
+ * true to recursively delete final path if it exists on the file
+ * system
+ * @param smudgeFilterCommand
+ * the filter command to be run for smudging the entry to be
+ * checked out
+ *
+ * @throws IOException
+ * @since 4.2
+ */
+ public static void checkoutEntry(Repository repo, DirCacheEntry entry,
+ ObjectReader or, boolean deleteRecursive,
+ String smudgeFilterCommand) throws IOException {
ObjectLoader ol = or.open(entry.getObjectId());
File f = new File(repo.getWorkTree(), entry.getPathString());
File parentDir = f.getParentFile();
@@ -1153,6 +1246,9 @@
&& opt.getSymLinks() == SymLinks.TRUE) {
byte[] bytes = ol.getBytes();
String target = RawParseUtils.decode(bytes);
+ if (deleteRecursive && f.isDirectory()) {
+ FileUtils.delete(f, FileUtils.RECURSIVE);
+ }
fs.createSymLink(f, target);
entry.setLength(bytes.length);
entry.setLastModified(fs.lastModified(f));
@@ -1164,14 +1260,52 @@
OutputStream channel = new FileOutputStream(tmpFile);
if (opt.getAutoCRLF() == AutoCRLF.TRUE)
channel = new AutoCRLFOutputStream(channel);
- try {
- ol.copyTo(channel);
- } finally {
- channel.close();
+ if (smudgeFilterCommand != null) {
+ ProcessBuilder filterProcessBuilder = fs
+ .runInShell(smudgeFilterCommand, new String[0]);
+ filterProcessBuilder.directory(repo.getWorkTree());
+ filterProcessBuilder.environment().put(Constants.GIT_DIR_KEY,
+ repo.getDirectory().getAbsolutePath());
+ ExecutionResult result;
+ int rc;
+ try {
+ // TODO: wire correctly with AUTOCRLF
+ result = fs.execute(filterProcessBuilder, ol.openStream());
+ rc = result.getRc();
+ if (rc == 0) {
+ result.getStdout().writeTo(channel,
+ NullProgressMonitor.INSTANCE);
+ }
+ } catch (IOException | InterruptedException e) {
+ throw new IOException(new FilterFailedException(e,
+ smudgeFilterCommand, entry.getPathString()));
+
+ } finally {
+ channel.close();
+ }
+ if (rc != 0) {
+ throw new IOException(new FilterFailedException(rc,
+ smudgeFilterCommand, entry.getPathString(),
+ result.getStdout().toByteArray(MAX_EXCEPTION_TEXT_SIZE),
+ RawParseUtils.decode(result.getStderr()
+ .toByteArray(MAX_EXCEPTION_TEXT_SIZE))));
+ }
+ } else {
+ try {
+ ol.copyTo(channel);
+ } finally {
+ channel.close();
+ }
}
- entry.setLength(opt.getAutoCRLF() == AutoCRLF.TRUE ? //
- tmpFile.length() // AutoCRLF wants on-disk-size
- : (int) ol.getSize());
+ // The entry needs to correspond to the on-disk filesize. If the content
+ // was filtered (either by autocrlf handling or smudge filters) ask the
+ // filesystem again for the length. Otherwise the objectloader knows the
+ // size
+ if (opt.getAutoCRLF() == AutoCRLF.TRUE || smudgeFilterCommand != null) {
+ entry.setLength(tmpFile.length());
+ } else {
+ entry.setLength(ol.getSize());
+ }
if (opt.isFileMode() && fs.supportsExecute()) {
if (FileMode.EXECUTABLE_FILE.equals(entry.getRawMode())) {
@@ -1183,11 +1317,19 @@
}
}
try {
- FileUtils.rename(tmpFile, f);
+ if (deleteRecursive && f.isDirectory()) {
+ FileUtils.delete(f, FileUtils.RECURSIVE);
+ }
+ FileUtils.rename(tmpFile, f, StandardCopyOption.ATOMIC_MOVE);
} catch (IOException e) {
- throw new IOException(MessageFormat.format(
- JGitText.get().renameFileFailed, tmpFile.getPath(),
- f.getPath()));
+ throw new IOException(
+ MessageFormat.format(JGitText.get().renameFileFailed,
+ tmpFile.getPath(), f.getPath()),
+ e);
+ } finally {
+ if (tmpFile.exists()) {
+ FileUtils.delete(tmpFile);
+ }
}
entry.setLastModified(f.lastModified());
}
@@ -1202,24 +1344,6 @@
checkValidPathSegment(chk, i);
}
- /**
- * Check if path is a valid path for a checked out file name or ref name.
- *
- * @param path
- * @throws InvalidPathException
- * if the path is invalid
- * @since 3.3
- */
- static void checkValidPath(String path) throws InvalidPathException {
- try {
- SystemReader.getInstance().checkPath(path);
- } catch (CorruptObjectException e) {
- InvalidPathException p = new InvalidPathException(path);
- p.initCause(e);
- throw p;
- }
- }
-
private static void checkValidPathSegment(ObjectChecker chk,
CanonicalTreeParser t) throws InvalidPathException {
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
index 13885d3..c987c96 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
@@ -44,6 +44,10 @@
package org.eclipse.jgit.dircache;
+import static org.eclipse.jgit.dircache.DirCache.cmp;
+import static org.eclipse.jgit.dircache.DirCacheTree.peq;
+import static org.eclipse.jgit.lib.FileMode.TYPE_TREE;
+
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
@@ -53,6 +57,7 @@
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.util.Paths;
/**
* Updates a {@link DirCache} by supplying discrete edit commands.
@@ -72,11 +77,12 @@
public int compare(final PathEdit o1, final PathEdit o2) {
final byte[] a = o1.path;
final byte[] b = o2.path;
- return DirCache.cmp(a, a.length, b, b.length);
+ return cmp(a, a.length, b, b.length);
}
};
private final List<PathEdit> edits;
+ private int editIdx;
/**
* Construct a new editor.
@@ -126,35 +132,44 @@
private void applyEdits() {
Collections.sort(edits, EDIT_CMP);
+ editIdx = 0;
final int maxIdx = cache.getEntryCount();
int lastIdx = 0;
- for (final PathEdit e : edits) {
- int eIdx = cache.findEntry(e.path, e.path.length);
+ while (editIdx < edits.size()) {
+ PathEdit e = edits.get(editIdx++);
+ int eIdx = cache.findEntry(lastIdx, e.path, e.path.length);
final boolean missing = eIdx < 0;
if (eIdx < 0)
eIdx = -(eIdx + 1);
final int cnt = Math.min(eIdx, maxIdx) - lastIdx;
if (cnt > 0)
fastKeep(lastIdx, cnt);
- lastIdx = missing ? eIdx : cache.nextEntry(eIdx);
- if (e instanceof DeletePath)
+ if (e instanceof DeletePath) {
+ lastIdx = missing ? eIdx : cache.nextEntry(eIdx);
continue;
+ }
if (e instanceof DeleteTree) {
lastIdx = cache.nextEntry(e.path, e.path.length, eIdx);
continue;
}
if (missing) {
- final DirCacheEntry ent = new DirCacheEntry(e.path);
+ DirCacheEntry ent = new DirCacheEntry(e.path);
e.apply(ent);
- if (ent.getRawMode() == 0)
- throw new IllegalArgumentException(MessageFormat.format(JGitText.get().fileModeNotSetForPath
- , ent.getPathString()));
+ if (ent.getRawMode() == 0) {
+ throw new IllegalArgumentException(MessageFormat.format(
+ JGitText.get().fileModeNotSetForPath,
+ ent.getPathString()));
+ }
+ lastIdx = e.replace
+ ? deleteOverlappingSubtree(ent, eIdx)
+ : eIdx;
fastAdd(ent);
} else {
// Apply to all entries of the current path (different stages)
+ lastIdx = cache.nextEntry(eIdx);
for (int i = eIdx; i < lastIdx; i++) {
final DirCacheEntry ent = cache.getEntry(i);
e.apply(ent);
@@ -168,6 +183,102 @@
fastKeep(lastIdx, cnt);
}
+ private int deleteOverlappingSubtree(DirCacheEntry ent, int eIdx) {
+ byte[] entPath = ent.path;
+ int entLen = entPath.length;
+
+ // Delete any file that was previously processed and overlaps
+ // the parent directory for the new entry. Since the editor
+ // always processes entries in path order, binary search back
+ // for the overlap for each parent directory.
+ for (int p = pdir(entPath, entLen); p > 0; p = pdir(entPath, p)) {
+ int i = findEntry(entPath, p);
+ if (i >= 0) {
+ // A file does overlap, delete the file from the array.
+ // No other parents can have overlaps as the file should
+ // have taken care of that itself.
+ int n = --entryCnt - i;
+ System.arraycopy(entries, i + 1, entries, i, n);
+ break;
+ }
+
+ // If at least one other entry already exists in this parent
+ // directory there is no need to continue searching up the tree.
+ i = -(i + 1);
+ if (i < entryCnt && inDir(entries[i], entPath, p)) {
+ break;
+ }
+ }
+
+ int maxEnt = cache.getEntryCount();
+ if (eIdx >= maxEnt) {
+ return maxEnt;
+ }
+
+ DirCacheEntry next = cache.getEntry(eIdx);
+ if (Paths.compare(next.path, 0, next.path.length, 0,
+ entPath, 0, entLen, TYPE_TREE) < 0) {
+ // Next DirCacheEntry sorts before new entry as tree. Defer a
+ // DeleteTree command to delete any entries if they exist. This
+ // case only happens for A, A.c, A/c type of conflicts (rare).
+ insertEdit(new DeleteTree(entPath));
+ return eIdx;
+ }
+
+ // Next entry may be contained by the entry-as-tree, skip if so.
+ while (eIdx < maxEnt && inDir(cache.getEntry(eIdx), entPath, entLen)) {
+ eIdx++;
+ }
+ return eIdx;
+ }
+
+ private int findEntry(byte[] p, int pLen) {
+ int low = 0;
+ int high = entryCnt;
+ while (low < high) {
+ int mid = (low + high) >>> 1;
+ int cmp = cmp(p, pLen, entries[mid]);
+ if (cmp < 0) {
+ high = mid;
+ } else if (cmp == 0) {
+ while (mid > 0 && cmp(p, pLen, entries[mid - 1]) == 0) {
+ mid--;
+ }
+ return mid;
+ } else {
+ low = mid + 1;
+ }
+ }
+ return -(low + 1);
+ }
+
+ private void insertEdit(DeleteTree d) {
+ for (int i = editIdx; i < edits.size(); i++) {
+ int cmp = EDIT_CMP.compare(d, edits.get(i));
+ if (cmp < 0) {
+ edits.add(i, d);
+ return;
+ } else if (cmp == 0) {
+ return;
+ }
+ }
+ edits.add(d);
+ }
+
+ private static boolean inDir(DirCacheEntry e, byte[] path, int pLen) {
+ return e.path.length > pLen && e.path[pLen] == '/'
+ && peq(path, e.path, pLen);
+ }
+
+ private static int pdir(byte[] path, int e) {
+ for (e--; e > 0; e--) {
+ if (path[e] == '/') {
+ return e;
+ }
+ }
+ return 0;
+ }
+
/**
* Any index record update.
* <p>
@@ -179,6 +290,7 @@
*/
public abstract static class PathEdit {
final byte[] path;
+ boolean replace = true;
/**
* Create a new update command by path name.
@@ -190,6 +302,10 @@
path = Constants.encode(entryPath);
}
+ PathEdit(byte[] path) {
+ this.path = path;
+ }
+
/**
* Create a new update command for an existing entry instance.
*
@@ -202,6 +318,22 @@
}
/**
+ * Configure if a file can replace a directory (or vice versa).
+ * <p>
+ * Default is {@code true} as this is usually the desired behavior.
+ *
+ * @param ok
+ * if true a file can replace a directory, or a directory can
+ * replace a file.
+ * @return {@code this}
+ * @since 4.2
+ */
+ public PathEdit setReplace(boolean ok) {
+ replace = ok;
+ return this;
+ }
+
+ /**
* Apply the update to a single cache entry matching the path.
* <p>
* After apply is invoked the entry is added to the output table, and
@@ -212,6 +344,12 @@
* the path is a new path in the index.
*/
public abstract void apply(DirCacheEntry ent);
+
+ @Override
+ public String toString() {
+ String p = DirCacheEntry.toString(path);
+ return getClass().getSimpleName() + '[' + p + ']';
+ }
}
/**
@@ -272,10 +410,26 @@
* only the subtree's contents are matched by the command.
* The special case "" (not "/"!) deletes all entries.
*/
- public DeleteTree(final String entryPath) {
- super(
- (entryPath.endsWith("/") || entryPath.length() == 0) ? entryPath //$NON-NLS-1$
- : entryPath + "/"); //$NON-NLS-1$
+ public DeleteTree(String entryPath) {
+ super(entryPath.isEmpty()
+ || entryPath.charAt(entryPath.length() - 1) == '/'
+ ? entryPath
+ : entryPath + '/');
+ }
+
+ DeleteTree(byte[] path) {
+ super(appendSlash(path));
+ }
+
+ private static byte[] appendSlash(byte[] path) {
+ int n = path.length;
+ if (n > 0 && path[n - 1] != '/') {
+ byte[] r = new byte[n + 1];
+ System.arraycopy(path, 0, r, 0, n);
+ r[n] = '/';
+ return r;
+ }
+ return path;
}
public void apply(final DirCacheEntry ent) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
index eef2e6d..4ebf2e0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
@@ -65,6 +65,7 @@
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.MutableInteger;
import org.eclipse.jgit.util.NB;
+import org.eclipse.jgit.util.SystemReader;
/**
* A single file (or stage of a file) in a {@link DirCache}.
@@ -191,7 +192,7 @@
}
try {
- DirCacheCheckout.checkValidPath(toString(path));
+ checkPath(path);
} catch (InvalidPathException e) {
CorruptObjectException p =
new CorruptObjectException(e.getMessage());
@@ -263,7 +264,7 @@
/**
* Create an empty entry at the specified stage.
*
- * @param newPath
+ * @param path
* name of the cache entry, in the standard encoding.
* @param stage
* the stage index of the new entry.
@@ -274,16 +275,16 @@
* range 0..3, inclusive.
*/
@SuppressWarnings("boxing")
- public DirCacheEntry(final byte[] newPath, final int stage) {
- DirCacheCheckout.checkValidPath(toString(newPath));
+ public DirCacheEntry(byte[] path, final int stage) {
+ checkPath(path);
if (stage < 0 || 3 < stage)
throw new IllegalArgumentException(MessageFormat.format(
JGitText.get().invalidStageForPath,
- stage, toString(newPath)));
+ stage, toString(path)));
info = new byte[INFO_LEN];
infoOffset = 0;
- path = newPath;
+ this.path = path;
int flags = ((stage & 0x3) << 12);
if (path.length < NAME_MASK)
@@ -293,6 +294,23 @@
NB.encodeInt16(info, infoOffset + P_FLAGS, flags);
}
+ /**
+ * Duplicate DirCacheEntry with same path and copied info.
+ * <p>
+ * The same path buffer is reused (avoiding copying), however a new info
+ * buffer is created and its contents are copied.
+ *
+ * @param src
+ * entry to clone.
+ * @since 4.2
+ */
+ public DirCacheEntry(DirCacheEntry src) {
+ path = src.path;
+ info = new byte[INFO_LEN];
+ infoOffset = 0;
+ System.arraycopy(src.info, src.infoOffset, info, 0, INFO_LEN);
+ }
+
void write(final OutputStream os) throws IOException {
final int len = isExtended() ? INFO_LEN_EXTENDED : INFO_LEN;
final int pathLen = path.length;
@@ -498,12 +516,16 @@
switch (mode.getBits() & FileMode.TYPE_MASK) {
case FileMode.TYPE_MISSING:
case FileMode.TYPE_TREE:
- throw new IllegalArgumentException(MessageFormat.format(JGitText.get().invalidModeForPath
- , mode, getPathString()));
+ throw new IllegalArgumentException(MessageFormat.format(
+ JGitText.get().invalidModeForPath, mode, getPathString()));
}
NB.encodeInt32(info, infoOffset + P_MODE, mode.getBits());
}
+ void setFileMode(int mode) {
+ NB.encodeInt32(info, infoOffset + P_MODE, mode);
+ }
+
/**
* Get the cached creation time of this file, in milliseconds.
*
@@ -730,7 +752,17 @@
return 0;
}
- private static String toString(final byte[] path) {
+ private static void checkPath(byte[] path) {
+ try {
+ SystemReader.getInstance().checkPath(path);
+ } catch (CorruptObjectException e) {
+ InvalidPathException p = new InvalidPathException(toString(path));
+ p.initCause(e);
+ throw p;
+ }
+ }
+
+ static String toString(final byte[] path) {
return Constants.CHARSET.decode(ByteBuffer.wrap(path)).toString();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java
index 354a074..ad93f72 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java
@@ -103,9 +103,6 @@
/** The subtree containing {@link #currentEntry} if this is first entry. */
protected DirCacheTree currentSubtree;
- /** Holds an {@link AttributesNode} for the current entry */
- private AttributesNode attributesNode;
-
/**
* Create a new iterator for an already loaded DirCache instance.
* <p>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
index f139afc..0cbb83d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
@@ -103,7 +103,7 @@
private DirCacheTree parent;
/** Name of this tree within its parent. */
- private byte[] encodedName;
+ byte[] encodedName;
/** Number of {@link DirCacheEntry} records that belong to this tree. */
private int entrySpan;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CorruptObjectException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CorruptObjectException.java
index c6ea093..e4db40b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/CorruptObjectException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/CorruptObjectException.java
@@ -49,8 +49,10 @@
import java.io.IOException;
import java.text.MessageFormat;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectChecker;
import org.eclipse.jgit.lib.ObjectId;
/**
@@ -59,15 +61,24 @@
public class CorruptObjectException extends IOException {
private static final long serialVersionUID = 1L;
+ private ObjectChecker.ErrorType errorType;
+
/**
- * Construct a CorruptObjectException for reporting a problem specified
- * object id
+ * Report a specific error condition discovered in an object.
*
+ * @param type
+ * type of error
* @param id
+ * identity of the bad object
* @param why
+ * description of the error.
+ * @since 4.2
*/
- public CorruptObjectException(final AnyObjectId id, final String why) {
- this(id.toObjectId(), why);
+ public CorruptObjectException(ObjectChecker.ErrorType type, AnyObjectId id,
+ String why) {
+ super(MessageFormat.format(JGitText.get().objectIsCorrupt3,
+ type.getMessageId(), id.name(), why));
+ this.errorType = type;
}
/**
@@ -77,7 +88,18 @@
* @param id
* @param why
*/
- public CorruptObjectException(final ObjectId id, final String why) {
+ public CorruptObjectException(AnyObjectId id, String why) {
+ super(MessageFormat.format(JGitText.get().objectIsCorrupt, id.name(), why));
+ }
+
+ /**
+ * Construct a CorruptObjectException for reporting a problem specified
+ * object id
+ *
+ * @param id
+ * @param why
+ */
+ public CorruptObjectException(ObjectId id, String why) {
super(MessageFormat.format(JGitText.get().objectIsCorrupt, id.name(), why));
}
@@ -87,7 +109,7 @@
*
* @param why
*/
- public CorruptObjectException(final String why) {
+ public CorruptObjectException(String why) {
super(why);
}
@@ -105,4 +127,15 @@
super(why);
initCause(cause);
}
+
+ /**
+ * Specific error condition identified by {@link ObjectChecker}.
+ *
+ * @return error condition or null.
+ * @since 4.2
+ */
+ @Nullable
+ public ObjectChecker.ErrorType getErrorType() {
+ return errorType;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/DirCacheNameConflictException.java
similarity index 61%
copy from org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
copy to org.eclipse.jgit/src/org/eclipse/jgit/errors/DirCacheNameConflictException.java
index c7e41bc..5f67e34 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/DirCacheNameConflictException.java
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006-2007, Shawn O. Pearce <spearce@spearce.org>
+ * 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
@@ -42,44 +41,40 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package org.eclipse.jgit.lib;
+package org.eclipse.jgit.errors;
/**
- * A tree entry representing a symbolic link.
+ * Thrown by DirCache code when entries overlap in impossible way.
*
- * Note. Java cannot really handle these as file system objects.
- *
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
+ * @since 4.2
*/
-@Deprecated
-public class SymlinkTreeEntry extends TreeEntry {
+public class DirCacheNameConflictException extends IllegalStateException {
+ private static final long serialVersionUID = 1L;
+
+ private final String path1;
+ private final String path2;
/**
- * Construct a {@link SymlinkTreeEntry} with the specified name and SHA-1 in
- * the specified parent
+ * Construct an exception for a specific path.
*
- * @param parent
- * @param id
- * @param nameUTF8
+ * @param path1
+ * one path that conflicts.
+ * @param path2
+ * another path that conflicts.
*/
- public SymlinkTreeEntry(final Tree parent, final ObjectId id,
- final byte[] nameUTF8) {
- super(parent, id, nameUTF8);
+ public DirCacheNameConflictException(String path1, String path2) {
+ super(path1 + ' ' + path2);
+ this.path1 = path1;
+ this.path2 = path2;
}
- public FileMode getMode() {
- return FileMode.SYMLINK;
+ /** @return one of the paths that has a conflict. */
+ public String getPath1() {
+ return path1;
}
- public String toString() {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(getId()));
- r.append(" S "); //$NON-NLS-1$
- r.append(getFullName());
- return r.toString();
+ /** @return another path that has a conflict. */
+ public String getPath2() {
+ return path2;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexReadException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexReadException.java
new file mode 100644
index 0000000..70f650d
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/IndexReadException.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com> and
+ * other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v1.0 which accompanies this
+ * distribution, is reproduced below, and is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.errors;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.internal.JGitText;
+
+/**
+ * Cannot read the index. This is a serious error that users need to be made
+ * aware of.
+ *
+ * @since 4.2
+ */
+public class IndexReadException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs an IndexReadException with the default message.
+ */
+ public IndexReadException() {
+ super(JGitText.get().indexWriteException);
+ }
+
+ /**
+ * Constructs an IndexReadException with the specified detail message.
+ *
+ * @param s
+ * message
+ */
+ public IndexReadException(final String s) {
+ super(s);
+ }
+
+ /**
+ * Constructs an IndexReadException with the specified detail message.
+ *
+ * @param s
+ * message
+ * @param cause
+ * root cause exception
+ */
+ public IndexReadException(final String s, final Throwable cause) {
+ super(s);
+ initCause(cause);
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
index 891479d..7eb9550 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
@@ -338,6 +338,20 @@
else
last = p;
}
+ removeNestedCopyfiles();
+ }
+
+ /** Remove copyfiles that sit in a subdirectory of any other project. */
+ void removeNestedCopyfiles() {
+ for (RepoProject proj : filteredProjects) {
+ List<CopyFile> copyfiles = new ArrayList<>(proj.getCopyFiles());
+ proj.clearCopyFiles();
+ for (CopyFile copyfile : copyfiles) {
+ if (!isNestedCopyfile(copyfile)) {
+ proj.addCopyFile(copyfile);
+ }
+ }
+ }
}
boolean inGroups(RepoProject proj) {
@@ -357,4 +371,22 @@
}
return false;
}
+
+ private boolean isNestedCopyfile(CopyFile copyfile) {
+ if (copyfile.dest.indexOf('/') == -1) {
+ // If the copyfile is at root level then it won't be nested.
+ return false;
+ }
+ for (RepoProject proj : filteredProjects) {
+ if (proj.getPath().compareTo(copyfile.dest) > 0) {
+ // Early return as remaining projects can't be ancestor of this
+ // copyfile config (filteredProjects is sorted).
+ return false;
+ }
+ if (proj.isAncestorOf(copyfile.dest)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
index 790f4db..ff9f233 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -42,6 +42,9 @@
*/
package org.eclipse.jgit.gitrepo;
+import static org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME;
+import static org.eclipse.jgit.lib.Constants.R_REMOTES;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -106,6 +109,7 @@
private String groups;
private String branch;
private String targetBranch = Constants.HEAD;
+ private boolean recordRemoteBranch = false;
private PersonIdent author;
private RemoteReader callback;
private InputStream inputStream;
@@ -314,6 +318,30 @@
}
/**
+ * Set whether the branch name should be recorded in .gitmodules
+ * <p>
+ * Submodule entries in .gitmodules can include a "branch" field
+ * to indicate what remote branch each submodule tracks.
+ * <p>
+ * That field is used by "git submodule update --remote" to update
+ * to the tip of the tracked branch when asked and by Gerrit to
+ * update the superproject when a change on that branch is merged.
+ * <p>
+ * Subprojects that request a specific commit or tag will not have
+ * a branch name recorded.
+ * <p>
+ * Not implemented for non-bare repositories.
+ *
+ * @param enable Whether to record the branch name
+ * @return this command
+ * @since 4.2
+ */
+ public RepoCommand setRecordRemoteBranch(boolean enable) {
+ this.recordRemoteBranch = enable;
+ return this;
+ }
+
+ /**
* The progress monitor associated with the clone operation. By default,
* this is set to <code>NullProgressMonitor</code>
*
@@ -429,10 +457,14 @@
// create gitlink
DirCacheEntry dcEntry = new DirCacheEntry(name);
ObjectId objectId;
- if (ObjectId.isId(proj.getRevision()))
+ if (ObjectId.isId(proj.getRevision())) {
objectId = ObjectId.fromString(proj.getRevision());
- else {
+ } else {
objectId = callback.sha1(nameUri, proj.getRevision());
+ if (recordRemoteBranch)
+ // can be branch or tag
+ cfg.setString("submodule", name, "branch", //$NON-NLS-1$ //$NON-NLS-2$
+ proj.getRevision());
}
if (objectId == null)
throw new RemoteUnavailableException(nameUri);
@@ -545,7 +577,7 @@
private static String findRef(String ref, Repository repo)
throws IOException {
if (!ObjectId.isId(ref)) {
- Ref r = repo.getRef(Constants.DEFAULT_REMOTE_NAME + "/" + ref); //$NON-NLS-1$
+ Ref r = repo.exactRef(R_REMOTES + DEFAULT_REMOTE_NAME + "/" + ref); //$NON-NLS-1$
if (r != null)
return r.getName();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
index 9a07211..f6d1209 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
@@ -252,10 +252,19 @@
/**
* Add a bunch of copyfile configurations.
*
- * @param copyfiles
+ * @param copyFiles
*/
- public void addCopyFiles(Collection<CopyFile> copyfiles) {
- this.copyfiles.addAll(copyfiles);
+ public void addCopyFiles(Collection<CopyFile> copyFiles) {
+ this.copyfiles.addAll(copyFiles);
+ }
+
+ /**
+ * Clear all the copyfiles.
+ *
+ * @since 4.2
+ */
+ public void clearCopyFiles() {
+ this.copyfiles.clear();
}
private String getPathWithSlash() {
@@ -273,7 +282,19 @@
* @return true if this sub repo is the ancestor of given sub repo.
*/
public boolean isAncestorOf(RepoProject that) {
- return that.getPathWithSlash().startsWith(this.getPathWithSlash());
+ return isAncestorOf(that.getPathWithSlash());
+ }
+
+ /**
+ * Check if this sub repo is an ancestor of the given path.
+ *
+ * @param thatPath
+ * path to be checked to see if it is within this repository
+ * @return true if this sub repo is an ancestor of the given path.
+ * @since 4.2
+ */
+ public boolean isAncestorOf(String thatPath) {
+ return thatPath.startsWith(getPathWithSlash());
}
@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java
index 1494576..6f7a21a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java
@@ -74,4 +74,15 @@
PrintStream outputStream) {
return new CommitMsgHook(repo, outputStream);
}
+
+ /**
+ * @param repo
+ * @param outputStream
+ * The output stream, or {@code null} to use {@code System.out}
+ * @return The pre-push hook for the given repository.
+ * @since 4.2
+ */
+ public static PrePushHook prePush(Repository repo, PrintStream outputStream) {
+ return new PrePushHook(repo, outputStream);
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java
new file mode 100644
index 0000000..a501fee
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015 Obeo.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.hooks;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Collection;
+
+import org.eclipse.jgit.api.errors.AbortedByHookException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.RemoteRefUpdate;
+
+/**
+ * The <code>pre-push</code> hook implementation. The pre-push hook runs during
+ * git push, after the remote refs have been updated but before any objects have
+ * been transferred.
+ *
+ * @since 4.2
+ */
+public class PrePushHook extends GitHook<String> {
+
+ /**
+ * Constant indicating the name of the pre-push hook.
+ */
+ public static final String NAME = "pre-push"; //$NON-NLS-1$
+
+ private String remoteName;
+
+ private String remoteLocation;
+
+ private String refs;
+
+ /**
+ * @param repo
+ * The repository
+ * @param outputStream
+ * The output stream the hook must use. {@code null} is allowed,
+ * in which case the hook will use {@code System.out}.
+ */
+ protected PrePushHook(Repository repo, PrintStream outputStream) {
+ super(repo, outputStream);
+ }
+
+ @Override
+ protected String getStdinArgs() {
+ return refs;
+ }
+
+ @Override
+ public String call() throws IOException, AbortedByHookException {
+ if (canRun()) {
+ doRun();
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * @return {@code true}
+ */
+ private boolean canRun() {
+ return true;
+ }
+
+ @Override
+ public String getHookName() {
+ return NAME;
+ }
+
+ /**
+ * This hook receives two parameters, which is the name and the location of
+ * the remote repository.
+ */
+ @Override
+ protected String[] getParameters() {
+ if (remoteName == null) {
+ remoteName = remoteLocation;
+ }
+ return new String[] { remoteName, remoteLocation };
+ }
+
+ /**
+ * @param name
+ */
+ public void setRemoteName(String name) {
+ remoteName = name;
+ }
+
+ /**
+ * @param location
+ */
+ public void setRemoteLocation(String location) {
+ remoteLocation = location;
+ }
+
+ /**
+ * @param toRefs
+ */
+ public void setRefs(Collection<RemoteRefUpdate> toRefs) {
+ StringBuilder b = new StringBuilder();
+ boolean first = true;
+ for (RemoteRefUpdate u : toRefs) {
+ if (!first)
+ b.append("\n"); //$NON-NLS-1$
+ else
+ first = false;
+ b.append(u.getSrcRef());
+ b.append(" "); //$NON-NLS-1$
+ b.append(u.getNewObjectId().getName());
+ b.append(" "); //$NON-NLS-1$
+ b.append(u.getRemoteName());
+ b.append(" "); //$NON-NLS-1$
+ ObjectId ooid = u.getExpectedOldObjectId();
+ b.append((ooid == null) ? ObjectId.zeroId().getName() : ooid
+ .getName());
+ }
+ refs = b.toString();
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java
index f972828..e354c71 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java
@@ -141,9 +141,7 @@
private static boolean isComplexWildcard(String pattern) {
int idx1 = pattern.indexOf('[');
if (idx1 != -1) {
- int idx2 = pattern.indexOf(']', idx1);
- if (idx2 > idx1)
- return true;
+ return true;
}
if (pattern.indexOf('?') != -1) {
return true;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index 9067e82..7740a2b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -79,6 +79,7 @@
/***/ public String atLeastOnePathIsRequired;
/***/ public String atLeastOnePatternIsRequired;
/***/ public String atLeastTwoFiltersNeeded;
+ /***/ public String atomicPushNotSupported;
/***/ public String authenticationNotSupported;
/***/ public String badBase64InputCharacterAt;
/***/ public String badEntryDelimiter;
@@ -104,6 +105,7 @@
/***/ public String cannotBeRecursiveWhenTreesAreIncluded;
/***/ public String cannotChangeActionOnComment;
/***/ public String cannotChangeToComment;
+ /***/ public String cannotCheckoutFromUnbornBranch;
/***/ public String cannotCheckoutOursSwitchBranch;
/***/ public String cannotCombineSquashWithNoff;
/***/ public String cannotCombineTreeFilterWithRevFilter;
@@ -146,6 +148,7 @@
/***/ public String cannotReadCommit;
/***/ public String cannotReadFile;
/***/ public String cannotReadHEAD;
+ /***/ public String cannotReadIndex;
/***/ public String cannotReadObject;
/***/ public String cannotReadObjectsPath;
/***/ public String cannotReadTree;
@@ -155,6 +158,7 @@
/***/ public String cannotStoreObjects;
/***/ public String cannotResolveUniquelyAbbrevObjectId;
/***/ public String cannotUnloadAModifiedTree;
+ /***/ public String cannotUpdateUnbornBranch;
/***/ public String cannotWorkWithOtherStagesThanZeroRightNow;
/***/ public String cannotWriteObjectsPath;
/***/ public String canOnlyCherryPickCommitsWithOneParent;
@@ -181,14 +185,15 @@
/***/ public String connectionTimeOut;
/***/ public String contextMustBeNonNegative;
/***/ public String corruptionDetectedReReadingAt;
+ /***/ public String corruptObjectBadDate;
+ /***/ public String corruptObjectBadEmail;
/***/ public String corruptObjectBadStream;
/***/ public String corruptObjectBadStreamCorruptHeader;
+ /***/ public String corruptObjectBadTimezone;
/***/ public String corruptObjectDuplicateEntryNames;
/***/ public String corruptObjectGarbageAfterSize;
/***/ public String corruptObjectIncorrectLength;
/***/ public String corruptObjectIncorrectSorting;
- /***/ public String corruptObjectInvalidAuthor;
- /***/ public String corruptObjectInvalidCommitter;
/***/ public String corruptObjectInvalidEntryMode;
/***/ public String corruptObjectInvalidMode;
/***/ public String corruptObjectInvalidModeChar;
@@ -207,11 +212,11 @@
/***/ public String corruptObjectInvalidNamePrn;
/***/ public String corruptObjectInvalidObject;
/***/ public String corruptObjectInvalidParent;
- /***/ public String corruptObjectInvalidTagger;
/***/ public String corruptObjectInvalidTree;
/***/ public String corruptObjectInvalidType;
/***/ public String corruptObjectInvalidType2;
/***/ public String corruptObjectMalformedHeader;
+ /***/ public String corruptObjectMissingEmail;
/***/ public String corruptObjectNameContainsByte;
/***/ public String corruptObjectNameContainsChar;
/***/ public String corruptObjectNameContainsNullByte;
@@ -237,6 +242,7 @@
/***/ public String corruptObjectTruncatedInMode;
/***/ public String corruptObjectTruncatedInName;
/***/ public String corruptObjectTruncatedInObjectId;
+ /***/ public String corruptObjectZeroId;
/***/ public String corruptPack;
/***/ public String couldNotCheckOutBecauseOfConflicts;
/***/ public String couldNotDeleteLockFileShouldNotHappen;
@@ -287,6 +293,7 @@
/***/ public String emptyPathNotPermitted;
/***/ public String emptyRef;
/***/ public String encryptionError;
+ /***/ public String encryptionOnlyPBE;
/***/ public String endOfFileInEscape;
/***/ public String entryNotFoundByPath;
/***/ public String enumValueNotSupported2;
@@ -337,6 +344,8 @@
/***/ public String fileIsTooBigForThisConvenienceMethod;
/***/ public String fileIsTooLarge;
/***/ public String fileModeNotSetForPath;
+ /***/ public String filterExecutionFailed;
+ /***/ public String filterExecutionFailedRc;
/***/ public String findingGarbage;
/***/ public String flagIsDisposed;
/***/ public String flagNotFromThis;
@@ -409,6 +418,7 @@
/***/ public String invalidURL;
/***/ public String invalidWildcards;
/***/ public String invalidRefSpec;
+ /***/ public String invalidRepositoryStateNoHead;
/***/ public String invalidWindowSize;
/***/ public String isAStaticFlagAndHasNorevWalkInstance;
/***/ public String JRELacksMD5Implementation;
@@ -484,6 +494,7 @@
/***/ public String objectAtHasBadZlibStream;
/***/ public String objectAtPathDoesNotHaveId;
/***/ public String objectIsCorrupt;
+ /***/ public String objectIsCorrupt3;
/***/ public String objectIsNotA;
/***/ public String objectNotFound;
/***/ public String objectNotFoundIn;
@@ -508,6 +519,7 @@
/***/ public String packfileIsTruncatedNoParam;
/***/ public String packHandleIsStale;
/***/ public String packHasUnresolvedDeltas;
+ /***/ public String packInaccessible;
/***/ public String packingCancelledDuringObjectsWriting;
/***/ public String packObjectCountMismatch;
/***/ public String packRefs;
@@ -655,6 +667,7 @@
/***/ public String transportProtoSFTP;
/***/ public String transportProtoSSH;
/***/ public String transportProtoTest;
+ /***/ public String transportProvidedRefWithNoObjectId;
/***/ public String transportSSHRetryInterrupt;
/***/ public String treeEntryAlreadyExists;
/***/ public String treeFilterMarkerTooManyFilters;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
index faf27e3..784507d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
@@ -44,18 +44,17 @@
package org.eclipse.jgit.internal.storage.dfs;
import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC_TXN;
import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE;
import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX;
import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX;
import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.internal.JGitText;
@@ -63,13 +62,15 @@
import org.eclipse.jgit.internal.storage.file.PackIndex;
import org.eclipse.jgit.internal.storage.pack.PackExt;
import org.eclipse.jgit.internal.storage.pack.PackWriter;
+import org.eclipse.jgit.internal.storage.reftree.RefTreeNames;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectIdOwnerMap;
+import org.eclipse.jgit.lib.ObjectIdSet;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.storage.pack.PackStatistics;
@@ -78,16 +79,14 @@
/** Repack and garbage collect a repository. */
public class DfsGarbageCollector {
private final DfsRepository repo;
-
- private final DfsRefDatabase refdb;
-
+ private final RefDatabase refdb;
private final DfsObjDatabase objdb;
private final List<DfsPackDescription> newPackDesc;
private final List<PackStatistics> newPackStats;
- private final List<PackWriter.ObjectIdSet> newPackObj;
+ private final List<ObjectIdSet> newPackObj;
private DfsReader ctx;
@@ -95,14 +94,11 @@
private long coalesceGarbageLimit = 50 << 20;
- private Map<String, Ref> refsBefore;
-
private List<DfsPackFile> packsBefore;
private Set<ObjectId> allHeads;
-
private Set<ObjectId> nonHeads;
-
+ private Set<ObjectId> txnHeads;
private Set<ObjectId> tagTargets;
/**
@@ -117,7 +113,7 @@
objdb = repo.getObjectDatabase();
newPackDesc = new ArrayList<DfsPackDescription>(4);
newPackStats = new ArrayList<PackStatistics>(4);
- newPackObj = new ArrayList<PackWriter.ObjectIdSet>(4);
+ newPackObj = new ArrayList<ObjectIdSet>(4);
packConfig = new PackConfig(repo);
packConfig.setIndexVersion(2);
@@ -195,22 +191,25 @@
ctx = (DfsReader) objdb.newReader();
try {
- refdb.clearCache();
+ refdb.refresh();
objdb.clearCache();
- refsBefore = refdb.getRefs(ALL);
+ Collection<Ref> refsBefore = RefTreeNames.allRefs(refdb);
packsBefore = packsToRebuild();
if (packsBefore.isEmpty())
return true;
allHeads = new HashSet<ObjectId>();
nonHeads = new HashSet<ObjectId>();
+ txnHeads = new HashSet<ObjectId>();
tagTargets = new HashSet<ObjectId>();
- for (Ref ref : refsBefore.values()) {
+ for (Ref ref : refsBefore) {
if (ref.isSymbolic() || ref.getObjectId() == null)
continue;
if (isHead(ref))
allHeads.add(ref.getObjectId());
+ else if (RefTreeNames.isRefTree(refdb, ref.getName()))
+ txnHeads.add(ref.getObjectId());
else
nonHeads.add(ref.getObjectId());
if (ref.getPeeledObjectId() != null)
@@ -222,6 +221,7 @@
try {
packHeads(pm);
packRest(pm);
+ packRefTreeGraph(pm);
packGarbage(pm);
objdb.commitPack(newPackDesc, toPrune());
rollback = false;
@@ -277,18 +277,17 @@
try (PackWriter pw = newPackWriter()) {
pw.setTagTargets(tagTargets);
- pw.preparePack(pm, allHeads, Collections.<ObjectId> emptySet());
+ pw.preparePack(pm, allHeads, PackWriter.NONE);
if (0 < pw.getObjectCount())
writePack(GC, pw, pm);
}
}
-
private void packRest(ProgressMonitor pm) throws IOException {
if (nonHeads.isEmpty())
return;
try (PackWriter pw = newPackWriter()) {
- for (PackWriter.ObjectIdSet packedObjs : newPackObj)
+ for (ObjectIdSet packedObjs : newPackObj)
pw.excludeObjects(packedObjs);
pw.preparePack(pm, nonHeads, allHeads);
if (0 < pw.getObjectCount())
@@ -296,6 +295,19 @@
}
}
+ private void packRefTreeGraph(ProgressMonitor pm) throws IOException {
+ if (txnHeads.isEmpty())
+ return;
+
+ try (PackWriter pw = newPackWriter()) {
+ for (ObjectIdSet packedObjs : newPackObj)
+ pw.excludeObjects(packedObjs);
+ pw.preparePack(pm, txnHeads, PackWriter.NONE);
+ if (0 < pw.getObjectCount())
+ writePack(GC_TXN, pw, pm);
+ }
+ }
+
private void packGarbage(ProgressMonitor pm) throws IOException {
// TODO(sop) This is ugly. The garbage pack needs to be deleted.
PackConfig cfg = new PackConfig(packConfig);
@@ -328,7 +340,7 @@
}
private boolean anyPackHas(AnyObjectId id) {
- for (PackWriter.ObjectIdSet packedObjs : newPackObj)
+ for (ObjectIdSet packedObjs : newPackObj)
if (packedObjs.contains(id))
return true;
return false;
@@ -389,17 +401,10 @@
}
}
- final ObjectIdOwnerMap<ObjectIdOwnerMap.Entry> packedObjs = pw
- .getObjectSet();
- newPackObj.add(new PackWriter.ObjectIdSet() {
- public boolean contains(AnyObjectId objectId) {
- return packedObjs.contains(objectId);
- }
- });
-
PackStatistics stats = pw.getStatistics();
pack.setPackStats(stats);
newPackStats.add(stats);
+ newPackObj.add(pw.getObjectSet());
DfsBlockCache.getInstance().getOrCreate(pack, null);
return pack;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
index 488eee9..e5ae980 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
@@ -95,16 +95,16 @@
/** Always produce version 2 indexes, to get CRC data. */
private static final int INDEX_VERSION = 2;
- private final DfsObjDatabase db;
- private int compression = Deflater.BEST_COMPRESSION;
+ final DfsObjDatabase db;
+ int compression = Deflater.BEST_COMPRESSION;
- private List<PackedObjectInfo> objectList;
- private ObjectIdOwnerMap<PackedObjectInfo> objectMap;
+ List<PackedObjectInfo> objectList;
+ ObjectIdOwnerMap<PackedObjectInfo> objectMap;
- private DfsBlockCache cache;
- private DfsPackKey packKey;
- private DfsPackDescription packDsc;
- private PackStream packOut;
+ DfsBlockCache cache;
+ DfsPackKey packKey;
+ DfsPackDescription packDsc;
+ PackStream packOut;
private boolean rollback;
/**
@@ -137,7 +137,8 @@
ObjectId id = idFor(type, data, off, len);
if (objectMap != null && objectMap.contains(id))
return id;
- if (db.has(id))
+ // Ignore unreachable (garbage) objects here.
+ if (db.has(id, true))
return id;
long offset = beginObject(type, len);
@@ -322,7 +323,7 @@
private class PackStream extends OutputStream {
private final DfsOutputStream out;
private final MessageDigest md;
- private final byte[] hdrBuf;
+ final byte[] hdrBuf;
private final Deflater deflater;
private final int blockSize;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
index b92f784..3641560 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
@@ -54,6 +54,7 @@
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jgit.internal.storage.pack.PackExt;
+import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectDatabase;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
@@ -90,6 +91,13 @@
GC(1),
/**
+ * RefTreeGraph pack was created by Git garbage collection.
+ *
+ * @see DfsGarbageCollector
+ */
+ GC_TXN(1),
+
+ /**
* The pack was created by compacting multiple packs together.
* <p>
* Packs created by compacting multiple packs together aren't nearly as
@@ -181,6 +189,28 @@
}
/**
+ * Does the requested object exist in this database?
+ * <p>
+ * This differs from ObjectDatabase's implementation in that we can selectively
+ * ignore unreachable (garbage) objects.
+ *
+ * @param objectId
+ * identity of the object to test for existence of.
+ * @param avoidUnreachableObjects
+ * if true, ignore objects that are unreachable.
+ * @return true if the specified object is stored in this database.
+ * @throws IOException
+ * the object store cannot be accessed.
+ */
+ public boolean has(AnyObjectId objectId, boolean avoidUnreachableObjects)
+ throws IOException {
+ try (ObjectReader or = newReader()) {
+ or.setAvoidUnreachableObjects(avoidUnreachableObjects);
+ return or.has(objectId);
+ }
+ }
+
+ /**
* Generate a new unique name for a pack file.
*
* @param source
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
index 7073763..11aef7f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
@@ -62,6 +62,7 @@
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.ProgressMonitor;
import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.jgit.revwalk.RevObject;
@@ -91,7 +92,7 @@
private final List<DfsPackFile> srcPacks;
- private final List<PackWriter.ObjectIdSet> exclude;
+ private final List<ObjectIdSet> exclude;
private final List<DfsPackDescription> newPacks;
@@ -113,7 +114,7 @@
repo = repository;
autoAddSize = 5 * 1024 * 1024; // 5 MiB
srcPacks = new ArrayList<DfsPackFile>();
- exclude = new ArrayList<PackWriter.ObjectIdSet>(4);
+ exclude = new ArrayList<ObjectIdSet>(4);
newPacks = new ArrayList<DfsPackDescription>(1);
newStats = new ArrayList<PackStatistics>(1);
}
@@ -164,7 +165,7 @@
* objects to not include.
* @return {@code this}.
*/
- public DfsPackCompactor exclude(PackWriter.ObjectIdSet set) {
+ public DfsPackCompactor exclude(ObjectIdSet set) {
exclude.add(set);
return this;
}
@@ -183,11 +184,7 @@
try (DfsReader ctx = (DfsReader) repo.newObjectReader()) {
idx = pack.getPackIndex(ctx);
}
- return exclude(new PackWriter.ObjectIdSet() {
- public boolean contains(AnyObjectId id) {
- return idx.hasObject(id);
- }
- });
+ return exclude(idx);
}
/**
@@ -343,7 +340,7 @@
RevObject obj = rw.lookupOrNull(id);
if (obj != null && (obj.has(added) || obj.has(isBase)))
continue;
- for (PackWriter.ObjectIdSet e : exclude)
+ for (ObjectIdSet e : exclude)
if (e.contains(id))
continue SCAN;
want.add(new ObjectIdWithOffset(id, ent.getOffset()));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
index a1035a1..e5469f6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
@@ -262,6 +262,11 @@
}
@Override
+ public void refresh() {
+ clearCache();
+ }
+
+ @Override
public void close() {
clearCache();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java
index 122f6d3..ef88450 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepository.java
@@ -44,8 +44,13 @@
package org.eclipse.jgit.internal.storage.dfs;
import java.io.IOException;
+import java.io.InputStream;
import java.text.MessageFormat;
+import java.util.Collections;
+import org.eclipse.jgit.attributes.AttributesNode;
+import org.eclipse.jgit.attributes.AttributesNodeProvider;
+import org.eclipse.jgit.attributes.AttributesRule;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.RefUpdate;
@@ -74,9 +79,6 @@
@Override
public abstract DfsObjDatabase getObjectDatabase();
- @Override
- public abstract DfsRefDatabase getRefDatabase();
-
/** @return a description of this repository. */
public DfsRepositoryDescription getDescription() {
return description;
@@ -90,7 +92,10 @@
* the repository cannot be checked.
*/
public boolean exists() throws IOException {
- return getRefDatabase().exists();
+ if (getRefDatabase() instanceof DfsRefDatabase) {
+ return ((DfsRefDatabase) getRefDatabase()).exists();
+ }
+ return true;
}
@Override
@@ -112,7 +117,7 @@
@Override
public void scanForRepoChanges() throws IOException {
- getRefDatabase().clearCache();
+ getRefDatabase().refresh();
getObjectDatabase().clearCache();
}
@@ -126,4 +131,36 @@
public ReflogReader getReflogReader(String refName) throws IOException {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public AttributesNodeProvider createAttributesNodeProvider() {
+ // TODO Check if the implementation used in FileRepository can be used
+ // for this kind of repository
+ return new EmptyAttributesNodeProvider();
+ }
+
+ private static class EmptyAttributesNodeProvider implements
+ AttributesNodeProvider {
+ private EmptyAttributesNode emptyAttributesNode = new EmptyAttributesNode();
+
+ public AttributesNode getInfoAttributesNode() throws IOException {
+ return emptyAttributesNode;
+ }
+
+ public AttributesNode getGlobalAttributesNode() throws IOException {
+ return emptyAttributesNode;
+ }
+
+ private static class EmptyAttributesNode extends AttributesNode {
+
+ public EmptyAttributesNode() {
+ super(Collections.<AttributesRule> emptyList());
+ }
+
+ @Override
+ public void parse(InputStream in) throws IOException {
+ // Do nothing
+ }
+ }
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
index 8e7af0d..b312835 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
@@ -13,14 +13,22 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.eclipse.jgit.internal.storage.pack.PackExt;
+import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Ref.Storage;
+import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.SymbolicRef;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
import org.eclipse.jgit.util.RefList;
/**
@@ -43,11 +51,11 @@
}
}
- private static final AtomicInteger packId = new AtomicInteger();
+ static final AtomicInteger packId = new AtomicInteger();
private final DfsObjDatabase objdb;
-
- private final DfsRefDatabase refdb;
+ private final RefDatabase refdb;
+ private boolean performsAtomicTransactions = true;
/**
* Initialize a new in-memory repository.
@@ -60,7 +68,7 @@
this(new Builder().setRepositoryDescription(repoDesc));
}
- private InMemoryRepository(Builder builder) {
+ InMemoryRepository(Builder builder) {
super(builder);
objdb = new MemObjDatabase(this);
refdb = new MemRefDatabase();
@@ -72,10 +80,21 @@
}
@Override
- public DfsRefDatabase getRefDatabase() {
+ public RefDatabase getRefDatabase() {
return refdb;
}
+ /**
+ * Enable (or disable) the atomic reference transaction support.
+ * <p>
+ * Useful for testing atomic support enabled or disabled.
+ *
+ * @param atomic
+ */
+ public void setPerformsAtomicTransactions(boolean atomic) {
+ performsAtomicTransactions = atomic;
+ }
+
private class MemObjDatabase extends DfsObjDatabase {
private List<DfsPackDescription> packs = new ArrayList<DfsPackDescription>();
@@ -139,7 +158,7 @@
}
private static class MemPack extends DfsPackDescription {
- private final Map<PackExt, byte[]>
+ final Map<PackExt, byte[]>
fileMap = new HashMap<PackExt, byte[]>();
MemPack(String name, DfsRepositoryDescription repoDesc) {
@@ -235,41 +254,142 @@
private class MemRefDatabase extends DfsRefDatabase {
private final ConcurrentMap<String, Ref> refs = new ConcurrentHashMap<String, Ref>();
+ private final ReadWriteLock lock = new ReentrantReadWriteLock(true /* fair */);
MemRefDatabase() {
super(InMemoryRepository.this);
}
@Override
+ public boolean performsAtomicTransactions() {
+ return performsAtomicTransactions;
+ }
+
+ @Override
+ public BatchRefUpdate newBatchUpdate() {
+ return new BatchRefUpdate(this) {
+ @Override
+ public void execute(RevWalk walk, ProgressMonitor monitor)
+ throws IOException {
+ if (performsAtomicTransactions()) {
+ try {
+ lock.writeLock().lock();
+ batch(getCommands());
+ } finally {
+ lock.writeLock().unlock();
+ }
+ } else {
+ super.execute(walk, monitor);
+ }
+ }
+ };
+ }
+
+ @Override
protected RefCache scanAllRefs() throws IOException {
RefList.Builder<Ref> ids = new RefList.Builder<Ref>();
RefList.Builder<Ref> sym = new RefList.Builder<Ref>();
- for (Ref ref : refs.values()) {
- if (ref.isSymbolic())
- sym.add(ref);
- ids.add(ref);
+ try {
+ lock.readLock().lock();
+ for (Ref ref : refs.values()) {
+ if (ref.isSymbolic())
+ sym.add(ref);
+ ids.add(ref);
+ }
+ } finally {
+ lock.readLock().unlock();
}
ids.sort();
sym.sort();
return new RefCache(ids.toRefList(), sym.toRefList());
}
+ private void batch(List<ReceiveCommand> cmds) {
+ // Validate that the target exists in a new RevWalk, as the RevWalk
+ // from the RefUpdate might be reading back unflushed objects.
+ Map<ObjectId, ObjectId> peeled = new HashMap<>();
+ try (RevWalk rw = new RevWalk(getRepository())) {
+ for (ReceiveCommand c : cmds) {
+ if (c.getResult() != ReceiveCommand.Result.NOT_ATTEMPTED) {
+ ReceiveCommand.abort(cmds);
+ return;
+ }
+
+ if (!ObjectId.zeroId().equals(c.getNewId())) {
+ try {
+ RevObject o = rw.parseAny(c.getNewId());
+ if (o instanceof RevTag) {
+ peeled.put(o, rw.peel(o).copy());
+ }
+ } catch (IOException e) {
+ c.setResult(ReceiveCommand.Result.REJECTED_MISSING_OBJECT);
+ ReceiveCommand.abort(cmds);
+ return;
+ }
+ }
+ }
+ }
+
+ // Check all references conform to expected old value.
+ for (ReceiveCommand c : cmds) {
+ Ref r = refs.get(c.getRefName());
+ if (r == null) {
+ if (c.getType() != ReceiveCommand.Type.CREATE) {
+ c.setResult(ReceiveCommand.Result.LOCK_FAILURE);
+ ReceiveCommand.abort(cmds);
+ return;
+ }
+ } else {
+ ObjectId objectId = r.getObjectId();
+ if (r.isSymbolic() || objectId == null
+ || !objectId.equals(c.getOldId())) {
+ c.setResult(ReceiveCommand.Result.LOCK_FAILURE);
+ ReceiveCommand.abort(cmds);
+ return;
+ }
+ }
+ }
+
+ // Write references.
+ for (ReceiveCommand c : cmds) {
+ if (c.getType() == ReceiveCommand.Type.DELETE) {
+ refs.remove(c.getRefName());
+ c.setResult(ReceiveCommand.Result.OK);
+ continue;
+ }
+
+ ObjectId p = peeled.get(c.getNewId());
+ Ref r;
+ if (p != null) {
+ r = new ObjectIdRef.PeeledTag(Storage.PACKED,
+ c.getRefName(), c.getNewId(), p);
+ } else {
+ r = new ObjectIdRef.PeeledNonTag(Storage.PACKED,
+ c.getRefName(), c.getNewId());
+ }
+ refs.put(r.getName(), r);
+ c.setResult(ReceiveCommand.Result.OK);
+ }
+ clearCache();
+ }
+
@Override
protected boolean compareAndPut(Ref oldRef, Ref newRef)
throws IOException {
- ObjectId id = newRef.getObjectId();
- if (id != null) {
- try (RevWalk rw = new RevWalk(getRepository())) {
- // Validate that the target exists in a new RevWalk, as the RevWalk
- // from the RefUpdate might be reading back unflushed objects.
- rw.parseAny(id);
+ try {
+ lock.writeLock().lock();
+ ObjectId id = newRef.getObjectId();
+ if (id != null) {
+ try (RevWalk rw = new RevWalk(getRepository())) {
+ // Validate that the target exists in a new RevWalk, as the RevWalk
+ // from the RefUpdate might be reading back unflushed objects.
+ rw.parseAny(id);
+ }
}
- }
- String name = newRef.getName();
- if (oldRef == null)
- return refs.putIfAbsent(name, newRef) == null;
+ String name = newRef.getName();
+ if (oldRef == null)
+ return refs.putIfAbsent(name, newRef) == null;
- synchronized (refs) {
Ref cur = refs.get(name);
Ref toCompare = cur;
if (toCompare != null) {
@@ -294,22 +414,29 @@
if (eq(toCompare, oldRef))
return refs.replace(name, cur, newRef);
}
+
+ if (oldRef.getStorage() == Storage.NEW)
+ return refs.putIfAbsent(name, newRef) == null;
+
+ return false;
+ } finally {
+ lock.writeLock().unlock();
}
-
- if (oldRef.getStorage() == Storage.NEW)
- return refs.putIfAbsent(name, newRef) == null;
-
- return false;
}
@Override
protected boolean compareAndRemove(Ref oldRef) throws IOException {
- String name = oldRef.getName();
- Ref cur = refs.get(name);
- if (cur != null && eq(cur, oldRef))
- return refs.remove(name, cur);
- else
- return false;
+ try {
+ lock.writeLock().lock();
+ String name = oldRef.getName();
+ Ref cur = refs.get(name);
+ if (cur != null && eq(cur, oldRef))
+ return refs.remove(name, cur);
+ else
+ return false;
+ } finally {
+ lock.writeLock().unlock();
+ }
}
private boolean eq(Ref a, Ref b) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java
index 0c3c736..b27bcc4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java
@@ -63,11 +63,11 @@
public class BitmapIndexImpl implements BitmapIndex {
private static final int EXTRA_BITS = 10 * 1024;
- private final PackBitmapIndex packIndex;
+ final PackBitmapIndex packIndex;
- private final MutableBitmapIndex mutableIndex;
+ final MutableBitmapIndex mutableIndex;
- private final int indexObjectCount;
+ final int indexObjectCount;
/**
* Creates a BitmapIndex that is back by Compressed bitmaps.
@@ -85,18 +85,20 @@
return packIndex;
}
+ @Override
public CompressedBitmap getBitmap(AnyObjectId objectId) {
EWAHCompressedBitmap compressed = packIndex.getBitmap(objectId);
if (compressed == null)
return null;
- return new CompressedBitmap(compressed);
+ return new CompressedBitmap(compressed, this);
}
+ @Override
public CompressedBitmapBuilder newBitmapBuilder() {
- return new CompressedBitmapBuilder();
+ return new CompressedBitmapBuilder(this);
}
- private int findPosition(AnyObjectId objectId) {
+ int findPosition(AnyObjectId objectId) {
int position = packIndex.findPosition(objectId);
if (position < 0) {
position = mutableIndex.findPosition(objectId);
@@ -106,10 +108,10 @@
return position;
}
- private int addObject(AnyObjectId objectId, int type) {
+ int findOrInsert(AnyObjectId objectId, int type) {
int position = findPosition(objectId);
if (position < 0) {
- position = mutableIndex.addObject(objectId, type);
+ position = mutableIndex.findOrInsert(objectId, type);
position += indexObjectCount;
}
return position;
@@ -122,11 +124,11 @@
private BitSet toRemove;
- private ComboBitset() {
+ ComboBitset() {
this(new EWAHCompressedBitmap());
}
- private ComboBitset(EWAHCompressedBitmap bitmap) {
+ ComboBitset(EWAHCompressedBitmap bitmap) {
this.inflatingBitmap = new InflatingBitSet(bitmap);
}
@@ -197,15 +199,22 @@
}
}
- private final class CompressedBitmapBuilder implements BitmapBuilder {
- private ComboBitset bitset = new ComboBitset();
+ private static final class CompressedBitmapBuilder implements BitmapBuilder {
+ private ComboBitset bitset;
+ private final BitmapIndexImpl bitmapIndex;
+ CompressedBitmapBuilder(BitmapIndexImpl bitmapIndex) {
+ this.bitset = new ComboBitset();
+ this.bitmapIndex = bitmapIndex;
+ }
+
+ @Override
public boolean add(AnyObjectId objectId, int type) {
- int position = addObject(objectId, type);
+ int position = bitmapIndex.findOrInsert(objectId, type);
if (bitset.contains(position))
return false;
- Bitmap entry = getBitmap(objectId);
+ Bitmap entry = bitmapIndex.getBitmap(objectId);
if (entry != null) {
or(entry);
return false;
@@ -215,120 +224,142 @@
return true;
}
+ @Override
public boolean contains(AnyObjectId objectId) {
- int position = findPosition(objectId);
+ int position = bitmapIndex.findPosition(objectId);
return 0 <= position && bitset.contains(position);
}
+ @Override
+ public BitmapBuilder addObject(AnyObjectId objectId, int type) {
+ bitset.set(bitmapIndex.findOrInsert(objectId, type));
+ return this;
+ }
+
+ @Override
public void remove(AnyObjectId objectId) {
- int position = findPosition(objectId);
+ int position = bitmapIndex.findPosition(objectId);
if (0 <= position)
bitset.remove(position);
}
+ @Override
public CompressedBitmapBuilder or(Bitmap other) {
- if (isSameCompressedBitmap(other)) {
- bitset.or(((CompressedBitmap) other).bitmap);
- } else if (isSameCompressedBitmapBuilder(other)) {
- CompressedBitmapBuilder b = (CompressedBitmapBuilder) other;
- bitset.or(b.bitset.combine());
- } else {
- throw new IllegalArgumentException();
- }
+ bitset.or(ewahBitmap(other));
return this;
}
+ @Override
public CompressedBitmapBuilder andNot(Bitmap other) {
- if (isSameCompressedBitmap(other)) {
- bitset.andNot(((CompressedBitmap) other).bitmap);
- } else if (isSameCompressedBitmapBuilder(other)) {
- CompressedBitmapBuilder b = (CompressedBitmapBuilder) other;
- bitset.andNot(b.bitset.combine());
- } else {
- throw new IllegalArgumentException();
- }
+ bitset.andNot(ewahBitmap(other));
return this;
}
+ @Override
public CompressedBitmapBuilder xor(Bitmap other) {
- if (isSameCompressedBitmap(other)) {
- bitset.xor(((CompressedBitmap) other).bitmap);
- } else if (isSameCompressedBitmapBuilder(other)) {
- CompressedBitmapBuilder b = (CompressedBitmapBuilder) other;
- bitset.xor(b.bitset.combine());
- } else {
- throw new IllegalArgumentException();
- }
+ bitset.xor(ewahBitmap(other));
return this;
}
/** @return the fully built immutable bitmap */
+ @Override
public CompressedBitmap build() {
- return new CompressedBitmap(bitset.combine());
+ return new CompressedBitmap(bitset.combine(), bitmapIndex);
}
+ @Override
public Iterator<BitmapObject> iterator() {
return build().iterator();
}
+ @Override
public int cardinality() {
return bitset.combine().cardinality();
}
+ @Override
public boolean removeAllOrNone(PackBitmapIndex index) {
- if (!packIndex.equals(index))
+ if (!bitmapIndex.packIndex.equals(index))
return false;
EWAHCompressedBitmap curr = bitset.combine()
- .xor(ones(indexObjectCount));
+ .xor(ones(bitmapIndex.indexObjectCount));
IntIterator ii = curr.intIterator();
- if (ii.hasNext() && ii.next() < indexObjectCount)
+ if (ii.hasNext() && ii.next() < bitmapIndex.indexObjectCount)
return false;
bitset = new ComboBitset(curr);
return true;
}
- private BitmapIndexImpl getBitmapIndex() {
- return BitmapIndexImpl.this;
+ @Override
+ public BitmapIndexImpl getBitmapIndex() {
+ return bitmapIndex;
+ }
+
+ private EWAHCompressedBitmap ewahBitmap(Bitmap other) {
+ if (other instanceof CompressedBitmap) {
+ CompressedBitmap b = (CompressedBitmap) other;
+ if (b.bitmapIndex != bitmapIndex) {
+ throw new IllegalArgumentException();
+ }
+ return b.bitmap;
+ }
+ if (other instanceof CompressedBitmapBuilder) {
+ CompressedBitmapBuilder b = (CompressedBitmapBuilder) other;
+ if (b.bitmapIndex != bitmapIndex) {
+ throw new IllegalArgumentException();
+ }
+ return b.bitset.combine();
+ }
+ throw new IllegalArgumentException();
}
}
- final class CompressedBitmap implements Bitmap {
- private final EWAHCompressedBitmap bitmap;
+ /**
+ * Wrapper for a {@link EWAHCompressedBitmap} and {@link PackBitmapIndex}.
+ * <p>
+ * For a EWAHCompressedBitmap {@code bitmap} representing a vector of
+ * bits, {@code new CompressedBitmap(bitmap, bitmapIndex)} represents the
+ * objects at those positions in {@code bitmapIndex.packIndex}.
+ */
+ public static final class CompressedBitmap implements Bitmap {
+ final EWAHCompressedBitmap bitmap;
+ final BitmapIndexImpl bitmapIndex;
- private CompressedBitmap(EWAHCompressedBitmap bitmap) {
+ /**
+ * Construct compressed bitmap for given bitmap and bitmap index
+ *
+ * @param bitmap
+ * @param bitmapIndex
+ */
+ public CompressedBitmap(EWAHCompressedBitmap bitmap, BitmapIndexImpl bitmapIndex) {
this.bitmap = bitmap;
+ this.bitmapIndex = bitmapIndex;
}
+ @Override
public CompressedBitmap or(Bitmap other) {
- return new CompressedBitmap(bitmap.or(bitmapOf(other)));
+ return new CompressedBitmap(bitmap.or(ewahBitmap(other)), bitmapIndex);
}
+ @Override
public CompressedBitmap andNot(Bitmap other) {
- return new CompressedBitmap(bitmap.andNot(bitmapOf(other)));
+ return new CompressedBitmap(bitmap.andNot(ewahBitmap(other)), bitmapIndex);
}
+ @Override
public CompressedBitmap xor(Bitmap other) {
- return new CompressedBitmap(bitmap.xor(bitmapOf(other)));
- }
-
- private EWAHCompressedBitmap bitmapOf(Bitmap other) {
- if (isSameCompressedBitmap(other))
- return ((CompressedBitmap) other).bitmap;
- if (isSameCompressedBitmapBuilder(other))
- return ((CompressedBitmapBuilder) other).build().bitmap;
- CompressedBitmapBuilder builder = newBitmapBuilder();
- builder.or(other);
- return builder.build().bitmap;
+ return new CompressedBitmap(bitmap.xor(ewahBitmap(other)), bitmapIndex);
}
private final IntIterator ofObjectType(int type) {
- return packIndex.ofObjectType(bitmap, type).intIterator();
+ return bitmapIndex.packIndex.ofObjectType(bitmap, type).intIterator();
}
+ @Override
public Iterator<BitmapObject> iterator() {
- final IntIterator dynamic = bitmap.andNot(ones(indexObjectCount))
+ final IntIterator dynamic = bitmap.andNot(ones(bitmapIndex.indexObjectCount))
.intIterator();
final IntIterator commits = ofObjectType(Constants.OBJ_COMMIT);
final IntIterator trees = ofObjectType(Constants.OBJ_TREE);
@@ -365,12 +396,12 @@
throw new NoSuchElementException();
int position = cached.next();
- if (position < indexObjectCount) {
+ if (position < bitmapIndex.indexObjectCount) {
out.type = type;
- out.objectId = packIndex.getObject(position);
+ out.objectId = bitmapIndex.packIndex.getObject(position);
} else {
- position -= indexObjectCount;
- MutableEntry entry = mutableIndex.getObject(position);
+ position -= bitmapIndex.indexObjectCount;
+ MutableEntry entry = bitmapIndex.mutableIndex.getObject(position);
out.type = entry.type;
out.objectId = entry;
}
@@ -387,8 +418,22 @@
return bitmap;
}
- private BitmapIndexImpl getPackBitmapIndex() {
- return BitmapIndexImpl.this;
+ private EWAHCompressedBitmap ewahBitmap(Bitmap other) {
+ if (other instanceof CompressedBitmap) {
+ CompressedBitmap b = (CompressedBitmap) other;
+ if (b.bitmapIndex != bitmapIndex) {
+ throw new IllegalArgumentException();
+ }
+ return b.bitmap;
+ }
+ if (other instanceof CompressedBitmapBuilder) {
+ CompressedBitmapBuilder b = (CompressedBitmapBuilder) other;
+ if (b.bitmapIndex != bitmapIndex) {
+ throw new IllegalArgumentException();
+ }
+ return b.bitset.combine();
+ }
+ throw new IllegalArgumentException();
}
}
@@ -419,7 +464,7 @@
}
}
- int addObject(AnyObjectId objectId, int type) {
+ int findOrInsert(AnyObjectId objectId, int type) {
MutableEntry entry = new MutableEntry(
objectId, type, revList.size());
revList.add(entry);
@@ -429,9 +474,9 @@
}
private static final class MutableEntry extends ObjectIdOwnerMap.Entry {
- private final int type;
+ final int type;
- private final int position;
+ final int position;
MutableEntry(AnyObjectId objectId, int type, int position) {
super(objectId);
@@ -456,23 +501,7 @@
}
}
- private boolean isSameCompressedBitmap(Bitmap other) {
- if (other instanceof CompressedBitmap) {
- CompressedBitmap b = (CompressedBitmap) other;
- return this == b.getPackBitmapIndex();
- }
- return false;
- }
-
- private boolean isSameCompressedBitmapBuilder(Bitmap other) {
- if (other instanceof CompressedBitmapBuilder) {
- CompressedBitmapBuilder b = (CompressedBitmapBuilder) other;
- return this == b.getBitmapIndex();
- }
- return false;
- }
-
- private static final EWAHCompressedBitmap ones(int sizeInBits) {
+ static final EWAHCompressedBitmap ones(int sizeInBits) {
EWAHCompressedBitmap mask = new EWAHCompressedBitmap();
mask.addStreamOfEmptyWords(
true, sizeInBits / EWAHCompressedBitmap.wordinbits);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java
index 2f30496..a95dea7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java
@@ -50,7 +50,7 @@
class DeltaBaseCache {
private static final int CACHE_SZ = 1024;
- private static final SoftReference<Entry> DEAD;
+ static final SoftReference<Entry> DEAD;
private static int hash(final long position) {
return (((int) position) << 22) >>> 22;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
index 995621e..b02efed 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
@@ -49,16 +49,21 @@
import static org.eclipse.jgit.lib.RefDatabase.ALL;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Set;
+import org.eclipse.jgit.attributes.AttributesNode;
+import org.eclipse.jgit.attributes.AttributesNodeProvider;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.events.ConfigChangedEvent;
import org.eclipse.jgit.events.ConfigChangedListener;
import org.eclipse.jgit.events.IndexChangedEvent;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase;
import org.eclipse.jgit.internal.storage.file.ObjectDirectory.AlternateHandle;
import org.eclipse.jgit.internal.storage.file.ObjectDirectory.AlternateRepository;
import org.eclipse.jgit.lib.BaseRepositoryBuilder;
@@ -197,7 +202,22 @@
}
});
- refs = new RefDirectory(this);
+ final long repositoryFormatVersion = getConfig().getLong(
+ ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 0);
+
+ String reftype = repoConfig.getString(
+ "extensions", null, "refsStorage"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (repositoryFormatVersion >= 1 && reftype != null) {
+ if (StringUtils.equalsIgnoreCase(reftype, "reftree")) { //$NON-NLS-1$
+ refs = new RefTreeDatabase(this, new RefDirectory(this));
+ } else {
+ throw new IOException(JGitText.get().unknownRepositoryFormat);
+ }
+ } else {
+ refs = new RefDirectory(this);
+ }
+
objectDatabase = new ObjectDirectory(repoConfig, //
options.getObjectDirectory(), //
options.getAlternateObjectDirectories(), //
@@ -205,10 +225,7 @@
new File(getDirectory(), Constants.SHALLOW));
if (objectDatabase.exists()) {
- final long repositoryFormatVersion = getConfig().getLong(
- ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 0);
- if (repositoryFormatVersion > 0)
+ if (repositoryFormatVersion > 1)
throw new IOException(MessageFormat.format(
JGitText.get().unknownRepositoryFormat2,
Long.valueOf(repositoryFormatVersion)));
@@ -337,7 +354,7 @@
ConfigConstants.CONFIG_KEY_WORKTREE, getWorkTree()
.getAbsolutePath());
LockFile dotGitLockFile = new LockFile(new File(workTree,
- Constants.DOT_GIT), getFS());
+ Constants.DOT_GIT));
try {
if (dotGitLockFile.lock()) {
dotGitLockFile.write(Constants.encode(Constants.GITDIR
@@ -479,4 +496,63 @@
return new ReflogReaderImpl(this, ref.getName());
return null;
}
+
+ @Override
+ public AttributesNodeProvider createAttributesNodeProvider() {
+ return new AttributesNodeProviderImpl(this);
+ }
+
+ /**
+ * Implementation a {@link AttributesNodeProvider} for a
+ * {@link FileRepository}.
+ *
+ * @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a>
+ *
+ */
+ static class AttributesNodeProviderImpl implements
+ AttributesNodeProvider {
+
+ private AttributesNode infoAttributesNode;
+
+ private AttributesNode globalAttributesNode;
+
+ /**
+ * Constructor.
+ *
+ * @param repo
+ * {@link Repository} that will provide the attribute nodes.
+ */
+ protected AttributesNodeProviderImpl(Repository repo) {
+ infoAttributesNode = new InfoAttributesNode(repo);
+ globalAttributesNode = new GlobalAttributesNode(repo);
+ }
+
+ public AttributesNode getInfoAttributesNode() throws IOException {
+ if (infoAttributesNode instanceof InfoAttributesNode)
+ infoAttributesNode = ((InfoAttributesNode) infoAttributesNode)
+ .load();
+ return infoAttributesNode;
+ }
+
+ public AttributesNode getGlobalAttributesNode() throws IOException {
+ if (globalAttributesNode instanceof GlobalAttributesNode)
+ globalAttributesNode = ((GlobalAttributesNode) globalAttributesNode)
+ .load();
+ return globalAttributesNode;
+ }
+
+ static void loadRulesFromFile(AttributesNode r, File attrs)
+ throws FileNotFoundException, IOException {
+ if (attrs.exists()) {
+ FileInputStream in = new FileInputStream(attrs);
+ try {
+ r.parse(in);
+ } finally {
+ in.close();
+ }
+ }
+ }
+
+ }
+
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index c5723c0..2ce0d47 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -45,7 +45,6 @@
import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX;
import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX;
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
import java.io.File;
import java.io.FileOutputStream;
@@ -53,6 +52,7 @@
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
+import java.nio.file.StandardCopyOption;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
@@ -62,14 +62,14 @@
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
+import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
+import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -78,18 +78,19 @@
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.pack.PackExt;
import org.eclipse.jgit.internal.storage.pack.PackWriter;
-import org.eclipse.jgit.internal.storage.pack.PackWriter.ObjectIdSet;
-import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.internal.storage.reftree.RefTreeNames;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdSet;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Ref.Storage;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.ReflogEntry;
+import org.eclipse.jgit.lib.ReflogReader;
import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
@@ -126,7 +127,7 @@
* difference between the current refs and the refs which existed during
* last {@link #repack()}.
*/
- private Map<String, Ref> lastPackedRefs;
+ private Collection<Ref> lastPackedRefs;
/**
* Holds the starting time of the last repack() execution. This is needed in
@@ -360,17 +361,20 @@
// during last repack(). Only those refs will survive which have been
// added or modified since the last repack. Only these can save existing
// loose refs from being pruned.
- Map<String, Ref> newRefs;
+ Collection<Ref> newRefs;
if (lastPackedRefs == null || lastPackedRefs.isEmpty())
newRefs = getAllRefs();
else {
- newRefs = new HashMap<String, Ref>();
- for (Iterator<Map.Entry<String, Ref>> i = getAllRefs().entrySet()
- .iterator(); i.hasNext();) {
- Entry<String, Ref> newEntry = i.next();
- Ref old = lastPackedRefs.get(newEntry.getKey());
- if (!equals(newEntry.getValue(), old))
- newRefs.put(newEntry.getKey(), newEntry.getValue());
+ Map<String, Ref> last = new HashMap<>();
+ for (Ref r : lastPackedRefs) {
+ last.put(r.getName(), r);
+ }
+ newRefs = new ArrayList<>();
+ for (Ref r : getAllRefs()) {
+ Ref old = last.get(r.getName());
+ if (!equals(r, old)) {
+ newRefs.add(r);
+ }
}
}
@@ -382,10 +386,10 @@
// leave this method.
ObjectWalk w = new ObjectWalk(repo);
try {
- for (Ref cr : newRefs.values())
+ for (Ref cr : newRefs)
w.markStart(w.parseAny(cr.getObjectId()));
if (lastPackedRefs != null)
- for (Ref lpr : lastPackedRefs.values())
+ for (Ref lpr : lastPackedRefs)
w.markUninteresting(w.parseAny(lpr.getObjectId()));
removeReferenced(deletionCandidates, w);
} finally {
@@ -403,11 +407,11 @@
// additional reflog entries not handled during last repack()
ObjectWalk w = new ObjectWalk(repo);
try {
- for (Ref ar : getAllRefs().values())
+ for (Ref ar : getAllRefs())
for (ObjectId id : listRefLogObjects(ar, lastRepackTime))
w.markStart(w.parseAny(id));
if (lastPackedRefs != null)
- for (Ref lpr : lastPackedRefs.values())
+ for (Ref lpr : lastPackedRefs)
w.markUninteresting(w.parseAny(lpr.getObjectId()));
removeReferenced(deletionCandidates, w);
} finally {
@@ -482,9 +486,10 @@
return false;
return r1.getTarget().getName().equals(r2.getTarget().getName());
} else {
- if (r2.isSymbolic())
+ if (r2.isSymbolic()) {
return false;
- return r1.getObjectId().equals(r2.getObjectId());
+ }
+ return Objects.equals(r1.getObjectId(), r2.getObjectId());
}
}
@@ -527,19 +532,23 @@
Collection<PackFile> toBeDeleted = repo.getObjectDatabase().getPacks();
long time = System.currentTimeMillis();
- Map<String, Ref> refsBefore = getAllRefs();
+ Collection<Ref> refsBefore = getAllRefs();
Set<ObjectId> allHeads = new HashSet<ObjectId>();
Set<ObjectId> nonHeads = new HashSet<ObjectId>();
+ Set<ObjectId> txnHeads = new HashSet<ObjectId>();
Set<ObjectId> tagTargets = new HashSet<ObjectId>();
Set<ObjectId> indexObjects = listNonHEADIndexObjects();
+ RefDatabase refdb = repo.getRefDatabase();
- for (Ref ref : refsBefore.values()) {
+ for (Ref ref : refsBefore) {
nonHeads.addAll(listRefLogObjects(ref, 0));
if (ref.isSymbolic() || ref.getObjectId() == null)
continue;
if (ref.getName().startsWith(Constants.R_HEADS))
allHeads.add(ref.getObjectId());
+ else if (RefTreeNames.isRefTree(refdb, ref.getName()))
+ txnHeads.add(ref.getObjectId());
else
nonHeads.add(ref.getObjectId());
if (ref.getPeeledObjectId() != null)
@@ -549,7 +558,7 @@
List<ObjectIdSet> excluded = new LinkedList<ObjectIdSet>();
for (final PackFile f : repo.getObjectDatabase().getPacks())
if (f.shouldBeKept())
- excluded.add(objectIdSet(f.getIndex()));
+ excluded.add(f.getIndex());
tagTargets.addAll(allHeads);
nonHeads.addAll(indexObjects);
@@ -561,7 +570,7 @@
tagTargets, excluded);
if (heads != null) {
ret.add(heads);
- excluded.add(0, objectIdSet(heads.getIndex()));
+ excluded.add(0, heads.getIndex());
}
}
if (!nonHeads.isEmpty()) {
@@ -569,6 +578,11 @@
if (rest != null)
ret.add(rest);
}
+ if (!txnHeads.isEmpty()) {
+ PackFile txn = writePack(txnHeads, PackWriter.NONE, null, excluded);
+ if (txn != null)
+ ret.add(txn);
+ }
try {
deleteOldPacks(toBeDeleted, ret);
} catch (ParseException e) {
@@ -592,7 +606,11 @@
* @throws IOException
*/
private Set<ObjectId> listRefLogObjects(Ref ref, long minTime) throws IOException {
- List<ReflogEntry> rlEntries = repo.getReflogReader(ref.getName())
+ ReflogReader reflogReader = repo.getReflogReader(ref.getName());
+ if (reflogReader == null) {
+ return Collections.emptySet();
+ }
+ List<ReflogEntry> rlEntries = reflogReader
.getReverseEntries();
if (rlEntries == null || rlEntries.isEmpty())
return Collections.<ObjectId> emptySet();
@@ -617,11 +635,16 @@
* @return a map where names of refs point to ref objects
* @throws IOException
*/
- private Map<String, Ref> getAllRefs() throws IOException {
- Map<String, Ref> ret = repo.getRefDatabase().getRefs(ALL);
- for (Ref ref : repo.getRefDatabase().getAdditionalRefs())
- ret.put(ref.getName(), ref);
- return ret;
+ private Collection<Ref> getAllRefs() throws IOException {
+ Collection<Ref> refs = RefTreeNames.allRefs(repo.getRefDatabase());
+ List<Ref> addl = repo.getRefDatabase().getAdditionalRefs();
+ if (!addl.isEmpty()) {
+ List<Ref> all = new ArrayList<>(refs.size() + addl.size());
+ all.addAll(refs);
+ all.addAll(addl);
+ return all;
+ }
+ return refs;
}
/**
@@ -635,10 +658,7 @@
*/
private Set<ObjectId> listNonHEADIndexObjects()
throws CorruptObjectException, IOException {
- try {
- if (repo.getIndexFile() == null)
- return Collections.emptySet();
- } catch (NoWorkTreeException e) {
+ if (repo.isBare()) {
return Collections.emptySet();
}
try (TreeWalk treeWalk = new TreeWalk(repo)) {
@@ -679,8 +699,8 @@
}
}
- private PackFile writePack(Set<? extends ObjectId> want,
- Set<? extends ObjectId> have, Set<ObjectId> tagTargets,
+ private PackFile writePack(@NonNull Set<? extends ObjectId> want,
+ @NonNull Set<? extends ObjectId> have, Set<ObjectId> tagTargets,
List<ObjectIdSet> excludeObjects) throws IOException {
File tmpPack = null;
Map<PackExt, File> tmpExts = new TreeMap<PackExt, File>(
@@ -786,39 +806,33 @@
break;
}
tmpPack.setReadOnly();
- boolean delete = true;
- try {
- FileUtils.rename(tmpPack, realPack);
- delete = false;
- for (Map.Entry<PackExt, File> tmpEntry : tmpExts.entrySet()) {
- File tmpExt = tmpEntry.getValue();
- tmpExt.setReadOnly();
- File realExt = nameFor(
- id, "." + tmpEntry.getKey().getExtension()); //$NON-NLS-1$
+ FileUtils.rename(tmpPack, realPack, StandardCopyOption.ATOMIC_MOVE);
+ for (Map.Entry<PackExt, File> tmpEntry : tmpExts.entrySet()) {
+ File tmpExt = tmpEntry.getValue();
+ tmpExt.setReadOnly();
+
+ File realExt = nameFor(id,
+ "." + tmpEntry.getKey().getExtension()); //$NON-NLS-1$
+ try {
+ FileUtils.rename(tmpExt, realExt,
+ StandardCopyOption.ATOMIC_MOVE);
+ } catch (IOException e) {
+ File newExt = new File(realExt.getParentFile(),
+ realExt.getName() + ".new"); //$NON-NLS-1$
try {
- FileUtils.rename(tmpExt, realExt);
- } catch (IOException e) {
- File newExt = new File(realExt.getParentFile(),
- realExt.getName() + ".new"); //$NON-NLS-1$
- if (!tmpExt.renameTo(newExt))
- newExt = tmpExt;
- throw new IOException(MessageFormat.format(
- JGitText.get().panicCantRenameIndexFile, newExt,
- realExt));
+ FileUtils.rename(tmpExt, newExt,
+ StandardCopyOption.ATOMIC_MOVE);
+ } catch (IOException e2) {
+ newExt = tmpExt;
+ e = e2;
}
- }
-
- } finally {
- if (delete) {
- if (tmpPack.exists())
- tmpPack.delete();
- for (File tmpExt : tmpExts.values()) {
- if (tmpExt.exists())
- tmpExt.delete();
- }
+ throw new IOException(MessageFormat.format(
+ JGitText.get().panicCantRenameIndexFile, newExt,
+ realExt), e);
}
}
+
return repo.getObjectDatabase().openPack(realPack);
} finally {
if (tmpPack != null && tmpPack.exists())
@@ -877,6 +891,11 @@
*/
public long numberOfPackedRefs;
+ /**
+ * The number of bitmaps in the bitmap indices.
+ */
+ public long numberOfBitmaps;
+
public String toString() {
final StringBuilder b = new StringBuilder();
b.append("numberOfPackedObjects=").append(numberOfPackedObjects); //$NON-NLS-1$
@@ -886,15 +905,15 @@
b.append(", numberOfPackedRefs=").append(numberOfPackedRefs); //$NON-NLS-1$
b.append(", sizeOfLooseObjects=").append(sizeOfLooseObjects); //$NON-NLS-1$
b.append(", sizeOfPackedObjects=").append(sizeOfPackedObjects); //$NON-NLS-1$
+ b.append(", numberOfBitmaps=").append(numberOfBitmaps); //$NON-NLS-1$
return b.toString();
}
}
/**
- * Returns the number of objects stored in pack files. If an object is
- * contained in multiple pack files it is counted as often as it occurs.
+ * Returns information about objects and pack files for a FileRepository.
*
- * @return the number of objects stored in pack files
+ * @return information about objects and pack files for a FileRepository
* @throws IOException
*/
public RepoStatistics getStatistics() throws IOException {
@@ -904,6 +923,8 @@
ret.numberOfPackedObjects += f.getIndex().getObjectCount();
ret.numberOfPackFiles++;
ret.sizeOfPackedObjects += f.getPackFile().length();
+ if (f.getBitmapIndex() != null)
+ ret.numberOfBitmaps += f.getBitmapIndex().getBitmapCount();
}
File objDir = repo.getObjectsDirectory();
String[] fanout = objDir.list();
@@ -989,12 +1010,4 @@
this.expire = expire;
expireAgeMillis = -1;
}
-
- private static ObjectIdSet objectIdSet(final PackIndex idx) {
- return new ObjectIdSet() {
- public boolean contains(AnyObjectId objectId) {
- return idx.hasObject(objectId);
- }
- };
- }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GlobalAttributesNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GlobalAttributesNode.java
new file mode 100644
index 0000000..454d3bf
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GlobalAttributesNode.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014, Arthur Daussy <arthur.daussy@obeo.fr>
+ * Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.internal.storage.file;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.jgit.attributes.AttributesNode;
+import org.eclipse.jgit.lib.CoreConfig;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.FS;
+
+/** Attribute node loaded from global system-wide file. */
+public class GlobalAttributesNode extends AttributesNode {
+ final Repository repository;
+
+ /**
+ * @param repository
+ */
+ public GlobalAttributesNode(Repository repository) {
+ this.repository = repository;
+ }
+
+ /**
+ * @return the attributes node
+ * @throws IOException
+ */
+ public AttributesNode load() throws IOException {
+ AttributesNode r = new AttributesNode();
+
+ FS fs = repository.getFS();
+ String path = repository.getConfig().get(CoreConfig.KEY)
+ .getAttributesFile();
+ if (path != null) {
+ File attributesFile;
+ if (path.startsWith("~/")) { //$NON-NLS-1$
+ attributesFile = fs.resolve(fs.userHome(),
+ path.substring(2));
+ } else {
+ attributesFile = fs.resolve(null, path);
+ }
+ FileRepository.AttributesNodeProviderImpl.loadRulesFromFile(r, attributesFile);
+ }
+ return r.getRules().isEmpty() ? null : r;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
similarity index 60%
copy from org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
copy to org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
index c7e41bc..bda5cbe 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006-2007, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2014, Arthur Daussy <arthur.daussy@obeo.fr>
+ * Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -41,45 +41,41 @@
* 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.file;
-package org.eclipse.jgit.lib;
+import java.io.File;
+import java.io.IOException;
-/**
- * A tree entry representing a symbolic link.
- *
- * Note. Java cannot really handle these as file system objects.
- *
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
- */
-@Deprecated
-public class SymlinkTreeEntry extends TreeEntry {
+import org.eclipse.jgit.attributes.AttributesNode;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.FS;
+
+/** Attribute node loaded from the $GIT_DIR/info/attributes file. */
+public class InfoAttributesNode extends AttributesNode {
+ final Repository repository;
/**
- * Construct a {@link SymlinkTreeEntry} with the specified name and SHA-1 in
- * the specified parent
- *
- * @param parent
- * @param id
- * @param nameUTF8
+ * @param repository
*/
- public SymlinkTreeEntry(final Tree parent, final ObjectId id,
- final byte[] nameUTF8) {
- super(parent, id, nameUTF8);
+ public InfoAttributesNode(Repository repository) {
+ this.repository = repository;
}
- public FileMode getMode() {
- return FileMode.SYMLINK;
+ /**
+ * @return the attributes node
+ * @throws IOException
+ */
+ public AttributesNode load() throws IOException {
+ AttributesNode r = new AttributesNode();
+
+ FS fs = repository.getFS();
+
+ File attributes = fs.resolve(repository.getDirectory(),
+ Constants.INFO_ATTRIBUTES);
+ FileRepository.AttributesNodeProviderImpl.loadRulesFromFile(r, attributes);
+
+ return r.getRules().isEmpty() ? null : r;
}
- public String toString() {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(getId()));
- r.append(" S "); //$NON-NLS-1$
- r.append(getFullName());
- return r.toString();
- }
-}
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LazyObjectIdSetFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LazyObjectIdSetFile.java
new file mode 100644
index 0000000..1e2617c
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LazyObjectIdSetFile.java
@@ -0,0 +1,106 @@
+/*
+ * 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.internal.storage.file;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.MutableObjectId;
+import org.eclipse.jgit.lib.ObjectIdOwnerMap;
+import org.eclipse.jgit.lib.ObjectIdSet;
+
+/** Lazily loads a set of ObjectIds, one per line. */
+public class LazyObjectIdSetFile implements ObjectIdSet {
+ private final File src;
+ private ObjectIdOwnerMap<Entry> set;
+
+ /**
+ * Create a new lazy set from a file.
+ *
+ * @param src
+ * the source file.
+ */
+ public LazyObjectIdSetFile(File src) {
+ this.src = src;
+ }
+
+ @Override
+ public boolean contains(AnyObjectId objectId) {
+ if (set == null) {
+ set = load();
+ }
+ return set.contains(objectId);
+ }
+
+ private ObjectIdOwnerMap<Entry> load() {
+ ObjectIdOwnerMap<Entry> r = new ObjectIdOwnerMap<>();
+ try (FileInputStream fin = new FileInputStream(src);
+ Reader rin = new InputStreamReader(fin, UTF_8);
+ BufferedReader br = new BufferedReader(rin)) {
+ MutableObjectId id = new MutableObjectId();
+ for (String line; (line = br.readLine()) != null;) {
+ id.fromString(line);
+ if (!r.contains(id)) {
+ r.add(new Entry(id));
+ }
+ }
+ } catch (IOException e) {
+ // Ignore IO errors accessing the lazy set.
+ }
+ return r;
+ }
+
+ static class Entry extends ObjectIdOwnerMap.Entry {
+ Entry(AnyObjectId id) {
+ super(id);
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
index 06eb42c..ce9677a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
@@ -54,6 +54,7 @@
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
+import java.nio.file.StandardCopyOption;
import java.text.MessageFormat;
import org.eclipse.jgit.errors.LockFailedException;
@@ -120,16 +121,14 @@
private boolean haveLck;
- private FileOutputStream os;
+ FileOutputStream os;
private boolean needSnapshot;
- private boolean fsync;
+ boolean fsync;
private FileSnapshot commitSnapshot;
- private final FS fs;
-
/**
* Create a new lock for any file.
*
@@ -138,11 +137,24 @@
* @param fs
* the file system abstraction which will be necessary to perform
* certain file system operations.
+ * @deprecated use {@link LockFile#LockFile(File)} instead
*/
+ @Deprecated
public LockFile(final File f, final FS fs) {
ref = f;
lck = getLockFile(ref);
- this.fs = fs;
+ }
+
+ /**
+ * Create a new lock for any file.
+ *
+ * @param f
+ * the file that will be locked.
+ * @since 4.2
+ */
+ public LockFile(final File f) {
+ ref = f;
+ lck = getLockFile(ref);
}
/**
@@ -227,6 +239,10 @@
fis.close();
}
} catch (FileNotFoundException fnfe) {
+ if (ref.exists()) {
+ unlock();
+ throw fnfe;
+ }
// Don't worry about a file that doesn't exist yet, it
// conceptually has no current content to copy.
//
@@ -437,56 +453,14 @@
}
saveStatInformation();
- if (lck.renameTo(ref)) {
+ try {
+ FileUtils.rename(lck, ref, StandardCopyOption.ATOMIC_MOVE);
haveLck = false;
return true;
+ } catch (IOException e) {
+ unlock();
+ return false;
}
- if (!ref.exists() || deleteRef()) {
- if (renameLock()) {
- haveLck = false;
- return true;
- }
- }
- unlock();
- return false;
- }
-
- private boolean deleteRef() {
- if (!fs.retryFailedLockFileCommit())
- return ref.delete();
-
- // File deletion fails on windows if another thread is
- // concurrently reading the same file. So try a few times.
- //
- for (int attempts = 0; attempts < 10; attempts++) {
- if (ref.delete())
- return true;
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- return false;
- }
- }
- return false;
- }
-
- private boolean renameLock() {
- if (!fs.retryFailedLockFileCommit())
- return lck.renameTo(ref);
-
- // File renaming fails on windows if another thread is
- // concurrently reading the same file. So try a few times.
- //
- for (int attempts = 0; attempts < 10; attempts++) {
- if (lck.renameTo(ref))
- return true;
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- return false;
- }
- }
- return false;
}
private void saveStatInformation() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
index e7ef127..ea80528 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
@@ -52,6 +52,9 @@
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
+import java.nio.file.AtomicMoveNotSupportedException;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -433,16 +436,14 @@
ObjectLoader openLooseObject(WindowCursor curs, AnyObjectId id)
throws IOException {
- try {
- File path = fileFor(id);
- FileInputStream in = new FileInputStream(path);
- try {
- unpackedObjectCache.add(id);
- return UnpackedObject.open(in, path, id, curs);
- } finally {
- in.close();
- }
+ File path = fileFor(id);
+ try (FileInputStream in = new FileInputStream(path)) {
+ unpackedObjectCache.add(id);
+ return UnpackedObject.open(in, path, id, curs);
} catch (FileNotFoundException noFile) {
+ if (path.exists()) {
+ throw noFile;
+ }
unpackedObjectCache.remove(id);
return null;
}
@@ -513,15 +514,14 @@
private long getLooseObjectSize(WindowCursor curs, AnyObjectId id)
throws IOException {
- try {
- FileInputStream in = new FileInputStream(fileFor(id));
- try {
- unpackedObjectCache.add(id);
- return UnpackedObject.getSize(in, id, curs);
- } finally {
- in.close();
- }
+ File f = fileFor(id);
+ try (FileInputStream in = new FileInputStream(f)) {
+ unpackedObjectCache.add(id);
+ return UnpackedObject.getSize(in, id, curs);
} catch (FileNotFoundException noFile) {
+ if (f.exists()) {
+ throw noFile;
+ }
unpackedObjectCache.remove(id);
return -1;
}
@@ -561,7 +561,11 @@
// Assume the pack is corrupted, and remove it from the list.
removePack(p);
} else if (e instanceof FileNotFoundException) {
- warnTmpl = JGitText.get().packWasDeleted;
+ if (p.getPackFile().exists()) {
+ warnTmpl = JGitText.get().packInaccessible;
+ } else {
+ warnTmpl = JGitText.get().packWasDeleted;
+ }
removePack(p);
} else if (FileUtils.isStaleFileHandle(e)) {
warnTmpl = JGitText.get().packHandleIsStale;
@@ -607,10 +611,16 @@
FileUtils.delete(tmp, FileUtils.RETRY);
return InsertLooseObjectResult.EXISTS_LOOSE;
}
- if (tmp.renameTo(dst)) {
+ try {
+ Files.move(tmp.toPath(), dst.toPath(),
+ StandardCopyOption.ATOMIC_MOVE);
dst.setReadOnly();
unpackedObjectCache.add(id);
return InsertLooseObjectResult.INSERTED;
+ } catch (AtomicMoveNotSupportedException e) {
+ LOG.error(e.getMessage(), e);
+ } catch (IOException e) {
+ // ignore
}
// Maybe the directory doesn't exist yet as the object
@@ -618,10 +628,16 @@
// try the rename first as the directory likely does exist.
//
FileUtils.mkdir(dst.getParentFile(), true);
- if (tmp.renameTo(dst)) {
+ try {
+ Files.move(tmp.toPath(), dst.toPath(),
+ StandardCopyOption.ATOMIC_MOVE);
dst.setReadOnly();
unpackedObjectCache.add(id);
return InsertLooseObjectResult.INSERTED;
+ } catch (AtomicMoveNotSupportedException e) {
+ LOG.error(e.getMessage(), e);
+ } catch (IOException e) {
+ LOG.debug(e.getMessage(), e);
}
if (!createDuplicate && has(id)) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
index 1c076ee..2e6c245 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java
@@ -50,6 +50,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
+import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.text.MessageFormat;
import java.util.Arrays;
@@ -476,20 +477,25 @@
}
}
- if (!tmpPack.renameTo(finalPack)) {
+ try {
+ FileUtils.rename(tmpPack, finalPack,
+ StandardCopyOption.ATOMIC_MOVE);
+ } catch (IOException e) {
cleanupTemporaryFiles();
keep.unlock();
throw new IOException(MessageFormat.format(
- JGitText.get().cannotMovePackTo, finalPack));
+ JGitText.get().cannotMovePackTo, finalPack), e);
}
- if (!tmpIdx.renameTo(finalIdx)) {
+ try {
+ FileUtils.rename(tmpIdx, finalIdx, StandardCopyOption.ATOMIC_MOVE);
+ } catch (IOException e) {
cleanupTemporaryFiles();
keep.unlock();
if (!finalPack.delete())
finalPack.deleteOnExit();
throw new IOException(MessageFormat.format(
- JGitText.get().cannotMoveIndexTo, finalIdx));
+ JGitText.get().cannotMoveIndexTo, finalIdx), e);
}
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java
index ae4de84..e743cb4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java
@@ -193,4 +193,11 @@
* pack that this index was generated from.
*/
public abstract int getObjectCount();
+
+ /**
+ * Returns the number of bitmaps in this bitmap index.
+ *
+ * @return the number of bitmaps in this bitmap index.
+ */
+ public abstract int getBitmapCount();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java
index 93f8918..4ff09a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java
@@ -74,9 +74,9 @@
private final EWAHCompressedBitmap blobs;
private final EWAHCompressedBitmap tags;
private final BlockList<PositionEntry> byOffset;
- private final BlockList<StoredBitmap>
+ final BlockList<StoredBitmap>
byAddOrder = new BlockList<StoredBitmap>();
- private final ObjectIdOwnerMap<PositionEntry>
+ final ObjectIdOwnerMap<PositionEntry>
positionEntries = new ObjectIdOwnerMap<PositionEntry>();
/**
@@ -253,7 +253,7 @@
return PackBitmapIndexV1.OPT_FULL;
}
- /** @return the number of bitmaps. */
+ @Override
public int getBitmapCount() {
return getBitmaps().size();
}
@@ -330,7 +330,7 @@
private final int xorOffset;
private final int flags;
- private StoredEntry(long objectId, EWAHCompressedBitmap bitmap,
+ StoredEntry(long objectId, EWAHCompressedBitmap bitmap,
int xorOffset, int flags) {
this.objectId = objectId;
this.bitmap = bitmap;
@@ -360,11 +360,11 @@
}
private static final class PositionEntry extends ObjectIdOwnerMap.Entry {
- private final int namePosition;
+ final int namePosition;
- private int offsetPosition;
+ int offsetPosition;
- private PositionEntry(AnyObjectId objectId, int namePosition) {
+ PositionEntry(AnyObjectId objectId, int namePosition) {
super(objectId);
this.namePosition = namePosition;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
index 6b96b07..7cd68b6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
@@ -66,7 +66,7 @@
implements Iterable<PackBitmapIndexRemapper.Entry> {
private final BasePackBitmapIndex oldPackIndex;
- private final PackBitmapIndex newPackIndex;
+ final PackBitmapIndex newPackIndex;
private final ObjectIdOwnerMap<StoredBitmap> convertedBitmaps;
private final BitSet inflated;
private final int[] prevToNewMapping;
@@ -199,7 +199,7 @@
public final class Entry extends ObjectId {
private final int flags;
- private Entry(AnyObjectId src, int flags) {
+ Entry(AnyObjectId src, int flags) {
super(src);
this.flags = flags;
}
@@ -209,4 +209,10 @@
return flags;
}
}
+
+ @Override
+ public int getBitmapCount() {
+ // The count is only useful for the end index, not the remapper.
+ return 0;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
index a38a26d..a7ab00d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java
@@ -213,6 +213,11 @@
}
@Override
+ public int getBitmapCount() {
+ return bitmaps.size();
+ }
+
+ @Override
public boolean equals(Object o) {
// TODO(cranger): compare the pack checksum?
if (o instanceof PackBitmapIndexV1)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
index 589a811..b385b8a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
@@ -119,7 +119,7 @@
private int activeCopyRawData;
- private int packLastModified;
+ int packLastModified;
private volatile boolean invalid;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
index 0040aea..f36bd4d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java
@@ -60,6 +60,7 @@
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.MutableObjectId;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdSet;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.NB;
@@ -72,7 +73,8 @@
* by ObjectId.
* </p>
*/
-public abstract class PackIndex implements Iterable<PackIndex.MutableEntry> {
+public abstract class PackIndex
+ implements Iterable<PackIndex.MutableEntry>, ObjectIdSet {
/**
* Open an existing pack <code>.idx</code> file for reading.
* <p>
@@ -166,6 +168,11 @@
return findOffset(id) != -1;
}
+ @Override
+ public boolean contains(AnyObjectId id) {
+ return findOffset(id) != -1;
+ }
+
/**
* Provide iterator that gives access to index entries. Note, that iterator
* returns reference to mutable object, the same reference in each call -
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
index ab3297a..e5a729d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
@@ -67,7 +67,7 @@
private final long[] idxHeader;
- private byte[][] idxdata;
+ byte[][] idxdata;
private long objectCnt;
@@ -233,9 +233,9 @@
}
private class IndexV1Iterator extends EntriesIterator {
- private int levelOne;
+ int levelOne;
- private int levelTwo;
+ int levelTwo;
@Override
protected MutableEntry initEntry() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java
index cb8c91a..d87336f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java
@@ -75,16 +75,16 @@
private final long[] fanoutTable;
/** 256 arrays of contiguous object names. */
- private int[][] names;
+ int[][] names;
/** 256 arrays of the 32 bit offset data, matching {@link #names}. */
- private byte[][] offset32;
+ byte[][] offset32;
/** 256 arrays of the CRC-32 of objects, matching {@link #names}. */
private byte[][] crc32;
/** 64 bit offset table. */
- private byte[] offset64;
+ byte[] offset64;
PackIndexV2(final InputStream fd) throws IOException {
final byte[] fanoutRaw = new byte[4 * FANOUT];
@@ -304,9 +304,9 @@
}
private class EntriesIteratorV2 extends EntriesIterator {
- private int levelOne;
+ int levelOne;
- private int levelTwo;
+ int levelTwo;
@Override
protected MutableEntry initEntry() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java
index b671b03..a433dec 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackLock.java
@@ -53,7 +53,6 @@
/** Keeps track of a {@link PackFile}'s associated <code>.keep</code> file. */
public class PackLock {
private final File keepFile;
- private final FS fs;
/**
* Create a new lock for a pack file.
@@ -67,7 +66,6 @@
final File p = packFile.getParentFile();
final String n = packFile.getName();
keepFile = new File(p, n.substring(0, n.length() - 5) + ".keep"); //$NON-NLS-1$
- this.fs = fs;
}
/**
@@ -84,7 +82,7 @@
return false;
if (!msg.endsWith("\n")) //$NON-NLS-1$
msg += "\n"; //$NON-NLS-1$
- final LockFile lf = new LockFile(keepFile, fs);
+ final LockFile lf = new LockFile(keepFile);
if (!lf.lock())
return false;
lf.write(Constants.encode(msg));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
index bb5b044..b8c2fb4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
@@ -73,6 +73,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.errors.InvalidObjectIdException;
import org.eclipse.jgit.errors.LockFailedException;
import org.eclipse.jgit.errors.MissingObjectException;
@@ -138,7 +139,7 @@
private final File gitDir;
- private final File refsDir;
+ final File refsDir;
private final ReflogWriter logWriter;
@@ -155,7 +156,7 @@
private final AtomicReference<RefList<LooseRef>> looseRefs = new AtomicReference<RefList<LooseRef>>();
/** Immutable sorted list of packed references. */
- private final AtomicReference<PackedRefList> packedRefs = new AtomicReference<PackedRefList>();
+ final AtomicReference<PackedRefList> packedRefs = new AtomicReference<PackedRefList>();
/**
* Number of modifications made to this database.
@@ -294,6 +295,8 @@
ref = readRef(prefix + needle, packed);
if (ref != null) {
ref = resolve(ref, 0, null, null, packed);
+ }
+ if (ref != null) {
break;
}
} catch (IOException e) {
@@ -585,8 +588,7 @@
// we don't miss an edit made externally.
final PackedRefList packed = getPackedRefs();
if (packed.contains(name)) {
- LockFile lck = new LockFile(packedRefsFile,
- update.getRepository().getFS());
+ LockFile lck = new LockFile(packedRefsFile);
if (!lck.lock())
throw new LockFailedException(packedRefsFile);
try {
@@ -636,7 +638,7 @@
FS fs = parent.getFS();
// Lock the packed refs file and read the content
- LockFile lck = new LockFile(packedRefsFile, fs);
+ LockFile lck = new LockFile(packedRefsFile);
if (!lck.lock())
throw new IOException(MessageFormat.format(
JGitText.get().cannotLock, packedRefsFile));
@@ -667,8 +669,7 @@
File refFile = fileFor(refName);
if (!fs.exists(refFile))
continue;
- LockFile rLck = new LockFile(refFile,
- parent.getFS());
+ LockFile rLck = new LockFile(refFile);
if (!rLck.lock())
continue;
try {
@@ -713,16 +714,20 @@
*/
private Ref peeledPackedRef(Ref f)
throws MissingObjectException, IOException {
- if (f.getStorage().isPacked() && f.isPeeled())
+ if (f.getStorage().isPacked() && f.isPeeled()) {
return f;
- if (!f.isPeeled())
+ }
+ if (!f.isPeeled()) {
f = peel(f);
- if (f.getPeeledObjectId() != null)
+ }
+ ObjectId peeledObjectId = f.getPeeledObjectId();
+ if (peeledObjectId != null) {
return new ObjectIdRef.PeeledTag(PACKED, f.getName(),
- f.getObjectId(), f.getPeeledObjectId());
- else
+ f.getObjectId(), peeledObjectId);
+ } else {
return new ObjectIdRef.PeeledNonTag(PACKED, f.getName(),
f.getObjectId());
+ }
}
void log(final RefUpdate update, final String msg, final boolean deref)
@@ -786,6 +791,9 @@
new DigestInputStream(new FileInputStream(packedRefsFile),
digest), CHARSET));
} catch (FileNotFoundException noPackedRefs) {
+ if (packedRefsFile.exists()) {
+ throw noPackedRefs;
+ }
// Ignore it and leave the new list empty.
return PackedRefList.NO_PACKED_REFS;
}
@@ -925,7 +933,7 @@
return n;
}
- private LooseRef scanRef(LooseRef ref, String name) throws IOException {
+ LooseRef scanRef(LooseRef ref, String name) throws IOException {
final File path = fileFor(name);
FileSnapshot currentSnapshot = null;
@@ -942,7 +950,10 @@
try {
buf = IO.readSome(path, limit);
} catch (FileNotFoundException noFile) {
- return null; // doesn't exist; not a reference.
+ if (path.exists() && path.isFile()) {
+ throw noFile;
+ }
+ return null; // doesn't exist or no file; not a reference.
}
int n = buf.length;
@@ -977,7 +988,7 @@
try {
id = ObjectId.fromString(buf, 0);
if (ref != null && !ref.isSymbolic()
- && ref.getTarget().getObjectId().equals(id)) {
+ && id.equals(ref.getTarget().getObjectId())) {
assert(currentSnapshot != null);
currentSnapshot.setClean(otherSnapshot);
return ref;
@@ -1095,8 +1106,8 @@
implements LooseRef {
private final FileSnapshot snapShot;
- LoosePeeledTag(FileSnapshot snapshot, String refName, ObjectId id,
- ObjectId p) {
+ LoosePeeledTag(FileSnapshot snapshot, @NonNull String refName,
+ @NonNull ObjectId id, @NonNull ObjectId p) {
super(LOOSE, refName, id, p);
this.snapShot = snapshot;
}
@@ -1114,7 +1125,8 @@
implements LooseRef {
private final FileSnapshot snapShot;
- LooseNonTag(FileSnapshot snapshot, String refName, ObjectId id) {
+ LooseNonTag(FileSnapshot snapshot, @NonNull String refName,
+ @NonNull ObjectId id) {
super(LOOSE, refName, id);
this.snapShot = snapshot;
}
@@ -1132,7 +1144,8 @@
implements LooseRef {
private FileSnapshot snapShot;
- LooseUnpeeled(FileSnapshot snapShot, String refName, ObjectId id) {
+ LooseUnpeeled(FileSnapshot snapShot, @NonNull String refName,
+ @NonNull ObjectId id) {
super(LOOSE, refName, id);
this.snapShot = snapShot;
}
@@ -1141,13 +1154,24 @@
return snapShot;
}
+ @NonNull
+ @Override
+ public ObjectId getObjectId() {
+ ObjectId id = super.getObjectId();
+ assert id != null; // checked in constructor
+ return id;
+ }
+
public LooseRef peel(ObjectIdRef newLeaf) {
- if (newLeaf.getPeeledObjectId() != null)
+ ObjectId peeledObjectId = newLeaf.getPeeledObjectId();
+ ObjectId objectId = getObjectId();
+ if (peeledObjectId != null) {
return new LoosePeeledTag(snapShot, getName(),
- getObjectId(), newLeaf.getPeeledObjectId());
- else
+ objectId, peeledObjectId);
+ } else {
return new LooseNonTag(snapShot, getName(),
- getObjectId());
+ objectId);
+ }
}
}
@@ -1155,7 +1179,8 @@
LooseRef {
private final FileSnapshot snapShot;
- LooseSymbolicRef(FileSnapshot snapshot, String refName, Ref target) {
+ LooseSymbolicRef(FileSnapshot snapshot, @NonNull String refName,
+ @NonNull Ref target) {
super(refName, target);
this.snapShot = snapshot;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java
index ba4a63d..4b803a5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java
@@ -46,6 +46,8 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.AtomicMoveNotSupportedException;
+import java.nio.file.StandardCopyOption;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -54,6 +56,8 @@
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.util.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Rename any reference stored by {@link RefDirectory}.
@@ -66,6 +70,9 @@
* directory that happens to match the source name.
*/
class RefDirectoryRename extends RefRename {
+ private static final Logger LOG = LoggerFactory
+ .getLogger(RefDirectoryRename.class);
+
private final RefDirectory refdb;
/**
@@ -201,13 +208,25 @@
}
private static boolean rename(File src, File dst) {
- if (src.renameTo(dst))
+ try {
+ FileUtils.rename(src, dst, StandardCopyOption.ATOMIC_MOVE);
return true;
+ } catch (AtomicMoveNotSupportedException e) {
+ LOG.error(e.getMessage(), e);
+ } catch (IOException e) {
+ // ignore
+ }
File dir = dst.getParentFile();
if ((dir.exists() || !dir.mkdirs()) && !dir.isDirectory())
return false;
- return src.renameTo(dst);
+ try {
+ FileUtils.rename(src, dst, StandardCopyOption.ATOMIC_MOVE);
+ return true;
+ } catch (IOException e) {
+ LOG.error(e.getMessage(), e);
+ return false;
+ }
}
private boolean linkHEAD(RefUpdate target) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
index 7858ee1..0d16f79 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
@@ -79,7 +79,7 @@
if (deref)
dst = dst.getLeaf();
String name = dst.getName();
- lock = new LockFile(database.fileFor(name), getRepository().getFS());
+ lock = new LockFile(database.fileFor(name));
if (lock.lock()) {
dst = database.getRef(name);
setOldObjectId(dst != null ? dst.getObjectId() : null);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
index dadc631..2f583b2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
@@ -96,6 +96,9 @@
try {
log = IO.readFully(logName);
} catch (FileNotFoundException e) {
+ if (logName.exists()) {
+ throw e;
+ }
return null;
}
@@ -118,6 +121,9 @@
try {
log = IO.readFully(logName);
} catch (FileNotFoundException e) {
+ if (logName.exists()) {
+ throw e;
+ }
return Collections.emptyList();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java
index e4cc697..a027437 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java
@@ -232,7 +232,7 @@
}
}
- private static void checkValidEndOfStream(InputStream in, Inflater inf,
+ static void checkValidEndOfStream(InputStream in, Inflater inf,
AnyObjectId id, final byte[] buf) throws IOException,
CorruptObjectException {
for (;;) {
@@ -266,7 +266,7 @@
}
}
- private static boolean isStandardFormat(final byte[] hdr) {
+ static boolean isStandardFormat(final byte[] hdr) {
/*
* We must determine if the buffer contains the standard
* zlib-deflated stream or the experimental format based
@@ -298,7 +298,7 @@
return (fb & 0x8f) == 0x08 && (((fb << 8) | hdr[1] & 0xff) % 31) == 0;
}
- private static InputStream inflate(final InputStream in, final long size,
+ static InputStream inflate(final InputStream in, final long size,
final ObjectId id) {
final Inflater inf = InflaterCache.get();
return new InflaterInputStream(in, inf) {
@@ -334,11 +334,11 @@
return new InflaterInputStream(in, inf, BUFFER_SIZE);
}
- private static BufferedInputStream buffer(InputStream in) {
+ static BufferedInputStream buffer(InputStream in) {
return new BufferedInputStream(in, BUFFER_SIZE);
}
- private static int readSome(InputStream in, final byte[] hdr, int off,
+ static int readSome(InputStream in, final byte[] hdr, int off,
int cnt) throws IOException {
int avail = 0;
while (0 < cnt) {
@@ -363,7 +363,7 @@
private final FileObjectDatabase source;
- private LargeObject(int type, long size, File path, AnyObjectId id,
+ LargeObject(int type, long size, File path, AnyObjectId id,
FileObjectDatabase db) {
this.type = type;
this.size = size;
@@ -399,6 +399,9 @@
try {
in = buffer(new FileInputStream(path));
} catch (FileNotFoundException gone) {
+ if (path.exists()) {
+ throw gone;
+ }
// If the loose file no longer exists, it may have been
// moved into a pack file in the mean time. Try again
// to locate the object.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java
index 8ea0c23..4292742 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java
@@ -73,7 +73,7 @@
final int endIndex;
private long totalWeight;
- private long bytesPerUnit;
+ long bytesPerUnit;
Block(int threads, PackConfig config, ObjectReader reader,
DeltaCache dc, ThreadSafeProgressMonitor pm,
@@ -110,10 +110,12 @@
maxWork = s.size();
}
}
- if (maxTask == null)
+ if (maxTask == null) {
return null;
- if (maxTask.tryStealWork(maxSlice))
+ }
+ if (maxTask.tryStealWork(maxSlice)) {
return forThread.initWindow(maxSlice);
+ }
}
}
@@ -138,26 +140,30 @@
for (; w < weightPerThread && i < endIndex;) {
if (nextTop < topPaths.size()
&& i == topPaths.get(nextTop).slice.beginIndex) {
- if (s < i)
+ if (s < i) {
task.add(new Slice(s, i));
+ }
s = i = topPaths.get(nextTop++).slice.endIndex;
- } else
- w += list[i++].getWeight();
+ } else {
+ w += getAdjustedWeight(list[i++]);
+ }
}
// Round up the slice to the end of a path.
if (s < i) {
int h = list[i - 1].getPathHash();
while (i < endIndex) {
- if (h == list[i].getPathHash())
+ if (h == list[i].getPathHash()) {
i++;
- else
+ } else {
break;
+ }
}
task.add(new Slice(s, i));
}
- if (!task.slices.isEmpty())
+ if (!task.slices.isEmpty()) {
tasks.add(task);
+ }
}
while (topPathItr.hasNext()) {
WeightedPath p = topPathItr.next();
@@ -174,8 +180,8 @@
threads);
int cp = beginIndex;
int ch = list[cp].getPathHash();
- long cw = list[cp].getWeight();
- totalWeight = list[cp].getWeight();
+ long cw = getAdjustedWeight(list[cp]);
+ totalWeight = cw;
for (int i = cp + 1; i < endIndex; i++) {
ObjectToPack o = list[i];
@@ -184,24 +190,25 @@
if (topPaths.size() < threads) {
Slice s = new Slice(cp, i);
topPaths.add(new WeightedPath(cw, s));
- if (topPaths.size() == threads)
+ if (topPaths.size() == threads) {
Collections.sort(topPaths);
+ }
} else if (topPaths.get(0).weight < cw) {
Slice s = new Slice(cp, i);
WeightedPath p = new WeightedPath(cw, s);
topPaths.set(0, p);
- if (p.compareTo(topPaths.get(1)) > 0)
+ if (p.compareTo(topPaths.get(1)) > 0) {
Collections.sort(topPaths);
+ }
}
}
cp = i;
ch = o.getPathHash();
cw = 0;
}
- if (o.isEdge() || o.doNotAttemptDelta())
- continue;
- cw += o.getWeight();
- totalWeight += o.getWeight();
+ int weight = getAdjustedWeight(o);
+ cw += weight;
+ totalWeight += weight;
}
// Sort by starting index to identify gaps later.
@@ -212,12 +219,22 @@
});
bytesPerUnit = 1;
- while (MAX_METER <= (totalWeight / bytesPerUnit))
+ while (MAX_METER <= (totalWeight / bytesPerUnit)) {
bytesPerUnit <<= 10;
+ }
return topPaths;
}
}
+ static int getAdjustedWeight(ObjectToPack o) {
+ // Edge objects and those with reused deltas do not need to be
+ // compressed. For compression calculations, ignore their weights.
+ if (o.isEdge() || o.doNotAttemptDelta()) {
+ return 0;
+ }
+ return o.getWeight();
+ }
+
static final class WeightedPath implements Comparable<WeightedPath> {
final long weight;
final Slice slice;
@@ -229,8 +246,9 @@
public int compareTo(WeightedPath o) {
int cmp = Long.signum(weight - o.weight);
- if (cmp != 0)
+ if (cmp != 0) {
return cmp;
+ }
return slice.beginIndex - o.slice.beginIndex;
}
}
@@ -250,7 +268,7 @@
}
private final Block block;
- private final LinkedList<Slice> slices;
+ final LinkedList<Slice> slices;
private ObjectReader or;
private DeltaWindow dw;
@@ -278,14 +296,16 @@
DeltaWindow w;
for (;;) {
synchronized (this) {
- if (slices.isEmpty())
+ if (slices.isEmpty()) {
break;
+ }
w = initWindow(slices.removeFirst());
}
runWindow(w);
}
- while ((w = block.stealWork(this)) != null)
+ while ((w = block.stealWork(this)) != null) {
runWindow(w);
+ }
} finally {
block.pm.endWorker();
or.close();
@@ -315,8 +335,9 @@
}
synchronized Slice remaining() {
- if (!slices.isEmpty())
+ if (!slices.isEmpty()) {
return slices.getLast();
+ }
DeltaWindow d = dw;
return d != null ? d.remaining() : null;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
index 683d1cd..525f9ae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
@@ -80,6 +80,7 @@
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
+import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.LargeObjectException;
@@ -99,6 +100,7 @@
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdOwnerMap;
+import org.eclipse.jgit.lib.ObjectIdSet;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.ProgressMonitor;
@@ -161,17 +163,8 @@
public class PackWriter implements AutoCloseable {
private static final int PACK_VERSION_GENERATED = 2;
- /** A collection of object ids. */
- public interface ObjectIdSet {
- /**
- * Returns true if the objectId is contained within the collection.
- *
- * @param objectId
- * the objectId to find
- * @return whether the collection contains the objectId.
- */
- boolean contains(AnyObjectId objectId);
- }
+ /** Empty set of objects for {@code preparePack()}. */
+ public static Set<ObjectId> NONE = Collections.emptySet();
private static final Map<WeakReference<PackWriter>, Boolean> instances =
new ConcurrentHashMap<WeakReference<PackWriter>, Boolean>();
@@ -218,7 +211,7 @@
}
@SuppressWarnings("unchecked")
- private BlockList<ObjectToPack> objectsLists[] = new BlockList[OBJ_TAG + 1];
+ BlockList<ObjectToPack> objectsLists[] = new BlockList[OBJ_TAG + 1];
{
objectsLists[OBJ_COMMIT] = new BlockList<ObjectToPack>();
objectsLists[OBJ_TREE] = new BlockList<ObjectToPack>();
@@ -249,7 +242,7 @@
/** {@link #reader} recast to the reuse interface, if it supports it. */
private final ObjectReuseAsIs reuseSupport;
- private final PackConfig config;
+ final PackConfig config;
private final PackStatistics.Accumulator stats;
@@ -681,7 +674,7 @@
* @throws IOException
* when some I/O problem occur during reading objects.
*/
- public void preparePack(final Iterator<RevObject> objectsSource)
+ public void preparePack(@NonNull Iterator<RevObject> objectsSource)
throws IOException {
while (objectsSource.hasNext()) {
addObject(objectsSource.next());
@@ -704,16 +697,18 @@
* progress during object enumeration.
* @param want
* collection of objects to be marked as interesting (start
- * points of graph traversal).
+ * points of graph traversal). Must not be {@code null}.
* @param have
* collection of objects to be marked as uninteresting (end
- * points of graph traversal).
+ * points of graph traversal). Pass {@link #NONE} if all objects
+ * reachable from {@code want} are desired, such as when serving
+ * a clone.
* @throws IOException
* when some I/O problem occur during reading objects.
*/
public void preparePack(ProgressMonitor countingMonitor,
- Set<? extends ObjectId> want,
- Set<? extends ObjectId> have) throws IOException {
+ @NonNull Set<? extends ObjectId> want,
+ @NonNull Set<? extends ObjectId> have) throws IOException {
ObjectWalk ow;
if (shallowPack)
ow = new DepthWalk.ObjectWalk(reader, depth);
@@ -740,17 +735,19 @@
* ObjectWalk to perform enumeration.
* @param interestingObjects
* collection of objects to be marked as interesting (start
- * points of graph traversal).
+ * points of graph traversal). Must not be {@code null}.
* @param uninterestingObjects
* collection of objects to be marked as uninteresting (end
- * points of graph traversal).
+ * points of graph traversal). Pass {@link #NONE} if all objects
+ * reachable from {@code want} are desired, such as when serving
+ * a clone.
* @throws IOException
* when some I/O problem occur during reading objects.
*/
public void preparePack(ProgressMonitor countingMonitor,
- ObjectWalk walk,
- final Set<? extends ObjectId> interestingObjects,
- final Set<? extends ObjectId> uninterestingObjects)
+ @NonNull ObjectWalk walk,
+ @NonNull Set<? extends ObjectId> interestingObjects,
+ @NonNull Set<? extends ObjectId> uninterestingObjects)
throws IOException {
if (countingMonitor == null)
countingMonitor = NullProgressMonitor.INSTANCE;
@@ -1306,8 +1303,7 @@
long totalWeight = 0;
for (int i = 0; i < cnt; i++) {
ObjectToPack o = list[i];
- if (!o.isEdge() && !o.doNotAttemptDelta())
- totalWeight += o.getWeight();
+ totalWeight += DeltaTask.getAdjustedWeight(o);
}
long bytesPerUnit = 1;
@@ -1552,6 +1548,8 @@
if (zbuf != null) {
out.writeHeader(otp, otp.getCachedSize());
out.write(zbuf);
+ typeStats.cntDeltas++;
+ typeStats.deltaBytes += out.length() - otp.getOffset();
return;
}
}
@@ -1607,17 +1605,12 @@
out.write(packcsum);
}
- private void findObjectsToPack(final ProgressMonitor countingMonitor,
- final ObjectWalk walker, final Set<? extends ObjectId> want,
- Set<? extends ObjectId> have)
- throws MissingObjectException, IOException,
- IncorrectObjectTypeException {
+ private void findObjectsToPack(@NonNull ProgressMonitor countingMonitor,
+ @NonNull ObjectWalk walker, @NonNull Set<? extends ObjectId> want,
+ @NonNull Set<? extends ObjectId> have) throws IOException {
final long countingStart = System.currentTimeMillis();
beginPhase(PackingPhase.COUNTING, countingMonitor, ProgressMonitor.UNKNOWN);
- if (have == null)
- have = Collections.emptySet();
-
stats.interestingObjects = Collections.unmodifiableSet(new HashSet<ObjectId>(want));
stats.uninterestingObjects = Collections.unmodifiableSet(new HashSet<ObjectId>(have));
@@ -2015,10 +2008,10 @@
byName = null;
PackWriterBitmapPreparer bitmapPreparer = new PackWriterBitmapPreparer(
- reader, writeBitmaps, pm, stats.interestingObjects);
+ reader, writeBitmaps, pm, stats.interestingObjects, config);
Collection<PackWriterBitmapPreparer.BitmapCommit> selectedCommits =
- bitmapPreparer.doCommitSelection(numCommits);
+ bitmapPreparer.selectCommits(numCommits);
beginPhase(PackingPhase.BUILDING_BITMAPS, pm, selectedCommits.size());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
index 756d4b0..77311ab 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.internal.storage.pack;
import static org.eclipse.jgit.internal.storage.file.PackBitmapIndex.FLAG_REUSE;
+import static org.eclipse.jgit.revwalk.RevFlag.SEEN;
import java.io.IOException;
import java.util.ArrayList;
@@ -55,34 +56,44 @@
import java.util.List;
import java.util.Set;
-import com.googlecode.javaewah.EWAHCompressedBitmap;
-
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl;
+import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl.CompressedBitmap;
import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder;
import org.eclipse.jgit.internal.storage.file.PackBitmapIndexRemapper;
+import org.eclipse.jgit.internal.storage.pack.PackWriterBitmapWalker.AddUnseenToBitmapFilter;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.ProgressMonitor;
-import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.revwalk.filter.RevFilter;
+import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.util.BlockList;
+import org.eclipse.jgit.util.SystemReader;
-/** Helper class for the PackWriter to select commits for pack index bitmaps. */
+import com.googlecode.javaewah.EWAHCompressedBitmap;
+
+/**
+ * Helper class for the {@link PackWriter} to select commits for which to build
+ * pack index bitmaps.
+ */
class PackWriterBitmapPreparer {
- private static final Comparator<BitmapBuilder> BUILDER_BY_CARDINALITY_DSC =
- new Comparator<BitmapBuilder>() {
- public int compare(BitmapBuilder a, BitmapBuilder b) {
- return Integer.signum(b.cardinality() - a.cardinality());
+ private static final int DAY_IN_SECONDS = 24 * 60 * 60;
+
+ private static final Comparator<BitmapBuilderEntry> ORDER_BY_CARDINALITY = new Comparator<BitmapBuilderEntry>() {
+ public int compare(BitmapBuilderEntry a, BitmapBuilderEntry b) {
+ return Integer.signum(a.getBuilder().cardinality()
+ - b.getBuilder().cardinality());
}
};
@@ -93,12 +104,18 @@
private final BitmapIndexImpl commitBitmapIndex;
private final PackBitmapIndexRemapper bitmapRemapper;
private final BitmapIndexImpl bitmapIndex;
- private final int minCommits = 100;
- private final int maxCommits = 5000;
+
+ private final int contiguousCommitCount;
+ private final int recentCommitCount;
+ private final int recentCommitSpan;
+ private final int distantCommitSpan;
+ private final int excessiveBranchCount;
+ private final long inactiveBranchTimestamp;
PackWriterBitmapPreparer(ObjectReader reader,
PackBitmapIndexBuilder writeBitmaps, ProgressMonitor pm,
- Set<? extends ObjectId> want) throws IOException {
+ Set<? extends ObjectId> want, PackConfig config)
+ throws IOException {
this.reader = reader;
this.writeBitmaps = writeBitmaps;
this.pm = pm;
@@ -107,208 +124,379 @@
this.bitmapRemapper = PackBitmapIndexRemapper.newPackBitmapIndex(
reader.getBitmapIndex(), writeBitmaps);
this.bitmapIndex = new BitmapIndexImpl(bitmapRemapper);
+ this.contiguousCommitCount = config.getBitmapContiguousCommitCount();
+ this.recentCommitCount = config.getBitmapRecentCommitCount();
+ this.recentCommitSpan = config.getBitmapRecentCommitSpan();
+ this.distantCommitSpan = config.getBitmapDistantCommitSpan();
+ this.excessiveBranchCount = config.getBitmapExcessiveBranchCount();
+ long now = SystemReader.getInstance().getCurrentTime();
+ long ageInSeconds = config.getBitmapInactiveBranchAgeInDays()
+ * DAY_IN_SECONDS;
+ this.inactiveBranchTimestamp = (now / 1000) - ageInSeconds;
}
- Collection<BitmapCommit> doCommitSelection(int expectedNumCommits)
- throws MissingObjectException, IncorrectObjectTypeException,
- IOException {
+ /**
+ * Returns the commit objects for which bitmap indices should be built.
+ *
+ * @param expectedCommitCount
+ * count of commits in the pack
+ * @return commit objects for which bitmap indices should be built
+ * @throws IncorrectObjectTypeException
+ * if any of the processed objects is not a commit
+ * @throws IOException
+ * on errors reading pack or index files
+ * @throws MissingObjectException
+ * if an expected object is missing
+ */
+ Collection<BitmapCommit> selectCommits(int expectedCommitCount)
+ throws IncorrectObjectTypeException, IOException,
+ MissingObjectException {
+ /*
+ * Thinking of bitmap indices as a cache, if we find bitmaps at or at a
+ * close ancestor to 'old' and 'new' when calculating old..new, then all
+ * objects can be calculated with minimal graph walking. A distribution
+ * that favors creating bitmaps for the most recent commits maximizes
+ * the cache hits for clients that are close to HEAD, which is the
+ * majority of calculations performed.
+ */
pm.beginTask(JGitText.get().selectingCommits, ProgressMonitor.UNKNOWN);
RevWalk rw = new RevWalk(reader);
rw.setRetainBody(false);
- WalkResult result = findPaths(rw, expectedNumCommits);
+ CommitSelectionHelper selectionHelper = setupTipCommitBitmaps(rw,
+ expectedCommitCount);
pm.endTask();
- int totCommits = result.commitsByOldest.length - result.commitStartPos;
+ int totCommits = selectionHelper.getCommitCount();
BlockList<BitmapCommit> selections = new BlockList<BitmapCommit>(
- totCommits / minCommits + 1);
- for (BitmapCommit reuse : result.reuse)
+ totCommits / recentCommitSpan + 1);
+ for (BitmapCommit reuse : selectionHelper.reusedCommits) {
selections.add(reuse);
+ }
if (totCommits == 0) {
- for (AnyObjectId id : result.peeledWant)
+ for (AnyObjectId id : selectionHelper.peeledWants) {
selections.add(new BitmapCommit(id, false, 0));
+ }
return selections;
}
pm.beginTask(JGitText.get().selectingCommits, totCommits);
+ int totalWants = selectionHelper.peeledWants.size();
- for (BitmapBuilder bitmapableCommits : result.paths) {
- int cardinality = bitmapableCommits.cardinality();
+ for (BitmapBuilderEntry entry : selectionHelper.tipCommitBitmaps) {
+ BitmapBuilder bitmap = entry.getBuilder();
+ int cardinality = bitmap.cardinality();
- List<List<BitmapCommit>> running = new ArrayList<
- List<BitmapCommit>>();
+ // Within this branch, keep ordered lists of commits representing
+ // chains in its history, where each chain is a "sub-branch".
+ // Ordering commits by these chains makes for fewer differences
+ // between consecutive selected commits, which in turn provides
+ // better compression/on the run-length encoding of the XORs between
+ // them.
+ List<List<BitmapCommit>> chains =
+ new ArrayList<List<BitmapCommit>>();
+
+ // Mark the current branch as inactive if its tip commit isn't
+ // recent and there are an excessive number of branches, to
+ // prevent memory bloat of computing too many bitmaps for stale
+ // branches.
+ boolean isActiveBranch = true;
+ if (totalWants > excessiveBranchCount
+ && !isRecentCommit(entry.getCommit())) {
+ isActiveBranch = false;
+ }
// Insert bitmaps at the offsets suggested by the
- // nextSelectionDistance() heuristic.
+ // nextSelectionDistance() heuristic. Only reuse bitmaps created
+ // for more distant commits.
int index = -1;
- int nextIn = nextSelectionDistance(0, cardinality);
- int nextFlg = nextIn == maxCommits ? PackBitmapIndex.FLAG_REUSE : 0;
- boolean mustPick = nextIn == 0;
- for (RevCommit c : result) {
- if (!bitmapableCommits.contains(c))
+ int nextIn = nextSpan(cardinality);
+ int nextFlg = nextIn == distantCommitSpan
+ ? PackBitmapIndex.FLAG_REUSE : 0;
+
+ // For the current branch, iterate through all commits from oldest
+ // to newest.
+ for (RevCommit c : selectionHelper) {
+ // Optimization: if we have found all the commits for this
+ // branch, stop searching
+ int distanceFromTip = cardinality - index - 1;
+ if (distanceFromTip == 0) {
+ break;
+ }
+
+ // Ignore commits that are not in this branch
+ if (!bitmap.contains(c)) {
continue;
+ }
index++;
nextIn--;
pm.update(1);
- // Always pick the items in want and prefer merge commits.
- if (result.peeledWant.remove(c)) {
- if (nextIn > 0)
+ // Always pick the items in wants, prefer merge commits.
+ if (selectionHelper.peeledWants.remove(c)) {
+ if (nextIn > 0) {
nextFlg = 0;
- } else if (!mustPick && ((nextIn > 0)
- || (c.getParentCount() <= 1 && nextIn > -minCommits))) {
- continue;
+ }
+ } else {
+ boolean stillInSpan = nextIn >= 0;
+ boolean isMergeCommit = c.getParentCount() > 1;
+ // Force selection if:
+ // a) we have exhausted the window looking for merges
+ // b) we are in the top commits of an active branch
+ // c) we are at a branch tip
+ boolean mustPick = (nextIn <= -recentCommitSpan)
+ || (isActiveBranch
+ && (distanceFromTip <= contiguousCommitCount))
+ || (distanceFromTip == 1); // most recent commit
+ if (!mustPick && (stillInSpan || !isMergeCommit)) {
+ continue;
+ }
}
+ // This commit is selected.
+ // Calculate where to look for the next one.
int flags = nextFlg;
- nextIn = nextSelectionDistance(index, cardinality);
- nextFlg = nextIn == maxCommits ? PackBitmapIndex.FLAG_REUSE : 0;
- mustPick = nextIn == 0;
+ nextIn = nextSpan(distanceFromTip);
+ nextFlg = nextIn == distantCommitSpan
+ ? PackBitmapIndex.FLAG_REUSE : 0;
BitmapBuilder fullBitmap = commitBitmapIndex.newBitmapBuilder();
rw.reset();
rw.markStart(c);
- for (AnyObjectId objectId : result.reuse)
- rw.markUninteresting(rw.parseCommit(objectId));
- rw.setRevFilter(
- PackWriterBitmapWalker.newRevFilter(null, fullBitmap));
+ rw.setRevFilter(new AddUnseenToBitmapFilter(
+ selectionHelper.reusedCommitsBitmap, fullBitmap));
while (rw.next() != null) {
- // Work is done in the RevFilter.
+ // The RevFilter adds the reachable commits from this
+ // selected commit to fullBitmap.
}
- List<List<BitmapCommit>> matches = new ArrayList<
- List<BitmapCommit>>();
- for (List<BitmapCommit> list : running) {
- BitmapCommit last = list.get(list.size() - 1);
- if (fullBitmap.contains(last))
- matches.add(list);
- }
-
- List<BitmapCommit> match;
- if (matches.isEmpty()) {
- match = new ArrayList<BitmapCommit>();
- running.add(match);
- } else {
- match = matches.get(0);
- // Append to longest
- for (List<BitmapCommit> list : matches) {
- if (list.size() > match.size())
- match = list;
+ // Sort the commits by independent chains in this branch's
+ // history, yielding better compression when building bitmaps.
+ List<BitmapCommit> longestAncestorChain = null;
+ for (List<BitmapCommit> chain : chains) {
+ BitmapCommit mostRecentCommit = chain.get(chain.size() - 1);
+ if (fullBitmap.contains(mostRecentCommit)) {
+ if (longestAncestorChain == null
+ || longestAncestorChain.size() < chain.size()) {
+ longestAncestorChain = chain;
+ }
}
}
- match.add(new BitmapCommit(c, !match.isEmpty(), flags));
+
+ if (longestAncestorChain == null) {
+ longestAncestorChain = new ArrayList<BitmapCommit>();
+ chains.add(longestAncestorChain);
+ }
+ longestAncestorChain.add(new BitmapCommit(
+ c, !longestAncestorChain.isEmpty(), flags));
writeBitmaps.addBitmap(c, fullBitmap, 0);
}
- for (List<BitmapCommit> list : running)
- selections.addAll(list);
+ for (List<BitmapCommit> chain : chains) {
+ selections.addAll(chain);
+ }
}
writeBitmaps.clearBitmaps(); // Remove the temporary commit bitmaps.
// Add the remaining peeledWant
- for (AnyObjectId remainingWant : result.peeledWant)
+ for (AnyObjectId remainingWant : selectionHelper.peeledWants) {
selections.add(new BitmapCommit(remainingWant, false, 0));
+ }
pm.endTask();
return selections;
}
- private WalkResult findPaths(RevWalk rw, int expectedNumCommits)
- throws MissingObjectException, IOException {
- BitmapBuilder reuseBitmap = commitBitmapIndex.newBitmapBuilder();
- List<BitmapCommit> reuse = new ArrayList<BitmapCommit>();
+ private boolean isRecentCommit(RevCommit revCommit) {
+ return revCommit.getCommitTime() > inactiveBranchTimestamp;
+ }
+
+ /**
+ * A RevFilter that excludes the commits named in a bitmap from the walk.
+ * <p>
+ * If a commit is in {@code bitmap} then that commit is not emitted by the
+ * walk and its parents are marked as SEEN so the walk can skip them. The
+ * bitmaps passed in have the property that the parents of any commit in
+ * {@code bitmap} are also in {@code bitmap}, so marking the parents as
+ * SEEN speeds up the RevWalk by saving it from walking down blind alleys
+ * and does not change the commits emitted.
+ */
+ private static class NotInBitmapFilter extends RevFilter {
+ private final BitmapBuilder bitmap;
+
+ NotInBitmapFilter(BitmapBuilder bitmap) {
+ this.bitmap = bitmap;
+ }
+
+ @Override
+ public final boolean include(RevWalk rw, RevCommit c) {
+ if (!bitmap.contains(c)) {
+ return true;
+ }
+ for (RevCommit p : c.getParents()) {
+ p.add(SEEN);
+ }
+ return false;
+ }
+
+ @Override
+ public final NotInBitmapFilter clone() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final boolean requiresCommitBody() {
+ return false;
+ }
+ }
+
+ /**
+ * For each of the {@code want}s, which represent the tip commit of each
+ * branch, set up an initial {@link BitmapBuilder}. Reuse previously built
+ * bitmaps if possible.
+ *
+ * @param rw
+ * a {@link RevWalk} to find reachable objects in this repository
+ * @param expectedCommitCount
+ * expected count of commits. The actual count may be less due to
+ * unreachable garbage.
+ * @return a {@link CommitSelectionHelper} containing bitmaps for the tip
+ * commits
+ * @throws IncorrectObjectTypeException
+ * if any of the processed objects is not a commit
+ * @throws IOException
+ * on errors reading pack or index files
+ * @throws MissingObjectException
+ * if an expected object is missing
+ */
+ private CommitSelectionHelper setupTipCommitBitmaps(RevWalk rw,
+ int expectedCommitCount) throws IncorrectObjectTypeException,
+ IOException, MissingObjectException {
+ BitmapBuilder reuse = commitBitmapIndex.newBitmapBuilder();
+ List<BitmapCommit> reuseCommits = new ArrayList<BitmapCommit>();
for (PackBitmapIndexRemapper.Entry entry : bitmapRemapper) {
- if ((entry.getFlags() & FLAG_REUSE) != FLAG_REUSE)
+ // More recent commits did not have the reuse flag set, so skip them
+ if ((entry.getFlags() & FLAG_REUSE) != FLAG_REUSE) {
continue;
-
+ }
RevObject ro = rw.peel(rw.parseAny(entry));
- if (ro instanceof RevCommit) {
- RevCommit rc = (RevCommit) ro;
- reuse.add(new BitmapCommit(rc, false, entry.getFlags()));
- rw.markUninteresting(rc);
+ if (!(ro instanceof RevCommit)) {
+ continue;
+ }
+ RevCommit rc = (RevCommit) ro;
+ reuseCommits.add(new BitmapCommit(rc, false, entry.getFlags()));
+ if (!reuse.contains(rc)) {
EWAHCompressedBitmap bitmap = bitmapRemapper.ofObjectType(
bitmapRemapper.getBitmap(rc), Constants.OBJ_COMMIT);
- writeBitmaps.addBitmap(rc, bitmap, 0);
- reuseBitmap.add(rc, Constants.OBJ_COMMIT);
+ reuse.or(new CompressedBitmap(bitmap, commitBitmapIndex));
}
}
- writeBitmaps.clearBitmaps(); // Remove temporary bitmaps
- // Do a RevWalk by commit time descending. Keep track of all the paths
- // from the wants.
- List<BitmapBuilder> paths = new ArrayList<BitmapBuilder>(want.size());
+ // Add branch tips that are not represented in old bitmap indices. Set
+ // up the RevWalk to walk the new commits not in the old packs.
+ List<BitmapBuilderEntry> tipCommitBitmaps = new ArrayList<BitmapBuilderEntry>(
+ want.size());
Set<RevCommit> peeledWant = new HashSet<RevCommit>(want.size());
for (AnyObjectId objectId : want) {
RevObject ro = rw.peel(rw.parseAny(objectId));
- if (ro instanceof RevCommit && !reuseBitmap.contains(ro)) {
- RevCommit rc = (RevCommit) ro;
- peeledWant.add(rc);
- rw.markStart(rc);
-
- BitmapBuilder bitmap = commitBitmapIndex.newBitmapBuilder();
- bitmap.or(reuseBitmap);
- bitmap.add(rc, Constants.OBJ_COMMIT);
- paths.add(bitmap);
+ if (!(ro instanceof RevCommit) || reuse.contains(ro)) {
+ continue;
}
+
+ RevCommit rc = (RevCommit) ro;
+ peeledWant.add(rc);
+ rw.markStart(rc);
+
+ BitmapBuilder bitmap = commitBitmapIndex.newBitmapBuilder();
+ bitmap.addObject(rc, Constants.OBJ_COMMIT);
+ tipCommitBitmaps.add(new BitmapBuilderEntry(rc, bitmap));
}
- // Update the paths from the wants and create a list of commits in
- // reverse iteration order.
- RevCommit[] commits = new RevCommit[expectedNumCommits];
+ // Create a list of commits in reverse order (older to newer).
+ // For each branch that contains the commit, mark its parents as being
+ // in the bitmap.
+ rw.setRevFilter(new NotInBitmapFilter(reuse));
+ RevCommit[] commits = new RevCommit[expectedCommitCount];
int pos = commits.length;
RevCommit rc;
- while ((rc = rw.next()) != null) {
+ while ((rc = rw.next()) != null && pos > 0) {
commits[--pos] = rc;
- for (BitmapBuilder path : paths) {
- if (path.contains(rc)) {
- for (RevCommit c : rc.getParents())
- path.add(c, Constants.OBJ_COMMIT);
+ for (BitmapBuilderEntry entry : tipCommitBitmaps) {
+ BitmapBuilder bitmap = entry.getBuilder();
+ if (!bitmap.contains(rc)) {
+ continue;
+ }
+ for (RevCommit c : rc.getParents()) {
+ if (reuse.contains(c)) {
+ continue;
+ }
+ bitmap.addObject(c, Constants.OBJ_COMMIT);
}
}
-
pm.update(1);
}
- // Remove the reused bitmaps from the paths
- if (!reuse.isEmpty())
- for (BitmapBuilder bitmap : paths)
- bitmap.andNot(reuseBitmap);
-
- // Sort the paths
- List<BitmapBuilder> distinctPaths = new ArrayList<BitmapBuilder>(paths.size());
- while (!paths.isEmpty()) {
- Collections.sort(paths, BUILDER_BY_CARDINALITY_DSC);
- BitmapBuilder largest = paths.remove(0);
- distinctPaths.add(largest);
+ // Sort the tip commit bitmaps. Find the one containing the most
+ // commits, remove those commits from the remaining bitmaps, resort and
+ // repeat.
+ List<BitmapBuilderEntry> orderedTipCommitBitmaps = new ArrayList<>(
+ tipCommitBitmaps.size());
+ while (!tipCommitBitmaps.isEmpty()) {
+ BitmapBuilderEntry largest =
+ Collections.max(tipCommitBitmaps, ORDER_BY_CARDINALITY);
+ tipCommitBitmaps.remove(largest);
+ orderedTipCommitBitmaps.add(largest);
// Update the remaining paths, by removing the objects from
// the path that was just added.
- for (int i = paths.size() - 1; i >= 0; i--)
- paths.get(i).andNot(largest);
+ for (int i = tipCommitBitmaps.size() - 1; i >= 0; i--) {
+ tipCommitBitmaps.get(i).getBuilder()
+ .andNot(largest.getBuilder());
+ }
}
- return new WalkResult(peeledWant, commits, pos, distinctPaths, reuse);
+ return new CommitSelectionHelper(peeledWant, commits, pos,
+ orderedTipCommitBitmaps, reuse, reuseCommits);
}
- private int nextSelectionDistance(int idx, int cardinality) {
- if (idx > cardinality)
+ /*-
+ * Returns the desired distance to the next bitmap based on the distance
+ * from the tip commit. Only differentiates recent from distant spans,
+ * selectCommits() handles the contiguous commits at the tip for active
+ * or inactive branches.
+ *
+ * A graph of this function looks like this, where
+ * the X axis is the distance from the tip commit and the Y axis is the
+ * bitmap selection distance.
+ *
+ * 5000 ____...
+ * /
+ * /
+ * /
+ * /
+ * 100 _____/
+ * 0 20100 25000
+ *
+ * Linear scaling between 20100 and 25000 prevents spans >100 for distances
+ * <20000 (otherwise, a span of 5000 would be returned for a distance of
+ * 21000, and the range 16000-20000 would have no selections).
+ */
+ int nextSpan(int distanceFromTip) {
+ if (distanceFromTip < 0) {
throw new IllegalArgumentException();
- int idxFromStart = cardinality - idx;
- int mustRegionEnd = 100;
- if (idxFromStart <= mustRegionEnd)
- return 0;
+ }
// Commits more toward the start will have more bitmaps.
- int minRegionEnd = 20000;
- if (idxFromStart <= minRegionEnd)
- return Math.min(idxFromStart - mustRegionEnd, minCommits);
+ if (distanceFromTip <= recentCommitCount) {
+ return recentCommitSpan;
+ }
- // Commits more toward the end will have fewer.
- int next = Math.min(idxFromStart - minRegionEnd, maxCommits);
- return Math.max(next, minCommits);
+ int next = Math.min(distanceFromTip - recentCommitCount,
+ distantCommitSpan);
+ return Math.max(next, recentCommitSpan);
}
PackWriterBitmapWalker newBitmapWalker() {
@@ -316,12 +504,14 @@
new ObjectWalk(reader), bitmapIndex, null);
}
+ /**
+ * A commit object for which a bitmap index should be built.
+ */
static final class BitmapCommit extends ObjectId {
private final boolean reuseWalker;
private final int flags;
- private BitmapCommit(
- AnyObjectId objectId, boolean reuseWalker, int flags) {
+ BitmapCommit(AnyObjectId objectId, boolean reuseWalker, int flags) {
super(objectId);
this.reuseWalker = reuseWalker;
this.flags = flags;
@@ -336,24 +526,62 @@
}
}
- private static final class WalkResult implements Iterable<RevCommit> {
- private final Set<? extends ObjectId> peeledWant;
- private final RevCommit[] commitsByOldest;
- private final int commitStartPos;
- private final List<BitmapBuilder> paths;
- private final Iterable<BitmapCommit> reuse;
+ /**
+ * A POJO representing a Pair<RevCommit, BitmapBuidler>.
+ */
+ private static final class BitmapBuilderEntry {
+ private final RevCommit commit;
+ private final BitmapBuilder builder;
- private WalkResult(Set<? extends ObjectId> peeledWant,
+ BitmapBuilderEntry(RevCommit commit, BitmapBuilder builder) {
+ this.commit = commit;
+ this.builder = builder;
+ }
+
+ RevCommit getCommit() {
+ return commit;
+ }
+
+ BitmapBuilder getBuilder() {
+ return builder;
+ }
+ }
+
+ /**
+ * Container for state used in the first phase of selecting commits, which
+ * walks all of the reachable commits via the branch tips (
+ * {@code peeledWants}), stores them in {@code commitsByOldest}, and sets up
+ * bitmaps for each branch tip ({@code tipCommitBitmaps}).
+ * {@code commitsByOldest} is initialized with an expected size of all
+ * commits, but may be smaller if some commits are unreachable, in which
+ * case {@code commitStartPos} will contain a positive offset to the root
+ * commit.
+ */
+ private static final class CommitSelectionHelper implements Iterable<RevCommit> {
+ final Set<? extends ObjectId> peeledWants;
+ final List<BitmapBuilderEntry> tipCommitBitmaps;
+
+ final BitmapBuilder reusedCommitsBitmap;
+ final Iterable<BitmapCommit> reusedCommits;
+ final RevCommit[] commitsByOldest;
+ final int commitStartPos;
+
+ CommitSelectionHelper(Set<? extends ObjectId> peeledWant,
RevCommit[] commitsByOldest, int commitStartPos,
- List<BitmapBuilder> paths, Iterable<BitmapCommit> reuse) {
- this.peeledWant = peeledWant;
+ List<BitmapBuilderEntry> bitmapEntries,
+ BitmapBuilder reusedCommitsBitmap,
+ Iterable<BitmapCommit> reuse) {
+ this.peeledWants = peeledWant;
this.commitsByOldest = commitsByOldest;
this.commitStartPos = commitStartPos;
- this.paths = paths;
- this.reuse = reuse;
+ this.tipCommitBitmaps = bitmapEntries;
+ this.reusedCommitsBitmap = reusedCommitsBitmap;
+ this.reusedCommits = reuse;
}
public Iterator<RevCommit> iterator() {
+ // Member variables referenced by this iterator will have synthetic
+ // accessors generated for them if they are made private.
return new Iterator<RevCommit>() {
int pos = commitStartPos;
@@ -370,5 +598,9 @@
}
};
}
+
+ int getCommitCount() {
+ return commitsByOldest.length - commitStartPos;
+ }
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java
index debb2f2..d9ac9ef 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java
@@ -110,21 +110,32 @@
}
if (marked) {
- BitmapRevFilter filter = newRevFilter(seen, bitmapResult);
- walker.setRevFilter(filter);
+ if (seen == null) {
+ walker.setRevFilter(new AddToBitmapFilter(bitmapResult));
+ } else {
+ walker.setRevFilter(
+ new AddUnseenToBitmapFilter(seen, bitmapResult));
+ }
while (walker.next() != null) {
// Iterate through all of the commits. The BitmapRevFilter does
// the work.
+ //
+ // filter.include returns true for commits that do not have
+ // a bitmap in bitmapIndex and are not reachable from a
+ // bitmap in bitmapIndex encountered earlier in the walk.
+ // Thus the number of commits returned by next() measures how
+ // much history was traversed without being able to make use
+ // of bitmaps.
pm.update(1);
+ countOfBitmapIndexMisses++;
}
RevObject ro;
while ((ro = walker.nextObject()) != null) {
- bitmapResult.add(ro, ro.getType());
+ bitmapResult.addObject(ro, ro.getType());
pm.update(1);
}
- countOfBitmapIndexMisses += filter.getCountOfLoadedCommits();
}
return bitmapResult;
@@ -134,53 +145,105 @@
walker.reset();
}
- static BitmapRevFilter newRevFilter(
- final BitmapBuilder seen, final BitmapBuilder bitmapResult) {
- if (seen != null) {
- return new BitmapRevFilter() {
- protected boolean load(RevCommit cmit) {
- if (seen.contains(cmit))
- return false;
- return bitmapResult.add(cmit, Constants.OBJ_COMMIT);
- }
- };
+ /**
+ * A RevFilter that adds the visited commits to {@code bitmap} as a side
+ * effect.
+ * <p>
+ * When the walk hits a commit that is part of {@code bitmap}'s
+ * BitmapIndex, that entire bitmap is ORed into {@code bitmap} and the
+ * commit and its parents are marked as SEEN so that the walk does not
+ * have to visit its ancestors. This ensures the walk is very short if
+ * there is good bitmap coverage.
+ */
+ static class AddToBitmapFilter extends RevFilter {
+ private final BitmapBuilder bitmap;
+
+ AddToBitmapFilter(BitmapBuilder bitmap) {
+ this.bitmap = bitmap;
}
- return new BitmapRevFilter() {
- @Override
- protected boolean load(RevCommit cmit) {
- return bitmapResult.add(cmit, Constants.OBJ_COMMIT);
- }
- };
- }
-
- static abstract class BitmapRevFilter extends RevFilter {
- private long countOfLoadedCommits;
-
- protected abstract boolean load(RevCommit cmit);
@Override
public final boolean include(RevWalk walker, RevCommit cmit) {
- if (load(cmit)) {
- countOfLoadedCommits++;
+ Bitmap visitedBitmap;
+
+ if (bitmap.contains(cmit)) {
+ // already included
+ } else if ((visitedBitmap = bitmap.getBitmapIndex()
+ .getBitmap(cmit)) != null) {
+ bitmap.or(visitedBitmap);
+ } else {
+ bitmap.addObject(cmit, Constants.OBJ_COMMIT);
return true;
}
- for (RevCommit p : cmit.getParents())
+
+ for (RevCommit p : cmit.getParents()) {
p.add(RevFlag.SEEN);
+ }
return false;
}
@Override
public final RevFilter clone() {
- return this;
+ throw new UnsupportedOperationException();
}
@Override
public final boolean requiresCommitBody() {
return false;
}
+ }
- long getCountOfLoadedCommits() {
- return countOfLoadedCommits;
+ /**
+ * A RevFilter that adds the visited commits to {@code bitmap} as a side
+ * effect.
+ * <p>
+ * When the walk hits a commit that is part of {@code bitmap}'s
+ * BitmapIndex, that entire bitmap is ORed into {@code bitmap} and the
+ * commit and its parents are marked as SEEN so that the walk does not
+ * have to visit its ancestors. This ensures the walk is very short if
+ * there is good bitmap coverage.
+ * <p>
+ * Commits named in {@code seen} are considered already seen. If one is
+ * encountered, that commit and its parents will be marked with the SEEN
+ * flag to prevent the walk from visiting its ancestors.
+ */
+ static class AddUnseenToBitmapFilter extends RevFilter {
+ private final BitmapBuilder seen;
+ private final BitmapBuilder bitmap;
+
+ AddUnseenToBitmapFilter(BitmapBuilder seen, BitmapBuilder bitmapResult) {
+ this.seen = seen;
+ this.bitmap = bitmapResult;
+ }
+
+ @Override
+ public final boolean include(RevWalk walker, RevCommit cmit) {
+ Bitmap visitedBitmap;
+
+ if (seen.contains(cmit) || bitmap.contains(cmit)) {
+ // already seen or included
+ } else if ((visitedBitmap = bitmap.getBitmapIndex()
+ .getBitmap(cmit)) != null) {
+ bitmap.or(visitedBitmap);
+ } else {
+ bitmap.addObject(cmit, Constants.OBJ_COMMIT);
+ return true;
+ }
+
+ for (RevCommit p : cmit.getParents()) {
+ p.add(RevFlag.SEEN);
+ }
+ return false;
+ }
+
+ @Override
+ public final RevFilter clone() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final boolean requiresCommitBody() {
+ return false;
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/AlwaysFailUpdate.java
similarity index 60%
copy from org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
copy to org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/AlwaysFailUpdate.java
index c7e41bc..12ef873 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/AlwaysFailUpdate.java
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006-2007, Shawn O. Pearce <spearce@spearce.org>
+ * 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
@@ -42,44 +41,58 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package org.eclipse.jgit.lib;
+package org.eclipse.jgit.internal.storage.reftree;
-/**
- * A tree entry representing a symbolic link.
- *
- * Note. Java cannot really handle these as file system objects.
- *
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
- */
-@Deprecated
-public class SymlinkTreeEntry extends TreeEntry {
+import java.io.IOException;
- /**
- * Construct a {@link SymlinkTreeEntry} with the specified name and SHA-1 in
- * the specified parent
- *
- * @param parent
- * @param id
- * @param nameUTF8
- */
- public SymlinkTreeEntry(final Tree parent, final ObjectId id,
- final byte[] nameUTF8) {
- super(parent, id, nameUTF8);
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+
+/** Update that always rejects with {@code LOCK_FAILURE}. */
+class AlwaysFailUpdate extends RefUpdate {
+ private final RefTreeDatabase refdb;
+
+ AlwaysFailUpdate(RefTreeDatabase refdb, String name) {
+ super(new ObjectIdRef.Unpeeled(Ref.Storage.NEW, name, null));
+ this.refdb = refdb;
+ setCheckConflicting(false);
}
- public FileMode getMode() {
- return FileMode.SYMLINK;
+ @Override
+ protected RefDatabase getRefDatabase() {
+ return refdb;
}
- public String toString() {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(getId()));
- r.append(" S "); //$NON-NLS-1$
- r.append(getFullName());
- return r.toString();
+ @Override
+ protected Repository getRepository() {
+ return refdb.getRepository();
+ }
+
+ @Override
+ protected boolean tryLock(boolean deref) throws IOException {
+ return false;
+ }
+
+ @Override
+ protected void unlock() {
+ // No locks are held here.
+ }
+
+ @Override
+ protected Result doUpdate(Result desiredResult) {
+ return Result.LOCK_FAILURE;
+ }
+
+ @Override
+ protected Result doDelete(Result desiredResult) {
+ return Result.LOCK_FAILURE;
+ }
+
+ @Override
+ protected Result doLink(String target) {
+ return Result.LOCK_FAILURE;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Command.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Command.java
new file mode 100644
index 0000000..dd08375
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Command.java
@@ -0,0 +1,316 @@
+/*
+ * 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.OBJ_BLOB;
+import static org.eclipse.jgit.lib.Constants.encode;
+import static org.eclipse.jgit.lib.FileMode.TYPE_GITLINK;
+import static org.eclipse.jgit.lib.FileMode.TYPE_SYMLINK;
+import static org.eclipse.jgit.lib.Ref.Storage.NETWORK;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevTag;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.eclipse.jgit.transport.ReceiveCommand.Result;
+
+/**
+ * Command to create, update or delete an entry inside a {@link RefTree}.
+ * <p>
+ * Unlike {@link ReceiveCommand} (which can only update a reference to an
+ * {@link ObjectId}), a RefTree Command can also create, modify or delete
+ * symbolic references to a target reference.
+ * <p>
+ * RefTree Commands may wrap a {@code ReceiveCommand} to allow callers to
+ * process an existing ReceiveCommand against a RefTree.
+ * <p>
+ * Commands should be passed into {@link RefTree#apply(java.util.Collection)}
+ * for processing.
+ */
+public class Command {
+ /**
+ * Set unprocessed commands as failed due to transaction aborted.
+ * <p>
+ * If a command is still {@link Result#NOT_ATTEMPTED} it will be set to
+ * {@link Result#REJECTED_OTHER_REASON}. If {@code why} is non-null its
+ * contents will be used as the message for the first command status.
+ *
+ * @param commands
+ * commands to mark as failed.
+ * @param why
+ * optional message to set on the first aborted command.
+ */
+ public static void abort(Iterable<Command> commands, @Nullable String why) {
+ if (why == null || why.isEmpty()) {
+ why = JGitText.get().transactionAborted;
+ }
+ for (Command c : commands) {
+ if (c.getResult() == NOT_ATTEMPTED) {
+ c.setResult(REJECTED_OTHER_REASON, why);
+ why = JGitText.get().transactionAborted;
+ }
+ }
+ }
+
+ private final Ref oldRef;
+ private final Ref newRef;
+ private final ReceiveCommand cmd;
+ private Result result;
+
+ /**
+ * Create a command to create, update or delete a reference.
+ * <p>
+ * At least one of {@code oldRef} or {@code newRef} must be supplied.
+ *
+ * @param oldRef
+ * expected value. Null if the ref should not exist.
+ * @param newRef
+ * desired value, must be peeled if not null and not symbolic.
+ * Null to delete the ref.
+ */
+ public Command(@Nullable Ref oldRef, @Nullable Ref newRef) {
+ this.oldRef = oldRef;
+ this.newRef = newRef;
+ this.cmd = null;
+ this.result = NOT_ATTEMPTED;
+
+ if (oldRef == null && newRef == null) {
+ throw new IllegalArgumentException();
+ }
+ if (newRef != null && !newRef.isPeeled() && !newRef.isSymbolic()) {
+ throw new IllegalArgumentException();
+ }
+ if (oldRef != null && newRef != null
+ && !oldRef.getName().equals(newRef.getName())) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Construct a RefTree command wrapped around a ReceiveCommand.
+ *
+ * @param rw
+ * walk instance to peel the {@code newId}.
+ * @param cmd
+ * command received from a push client.
+ * @throws MissingObjectException
+ * {@code oldId} or {@code newId} is missing.
+ * @throws IOException
+ * {@code oldId} or {@code newId} cannot be peeled.
+ */
+ public Command(RevWalk rw, ReceiveCommand cmd)
+ throws MissingObjectException, IOException {
+ this.oldRef = toRef(rw, cmd.getOldId(), cmd.getRefName(), false);
+ this.newRef = toRef(rw, cmd.getNewId(), cmd.getRefName(), true);
+ this.cmd = cmd;
+ }
+
+ static Ref toRef(RevWalk rw, ObjectId id, String name,
+ boolean mustExist) throws MissingObjectException, IOException {
+ if (ObjectId.zeroId().equals(id)) {
+ return null;
+ }
+
+ try {
+ RevObject o = rw.parseAny(id);
+ if (o instanceof RevTag) {
+ RevObject p = rw.peel(o);
+ return new ObjectIdRef.PeeledTag(NETWORK, name, id, p.copy());
+ }
+ return new ObjectIdRef.PeeledNonTag(NETWORK, name, id);
+ } catch (MissingObjectException e) {
+ if (mustExist) {
+ throw e;
+ }
+ return new ObjectIdRef.Unpeeled(NETWORK, name, id);
+ }
+ }
+
+ /** @return name of the reference affected by this command. */
+ public String getRefName() {
+ if (cmd != null) {
+ return cmd.getRefName();
+ } else if (newRef != null) {
+ return newRef.getName();
+ }
+ return oldRef.getName();
+ }
+
+ /**
+ * Set the result of this command.
+ *
+ * @param result
+ * the command result.
+ */
+ public void setResult(Result result) {
+ setResult(result, null);
+ }
+
+ /**
+ * Set the result of this command.
+ *
+ * @param result
+ * the command result.
+ * @param why
+ * optional message explaining the result status.
+ */
+ public void setResult(Result result, @Nullable String why) {
+ if (cmd != null) {
+ cmd.setResult(result, why);
+ } else {
+ this.result = result;
+ }
+ }
+
+ /** @return result of executing this command. */
+ public Result getResult() {
+ return cmd != null ? cmd.getResult() : result;
+ }
+
+ /** @return optional message explaining command failure. */
+ @Nullable
+ public String getMessage() {
+ return cmd != null ? cmd.getMessage() : null;
+ }
+
+ /**
+ * Old peeled reference.
+ *
+ * @return the old reference; null if the command is creating the reference.
+ */
+ @Nullable
+ public Ref getOldRef() {
+ return oldRef;
+ }
+
+ /**
+ * New peeled reference.
+ *
+ * @return the new reference; null if the command is deleting the reference.
+ */
+ @Nullable
+ public Ref getNewRef() {
+ return newRef;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+ append(s, oldRef, "CREATE"); //$NON-NLS-1$
+ s.append(' ');
+ append(s, newRef, "DELETE"); //$NON-NLS-1$
+ s.append(' ').append(getRefName());
+ s.append(' ').append(getResult());
+ if (getMessage() != null) {
+ s.append(' ').append(getMessage());
+ }
+ return s.toString();
+ }
+
+ private static void append(StringBuilder s, Ref r, String nullName) {
+ if (r == null) {
+ s.append(nullName);
+ } else if (r.isSymbolic()) {
+ s.append(r.getTarget().getName());
+ } else {
+ ObjectId id = r.getObjectId();
+ if (id != null) {
+ s.append(id.name());
+ }
+ }
+ }
+
+ /**
+ * Check the entry is consistent with either the old or the new ref.
+ *
+ * @param entry
+ * current entry; null if the entry does not exist.
+ * @return true if entry matches {@link #getOldRef()} or
+ * {@link #getNewRef()}; otherwise false.
+ */
+ boolean checkRef(@Nullable DirCacheEntry entry) {
+ if (entry != null && entry.getRawMode() == 0) {
+ entry = null;
+ }
+ return check(entry, oldRef) || check(entry, newRef);
+ }
+
+ private static boolean check(@Nullable DirCacheEntry cur,
+ @Nullable Ref exp) {
+ if (cur == null) {
+ // Does not exist, ok if oldRef does not exist.
+ return exp == null;
+ } else if (exp == null) {
+ // Expected to not exist, but currently exists, fail.
+ return false;
+ }
+
+ if (exp.isSymbolic()) {
+ String dst = exp.getTarget().getName();
+ return cur.getRawMode() == TYPE_SYMLINK
+ && cur.getObjectId().equals(symref(dst));
+ }
+
+ return cur.getRawMode() == TYPE_GITLINK
+ && cur.getObjectId().equals(exp.getObjectId());
+ }
+
+ static ObjectId symref(String s) {
+ @SuppressWarnings("resource")
+ ObjectInserter.Formatter fmt = new ObjectInserter.Formatter();
+ return fmt.idFor(OBJ_BLOB, encode(s));
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTree.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTree.java
new file mode 100644
index 0000000..85690c8
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTree.java
@@ -0,0 +1,411 @@
+/*
+ * 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.OBJ_BLOB;
+import static org.eclipse.jgit.lib.Constants.R_REFS;
+import static org.eclipse.jgit.lib.Constants.encode;
+import static org.eclipse.jgit.lib.FileMode.GITLINK;
+import static org.eclipse.jgit.lib.FileMode.SYMLINK;
+import static org.eclipse.jgit.lib.FileMode.TYPE_GITLINK;
+import static org.eclipse.jgit.lib.FileMode.TYPE_SYMLINK;
+import static org.eclipse.jgit.lib.Ref.Storage.NEW;
+import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
+import static org.eclipse.jgit.lib.RefDatabase.MAX_SYMBOLIC_REF_DEPTH;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEditor;
+import org.eclipse.jgit.dircache.DirCacheEditor.DeletePath;
+import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.DirCacheNameConflictException;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.FileMode;
+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.Repository;
+import org.eclipse.jgit.lib.SymbolicRef;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.util.RawParseUtils;
+
+/**
+ * Tree of references in the reference graph.
+ * <p>
+ * The root corresponds to the {@code "refs/"} subdirectory, for example the
+ * default reference {@code "refs/heads/master"} is stored at path
+ * {@code "heads/master"} in a {@code RefTree}.
+ * <p>
+ * Normal references are stored as {@link FileMode#GITLINK} tree entries. The
+ * ObjectId in the tree entry is the ObjectId the reference refers to.
+ * <p>
+ * Symbolic references are stored as {@link FileMode#SYMLINK} entries, with the
+ * blob storing the name of the target reference.
+ * <p>
+ * Annotated tags also store the peeled object using a {@code GITLINK} entry
+ * with the suffix <code>" ^"</code> (space carrot), for example
+ * {@code "tags/v1.0"} stores the annotated tag object, while
+ * <code>"tags/v1.0 ^"</code> stores the commit the tag annotates.
+ * <p>
+ * {@code HEAD} is a special case and stored as {@code "..HEAD"}.
+ */
+public class RefTree {
+ /** Suffix applied to GITLINK to indicate its the peeled value of a tag. */
+ public static final String PEELED_SUFFIX = " ^"; //$NON-NLS-1$
+ static final String ROOT_DOTDOT = ".."; //$NON-NLS-1$
+
+ /**
+ * Create an empty reference tree.
+ *
+ * @return a new empty reference tree.
+ */
+ public static RefTree newEmptyTree() {
+ return new RefTree(DirCache.newInCore());
+ }
+
+ /**
+ * Load a reference tree.
+ *
+ * @param reader
+ * reader to scan the reference tree with.
+ * @param tree
+ * the tree to read.
+ * @return the ref tree read from the commit.
+ * @throws IOException
+ * the repository cannot be accessed through the reader.
+ * @throws CorruptObjectException
+ * a tree object is corrupt and cannot be read.
+ * @throws IncorrectObjectTypeException
+ * a tree object wasn't actually a tree.
+ * @throws MissingObjectException
+ * a reference tree object doesn't exist.
+ */
+ public static RefTree read(ObjectReader reader, RevTree tree)
+ throws MissingObjectException, IncorrectObjectTypeException,
+ CorruptObjectException, IOException {
+ return new RefTree(DirCache.read(reader, tree));
+ }
+
+ private DirCache contents;
+ private Map<ObjectId, String> pendingBlobs;
+
+ private RefTree(DirCache dc) {
+ this.contents = dc;
+ }
+
+ /**
+ * Read one reference.
+ * <p>
+ * References are always returned peeled ({@link Ref#isPeeled()} is true).
+ * If the reference points to an annotated tag, the returned reference will
+ * be peeled and contain {@link Ref#getPeeledObjectId()}.
+ * <p>
+ * If the reference is a symbolic reference and the chain depth is less than
+ * {@link org.eclipse.jgit.lib.RefDatabase#MAX_SYMBOLIC_REF_DEPTH} the
+ * returned reference is resolved. If the chain depth is longer, the
+ * symbolic reference is returned without resolving.
+ *
+ * @param reader
+ * to access objects necessary to read the requested reference.
+ * @param name
+ * name of the reference to read.
+ * @return the reference; null if it does not exist.
+ * @throws IOException
+ * cannot read a symbolic reference target.
+ */
+ @Nullable
+ public Ref exactRef(ObjectReader reader, String name) throws IOException {
+ Ref r = readRef(reader, name);
+ if (r == null) {
+ return null;
+ } else if (r.isSymbolic()) {
+ return resolve(reader, r, 0);
+ }
+
+ DirCacheEntry p = contents.getEntry(peeledPath(name));
+ if (p != null && p.getRawMode() == TYPE_GITLINK) {
+ return new ObjectIdRef.PeeledTag(PACKED, r.getName(),
+ r.getObjectId(), p.getObjectId());
+ }
+ return r;
+ }
+
+ private Ref readRef(ObjectReader reader, String name) throws IOException {
+ DirCacheEntry e = contents.getEntry(refPath(name));
+ return e != null ? toRef(reader, e, name) : null;
+ }
+
+ private Ref toRef(ObjectReader reader, DirCacheEntry e, String name)
+ throws IOException {
+ int mode = e.getRawMode();
+ if (mode == TYPE_GITLINK) {
+ ObjectId id = e.getObjectId();
+ return new ObjectIdRef.PeeledNonTag(PACKED, name, id);
+ }
+
+ if (mode == TYPE_SYMLINK) {
+ ObjectId id = e.getObjectId();
+ String n = pendingBlobs != null ? pendingBlobs.get(id) : null;
+ if (n == null) {
+ byte[] bin = reader.open(id, OBJ_BLOB).getCachedBytes();
+ n = RawParseUtils.decode(bin);
+ }
+ Ref dst = new ObjectIdRef.Unpeeled(NEW, n, null);
+ return new SymbolicRef(name, dst);
+ }
+
+ return null; // garbage file or something; not a reference.
+ }
+
+ private Ref resolve(ObjectReader reader, Ref ref, int depth)
+ throws IOException {
+ if (ref.isSymbolic() && depth < MAX_SYMBOLIC_REF_DEPTH) {
+ Ref r = readRef(reader, ref.getTarget().getName());
+ if (r == null) {
+ return ref;
+ }
+ Ref dst = resolve(reader, r, depth + 1);
+ return new SymbolicRef(ref.getName(), dst);
+ }
+ return ref;
+ }
+
+ /**
+ * Attempt a batch of commands against this RefTree.
+ * <p>
+ * The batch is applied atomically, either all commands apply at once, or
+ * they all reject and the RefTree is left unmodified.
+ * <p>
+ * On success (when this method returns {@code true}) the command results
+ * are left as-is (probably {@code NOT_ATTEMPTED}). Result fields are set
+ * only when this method returns {@code false} to indicate failure.
+ *
+ * @param cmdList
+ * to apply. All commands should still have result NOT_ATTEMPTED.
+ * @return true if the commands applied; false if they were rejected.
+ */
+ public boolean apply(Collection<Command> cmdList) {
+ try {
+ DirCacheEditor ed = contents.editor();
+ for (Command cmd : cmdList) {
+ if (!isValidRef(cmd)) {
+ cmd.setResult(REJECTED_OTHER_REASON,
+ JGitText.get().funnyRefname);
+ Command.abort(cmdList, null);
+ return false;
+ }
+ apply(ed, cmd);
+ }
+ ed.finish();
+ return true;
+ } catch (DirCacheNameConflictException e) {
+ String r1 = refName(e.getPath1());
+ String r2 = refName(e.getPath2());
+ for (Command cmd : cmdList) {
+ if (r1.equals(cmd.getRefName())
+ || r2.equals(cmd.getRefName())) {
+ cmd.setResult(LOCK_FAILURE);
+ break;
+ }
+ }
+ Command.abort(cmdList, null);
+ return false;
+ } catch (LockFailureException e) {
+ Command.abort(cmdList, null);
+ return false;
+ }
+ }
+
+ private static boolean isValidRef(Command cmd) {
+ String n = cmd.getRefName();
+ return HEAD.equals(n) || Repository.isValidRefName(n);
+ }
+
+ private void apply(DirCacheEditor ed, final Command cmd) {
+ String path = refPath(cmd.getRefName());
+ Ref oldRef = cmd.getOldRef();
+ final Ref newRef = cmd.getNewRef();
+
+ if (newRef == null) {
+ checkRef(contents.getEntry(path), cmd);
+ ed.add(new DeletePath(path));
+ cleanupPeeledRef(ed, oldRef);
+ return;
+ }
+
+ if (newRef.isSymbolic()) {
+ final String dst = newRef.getTarget().getName();
+ ed.add(new PathEdit(path) {
+ @Override
+ public void apply(DirCacheEntry ent) {
+ checkRef(ent, cmd);
+ ObjectId id = Command.symref(dst);
+ ent.setFileMode(SYMLINK);
+ ent.setObjectId(id);
+ if (pendingBlobs == null) {
+ pendingBlobs = new HashMap<>(4);
+ }
+ pendingBlobs.put(id, dst);
+ }
+ }.setReplace(false));
+ cleanupPeeledRef(ed, oldRef);
+ return;
+ }
+
+ ed.add(new PathEdit(path) {
+ @Override
+ public void apply(DirCacheEntry ent) {
+ checkRef(ent, cmd);
+ ent.setFileMode(GITLINK);
+ ent.setObjectId(newRef.getObjectId());
+ }
+ }.setReplace(false));
+
+ if (newRef.getPeeledObjectId() != null) {
+ ed.add(new PathEdit(peeledPath(newRef.getName())) {
+ @Override
+ public void apply(DirCacheEntry ent) {
+ ent.setFileMode(GITLINK);
+ ent.setObjectId(newRef.getPeeledObjectId());
+ }
+ }.setReplace(false));
+ } else {
+ cleanupPeeledRef(ed, oldRef);
+ }
+ }
+
+ private static void checkRef(@Nullable DirCacheEntry ent, Command cmd) {
+ if (!cmd.checkRef(ent)) {
+ cmd.setResult(LOCK_FAILURE);
+ throw new LockFailureException();
+ }
+ }
+
+ private static void cleanupPeeledRef(DirCacheEditor ed, Ref ref) {
+ if (ref != null && !ref.isSymbolic()
+ && (!ref.isPeeled() || ref.getPeeledObjectId() != null)) {
+ ed.add(new DeletePath(peeledPath(ref.getName())));
+ }
+ }
+
+ /**
+ * Convert a path name in a RefTree to the reference name known by Git.
+ *
+ * @param path
+ * name read from the RefTree structure, for example
+ * {@code "heads/master"}.
+ * @return reference name for the path, {@code "refs/heads/master"}.
+ */
+ public static String refName(String path) {
+ if (path.startsWith(ROOT_DOTDOT)) {
+ return path.substring(2);
+ }
+ return R_REFS + path;
+ }
+
+ static String refPath(String name) {
+ if (name.startsWith(R_REFS)) {
+ return name.substring(R_REFS.length());
+ }
+ return ROOT_DOTDOT + name;
+ }
+
+ private static String peeledPath(String name) {
+ return refPath(name) + PEELED_SUFFIX;
+ }
+
+ /**
+ * Write this reference tree.
+ *
+ * @param inserter
+ * inserter to use when writing trees to the object database.
+ * Caller is responsible for flushing the inserter before trying
+ * to read the objects, or exposing them through a reference.
+ * @return the top level tree.
+ * @throws IOException
+ * a tree could not be written.
+ */
+ public ObjectId writeTree(ObjectInserter inserter) throws IOException {
+ if (pendingBlobs != null) {
+ for (String s : pendingBlobs.values()) {
+ inserter.insert(OBJ_BLOB, encode(s));
+ }
+ pendingBlobs = null;
+ }
+ return contents.writeTree(inserter);
+ }
+
+ /** @return a deep copy of this RefTree. */
+ public RefTree copy() {
+ RefTree r = new RefTree(DirCache.newInCore());
+ DirCacheBuilder b = r.contents.builder();
+ for (int i = 0; i < contents.getEntryCount(); i++) {
+ b.add(new DirCacheEntry(contents.getEntry(i)));
+ }
+ b.finish();
+ if (pendingBlobs != null) {
+ r.pendingBlobs = new HashMap<>(pendingBlobs);
+ }
+ return r;
+ }
+
+ private static class LockFailureException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java
new file mode 100644
index 0000000..a55a9f5
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java
@@ -0,0 +1,222 @@
+/*
+ * 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.OBJ_TREE;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
+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.eclipse.jgit.transport.ReceiveCommand.Type.UPDATE;
+import static org.eclipse.jgit.transport.ReceiveCommand.Type.UPDATE_NONFASTFORWARD;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.internal.JGitText;
+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.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
+
+/** Batch update a {@link RefTreeDatabase}. */
+class RefTreeBatch extends BatchRefUpdate {
+ private final RefTreeDatabase refdb;
+ private Ref src;
+ private ObjectId parentCommitId;
+ private ObjectId parentTreeId;
+ private RefTree tree;
+ private PersonIdent author;
+ private ObjectId newCommitId;
+
+ RefTreeBatch(RefTreeDatabase refdb) {
+ super(refdb);
+ this.refdb = refdb;
+ }
+
+ @Override
+ public void execute(RevWalk rw, ProgressMonitor monitor)
+ throws IOException {
+ List<Command> todo = new ArrayList<>(getCommands().size());
+ for (ReceiveCommand c : getCommands()) {
+ if (!isAllowNonFastForwards()) {
+ if (c.getType() == UPDATE) {
+ c.updateType(rw);
+ }
+ if (c.getType() == UPDATE_NONFASTFORWARD) {
+ c.setResult(REJECTED_NONFASTFORWARD);
+ ReceiveCommand.abort(getCommands());
+ return;
+ }
+ }
+ todo.add(new Command(rw, c));
+ }
+ init(rw);
+ execute(rw, todo);
+ }
+
+ void init(RevWalk rw) throws IOException {
+ src = refdb.getBootstrap().exactRef(refdb.getTxnCommitted());
+ if (src != null && src.getObjectId() != null) {
+ RevCommit c = rw.parseCommit(src.getObjectId());
+ parentCommitId = c;
+ parentTreeId = c.getTree();
+ tree = RefTree.read(rw.getObjectReader(), c.getTree());
+ } else {
+ parentCommitId = ObjectId.zeroId();
+ parentTreeId = new ObjectInserter.Formatter()
+ .idFor(OBJ_TREE, new byte[] {});
+ tree = RefTree.newEmptyTree();
+ }
+ }
+
+ @Nullable
+ Ref exactRef(ObjectReader reader, String name) throws IOException {
+ return tree.exactRef(reader, name);
+ }
+
+ /**
+ * Execute an update from {@link RefTreeUpdate} or {@link RefTreeRename}.
+ *
+ * @param rw
+ * current RevWalk handling the update or rename.
+ * @param todo
+ * commands to execute. Must never be a bootstrap reference name.
+ * @throws IOException
+ * the storage system is unable to read or write data.
+ */
+ void execute(RevWalk rw, List<Command> todo) throws IOException {
+ for (Command c : todo) {
+ if (c.getResult() != NOT_ATTEMPTED) {
+ Command.abort(todo, null);
+ return;
+ }
+ if (refdb.conflictsWithBootstrap(c.getRefName())) {
+ c.setResult(REJECTED_OTHER_REASON, MessageFormat
+ .format(JGitText.get().invalidRefName, c.getRefName()));
+ Command.abort(todo, null);
+ return;
+ }
+ }
+
+ if (apply(todo) && newCommitId != null) {
+ commit(rw, todo);
+ }
+ }
+
+ private boolean apply(List<Command> todo) throws IOException {
+ if (!tree.apply(todo)) {
+ // apply set rejection information on commands.
+ return false;
+ }
+
+ Repository repo = refdb.getRepository();
+ try (ObjectInserter ins = repo.newObjectInserter()) {
+ CommitBuilder b = new CommitBuilder();
+ b.setTreeId(tree.writeTree(ins));
+ if (parentTreeId.equals(b.getTreeId())) {
+ for (Command c : todo) {
+ c.setResult(OK);
+ }
+ return true;
+ }
+ if (!parentCommitId.equals(ObjectId.zeroId())) {
+ b.setParentId(parentCommitId);
+ }
+
+ author = getRefLogIdent();
+ if (author == null) {
+ author = new PersonIdent(repo);
+ }
+ b.setAuthor(author);
+ b.setCommitter(author);
+ b.setMessage(getRefLogMessage());
+ newCommitId = ins.insert(b);
+ ins.flush();
+ }
+ return true;
+ }
+
+ private void commit(RevWalk rw, List<Command> todo) throws IOException {
+ ReceiveCommand commit = new ReceiveCommand(
+ parentCommitId, newCommitId,
+ refdb.getTxnCommitted());
+ updateBootstrap(rw, commit);
+
+ if (commit.getResult() == OK) {
+ for (Command c : todo) {
+ c.setResult(OK);
+ }
+ } else {
+ Command.abort(todo, commit.getResult().name());
+ }
+ }
+
+ private void updateBootstrap(RevWalk rw, ReceiveCommand commit)
+ throws IOException {
+ BatchRefUpdate u = refdb.getBootstrap().newBatchUpdate();
+ u.setAllowNonFastForwards(true);
+ u.setPushCertificate(getPushCertificate());
+ if (isRefLogDisabled()) {
+ u.disableRefLog();
+ } else {
+ u.setRefLogIdent(author);
+ u.setRefLogMessage(getRefLogMessage(), false);
+ }
+ u.addCommand(commit);
+ u.execute(rw, NullProgressMonitor.INSTANCE);
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabase.java
new file mode 100644
index 0000000..dc60311
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabase.java
@@ -0,0 +1,337 @@
+/*
+ * 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.Ref.Storage.LOOSE;
+import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.lib.BatchRefUpdate;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Ref.Storage;
+import org.eclipse.jgit.lib.RefDatabase;
+import org.eclipse.jgit.lib.RefRename;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.SymbolicRef;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevTag;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.util.RefList;
+import org.eclipse.jgit.util.RefMap;
+
+/**
+ * Reference database backed by a {@link RefTree}.
+ * <p>
+ * The storage for RefTreeDatabase has two parts. The main part is a native Git
+ * tree object stored under the {@code refs/txn} namespace. To avoid cycles,
+ * references to {@code refs/txn} are not stored in that tree object, but
+ * instead in a "bootstrap" layer, which is a separate {@link RefDatabase} such
+ * as {@link org.eclipse.jgit.internal.storage.file.RefDirectory} using local
+ * reference files inside of {@code $GIT_DIR/refs}.
+ */
+public class RefTreeDatabase extends RefDatabase {
+ private final Repository repo;
+ private final RefDatabase bootstrap;
+ private final String txnCommitted;
+
+ @Nullable
+ private final String txnNamespace;
+ private volatile Scanner.Result refs;
+
+ /**
+ * Create a RefTreeDb for a repository.
+ *
+ * @param repo
+ * the repository using references in this database.
+ * @param bootstrap
+ * bootstrap reference database storing the references that
+ * anchor the {@link RefTree}.
+ */
+ public RefTreeDatabase(Repository repo, RefDatabase bootstrap) {
+ Config cfg = repo.getConfig();
+ String committed = cfg.getString("reftree", null, "committedRef"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (committed == null || committed.isEmpty()) {
+ committed = "refs/txn/committed"; //$NON-NLS-1$
+ }
+
+ this.repo = repo;
+ this.bootstrap = bootstrap;
+ this.txnNamespace = initNamespace(committed);
+ this.txnCommitted = committed;
+ }
+
+ /**
+ * Create a RefTreeDb for a repository.
+ *
+ * @param repo
+ * the repository using references in this database.
+ * @param bootstrap
+ * bootstrap reference database storing the references that
+ * anchor the {@link RefTree}.
+ * @param txnCommitted
+ * name of the bootstrap reference holding the committed RefTree.
+ */
+ public RefTreeDatabase(Repository repo, RefDatabase bootstrap,
+ String txnCommitted) {
+ this.repo = repo;
+ this.bootstrap = bootstrap;
+ this.txnNamespace = initNamespace(txnCommitted);
+ this.txnCommitted = txnCommitted;
+ }
+
+ private static String initNamespace(String committed) {
+ int s = committed.lastIndexOf('/');
+ if (s < 0) {
+ return null;
+ }
+ return committed.substring(0, s + 1); // Keep trailing '/'.
+ }
+
+ Repository getRepository() {
+ return repo;
+ }
+
+ /**
+ * @return the bootstrap reference database, which must be used to access
+ * {@link #getTxnCommitted()}, {@link #getTxnNamespace()}.
+ */
+ public RefDatabase getBootstrap() {
+ return bootstrap;
+ }
+
+ /** @return name of bootstrap reference anchoring committed RefTree. */
+ public String getTxnCommitted() {
+ return txnCommitted;
+ }
+
+ /**
+ * @return namespace used by bootstrap layer, e.g. {@code refs/txn/}.
+ * Always ends in {@code '/'}.
+ */
+ @Nullable
+ public String getTxnNamespace() {
+ return txnNamespace;
+ }
+
+ @Override
+ public void create() throws IOException {
+ bootstrap.create();
+ }
+
+ @Override
+ public boolean performsAtomicTransactions() {
+ return true;
+ }
+
+ @Override
+ public void refresh() {
+ bootstrap.refresh();
+ }
+
+ @Override
+ public void close() {
+ refs = null;
+ bootstrap.close();
+ }
+
+ @Override
+ public Ref getRef(String name) throws IOException {
+ return findRef(getRefs(ALL), name);
+ }
+
+ @Override
+ public Ref exactRef(String name) throws IOException {
+ if (conflictsWithBootstrap(name)) {
+ return null;
+ }
+
+ boolean partial = false;
+ Ref src = bootstrap.exactRef(txnCommitted);
+ Scanner.Result c = refs;
+ if (c == null || !c.refTreeId.equals(idOf(src))) {
+ c = Scanner.scanRefTree(repo, src, prefixOf(name), false);
+ partial = true;
+ }
+
+ Ref r = c.all.get(name);
+ if (r != null && r.isSymbolic()) {
+ r = c.sym.get(name);
+ if (partial && r.getObjectId() == null) {
+ // Attempting exactRef("HEAD") with partial scan will leave
+ // an unresolved symref as its target e.g. refs/heads/master
+ // was not read by the partial scan. Scan everything instead.
+ return getRefs(ALL).get(name);
+ }
+ }
+ return r;
+ }
+
+ private static String prefixOf(String name) {
+ int s = name.lastIndexOf('/');
+ if (s >= 0) {
+ return name.substring(0, s);
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ @Override
+ public Map<String, Ref> getRefs(String prefix) throws IOException {
+ if (!prefix.isEmpty() && prefix.charAt(prefix.length() - 1) != '/') {
+ return new HashMap<>(0);
+ }
+
+ Ref src = bootstrap.exactRef(txnCommitted);
+ Scanner.Result c = refs;
+ if (c == null || !c.refTreeId.equals(idOf(src))) {
+ c = Scanner.scanRefTree(repo, src, prefix, true);
+ if (prefix.isEmpty()) {
+ refs = c;
+ }
+ }
+ return new RefMap(prefix, RefList.<Ref> emptyList(), c.all, c.sym);
+ }
+
+ private static ObjectId idOf(@Nullable Ref src) {
+ return src != null && src.getObjectId() != null
+ ? src.getObjectId()
+ : ObjectId.zeroId();
+ }
+
+ @Override
+ public List<Ref> getAdditionalRefs() throws IOException {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Ref peel(Ref ref) throws IOException {
+ Ref i = ref.getLeaf();
+ ObjectId id = i.getObjectId();
+ if (i.isPeeled() || id == null) {
+ return ref;
+ }
+ try (RevWalk rw = new RevWalk(repo)) {
+ RevObject obj = rw.parseAny(id);
+ if (obj instanceof RevTag) {
+ ObjectId p = rw.peel(obj).copy();
+ i = new ObjectIdRef.PeeledTag(PACKED, i.getName(), id, p);
+ } else {
+ i = new ObjectIdRef.PeeledNonTag(PACKED, i.getName(), id);
+ }
+ }
+ return recreate(ref, i);
+ }
+
+ private static Ref recreate(Ref old, Ref leaf) {
+ if (old.isSymbolic()) {
+ Ref dst = recreate(old.getTarget(), leaf);
+ return new SymbolicRef(old.getName(), dst);
+ }
+ return leaf;
+ }
+
+ @Override
+ public boolean isNameConflicting(String name) throws IOException {
+ return conflictsWithBootstrap(name)
+ || !getConflictingNames(name).isEmpty();
+ }
+
+ @Override
+ public BatchRefUpdate newBatchUpdate() {
+ return new RefTreeBatch(this);
+ }
+
+ @Override
+ public RefUpdate newUpdate(String name, boolean detach) throws IOException {
+ if (conflictsWithBootstrap(name)) {
+ return new AlwaysFailUpdate(this, name);
+ }
+
+ Ref r = exactRef(name);
+ if (r == null) {
+ r = new ObjectIdRef.Unpeeled(Storage.NEW, name, null);
+ }
+
+ boolean detaching = detach && r.isSymbolic();
+ if (detaching) {
+ r = new ObjectIdRef.Unpeeled(LOOSE, name, r.getObjectId());
+ }
+
+ RefTreeUpdate u = new RefTreeUpdate(this, r);
+ if (detaching) {
+ u.setDetachingSymbolicRef();
+ }
+ return u;
+ }
+
+ @Override
+ public RefRename newRename(String fromName, String toName)
+ throws IOException {
+ RefUpdate from = newUpdate(fromName, true);
+ RefUpdate to = newUpdate(toName, true);
+ return new RefTreeRename(this, from, to);
+ }
+
+ boolean conflictsWithBootstrap(String name) {
+ if (txnNamespace != null && name.startsWith(txnNamespace)) {
+ return true;
+ } else if (txnCommitted.equals(name)) {
+ return true;
+ } else if (name.length() > txnCommitted.length()
+ && name.charAt(txnCommitted.length()) == '/'
+ && name.startsWith(txnCommitted)) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeNames.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeNames.java
new file mode 100644
index 0000000..239a745
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeNames.java
@@ -0,0 +1,124 @@
+/*
+ * 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.RefDatabase.ALL;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
+
+/** Magic reference name logic for RefTrees. */
+public class RefTreeNames {
+ /**
+ * Suffix used on a {@link RefTreeDatabase#getTxnNamespace()} for user data.
+ * <p>
+ * A {@link RefTreeDatabase}'s namespace may include a subspace (e.g.
+ * {@code "refs/txn/stage/"}) containing commit objects from the usual user
+ * portion of the repository (e.g. {@code "refs/heads/"}). These should be
+ * packed by the garbage collector alongside other user content rather than
+ * with the RefTree.
+ */
+ private static final String STAGE = "stage/"; //$NON-NLS-1$
+
+ /**
+ * Determine if the reference is likely to be a RefTree.
+ *
+ * @param refdb
+ * database instance.
+ * @param ref
+ * reference name.
+ * @return {@code true} if the reference is a RefTree.
+ */
+ public static boolean isRefTree(RefDatabase refdb, String ref) {
+ if (refdb instanceof RefTreeDatabase) {
+ RefTreeDatabase b = (RefTreeDatabase) refdb;
+ if (ref.equals(b.getTxnCommitted())) {
+ return true;
+ }
+
+ String namespace = b.getTxnNamespace();
+ if (namespace != null
+ && ref.startsWith(namespace)
+ && !ref.startsWith(namespace + STAGE)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Snapshot all references from a RefTreeDatabase and its bootstrap.
+ * <p>
+ * There may be name conflicts with multiple {@link Ref} objects containing
+ * the same name in the returned collection.
+ *
+ * @param refdb
+ * database instance.
+ * @return all known references.
+ * @throws IOException
+ * references cannot be enumerated.
+ */
+ public static Collection<Ref> allRefs(RefDatabase refdb)
+ throws IOException {
+ Collection<Ref> refs = refdb.getRefs(ALL).values();
+ if (!(refdb instanceof RefTreeDatabase)) {
+ return refs;
+ }
+
+ RefDatabase bootstrap = ((RefTreeDatabase) refdb).getBootstrap();
+ Collection<Ref> br = bootstrap.getRefs(ALL).values();
+ List<Ref> all = new ArrayList<>(refs.size() + br.size());
+ all.addAll(refs);
+ all.addAll(br);
+ return all;
+ }
+
+ private RefTreeNames() {
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeRename.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeRename.java
new file mode 100644
index 0000000..5fd7ecd
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeRename.java
@@ -0,0 +1,121 @@
+/*
+ * 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.RefUpdate.Result.REJECTED;
+import static org.eclipse.jgit.lib.RefUpdate.Result.RENAMED;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefRename;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.RefUpdate.Result;
+import org.eclipse.jgit.lib.SymbolicRef;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+/** Single reference rename to {@link RefTreeDatabase}. */
+class RefTreeRename extends RefRename {
+ private final RefTreeDatabase refdb;
+
+ RefTreeRename(RefTreeDatabase refdb, RefUpdate src, RefUpdate dst) {
+ super(src, dst);
+ this.refdb = refdb;
+ }
+
+ @Override
+ protected Result doRename() throws IOException {
+ try (RevWalk rw = new RevWalk(refdb.getRepository())) {
+ RefTreeBatch batch = new RefTreeBatch(refdb);
+ batch.setRefLogIdent(getRefLogIdent());
+ batch.setRefLogMessage(getRefLogMessage(), false);
+ batch.init(rw);
+
+ Ref head = batch.exactRef(rw.getObjectReader(), HEAD);
+ Ref oldRef = batch.exactRef(rw.getObjectReader(), source.getName());
+ if (oldRef == null) {
+ return REJECTED;
+ }
+
+ Ref newRef = asNew(oldRef);
+ List<Command> mv = new ArrayList<>(3);
+ mv.add(new Command(oldRef, null));
+ mv.add(new Command(null, newRef));
+ if (head != null && head.isSymbolic()
+ && head.getTarget().getName().equals(oldRef.getName())) {
+ mv.add(new Command(
+ head,
+ new SymbolicRef(head.getName(), newRef)));
+ }
+ batch.execute(rw, mv);
+ return RefTreeUpdate.translate(mv.get(1).getResult(), RENAMED);
+ }
+ }
+
+ private Ref asNew(Ref src) {
+ String name = destination.getName();
+ if (src.isSymbolic()) {
+ return new SymbolicRef(name, src.getTarget());
+ }
+
+ ObjectId peeled = src.getPeeledObjectId();
+ if (peeled != null) {
+ return new ObjectIdRef.PeeledTag(
+ src.getStorage(),
+ name,
+ src.getObjectId(),
+ peeled);
+ }
+
+ return new ObjectIdRef.PeeledNonTag(
+ src.getStorage(),
+ name,
+ src.getObjectId());
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeUpdate.java
new file mode 100644
index 0000000..8829c11
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeUpdate.java
@@ -0,0 +1,176 @@
+/*
+ * 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.Ref.Storage.LOOSE;
+import static org.eclipse.jgit.lib.Ref.Storage.NEW;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.SymbolicRef;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevTag;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
+
+/** Single reference update to {@link RefTreeDatabase}. */
+class RefTreeUpdate extends RefUpdate {
+ private final RefTreeDatabase refdb;
+ private RevWalk rw;
+ private RefTreeBatch batch;
+ private Ref oldRef;
+
+ RefTreeUpdate(RefTreeDatabase refdb, Ref ref) {
+ super(ref);
+ this.refdb = refdb;
+ setCheckConflicting(false); // Done automatically by doUpdate.
+ }
+
+ @Override
+ protected RefDatabase getRefDatabase() {
+ return refdb;
+ }
+
+ @Override
+ protected Repository getRepository() {
+ return refdb.getRepository();
+ }
+
+ @Override
+ protected boolean tryLock(boolean deref) throws IOException {
+ rw = new RevWalk(getRepository());
+ batch = new RefTreeBatch(refdb);
+ batch.init(rw);
+ oldRef = batch.exactRef(rw.getObjectReader(), getName());
+ if (oldRef != null && oldRef.getObjectId() != null) {
+ setOldObjectId(oldRef.getObjectId());
+ } else if (oldRef == null && getExpectedOldObjectId() != null) {
+ setOldObjectId(ObjectId.zeroId());
+ }
+ return true;
+ }
+
+ @Override
+ protected void unlock() {
+ batch = null;
+ if (rw != null) {
+ rw.close();
+ rw = null;
+ }
+ }
+
+ @Override
+ protected Result doUpdate(Result desiredResult) throws IOException {
+ return run(newRef(getName(), getNewObjectId()), desiredResult);
+ }
+
+ private Ref newRef(String name, ObjectId id)
+ throws MissingObjectException, IOException {
+ RevObject o = rw.parseAny(id);
+ if (o instanceof RevTag) {
+ RevObject p = rw.peel(o);
+ return new ObjectIdRef.PeeledTag(LOOSE, name, id, p.copy());
+ }
+ return new ObjectIdRef.PeeledNonTag(LOOSE, name, id);
+ }
+
+ @Override
+ protected Result doDelete(Result desiredResult) throws IOException {
+ return run(null, desiredResult);
+ }
+
+ @Override
+ protected Result doLink(String target) throws IOException {
+ Ref dst = new ObjectIdRef.Unpeeled(NEW, target, null);
+ SymbolicRef n = new SymbolicRef(getName(), dst);
+ Result desiredResult = getRef().getStorage() == NEW
+ ? Result.NEW
+ : Result.FORCED;
+ return run(n, desiredResult);
+ }
+
+ private Result run(@Nullable Ref newRef, Result desiredResult)
+ throws IOException {
+ Command c = new Command(oldRef, newRef);
+ batch.setRefLogIdent(getRefLogIdent());
+ batch.setRefLogMessage(getRefLogMessage(), isRefLogIncludingResult());
+ batch.execute(rw, Collections.singletonList(c));
+ return translate(c.getResult(), desiredResult);
+ }
+
+ static Result translate(ReceiveCommand.Result r, Result desiredResult) {
+ switch (r) {
+ case OK:
+ return desiredResult;
+
+ case LOCK_FAILURE:
+ return Result.LOCK_FAILURE;
+
+ case NOT_ATTEMPTED:
+ return Result.NOT_ATTEMPTED;
+
+ case REJECTED_MISSING_OBJECT:
+ return Result.IO_FAILURE;
+
+ case REJECTED_CURRENT_BRANCH:
+ return Result.REJECTED_CURRENT_BRANCH;
+
+ case REJECTED_OTHER_REASON:
+ case REJECTED_NOCREATE:
+ case REJECTED_NODELETE:
+ case REJECTED_NONFASTFORWARD:
+ default:
+ return Result.REJECTED;
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Scanner.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Scanner.java
new file mode 100644
index 0000000..d383abf
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/Scanner.java
@@ -0,0 +1,286 @@
+/*
+ * 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.RefDatabase.MAX_SYMBOLIC_REF_DEPTH;
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.eclipse.jgit.lib.Constants.R_REFS;
+import static org.eclipse.jgit.lib.Constants.encode;
+import static org.eclipse.jgit.lib.FileMode.TYPE_GITLINK;
+import static org.eclipse.jgit.lib.FileMode.TYPE_SYMLINK;
+import static org.eclipse.jgit.lib.FileMode.TYPE_TREE;
+import static org.eclipse.jgit.lib.Ref.Storage.NEW;
+import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.SymbolicRef;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.AbstractTreeIterator;
+import org.eclipse.jgit.treewalk.CanonicalTreeParser;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.util.Paths;
+import org.eclipse.jgit.util.RawParseUtils;
+import org.eclipse.jgit.util.RefList;
+
+/** A tree parser that extracts references from a {@link RefTree}. */
+class Scanner {
+ private static final int MAX_SYMLINK_BYTES = 10 << 10;
+ private static final byte[] BINARY_R_REFS = encode(R_REFS);
+ private static final byte[] REFS_DOT_DOT = encode("refs/.."); //$NON-NLS-1$
+
+ static class Result {
+ final ObjectId refTreeId;
+ final RefList<Ref> all;
+ final RefList<Ref> sym;
+
+ Result(ObjectId id, RefList<Ref> all, RefList<Ref> sym) {
+ this.refTreeId = id;
+ this.all = all;
+ this.sym = sym;
+ }
+ }
+
+ /**
+ * Scan a {@link RefTree} and parse entries into {@link Ref} instances.
+ *
+ * @param repo
+ * source repository containing the commit and tree objects that
+ * make up the RefTree.
+ * @param src
+ * bootstrap reference such as {@code refs/txn/committed} to read
+ * the reference tree tip from. The current ObjectId will be
+ * included in {@link Result#refTreeId}.
+ * @param prefix
+ * if non-empty a reference prefix to scan only a subdirectory.
+ * For example {@code prefix = "refs/heads/"} will limit the scan
+ * to only the {@code "heads"} directory of the RefTree, avoiding
+ * other directories like {@code "tags"}. Empty string reads all
+ * entries in the RefTree.
+ * @param recursive
+ * if true recurse into subdirectories of the reference tree;
+ * false to read only one level. Callers may use false during an
+ * implementation of {@code exactRef(String)} where only one
+ * reference is needed out of a specific subtree.
+ * @return sorted list of references after parsing.
+ * @throws IOException
+ * tree cannot be accessed from the repository.
+ */
+ static Result scanRefTree(Repository repo, @Nullable Ref src, String prefix,
+ boolean recursive) throws IOException {
+ RefList.Builder<Ref> all = new RefList.Builder<>();
+ RefList.Builder<Ref> sym = new RefList.Builder<>();
+
+ ObjectId srcId;
+ if (src != null && src.getObjectId() != null) {
+ try (ObjectReader reader = repo.newObjectReader()) {
+ srcId = src.getObjectId();
+ scan(reader, srcId, prefix, recursive, all, sym);
+ }
+ } else {
+ srcId = ObjectId.zeroId();
+ }
+
+ RefList<Ref> aList = all.toRefList();
+ for (int idx = 0; idx < sym.size();) {
+ Ref s = sym.get(idx);
+ Ref r = resolve(s, 0, aList);
+ if (r != null) {
+ sym.set(idx++, r);
+ } else {
+ // Remove broken symbolic reference, they don't exist.
+ sym.remove(idx);
+ int rm = aList.find(s.getName());
+ if (0 <= rm) {
+ aList = aList.remove(rm);
+ }
+ }
+ }
+ return new Result(srcId, aList, sym.toRefList());
+ }
+
+ private static void scan(ObjectReader reader, AnyObjectId srcId,
+ String prefix, boolean recursive,
+ RefList.Builder<Ref> all, RefList.Builder<Ref> sym)
+ throws IncorrectObjectTypeException, IOException {
+ CanonicalTreeParser p = createParserAtPath(reader, srcId, prefix);
+ if (p == null) {
+ return;
+ }
+
+ while (!p.eof()) {
+ int mode = p.getEntryRawMode();
+ if (mode == TYPE_TREE) {
+ if (recursive) {
+ p = p.createSubtreeIterator(reader);
+ } else {
+ p = p.next();
+ }
+ continue;
+ }
+
+ if (!curElementHasPeelSuffix(p)) {
+ Ref r = toRef(reader, mode, p);
+ if (r != null) {
+ all.add(r);
+ if (r.isSymbolic()) {
+ sym.add(r);
+ }
+ }
+ } else if (mode == TYPE_GITLINK) {
+ peel(all, p);
+ }
+ p = p.next();
+ }
+ }
+
+ private static CanonicalTreeParser createParserAtPath(ObjectReader reader,
+ AnyObjectId srcId, String prefix) throws IOException {
+ ObjectId root = toTree(reader, srcId);
+ if (prefix.isEmpty()) {
+ return new CanonicalTreeParser(BINARY_R_REFS, reader, root);
+ }
+
+ String dir = RefTree.refPath(Paths.stripTrailingSeparator(prefix));
+ TreeWalk tw = TreeWalk.forPath(reader, dir, root);
+ if (tw == null || !tw.isSubtree()) {
+ return null;
+ }
+
+ ObjectId id = tw.getObjectId(0);
+ return new CanonicalTreeParser(encode(prefix), reader, id);
+ }
+
+ private static Ref resolve(Ref ref, int depth, RefList<Ref> refs)
+ throws IOException {
+ if (!ref.isSymbolic()) {
+ return ref;
+ } else if (MAX_SYMBOLIC_REF_DEPTH <= depth) {
+ return null;
+ }
+
+ Ref r = refs.get(ref.getTarget().getName());
+ if (r == null) {
+ return ref;
+ }
+
+ Ref dst = resolve(r, depth + 1, refs);
+ if (dst == null) {
+ return null;
+ }
+ return new SymbolicRef(ref.getName(), dst);
+ }
+
+ @SuppressWarnings("resource")
+ private static RevTree toTree(ObjectReader reader, AnyObjectId id)
+ throws IOException {
+ return new RevWalk(reader).parseTree(id);
+ }
+
+ private static boolean curElementHasPeelSuffix(AbstractTreeIterator itr) {
+ int n = itr.getEntryPathLength();
+ byte[] c = itr.getEntryPathBuffer();
+ return n > 2 && c[n - 2] == ' ' && c[n - 1] == '^';
+ }
+
+ private static void peel(RefList.Builder<Ref> all, CanonicalTreeParser p) {
+ String name = refName(p, true);
+ for (int idx = all.size() - 1; 0 <= idx; idx--) {
+ Ref r = all.get(idx);
+ int cmp = r.getName().compareTo(name);
+ if (cmp == 0) {
+ all.set(idx, new ObjectIdRef.PeeledTag(PACKED, r.getName(),
+ r.getObjectId(), p.getEntryObjectId()));
+ break;
+ } else if (cmp < 0) {
+ // Stray peeled name without matching base name; skip entry.
+ break;
+ }
+ }
+ }
+
+ private static Ref toRef(ObjectReader reader, int mode,
+ CanonicalTreeParser p) throws IOException {
+ if (mode == TYPE_GITLINK) {
+ String name = refName(p, false);
+ ObjectId id = p.getEntryObjectId();
+ return new ObjectIdRef.PeeledNonTag(PACKED, name, id);
+
+ } else if (mode == TYPE_SYMLINK) {
+ ObjectId id = p.getEntryObjectId();
+ byte[] bin = reader.open(id, OBJ_BLOB)
+ .getCachedBytes(MAX_SYMLINK_BYTES);
+ String dst = RawParseUtils.decode(bin);
+ Ref trg = new ObjectIdRef.Unpeeled(NEW, dst, null);
+ String name = refName(p, false);
+ return new SymbolicRef(name, trg);
+ }
+ return null;
+ }
+
+ private static String refName(CanonicalTreeParser p, boolean peel) {
+ byte[] buf = p.getEntryPathBuffer();
+ int len = p.getEntryPathLength();
+ if (peel) {
+ len -= 2;
+ }
+ int ptr = 0;
+ if (RawParseUtils.match(buf, ptr, REFS_DOT_DOT) > 0) {
+ ptr = 7;
+ }
+ return RawParseUtils.decode(buf, ptr, len);
+ }
+
+ private Scanner() {
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
index 45dd7ee..670f9a9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
@@ -109,7 +109,8 @@
int pathStart = 8;
int lineEnd = RawParseUtils.nextLF(content, pathStart);
- if (content[lineEnd - 1] == '\n')
+ while (content[lineEnd - 1] == '\n' ||
+ (content[lineEnd - 1] == '\r' && SystemReader.getInstance().isWindows()))
lineEnd--;
if (lineEnd == pathStart)
throw new IOException(MessageFormat.format(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java
index 3c0e2c1..9ddff25 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java
@@ -125,7 +125,9 @@
* @param type
* the Git object type. See {@link Constants}.
* @return true if the value was not contained or able to be loaded.
+ * @deprecated use {@link #or} or {@link #addObject} instead.
*/
+ @Deprecated
boolean add(AnyObjectId objectId, int type);
/**
@@ -138,6 +140,18 @@
boolean contains(AnyObjectId objectId);
/**
+ * Adds the id to the bitmap.
+ *
+ * @param objectId
+ * the object ID
+ * @param type
+ * the Git object type. See {@link Constants}.
+ * @return the current builder.
+ * @since 4.2
+ */
+ BitmapBuilder addObject(AnyObjectId objectId, int type);
+
+ /**
* Remove the id from the bitmap.
*
* @param objectId
@@ -190,5 +204,14 @@
/** @return the number of elements in the bitmap. */
int cardinality();
+
+ /**
+ * Get the BitmapIndex for this BitmapBuilder.
+ *
+ * @return the BitmapIndex for this BitmapBuilder
+ *
+ * @since 4.2
+ */
+ BitmapIndex getBitmapIndex();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java
index cbb2f5b..7d52991 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BlobBasedConfig.java
@@ -79,7 +79,15 @@
public BlobBasedConfig(Config base, final byte[] blob)
throws ConfigInvalidException {
super(base);
- fromText(RawParseUtils.decode(blob));
+ final String decoded;
+ if (blob.length >= 3 && blob[0] == (byte) 0xEF
+ && blob[1] == (byte) 0xBB && blob[2] == (byte) 0xBF) {
+ decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET,
+ blob, 3, blob.length);
+ } else {
+ decoded = RawParseUtils.decode(blob);
+ }
+ fromText(decoded);
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
index 535a6ee..d30edaf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
@@ -273,6 +273,13 @@
public static final String INFO_EXCLUDE = "info/exclude";
/**
+ * Attributes-override-file
+ *
+ * @since 4.2
+ */
+ public static final String INFO_ATTRIBUTES = "info/attributes";
+
+ /**
* The system property that contains the system user name
*
* @since 3.6
@@ -363,6 +370,27 @@
*/
public static final String DOT_GIT_ATTRIBUTES = ".gitattributes";
+ /**
+ * Key for filters in .gitattributes
+ *
+ * @since 4.2
+ */
+ public static final String ATTR_FILTER = "filter";
+
+ /**
+ * clean command name, used to call filter driver
+ *
+ * @since 4.2
+ */
+ public static final String ATTR_FILTER_TYPE_CLEAN = "clean";
+
+ /**
+ * smudge command name, used to call filter driver
+ *
+ * @since 4.2
+ */
+ public static final String ATTR_FILTER_TYPE_SMUDGE = "smudge";
+
/** Name of the ignore file */
public static final String DOT_GIT_IGNORE = ".gitignore";
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileTreeEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileTreeEntry.java
deleted file mode 100644
index 6811417..0000000
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileTreeEntry.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006-2007, 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 java.io.IOException;
-
-/**
- * A representation of a file (blob) object in a {@link Tree}.
- *
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
- */
-@Deprecated
-public class FileTreeEntry extends TreeEntry {
- private FileMode mode;
-
- /**
- * Constructor for a File (blob) object.
- *
- * @param parent
- * The {@link Tree} holding this object (or null)
- * @param id
- * the SHA-1 of the blob (or null for a yet unhashed file)
- * @param nameUTF8
- * raw object name in the parent tree
- * @param execute
- * true if the executable flag is set
- */
- public FileTreeEntry(final Tree parent, final ObjectId id,
- final byte[] nameUTF8, final boolean execute) {
- super(parent, id, nameUTF8);
- setExecutable(execute);
- }
-
- public FileMode getMode() {
- return mode;
- }
-
- /**
- * @return true if this file is executable
- */
- public boolean isExecutable() {
- return getMode().equals(FileMode.EXECUTABLE_FILE);
- }
-
- /**
- * @param execute set/reset the executable flag
- */
- public void setExecutable(final boolean execute) {
- mode = execute ? FileMode.EXECUTABLE_FILE : FileMode.REGULAR_FILE;
- }
-
- /**
- * @return an {@link ObjectLoader} that will return the data
- * @throws IOException
- */
- public ObjectLoader openReader() throws IOException {
- return getRepository().open(getId(), Constants.OBJ_BLOB);
- }
-
- public String toString() {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(getId()));
- r.append(' ');
- r.append(isExecutable() ? 'X' : 'F');
- r.append(' ');
- r.append(getFullName());
- return r.toString();
- }
-}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GitlinkTreeEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GitlinkTreeEntry.java
deleted file mode 100644
index 936fd82..0000000
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GitlinkTreeEntry.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2009, Jonas Fonseca <fonseca@diku.dk>
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2007, 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;
-
-/**
- * A tree entry representing a gitlink entry used for submodules.
- *
- * Note. Java cannot really handle these as file system objects.
- *
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
- */
-@Deprecated
-public class GitlinkTreeEntry extends TreeEntry {
-
- /**
- * Construct a {@link GitlinkTreeEntry} with the specified name and SHA-1 in
- * the specified parent
- *
- * @param parent
- * @param id
- * @param nameUTF8
- */
- public GitlinkTreeEntry(final Tree parent, final ObjectId id,
- final byte[] nameUTF8) {
- super(parent, id, nameUTF8);
- }
-
- public FileMode getMode() {
- return FileMode.GITLINK;
- }
-
- @Override
- public String toString() {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(getId()));
- r.append(" G "); //$NON-NLS-1$
- r.append(getFullName());
- return r.toString();
- }
-}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
index 3fde2f9..9e474f8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -74,6 +74,7 @@
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.WorkingTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
import org.eclipse.jgit.treewalk.filter.IndexDiffFilter;
import org.eclipse.jgit.treewalk.filter.SkipWorkTreeFilter;
@@ -403,6 +404,7 @@
dirCache = repository.readDirCache();
try (TreeWalk treeWalk = new TreeWalk(repository)) {
+ treeWalk.setOperationType(OperationType.CHECKIN_OP);
treeWalk.setRecursive(true);
// add the trees (tree, dirchache, workdir)
if (tree != null)
@@ -411,6 +413,7 @@
treeWalk.addTree(new EmptyTreeIterator());
treeWalk.addTree(new DirCacheIterator(dirCache));
treeWalk.addTree(initialWorkingTreeIterator);
+ initialWorkingTreeIterator.setDirCacheIterator(treeWalk, 1);
Collection<TreeFilter> filters = new ArrayList<TreeFilter>(4);
if (monitor != null) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
index a7a67a8..0b5efd7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
@@ -44,21 +44,58 @@
package org.eclipse.jgit.lib;
-import static org.eclipse.jgit.util.RawParseUtils.match;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH;
+import static org.eclipse.jgit.lib.Constants.OBJ_BAD;
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
+import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
+import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.BAD_DATE;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.BAD_EMAIL;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.BAD_OBJECT_SHA1;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.BAD_PARENT_SHA1;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.BAD_TIMEZONE;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.BAD_TREE_SHA1;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.BAD_UTF8;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.DUPLICATE_ENTRIES;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.EMPTY_NAME;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.FULL_PATHNAME;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOT;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOTDOT;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOTGIT;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.MISSING_AUTHOR;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.MISSING_COMMITTER;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.MISSING_EMAIL;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.MISSING_OBJECT;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.MISSING_SPACE_BEFORE_DATE;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.MISSING_TAG_ENTRY;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.MISSING_TREE;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.MISSING_TYPE_ENTRY;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.NULL_SHA1;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.TREE_NOT_SORTED;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.UNKNOWN_TYPE;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.WIN32_BAD_NAME;
+import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE;
+import static org.eclipse.jgit.util.Paths.compare;
+import static org.eclipse.jgit.util.Paths.compareSameName;
import static org.eclipse.jgit.util.RawParseUtils.nextLF;
import static org.eclipse.jgit.util.RawParseUtils.parseBase10;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.text.MessageFormat;
+import java.text.Normalizer;
+import java.util.EnumSet;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.util.MutableInteger;
import org.eclipse.jgit.util.RawParseUtils;
+import org.eclipse.jgit.util.StringUtils;
/**
* Verifies that an object is formatted correctly.
@@ -99,31 +136,135 @@
/** Header "tagger " */
public static final byte[] tagger = Constants.encodeASCII("tagger "); //$NON-NLS-1$
+ /**
+ * Potential issues identified by the checker.
+ *
+ * @since 4.2
+ */
+ public enum ErrorType {
+ // @formatter:off
+ // These names match git-core so that fsck section keys also match.
+ /***/ NULL_SHA1,
+ /***/ DUPLICATE_ENTRIES,
+ /***/ TREE_NOT_SORTED,
+ /***/ ZERO_PADDED_FILEMODE,
+ /***/ EMPTY_NAME,
+ /***/ FULL_PATHNAME,
+ /***/ HAS_DOT,
+ /***/ HAS_DOTDOT,
+ /***/ HAS_DOTGIT,
+ /***/ BAD_OBJECT_SHA1,
+ /***/ BAD_PARENT_SHA1,
+ /***/ BAD_TREE_SHA1,
+ /***/ MISSING_AUTHOR,
+ /***/ MISSING_COMMITTER,
+ /***/ MISSING_OBJECT,
+ /***/ MISSING_TREE,
+ /***/ MISSING_TYPE_ENTRY,
+ /***/ MISSING_TAG_ENTRY,
+ /***/ BAD_DATE,
+ /***/ BAD_EMAIL,
+ /***/ BAD_TIMEZONE,
+ /***/ MISSING_EMAIL,
+ /***/ MISSING_SPACE_BEFORE_DATE,
+ /***/ UNKNOWN_TYPE,
+
+ // These are unique to JGit.
+ /***/ WIN32_BAD_NAME,
+ /***/ BAD_UTF8;
+ // @formatter:on
+
+ /** @return camelCaseVersion of the name. */
+ public String getMessageId() {
+ String n = name();
+ StringBuilder r = new StringBuilder(n.length());
+ for (int i = 0; i < n.length(); i++) {
+ char c = n.charAt(i);
+ if (c != '_') {
+ r.append(StringUtils.toLowerCase(c));
+ } else {
+ r.append(n.charAt(++i));
+ }
+ }
+ return r.toString();
+ }
+ }
+
private final MutableObjectId tempId = new MutableObjectId();
+ private final MutableInteger bufPtr = new MutableInteger();
- private final MutableInteger ptrout = new MutableInteger();
-
- private boolean allowZeroMode;
-
+ private EnumSet<ErrorType> errors = EnumSet.allOf(ErrorType.class);
+ private ObjectIdSet skipList;
private boolean allowInvalidPersonIdent;
private boolean windows;
private boolean macosx;
/**
+ * Enable accepting specific malformed (but not horribly broken) objects.
+ *
+ * @param objects
+ * collection of object names known to be broken in a non-fatal
+ * way that should be ignored by the checker.
+ * @return {@code this}
+ * @since 4.2
+ */
+ public ObjectChecker setSkipList(@Nullable ObjectIdSet objects) {
+ skipList = objects;
+ return this;
+ }
+
+ /**
+ * Configure error types to be ignored across all objects.
+ *
+ * @param ids
+ * error types to ignore. The caller's set is copied.
+ * @return {@code this}
+ * @since 4.2
+ */
+ public ObjectChecker setIgnore(@Nullable Set<ErrorType> ids) {
+ errors = EnumSet.allOf(ErrorType.class);
+ if (ids != null) {
+ errors.removeAll(ids);
+ }
+ return this;
+ }
+
+ /**
+ * Add message type to be ignored across all objects.
+ *
+ * @param id
+ * error type to ignore.
+ * @param ignore
+ * true to ignore this error; false to treat the error as an
+ * error and throw.
+ * @return {@code this}
+ * @since 4.2
+ */
+ public ObjectChecker setIgnore(ErrorType id, boolean ignore) {
+ if (ignore) {
+ errors.remove(id);
+ } else {
+ errors.add(id);
+ }
+ return this;
+ }
+
+ /**
* Enable accepting leading zero mode in tree entries.
* <p>
* Some broken Git libraries generated leading zeros in the mode part of
* tree entries. This is technically incorrect but gracefully allowed by
* git-core. JGit rejects such trees by default, but may need to accept
* them on broken histories.
+ * <p>
+ * Same as {@code setIgnore(ZERO_PADDED_FILEMODE, allow)}.
*
* @param allow allow leading zero mode.
* @return {@code this}.
* @since 3.4
*/
public ObjectChecker setAllowLeadingZeroFileMode(boolean allow) {
- allowZeroMode = allow;
- return this;
+ return setIgnore(ZERO_PADDED_FILEMODE, allow);
}
/**
@@ -184,62 +325,117 @@
* @throws CorruptObjectException
* if an error is identified.
*/
- public void check(final int objType, final byte[] raw)
+ public void check(int objType, byte[] raw)
+ throws CorruptObjectException {
+ check(idFor(objType, raw), objType, raw);
+ }
+
+ /**
+ * Check an object for parsing errors.
+ *
+ * @param id
+ * identify of the object being checked.
+ * @param objType
+ * type of the object. Must be a valid object type code in
+ * {@link Constants}.
+ * @param raw
+ * the raw data which comprises the object. This should be in the
+ * canonical format (that is the format used to generate the
+ * ObjectId of the object). The array is never modified.
+ * @throws CorruptObjectException
+ * if an error is identified.
+ * @since 4.2
+ */
+ public void check(@Nullable AnyObjectId id, int objType, byte[] raw)
throws CorruptObjectException {
switch (objType) {
- case Constants.OBJ_COMMIT:
- checkCommit(raw);
+ case OBJ_COMMIT:
+ checkCommit(id, raw);
break;
- case Constants.OBJ_TAG:
- checkTag(raw);
+ case OBJ_TAG:
+ checkTag(id, raw);
break;
- case Constants.OBJ_TREE:
- checkTree(raw);
+ case OBJ_TREE:
+ checkTree(id, raw);
break;
- case Constants.OBJ_BLOB:
+ case OBJ_BLOB:
checkBlob(raw);
break;
default:
- throw new CorruptObjectException(MessageFormat.format(
+ report(UNKNOWN_TYPE, id, MessageFormat.format(
JGitText.get().corruptObjectInvalidType2,
Integer.valueOf(objType)));
}
}
- private int id(final byte[] raw, final int ptr) {
+ private boolean checkId(byte[] raw) {
+ int p = bufPtr.value;
try {
- tempId.fromString(raw, ptr);
- return ptr + Constants.OBJECT_ID_STRING_LENGTH;
+ tempId.fromString(raw, p);
} catch (IllegalArgumentException e) {
- return -1;
+ bufPtr.value = nextLF(raw, p);
+ return false;
}
+
+ p += OBJECT_ID_STRING_LENGTH;
+ if (raw[p] == '\n') {
+ bufPtr.value = p + 1;
+ return true;
+ }
+ bufPtr.value = nextLF(raw, p);
+ return false;
}
- private int personIdent(final byte[] raw, int ptr) {
- if (allowInvalidPersonIdent)
- return nextLF(raw, ptr) - 1;
+ private void checkPersonIdent(byte[] raw, @Nullable AnyObjectId id)
+ throws CorruptObjectException {
+ if (allowInvalidPersonIdent) {
+ bufPtr.value = nextLF(raw, bufPtr.value);
+ return;
+ }
- final int emailB = nextLF(raw, ptr, '<');
- if (emailB == ptr || raw[emailB - 1] != '<')
- return -1;
+ final int emailB = nextLF(raw, bufPtr.value, '<');
+ if (emailB == bufPtr.value || raw[emailB - 1] != '<') {
+ report(MISSING_EMAIL, id, JGitText.get().corruptObjectMissingEmail);
+ bufPtr.value = nextLF(raw, bufPtr.value);
+ return;
+ }
final int emailE = nextLF(raw, emailB, '>');
- if (emailE == emailB || raw[emailE - 1] != '>')
- return -1;
- if (emailE == raw.length || raw[emailE] != ' ')
- return -1;
+ if (emailE == emailB || raw[emailE - 1] != '>') {
+ report(BAD_EMAIL, id, JGitText.get().corruptObjectBadEmail);
+ bufPtr.value = nextLF(raw, bufPtr.value);
+ return;
+ }
+ if (emailE == raw.length || raw[emailE] != ' ') {
+ report(MISSING_SPACE_BEFORE_DATE, id,
+ JGitText.get().corruptObjectBadDate);
+ bufPtr.value = nextLF(raw, bufPtr.value);
+ return;
+ }
- parseBase10(raw, emailE + 1, ptrout); // when
- ptr = ptrout.value;
- if (emailE + 1 == ptr)
- return -1;
- if (ptr == raw.length || raw[ptr] != ' ')
- return -1;
+ parseBase10(raw, emailE + 1, bufPtr); // when
+ if (emailE + 1 == bufPtr.value || bufPtr.value == raw.length
+ || raw[bufPtr.value] != ' ') {
+ report(BAD_DATE, id, JGitText.get().corruptObjectBadDate);
+ bufPtr.value = nextLF(raw, bufPtr.value);
+ return;
+ }
- parseBase10(raw, ptr + 1, ptrout); // tz offset
- if (ptr + 1 == ptrout.value)
- return -1;
- return ptrout.value;
+ int p = bufPtr.value + 1;
+ parseBase10(raw, p, bufPtr); // tz offset
+ if (p == bufPtr.value) {
+ report(BAD_TIMEZONE, id, JGitText.get().corruptObjectBadTimezone);
+ bufPtr.value = nextLF(raw, bufPtr.value);
+ return;
+ }
+
+ p = bufPtr.value;
+ if (raw[p] == '\n') {
+ bufPtr.value = p + 1;
+ } else {
+ report(BAD_TIMEZONE, id, JGitText.get().corruptObjectBadTimezone);
+ bufPtr.value = nextLF(raw, p);
+ }
}
/**
@@ -250,36 +446,50 @@
* @throws CorruptObjectException
* if any error was detected.
*/
- public void checkCommit(final byte[] raw) throws CorruptObjectException {
- int ptr = 0;
+ public void checkCommit(byte[] raw) throws CorruptObjectException {
+ checkCommit(idFor(OBJ_COMMIT, raw), raw);
+ }
- if ((ptr = match(raw, ptr, tree)) < 0)
- throw new CorruptObjectException(
- JGitText.get().corruptObjectNotreeHeader);
- if ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\n')
- throw new CorruptObjectException(
- JGitText.get().corruptObjectInvalidTree);
+ /**
+ * Check a commit for errors.
+ *
+ * @param id
+ * identity of the object being checked.
+ * @param raw
+ * the commit data. The array is never modified.
+ * @throws CorruptObjectException
+ * if any error was detected.
+ * @since 4.2
+ */
+ public void checkCommit(@Nullable AnyObjectId id, byte[] raw)
+ throws CorruptObjectException {
+ bufPtr.value = 0;
- while (match(raw, ptr, parent) >= 0) {
- ptr += parent.length;
- if ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\n')
- throw new CorruptObjectException(
- JGitText.get().corruptObjectInvalidParent);
+ if (!match(raw, tree)) {
+ report(MISSING_TREE, id, JGitText.get().corruptObjectNotreeHeader);
+ } else if (!checkId(raw)) {
+ report(BAD_TREE_SHA1, id, JGitText.get().corruptObjectInvalidTree);
}
- if ((ptr = match(raw, ptr, author)) < 0)
- throw new CorruptObjectException(
- JGitText.get().corruptObjectNoAuthor);
- if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
- throw new CorruptObjectException(
- JGitText.get().corruptObjectInvalidAuthor);
+ while (match(raw, parent)) {
+ if (!checkId(raw)) {
+ report(BAD_PARENT_SHA1, id,
+ JGitText.get().corruptObjectInvalidParent);
+ }
+ }
- if ((ptr = match(raw, ptr, committer)) < 0)
- throw new CorruptObjectException(
+ if (match(raw, author)) {
+ checkPersonIdent(raw, id);
+ } else {
+ report(MISSING_AUTHOR, id, JGitText.get().corruptObjectNoAuthor);
+ }
+
+ if (match(raw, committer)) {
+ checkPersonIdent(raw, id);
+ } else {
+ report(MISSING_COMMITTER, id,
JGitText.get().corruptObjectNoCommitter);
- if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
- throw new CorruptObjectException(
- JGitText.get().corruptObjectInvalidCommitter);
+ }
}
/**
@@ -290,50 +500,47 @@
* @throws CorruptObjectException
* if any error was detected.
*/
- public void checkTag(final byte[] raw) throws CorruptObjectException {
- int ptr = 0;
+ public void checkTag(byte[] raw) throws CorruptObjectException {
+ checkTag(idFor(OBJ_TAG, raw), raw);
+ }
- if ((ptr = match(raw, ptr, object)) < 0)
- throw new CorruptObjectException(
+ /**
+ * Check an annotated tag for errors.
+ *
+ * @param id
+ * identity of the object being checked.
+ * @param raw
+ * the tag data. The array is never modified.
+ * @throws CorruptObjectException
+ * if any error was detected.
+ * @since 4.2
+ */
+ public void checkTag(@Nullable AnyObjectId id, byte[] raw)
+ throws CorruptObjectException {
+ bufPtr.value = 0;
+ if (!match(raw, object)) {
+ report(MISSING_OBJECT, id,
JGitText.get().corruptObjectNoObjectHeader);
- if ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\n')
- throw new CorruptObjectException(
+ } else if (!checkId(raw)) {
+ report(BAD_OBJECT_SHA1, id,
JGitText.get().corruptObjectInvalidObject);
+ }
- if ((ptr = match(raw, ptr, type)) < 0)
- throw new CorruptObjectException(
+ if (!match(raw, type)) {
+ report(MISSING_TYPE_ENTRY, id,
JGitText.get().corruptObjectNoTypeHeader);
- ptr = nextLF(raw, ptr);
+ }
+ bufPtr.value = nextLF(raw, bufPtr.value);
- if ((ptr = match(raw, ptr, tag)) < 0)
- throw new CorruptObjectException(
+ if (!match(raw, tag)) {
+ report(MISSING_TAG_ENTRY, id,
JGitText.get().corruptObjectNoTagHeader);
- ptr = nextLF(raw, ptr);
-
- if ((ptr = match(raw, ptr, tagger)) > 0) {
- if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
- throw new CorruptObjectException(
- JGitText.get().corruptObjectInvalidTagger);
}
- }
+ bufPtr.value = nextLF(raw, bufPtr.value);
- private static int lastPathChar(final int mode) {
- return FileMode.TREE.equals(mode) ? '/' : '\0';
- }
-
- private static int pathCompare(final byte[] raw, int aPos, final int aEnd,
- final int aMode, int bPos, final int bEnd, final int bMode) {
- while (aPos < aEnd && bPos < bEnd) {
- final int cmp = (raw[aPos++] & 0xff) - (raw[bPos++] & 0xff);
- if (cmp != 0)
- return cmp;
+ if (match(raw, tagger)) {
+ checkPersonIdent(raw, id);
}
-
- if (aPos < aEnd)
- return (raw[aPos] & 0xff) - lastPathChar(bMode);
- if (bPos < bEnd)
- return lastPathChar(aMode) - (raw[bPos] & 0xff);
- return 0;
}
private static boolean duplicateName(final byte[] raw,
@@ -363,8 +570,9 @@
if (nextNamePos + 1 == nextPtr)
return false;
- final int cmp = pathCompare(raw, thisNamePos, thisNameEnd,
- FileMode.TREE.getBits(), nextNamePos, nextPtr - 1, nextMode);
+ int cmp = compareSameName(
+ raw, thisNamePos, thisNameEnd,
+ raw, nextNamePos, nextPtr - 1, nextMode);
if (cmp < 0)
return false;
else if (cmp == 0)
@@ -382,7 +590,23 @@
* @throws CorruptObjectException
* if any error was detected.
*/
- public void checkTree(final byte[] raw) throws CorruptObjectException {
+ public void checkTree(byte[] raw) throws CorruptObjectException {
+ checkTree(idFor(OBJ_TREE, raw), raw);
+ }
+
+ /**
+ * Check a canonical formatted tree for errors.
+ *
+ * @param id
+ * identity of the object being checked.
+ * @param raw
+ * the raw tree data. The array is never modified.
+ * @throws CorruptObjectException
+ * if any error was detected.
+ * @since 4.2
+ */
+ public void checkTree(@Nullable AnyObjectId id, byte[] raw)
+ throws CorruptObjectException {
final int sz = raw.length;
int ptr = 0;
int lastNameB = 0, lastNameE = 0, lastMode = 0;
@@ -393,74 +617,90 @@
while (ptr < sz) {
int thisMode = 0;
for (;;) {
- if (ptr == sz)
+ if (ptr == sz) {
throw new CorruptObjectException(
JGitText.get().corruptObjectTruncatedInMode);
+ }
final byte c = raw[ptr++];
if (' ' == c)
break;
- if (c < '0' || c > '7')
+ if (c < '0' || c > '7') {
throw new CorruptObjectException(
JGitText.get().corruptObjectInvalidModeChar);
- if (thisMode == 0 && c == '0' && !allowZeroMode)
- throw new CorruptObjectException(
+ }
+ if (thisMode == 0 && c == '0') {
+ report(ZERO_PADDED_FILEMODE, id,
JGitText.get().corruptObjectInvalidModeStartsZero);
+ }
thisMode <<= 3;
thisMode += c - '0';
}
- if (FileMode.fromBits(thisMode).getObjectType() == Constants.OBJ_BAD)
+ if (FileMode.fromBits(thisMode).getObjectType() == OBJ_BAD) {
throw new CorruptObjectException(MessageFormat.format(
JGitText.get().corruptObjectInvalidMode2,
Integer.valueOf(thisMode)));
+ }
final int thisNameB = ptr;
- ptr = scanPathSegment(raw, ptr, sz);
- if (ptr == sz || raw[ptr] != 0)
+ ptr = scanPathSegment(raw, ptr, sz, id);
+ if (ptr == sz || raw[ptr] != 0) {
throw new CorruptObjectException(
JGitText.get().corruptObjectTruncatedInName);
- checkPathSegment2(raw, thisNameB, ptr);
+ }
+ checkPathSegment2(raw, thisNameB, ptr, id);
if (normalized != null) {
- if (!normalized.add(normalize(raw, thisNameB, ptr)))
- throw new CorruptObjectException(
+ if (!normalized.add(normalize(raw, thisNameB, ptr))) {
+ report(DUPLICATE_ENTRIES, id,
JGitText.get().corruptObjectDuplicateEntryNames);
- } else if (duplicateName(raw, thisNameB, ptr))
- throw new CorruptObjectException(
+ }
+ } else if (duplicateName(raw, thisNameB, ptr)) {
+ report(DUPLICATE_ENTRIES, id,
JGitText.get().corruptObjectDuplicateEntryNames);
+ }
if (lastNameB != 0) {
- final int cmp = pathCompare(raw, lastNameB, lastNameE,
- lastMode, thisNameB, ptr, thisMode);
- if (cmp > 0)
- throw new CorruptObjectException(
+ int cmp = compare(
+ raw, lastNameB, lastNameE, lastMode,
+ raw, thisNameB, ptr, thisMode);
+ if (cmp > 0) {
+ report(TREE_NOT_SORTED, id,
JGitText.get().corruptObjectIncorrectSorting);
+ }
}
lastNameB = thisNameB;
lastNameE = ptr;
lastMode = thisMode;
- ptr += 1 + Constants.OBJECT_ID_LENGTH;
- if (ptr > sz)
+ ptr += 1 + OBJECT_ID_LENGTH;
+ if (ptr > sz) {
throw new CorruptObjectException(
JGitText.get().corruptObjectTruncatedInObjectId);
+ }
+ if (ObjectId.zeroId().compareTo(raw, ptr - OBJECT_ID_LENGTH) == 0) {
+ report(NULL_SHA1, id, JGitText.get().corruptObjectZeroId);
+ }
}
}
- private int scanPathSegment(byte[] raw, int ptr, int end)
- throws CorruptObjectException {
+ private int scanPathSegment(byte[] raw, int ptr, int end,
+ @Nullable AnyObjectId id) throws CorruptObjectException {
for (; ptr < end; ptr++) {
byte c = raw[ptr];
- if (c == 0)
+ if (c == 0) {
return ptr;
- if (c == '/')
- throw new CorruptObjectException(
+ }
+ if (c == '/') {
+ report(FULL_PATHNAME, id,
JGitText.get().corruptObjectNameContainsSlash);
+ }
if (windows && isInvalidOnWindows(c)) {
- if (c > 31)
+ if (c > 31) {
throw new CorruptObjectException(String.format(
JGitText.get().corruptObjectNameContainsChar,
Byte.valueOf(c)));
+ }
throw new CorruptObjectException(String.format(
JGitText.get().corruptObjectNameContainsByte,
Integer.valueOf(c & 0xff)));
@@ -469,6 +709,26 @@
return ptr;
}
+ @SuppressWarnings("resource")
+ @Nullable
+ private ObjectId idFor(int objType, byte[] raw) {
+ if (skipList != null) {
+ return new ObjectInserter.Formatter().idFor(objType, raw);
+ }
+ return null;
+ }
+
+ private void report(@NonNull ErrorType err, @Nullable AnyObjectId id,
+ String why) throws CorruptObjectException {
+ if (errors.contains(err)
+ && (id == null || skipList == null || !skipList.contains(id))) {
+ if (id != null) {
+ throw new CorruptObjectException(err, id, why);
+ }
+ throw new CorruptObjectException(why);
+ }
+ }
+
/**
* Check tree path entry for validity.
* <p>
@@ -519,73 +779,82 @@
*/
public void checkPathSegment(byte[] raw, int ptr, int end)
throws CorruptObjectException {
- int e = scanPathSegment(raw, ptr, end);
+ int e = scanPathSegment(raw, ptr, end, null);
if (e < end && raw[e] == 0)
throw new CorruptObjectException(
JGitText.get().corruptObjectNameContainsNullByte);
- checkPathSegment2(raw, ptr, end);
+ checkPathSegment2(raw, ptr, end, null);
}
- private void checkPathSegment2(byte[] raw, int ptr, int end)
- throws CorruptObjectException {
- if (ptr == end)
- throw new CorruptObjectException(
- JGitText.get().corruptObjectNameZeroLength);
+ private void checkPathSegment2(byte[] raw, int ptr, int end,
+ @Nullable AnyObjectId id) throws CorruptObjectException {
+ if (ptr == end) {
+ report(EMPTY_NAME, id, JGitText.get().corruptObjectNameZeroLength);
+ return;
+ }
+
if (raw[ptr] == '.') {
switch (end - ptr) {
case 1:
- throw new CorruptObjectException(
- JGitText.get().corruptObjectNameDot);
+ report(HAS_DOT, id, JGitText.get().corruptObjectNameDot);
+ break;
case 2:
- if (raw[ptr + 1] == '.')
- throw new CorruptObjectException(
+ if (raw[ptr + 1] == '.') {
+ report(HAS_DOTDOT, id,
JGitText.get().corruptObjectNameDotDot);
+ }
break;
case 4:
- if (isGit(raw, ptr + 1))
- throw new CorruptObjectException(String.format(
+ if (isGit(raw, ptr + 1)) {
+ report(HAS_DOTGIT, id, String.format(
JGitText.get().corruptObjectInvalidName,
RawParseUtils.decode(raw, ptr, end)));
+ }
break;
default:
- if (end - ptr > 4 && isNormalizedGit(raw, ptr + 1, end))
- throw new CorruptObjectException(String.format(
+ if (end - ptr > 4 && isNormalizedGit(raw, ptr + 1, end)) {
+ report(HAS_DOTGIT, id, String.format(
JGitText.get().corruptObjectInvalidName,
RawParseUtils.decode(raw, ptr, end)));
+ }
}
} else if (isGitTilde1(raw, ptr, end)) {
- throw new CorruptObjectException(String.format(
+ report(HAS_DOTGIT, id, String.format(
JGitText.get().corruptObjectInvalidName,
RawParseUtils.decode(raw, ptr, end)));
}
-
- if (macosx && isMacHFSGit(raw, ptr, end))
- throw new CorruptObjectException(String.format(
+ if (macosx && isMacHFSGit(raw, ptr, end, id)) {
+ report(HAS_DOTGIT, id, String.format(
JGitText.get().corruptObjectInvalidNameIgnorableUnicode,
RawParseUtils.decode(raw, ptr, end)));
+ }
if (windows) {
// Windows ignores space and dot at end of file name.
- if (raw[end - 1] == ' ' || raw[end - 1] == '.')
- throw new CorruptObjectException(String.format(
+ if (raw[end - 1] == ' ' || raw[end - 1] == '.') {
+ report(WIN32_BAD_NAME, id, String.format(
JGitText.get().corruptObjectInvalidNameEnd,
Character.valueOf(((char) raw[end - 1]))));
- if (end - ptr >= 3)
- checkNotWindowsDevice(raw, ptr, end);
+ }
+ if (end - ptr >= 3) {
+ checkNotWindowsDevice(raw, ptr, end, id);
+ }
}
}
// Mac's HFS+ folds permutations of ".git" and Unicode ignorable characters
// to ".git" therefore we should prevent such names
- private static boolean isMacHFSGit(byte[] raw, int ptr, int end)
- throws CorruptObjectException {
+ private boolean isMacHFSGit(byte[] raw, int ptr, int end,
+ @Nullable AnyObjectId id) throws CorruptObjectException {
boolean ignorable = false;
byte[] git = new byte[] { '.', 'g', 'i', 't' };
int g = 0;
while (ptr < end) {
switch (raw[ptr]) {
case (byte) 0xe2: // http://www.utf8-chartable.de/unicode-utf8-table.pl?start=8192
- checkTruncatedIgnorableUTF8(raw, ptr, end);
+ if (!checkTruncatedIgnorableUTF8(raw, ptr, end, id)) {
+ return false;
+ }
switch (raw[ptr + 1]) {
case (byte) 0x80:
switch (raw[ptr + 2]) {
@@ -622,7 +891,9 @@
return false;
}
case (byte) 0xef: // http://www.utf8-chartable.de/unicode-utf8-table.pl?start=65024
- checkTruncatedIgnorableUTF8(raw, ptr, end);
+ if (!checkTruncatedIgnorableUTF8(raw, ptr, end, id)) {
+ return false;
+ }
// U+FEFF 0xefbbbf ZERO WIDTH NO-BREAK SPACE
if ((raw[ptr + 1] == (byte) 0xbb)
&& (raw[ptr + 2] == (byte) 0xbf)) {
@@ -643,12 +914,15 @@
return false;
}
- private static void checkTruncatedIgnorableUTF8(byte[] raw, int ptr, int end)
- throws CorruptObjectException {
- if ((ptr + 2) >= end)
- throw new CorruptObjectException(MessageFormat.format(
+ private boolean checkTruncatedIgnorableUTF8(byte[] raw, int ptr, int end,
+ @Nullable AnyObjectId id) throws CorruptObjectException {
+ if ((ptr + 2) >= end) {
+ report(BAD_UTF8, id, MessageFormat.format(
JGitText.get().corruptObjectInvalidNameInvalidUtf8,
toHexString(raw, ptr, end)));
+ return false;
+ }
+ return true;
}
private static String toHexString(byte[] raw, int ptr, int end) {
@@ -658,33 +932,36 @@
return b.toString();
}
- private static void checkNotWindowsDevice(byte[] raw, int ptr, int end)
- throws CorruptObjectException {
+ private void checkNotWindowsDevice(byte[] raw, int ptr, int end,
+ @Nullable AnyObjectId id) throws CorruptObjectException {
switch (toLower(raw[ptr])) {
case 'a': // AUX
if (end - ptr >= 3
&& toLower(raw[ptr + 1]) == 'u'
&& toLower(raw[ptr + 2]) == 'x'
- && (end - ptr == 3 || raw[ptr + 3] == '.'))
- throw new CorruptObjectException(
+ && (end - ptr == 3 || raw[ptr + 3] == '.')) {
+ report(WIN32_BAD_NAME, id,
JGitText.get().corruptObjectInvalidNameAux);
+ }
break;
case 'c': // CON, COM[1-9]
if (end - ptr >= 3
&& toLower(raw[ptr + 2]) == 'n'
&& toLower(raw[ptr + 1]) == 'o'
- && (end - ptr == 3 || raw[ptr + 3] == '.'))
- throw new CorruptObjectException(
+ && (end - ptr == 3 || raw[ptr + 3] == '.')) {
+ report(WIN32_BAD_NAME, id,
JGitText.get().corruptObjectInvalidNameCon);
+ }
if (end - ptr >= 4
&& toLower(raw[ptr + 2]) == 'm'
&& toLower(raw[ptr + 1]) == 'o'
&& isPositiveDigit(raw[ptr + 3])
- && (end - ptr == 4 || raw[ptr + 4] == '.'))
- throw new CorruptObjectException(String.format(
+ && (end - ptr == 4 || raw[ptr + 4] == '.')) {
+ report(WIN32_BAD_NAME, id, String.format(
JGitText.get().corruptObjectInvalidNameCom,
Character.valueOf(((char) raw[ptr + 3]))));
+ }
break;
case 'l': // LPT[1-9]
@@ -692,28 +969,31 @@
&& toLower(raw[ptr + 1]) == 'p'
&& toLower(raw[ptr + 2]) == 't'
&& isPositiveDigit(raw[ptr + 3])
- && (end - ptr == 4 || raw[ptr + 4] == '.'))
- throw new CorruptObjectException(String.format(
+ && (end - ptr == 4 || raw[ptr + 4] == '.')) {
+ report(WIN32_BAD_NAME, id, String.format(
JGitText.get().corruptObjectInvalidNameLpt,
Character.valueOf(((char) raw[ptr + 3]))));
+ }
break;
case 'n': // NUL
if (end - ptr >= 3
&& toLower(raw[ptr + 1]) == 'u'
&& toLower(raw[ptr + 2]) == 'l'
- && (end - ptr == 3 || raw[ptr + 3] == '.'))
- throw new CorruptObjectException(
+ && (end - ptr == 3 || raw[ptr + 3] == '.')) {
+ report(WIN32_BAD_NAME, id,
JGitText.get().corruptObjectInvalidNameNul);
+ }
break;
case 'p': // PRN
if (end - ptr >= 3
&& toLower(raw[ptr + 1]) == 'r'
&& toLower(raw[ptr + 2]) == 'n'
- && (end - ptr == 3 || raw[ptr + 3] == '.'))
- throw new CorruptObjectException(
+ && (end - ptr == 3 || raw[ptr + 3] == '.')) {
+ report(WIN32_BAD_NAME, id,
JGitText.get().corruptObjectInvalidNamePrn);
+ }
break;
}
}
@@ -766,6 +1046,15 @@
return false;
}
+ private boolean match(byte[] b, byte[] src) {
+ int r = RawParseUtils.match(b, bufPtr.value, src);
+ if (r < 0) {
+ return false;
+ }
+ bufPtr.value = r;
+ return true;
+ }
+
private static char toLower(byte b) {
if ('A' <= b && b <= 'Z')
return (char) (b + ('a' - 'A'));
@@ -790,58 +1079,6 @@
private String normalize(byte[] raw, int ptr, int end) {
String n = RawParseUtils.decode(raw, ptr, end).toLowerCase(Locale.US);
- return macosx ? Normalizer.normalize(n) : n;
- }
-
- private static class Normalizer {
- // TODO Simplify invocation to Normalizer after dropping Java 5.
- private static final Method normalize;
- private static final Object nfc;
- static {
- Method method;
- Object formNfc;
- try {
- Class<?> formClazz = Class.forName("java.text.Normalizer$Form"); //$NON-NLS-1$
- formNfc = formClazz.getField("NFC").get(null); //$NON-NLS-1$
- method = Class.forName("java.text.Normalizer") //$NON-NLS-1$
- .getMethod("normalize", CharSequence.class, formClazz); //$NON-NLS-1$
- } catch (ClassNotFoundException e) {
- method = null;
- formNfc = null;
- } catch (NoSuchFieldException e) {
- method = null;
- formNfc = null;
- } catch (NoSuchMethodException e) {
- method = null;
- formNfc = null;
- } catch (SecurityException e) {
- method = null;
- formNfc = null;
- } catch (IllegalArgumentException e) {
- method = null;
- formNfc = null;
- } catch (IllegalAccessException e) {
- method = null;
- formNfc = null;
- }
- normalize = method;
- nfc = formNfc;
- }
-
- static String normalize(String in) {
- if (normalize == null)
- return in;
- try {
- return (String) normalize.invoke(null, in, nfc);
- } catch (IllegalAccessException e) {
- return in;
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof RuntimeException)
- throw (RuntimeException) e.getCause();
- if (e.getCause() instanceof Error)
- throw (Error) e.getCause();
- return in;
- }
- }
+ return macosx ? Normalizer.normalize(n, Normalizer.Form.NFC) : n;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
index c9b483f..442261c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
@@ -67,8 +67,8 @@
* @param <V>
* type of subclass of ObjectId that will be stored in the map.
*/
-public class ObjectIdOwnerMap<V extends ObjectIdOwnerMap.Entry> implements
- Iterable<V> {
+public class ObjectIdOwnerMap<V extends ObjectIdOwnerMap.Entry>
+ implements Iterable<V>, ObjectIdSet {
/** Size of the initial directory, will grow as necessary. */
private static final int INITIAL_DIRECTORY = 1024;
@@ -83,16 +83,16 @@
* The low {@link #bits} of the SHA-1 are used to select the segment from
* this directory. Each segment is constant sized at 2^SEGMENT_BITS.
*/
- private V[][] directory;
+ V[][] directory;
/** Total number of objects in this map. */
- private int size;
+ int size;
/** The map doubles in capacity when {@link #size} reaches this target. */
private int grow;
/** Number of low bits used to form the index into {@link #directory}. */
- private int bits;
+ int bits;
/** Low bit mask to index into {@link #directory}, {@code 2^bits-1}. */
private int mask;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java
index f481c77..c286f5e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdRef.java
@@ -44,6 +44,9 @@
package org.eclipse.jgit.lib;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
+
/** A {@link Ref} that points directly at an {@link ObjectId}. */
public abstract class ObjectIdRef implements Ref {
/** Any reference whose peeled value is not yet known. */
@@ -56,13 +59,15 @@
* @param name
* name of this ref.
* @param id
- * current value of the ref. May be null to indicate a ref
- * that does not exist yet.
+ * current value of the ref. May be {@code null} to indicate
+ * a ref that does not exist yet.
*/
- public Unpeeled(Storage st, String name, ObjectId id) {
+ public Unpeeled(@NonNull Storage st, @NonNull String name,
+ @Nullable ObjectId id) {
super(st, name, id);
}
+ @Nullable
public ObjectId getPeeledObjectId() {
return null;
}
@@ -88,11 +93,13 @@
* @param p
* the first non-tag object that tag {@code id} points to.
*/
- public PeeledTag(Storage st, String name, ObjectId id, ObjectId p) {
+ public PeeledTag(@NonNull Storage st, @NonNull String name,
+ @Nullable ObjectId id, @NonNull ObjectId p) {
super(st, name, id);
peeledObjectId = p;
}
+ @NonNull
public ObjectId getPeeledObjectId() {
return peeledObjectId;
}
@@ -112,13 +119,15 @@
* @param name
* name of this ref.
* @param id
- * current value of the ref. May be null to indicate a ref
- * that does not exist yet.
+ * current value of the ref. May be {@code null} to indicate
+ * a ref that does not exist yet.
*/
- public PeeledNonTag(Storage st, String name, ObjectId id) {
+ public PeeledNonTag(@NonNull Storage st, @NonNull String name,
+ @Nullable ObjectId id) {
super(st, name, id);
}
+ @Nullable
public ObjectId getPeeledObjectId() {
return null;
}
@@ -142,15 +151,17 @@
* @param name
* name of this ref.
* @param id
- * current value of the ref. May be null to indicate a ref that
- * does not exist yet.
+ * current value of the ref. May be {@code null} to indicate a
+ * ref that does not exist yet.
*/
- protected ObjectIdRef(Storage st, String name, ObjectId id) {
+ protected ObjectIdRef(@NonNull Storage st, @NonNull String name,
+ @Nullable ObjectId id) {
this.name = name;
this.storage = st;
this.objectId = id;
}
+ @NonNull
public String getName() {
return name;
}
@@ -159,22 +170,27 @@
return false;
}
+ @NonNull
public Ref getLeaf() {
return this;
}
+ @NonNull
public Ref getTarget() {
return this;
}
+ @Nullable
public ObjectId getObjectId() {
return objectId;
}
+ @NonNull
public Storage getStorage() {
return storage;
}
+ @NonNull
@Override
public String toString() {
StringBuilder r = new StringBuilder();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSet.java
similarity index 61%
rename from org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
rename to org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSet.java
index c7e41bc..0b58484 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymlinkTreeEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSet.java
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006-2007, Shawn O. Pearce <spearce@spearce.org>
+ * 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
@@ -45,41 +44,21 @@
package org.eclipse.jgit.lib;
/**
- * A tree entry representing a symbolic link.
+ * Simple set of ObjectIds.
+ * <p>
+ * Usually backed by a read-only data structure such as
+ * {@link org.eclipse.jgit.internal.storage.file.PackIndex}. Mutable types like
+ * {@link ObjectIdOwnerMap} also implement the interface by checking keys.
*
- * Note. Java cannot really handle these as file system objects.
- *
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
+ * @since 4.2
*/
-@Deprecated
-public class SymlinkTreeEntry extends TreeEntry {
-
+public interface ObjectIdSet {
/**
- * Construct a {@link SymlinkTreeEntry} with the specified name and SHA-1 in
- * the specified parent
+ * Returns true if the objectId is contained within the collection.
*
- * @param parent
- * @param id
- * @param nameUTF8
+ * @param objectId
+ * the objectId to find
+ * @return whether the collection contains the objectId.
*/
- public SymlinkTreeEntry(final Tree parent, final ObjectId id,
- final byte[] nameUTF8) {
- super(parent, id, nameUTF8);
- }
-
- public FileMode getMode() {
- return FileMode.SYMLINK;
- }
-
- public String toString() {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(getId()));
- r.append(" S "); //$NON-NLS-1$
- r.append(getFullName());
- return r.toString();
- }
+ boolean contains(AnyObjectId objectId);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java
index 69972dc..faed64b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java
@@ -60,16 +60,17 @@
* @param <V>
* type of subclass of ObjectId that will be stored in the map.
*/
-public class ObjectIdSubclassMap<V extends ObjectId> implements Iterable<V> {
+public class ObjectIdSubclassMap<V extends ObjectId>
+ implements Iterable<V>, ObjectIdSet {
private static final int INITIAL_TABLE_SIZE = 2048;
- private int size;
+ int size;
private int grow;
private int mask;
- private V[] table;
+ V[] table;
/** Create an empty map. */
public ObjectIdSubclassMap() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
index f119c44..a78a90f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Ref.java
@@ -43,6 +43,9 @@
package org.eclipse.jgit.lib;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
+
/**
* Pairing of a name and the {@link ObjectId} it currently has.
* <p>
@@ -126,6 +129,7 @@
*
* @return name of this ref.
*/
+ @NonNull
public String getName();
/**
@@ -156,6 +160,7 @@
*
* @return the reference that actually stores the ObjectId value.
*/
+ @NonNull
public abstract Ref getLeaf();
/**
@@ -170,22 +175,27 @@
*
* @return the target reference, or {@code this}.
*/
+ @NonNull
public abstract Ref getTarget();
/**
* Cached value of this ref.
*
- * @return the value of this ref at the last time we read it.
+ * @return the value of this ref at the last time we read it. May be
+ * {@code null} to indicate a ref that does not exist yet or a
+ * symbolic ref pointing to an unborn branch.
*/
+ @Nullable
public abstract ObjectId getObjectId();
/**
* Cached value of <code>ref^{}</code> (the ref peeled to commit).
*
* @return if this ref is an annotated tag the id of the commit (or tree or
- * blob) that the annotated tag refers to; null if this ref does not
- * refer to an annotated tag.
+ * blob) that the annotated tag refers to; {@code null} if this ref
+ * does not refer to an annotated tag.
*/
+ @Nullable
public abstract ObjectId getPeeledObjectId();
/**
@@ -201,5 +211,6 @@
*
* @return type of ref.
*/
+ @NonNull
public abstract Storage getStorage();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
index b62033c..c0c3862 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java
@@ -51,6 +51,9 @@
import java.util.List;
import java.util.Map;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
+
/**
* Abstraction of name to {@link ObjectId} mapping.
* <p>
@@ -79,8 +82,10 @@
* <p>
* If the reference is nested deeper than this depth, the implementation
* should either fail, or at least claim the reference does not exist.
+ *
+ * @since 4.2
*/
- protected static final int MAX_SYMBOLIC_REF_DEPTH = 5;
+ public static final int MAX_SYMBOLIC_REF_DEPTH = 5;
/** Magic value for {@link #getRefs(String)} to return all references. */
public static final String ALL = "";//$NON-NLS-1$
@@ -132,6 +137,7 @@
* @since 2.3
* @see #isNameConflicting(String)
*/
+ @NonNull
public Collection<String> getConflictingNames(String name)
throws IOException {
Map<String, Ref> allRefs = getRefs(ALL);
@@ -169,6 +175,7 @@
* @throws IOException
* the reference space cannot be accessed.
*/
+ @NonNull
public abstract RefUpdate newUpdate(String name, boolean detach)
throws IOException;
@@ -183,6 +190,7 @@
* @throws IOException
* the reference space cannot be accessed.
*/
+ @NonNull
public abstract RefRename newRename(String fromName, String toName)
throws IOException;
@@ -193,6 +201,7 @@
*
* @return a new batch update object.
*/
+ @NonNull
public BatchRefUpdate newBatchUpdate() {
return new BatchRefUpdate(this);
}
@@ -223,6 +232,7 @@
* @throws IOException
* the reference space cannot be accessed.
*/
+ @Nullable
public abstract Ref getRef(String name) throws IOException;
/**
@@ -238,6 +248,7 @@
* the reference space cannot be accessed.
* @since 4.1
*/
+ @Nullable
public Ref exactRef(String name) throws IOException {
Ref ref = getRef(name);
if (ref == null || !name.equals(ref.getName())) {
@@ -261,6 +272,7 @@
* the reference space cannot be accessed.
* @since 4.1
*/
+ @NonNull
public Map<String, Ref> exactRef(String... refs) throws IOException {
Map<String, Ref> result = new HashMap<>(refs.length);
for (String name : refs) {
@@ -285,6 +297,7 @@
* the reference space cannot be accessed.
* @since 4.1
*/
+ @Nullable
public Ref firstExactRef(String... refs) throws IOException {
for (String name : refs) {
Ref ref = exactRef(name);
@@ -308,6 +321,7 @@
* @throws IOException
* the reference space cannot be accessed.
*/
+ @NonNull
public abstract Map<String, Ref> getRefs(String prefix) throws IOException;
/**
@@ -322,6 +336,7 @@
* @throws IOException
* the reference space cannot be accessed.
*/
+ @NonNull
public abstract List<Ref> getAdditionalRefs() throws IOException;
/**
@@ -338,10 +353,11 @@
* @return {@code ref} if {@code ref.isPeeled()} is true; otherwise a new
* Ref object representing the same data as Ref, but isPeeled() will
* be true and getPeeledObjectId() will contain the peeled object
- * (or null).
+ * (or {@code null}).
* @throws IOException
* the reference space or object space cannot be accessed.
*/
+ @NonNull
public abstract Ref peel(Ref ref) throws IOException;
/**
@@ -365,9 +381,10 @@
* @param name
* short name of ref to find, e.g. "master" to find
* "refs/heads/master" in map.
- * @return The first ref matching the name, or null if not found.
+ * @return The first ref matching the name, or {@code null} if not found.
* @since 3.4
*/
+ @Nullable
public static Ref findRef(Map<String, Ref> map, String name) {
for (String prefix : SEARCH_PATH) {
String fullname = prefix + name;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
index 05eb311..59f852b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
@@ -170,7 +170,7 @@
*/
protected boolean needToUpdateHEAD() throws IOException {
Ref head = source.getRefDatabase().getRef(Constants.HEAD);
- if (head.isSymbolic()) {
+ if (head != null && head.isSymbolic()) {
head = head.getTarget();
return head.getName().equals(source.getName());
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java
index 747fa62..3a02b22 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefWriter.java
@@ -119,13 +119,20 @@
continue;
}
- r.getObjectId().copyTo(tmp, w);
+ ObjectId objectId = r.getObjectId();
+ if (objectId == null) {
+ // Symrefs to unborn branches aren't advertised in the info/refs
+ // file.
+ continue;
+ }
+ objectId.copyTo(tmp, w);
w.write('\t');
w.write(r.getName());
w.write('\n');
- if (r.getPeeledObjectId() != null) {
- r.getPeeledObjectId().copyTo(tmp, w);
+ ObjectId peeledObjectId = r.getPeeledObjectId();
+ if (peeledObjectId != null) {
+ peeledObjectId.copyTo(tmp, w);
w.write('\t');
w.write(r.getName());
w.write("^{}\n"); //$NON-NLS-1$
@@ -167,14 +174,21 @@
if (r.getStorage() != Ref.Storage.PACKED)
continue;
- r.getObjectId().copyTo(tmp, w);
+ ObjectId objectId = r.getObjectId();
+ if (objectId == null) {
+ // A packed ref cannot be a symref, let alone a symref
+ // to an unborn branch.
+ throw new NullPointerException();
+ }
+ objectId.copyTo(tmp, w);
w.write(' ');
w.write(r.getName());
w.write('\n');
- if (r.getPeeledObjectId() != null) {
+ ObjectId peeledObjectId = r.getPeeledObjectId();
+ if (peeledObjectId != null) {
w.write('^');
- r.getPeeledObjectId().copyTo(tmp, w);
+ peeledObjectId.copyTo(tmp, w);
w.write('\n');
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
index d4c72cb..f826613 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -64,6 +64,9 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.attributes.AttributesNodeProvider;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.errors.AmbiguousObjectException;
import org.eclipse.jgit.errors.CorruptObjectException;
@@ -137,6 +140,7 @@
}
/** @return listeners observing only events on this repository. */
+ @NonNull
public ListenerList getListenerList() {
return myListeners;
}
@@ -181,7 +185,16 @@
*/
public abstract void create(boolean bare) throws IOException;
- /** @return local metadata directory; null if repository isn't local. */
+ /**
+ * @return local metadata directory; {@code null} if repository isn't local.
+ */
+ /*
+ * TODO This method should be annotated as Nullable, because in some
+ * specific configurations metadata is not located in the local file system
+ * (for example in memory databases). In "usual" repositories this
+ * annotation would only cause compiler errors at places where the actual
+ * directory can never be null.
+ */
public File getDirectory() {
return gitDir;
}
@@ -189,28 +202,52 @@
/**
* @return the object database which stores this repository's data.
*/
+ @NonNull
public abstract ObjectDatabase getObjectDatabase();
/** @return a new inserter to create objects in {@link #getObjectDatabase()} */
+ @NonNull
public ObjectInserter newObjectInserter() {
return getObjectDatabase().newInserter();
}
/** @return a new reader to read objects from {@link #getObjectDatabase()} */
+ @NonNull
public ObjectReader newObjectReader() {
return getObjectDatabase().newReader();
}
/** @return the reference database which stores the reference namespace. */
+ @NonNull
public abstract RefDatabase getRefDatabase();
/**
* @return the configuration of this repository
*/
+ @NonNull
public abstract StoredConfig getConfig();
/**
- * @return the used file system abstraction
+ * @return a new {@link AttributesNodeProvider}. This
+ * {@link AttributesNodeProvider} is lazy loaded only once. It means
+ * that it will not be updated after loading. Prefer creating new
+ * instance for each use.
+ * @since 4.2
+ */
+ @NonNull
+ public abstract AttributesNodeProvider createAttributesNodeProvider();
+
+
+ /**
+ * @return the used file system abstraction, or or {@code null} if
+ * repository isn't local.
+ */
+ /*
+ * TODO This method should be annotated as Nullable, because in some
+ * specific configurations metadata is not located in the local file system
+ * (for example in memory databases). In "usual" repositories this
+ * annotation would only cause compiler errors at places where the actual
+ * directory can never be null.
*/
public FS getFS() {
return fs;
@@ -244,6 +281,7 @@
* @throws IOException
* the object store cannot be accessed.
*/
+ @NonNull
public ObjectLoader open(final AnyObjectId objectId)
throws MissingObjectException, IOException {
return getObjectDatabase().open(objectId);
@@ -271,6 +309,7 @@
* @throws IOException
* the object store cannot be accessed.
*/
+ @NonNull
public ObjectLoader open(AnyObjectId objectId, int typeHint)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
@@ -289,6 +328,7 @@
* a symbolic ref was passed in and could not be resolved back
* to the base ref, as the symbolic ref could not be read.
*/
+ @NonNull
public RefUpdate updateRef(final String ref) throws IOException {
return updateRef(ref, false);
}
@@ -307,6 +347,7 @@
* a symbolic ref was passed in and could not be resolved back
* to the base ref, as the symbolic ref could not be read.
*/
+ @NonNull
public RefUpdate updateRef(final String ref, final boolean detach) throws IOException {
return getRefDatabase().newUpdate(ref, detach);
}
@@ -323,6 +364,7 @@
* the rename could not be performed.
*
*/
+ @NonNull
public RefRename renameRef(final String fromRef, final String toRef) throws IOException {
return getRefDatabase().newRename(fromRef, toRef);
}
@@ -362,7 +404,8 @@
*
* @param revstr
* A git object references expression
- * @return an ObjectId or null if revstr can't be resolved to any ObjectId
+ * @return an ObjectId or {@code null} if revstr can't be resolved to any
+ * ObjectId
* @throws AmbiguousObjectException
* {@code revstr} contains an abbreviated ObjectId and this
* repository contains more than one object which match to the
@@ -376,6 +419,7 @@
* @throws IOException
* on serious errors
*/
+ @Nullable
public ObjectId resolve(final String revstr)
throws AmbiguousObjectException, IncorrectObjectTypeException,
RevisionSyntaxException, IOException {
@@ -397,10 +441,12 @@
* expects a branch or revision id.
*
* @param revstr
- * @return object id or ref name from resolved expression
+ * @return object id or ref name from resolved expression or {@code null} if
+ * given expression cannot be resolved
* @throws AmbiguousObjectException
* @throws IOException
*/
+ @Nullable
public String simplify(final String revstr)
throws AmbiguousObjectException, IOException {
try (RevWalk rw = new RevWalk(this)) {
@@ -414,6 +460,7 @@
}
}
+ @Nullable
private Object resolve(final RevWalk rw, final String revstr)
throws IOException {
char[] revChars = revstr.toCharArray();
@@ -717,11 +764,13 @@
return true;
}
+ @Nullable
private RevObject parseSimple(RevWalk rw, String revstr) throws IOException {
ObjectId id = resolveSimple(revstr);
return id != null ? rw.parseAny(id) : null;
}
+ @Nullable
private ObjectId resolveSimple(final String revstr) throws IOException {
if (ObjectId.isId(revstr))
return ObjectId.fromString(revstr);
@@ -749,6 +798,7 @@
return null;
}
+ @Nullable
private String resolveReflogCheckout(int checkoutNo)
throws IOException {
ReflogReader reader = getReflogReader(Constants.HEAD);
@@ -790,6 +840,7 @@
return rw.parseCommit(entry.getNewId());
}
+ @Nullable
private ObjectId resolveAbbreviation(final String revstr) throws IOException,
AmbiguousObjectException {
AbbreviatedObjectId id = AbbreviatedObjectId.fromString(revstr);
@@ -826,11 +877,13 @@
getRefDatabase().close();
}
+ @NonNull
@SuppressWarnings("nls")
public String toString() {
String desc;
- if (getDirectory() != null)
- desc = getDirectory().getPath();
+ File directory = getDirectory();
+ if (directory != null)
+ desc = directory.getPath();
else
desc = getClass().getSimpleName() + "-" //$NON-NLS-1$
+ System.identityHashCode(this);
@@ -850,18 +903,24 @@
* current ObjectId in hexadecimal string format.
*
* @return name of current branch (for example {@code refs/heads/master}),
- * an ObjectId in hex format if the current branch is detached,
- * or null if the repository is corrupt and has no HEAD reference.
+ * an ObjectId in hex format if the current branch is detached, or
+ * {@code null} if the repository is corrupt and has no HEAD
+ * reference.
* @throws IOException
*/
+ @Nullable
public String getFullBranch() throws IOException {
Ref head = getRef(Constants.HEAD);
- if (head == null)
+ if (head == null) {
return null;
- if (head.isSymbolic())
+ }
+ if (head.isSymbolic()) {
return head.getTarget().getName();
- if (head.getObjectId() != null)
- return head.getObjectId().name();
+ }
+ ObjectId objectId = head.getObjectId();
+ if (objectId != null) {
+ return objectId.name();
+ }
return null;
}
@@ -872,16 +931,17 @@
* leading prefix {@code refs/heads/} is removed from the reference before
* it is returned to the caller.
*
- * @return name of current branch (for example {@code master}), an
- * ObjectId in hex format if the current branch is detached,
- * or null if the repository is corrupt and has no HEAD reference.
+ * @return name of current branch (for example {@code master}), an ObjectId
+ * in hex format if the current branch is detached, or {@code null}
+ * if the repository is corrupt and has no HEAD reference.
* @throws IOException
*/
+ @Nullable
public String getBranch() throws IOException {
String name = getFullBranch();
if (name != null)
return shortenRefName(name);
- return name;
+ return null;
}
/**
@@ -894,6 +954,7 @@
*
* @return unmodifiable collection of other known objects.
*/
+ @NonNull
public Set<ObjectId> getAdditionalHaves() {
return Collections.emptySet();
}
@@ -905,16 +966,53 @@
* the name of the ref to lookup. May be a short-hand form, e.g.
* "master" which is is automatically expanded to
* "refs/heads/master" if "refs/heads/master" already exists.
- * @return the Ref with the given name, or null if it does not exist
+ * @return the Ref with the given name, or {@code null} if it does not exist
* @throws IOException
+ * @deprecated Use {@link #exactRef(String)} or {@link #findRef(String)}
+ * instead.
*/
+ @Deprecated
+ @Nullable
public Ref getRef(final String name) throws IOException {
+ return findRef(name);
+ }
+
+ /**
+ * Get a ref by name.
+ *
+ * @param name
+ * the name of the ref to lookup. Must not be a short-hand
+ * form; e.g., "master" is not automatically expanded to
+ * "refs/heads/master".
+ * @return the Ref with the given name, or {@code null} if it does not exist
+ * @throws IOException
+ * @since 4.2
+ */
+ @Nullable
+ public Ref exactRef(String name) throws IOException {
+ return getRefDatabase().exactRef(name);
+ }
+
+ /**
+ * Search for a ref by (possibly abbreviated) name.
+ *
+ * @param name
+ * the name of the ref to lookup. May be a short-hand form, e.g.
+ * "master" which is is automatically expanded to
+ * "refs/heads/master" if "refs/heads/master" already exists.
+ * @return the Ref with the given name, or {@code null} if it does not exist
+ * @throws IOException
+ * @since 4.2
+ */
+ @Nullable
+ public Ref findRef(String name) throws IOException {
return getRefDatabase().getRef(name);
}
/**
* @return mutable map of all known refs (heads, tags, remotes).
*/
+ @NonNull
public Map<String, Ref> getAllRefs() {
try {
return getRefDatabase().getRefs(RefDatabase.ALL);
@@ -928,6 +1026,7 @@
* of the entry contains the ref with the full tag name
* ("refs/tags/v1.0").
*/
+ @NonNull
public Map<String, Ref> getTags() {
try {
return getRefDatabase().getRefs(Constants.R_TAGS);
@@ -949,6 +1048,7 @@
* will be true and getPeeledObjectId will contain the peeled object
* (or null).
*/
+ @NonNull
public Ref peel(final Ref ref) {
try {
return getRefDatabase().peel(ref);
@@ -963,6 +1063,7 @@
/**
* @return a map with all objects referenced by a peeled ref.
*/
+ @NonNull
public Map<AnyObjectId, Set<Ref>> getAllRefsByPeeledObjectId() {
Map<String, Ref> allRefs = getAllRefs();
Map<AnyObjectId, Set<Ref>> ret = new HashMap<AnyObjectId, Set<Ref>>(allRefs.size());
@@ -987,11 +1088,13 @@
}
/**
- * @return the index file location
+ * @return the index file location or {@code null} if repository isn't
+ * local.
* @throws NoWorkTreeException
* if this is bare, which implies it has no working directory.
* See {@link #isBare()}.
*/
+ @NonNull
public File getIndexFile() throws NoWorkTreeException {
if (isBare())
throw new NoWorkTreeException();
@@ -1016,6 +1119,7 @@
* the index file is using a format or extension that this
* library does not support.
*/
+ @NonNull
public DirCache readDirCache() throws NoWorkTreeException,
CorruptObjectException, IOException {
return DirCache.read(this);
@@ -1040,6 +1144,7 @@
* the index file is using a format or extension that this
* library does not support.
*/
+ @NonNull
public DirCache lockDirCache() throws NoWorkTreeException,
CorruptObjectException, IOException {
// we want DirCache to inform us so that we can inform registered
@@ -1065,6 +1170,7 @@
/**
* @return an important state
*/
+ @NonNull
public RepositoryState getRepositoryState() {
if (isBare() || getDirectory() == null)
return RepositoryState.BARE;
@@ -1207,6 +1313,7 @@
* @return normalized repository relative path or the empty
* string if the file is not relative to the work directory.
*/
+ @NonNull
public static String stripWorkDir(File workDir, File file) {
final String filePath = file.getPath();
final String workDirPath = workDir.getPath();
@@ -1241,6 +1348,7 @@
* if this is bare, which implies it has no working directory.
* See {@link #isBare()}.
*/
+ @NonNull
public File getWorkTree() throws NoWorkTreeException {
if (isBare())
throw new NoWorkTreeException();
@@ -1264,6 +1372,7 @@
*
* @return a more user friendly ref name
*/
+ @NonNull
public static String shortenRefName(String refName) {
if (refName.startsWith(Constants.R_HEADS))
return refName.substring(Constants.R_HEADS.length());
@@ -1279,9 +1388,10 @@
* @return the remote branch name part of <code>refName</code>, i.e. without
* the <code>refs/remotes/<remote></code> prefix, if
* <code>refName</code> represents a remote tracking branch;
- * otherwise null.
+ * otherwise {@code null}.
* @since 3.4
*/
+ @Nullable
public String shortenRemoteBranchName(String refName) {
for (String remote : getRemoteNames()) {
String remotePrefix = Constants.R_REMOTES + remote + "/"; //$NON-NLS-1$
@@ -1296,9 +1406,10 @@
* @return the remote name part of <code>refName</code>, i.e. without the
* <code>refs/remotes/<remote></code> prefix, if
* <code>refName</code> represents a remote tracking branch;
- * otherwise null.
+ * otherwise {@code null}.
* @since 3.4
*/
+ @Nullable
public String getRemoteName(String refName) {
for (String remote : getRemoteNames()) {
String remotePrefix = Constants.R_REMOTES + remote + "/"; //$NON-NLS-1$
@@ -1310,12 +1421,13 @@
/**
* @param refName
- * @return a {@link ReflogReader} for the supplied refname, or null if the
- * named ref does not exist.
+ * @return a {@link ReflogReader} for the supplied refname, or {@code null}
+ * if the named ref does not exist.
* @throws IOException
* the ref could not be accessed.
* @since 3.0
*/
+ @Nullable
public abstract ReflogReader getReflogReader(String refName)
throws IOException;
@@ -1331,6 +1443,7 @@
* if this is bare, which implies it has no working directory.
* See {@link #isBare()}.
*/
+ @Nullable
public String readMergeCommitMsg() throws IOException, NoWorkTreeException {
return readCommitMsgFile(Constants.MERGE_MSG);
}
@@ -1365,6 +1478,7 @@
* See {@link #isBare()}.
* @since 4.0
*/
+ @Nullable
public String readCommitEditMsg() throws IOException, NoWorkTreeException {
return readCommitMsgFile(Constants.COMMIT_EDITMSG);
}
@@ -1399,6 +1513,7 @@
* if this is bare, which implies it has no working directory.
* See {@link #isBare()}.
*/
+ @Nullable
public List<ObjectId> readMergeHeads() throws IOException, NoWorkTreeException {
if (isBare() || getDirectory() == null)
throw new NoWorkTreeException();
@@ -1442,6 +1557,7 @@
* if this is bare, which implies it has no working directory.
* See {@link #isBare()}.
*/
+ @Nullable
public ObjectId readCherryPickHead() throws IOException,
NoWorkTreeException {
if (isBare() || getDirectory() == null)
@@ -1465,6 +1581,7 @@
* if this is bare, which implies it has no working directory.
* See {@link #isBare()}.
*/
+ @Nullable
public ObjectId readRevertHead() throws IOException, NoWorkTreeException {
if (isBare() || getDirectory() == null)
throw new NoWorkTreeException();
@@ -1530,6 +1647,7 @@
* if this is bare, which implies it has no working directory.
* See {@link #isBare()}.
*/
+ @Nullable
public ObjectId readOrigHead() throws IOException, NoWorkTreeException {
if (isBare() || getDirectory() == null)
throw new NoWorkTreeException();
@@ -1550,6 +1668,7 @@
* if this is bare, which implies it has no working directory.
* See {@link #isBare()}.
*/
+ @Nullable
public String readSquashCommitMsg() throws IOException {
return readCommitMsgFile(Constants.SQUASH_MSG);
}
@@ -1571,6 +1690,7 @@
writeCommitMsg(squashMsgFile, msg);
}
+ @Nullable
private String readCommitMsgFile(String msgFilename) throws IOException {
if (isBare() || getDirectory() == null)
throw new NoWorkTreeException();
@@ -1579,6 +1699,9 @@
try {
return RawParseUtils.decode(IO.readFully(mergeMsgFile));
} catch (FileNotFoundException e) {
+ if (mergeMsgFile.exists()) {
+ throw e;
+ }
// the file has disappeared in the meantime ignore it
return null;
}
@@ -1601,15 +1724,20 @@
* Read a file from the git directory.
*
* @param filename
- * @return the raw contents or null if the file doesn't exist or is empty
+ * @return the raw contents or {@code null} if the file doesn't exist or is
+ * empty
* @throws IOException
*/
+ @Nullable
private byte[] readGitDirectoryFile(String filename) throws IOException {
File file = new File(getDirectory(), filename);
try {
byte[] raw = IO.readFully(file);
return raw.length > 0 ? raw : null;
} catch (FileNotFoundException notFound) {
+ if (file.exists()) {
+ throw notFound;
+ }
return null;
}
}
@@ -1657,6 +1785,7 @@
* @throws IOException
* @since 3.2
*/
+ @NonNull
public List<RebaseTodoLine> readRebaseTodo(String path,
boolean includeComments)
throws IOException {
@@ -1686,6 +1815,7 @@
* @return the names of all known remotes
* @since 3.4
*/
+ @NonNull
public Set<String> getRemoteNames() {
return getConfig()
.getSubsections(ConfigConstants.CONFIG_REMOTE_SECTION);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java
index 43b1510..eeab921 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/SymbolicRef.java
@@ -43,6 +43,9 @@
package org.eclipse.jgit.lib;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
+
/**
* A reference that indirectly points at another {@link Ref}.
* <p>
@@ -62,11 +65,12 @@
* @param target
* the ref we reference and derive our value from.
*/
- public SymbolicRef(String refName, Ref target) {
+ public SymbolicRef(@NonNull String refName, @NonNull Ref target) {
this.name = refName;
this.target = target;
}
+ @NonNull
public String getName() {
return name;
}
@@ -75,6 +79,7 @@
return true;
}
+ @NonNull
public Ref getLeaf() {
Ref dst = getTarget();
while (dst.isSymbolic())
@@ -82,18 +87,22 @@
return dst;
}
+ @NonNull
public Ref getTarget() {
return target;
}
+ @Nullable
public ObjectId getObjectId() {
return getLeaf().getObjectId();
}
+ @NonNull
public Storage getStorage() {
return Storage.LOOSE;
}
+ @Nullable
public ObjectId getPeeledObjectId() {
return getLeaf().getPeeledObjectId();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Tree.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Tree.java
deleted file mode 100644
index 43bd489..0000000
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Tree.java
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * Copyright (C) 2007, Robin Rosenberg <me@lathund.dewire.com>
- * Copyright (C) 2007-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 java.io.IOException;
-import java.text.MessageFormat;
-
-import org.eclipse.jgit.errors.CorruptObjectException;
-import org.eclipse.jgit.errors.EntryExistsException;
-import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.errors.ObjectWritingException;
-import org.eclipse.jgit.internal.JGitText;
-import org.eclipse.jgit.util.RawParseUtils;
-
-/**
- * A representation of a Git tree entry. A Tree is a directory in Git.
- *
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
- */
-@Deprecated
-public class Tree extends TreeEntry {
- private static final TreeEntry[] EMPTY_TREE = {};
-
- /**
- * Compare two names represented as bytes. Since git treats names of trees and
- * blobs differently we have one parameter that represents a '/' for trees. For
- * other objects the value should be NUL. The names are compare by their positive
- * byte value (0..255).
- *
- * A blob and a tree with the same name will not compare equal.
- *
- * @param a name
- * @param b name
- * @param lasta '/' if a is a tree, else NUL
- * @param lastb '/' if b is a tree, else NUL
- *
- * @return < 0 if a is sorted before b, 0 if they are the same, else b
- */
- public static final int compareNames(final byte[] a, final byte[] b, final int lasta,final int lastb) {
- return compareNames(a, b, 0, b.length, lasta, lastb);
- }
-
- private static final int compareNames(final byte[] a, final byte[] nameUTF8,
- final int nameStart, final int nameEnd, final int lasta, int lastb) {
- int j,k;
- for (j = 0, k = nameStart; j < a.length && k < nameEnd; j++, k++) {
- final int aj = a[j] & 0xff;
- final int bk = nameUTF8[k] & 0xff;
- if (aj < bk)
- return -1;
- else if (aj > bk)
- return 1;
- }
- if (j < a.length) {
- int aj = a[j]&0xff;
- if (aj < lastb)
- return -1;
- else if (aj > lastb)
- return 1;
- else
- if (j == a.length - 1)
- return 0;
- else
- return -1;
- }
- if (k < nameEnd) {
- int bk = nameUTF8[k] & 0xff;
- if (lasta < bk)
- return -1;
- else if (lasta > bk)
- return 1;
- else
- if (k == nameEnd - 1)
- return 0;
- else
- return 1;
- }
- if (lasta < lastb)
- return -1;
- else if (lasta > lastb)
- return 1;
-
- final int namelength = nameEnd - nameStart;
- if (a.length == namelength)
- return 0;
- else if (a.length < namelength)
- return -1;
- else
- return 1;
- }
-
- private static final byte[] substring(final byte[] s, final int nameStart,
- final int nameEnd) {
- if (nameStart == 0 && nameStart == s.length)
- return s;
- final byte[] n = new byte[nameEnd - nameStart];
- System.arraycopy(s, nameStart, n, 0, n.length);
- return n;
- }
-
- private static final int binarySearch(final TreeEntry[] entries,
- final byte[] nameUTF8, final int nameUTF8last, final int nameStart, final int nameEnd) {
- if (entries.length == 0)
- return -1;
- int high = entries.length;
- int low = 0;
- do {
- final int mid = (low + high) >>> 1;
- final int cmp = compareNames(entries[mid].getNameUTF8(), nameUTF8,
- nameStart, nameEnd, TreeEntry.lastChar(entries[mid]), nameUTF8last);
- if (cmp < 0)
- low = mid + 1;
- else if (cmp == 0)
- return mid;
- else
- high = mid;
- } while (low < high);
- return -(low + 1);
- }
-
- private final Repository db;
-
- private TreeEntry[] contents;
-
- /**
- * Constructor for a new Tree
- *
- * @param repo The repository that owns the Tree.
- */
- public Tree(final Repository repo) {
- super(null, null, null);
- db = repo;
- contents = EMPTY_TREE;
- }
-
- /**
- * Construct a Tree object with known content and hash value
- *
- * @param repo
- * @param myId
- * @param raw
- * @throws IOException
- */
- public Tree(final Repository repo, final ObjectId myId, final byte[] raw)
- throws IOException {
- super(null, myId, null);
- db = repo;
- readTree(raw);
- }
-
- /**
- * Construct a new Tree under another Tree
- *
- * @param parent
- * @param nameUTF8
- */
- public Tree(final Tree parent, final byte[] nameUTF8) {
- super(parent, null, nameUTF8);
- db = parent.getRepository();
- contents = EMPTY_TREE;
- }
-
- /**
- * Construct a Tree with a known SHA-1 under another tree. Data is not yet
- * specified and will have to be loaded on demand.
- *
- * @param parent
- * @param id
- * @param nameUTF8
- */
- public Tree(final Tree parent, final ObjectId id, final byte[] nameUTF8) {
- super(parent, id, nameUTF8);
- db = parent.getRepository();
- }
-
- public FileMode getMode() {
- return FileMode.TREE;
- }
-
- /**
- * @return true if this Tree is the top level Tree.
- */
- public boolean isRoot() {
- return getParent() == null;
- }
-
- public Repository getRepository() {
- return db;
- }
-
- /**
- * @return true of the data of this Tree is loaded
- */
- public boolean isLoaded() {
- return contents != null;
- }
-
- /**
- * Forget the in-memory data for this tree.
- */
- public void unload() {
- if (isModified())
- throw new IllegalStateException(JGitText.get().cannotUnloadAModifiedTree);
- contents = null;
- }
-
- /**
- * Adds a new or existing file with the specified name to this tree.
- * Trees are added if necessary as the name may contain '/':s.
- *
- * @param name Name
- * @return a {@link FileTreeEntry} for the added file.
- * @throws IOException
- */
- public FileTreeEntry addFile(final String name) throws IOException {
- return addFile(Repository.gitInternalSlash(Constants.encode(name)), 0);
- }
-
- /**
- * Adds a new or existing file with the specified name to this tree.
- * Trees are added if necessary as the name may contain '/':s.
- *
- * @param s an array containing the name
- * @param offset when the name starts in the tree.
- *
- * @return a {@link FileTreeEntry} for the added file.
- * @throws IOException
- */
- public FileTreeEntry addFile(final byte[] s, final int offset)
- throws IOException {
- int slash;
- int p;
-
- for (slash = offset; slash < s.length && s[slash] != '/'; slash++) {
- // search for path component terminator
- }
-
- ensureLoaded();
- byte xlast = slash<s.length ? (byte)'/' : 0;
- p = binarySearch(contents, s, xlast, offset, slash);
- if (p >= 0 && slash < s.length && contents[p] instanceof Tree)
- return ((Tree) contents[p]).addFile(s, slash + 1);
-
- final byte[] newName = substring(s, offset, slash);
- if (p >= 0)
- throw new EntryExistsException(RawParseUtils.decode(newName));
- else if (slash < s.length) {
- final Tree t = new Tree(this, newName);
- insertEntry(p, t);
- return t.addFile(s, slash + 1);
- } else {
- final FileTreeEntry f = new FileTreeEntry(this, null, newName,
- false);
- insertEntry(p, f);
- return f;
- }
- }
-
- /**
- * Adds a new or existing Tree with the specified name to this tree.
- * Trees are added if necessary as the name may contain '/':s.
- *
- * @param name Name
- * @return a {@link FileTreeEntry} for the added tree.
- * @throws IOException
- */
- public Tree addTree(final String name) throws IOException {
- return addTree(Repository.gitInternalSlash(Constants.encode(name)), 0);
- }
-
- /**
- * Adds a new or existing Tree with the specified name to this tree.
- * Trees are added if necessary as the name may contain '/':s.
- *
- * @param s an array containing the name
- * @param offset when the name starts in the tree.
- *
- * @return a {@link FileTreeEntry} for the added tree.
- * @throws IOException
- */
- public Tree addTree(final byte[] s, final int offset) throws IOException {
- int slash;
- int p;
-
- for (slash = offset; slash < s.length && s[slash] != '/'; slash++) {
- // search for path component terminator
- }
-
- ensureLoaded();
- p = binarySearch(contents, s, (byte)'/', offset, slash);
- if (p >= 0 && slash < s.length && contents[p] instanceof Tree)
- return ((Tree) contents[p]).addTree(s, slash + 1);
-
- final byte[] newName = substring(s, offset, slash);
- if (p >= 0)
- throw new EntryExistsException(RawParseUtils.decode(newName));
-
- final Tree t = new Tree(this, newName);
- insertEntry(p, t);
- return slash == s.length ? t : t.addTree(s, slash + 1);
- }
-
- /**
- * Add the specified tree entry to this tree.
- *
- * @param e
- * @throws IOException
- */
- public void addEntry(final TreeEntry e) throws IOException {
- final int p;
-
- ensureLoaded();
- p = binarySearch(contents, e.getNameUTF8(), TreeEntry.lastChar(e), 0, e.getNameUTF8().length);
- if (p < 0) {
- e.attachParent(this);
- insertEntry(p, e);
- } else {
- throw new EntryExistsException(e.getName());
- }
- }
-
- private void insertEntry(int p, final TreeEntry e) {
- final TreeEntry[] c = contents;
- final TreeEntry[] n = new TreeEntry[c.length + 1];
- p = -(p + 1);
- for (int k = c.length - 1; k >= p; k--)
- n[k + 1] = c[k];
- n[p] = e;
- for (int k = p - 1; k >= 0; k--)
- n[k] = c[k];
- contents = n;
- setModified();
- }
-
- void removeEntry(final TreeEntry e) {
- final TreeEntry[] c = contents;
- final int p = binarySearch(c, e.getNameUTF8(), TreeEntry.lastChar(e), 0,
- e.getNameUTF8().length);
- if (p >= 0) {
- final TreeEntry[] n = new TreeEntry[c.length - 1];
- for (int k = c.length - 1; k > p; k--)
- n[k - 1] = c[k];
- for (int k = p - 1; k >= 0; k--)
- n[k] = c[k];
- contents = n;
- setModified();
- }
- }
-
- /**
- * @return number of members in this tree
- * @throws IOException
- */
- public int memberCount() throws IOException {
- ensureLoaded();
- return contents.length;
- }
-
- /**
- * Return all members of the tree sorted in Git order.
- *
- * Entries are sorted by the numerical unsigned byte
- * values with (sub)trees having an implicit '/'. An
- * example of a tree with three entries. a:b is an
- * actual file name here.
- *
- * <p>
- * 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a.b
- * 040000 tree 4277b6e69d25e5efa77c455340557b384a4c018a a
- * 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a:b
- *
- * @return all entries in this Tree, sorted.
- * @throws IOException
- */
- public TreeEntry[] members() throws IOException {
- ensureLoaded();
- final TreeEntry[] c = contents;
- if (c.length != 0) {
- final TreeEntry[] r = new TreeEntry[c.length];
- for (int k = c.length - 1; k >= 0; k--)
- r[k] = c[k];
- return r;
- } else
- return c;
- }
-
- private boolean exists(final String s, byte slast) throws IOException {
- return findMember(s, slast) != null;
- }
-
- /**
- * @param path to the tree.
- * @return true if a tree with the specified path can be found under this
- * tree.
- * @throws IOException
- */
- public boolean existsTree(String path) throws IOException {
- return exists(path,(byte)'/');
- }
-
- /**
- * @param path of the non-tree entry.
- * @return true if a blob, symlink, or gitlink with the specified name
- * can be found under this tree.
- * @throws IOException
- */
- public boolean existsBlob(String path) throws IOException {
- return exists(path,(byte)0);
- }
-
- private TreeEntry findMember(final String s, byte slast) throws IOException {
- return findMember(Repository.gitInternalSlash(Constants.encode(s)), slast, 0);
- }
-
- private TreeEntry findMember(final byte[] s, final byte slast, final int offset)
- throws IOException {
- int slash;
- int p;
-
- for (slash = offset; slash < s.length && s[slash] != '/'; slash++) {
- // search for path component terminator
- }
-
- ensureLoaded();
- byte xlast = slash<s.length ? (byte)'/' : slast;
- p = binarySearch(contents, s, xlast, offset, slash);
- if (p >= 0) {
- final TreeEntry r = contents[p];
- if (slash < s.length-1)
- return r instanceof Tree ? ((Tree) r).findMember(s, slast, slash + 1)
- : null;
- return r;
- }
- return null;
- }
-
- /**
- * @param s
- * blob name
- * @return a {@link TreeEntry} representing an object with the specified
- * relative path.
- * @throws IOException
- */
- public TreeEntry findBlobMember(String s) throws IOException {
- return findMember(s,(byte)0);
- }
-
- /**
- * @param s Tree Name
- * @return a Tree with the name s or null
- * @throws IOException
- */
- public TreeEntry findTreeMember(String s) throws IOException {
- return findMember(s,(byte)'/');
- }
-
- private void ensureLoaded() throws IOException, MissingObjectException {
- if (!isLoaded()) {
- ObjectLoader ldr = db.open(getId(), Constants.OBJ_TREE);
- readTree(ldr.getCachedBytes());
- }
- }
-
- private void readTree(final byte[] raw) throws IOException {
- final int rawSize = raw.length;
- int rawPtr = 0;
- TreeEntry[] temp;
- int nextIndex = 0;
-
- while (rawPtr < rawSize) {
- while (rawPtr < rawSize && raw[rawPtr] != 0)
- rawPtr++;
- rawPtr++;
- rawPtr += Constants.OBJECT_ID_LENGTH;
- nextIndex++;
- }
-
- temp = new TreeEntry[nextIndex];
- rawPtr = 0;
- nextIndex = 0;
- while (rawPtr < rawSize) {
- int c = raw[rawPtr++];
- if (c < '0' || c > '7')
- throw new CorruptObjectException(getId(), JGitText.get().corruptObjectInvalidEntryMode);
- int mode = c - '0';
- for (;;) {
- c = raw[rawPtr++];
- if (' ' == c)
- break;
- else if (c < '0' || c > '7')
- throw new CorruptObjectException(getId(), JGitText.get().corruptObjectInvalidMode);
- mode <<= 3;
- mode += c - '0';
- }
-
- int nameLen = 0;
- while (raw[rawPtr + nameLen] != 0)
- nameLen++;
- final byte[] name = new byte[nameLen];
- System.arraycopy(raw, rawPtr, name, 0, nameLen);
- rawPtr += nameLen + 1;
-
- final ObjectId id = ObjectId.fromRaw(raw, rawPtr);
- rawPtr += Constants.OBJECT_ID_LENGTH;
-
- final TreeEntry ent;
- if (FileMode.REGULAR_FILE.equals(mode))
- ent = new FileTreeEntry(this, id, name, false);
- else if (FileMode.EXECUTABLE_FILE.equals(mode))
- ent = new FileTreeEntry(this, id, name, true);
- else if (FileMode.TREE.equals(mode))
- ent = new Tree(this, id, name);
- else if (FileMode.SYMLINK.equals(mode))
- ent = new SymlinkTreeEntry(this, id, name);
- else if (FileMode.GITLINK.equals(mode))
- ent = new GitlinkTreeEntry(this, id, name);
- else
- throw new CorruptObjectException(getId(), MessageFormat.format(
- JGitText.get().corruptObjectInvalidMode2, Integer.toOctalString(mode)));
- temp[nextIndex++] = ent;
- }
-
- contents = temp;
- }
-
- /**
- * Format this Tree in canonical format.
- *
- * @return canonical encoding of the tree object.
- * @throws IOException
- * the tree cannot be loaded, or its not in a writable state.
- */
- public byte[] format() throws IOException {
- TreeFormatter fmt = new TreeFormatter();
- for (TreeEntry e : members()) {
- ObjectId id = e.getId();
- if (id == null)
- throw new ObjectWritingException(MessageFormat.format(JGitText
- .get().objectAtPathDoesNotHaveId, e.getFullName()));
-
- fmt.append(e.getNameUTF8(), e.getMode(), id);
- }
- return fmt.toByteArray();
- }
-
- public String toString() {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(getId()));
- r.append(" T "); //$NON-NLS-1$
- r.append(getFullName());
- return r.toString();
- }
-
-}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeEntry.java
deleted file mode 100644
index a1ffa68..0000000
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeEntry.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006-2007, 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 java.io.IOException;
-
-import org.eclipse.jgit.util.RawParseUtils;
-
-/**
- * This class represents an entry in a tree, like a blob or another tree.
- *
- * @deprecated To look up information about a single path, use
- * {@link org.eclipse.jgit.treewalk.TreeWalk#forPath(Repository, String, org.eclipse.jgit.revwalk.RevTree)}.
- * To lookup information about multiple paths at once, use a
- * {@link org.eclipse.jgit.treewalk.TreeWalk} and obtain the current entry's
- * information from its getter methods.
- */
-@Deprecated
-public abstract class TreeEntry implements Comparable {
- private byte[] nameUTF8;
-
- private Tree parent;
-
- private ObjectId id;
-
- /**
- * Construct a named tree entry.
- *
- * @param myParent
- * @param myId
- * @param myNameUTF8
- */
- protected TreeEntry(final Tree myParent, final ObjectId myId,
- final byte[] myNameUTF8) {
- nameUTF8 = myNameUTF8;
- parent = myParent;
- id = myId;
- }
-
- /**
- * @return parent of this tree.
- */
- public Tree getParent() {
- return parent;
- }
-
- /**
- * Delete this entry.
- */
- public void delete() {
- getParent().removeEntry(this);
- detachParent();
- }
-
- /**
- * Detach this entry from it's parent.
- */
- public void detachParent() {
- parent = null;
- }
-
- void attachParent(final Tree p) {
- parent = p;
- }
-
- /**
- * @return the repository owning this entry.
- */
- public Repository getRepository() {
- return getParent().getRepository();
- }
-
- /**
- * @return the raw byte name of this entry.
- */
- public byte[] getNameUTF8() {
- return nameUTF8;
- }
-
- /**
- * @return the name of this entry.
- */
- public String getName() {
- if (nameUTF8 != null)
- return RawParseUtils.decode(nameUTF8);
- return null;
- }
-
- /**
- * Rename this entry.
- *
- * @param n The new name
- * @throws IOException
- */
- public void rename(final String n) throws IOException {
- rename(Constants.encode(n));
- }
-
- /**
- * Rename this entry.
- *
- * @param n The new name
- * @throws IOException
- */
- public void rename(final byte[] n) throws IOException {
- final Tree t = getParent();
- if (t != null) {
- delete();
- }
- nameUTF8 = n;
- if (t != null) {
- t.addEntry(this);
- }
- }
-
- /**
- * @return true if this entry is new or modified since being loaded.
- */
- public boolean isModified() {
- return getId() == null;
- }
-
- /**
- * Mark this entry as modified.
- */
- public void setModified() {
- setId(null);
- }
-
- /**
- * @return SHA-1 of this tree entry (null for new unhashed entries)
- */
- public ObjectId getId() {
- return id;
- }
-
- /**
- * Set (update) the SHA-1 of this entry. Invalidates the id's of all
- * entries above this entry as they will have to be recomputed.
- *
- * @param n SHA-1 for this entry.
- */
- public void setId(final ObjectId n) {
- // If we have a parent and our id is being cleared or changed then force
- // the parent's id to become unset as it depends on our id.
- //
- final Tree p = getParent();
- if (p != null && id != n) {
- if ((id == null && n != null) || (id != null && n == null)
- || !id.equals(n)) {
- p.setId(null);
- }
- }
-
- id = n;
- }
-
- /**
- * @return repository relative name of this entry
- */
- public String getFullName() {
- final StringBuilder r = new StringBuilder();
- appendFullName(r);
- return r.toString();
- }
-
- /**
- * @return repository relative name of the entry
- * FIXME better encoding
- */
- public byte[] getFullNameUTF8() {
- return getFullName().getBytes();
- }
-
- public int compareTo(final Object o) {
- if (this == o)
- return 0;
- if (o instanceof TreeEntry)
- return Tree.compareNames(nameUTF8, ((TreeEntry) o).nameUTF8, lastChar(this), lastChar((TreeEntry)o));
- return -1;
- }
-
- /**
- * Helper for accessing tree/blob methods.
- *
- * @param treeEntry
- * @return '/' for Tree entries and NUL for non-treeish objects.
- */
- final public static int lastChar(TreeEntry treeEntry) {
- if (!(treeEntry instanceof Tree))
- return '\0';
- else
- return '/';
- }
-
- /**
- * @return mode (type of object)
- */
- public abstract FileMode getMode();
-
- private void appendFullName(final StringBuilder r) {
- final TreeEntry p = getParent();
- final String n = getName();
- if (p != null) {
- p.appendFullName(r);
- if (r.length() > 0) {
- r.append('/');
- }
- }
- if (n != null) {
- r.append(n);
- }
- }
-}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
index 191f3d8..82cbf36 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
@@ -46,6 +46,7 @@
import java.util.List;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.ChangeIdUtil;
@@ -76,22 +77,22 @@
List<String> commits = new ArrayList<String>();
List<String> others = new ArrayList<String>();
for (Ref ref : refsToMerge) {
- if (ref.getName().startsWith(Constants.R_HEADS))
+ if (ref.getName().startsWith(Constants.R_HEADS)) {
branches.add("'" + Repository.shortenRefName(ref.getName()) //$NON-NLS-1$
+ "'"); //$NON-NLS-1$
-
- else if (ref.getName().startsWith(Constants.R_REMOTES))
+ } else if (ref.getName().startsWith(Constants.R_REMOTES)) {
remoteBranches.add("'" //$NON-NLS-1$
+ Repository.shortenRefName(ref.getName()) + "'"); //$NON-NLS-1$
-
- else if (ref.getName().startsWith(Constants.R_TAGS))
+ } else if (ref.getName().startsWith(Constants.R_TAGS)) {
tags.add("'" + Repository.shortenRefName(ref.getName()) + "'"); //$NON-NLS-1$ //$NON-NLS-2$
-
- else if (ref.getName().equals(ref.getObjectId().getName()))
- commits.add("'" + ref.getName() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
-
- else
- others.add(ref.getName());
+ } else {
+ ObjectId objectId = ref.getObjectId();
+ if (objectId != null && ref.getName().equals(objectId.getName())) {
+ commits.add("'" + ref.getName() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ others.add(ref.getName());
+ }
+ }
}
List<String> listings = new ArrayList<String>();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
index dc3c772..106f9c7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
@@ -70,7 +70,7 @@
public class MergeResult<S extends Sequence> implements Iterable<MergeChunk> {
private final List<S> sequences;
- private final IntList chunks = new IntList();
+ final IntList chunks = new IntList();
private boolean containsConflicts = false;
@@ -127,7 +127,7 @@
return sequences;
}
- private static final ConflictState[] states = ConflictState.values();
+ static final ConflictState[] states = ConflictState.values();
/**
* @return an iterator over the MergeChunks. The iterator does not support
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
index 983bf5c..bee2d03 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/Merger.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008-2013, Google Inc.
+ * Copyright (C) 2016, Laurent Delaigue <laurent.delaigue@obeo.fr>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -51,9 +52,11 @@
import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
@@ -88,6 +91,13 @@
protected RevTree[] sourceTrees;
/**
+ * A progress monitor.
+ *
+ * @since 4.2
+ */
+ protected ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
+
+ /**
* Create a new merge instance for a repository.
*
* @param local
@@ -290,4 +300,20 @@
* @return resulting tree, if {@link #merge(AnyObjectId[])} returned true.
*/
public abstract ObjectId getResultTreeId();
+
+ /**
+ * Set a progress monitor.
+ *
+ * @param monitor
+ * Monitor to use, can be null to indicate no progress reporting
+ * is desired.
+ * @since 4.2
+ */
+ public void setProgressMonitor(ProgressMonitor monitor) {
+ if (monitor == null) {
+ this.monitor = NullProgressMonitor.INSTANCE;
+ } else {
+ this.monitor = monitor;
+ }
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
index aef47c5..e055644 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
@@ -57,8 +57,6 @@
import java.util.TimeZone;
import org.eclipse.jgit.dircache.DirCache;
-import org.eclipse.jgit.dircache.DirCacheBuilder;
-import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.NoMergeBaseException;
import org.eclipse.jgit.internal.JGitText;
@@ -70,7 +68,6 @@
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.EmptyTreeIterator;
-import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.WorkingTreeIterator;
/**
@@ -181,7 +178,7 @@
WorkingTreeIterator oldWTreeIt = workingTreeIterator;
workingTreeIterator = null;
try {
- dircache = dircacheFromTree(currentBase.getTree());
+ dircache = DirCache.read(reader, currentBase.getTree());
inCore = true;
List<RevCommit> parents = new ArrayList<RevCommit>();
@@ -256,30 +253,4 @@
new Date((time + 1) * 1000L),
TimeZone.getTimeZone("GMT+0000")); //$NON-NLS-1$
}
-
- /**
- * Create a new in memory dircache which has the same content as a given
- * tree.
- *
- * @param treeId
- * the tree which should be used to fill the dircache
- * @return a new in memory dircache
- * @throws IOException
- */
- private DirCache dircacheFromTree(ObjectId treeId) throws IOException {
- DirCache ret = DirCache.newInCore();
- DirCacheBuilder aBuilder = ret.builder();
- try (TreeWalk atw = new TreeWalk(reader)) {
- atw.addTree(treeId);
- atw.setRecursive(true);
- while (atw.next()) {
- DirCacheEntry e = new DirCacheEntry(atw.getRawPath());
- e.setFileMode(atw.getFileMode(0));
- e.setObjectId(atw.getObjectId(0));
- aBuilder.add(e);
- }
- }
- aBuilder.finish();
- return ret;
- }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
index 8a6343c..de08e4b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -786,11 +786,6 @@
private File writeMergedFile(MergeResult<RawText> result)
throws FileNotFoundException, IOException {
File workTree = db.getWorkTree();
- if (workTree == null)
- // TODO: This should be handled by WorkingTreeIterators which
- // support write operations
- throw new UnsupportedOperationException();
-
FS fs = db.getFS();
File of = new File(workTree, tw.getPathString());
File parentFolder = of.getParentFile();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NonNoteEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NonNoteEntry.java
index 6a2d44b..362328a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NonNoteEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NonNoteEntry.java
@@ -47,6 +47,7 @@
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.TreeFormatter;
+import org.eclipse.jgit.util.Paths;
/** A tree entry found in a note branch that isn't a valid note. */
class NonNoteEntry extends ObjectId {
@@ -74,27 +75,8 @@
}
int pathCompare(byte[] bBuf, int bPos, int bLen, FileMode bMode) {
- return pathCompare(name, 0, name.length, mode, //
- bBuf, bPos, bLen, bMode);
- }
-
- private static int pathCompare(final byte[] aBuf, int aPos, final int aEnd,
- final FileMode aMode, final byte[] bBuf, int bPos, final int bEnd,
- final FileMode bMode) {
- while (aPos < aEnd && bPos < bEnd) {
- int cmp = (aBuf[aPos++] & 0xff) - (bBuf[bPos++] & 0xff);
- if (cmp != 0)
- return cmp;
- }
-
- if (aPos < aEnd)
- return (aBuf[aPos] & 0xff) - lastPathChar(bMode);
- if (bPos < bEnd)
- return lastPathChar(aMode) - (bBuf[bPos] & 0xff);
- return 0;
- }
-
- private static int lastPathChar(final FileMode mode) {
- return FileMode.TREE.equals(mode.getBits()) ? '/' : '\0';
+ return Paths.compare(
+ name, 0, name.length, mode.getBits(),
+ bBuf, bPos, bLen, bMode.getBits());
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
index c23e4e3..e67ada6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
@@ -44,12 +44,17 @@
package org.eclipse.jgit.revwalk;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import java.io.IOException;
import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.AnyObjectId;
@@ -441,12 +446,12 @@
* @return decoded commit message as a string. Never null.
*/
public final String getFullMessage() {
- final byte[] raw = buffer;
- final int msgB = RawParseUtils.commitMessage(raw, 0);
- if (msgB < 0)
+ byte[] raw = buffer;
+ int msgB = RawParseUtils.commitMessage(raw, 0);
+ if (msgB < 0) {
return ""; //$NON-NLS-1$
- final Charset enc = RawParseUtils.parseEncoding(raw);
- return RawParseUtils.decode(enc, raw, msgB, raw.length);
+ }
+ return RawParseUtils.decode(guessEncoding(), raw, msgB, raw.length);
}
/**
@@ -465,16 +470,17 @@
* spanned multiple lines. Embedded LFs are converted to spaces.
*/
public final String getShortMessage() {
- final byte[] raw = buffer;
- final int msgB = RawParseUtils.commitMessage(raw, 0);
- if (msgB < 0)
+ byte[] raw = buffer;
+ int msgB = RawParseUtils.commitMessage(raw, 0);
+ if (msgB < 0) {
return ""; //$NON-NLS-1$
+ }
- final Charset enc = RawParseUtils.parseEncoding(raw);
- final int msgE = RawParseUtils.endOfParagraph(raw, msgB);
- String str = RawParseUtils.decode(enc, raw, msgB, msgE);
- if (hasLF(raw, msgB, msgE))
+ int msgE = RawParseUtils.endOfParagraph(raw, msgB);
+ String str = RawParseUtils.decode(guessEncoding(), raw, msgB, msgE);
+ if (hasLF(raw, msgB, msgE)) {
str = StringUtils.replaceLineBreaksWithSpace(str);
+ }
return str;
}
@@ -488,18 +494,49 @@
/**
* Determine the encoding of the commit message buffer.
* <p>
+ * Locates the "encoding" header (if present) and returns its value. Due to
+ * corruption in the wild this may be an invalid encoding name that is not
+ * recognized by any character encoding library.
+ * <p>
+ * If no encoding header is present, null.
+ *
+ * @return the preferred encoding of {@link #getRawBuffer()}; or null.
+ * @since 4.2
+ */
+ @Nullable
+ public final String getEncodingName() {
+ return RawParseUtils.parseEncodingName(buffer);
+ }
+
+ /**
+ * Determine the encoding of the commit message buffer.
+ * <p>
* Locates the "encoding" header (if present) and then returns the proper
* character set to apply to this buffer to evaluate its contents as
* character data.
* <p>
- * If no encoding header is present, {@link Constants#CHARSET} is assumed.
+ * If no encoding header is present {@code UTF-8} is assumed.
*
* @return the preferred encoding of {@link #getRawBuffer()}.
+ * @throws IllegalCharsetNameException
+ * if the character set requested by the encoding header is
+ * malformed and unsupportable.
+ * @throws UnsupportedCharsetException
+ * if the JRE does not support the character set requested by
+ * the encoding header.
*/
public final Charset getEncoding() {
return RawParseUtils.parseEncoding(buffer);
}
+ private Charset guessEncoding() {
+ try {
+ return getEncoding();
+ } catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
+ return UTF_8;
+ }
+ }
+
/**
* Parse the footer lines (e.g. "Signed-off-by") for machine processing.
* <p>
@@ -529,7 +566,7 @@
final int msgB = RawParseUtils.commitMessage(raw, 0);
final ArrayList<FooterLine> r = new ArrayList<FooterLine>(4);
- final Charset enc = getEncoding();
+ final Charset enc = guessEncoding();
for (;;) {
ptr = RawParseUtils.prevLF(raw, ptr);
if (ptr <= msgB)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java
index bf2785e..81a54bf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java
@@ -45,8 +45,12 @@
package org.eclipse.jgit.revwalk;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import java.io.IOException;
import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -162,7 +166,7 @@
int p = pos.value += 4; // "tag "
final int nameEnd = RawParseUtils.nextLF(rawTag, p) - 1;
- tagName = RawParseUtils.decode(Constants.CHARSET, rawTag, p, nameEnd);
+ tagName = RawParseUtils.decode(UTF_8, rawTag, p, nameEnd);
if (walk.isRetainBody())
buffer = rawTag;
@@ -207,12 +211,12 @@
* @return decoded tag message as a string. Never null.
*/
public final String getFullMessage() {
- final byte[] raw = buffer;
- final int msgB = RawParseUtils.tagMessage(raw, 0);
- if (msgB < 0)
+ byte[] raw = buffer;
+ int msgB = RawParseUtils.tagMessage(raw, 0);
+ if (msgB < 0) {
return ""; //$NON-NLS-1$
- final Charset enc = RawParseUtils.parseEncoding(raw);
- return RawParseUtils.decode(enc, raw, msgB, raw.length);
+ }
+ return RawParseUtils.decode(guessEncoding(), raw, msgB, raw.length);
}
/**
@@ -231,19 +235,28 @@
* multiple lines. Embedded LFs are converted to spaces.
*/
public final String getShortMessage() {
- final byte[] raw = buffer;
- final int msgB = RawParseUtils.tagMessage(raw, 0);
- if (msgB < 0)
+ byte[] raw = buffer;
+ int msgB = RawParseUtils.tagMessage(raw, 0);
+ if (msgB < 0) {
return ""; //$NON-NLS-1$
+ }
- final Charset enc = RawParseUtils.parseEncoding(raw);
- final int msgE = RawParseUtils.endOfParagraph(raw, msgB);
- String str = RawParseUtils.decode(enc, raw, msgB, msgE);
- if (RevCommit.hasLF(raw, msgB, msgE))
+ int msgE = RawParseUtils.endOfParagraph(raw, msgB);
+ String str = RawParseUtils.decode(guessEncoding(), raw, msgB, msgE);
+ if (RevCommit.hasLF(raw, msgB, msgE)) {
str = StringUtils.replaceLineBreaksWithSpace(str);
+ }
return str;
}
+ private Charset guessEncoding() {
+ try {
+ return RawParseUtils.parseEncoding(buffer);
+ } catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
+ return UTF_8;
+ }
+ }
+
/**
* Get a reference to the object this tag was placed on.
* <p>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
index 1176d95..c850493 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -1295,7 +1295,6 @@
retainOnReset = 0;
carryFlags = UNINTERESTING;
objects.clear();
- reader.close();
roots.clear();
queue = new DateRevQueue();
pending = new StartGenerator(this);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
index 5509fc6..702fd70 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
@@ -74,8 +74,6 @@
public class FileBasedConfig extends StoredConfig {
private final File configFile;
- private final FS fs;
-
private boolean utf8Bom;
private volatile FileSnapshot snapshot;
@@ -109,7 +107,6 @@
public FileBasedConfig(Config base, File cfgLocation, FS fs) {
super(base);
configFile = cfgLocation;
- this.fs = fs;
this.snapshot = FileSnapshot.DIRTY;
this.hash = ObjectId.zeroId();
}
@@ -163,6 +160,9 @@
hash = newHash;
}
} catch (FileNotFoundException noFile) {
+ if (configFile.exists()) {
+ throw noFile;
+ }
clear();
snapshot = newSnapshot;
} catch (IOException e) {
@@ -200,7 +200,7 @@
out = Constants.encode(text);
}
- final LockFile lf = new LockFile(getFile(), fs);
+ final LockFile lf = new LockFile(getFile());
if (!lf.lock())
throw new LockFailedException(getFile());
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
index a8835b7..d594e97 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
@@ -138,6 +138,65 @@
*/
public static final boolean DEFAULT_BUILD_BITMAPS = true;
+ /**
+ * Default count of most recent commits to select for bitmaps. Only applies
+ * when bitmaps are enabled: {@value}
+ *
+ * @see #setBitmapContiguousCommitCount(int)
+ * @since 4.2
+ */
+ public static final int DEFAULT_BITMAP_CONTIGUOUS_COMMIT_COUNT = 100;
+
+ /**
+ * Count at which the span between selected commits changes from
+ * "bitmapRecentCommitSpan" to "bitmapDistantCommitSpan". Only applies when
+ * bitmaps are enabled: {@value}
+ *
+ * @see #setBitmapRecentCommitCount(int)
+ * @since 4.2
+ */
+ public static final int DEFAULT_BITMAP_RECENT_COMMIT_COUNT = 20000;
+
+ /**
+ * Default spacing between commits in recent history when selecting commits
+ * for bitmaps. Only applies when bitmaps are enabled: {@value}
+ *
+ * @see #setBitmapRecentCommitSpan(int)
+ * @since 4.2
+ */
+ public static final int DEFAULT_BITMAP_RECENT_COMMIT_SPAN = 100;
+
+ /**
+ * Default spacing between commits in distant history when selecting commits
+ * for bitmaps. Only applies when bitmaps are enabled: {@value}
+ *
+ * @see #setBitmapDistantCommitSpan(int)
+ * @since 4.2
+ */
+ public static final int DEFAULT_BITMAP_DISTANT_COMMIT_SPAN = 5000;
+
+ /**
+ * Default count of branches required to activate inactive branch commit
+ * selection. If the number of branches is less than this then bitmaps for
+ * the entire commit history of all branches will be created, otherwise
+ * branches marked as "inactive" will have coverage for only partial
+ * history: {@value}
+ *
+ * @see #setBitmapExcessiveBranchCount(int)
+ * @since 4.2
+ */
+ public static final int DEFAULT_BITMAP_EXCESSIVE_BRANCH_COUNT = 100;
+
+ /**
+ * Default age at which a branch is considered inactive. Age is taken as the
+ * number of days ago that the most recent commit was made to a branch. Only
+ * affects bitmap processing if bitmaps are enabled and the
+ * "excessive branch count" has been exceeded: {@value}
+ *
+ * @see #setBitmapInactiveBranchAgeInDays(int)
+ * @since 4.2
+ */
+ public static final int DEFAULT_BITMAP_INACTIVE_BRANCH_AGE_IN_DAYS = 90;
private int compressionLevel = Deflater.DEFAULT_COMPRESSION;
@@ -169,6 +228,18 @@
private boolean buildBitmaps = DEFAULT_BUILD_BITMAPS;
+ private int bitmapContiguousCommitCount = DEFAULT_BITMAP_CONTIGUOUS_COMMIT_COUNT;
+
+ private int bitmapRecentCommitCount = DEFAULT_BITMAP_RECENT_COMMIT_COUNT;
+
+ private int bitmapRecentCommitSpan = DEFAULT_BITMAP_RECENT_COMMIT_SPAN;
+
+ private int bitmapDistantCommitSpan = DEFAULT_BITMAP_DISTANT_COMMIT_SPAN;
+
+ private int bitmapExcessiveBranchCount = DEFAULT_BITMAP_EXCESSIVE_BRANCH_COUNT;
+
+ private int bitmapInactiveBranchAgeInDays = DEFAULT_BITMAP_INACTIVE_BRANCH_AGE_IN_DAYS;
+
private boolean cutDeltaChains;
/** Create a default configuration. */
@@ -222,6 +293,12 @@
this.executor = cfg.executor;
this.indexVersion = cfg.indexVersion;
this.buildBitmaps = cfg.buildBitmaps;
+ this.bitmapContiguousCommitCount = cfg.bitmapContiguousCommitCount;
+ this.bitmapRecentCommitCount = cfg.bitmapRecentCommitCount;
+ this.bitmapRecentCommitSpan = cfg.bitmapRecentCommitSpan;
+ this.bitmapDistantCommitSpan = cfg.bitmapDistantCommitSpan;
+ this.bitmapExcessiveBranchCount = cfg.bitmapExcessiveBranchCount;
+ this.bitmapInactiveBranchAgeInDays = cfg.bitmapInactiveBranchAgeInDays;
this.cutDeltaChains = cfg.cutDeltaChains;
}
@@ -650,7 +727,7 @@
* oldest (most compatible) format available for the objects.
* @see PackIndexWriter
*/
- public void setIndexVersion(final int version) {
+ public void setIndexVersion(int version) {
indexVersion = version;
}
@@ -684,6 +761,162 @@
}
/**
+ * Get the count of most recent commits for which to build bitmaps.
+ *
+ * Default setting: {@value #DEFAULT_BITMAP_CONTIGUOUS_COMMIT_COUNT}
+ *
+ * @return the count of most recent commits for which to build bitmaps
+ * @since 4.2
+ */
+ public int getBitmapContiguousCommitCount() {
+ return bitmapContiguousCommitCount;
+ }
+
+ /**
+ * Set the count of most recent commits for which to build bitmaps.
+ *
+ * Default setting: {@value #DEFAULT_BITMAP_CONTIGUOUS_COMMIT_COUNT}
+ *
+ * @param count
+ * the count of most recent commits for which to build bitmaps
+ * @since 4.2
+ */
+ public void setBitmapContiguousCommitCount(int count) {
+ bitmapContiguousCommitCount = count;
+ }
+
+ /**
+ * Get the count at which to switch from "bitmapRecentCommitSpan" to
+ * "bitmapDistantCommitSpan".
+ *
+ * Default setting: {@value #DEFAULT_BITMAP_RECENT_COMMIT_COUNT}
+ *
+ * @return the count for switching between recent and distant spans
+ * @since 4.2
+ */
+ public int getBitmapRecentCommitCount() {
+ return bitmapRecentCommitCount;
+ }
+
+ /**
+ * Set the count at which to switch from "bitmapRecentCommitSpan" to
+ * "bitmapDistantCommitSpan".
+ *
+ * Default setting: {@value #DEFAULT_BITMAP_RECENT_COMMIT_COUNT}
+ *
+ * @param count
+ * the count for switching between recent and distant spans
+ * @since 4.2
+ */
+ public void setBitmapRecentCommitCount(int count) {
+ bitmapRecentCommitCount = count;
+ }
+
+ /**
+ * Get the span of commits when building bitmaps for recent history.
+ *
+ * Default setting: {@value #DEFAULT_BITMAP_RECENT_COMMIT_SPAN}
+ *
+ * @return the span of commits when building bitmaps for recent history
+ * @since 4.2
+ */
+ public int getBitmapRecentCommitSpan() {
+ return bitmapRecentCommitSpan;
+ }
+
+ /**
+ * Set the span of commits when building bitmaps for recent history.
+ *
+ * Default setting: {@value #DEFAULT_BITMAP_RECENT_COMMIT_SPAN}
+ *
+ * @param span
+ * the span of commits when building bitmaps for recent history
+ * @since 4.2
+ */
+ public void setBitmapRecentCommitSpan(int span) {
+ bitmapRecentCommitSpan = span;
+ }
+
+ /**
+ * Get the span of commits when building bitmaps for distant history.
+ *
+ * Default setting: {@value #DEFAULT_BITMAP_DISTANT_COMMIT_SPAN}
+ *
+ * @return the span of commits when building bitmaps for distant history
+ * @since 4.2
+ */
+ public int getBitmapDistantCommitSpan() {
+ return bitmapDistantCommitSpan;
+ }
+
+ /**
+ * Set the span of commits when building bitmaps for distant history.
+ *
+ * Default setting: {@value #DEFAULT_BITMAP_DISTANT_COMMIT_SPAN}
+ *
+ * @param span
+ * the span of commits when building bitmaps for distant history
+ * @since 4.2
+ */
+ public void setBitmapDistantCommitSpan(int span) {
+ bitmapDistantCommitSpan = span;
+ }
+
+ /**
+ * Get the count of branches deemed "excessive". If the count of branches in
+ * a repository exceeds this number and bitmaps are enabled, "inactive"
+ * branches will have fewer bitmaps than "active" branches.
+ *
+ * Default setting: {@value #DEFAULT_BITMAP_EXCESSIVE_BRANCH_COUNT}
+ *
+ * @return the count of branches deemed "excessive"
+ * @since 4.2
+ */
+ public int getBitmapExcessiveBranchCount() {
+ return bitmapExcessiveBranchCount;
+ }
+
+ /**
+ * Set the count of branches deemed "excessive". If the count of branches in
+ * a repository exceeds this number and bitmaps are enabled, "inactive"
+ * branches will have fewer bitmaps than "active" branches.
+ *
+ * Default setting: {@value #DEFAULT_BITMAP_EXCESSIVE_BRANCH_COUNT}
+ *
+ * @param count
+ * the count of branches deemed "excessive"
+ * @since 4.2
+ */
+ public void setBitmapExcessiveBranchCount(int count) {
+ bitmapExcessiveBranchCount = count;
+ }
+
+ /**
+ * Get the the age in days that marks a branch as "inactive".
+ *
+ * Default setting: {@value #DEFAULT_BITMAP_INACTIVE_BRANCH_AGE_IN_DAYS}
+ *
+ * @return the age in days that marks a branch as "inactive"
+ * @since 4.2
+ */
+ public int getBitmapInactiveBranchAgeInDays() {
+ return bitmapInactiveBranchAgeInDays;
+ }
+
+ /**
+ * Set the the age in days that marks a branch as "inactive".
+ *
+ * Default setting: {@value #DEFAULT_BITMAP_INACTIVE_BRANCH_AGE_IN_DAYS}
+ *
+ * @param ageInDays
+ * the age in days that marks a branch as "inactive"
+ * @since 4.2
+ */
+ public void setBitmapInactiveBranchAgeInDays(int ageInDays) {
+ bitmapInactiveBranchAgeInDays = ageInDays;
+ }
+
+ /**
* Update properties by setting fields from the configuration.
*
* If a property's corresponding variable is not defined in the supplied
@@ -712,19 +945,36 @@
// These variables aren't standardized
//
setReuseDeltas(rc.getBoolean("pack", "reusedeltas", isReuseDeltas())); //$NON-NLS-1$ //$NON-NLS-2$
- setReuseObjects(rc.getBoolean("pack", "reuseobjects", isReuseObjects())); //$NON-NLS-1$ //$NON-NLS-2$
- setDeltaCompress(rc.getBoolean(
- "pack", "deltacompression", isDeltaCompress())); //$NON-NLS-1$ //$NON-NLS-2$
- setCutDeltaChains(rc.getBoolean(
- "pack", "cutdeltachains", getCutDeltaChains())); //$NON-NLS-1$ //$NON-NLS-2$
- setBuildBitmaps(rc.getBoolean("pack", "buildbitmaps", isBuildBitmaps())); //$NON-NLS-1$ //$NON-NLS-2$
+ setReuseObjects(
+ rc.getBoolean("pack", "reuseobjects", isReuseObjects())); //$NON-NLS-1$ //$NON-NLS-2$
+ setDeltaCompress(
+ rc.getBoolean("pack", "deltacompression", isDeltaCompress())); //$NON-NLS-1$ //$NON-NLS-2$
+ setCutDeltaChains(
+ rc.getBoolean("pack", "cutdeltachains", getCutDeltaChains())); //$NON-NLS-1$ //$NON-NLS-2$
+ setBuildBitmaps(
+ rc.getBoolean("pack", "buildbitmaps", isBuildBitmaps())); //$NON-NLS-1$ //$NON-NLS-2$
+ setBitmapContiguousCommitCount(
+ rc.getInt("pack", "bitmapcontiguouscommitcount", //$NON-NLS-1$ //$NON-NLS-2$
+ getBitmapContiguousCommitCount()));
+ setBitmapRecentCommitCount(rc.getInt("pack", "bitmaprecentcommitcount", //$NON-NLS-1$ //$NON-NLS-2$
+ getBitmapRecentCommitCount()));
+ setBitmapRecentCommitSpan(rc.getInt("pack", "bitmaprecentcommitspan", //$NON-NLS-1$ //$NON-NLS-2$
+ getBitmapRecentCommitSpan()));
+ setBitmapDistantCommitSpan(rc.getInt("pack", "bitmapdistantcommitspan", //$NON-NLS-1$ //$NON-NLS-2$
+ getBitmapDistantCommitSpan()));
+ setBitmapExcessiveBranchCount(rc.getInt("pack", //$NON-NLS-1$
+ "bitmapexcessivebranchcount", getBitmapExcessiveBranchCount())); //$NON-NLS-1$
+ setBitmapInactiveBranchAgeInDays(
+ rc.getInt("pack", "bitmapinactivebranchageindays", //$NON-NLS-1$ //$NON-NLS-2$
+ getBitmapInactiveBranchAgeInDays()));
}
public String toString() {
final StringBuilder b = new StringBuilder();
b.append("maxDeltaDepth=").append(getMaxDeltaDepth()); //$NON-NLS-1$
b.append(", deltaSearchWindowSize=").append(getDeltaSearchWindowSize()); //$NON-NLS-1$
- b.append(", deltaSearchMemoryLimit=").append(getDeltaSearchMemoryLimit()); //$NON-NLS-1$
+ b.append(", deltaSearchMemoryLimit=") //$NON-NLS-1$
+ .append(getDeltaSearchMemoryLimit());
b.append(", deltaCacheSize=").append(getDeltaCacheSize()); //$NON-NLS-1$
b.append(", deltaCacheLimit=").append(getDeltaCacheLimit()); //$NON-NLS-1$
b.append(", compressionLevel=").append(getCompressionLevel()); //$NON-NLS-1$
@@ -735,6 +985,18 @@
b.append(", reuseObjects=").append(isReuseObjects()); //$NON-NLS-1$
b.append(", deltaCompress=").append(isDeltaCompress()); //$NON-NLS-1$
b.append(", buildBitmaps=").append(isBuildBitmaps()); //$NON-NLS-1$
+ b.append(", bitmapContiguousCommitCount=") //$NON-NLS-1$
+ .append(getBitmapContiguousCommitCount());
+ b.append(", bitmapRecentCommitCount=") //$NON-NLS-1$
+ .append(getBitmapRecentCommitCount());
+ b.append(", bitmapRecentCommitSpan=") //$NON-NLS-1$
+ .append(getBitmapRecentCommitSpan());
+ b.append(", bitmapDistantCommitSpan=") //$NON-NLS-1$
+ .append(getBitmapDistantCommitSpan());
+ b.append(", bitmapExcessiveBranchCount=") //$NON-NLS-1$
+ .append(getBitmapExcessiveBranchCount());
+ b.append(", bitmapInactiveBranchAge=") //$NON-NLS-1$
+ .append(getBitmapInactiveBranchAgeInDays());
return b.toString();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
index d3cdba5..4069a64 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
@@ -56,10 +56,10 @@
import java.net.URL;
import java.net.URLConnection;
import java.security.DigestOutputStream;
+import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.security.spec.InvalidKeySpecException;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -175,7 +175,7 @@
private final String acl;
/** Maximum number of times to try an operation. */
- private final int maxAttempts;
+ final int maxAttempts;
/** Encryption algorithm, may be a null instance that provides pass-through. */
private final WalkEncryption encryption;
@@ -186,6 +186,19 @@
/** S3 Bucket Domain. */
private final String domain;
+ /** Property names used in amazon connection configuration file. */
+ interface Keys {
+ String ACCESS_KEY = "accesskey"; //$NON-NLS-1$
+ String SECRET_KEY = "secretkey"; //$NON-NLS-1$
+ String PASSWORD = "password"; //$NON-NLS-1$
+ String CRYPTO_ALG = "crypto.algorithm"; //$NON-NLS-1$
+ String CRYPTO_VER = "crypto.version"; //$NON-NLS-1$
+ String ACL = "acl"; //$NON-NLS-1$
+ String DOMAIN = "domain"; //$NON-NLS-1$
+ String HTTP_RETRY = "httpclient.retry-max"; //$NON-NLS-1$
+ String TMP_DIR = "tmpdir"; //$NON-NLS-1$
+ }
+
/**
* Create a new S3 client for the supplied user information.
* <p>
@@ -219,17 +232,18 @@
*
*/
public AmazonS3(final Properties props) {
- domain = props.getProperty("domain", "s3.amazonaws.com"); //$NON-NLS-1$ //$NON-NLS-2$
- publicKey = props.getProperty("accesskey"); //$NON-NLS-1$
+ domain = props.getProperty(Keys.DOMAIN, "s3.amazonaws.com"); //$NON-NLS-1$
+
+ publicKey = props.getProperty(Keys.ACCESS_KEY);
if (publicKey == null)
throw new IllegalArgumentException(JGitText.get().missingAccesskey);
- final String secret = props.getProperty("secretkey"); //$NON-NLS-1$
+ final String secret = props.getProperty(Keys.SECRET_KEY);
if (secret == null)
throw new IllegalArgumentException(JGitText.get().missingSecretkey);
privateKey = new SecretKeySpec(Constants.encodeASCII(secret), HMAC);
- final String pacl = props.getProperty("acl", "PRIVATE"); //$NON-NLS-1$ //$NON-NLS-2$
+ final String pacl = props.getProperty(Keys.ACL, "PRIVATE"); //$NON-NLS-1$
if (StringUtils.equalsIgnoreCase("PRIVATE", pacl)) //$NON-NLS-1$
acl = "private"; //$NON-NLS-1$
else if (StringUtils.equalsIgnoreCase("PUBLIC", pacl)) //$NON-NLS-1$
@@ -242,26 +256,16 @@
throw new IllegalArgumentException("Invalid acl: " + pacl); //$NON-NLS-1$
try {
- final String cPas = props.getProperty("password"); //$NON-NLS-1$
- if (cPas != null) {
- String cAlg = props.getProperty("crypto.algorithm"); //$NON-NLS-1$
- if (cAlg == null)
- cAlg = "PBEWithMD5AndDES"; //$NON-NLS-1$
- encryption = new WalkEncryption.ObjectEncryptionV2(cAlg, cPas);
- } else {
- encryption = WalkEncryption.NONE;
- }
- } catch (InvalidKeySpecException e) {
- throw new IllegalArgumentException(JGitText.get().invalidEncryption, e);
- } catch (NoSuchAlgorithmException e) {
+ encryption = WalkEncryption.instance(props);
+ } catch (GeneralSecurityException e) {
throw new IllegalArgumentException(JGitText.get().invalidEncryption, e);
}
- maxAttempts = Integer.parseInt(props.getProperty(
- "httpclient.retry-max", "3")); //$NON-NLS-1$ //$NON-NLS-2$
+ maxAttempts = Integer
+ .parseInt(props.getProperty(Keys.HTTP_RETRY, "3")); //$NON-NLS-1$
proxySelector = ProxySelector.getDefault();
- String tmp = props.getProperty("tmpdir"); //$NON-NLS-1$
+ String tmp = props.getProperty(Keys.TMP_DIR);
tmpDir = tmp != null && tmp.length() > 0 ? new File(tmp) : null;
}
@@ -479,7 +483,7 @@
return encryption.encrypt(new DigestOutputStream(buffer, md5));
}
- private void putImpl(final String bucket, final String key,
+ void putImpl(final String bucket, final String key,
final byte[] csum, final TemporaryBuffer buf,
ProgressMonitor monitor, String monitorTask) throws IOException {
if (monitor == null)
@@ -518,7 +522,7 @@
throw maxAttempts(JGitText.get().s3ActionWriting, key);
}
- private IOException error(final String action, final String key,
+ IOException error(final String action, final String key,
final HttpURLConnection c) throws IOException {
final IOException err = new IOException(MessageFormat.format(
JGitText.get().amazonS3ActionFailed, action, key,
@@ -543,7 +547,7 @@
return err;
}
- private IOException maxAttempts(final String action, final String key) {
+ IOException maxAttempts(final String action, final String key) {
return new IOException(MessageFormat.format(
JGitText.get().amazonS3ActionFailedGivingUp, action, key,
Integer.valueOf(maxAttempts)));
@@ -555,7 +559,7 @@
return open(method, bucket, key, noArgs);
}
- private HttpURLConnection open(final String method, final String bucket,
+ HttpURLConnection open(final String method, final String bucket,
final String key, final Map<String, String> args)
throws IOException {
final StringBuilder urlstr = new StringBuilder();
@@ -592,7 +596,7 @@
return c;
}
- private void authorize(final HttpURLConnection c) throws IOException {
+ void authorize(final HttpURLConnection c) throws IOException {
final Map<String, List<String>> reqHdr = c.getRequestProperties();
final SortedMap<String, String> sigHdr = new TreeMap<String, String>();
for (final Map.Entry<String, List<String>> entry : reqHdr.entrySet()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java
index 7f9cec7..aa36aeb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackConnection.java
@@ -143,7 +143,9 @@
final int timeout = transport.getTimeout();
if (timeout > 0) {
final Thread caller = Thread.currentThread();
- myTimer = new InterruptTimer(caller.getName() + "-Timer"); //$NON-NLS-1$
+ if (myTimer == null) {
+ myTimer = new InterruptTimer(caller.getName() + "-Timer"); //$NON-NLS-1$
+ }
timeoutIn = new TimeoutInputStream(myIn, myTimer);
timeoutOut = new TimeoutOutputStream(myOut, myTimer);
timeoutIn.setTimeout(timeout * 1000);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
index cf13582..754cf36 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java
@@ -464,8 +464,12 @@
final PacketLineOut p = statelessRPC ? pckState : pckOut;
boolean first = true;
for (final Ref r : want) {
+ ObjectId objectId = r.getObjectId();
+ if (objectId == null) {
+ continue;
+ }
try {
- if (walk.parseAny(r.getObjectId()).has(REACHABLE)) {
+ if (walk.parseAny(objectId).has(REACHABLE)) {
// We already have this object. Asking for it is
// not a very good idea.
//
@@ -478,7 +482,7 @@
final StringBuilder line = new StringBuilder(46);
line.append("want "); //$NON-NLS-1$
- line.append(r.getObjectId().name());
+ line.append(objectId.name());
if (first) {
line.append(enableCapabilities());
first = false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
index 24fb3be..963de35 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -44,6 +44,8 @@
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
+
import java.io.IOException;
import java.io.OutputStream;
import java.text.MessageFormat;
@@ -110,17 +112,15 @@
public static final String CAPABILITY_SIDE_BAND_64K = GitProtocolConstants.CAPABILITY_SIDE_BAND_64K;
private final boolean thinPack;
+ private final boolean atomic;
+ private boolean capableAtomic;
private boolean capableDeleteRefs;
-
private boolean capableReport;
-
private boolean capableSideBand;
-
private boolean capableOfsDelta;
private boolean sentCommand;
-
private boolean writePack;
/** Time in milliseconds spent transferring the pack data. */
@@ -135,6 +135,7 @@
public BasePackPushConnection(final PackTransport packTransport) {
super(packTransport);
thinPack = transport.isPushThin();
+ atomic = transport.isPushAtomic();
}
public void push(final ProgressMonitor monitor,
@@ -224,6 +225,11 @@
private void writeCommands(final Collection<RemoteRefUpdate> refUpdates,
final ProgressMonitor monitor, OutputStream outputStream) throws IOException {
final String capabilities = enableCapabilities(monitor, outputStream);
+ if (atomic && !capableAtomic) {
+ throw new TransportException(uri,
+ JGitText.get().atomicPushNotSupported);
+ }
+
for (final RemoteRefUpdate rru : refUpdates) {
if (!capableDeleteRefs && rru.isDelete()) {
rru.setStatus(Status.REJECTED_NODELETE);
@@ -231,9 +237,14 @@
}
final StringBuilder sb = new StringBuilder();
- final Ref advertisedRef = getRef(rru.getRemoteName());
- final ObjectId oldId = (advertisedRef == null ? ObjectId.zeroId()
- : advertisedRef.getObjectId());
+ ObjectId oldId = rru.getExpectedOldObjectId();
+ if (oldId == null) {
+ final Ref advertised = getRef(rru.getRemoteName());
+ oldId = advertised != null ? advertised.getObjectId() : null;
+ if (oldId == null) {
+ oldId = ObjectId.zeroId();
+ }
+ }
sb.append(oldId.name());
sb.append(' ');
sb.append(rru.getNewObjectId().name());
@@ -259,6 +270,8 @@
private String enableCapabilities(final ProgressMonitor monitor,
OutputStream outputStream) {
final StringBuilder line = new StringBuilder();
+ if (atomic)
+ capableAtomic = wantCapability(line, CAPABILITY_ATOMIC);
capableReport = wantCapability(line, CAPABILITY_REPORT_STATUS);
capableDeleteRefs = wantCapability(line, CAPABILITY_DELETE_REFS);
capableOfsDelta = wantCapability(line, CAPABILITY_OFS_DELTA);
@@ -372,7 +385,8 @@
final int oldTimeout = timeoutIn.getTimeout();
final int sendTime = (int) Math.min(packTransferTime, 28800000L);
try {
- timeoutIn.setTimeout(10 * Math.max(sendTime, oldTimeout));
+ int timeout = 10 * Math.max(sendTime, oldTimeout);
+ timeoutIn.setTimeout((timeout < 0) ? Integer.MAX_VALUE : timeout);
return pckIn.readString();
} finally {
timeoutIn.setTimeout(oldTimeout);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
index 776a9f6..a20e652 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
@@ -293,18 +293,20 @@
db = into;
walk = new RevWalk(db);
- final ReceiveConfig cfg = db.getConfig().get(ReceiveConfig.KEY);
- objectChecker = cfg.newObjectChecker();
- allowCreates = cfg.allowCreates;
+ TransferConfig tc = db.getConfig().get(TransferConfig.KEY);
+ objectChecker = tc.newReceiveObjectChecker();
+
+ ReceiveConfig rc = db.getConfig().get(ReceiveConfig.KEY);
+ allowCreates = rc.allowCreates;
allowAnyDeletes = true;
- allowBranchDeletes = cfg.allowDeletes;
- allowNonFastForwards = cfg.allowNonFastForwards;
- allowOfsDelta = cfg.allowOfsDelta;
+ allowBranchDeletes = rc.allowDeletes;
+ allowNonFastForwards = rc.allowNonFastForwards;
+ allowOfsDelta = rc.allowOfsDelta;
advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
refFilter = RefFilter.DEFAULT;
advertisedHaves = new HashSet<ObjectId>();
clientShallowCommits = new HashSet<ObjectId>();
- signedPushConfig = cfg.signedPush;
+ signedPushConfig = rc.signedPush;
}
/** Configuration for receive operations. */
@@ -315,32 +317,13 @@
}
};
- final boolean checkReceivedObjects;
- final boolean allowLeadingZeroFileMode;
- final boolean allowInvalidPersonIdent;
- final boolean safeForWindows;
- final boolean safeForMacOS;
-
final boolean allowCreates;
final boolean allowDeletes;
final boolean allowNonFastForwards;
final boolean allowOfsDelta;
-
final SignedPushConfig signedPush;
ReceiveConfig(final Config config) {
- checkReceivedObjects = config.getBoolean(
- "receive", "fsckobjects", //$NON-NLS-1$ //$NON-NLS-2$
- config.getBoolean("transfer", "fsckobjects", false)); //$NON-NLS-1$ //$NON-NLS-2$
- allowLeadingZeroFileMode = checkReceivedObjects
- && config.getBoolean("fsck", "allowLeadingZeroFileMode", false); //$NON-NLS-1$ //$NON-NLS-2$
- allowInvalidPersonIdent = checkReceivedObjects
- && config.getBoolean("fsck", "allowInvalidPersonIdent", false); //$NON-NLS-1$ //$NON-NLS-2$
- safeForWindows = checkReceivedObjects
- && config.getBoolean("fsck", "safeForWindows", false); //$NON-NLS-1$ //$NON-NLS-2$
- safeForMacOS = checkReceivedObjects
- && config.getBoolean("fsck", "safeForMacOS", false); //$NON-NLS-1$ //$NON-NLS-2$
-
allowCreates = true;
allowDeletes = !config.getBoolean("receive", "denydeletes", false); //$NON-NLS-1$ //$NON-NLS-2$
allowNonFastForwards = !config.getBoolean("receive", //$NON-NLS-1$
@@ -349,16 +332,6 @@
true);
signedPush = SignedPushConfig.KEY.parse(config);
}
-
- ObjectChecker newObjectChecker() {
- if (!checkReceivedObjects)
- return null;
- return new ObjectChecker()
- .setAllowLeadingZeroFileMode(allowLeadingZeroFileMode)
- .setAllowInvalidPersonIdent(allowInvalidPersonIdent)
- .setSafeForWindows(safeForWindows)
- .setSafeForMacOS(safeForMacOS);
- }
}
/**
@@ -1372,16 +1345,21 @@
}
}
- if (cmd.getType() == ReceiveCommand.Type.DELETE && ref != null
- && !ObjectId.zeroId().equals(cmd.getOldId())
- && !ref.getObjectId().equals(cmd.getOldId())) {
- // Delete commands can be sent with the old id matching our
- // advertised value, *OR* with the old id being 0{40}. Any
- // other requested old id is invalid.
- //
- cmd.setResult(Result.REJECTED_OTHER_REASON,
- JGitText.get().invalidOldIdSent);
- continue;
+ if (cmd.getType() == ReceiveCommand.Type.DELETE && ref != null) {
+ ObjectId id = ref.getObjectId();
+ if (id == null) {
+ id = ObjectId.zeroId();
+ }
+ if (!ObjectId.zeroId().equals(cmd.getOldId())
+ && !id.equals(cmd.getOldId())) {
+ // Delete commands can be sent with the old id matching our
+ // advertised value, *OR* with the old id being 0{40}. Any
+ // other requested old id is invalid.
+ //
+ cmd.setResult(Result.REJECTED_OTHER_REASON,
+ JGitText.get().invalidOldIdSent);
+ continue;
+ }
}
if (cmd.getType() == ReceiveCommand.Type.UPDATE) {
@@ -1391,8 +1369,15 @@
cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().noSuchRef);
continue;
}
+ ObjectId id = ref.getObjectId();
+ if (id == null) {
+ // We cannot update unborn branch
+ cmd.setResult(Result.REJECTED_OTHER_REASON,
+ JGitText.get().cannotUpdateUnbornBranch);
+ continue;
+ }
- if (!ref.getObjectId().equals(cmd.getOldId())) {
+ if (!id.equals(cmd.getOldId())) {
// A properly functioning client will send the same
// object id we advertised.
//
@@ -1468,10 +1453,7 @@
* @since 3.6
*/
protected void failPendingCommands() {
- for (ReceiveCommand cmd : commands) {
- if (cmd.getResult() == Result.NOT_ATTEMPTED)
- cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().transactionAborted);
- }
+ ReceiveCommand.abort(commands);
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java
index e53c04b..8038fa4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleFetchConnection.java
@@ -161,16 +161,23 @@
}
private String readLine(final byte[] hdrbuf) throws IOException {
- bin.mark(hdrbuf.length);
- final int cnt = bin.read(hdrbuf);
- int lf = 0;
- while (lf < cnt && hdrbuf[lf] != '\n')
- lf++;
- bin.reset();
- IO.skipFully(bin, lf);
- if (lf < cnt && hdrbuf[lf] == '\n')
- IO.skipFully(bin, 1);
- return RawParseUtils.decode(Constants.CHARSET, hdrbuf, 0, lf);
+ StringBuilder line = new StringBuilder();
+ boolean done = false;
+ while (!done) {
+ bin.mark(hdrbuf.length);
+ final int cnt = bin.read(hdrbuf);
+ int lf = 0;
+ while (lf < cnt && hdrbuf[lf] != '\n')
+ lf++;
+ bin.reset();
+ IO.skipFully(bin, lf);
+ if (lf < cnt && hdrbuf[lf] == '\n') {
+ IO.skipFully(bin, 1);
+ done = true;
+ }
+ line.append(RawParseUtils.decode(Constants.CHARSET, hdrbuf, 0, lf));
+ }
+ return line.toString();
}
public boolean didFetchTestConnectivity() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ChainingCredentialsProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ChainingCredentialsProvider.java
index 3e0ee2f..3941d3c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ChainingCredentialsProvider.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ChainingCredentialsProvider.java
@@ -113,19 +113,18 @@
throws UnsupportedCredentialItem {
for (CredentialsProvider p : credentialProviders) {
if (p.supports(items)) {
- p.get(uri, items);
- if (isAnyNull(items))
+ if (!p.get(uri, items)) {
+ if (p.isInteractive()) {
+ return false; // user cancelled the request
+ }
continue;
+ }
+ if (isAnyNull(items)) {
+ continue;
+ }
return true;
}
}
return false;
}
-
- private boolean isAnyNull(CredentialItem... items) {
- for (CredentialItem i : items)
- if (i == null)
- return true;
- return false;
- }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Connection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Connection.java
index 0ff9fce..da288ec 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Connection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Connection.java
@@ -59,8 +59,7 @@
*
* @see Transport
*/
-public interface Connection {
-
+public interface Connection extends AutoCloseable {
/**
* Get the complete map of refs advertised as available for fetching or
* pushing.
@@ -108,6 +107,10 @@
* <p>
* If additional messages were produced by the remote peer, these should
* still be retained in the connection instance for {@link #getMessages()}.
+ * <p>
+ * {@code AutoClosable.close()} declares that it throws {@link Exception}.
+ * Implementers shouldn't throw checked exceptions. This override narrows
+ * the signature to prevent them from doing so.
*/
public void close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProvider.java
index 464d0f9..4800f68 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProvider.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProvider.java
@@ -81,6 +81,20 @@
}
/**
+ * @param items
+ * credential items to check
+ * @return {@code true} if any of the passed items is null, {@code false}
+ * otherwise
+ * @since 4.2
+ */
+ protected static boolean isAnyNull(CredentialItem... items) {
+ for (CredentialItem i : items)
+ if (i == null)
+ return true;
+ return false;
+ }
+
+ /**
* Check if the provider is interactive with the end-user.
*
* An interactive provider may try to open a dialog box, or prompt for input
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java
index 03f7c72..d9e0b93 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java
@@ -79,7 +79,7 @@
private boolean run;
- private Thread acceptThread;
+ Thread acceptThread;
private int timeout;
@@ -87,9 +87,9 @@
private volatile RepositoryResolver<DaemonClient> repositoryResolver;
- private volatile UploadPackFactory<DaemonClient> uploadPackFactory;
+ volatile UploadPackFactory<DaemonClient> uploadPackFactory;
- private volatile ReceivePackFactory<DaemonClient> receivePackFactory;
+ volatile ReceivePackFactory<DaemonClient> receivePackFactory;
/** Configure a daemon to listen on any available network port. */
public Daemon() {
@@ -326,7 +326,7 @@
}
}
- private void startClient(final Socket s) {
+ void startClient(final Socket s) {
final DaemonClient dc = new DaemonClient(this);
final SocketAddress peer = s.getRemoteSocketAddress();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
index 9aae1c3..8cb36c7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
@@ -314,8 +314,7 @@
File meta = transport.local.getDirectory();
if (meta == null)
return;
- final LockFile lock = new LockFile(new File(meta, "FETCH_HEAD"), //$NON-NLS-1$
- transport.local.getFS());
+ final LockFile lock = new LockFile(new File(meta, "FETCH_HEAD")); //$NON-NLS-1$
try {
if (lock.lock()) {
final Writer w = new OutputStreamWriter(lock.getOutputStream());
@@ -397,11 +396,17 @@
private void expandFetchTags() throws TransportException {
final Map<String, Ref> haveRefs = localRefs();
for (final Ref r : conn.getRefs()) {
- if (!isTag(r))
+ if (!isTag(r)) {
continue;
+ }
+ ObjectId id = r.getObjectId();
+ if (id == null) {
+ continue;
+ }
final Ref local = haveRefs.get(r.getName());
- if (local == null || !r.getObjectId().equals(local.getObjectId()))
+ if (local == null || !id.equals(local.getObjectId())) {
wantTag(r);
+ }
}
}
@@ -413,6 +418,11 @@
private void want(final Ref src, final RefSpec spec)
throws TransportException {
final ObjectId newId = src.getObjectId();
+ if (newId == null) {
+ throw new NullPointerException(MessageFormat.format(
+ JGitText.get().transportProvidedRefWithNoObjectId,
+ src.getName()));
+ }
if (spec.getDestination() != null) {
final TrackingRefUpdate tru = createUpdate(spec, newId);
if (newId.equals(tru.getOldObjectId()))
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
index 7e9434a..622680a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java
@@ -42,6 +42,7 @@
*/
package org.eclipse.jgit.transport;
+import java.io.File;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
@@ -85,12 +86,16 @@
public synchronized String createNonce(Repository repo, long timestamp)
throws IllegalStateException {
String path;
- if (repo instanceof DfsRepository)
+ if (repo instanceof DfsRepository) {
path = ((DfsRepository) repo).getDescription().getRepositoryName();
- else if (repo.getDirectory() != null)
- path = repo.getDirectory().getPath();
- else
- throw new IllegalStateException();
+ } else {
+ File directory = repo.getDirectory();
+ if (directory != null) {
+ path = directory.getPath();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
String input = path + ":" + String.valueOf(timestamp); //$NON-NLS-1$
byte[] rawHmac;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
index 3594ea9..998f280 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
@@ -219,7 +219,8 @@
if (credentialsProvider.supports(u, p)
&& credentialsProvider.get(uri, u, p)) {
username = u.getValue();
- password = new String(p.getValue());
+ char[] v = p.getValue();
+ password = (v == null) ? null : new String(p.getValue());
p.clear();
} else
return false;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
index b4a0902..1dfe5d9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
@@ -71,8 +71,8 @@
* to the constructor.
*/
public class JschSession implements RemoteSession {
- private final Session sock;
- private final URIish uri;
+ final Session sock;
+ final URIish uri;
/**
* Create a new session object by passing the real Jsch session and the URI
@@ -119,7 +119,7 @@
private class JschProcess extends Process {
private ChannelExec channel;
- private final int timeout;
+ final int timeout;
private InputStream inputStream;
@@ -141,7 +141,7 @@
* @throws IOException
* on problems opening streams
*/
- private JschProcess(final String commandName, int tms)
+ JschProcess(final String commandName, int tms)
throws TransportException, IOException {
timeout = tms;
try {
@@ -149,14 +149,27 @@
channel.setCommand(commandName);
setupStreams();
channel.connect(timeout > 0 ? timeout * 1000 : 0);
- if (!channel.isConnected())
+ if (!channel.isConnected()) {
+ closeOutputStream();
throw new TransportException(uri,
JGitText.get().connectionFailed);
+ }
} catch (JSchException e) {
+ closeOutputStream();
throw new TransportException(uri, e.getMessage(), e);
}
}
+ private void closeOutputStream() {
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+ }
+
private void setupStreams() throws IOException {
inputStream = channel.getInputStream();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRCCredentialsProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRCCredentialsProvider.java
index 7490999..4037545 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRCCredentialsProvider.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/NetRCCredentialsProvider.java
@@ -105,12 +105,11 @@
throw new UnsupportedCredentialItem(uri, i.getClass().getName()
+ ":" + i.getPromptText()); //$NON-NLS-1$
}
- return true;
+ return !isAnyNull(items);
}
@Override
public boolean isInteractive() {
return false;
}
-
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
index 918df94..b96fe88 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -122,14 +122,14 @@
private InputStream in;
- private byte[] buf;
+ byte[] buf;
/** Position in the input stream of {@code buf[0]}. */
private long bBase;
private int bOffset;
- private int bAvail;
+ int bAvail;
private ObjectChecker objCheck;
@@ -1049,8 +1049,11 @@
final byte[] data) throws IOException {
if (objCheck != null) {
try {
- objCheck.check(type, data);
+ objCheck.check(id, type, data);
} catch (CorruptObjectException e) {
+ if (e.getErrorType() != null) {
+ throw e;
+ }
throw new CorruptObjectException(MessageFormat.format(
JGitText.get().invalidObject,
Constants.typeString(type),
@@ -1141,13 +1144,13 @@
}
// Consume cnt bytes from the buffer.
- private void use(final int cnt) {
+ void use(final int cnt) {
bOffset += cnt;
bAvail -= cnt;
}
// Ensure at least need bytes are available in in {@link #buf}.
- private int fill(final Source src, final int need) throws IOException {
+ int fill(final Source src, final int need) throws IOException {
while (bAvail < need) {
int next = bOffset + bAvail;
int free = buf.length - next;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProgressSpinner.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProgressSpinner.java
new file mode 100644
index 0000000..ac048a1
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProgressSpinner.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A simple spinner connected to an {@code OutputStream}.
+ * <p>
+ * This is class is not thread-safe. The update method may only be used from a
+ * single thread. Updates are sent only as frequently as {@link #update()} is
+ * invoked by the caller, and are capped at no more than 2 times per second by
+ * requiring at least 500 milliseconds between updates.
+ *
+ * @since 4.2
+ */
+public class ProgressSpinner {
+ private static final long MIN_REFRESH_MILLIS = 500;
+ private static final char[] STATES = new char[] { '-', '\\', '|', '/' };
+
+ private final OutputStream out;
+ private String msg;
+ private int state;
+ private boolean write;
+ private boolean shown;
+ private long nextUpdateMillis;
+
+ /**
+ * Initialize a new spinner.
+ *
+ * @param out
+ * where to send output to.
+ */
+ public ProgressSpinner(OutputStream out) {
+ this.out = out;
+ this.write = true;
+ }
+
+ /**
+ * Begin a time consuming task.
+ *
+ * @param title
+ * description of the task, suitable for human viewing.
+ * @param delay
+ * delay to wait before displaying anything at all.
+ * @param delayUnits
+ * unit for {@code delay}.
+ */
+ public void beginTask(String title, long delay, TimeUnit delayUnits) {
+ msg = title;
+ state = 0;
+ shown = false;
+
+ long now = System.currentTimeMillis();
+ if (delay > 0) {
+ nextUpdateMillis = now + delayUnits.toMillis(delay);
+ } else {
+ send(now);
+ }
+ }
+
+ /** Update the spinner if it is showing. */
+ public void update() {
+ long now = System.currentTimeMillis();
+ if (now >= nextUpdateMillis) {
+ send(now);
+ state = (state + 1) % STATES.length;
+ }
+ }
+
+ private void send(long now) {
+ StringBuilder buf = new StringBuilder(msg.length() + 16);
+ buf.append('\r').append(msg).append("... ("); //$NON-NLS-1$
+ buf.append(STATES[state]);
+ buf.append(") "); //$NON-NLS-1$
+ shown = true;
+ write(buf.toString());
+ nextUpdateMillis = now + MIN_REFRESH_MILLIS;
+ }
+
+ /**
+ * Denote the current task completed.
+ *
+ * @param result
+ * text to print after the task's title
+ * {@code "$title ... $result"}.
+ */
+ public void endTask(String result) {
+ if (shown) {
+ write('\r' + msg + "... " + result + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ private void write(String s) {
+ if (write) {
+ try {
+ out.write(s.getBytes(UTF_8));
+ out.flush();
+ } catch (IOException e) {
+ write = false;
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java
index d8672d5..d436e08 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java
@@ -65,7 +65,6 @@
import java.util.NoSuchElementException;
import org.eclipse.jgit.dircache.DirCache;
-import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.dircache.DirCacheEntry;
@@ -107,11 +106,11 @@
Constants.R_REFS + "meta/push-certs"; //$NON-NLS-1$
private static class PendingCert {
- private PushCertificate cert;
- private PersonIdent ident;
- private Collection<ReceiveCommand> matching;
+ PushCertificate cert;
+ PersonIdent ident;
+ Collection<ReceiveCommand> matching;
- private PendingCert(PushCertificate cert, PersonIdent ident,
+ PendingCert(PushCertificate cert, PersonIdent ident,
Collection<ReceiveCommand> matching) {
this.cert = cert;
this.ident = ident;
@@ -121,8 +120,8 @@
private final Repository db;
private final List<PendingCert> pending;
- private ObjectReader reader;
- private RevCommit commit;
+ ObjectReader reader;
+ RevCommit commit;
/**
* Create a new store backed by the given repository.
@@ -270,7 +269,7 @@
};
}
- private void load() throws IOException {
+ void load() throws IOException {
close();
reader = db.newObjectReader();
Ref ref = db.getRefDatabase().exactRef(REF_NAME);
@@ -283,7 +282,7 @@
}
}
- private static PushCertificate read(TreeWalk tw) throws IOException {
+ static PushCertificate read(TreeWalk tw) throws IOException {
if (tw == null || (tw.getRawMode(0) & TYPE_FILE) != TYPE_FILE) {
return null;
}
@@ -448,13 +447,10 @@
}
private DirCache newDirCache() throws IOException {
- DirCache dc = DirCache.newInCore();
if (commit != null) {
- DirCacheBuilder b = dc.builder();
- b.addTree(new byte[0], DirCacheEntry.STAGE_0, reader, commit.getTree());
- b.finish();
+ return DirCache.read(reader, commit.getTree());
}
- return dc;
+ return DirCache.newInCore();
}
private ObjectId saveCert(ObjectInserter inserter, DirCache dc,
@@ -532,7 +528,7 @@
return TreeWalk.forPath(reader, pathName(refName), commit.getTree());
}
- private static String pathName(String refName) {
+ static String pathName(String refName) {
return refName + "@{cert}"; //$NON-NLS-1$
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
index 9721ee9..5cea882 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
@@ -47,6 +47,7 @@
import java.io.OutputStream;
import java.text.MessageFormat;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -183,11 +184,17 @@
private Map<String, RemoteRefUpdate> prepareRemoteUpdates()
throws TransportException {
+ boolean atomic = transport.isPushAtomic();
final Map<String, RemoteRefUpdate> result = new HashMap<String, RemoteRefUpdate>();
for (final RemoteRefUpdate rru : toPush.values()) {
final Ref advertisedRef = connection.getRef(rru.getRemoteName());
- final ObjectId advertisedOld = (advertisedRef == null ? ObjectId
- .zeroId() : advertisedRef.getObjectId());
+ ObjectId advertisedOld = null;
+ if (advertisedRef != null) {
+ advertisedOld = advertisedRef.getObjectId();
+ }
+ if (advertisedOld == null) {
+ advertisedOld = ObjectId.zeroId();
+ }
if (rru.getNewObjectId().equals(advertisedOld)) {
if (rru.isDelete()) {
@@ -205,8 +212,14 @@
if (rru.isExpectingOldObjectId()
&& !rru.getExpectedOldObjectId().equals(advertisedOld)) {
rru.setStatus(Status.REJECTED_REMOTE_CHANGED);
+ if (atomic) {
+ return rejectAll();
+ }
continue;
}
+ if (!rru.isExpectingOldObjectId()) {
+ rru.setExpectedOldObjectId(advertisedOld);
+ }
// create ref (hasn't existed on remote side) and delete ref
// are always fast-forward commands, feasible at this level
@@ -236,14 +249,28 @@
JGitText.get().readingObjectsFromLocalRepositoryFailed, x.getMessage()), x);
}
rru.setFastForward(fastForward);
- if (!fastForward && !rru.isForceUpdate())
+ if (!fastForward && !rru.isForceUpdate()) {
rru.setStatus(Status.REJECTED_NONFASTFORWARD);
- else
+ if (atomic) {
+ return rejectAll();
+ }
+ } else {
result.put(rru.getRemoteName(), rru);
+ }
}
return result;
}
+ private Map<String, RemoteRefUpdate> rejectAll() {
+ for (RemoteRefUpdate rru : toPush.values()) {
+ if (rru.getStatus() == Status.NOT_ATTEMPTED) {
+ rru.setStatus(RemoteRefUpdate.Status.REJECTED_OTHER_REASON);
+ rru.setMessage(JGitText.get().transactionAborted);
+ }
+ }
+ return Collections.emptyMap();
+ }
+
private void modifyUpdatesForDryRun() {
for (final RemoteRefUpdate rru : toPush.values())
if (rru.getStatus() == Status.NOT_ATTEMPTED)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java
index 7c44dba..2b21c4a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java
@@ -43,9 +43,13 @@
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
+
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import org.eclipse.jgit.internal.JGitText;
@@ -127,6 +131,31 @@
}
/**
+ * Filter a collection of commands according to result.
+ *
+ * @param in
+ * commands to filter.
+ * @param want
+ * desired status to filter by.
+ * @return a copy of the command list containing only those commands with
+ * the desired status.
+ * @since 4.2
+ */
+ public static List<ReceiveCommand> filter(Iterable<ReceiveCommand> in,
+ Result want) {
+ List<ReceiveCommand> r;
+ if (in instanceof Collection)
+ r = new ArrayList<>(((Collection<?>) in).size());
+ else
+ r = new ArrayList<>();
+ for (ReceiveCommand cmd : in) {
+ if (cmd.getResult() == want)
+ r.add(cmd);
+ }
+ return r;
+ }
+
+ /**
* Filter a list of commands according to result.
*
* @param commands
@@ -138,13 +167,27 @@
* @since 2.0
*/
public static List<ReceiveCommand> filter(List<ReceiveCommand> commands,
- final Result want) {
- List<ReceiveCommand> r = new ArrayList<ReceiveCommand>(commands.size());
- for (final ReceiveCommand cmd : commands) {
- if (cmd.getResult() == want)
- r.add(cmd);
+ Result want) {
+ return filter((Iterable<ReceiveCommand>) commands, want);
+ }
+
+ /**
+ * Set unprocessed commands as failed due to transaction aborted.
+ * <p>
+ * If a command is still {@link Result#NOT_ATTEMPTED} it will be set to
+ * {@link Result#REJECTED_OTHER_REASON}.
+ *
+ * @param commands
+ * commands to mark as failed.
+ * @since 4.2
+ */
+ public static void abort(Iterable<ReceiveCommand> commands) {
+ for (ReceiveCommand c : commands) {
+ if (c.getResult() == NOT_ATTEMPTED) {
+ c.setResult(REJECTED_OTHER_REASON,
+ JGitText.get().transactionAborted);
+ }
}
- return r;
}
private final ObjectId oldId;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
index 66ffc3a..0e803bd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java
@@ -457,10 +457,6 @@
if (i != -1) {
if (s.indexOf('*', i + 1) > i)
return false;
- if (i > 0 && s.charAt(i - 1) != '/')
- return false;
- if (i < s.length() - 1 && s.charAt(i + 1) != '/')
- return false;
}
return true;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
index 1b82a36..5c58346 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteRefUpdate.java
@@ -125,7 +125,7 @@
OK;
}
- private final ObjectId expectedOldObjectId;
+ private ObjectId expectedOldObjectId;
private final ObjectId newObjectId;
@@ -440,6 +440,10 @@
return message;
}
+ void setExpectedOldObjectId(ObjectId id) {
+ expectedOldObjectId = id;
+ }
+
void setStatus(final Status status) {
this.status = status;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java
index cf388e2..fe9f2a3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java
@@ -78,12 +78,8 @@
* @see SideBandOutputStream
*/
class SideBandInputStream extends InputStream {
- private static final String PFX_REMOTE = JGitText.get().prefixRemote;
-
static final int CH_DATA = 1;
-
static final int CH_PROGRESS = 2;
-
static final int CH_ERROR = 3;
private static Pattern P_UNBOUNDED = Pattern
@@ -174,7 +170,7 @@
continue;
case CH_ERROR:
eof = true;
- throw new TransportException(PFX_REMOTE + readString(available));
+ throw new TransportException(remote(readString(available)));
default:
throw new PackProtocolException(
MessageFormat.format(JGitText.get().invalidChannel,
@@ -241,7 +237,18 @@
}
private void beginTask(final int totalWorkUnits) {
- monitor.beginTask(PFX_REMOTE + currentTask, totalWorkUnits);
+ monitor.beginTask(remote(currentTask), totalWorkUnits);
+ }
+
+ private static String remote(String msg) {
+ String prefix = JGitText.get().prefixRemote;
+ StringBuilder r = new StringBuilder(prefix.length() + msg.length() + 1);
+ r.append(prefix);
+ if (prefix.length() > 0 && prefix.charAt(prefix.length() - 1) != ' ') {
+ r.append(' ');
+ }
+ r.append(msg);
+ return r.toString();
}
private String readString(final int len) throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TestProtocol.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TestProtocol.java
index 5243010..5fd2f84 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TestProtocol.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TestProtocol.java
@@ -78,17 +78,17 @@
private static final String SCHEME = "test"; //$NON-NLS-1$
private class Handle {
- private final C req;
- private final Repository remote;
+ final C req;
+ final Repository remote;
- private Handle(C req, Repository remote) {
+ Handle(C req, Repository remote) {
this.req = req;
this.remote = remote;
}
}
- private final UploadPackFactory<C> uploadPackFactory;
- private final ReceivePackFactory<C> receivePackFactory;
+ final UploadPackFactory<C> uploadPackFactory;
+ final ReceivePackFactory<C> receivePackFactory;
private final HashMap<URIish, Handle> handles;
/**
@@ -165,7 +165,7 @@
private class TransportInternal extends Transport implements PackTransport {
private final Handle handle;
- private TransportInternal(Repository local, URIish uri, Handle handle) {
+ TransportInternal(Repository local, URIish uri, Handle handle) {
super(local, uri);
this.handle = handle;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java
index 1ef3fbf..5aae5ea 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java
@@ -52,10 +52,10 @@
/** Update of a locally stored tracking branch. */
public class TrackingRefUpdate {
private final String remoteName;
- private final String localName;
- private boolean forceUpdate;
- private ObjectId oldObjectId;
- private ObjectId newObjectId;
+ final String localName;
+ boolean forceUpdate;
+ ObjectId oldObjectId;
+ ObjectId newObjectId;
private RefUpdate.Result result;
private ReceiveCommand cmd;
@@ -142,7 +142,7 @@
}
final class Command extends ReceiveCommand {
- private Command() {
+ Command() {
super(oldObjectId, newObjectId, localName);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
index f4de821..72c9c8b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
@@ -43,12 +43,20 @@
package org.eclipse.jgit.transport;
+import static org.eclipse.jgit.util.StringUtils.equalsIgnoreCase;
+import static org.eclipse.jgit.util.StringUtils.toLowerCase;
+
+import java.io.File;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.internal.storage.file.LazyObjectIdSetFile;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Config.SectionParser;
import org.eclipse.jgit.lib.ObjectChecker;
+import org.eclipse.jgit.lib.ObjectIdSet;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.SystemReader;
@@ -58,6 +66,8 @@
* parameters.
*/
public class TransferConfig {
+ private static final String FSCK = "fsck"; //$NON-NLS-1$
+
/** Key for {@link Config#get(SectionParser)}. */
public static final Config.SectionParser<TransferConfig> KEY = new SectionParser<TransferConfig>() {
public TransferConfig parse(final Config cfg) {
@@ -65,34 +75,67 @@
}
};
- private final boolean checkReceivedObjects;
- private final boolean allowLeadingZeroFileMode;
+ enum FsckMode {
+ ERROR, WARN, IGNORE;
+ }
+
+ private final boolean fetchFsck;
+ private final boolean receiveFsck;
+ private final String fsckSkipList;
+ private final EnumSet<ObjectChecker.ErrorType> ignore;
private final boolean allowInvalidPersonIdent;
private final boolean safeForWindows;
private final boolean safeForMacOS;
private final boolean allowTipSha1InWant;
private final boolean allowReachableSha1InWant;
- private final String[] hideRefs;
+ final String[] hideRefs;
TransferConfig(final Repository db) {
this(db.getConfig());
}
- private TransferConfig(final Config rc) {
- checkReceivedObjects = rc.getBoolean(
- "fetch", "fsckobjects", //$NON-NLS-1$ //$NON-NLS-2$
- rc.getBoolean("transfer", "fsckobjects", false)); //$NON-NLS-1$ //$NON-NLS-2$
- allowLeadingZeroFileMode = checkReceivedObjects
- && rc.getBoolean("fsck", "allowLeadingZeroFileMode", false); //$NON-NLS-1$ //$NON-NLS-2$
- allowInvalidPersonIdent = checkReceivedObjects
- && rc.getBoolean("fsck", "allowInvalidPersonIdent", false); //$NON-NLS-1$ //$NON-NLS-2$
- safeForWindows = checkReceivedObjects
- && rc.getBoolean("fsck", "safeForWindows", //$NON-NLS-1$ //$NON-NLS-2$
+ TransferConfig(final Config rc) {
+ boolean fsck = rc.getBoolean("transfer", "fsckobjects", false); //$NON-NLS-1$ //$NON-NLS-2$
+ fetchFsck = rc.getBoolean("fetch", "fsckobjects", fsck); //$NON-NLS-1$ //$NON-NLS-2$
+ receiveFsck = rc.getBoolean("receive", "fsckobjects", fsck); //$NON-NLS-1$ //$NON-NLS-2$
+ fsckSkipList = rc.getString(FSCK, null, "skipList"); //$NON-NLS-1$
+ allowInvalidPersonIdent = rc.getBoolean(FSCK, "allowInvalidPersonIdent", false); //$NON-NLS-1$
+ safeForWindows = rc.getBoolean(FSCK, "safeForWindows", //$NON-NLS-1$
SystemReader.getInstance().isWindows());
- safeForMacOS = checkReceivedObjects
- && rc.getBoolean("fsck", "safeForMacOS", //$NON-NLS-1$ //$NON-NLS-2$
+ safeForMacOS = rc.getBoolean(FSCK, "safeForMacOS", //$NON-NLS-1$
SystemReader.getInstance().isMacOS());
+ ignore = EnumSet.noneOf(ObjectChecker.ErrorType.class);
+ EnumSet<ObjectChecker.ErrorType> set = EnumSet
+ .noneOf(ObjectChecker.ErrorType.class);
+ for (String key : rc.getNames(FSCK)) {
+ if (equalsIgnoreCase(key, "skipList") //$NON-NLS-1$
+ || equalsIgnoreCase(key, "allowLeadingZeroFileMode") //$NON-NLS-1$
+ || equalsIgnoreCase(key, "allowInvalidPersonIdent") //$NON-NLS-1$
+ || equalsIgnoreCase(key, "safeForWindows") //$NON-NLS-1$
+ || equalsIgnoreCase(key, "safeForMacOS")) { //$NON-NLS-1$
+ continue;
+ }
+
+ ObjectChecker.ErrorType id = FsckKeyNameHolder.parse(key);
+ if (id != null) {
+ switch (rc.getEnum(FSCK, null, key, FsckMode.ERROR)) {
+ case ERROR:
+ ignore.remove(id);
+ break;
+ case WARN:
+ case IGNORE:
+ ignore.add(id);
+ break;
+ }
+ set.add(id);
+ }
+ }
+ if (!set.contains(ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE)
+ && rc.getBoolean(FSCK, "allowLeadingZeroFileMode", false)) { //$NON-NLS-1$
+ ignore.add(ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE);
+ }
+
allowTipSha1InWant = rc.getBoolean(
"uploadpack", "allowtipsha1inwant", false); //$NON-NLS-1$ //$NON-NLS-2$
allowReachableSha1InWant = rc.getBoolean(
@@ -105,14 +148,38 @@
* enabled in the repository configuration.
* @since 3.6
*/
+ @Nullable
public ObjectChecker newObjectChecker() {
- if (!checkReceivedObjects)
+ return newObjectChecker(fetchFsck);
+ }
+
+ /**
+ * @return checker to verify objects pushed into this repository, or null if
+ * checking is not enabled in the repository configuration.
+ * @since 4.2
+ */
+ @Nullable
+ public ObjectChecker newReceiveObjectChecker() {
+ return newObjectChecker(receiveFsck);
+ }
+
+ private ObjectChecker newObjectChecker(boolean check) {
+ if (!check) {
return null;
+ }
return new ObjectChecker()
- .setAllowLeadingZeroFileMode(allowLeadingZeroFileMode)
+ .setIgnore(ignore)
.setAllowInvalidPersonIdent(allowInvalidPersonIdent)
.setSafeForWindows(safeForWindows)
- .setSafeForMacOS(safeForMacOS);
+ .setSafeForMacOS(safeForMacOS)
+ .setSkipList(skipList());
+ }
+
+ private ObjectIdSet skipList() {
+ if (fsckSkipList != null && !fsckSkipList.isEmpty()) {
+ return new LazyObjectIdSetFile(new File(fsckSkipList));
+ }
+ return null;
}
/**
@@ -161,4 +228,34 @@
}
};
}
+
+ static class FsckKeyNameHolder {
+ private static final Map<String, ObjectChecker.ErrorType> errors;
+
+ static {
+ errors = new HashMap<>();
+ for (ObjectChecker.ErrorType m : ObjectChecker.ErrorType.values()) {
+ errors.put(keyNameFor(m.name()), m);
+ }
+ }
+
+ @Nullable
+ static ObjectChecker.ErrorType parse(String key) {
+ return errors.get(toLowerCase(key));
+ }
+
+ private static String keyNameFor(String name) {
+ StringBuilder r = new StringBuilder(name.length());
+ for (int i = 0; i < name.length(); i++) {
+ char c = name.charAt(i);
+ if (c != '_') {
+ r.append(c);
+ }
+ }
+ return toLowerCase(r.toString());
+ }
+
+ private FsckKeyNameHolder() {
+ }
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
index 2185622..9e6d1f6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
@@ -53,6 +53,7 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
+import java.io.PrintStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@@ -70,8 +71,11 @@
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
+import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.hooks.Hooks;
+import org.eclipse.jgit.hooks.PrePushHook;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
@@ -94,7 +98,7 @@
* Transport instances and the connections they create are not thread-safe.
* Callers must ensure a transport is accessed by only one thread at a time.
*/
-public abstract class Transport {
+public abstract class Transport implements AutoCloseable {
/** Type of operation a Transport is being opened for. */
public enum Operation {
/** Transport is to fetch objects locally. */
@@ -557,8 +561,13 @@
continue;
}
- if (proto.canHandle(uri, local, remoteName))
- return proto.open(uri, local, remoteName);
+ if (proto.canHandle(uri, local, remoteName)) {
+ Transport tn = proto.open(uri, local, remoteName);
+ tn.prePush = Hooks.prePush(local, tn.hookOutRedirect);
+ tn.prePush.setRemoteLocation(uri.toString());
+ tn.prePush.setRemoteName(remoteName);
+ return tn;
+ }
}
throw new NotSupportedException(MessageFormat.format(JGitText.get().URINotSupported, uri));
@@ -743,6 +752,9 @@
/** Should push produce thin-pack when sending objects to remote repository. */
private boolean pushThin = DEFAULT_PUSH_THIN;
+ /** Should push be all-or-nothing atomic behavior? */
+ private boolean pushAtomic;
+
/** Should push just check for operation result, not really push. */
private boolean dryRun;
@@ -761,6 +773,9 @@
/** Assists with authentication the connection. */
private CredentialsProvider credentialsProvider;
+ private PrintStream hookOutRedirect;
+
+ private PrePushHook prePush;
/**
* Create a new transport instance.
*
@@ -778,6 +793,7 @@
this.uri = uri;
this.objectChecker = tc.newObjectChecker();
this.credentialsProvider = CredentialsProvider.getDefault();
+ prePush = Hooks.prePush(local, hookOutRedirect);
}
/**
@@ -957,6 +973,31 @@
}
/**
+ * Default setting is false.
+ *
+ * @return true if push requires all-or-nothing atomic behavior.
+ * @since 4.2
+ */
+ public boolean isPushAtomic() {
+ return pushAtomic;
+ }
+
+ /**
+ * Request atomic push (all references succeed, or none do).
+ * <p>
+ * Server must also support atomic push. If the server does not support the
+ * feature the push will abort without making changes.
+ *
+ * @param atomic
+ * true when push should be an all-or-nothing operation.
+ * @see PackTransport
+ * @since 4.2
+ */
+ public void setPushAtomic(final boolean atomic) {
+ this.pushAtomic = atomic;
+ }
+
+ /**
* @return true if destination refs should be removed if they no longer
* exist at the source repository.
*/
@@ -1196,6 +1237,15 @@
if (toPush.isEmpty())
throw new TransportException(JGitText.get().nothingToPush);
}
+ if (prePush != null) {
+ try {
+ prePush.setRefs(toPush);
+ prePush.call();
+ } catch (AbortedByHookException | IOException e) {
+ throw new TransportException(e.getMessage(), e);
+ }
+ }
+
final PushProcess pushProcess = new PushProcess(this, toPush, out);
return pushProcess.execute(monitor);
}
@@ -1303,6 +1353,10 @@
* must close that network socket, disconnecting the two peers. If the
* remote repository is actually local (same system) this method must close
* any open file handles used to read the "remote" repository.
+ * <p>
+ * {@code AutoClosable.close()} declares that it throws {@link Exception}.
+ * Implementers shouldn't throw checked exceptions. This override narrows
+ * the signature to prevent them from doing so.
*/
public abstract void close();
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
index 745cdb7..23c506b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
@@ -125,10 +125,10 @@
};
/** User information necessary to connect to S3. */
- private final AmazonS3 s3;
+ final AmazonS3 s3;
/** Bucket the remote repository is stored in. */
- private final String bucket;
+ final String bucket;
/**
* Key prefix which all objects related to the repository start with.
@@ -148,8 +148,9 @@
super(local, uri);
Properties props = loadProperties();
- if (!props.containsKey("tmpdir") && local.getDirectory() != null) //$NON-NLS-1$
- props.put("tmpdir", local.getDirectory().getPath()); //$NON-NLS-1$
+ File directory = local.getDirectory();
+ if (!props.containsKey("tmpdir") && directory != null) //$NON-NLS-1$
+ props.put("tmpdir", directory.getPath()); //$NON-NLS-1$
s3 = new AmazonS3(props);
bucket = uri.getHost();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
index b27fa0d..52f0f04 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
@@ -46,6 +46,7 @@
package org.eclipse.jgit.transport;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
@@ -235,9 +236,10 @@
ProcessBuilder pb = new ProcessBuilder();
pb.command(args);
- if (local.getDirectory() != null)
+ File directory = local.getDirectory();
+ if (directory != null)
pb.environment().put(Constants.GIT_DIR_KEY,
- local.getDirectory().getPath());
+ directory.getPath());
try {
return pb.start();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
index b23771e..5948278 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
@@ -218,16 +218,16 @@
sslVerify = rc.getBoolean("http", "sslVerify", true); //$NON-NLS-1$ //$NON-NLS-2$
}
- private HttpConfig() {
+ HttpConfig() {
this(new Config());
}
}
- private final URL baseUrl;
+ final URL baseUrl;
private final URL objectsUrl;
- private final HttpConfig http;
+ final HttpConfig http;
private final ProxySelector proxySelector;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
index 3700b49..3ee2feb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
@@ -83,7 +83,7 @@
* capturing groups: the first containing the user and the second containing
* the password
*/
- private static final String OPT_USER_PWD_P = "(?:([^/:@]+)(?::([^\\\\/]+))?@)?"; //$NON-NLS-1$
+ private static final String OPT_USER_PWD_P = "(?:([^/:]+)(?::([^\\\\/]+))?@)?"; //$NON-NLS-1$
/**
* Part of a pattern which matches the host part of URIs. Defines one
@@ -137,7 +137,11 @@
+ OPT_PORT_P //
+ "(" // open a group capturing the user-home-dir-part //$NON-NLS-1$
+ (USER_HOME_P + "?") //$NON-NLS-1$
- + "[\\\\/])" //$NON-NLS-1$
+ + "(?:" // start non capturing group for host //$NON-NLS-1$
+ // separator or end of line
+ + "[\\\\/])|$" //$NON-NLS-1$
+ + ")" // close non capturing group for the host//$NON-NLS-1$
+ // separator or end of line
+ ")?" // close the optional group containing hostname //$NON-NLS-1$
+ "(.+)?" //$NON-NLS-1$
+ "$"); //$NON-NLS-1$
@@ -593,6 +597,8 @@
private static boolean eq(final String a, final String b) {
if (a == b)
return true;
+ if (StringUtils.isEmptyOrNull(a) && StringUtils.isEmptyOrNull(b))
+ return true;
if (a == null || b == null)
return false;
return a.equals(b);
@@ -638,7 +644,7 @@
if (getPath() != null) {
if (getScheme() != null) {
- if (!getPath().startsWith("/")) //$NON-NLS-1$
+ if (!getPath().startsWith("/") && !getPath().isEmpty()) //$NON-NLS-1$
r.append('/');
} else if (getHost() != null)
r.append(':');
@@ -709,9 +715,9 @@
*/
public String getHumanishName() throws IllegalArgumentException {
String s = getPath();
- if ("/".equals(s)) //$NON-NLS-1$
+ if ("/".equals(s) || "".equals(s)) //$NON-NLS-1$ //$NON-NLS-2$
s = getHost();
- if ("".equals(s) || s == null) //$NON-NLS-1$
+ if (s == null) // $NON-NLS-1$
throw new IllegalArgumentException();
String[] elements;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
index e55b984..fe03bdc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
@@ -47,22 +47,28 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.spec.InvalidKeySpecException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.KeySpec;
import java.text.MessageFormat;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
-import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.bind.DatatypeConverter;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.util.Base64;
abstract class WalkEncryption {
static final WalkEncryption NONE = new NoEncryption();
@@ -71,29 +77,40 @@
static final String JETS3T_CRYPTO_ALG = "jets3t-crypto-alg"; //$NON-NLS-1$
- abstract OutputStream encrypt(OutputStream os) throws IOException;
+ // Note: encrypt -> request state machine, step 1.
+ abstract OutputStream encrypt(OutputStream output) throws IOException;
- abstract InputStream decrypt(InputStream in) throws IOException;
+ // Note: encrypt -> request state machine, step 2.
+ abstract void request(HttpURLConnection conn, String prefix) throws IOException;
- abstract void request(HttpURLConnection u, String prefix);
+ // Note: validate -> decrypt state machine, step 1.
+ abstract void validate(HttpURLConnection conn, String prefix) throws IOException;
- abstract void validate(HttpURLConnection u, String p) throws IOException;
+ // Note: validate -> decrypt state machine, step 2.
+ abstract InputStream decrypt(InputStream input) throws IOException;
- protected void validateImpl(final HttpURLConnection u, final String p,
+
+ // TODO mixed ciphers
+ // consider permitting mixed ciphers to facilitate algorithm migration
+ // i.e. user keeps the password, but changes the algorithm
+ // then existing remote entries will still be readable
+ protected void validateImpl(final HttpURLConnection u, final String prefix,
final String version, final String name) throws IOException {
String v;
- v = u.getHeaderField(p + JETS3T_CRYPTO_VER);
+ v = u.getHeaderField(prefix + JETS3T_CRYPTO_VER);
if (v == null)
v = ""; //$NON-NLS-1$
if (!version.equals(v))
throw new IOException(MessageFormat.format(JGitText.get().unsupportedEncryptionVersion, v));
- v = u.getHeaderField(p + JETS3T_CRYPTO_ALG);
+ v = u.getHeaderField(prefix + JETS3T_CRYPTO_ALG);
if (v == null)
v = ""; //$NON-NLS-1$
- if (!name.equals(v))
- throw new IOException(JGitText.get().unsupportedEncryptionAlgorithm + v);
+ // Standard names are not case-sensitive.
+ // http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
+ if (!name.equalsIgnoreCase(v))
+ throw new IOException(MessageFormat.format(JGitText.get().unsupportedEncryptionAlgorithm, v));
}
IOException error(final Throwable why) {
@@ -110,9 +127,9 @@
}
@Override
- void validate(final HttpURLConnection u, final String p)
+ void validate(final HttpURLConnection u, final String prefix)
throws IOException {
- validateImpl(u, p, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ validateImpl(u, prefix, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
@@ -126,53 +143,139 @@
}
}
- static class ObjectEncryptionV2 extends WalkEncryption {
- private static int ITERATION_COUNT = 5000;
+ // PBEParameterSpec factory for Java (version <= 7).
+ // Does not support AlgorithmParameterSpec.
+ static PBEParameterSpec java7PBEParameterSpec(byte[] salt,
+ int iterationCount) {
+ return new PBEParameterSpec(salt, iterationCount);
+ }
- private static byte[] salt = { (byte) 0xA4, (byte) 0x0B, (byte) 0xC8,
- (byte) 0x34, (byte) 0xD6, (byte) 0x95, (byte) 0xF3, (byte) 0x13 };
+ // PBEParameterSpec factory for Java (version >= 8).
+ // Adds support for AlgorithmParameterSpec.
+ static PBEParameterSpec java8PBEParameterSpec(byte[] salt,
+ int iterationCount, AlgorithmParameterSpec paramSpec) {
+ try {
+ @SuppressWarnings("boxing")
+ PBEParameterSpec instance = PBEParameterSpec.class
+ .getConstructor(byte[].class, int.class,
+ AlgorithmParameterSpec.class)
+ .newInstance(salt, iterationCount, paramSpec);
+ return instance;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
- private final String algorithmName;
+ // Current runtime version.
+ // https://docs.oracle.com/javase/7/docs/technotes/guides/versioning/spec/versioning2.html
+ static double javaVersion() {
+ return Double.parseDouble(System.getProperty("java.specification.version")); //$NON-NLS-1$
+ }
- private final SecretKey skey;
+ /**
+ * JetS3t compatibility reference: <a href=
+ * "https://bitbucket.org/jmurty/jets3t/src/156c00eb160598c2e9937fd6873f00d3190e28ca/src/org/jets3t/service/security/EncryptionUtil.java">
+ * EncryptionUtil.java</a>
+ * <p>
+ * Note: EncryptionUtil is inadequate:
+ * <li>EncryptionUtil.isCipherAvailableForUse checks encryption only which
+ * "always works", but in JetS3t both encryption and decryption use non-IV
+ * aware algorithm parameters for all PBE specs, which breaks in case of AES
+ * <li>that means that only non-IV algorithms will work round trip in
+ * JetS3t, such as PBEWithMD5AndDES and PBEWithSHAAndTwofish-CBC
+ * <li>any AES based algorithms such as "PBE...With...And...AES" will not
+ * work, since they need proper IV setup
+ */
+ static class JetS3tV2 extends WalkEncryption {
- private final PBEParameterSpec aspec;
+ static final String VERSION = "2"; //$NON-NLS-1$
- ObjectEncryptionV2(final String algo, final String key)
- throws InvalidKeySpecException, NoSuchAlgorithmException {
- algorithmName = algo;
+ static final String ALGORITHM = "PBEWithMD5AndDES"; //$NON-NLS-1$
- final PBEKeySpec s;
- s = new PBEKeySpec(key.toCharArray(), salt, ITERATION_COUNT, 32);
- skey = SecretKeyFactory.getInstance(algo).generateSecret(s);
- aspec = new PBEParameterSpec(salt, ITERATION_COUNT);
+ static final int ITERATIONS = 5000;
+
+ static final int KEY_SIZE = 32;
+
+ static final byte[] SALT = { //
+ (byte) 0xA4, (byte) 0x0B, (byte) 0xC8, (byte) 0x34, //
+ (byte) 0xD6, (byte) 0x95, (byte) 0xF3, (byte) 0x13 //
+ };
+
+ // Size 16, see com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE
+ static final byte[] ZERO_AES_IV = new byte[16];
+
+ private static final String cryptoVer = VERSION;
+
+ private final String cryptoAlg;
+
+ private final SecretKey secretKey;
+
+ private final AlgorithmParameterSpec paramSpec;
+
+ JetS3tV2(final String algo, final String key)
+ throws GeneralSecurityException {
+ cryptoAlg = algo;
+
+ // Verify if cipher is present.
+ Cipher cipher = Cipher.getInstance(cryptoAlg);
+
+ // Standard names are not case-sensitive.
+ // http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
+ String cryptoName = cryptoAlg.toUpperCase();
+
+ if (!cryptoName.startsWith("PBE")) //$NON-NLS-1$
+ throw new GeneralSecurityException(JGitText.get().encryptionOnlyPBE);
+
+ PBEKeySpec keySpec = new PBEKeySpec(key.toCharArray(), SALT, ITERATIONS, KEY_SIZE);
+ secretKey = SecretKeyFactory.getInstance(algo).generateSecret(keySpec);
+
+ // Detect algorithms which require initialization vector.
+ boolean useIV = cryptoName.contains("AES"); //$NON-NLS-1$
+
+ // PBEParameterSpec algorithm parameters are supported from Java 8.
+ boolean isJava8 = javaVersion() >= 1.8;
+
+ if (useIV && isJava8) {
+ // Support IV where possible:
+ // * since JCE provider uses random IV for PBE/AES
+ // * and there is no place to store dynamic IV in JetS3t V2
+ // * we use static IV, and tolerate increased security risk
+ // TODO back port this change to JetS3t V2
+ // See:
+ // https://bitbucket.org/jmurty/jets3t/raw/156c00eb160598c2e9937fd6873f00d3190e28ca/src/org/jets3t/service/security/EncryptionUtil.java
+ // http://cr.openjdk.java.net/~mullan/webrevs/ascarpin/webrev.00/raw_files/new/src/share/classes/com/sun/crypto/provider/PBES2Core.java
+ IvParameterSpec paramIV = new IvParameterSpec(ZERO_AES_IV);
+ paramSpec = java8PBEParameterSpec(SALT, ITERATIONS, paramIV);
+ } else {
+ // Strict legacy JetS3t V2 compatibility, with no IV support.
+ paramSpec = java7PBEParameterSpec(SALT, ITERATIONS);
+ }
+
+ // Verify if cipher + key are allowed by policy.
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
+ cipher.doFinal();
+
}
@Override
void request(final HttpURLConnection u, final String prefix) {
- u.setRequestProperty(prefix + JETS3T_CRYPTO_VER, "2"); //$NON-NLS-1$
- u.setRequestProperty(prefix + JETS3T_CRYPTO_ALG, algorithmName);
+ u.setRequestProperty(prefix + JETS3T_CRYPTO_VER, cryptoVer);
+ u.setRequestProperty(prefix + JETS3T_CRYPTO_ALG, cryptoAlg);
}
@Override
- void validate(final HttpURLConnection u, final String p)
+ void validate(final HttpURLConnection u, final String prefix)
throws IOException {
- validateImpl(u, p, "2", algorithmName); //$NON-NLS-1$
+ validateImpl(u, prefix, cryptoVer, cryptoAlg);
}
@Override
OutputStream encrypt(final OutputStream os) throws IOException {
try {
- final Cipher c = Cipher.getInstance(algorithmName);
- c.init(Cipher.ENCRYPT_MODE, skey, aspec);
- return new CipherOutputStream(os, c);
- } catch (NoSuchAlgorithmException e) {
- throw error(e);
- } catch (NoSuchPaddingException e) {
- throw error(e);
- } catch (InvalidKeyException e) {
- throw error(e);
- } catch (InvalidAlgorithmParameterException e) {
+ final Cipher cipher = Cipher.getInstance(cryptoAlg);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
+ return new CipherOutputStream(os, cipher);
+ } catch (GeneralSecurityException e) {
throw error(e);
}
}
@@ -180,18 +283,311 @@
@Override
InputStream decrypt(final InputStream in) throws IOException {
try {
- final Cipher c = Cipher.getInstance(algorithmName);
- c.init(Cipher.DECRYPT_MODE, skey, aspec);
- return new CipherInputStream(in, c);
- } catch (NoSuchAlgorithmException e) {
- throw error(e);
- } catch (NoSuchPaddingException e) {
- throw error(e);
- } catch (InvalidKeyException e) {
- throw error(e);
- } catch (InvalidAlgorithmParameterException e) {
+ final Cipher cipher = Cipher.getInstance(cryptoAlg);
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
+ return new CipherInputStream(in, cipher);
+ } catch (GeneralSecurityException e) {
throw error(e);
}
}
}
+
+ /** Encryption property names. */
+ interface Keys {
+ // Remote S3 meta: V1 algorithm name or V2 profile name.
+ String JGIT_PROFILE = "jgit-crypto-profile"; //$NON-NLS-1$
+
+ // Remote S3 meta: JGit encryption implementation version.
+ String JGIT_VERSION = "jgit-crypto-version"; //$NON-NLS-1$
+
+ // Remote S3 meta: base-64 encoded cipher algorithm parameters.
+ String JGIT_CONTEXT = "jgit-crypto-context"; //$NON-NLS-1$
+
+ // Amazon S3 connection configuration file profile property suffixes:
+ String X_ALGO = ".algo"; //$NON-NLS-1$
+ String X_KEY_ALGO = ".key.algo"; //$NON-NLS-1$
+ String X_KEY_SIZE = ".key.size"; //$NON-NLS-1$
+ String X_KEY_ITER = ".key.iter"; //$NON-NLS-1$
+ String X_KEY_SALT = ".key.salt"; //$NON-NLS-1$
+ }
+
+ /** Encryption constants and defaults. */
+ interface Vals {
+ // Compatibility defaults.
+ String DEFAULT_VERS = "0"; //$NON-NLS-1$
+ String DEFAULT_ALGO = JetS3tV2.ALGORITHM;
+ String DEFAULT_KEY_ALGO = JetS3tV2.ALGORITHM;
+ String DEFAULT_KEY_SIZE = Integer.toString(JetS3tV2.KEY_SIZE);
+ String DEFAULT_KEY_ITER = Integer.toString(JetS3tV2.ITERATIONS);
+ String DEFAULT_KEY_SALT = DatatypeConverter.printHexBinary(JetS3tV2.SALT);
+
+ String EMPTY = ""; //$NON-NLS-1$
+
+ // Match white space.
+ String REGEX_WS = "\\s+"; //$NON-NLS-1$
+
+ // Match PBE ciphers, i.e: PBEWithMD5AndDES
+ String REGEX_PBE = "(PBE).*(WITH).+(AND).+"; //$NON-NLS-1$
+
+ // Match transformation ciphers, i.e: AES/CBC/PKCS5Padding
+ String REGEX_TRANS = "(.+)/(.+)/(.+)"; //$NON-NLS-1$
+ }
+
+ static GeneralSecurityException securityError(String message) {
+ return new GeneralSecurityException(
+ MessageFormat.format(JGitText.get().encryptionError, message));
+ }
+
+ /**
+ * Base implementation of JGit symmetric encryption. Supports V2 properties
+ * format.
+ */
+ static abstract class SymmetricEncryption extends WalkEncryption
+ implements Keys, Vals {
+
+ /** Encryption profile, root name of group of related properties. */
+ final String profile;
+
+ /** Encryption version, reflects actual implementation class. */
+ final String version;
+
+ /** Full cipher algorithm name. */
+ final String cipherAlgo;
+
+ /** Cipher algorithm name for parameters lookup. */
+ final String paramsAlgo;
+
+ /** Generated secret key. */
+ final SecretKey secretKey;
+
+ SymmetricEncryption(Properties props) throws GeneralSecurityException {
+
+ profile = props.getProperty(AmazonS3.Keys.CRYPTO_ALG);
+ version = props.getProperty(AmazonS3.Keys.CRYPTO_VER);
+ String pass = props.getProperty(AmazonS3.Keys.PASSWORD);
+
+ cipherAlgo = props.getProperty(profile + X_ALGO, DEFAULT_ALGO);
+
+ String keyAlgo = props.getProperty(profile + X_KEY_ALGO, DEFAULT_KEY_ALGO);
+ String keySize = props.getProperty(profile + X_KEY_SIZE, DEFAULT_KEY_SIZE);
+ String keyIter = props.getProperty(profile + X_KEY_ITER, DEFAULT_KEY_ITER);
+ String keySalt = props.getProperty(profile + X_KEY_SALT, DEFAULT_KEY_SALT);
+
+ // Verify if cipher is present.
+ Cipher cipher = Cipher.getInstance(cipherAlgo);
+
+ // Verify if key factory is present.
+ SecretKeyFactory factory = SecretKeyFactory.getInstance(keyAlgo);
+
+ final int size;
+ try {
+ size = Integer.parseInt(keySize);
+ } catch (Exception e) {
+ throw securityError(X_KEY_SIZE + EMPTY + keySize);
+ }
+
+ final int iter;
+ try {
+ iter = Integer.parseInt(keyIter);
+ } catch (Exception e) {
+ throw securityError(X_KEY_ITER + EMPTY + keyIter);
+ }
+
+ final byte[] salt;
+ try {
+ salt = DatatypeConverter
+ .parseHexBinary(keySalt.replaceAll(REGEX_WS, EMPTY));
+ } catch (Exception e) {
+ throw securityError(X_KEY_SALT + EMPTY + keySalt);
+ }
+
+ KeySpec keySpec = new PBEKeySpec(pass.toCharArray(), salt, iter, size);
+
+ SecretKey keyBase = factory.generateSecret(keySpec);
+
+ String name = cipherAlgo.toUpperCase();
+ Matcher matcherPBE = Pattern.compile(REGEX_PBE).matcher(name);
+ Matcher matcherTrans = Pattern.compile(REGEX_TRANS).matcher(name);
+ if (matcherPBE.matches()) {
+ paramsAlgo = cipherAlgo;
+ secretKey = keyBase;
+ } else if (matcherTrans.find()) {
+ paramsAlgo = matcherTrans.group(1);
+ secretKey = new SecretKeySpec(keyBase.getEncoded(), paramsAlgo);
+ } else {
+ throw new GeneralSecurityException(MessageFormat.format(
+ JGitText.get().unsupportedEncryptionAlgorithm,
+ cipherAlgo));
+ }
+
+ // Verify if cipher + key are allowed by policy.
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+ cipher.doFinal();
+
+ }
+
+ // Shared state encrypt -> request.
+ volatile String context;
+
+ @Override
+ OutputStream encrypt(OutputStream output) throws IOException {
+ try {
+ Cipher cipher = Cipher.getInstance(cipherAlgo);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+ AlgorithmParameters params = cipher.getParameters();
+ if (params == null) {
+ context = EMPTY;
+ } else {
+ context = Base64.encodeBytes(params.getEncoded());
+ }
+ return new CipherOutputStream(output, cipher);
+ } catch (Exception e) {
+ throw error(e);
+ }
+ }
+
+ @Override
+ void request(HttpURLConnection conn, String prefix) throws IOException {
+ conn.setRequestProperty(prefix + JGIT_PROFILE, profile);
+ conn.setRequestProperty(prefix + JGIT_VERSION, version);
+ conn.setRequestProperty(prefix + JGIT_CONTEXT, context);
+ // No cleanup:
+ // single encrypt can be followed by several request
+ // from the AmazonS3.putImpl() multiple retry attempts
+ // context = null; // Cleanup encrypt -> request transition.
+ // TODO re-factor AmazonS3.putImpl to be more transaction-like
+ }
+
+ // Shared state validate -> decrypt.
+ volatile Cipher decryptCipher;
+
+ @Override
+ void validate(HttpURLConnection conn, String prefix)
+ throws IOException {
+ String prof = conn.getHeaderField(prefix + JGIT_PROFILE);
+ String vers = conn.getHeaderField(prefix + JGIT_VERSION);
+ String cont = conn.getHeaderField(prefix + JGIT_CONTEXT);
+
+ if (prof == null) {
+ throw new IOException(MessageFormat
+ .format(JGitText.get().encryptionError, JGIT_PROFILE));
+ }
+ if (vers == null) {
+ throw new IOException(MessageFormat
+ .format(JGitText.get().encryptionError, JGIT_VERSION));
+ }
+ if (cont == null) {
+ throw new IOException(MessageFormat
+ .format(JGitText.get().encryptionError, JGIT_CONTEXT));
+ }
+ if (!profile.equals(prof)) {
+ throw new IOException(MessageFormat.format(
+ JGitText.get().unsupportedEncryptionAlgorithm, prof));
+ }
+ if (!version.equals(vers)) {
+ throw new IOException(MessageFormat.format(
+ JGitText.get().unsupportedEncryptionVersion, vers));
+ }
+ try {
+ decryptCipher = Cipher.getInstance(cipherAlgo);
+ if (cont.isEmpty()) {
+ decryptCipher.init(Cipher.DECRYPT_MODE, secretKey);
+ } else {
+ AlgorithmParameters params = AlgorithmParameters
+ .getInstance(paramsAlgo);
+ params.init(Base64.decode(cont));
+ decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, params);
+ }
+ } catch (Exception e) {
+ throw error(e);
+ }
+ }
+
+ @Override
+ InputStream decrypt(InputStream input) throws IOException {
+ try {
+ return new CipherInputStream(input, decryptCipher);
+ } finally {
+ decryptCipher = null; // Cleanup validate -> decrypt transition.
+ }
+ }
+ }
+
+ /**
+ * Provides JetS3t-like encryption with AES support. Uses V1 connection file
+ * format. For reference, see: 'jgit-s3-connection-v-1.properties'.
+ */
+ static class JGitV1 extends SymmetricEncryption {
+
+ static final String VERSION = "1"; //$NON-NLS-1$
+
+ // Re-map connection properties V1 -> V2.
+ static Properties wrap(String algo, String pass) {
+ Properties props = new Properties();
+ props.put(AmazonS3.Keys.CRYPTO_ALG, algo);
+ props.put(AmazonS3.Keys.CRYPTO_VER, VERSION);
+ props.put(AmazonS3.Keys.PASSWORD, pass);
+ props.put(algo + Keys.X_ALGO, algo);
+ props.put(algo + Keys.X_KEY_ALGO, algo);
+ props.put(algo + Keys.X_KEY_ITER, DEFAULT_KEY_ITER);
+ props.put(algo + Keys.X_KEY_SIZE, DEFAULT_KEY_SIZE);
+ props.put(algo + Keys.X_KEY_SALT, DEFAULT_KEY_SALT);
+ return props;
+ }
+
+ JGitV1(String algo, String pass)
+ throws GeneralSecurityException {
+ super(wrap(algo, pass));
+ String name = cipherAlgo.toUpperCase();
+ Matcher matcherPBE = Pattern.compile(REGEX_PBE).matcher(name);
+ if (!matcherPBE.matches())
+ throw new GeneralSecurityException(
+ JGitText.get().encryptionOnlyPBE);
+ }
+
+ }
+
+ /**
+ * Supports both PBE and non-PBE algorithms. Uses V2 connection file format.
+ * For reference, see: 'jgit-s3-connection-v-2.properties'.
+ */
+ static class JGitV2 extends SymmetricEncryption {
+
+ static final String VERSION = "2"; //$NON-NLS-1$
+
+ JGitV2(Properties props)
+ throws GeneralSecurityException {
+ super(props);
+ }
+ }
+
+ /**
+ * Encryption factory.
+ *
+ * @param props
+ * @return instance
+ * @throws GeneralSecurityException
+ */
+ static WalkEncryption instance(Properties props)
+ throws GeneralSecurityException {
+
+ String algo = props.getProperty(AmazonS3.Keys.CRYPTO_ALG, Vals.DEFAULT_ALGO);
+ String vers = props.getProperty(AmazonS3.Keys.CRYPTO_VER, Vals.DEFAULT_VERS);
+ String pass = props.getProperty(AmazonS3.Keys.PASSWORD);
+
+ if (pass == null) // Disable encryption.
+ return WalkEncryption.NONE;
+
+ switch (vers) {
+ case Vals.DEFAULT_VERS:
+ return new JetS3tV2(algo, pass);
+ case JGitV1.VERSION:
+ return new JGitV1(algo, pass);
+ case JGitV2.VERSION:
+ return new JGitV2(props);
+ default:
+ throw new GeneralSecurityException(MessageFormat.format(
+ JGitText.get().unsupportedEncryptionVersion, vers));
+ }
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
index dc9dee5..17edfdc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
@@ -115,10 +115,10 @@
*/
class WalkFetchConnection extends BaseFetchConnection {
/** The repository this transport fetches into, or pushes out of. */
- private final Repository local;
+ final Repository local;
/** If not null the validator for received objects. */
- private final ObjectChecker objCheck;
+ final ObjectChecker objCheck;
/**
* List of all remote repositories we may need to get objects out of.
@@ -180,12 +180,12 @@
*/
private final HashMap<ObjectId, List<Throwable>> fetchErrors;
- private String lockMessage;
+ String lockMessage;
- private final List<PackLock> packLocks;
+ final List<PackLock> packLocks;
/** Inserter to write objects onto {@link #local}. */
- private final ObjectInserter inserter;
+ final ObjectInserter inserter;
/** Inserter to read objects from {@link #local}. */
private final ObjectReader reader;
@@ -267,6 +267,10 @@
final HashSet<ObjectId> inWorkQueue = new HashSet<ObjectId>();
for (final Ref r : want) {
final ObjectId id = r.getObjectId();
+ if (id == null) {
+ throw new NullPointerException(MessageFormat.format(
+ JGitText.get().transportProvidedRefWithNoObjectId, r.getName()));
+ }
try {
final RevObject obj = revWalk.parseAny(id);
if (obj.has(COMPLETE))
@@ -633,10 +637,11 @@
final byte[] raw = uol.getCachedBytes();
if (objCheck != null) {
try {
- objCheck.check(type, raw);
+ objCheck.check(id, type, raw);
} catch (CorruptObjectException e) {
- throw new TransportException(MessageFormat.format(JGitText.get().transportExceptionInvalid
- , Constants.typeString(type), id.name(), e.getMessage()));
+ throw new TransportException(MessageFormat.format(
+ JGitText.get().transportExceptionInvalid,
+ Constants.typeString(type), id.name(), e.getMessage()));
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
index deecb8e..4eaf3f9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
@@ -103,7 +103,7 @@
private final URIish uri;
/** Database connection to the remote repository. */
- private final WalkRemoteObjectDatabase dest;
+ final WalkRemoteObjectDatabase dest;
/** The configured transport we were constructed by. */
private final Transport transport;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
index 41e593e..5813635 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
@@ -49,6 +49,7 @@
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
+import org.eclipse.jgit.attributes.AttributesNode;
import org.eclipse.jgit.dircache.DirCacheCheckout;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -58,6 +59,7 @@
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.eclipse.jgit.util.Paths;
/**
* Walks a Git tree (directory) in Git sort order.
@@ -93,6 +95,13 @@
AbstractTreeIterator matches;
/**
+ * Parsed rules of .gitattributes file if it exists.
+ *
+ * @since 4.2
+ */
+ protected AttributesNode attributesNode;
+
+ /**
* Number of entries we moved forward to force a D/F conflict match.
*
* @see NameConflictTreeWalk
@@ -320,6 +329,42 @@
}
/**
+ * Seek the iterator on a file, if present.
+ *
+ * @param name
+ * file name to find (will not find a directory).
+ * @return true if the file exists in this tree; false otherwise.
+ * @throws CorruptObjectException
+ * tree is invalid.
+ * @since 4.2
+ */
+ public boolean findFile(String name) throws CorruptObjectException {
+ return findFile(Constants.encode(name));
+ }
+
+ /**
+ * Seek the iterator on a file, if present.
+ *
+ * @param name
+ * file name to find (will not find a directory).
+ * @return true if the file exists in this tree; false otherwise.
+ * @throws CorruptObjectException
+ * tree is invalid.
+ * @since 4.2
+ */
+ public boolean findFile(byte[] name) throws CorruptObjectException {
+ for (; !eof(); next(1)) {
+ int cmp = pathCompare(name, 0, name.length, 0, pathOffset);
+ if (cmp == 0) {
+ return true;
+ } else if (cmp > 0) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
* Compare the path of this current entry to a raw buffer.
*
* @param buf
@@ -338,20 +383,9 @@
}
private int pathCompare(byte[] b, int bPos, int bEnd, int bMode, int aPos) {
- final byte[] a = path;
- final int aEnd = pathLen;
-
- for (; aPos < aEnd && bPos < bEnd; aPos++, bPos++) {
- final int cmp = (a[aPos] & 0xff) - (b[bPos] & 0xff);
- if (cmp != 0)
- return cmp;
- }
-
- if (aPos < aEnd)
- return (a[aPos] & 0xff) - lastPathChar(bMode);
- if (bPos < bEnd)
- return lastPathChar(mode) - (b[bPos] & 0xff);
- return lastPathChar(mode) - lastPathChar(bMode);
+ return Paths.compare(
+ path, aPos, pathLen, mode,
+ b, bPos, bEnd, bMode);
}
private static int alreadyMatch(AbstractTreeIterator a,
@@ -368,10 +402,6 @@
}
}
- private static int lastPathChar(final int mode) {
- return FileMode.TREE.equals(mode) ? '/' : '\0';
- }
-
/**
* Check if the current entry of both iterators has the same id.
* <p>
@@ -648,6 +678,14 @@
}
/**
+ * @return true if the iterator implements {@link #stopWalk()}.
+ * @since 4.2
+ */
+ protected boolean needsStopWalk() {
+ return false;
+ }
+
+ /**
* @return the length of the name component of the path for the current entry
*/
public int getNameLength() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java
index 0805e50..c038f07 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java
@@ -44,13 +44,23 @@
package org.eclipse.jgit.treewalk;
-import java.io.IOException;
-import java.util.Arrays;
+import static org.eclipse.jgit.lib.Constants.DOT_GIT_ATTRIBUTES;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
+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.TYPE_TREE;
+import static org.eclipse.jgit.lib.Constants.encode;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.eclipse.jgit.attributes.AttributesNode;
+import org.eclipse.jgit.attributes.AttributesRule;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.AnyObjectId;
-import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.MutableObjectId;
import org.eclipse.jgit.lib.ObjectId;
@@ -59,6 +69,7 @@
/** Parses raw Git trees from the canonical semi-text/semi-binary format. */
public class CanonicalTreeParser extends AbstractTreeIterator {
private static final byte[] EMPTY = {};
+ private static final byte[] ATTRS = encode(DOT_GIT_ATTRIBUTES);
private byte[] raw;
@@ -124,6 +135,7 @@
* the raw tree content.
*/
public void reset(final byte[] treeData) {
+ attributesNode = null;
raw = treeData;
prevPtr = -1;
currPtr = 0;
@@ -199,7 +211,7 @@
*/
public void reset(final ObjectReader reader, final AnyObjectId id)
throws IncorrectObjectTypeException, IOException {
- reset(reader.open(id, Constants.OBJ_TREE).getCachedBytes());
+ reset(reader.open(id, OBJ_TREE).getCachedBytes());
}
@Override
@@ -209,7 +221,7 @@
idBuffer.fromRaw(idBuffer(), idOffset());
if (!FileMode.TREE.equals(mode)) {
final ObjectId me = idBuffer.toObjectId();
- throw new IncorrectObjectTypeException(me, Constants.TYPE_TREE);
+ throw new IncorrectObjectTypeException(me, TYPE_TREE);
}
return createSubtreeIterator0(reader, idBuffer);
}
@@ -254,7 +266,7 @@
@Override
public int idOffset() {
- return nextPtr - Constants.OBJECT_ID_LENGTH;
+ return nextPtr - OBJECT_ID_LENGTH;
}
@Override
@@ -292,7 +304,7 @@
prevPtr = ptr;
while (raw[ptr] != 0)
ptr++;
- ptr += Constants.OBJECT_ID_LENGTH + 1;
+ ptr += OBJECT_ID_LENGTH + 1;
}
if (delta != 0)
throw new ArrayIndexOutOfBoundsException(delta);
@@ -328,7 +340,7 @@
trace[delta] = ptr;
while (raw[ptr] != 0)
ptr++;
- ptr += Constants.OBJECT_ID_LENGTH + 1;
+ ptr += OBJECT_ID_LENGTH + 1;
}
if (trace[1] == -1)
throw new ArrayIndexOutOfBoundsException(delta);
@@ -363,6 +375,46 @@
}
}
pathLen = tmp;
- nextPtr = ptr + Constants.OBJECT_ID_LENGTH;
+ nextPtr = ptr + OBJECT_ID_LENGTH;
+ }
+
+ /**
+ * Retrieve the {@link AttributesNode} for the current entry.
+ *
+ * @param reader
+ * {@link ObjectReader} used to parse the .gitattributes entry.
+ * @return {@link AttributesNode} for the current entry.
+ * @throws IOException
+ * @since 4.2
+ */
+ public AttributesNode getEntryAttributesNode(ObjectReader reader)
+ throws IOException {
+ if (attributesNode == null) {
+ attributesNode = findAttributes(reader);
+ }
+ return attributesNode.getRules().isEmpty() ? null : attributesNode;
+ }
+
+ private AttributesNode findAttributes(ObjectReader reader)
+ throws IOException {
+ CanonicalTreeParser itr = new CanonicalTreeParser();
+ itr.reset(raw);
+ if (itr.findFile(ATTRS)) {
+ return loadAttributes(reader, itr.getEntryObjectId());
+ }
+ return noAttributes();
+ }
+
+ private static AttributesNode loadAttributes(ObjectReader reader,
+ AnyObjectId id) throws IOException {
+ AttributesNode r = new AttributesNode();
+ try (InputStream in = reader.open(id, OBJ_BLOB).openStream()) {
+ r.parse(in);
+ }
+ return r.getRules().isEmpty() ? noAttributes() : r;
+ }
+
+ private static AttributesNode noAttributes() {
+ return new AttributesNode(Collections.<AttributesRule> emptyList());
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/EmptyTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/EmptyTreeIterator.java
index 8dbf80e..ec4a84e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/EmptyTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/EmptyTreeIterator.java
@@ -142,4 +142,9 @@
if (parent != null)
parent.stopWalk();
}
+
+ @Override
+ protected boolean needsStopWalk() {
+ return parent != null && parent.needsStopWalk();
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
index 8d2cb1d..accf495 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
@@ -67,8 +67,8 @@
*/
public class FileTreeIterator extends WorkingTreeIterator {
/**
- * the starting directory. This directory should correspond to the root of
- * the repository.
+ * the starting directory of this Iterator. All entries are located directly
+ * in this directory.
*/
protected final File directory;
@@ -238,8 +238,6 @@
@Override
protected byte[] idSubmodule(final Entry e) {
- if (repository == null)
- return idSubmodule(getDirectory(), e);
- return super.idSubmodule(e);
+ return idSubmodule(getDirectory(), e);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
index 2d6acbd..d2195a8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
@@ -43,6 +43,8 @@
package org.eclipse.jgit.treewalk;
+import java.io.IOException;
+
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.lib.FileMode;
@@ -96,7 +98,7 @@
* the repository the walker will obtain data from.
*/
public NameConflictTreeWalk(final Repository repo) {
- this(repo.newObjectReader());
+ super(repo);
}
/**
@@ -338,6 +340,41 @@
dfConflict = null;
}
+ void stopWalk() throws IOException {
+ if (!needsStopWalk()) {
+ return;
+ }
+
+ // Name conflicts make aborting early difficult. Multiple paths may
+ // exist between the file and directory versions of a name. To ensure
+ // the directory version is skipped over (as it was previously visited
+ // during the file version step) requires popping up the stack and
+ // finishing out each subtree that the walker dove into. Siblings in
+ // parents do not need to be recursed into, bounding the cost.
+ for (;;) {
+ AbstractTreeIterator t = min();
+ if (t.eof()) {
+ if (depth > 0) {
+ exitSubtree();
+ popEntriesEqual();
+ continue;
+ }
+ return;
+ }
+ currentHead = t;
+ skipEntriesEqual();
+ }
+ }
+
+ private boolean needsStopWalk() {
+ for (AbstractTreeIterator t : trees) {
+ if (t.needsStopWalk()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* True if the current entry is covered by a directory/file conflict.
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
index 06e8284..5cd713d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
@@ -45,12 +45,26 @@
package org.eclipse.jgit.treewalk;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.attributes.Attribute;
+import org.eclipse.jgit.attributes.Attribute.State;
+import org.eclipse.jgit.attributes.Attributes;
+import org.eclipse.jgit.attributes.AttributesNode;
+import org.eclipse.jgit.attributes.AttributesNodeProvider;
+import org.eclipse.jgit.attributes.AttributesProvider;
+import org.eclipse.jgit.dircache.DirCacheBuildIterator;
+import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.StopWalkException;
import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.MutableObjectId;
@@ -60,6 +74,7 @@
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.eclipse.jgit.util.QuotedString;
import org.eclipse.jgit.util.RawParseUtils;
/**
@@ -82,10 +97,45 @@
* Multiple simultaneous TreeWalk instances per {@link Repository} are
* permitted, even from concurrent threads.
*/
-public class TreeWalk implements AutoCloseable {
+public class TreeWalk implements AutoCloseable, AttributesProvider {
private static final AbstractTreeIterator[] NO_TREES = {};
/**
+ * @since 4.2
+ */
+ public static enum OperationType {
+ /**
+ * Represents a checkout operation (for example a checkout or reset
+ * operation).
+ */
+ CHECKOUT_OP,
+
+ /**
+ * Represents a checkin operation (for example an add operation)
+ */
+ CHECKIN_OP
+ }
+
+ /**
+ * Type of operation you want to retrieve the git attributes for.
+ */
+ private OperationType operationType = OperationType.CHECKOUT_OP;
+
+ /**
+ * The filter command as defined in gitattributes. The keys are
+ * filterName+"."+filterCommandType. E.g. "lfs.clean"
+ */
+ private Map<String, String> filterCommandsByNameDotType = new HashMap<String, String>();
+
+ /**
+ * @param operationType
+ * @since 4.2
+ */
+ public void setOperationType(OperationType operationType) {
+ this.operationType = operationType;
+ }
+
+ /**
* Open a tree walk and filter to exactly one path.
* <p>
* The returned tree walk is already positioned on the requested path, so
@@ -207,14 +257,21 @@
private boolean postOrderTraversal;
- private int depth;
+ int depth;
private boolean advance;
private boolean postChildren;
+ private AttributesNodeProvider attributesNodeProvider;
+
AbstractTreeIterator currentHead;
+ /** Cached attribute for the current entry */
+ private Attributes attrs = null;
+
+ private Config config;
+
/**
* Create a new tree walker for a given repository.
*
@@ -225,6 +282,8 @@
*/
public TreeWalk(final Repository repo) {
this(repo.newObjectReader(), true);
+ config = repo.getConfig();
+ attributesNodeProvider = repo.createAttributesNodeProvider();
}
/**
@@ -356,8 +415,29 @@
postOrderTraversal = b;
}
+ /**
+ * Sets the {@link AttributesNodeProvider} for this {@link TreeWalk}.
+ * <p>
+ * This is a requirement for a correct computation of the git attributes.
+ * If this {@link TreeWalk} has been built using
+ * {@link #TreeWalk(Repository)} constructor, the
+ * {@link AttributesNodeProvider} has already been set. Indeed,the
+ * {@link Repository} can provide an {@link AttributesNodeProvider} using
+ * {@link Repository#createAttributesNodeProvider()} method. Otherwise you
+ * should provide one.
+ * </p>
+ *
+ * @see Repository#createAttributesNodeProvider()
+ * @param provider
+ * @since 4.2
+ */
+ public void setAttributesNodeProvider(AttributesNodeProvider provider) {
+ attributesNodeProvider = provider;
+ }
+
/** Reset this walker so new tree iterators can be added to it. */
public void reset() {
+ attrs = null;
trees = NO_TREES;
advance = false;
depth = 0;
@@ -401,6 +481,7 @@
advance = false;
depth = 0;
+ attrs = null;
}
/**
@@ -450,6 +531,7 @@
trees = r;
advance = false;
depth = 0;
+ attrs = null;
}
/**
@@ -492,18 +574,13 @@
* @param p
* an iterator to walk over. The iterator should be new, with no
* parent, and should still be positioned before the first entry.
- * The tree which the iterator operates on must have the same root
- * as other trees in the walk.
- *
+ * The tree which the iterator operates on must have the same
+ * root as other trees in the walk.
* @return position of this tree within the walker.
- * @throws CorruptObjectException
- * the iterator was unable to obtain its first entry, due to
- * possible data corruption within the backing data store.
*/
- public int addTree(final AbstractTreeIterator p)
- throws CorruptObjectException {
- final int n = trees.length;
- final AbstractTreeIterator[] newTrees = new AbstractTreeIterator[n + 1];
+ public int addTree(AbstractTreeIterator p) {
+ int n = trees.length;
+ AbstractTreeIterator[] newTrees = new AbstractTreeIterator[n + 1];
System.arraycopy(trees, 0, newTrees, 0, n);
newTrees[n] = p;
@@ -546,6 +623,7 @@
public boolean next() throws MissingObjectException,
IncorrectObjectTypeException, CorruptObjectException, IOException {
try {
+ attrs = null;
if (advance) {
advance = false;
postChildren = false;
@@ -583,13 +661,30 @@
return true;
}
} catch (StopWalkException stop) {
- for (final AbstractTreeIterator t : trees)
- t.stopWalk();
+ stopWalk();
return false;
}
}
/**
+ * Notify iterators the walk is aborting.
+ * <p>
+ * Primarily to notify {@link DirCacheBuildIterator} the walk is aborting so
+ * that it can copy any remaining entries.
+ *
+ * @throws IOException
+ * if traversal of remaining entries throws an exception during
+ * object access. This should never occur as remaining trees
+ * should already be in memory, however the methods used to
+ * finish traversal are declared to throw IOException.
+ */
+ void stopWalk() throws IOException {
+ for (AbstractTreeIterator t : trees) {
+ t.stopWalk();
+ }
+ }
+
+ /**
* Obtain the tree iterator for the current entry.
* <p>
* Entering into (or exiting out of) a subtree causes the current tree
@@ -779,10 +874,13 @@
* Test if the supplied path matches the current entry's path.
* <p>
* This method tests that the supplied path is exactly equal to the current
- * entry, or is one of its parent directories. It is faster to use this
+ * entry or is one of its parent directories. It is faster to use this
* method then to use {@link #getPathString()} to first create a String
* object, then test <code>startsWith</code> or some other type of string
* match function.
+ * <p>
+ * If the current entry is a subtree, then all paths within the subtree
+ * are considered to match it.
*
* @param p
* path buffer to test. Callers should ensure the path does not
@@ -818,7 +916,7 @@
// If p[ci] == '/' then pattern matches this subtree,
// otherwise we cannot be certain so we return -1.
//
- return p[ci] == '/' ? 0 : -1;
+ return p[ci] == '/' && FileMode.TREE.equals(t.mode) ? 0 : -1;
}
// Both strings are identical.
@@ -915,6 +1013,7 @@
*/
public void enterSubtree() throws MissingObjectException,
IncorrectObjectTypeException, CorruptObjectException, IOException {
+ attrs = null;
final AbstractTreeIterator ch = currentHead;
final AbstractTreeIterator[] tmp = new AbstractTreeIterator[trees.length];
for (int i = 0; i < trees.length; i++) {
@@ -979,7 +1078,7 @@
}
}
- private void exitSubtree() {
+ void exitSubtree() {
depth--;
for (int i = 0; i < trees.length; i++)
trees[i] = trees[i].parent;
@@ -1008,4 +1107,296 @@
static String pathOf(final byte[] buf, int pos, int end) {
return RawParseUtils.decode(Constants.CHARSET, buf, pos, end);
}
+
+ /**
+ * Retrieve the git attributes for the current entry.
+ *
+ * <h4>Git attribute computation</h4>
+ *
+ * <ul>
+ * <li>Get the attributes matching the current path entry from the info file
+ * (see {@link AttributesNodeProvider#getInfoAttributesNode()}).</li>
+ * <li>Completes the list of attributes using the .gitattributes files
+ * located on the current path (the further the directory that contains
+ * .gitattributes is from the path in question, the lower its precedence).
+ * For a checkin operation, it will look first on the working tree (if any).
+ * If there is no attributes file, it will fallback on the index. For a
+ * checkout operation, it will first use the index entry and then fallback
+ * on the working tree if none.</li>
+ * <li>In the end, completes the list of matching attributes using the
+ * global attribute file define in the configuration (see
+ * {@link AttributesNodeProvider#getGlobalAttributesNode()})</li>
+ *
+ * </ul>
+ *
+ *
+ * <h4>Iterator constraints</h4>
+ *
+ * <p>
+ * In order to have a correct list of attributes for the current entry, this
+ * {@link TreeWalk} requires to have at least one
+ * {@link AttributesNodeProvider} and a {@link DirCacheIterator} set up. An
+ * {@link AttributesNodeProvider} is used to retrieve the attributes from
+ * the info attributes file and the global attributes file. The
+ * {@link DirCacheIterator} is used to retrieve the .gitattributes files
+ * stored in the index. A {@link WorkingTreeIterator} can also be provided
+ * to access the local version of the .gitattributes files. If none is
+ * provided it will fallback on the {@link DirCacheIterator}.
+ * </p>
+ *
+ * @return a {@link Set} of {@link Attribute}s that match the current entry.
+ * @since 4.2
+ */
+ public Attributes getAttributes() {
+ if (attrs != null)
+ return attrs;
+
+ if (attributesNodeProvider == null) {
+ // The work tree should have a AttributesNodeProvider to be able to
+ // retrieve the info and global attributes node
+ throw new IllegalStateException(
+ "The tree walk should have one AttributesNodeProvider set in order to compute the git attributes."); //$NON-NLS-1$
+ }
+
+ WorkingTreeIterator workingTreeIterator = getTree(WorkingTreeIterator.class);
+ DirCacheIterator dirCacheIterator = getTree(DirCacheIterator.class);
+ CanonicalTreeParser other = getTree(CanonicalTreeParser.class);
+
+ if (workingTreeIterator == null && dirCacheIterator == null
+ && other == null) {
+ // Can not retrieve the attributes without at least one of the above
+ // iterators.
+ return new Attributes();
+ }
+
+ String path = currentHead.getEntryPathString();
+ final boolean isDir = FileMode.TREE.equals(currentHead.mode);
+ Attributes attributes = new Attributes();
+ try {
+ // Gets the global attributes node
+ AttributesNode globalNodeAttr = attributesNodeProvider
+ .getGlobalAttributesNode();
+ // Gets the info attributes node
+ AttributesNode infoNodeAttr = attributesNodeProvider
+ .getInfoAttributesNode();
+
+ // Gets the info attributes
+ if (infoNodeAttr != null) {
+ infoNodeAttr.getAttributes(path, isDir, attributes);
+ }
+
+ // Gets the attributes located on the current entry path
+ getPerDirectoryEntryAttributes(path, isDir, operationType,
+ workingTreeIterator, dirCacheIterator, other, attributes);
+
+ // Gets the attributes located in the global attribute file
+ if (globalNodeAttr != null) {
+ globalNodeAttr.getAttributes(path, isDir, attributes);
+ }
+ } catch (IOException e) {
+ throw new JGitInternalException("Error while parsing attributes", e); //$NON-NLS-1$
+ }
+ // now after all attributes are collected - in the correct hierarchy
+ // order - remove all unspecified entries (the ! marker)
+ for (Attribute a : attributes.getAll()) {
+ if (a.getState() == State.UNSPECIFIED)
+ attributes.remove(a.getKey());
+ }
+ return attributes;
+ }
+
+ /**
+ * Get the attributes located on the current entry path.
+ *
+ * @param path
+ * current entry path
+ * @param isDir
+ * holds true if the current entry is a directory
+ * @param opType
+ * type of operation
+ * @param workingTreeIterator
+ * a {@link WorkingTreeIterator} matching the current entry
+ * @param dirCacheIterator
+ * a {@link DirCacheIterator} matching the current entry
+ * @param other
+ * a {@link CanonicalTreeParser} matching the current entry
+ * @param attributes
+ * Non null map holding the existing attributes. This map will be
+ * augmented with new entry. None entry will be overrided.
+ * @throws IOException
+ * It raises an {@link IOException} if a problem appears while
+ * parsing one on the attributes file.
+ */
+ private void getPerDirectoryEntryAttributes(String path, boolean isDir,
+ OperationType opType, WorkingTreeIterator workingTreeIterator,
+ DirCacheIterator dirCacheIterator, CanonicalTreeParser other,
+ Attributes attributes)
+ throws IOException {
+ // Prevents infinite recurrence
+ if (workingTreeIterator != null || dirCacheIterator != null
+ || other != null) {
+ AttributesNode currentAttributesNode = getCurrentAttributesNode(
+ opType, workingTreeIterator, dirCacheIterator, other);
+ if (currentAttributesNode != null) {
+ currentAttributesNode.getAttributes(path, isDir, attributes);
+ }
+ getPerDirectoryEntryAttributes(path, isDir, opType,
+ getParent(workingTreeIterator, WorkingTreeIterator.class),
+ getParent(dirCacheIterator, DirCacheIterator.class),
+ getParent(other, CanonicalTreeParser.class), attributes);
+ }
+ }
+
+ private static <T extends AbstractTreeIterator> T getParent(T current,
+ Class<T> type) {
+ if (current != null) {
+ AbstractTreeIterator parent = current.parent;
+ if (type.isInstance(parent)) {
+ return type.cast(parent);
+ }
+ }
+ return null;
+ }
+
+ private <T extends AbstractTreeIterator> T getTree(Class<T> type) {
+ for (int i = 0; i < trees.length; i++) {
+ AbstractTreeIterator tree = trees[i];
+ if (type.isInstance(tree)) {
+ return type.cast(tree);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the {@link AttributesNode} for the current entry.
+ * <p>
+ * This method implements the fallback mechanism between the index and the
+ * working tree depending on the operation type
+ * </p>
+ *
+ * @param opType
+ * @param workingTreeIterator
+ * @param dirCacheIterator
+ * @param other
+ * @return a {@link AttributesNode} of the current entry,
+ * {@link NullPointerException} otherwise.
+ * @throws IOException
+ * It raises an {@link IOException} if a problem appears while
+ * parsing one on the attributes file.
+ */
+ private AttributesNode getCurrentAttributesNode(OperationType opType,
+ @Nullable WorkingTreeIterator workingTreeIterator,
+ @Nullable DirCacheIterator dirCacheIterator,
+ @Nullable CanonicalTreeParser other)
+ throws IOException {
+ AttributesNode attributesNode = null;
+ switch (opType) {
+ case CHECKIN_OP:
+ if (workingTreeIterator != null) {
+ attributesNode = workingTreeIterator.getEntryAttributesNode();
+ }
+ if (attributesNode == null && dirCacheIterator != null) {
+ attributesNode = getAttributesNode(dirCacheIterator
+ .getEntryAttributesNode(getObjectReader()),
+ attributesNode);
+ }
+ if (attributesNode == null && other != null) {
+ attributesNode = getAttributesNode(
+ other.getEntryAttributesNode(getObjectReader()),
+ attributesNode);
+ }
+ break;
+ case CHECKOUT_OP:
+ if (other != null) {
+ attributesNode = other
+ .getEntryAttributesNode(getObjectReader());
+ }
+ if (dirCacheIterator != null) {
+ attributesNode = getAttributesNode(dirCacheIterator
+ .getEntryAttributesNode(getObjectReader()),
+ attributesNode);
+ }
+ if (attributesNode == null && workingTreeIterator != null) {
+ attributesNode = getAttributesNode(
+ workingTreeIterator.getEntryAttributesNode(),
+ attributesNode);
+ }
+ break;
+ default:
+ throw new IllegalStateException(
+ "The only supported operation types are:" //$NON-NLS-1$
+ + OperationType.CHECKIN_OP + "," //$NON-NLS-1$
+ + OperationType.CHECKOUT_OP);
+ }
+
+ return attributesNode;
+ }
+
+ private static AttributesNode getAttributesNode(AttributesNode value,
+ AttributesNode defaultValue) {
+ return (value == null) ? defaultValue : value;
+ }
+
+ /**
+ * Inspect config and attributes to return a filtercommand applicable for
+ * the current path
+ *
+ * @param filterCommandType
+ * which type of filterCommand should be executed. E.g. "clean",
+ * "smudge"
+ * @return a filter command
+ * @throws IOException
+ * @since 4.2
+ */
+ public String getFilterCommand(String filterCommandType)
+ throws IOException {
+ Attributes attributes = getAttributes();
+
+ Attribute f = attributes.get(Constants.ATTR_FILTER);
+ if (f == null) {
+ return null;
+ }
+ String filterValue = f.getValue();
+ if (filterValue == null) {
+ return null;
+ }
+
+ String filterCommand = getFilterCommandDefinition(filterValue,
+ filterCommandType);
+ if (filterCommand == null) {
+ return null;
+ }
+ return filterCommand.replaceAll("%f", //$NON-NLS-1$
+ QuotedString.BOURNE.quote((getPathString())));
+ }
+
+ /**
+ * Get the filter command how it is defined in gitconfig. The returned
+ * string may contain "%f" which needs to be replaced by the current path
+ * before executing the filter command. These filter definitions are cached
+ * for better performance.
+ *
+ * @param filterDriverName
+ * The name of the filter driver as it is referenced in the
+ * gitattributes file. E.g. "lfs". For each filter driver there
+ * may be many commands defined in the .gitconfig
+ * @param filterCommandType
+ * The type of the filter command for a specific filter driver.
+ * May be "clean" or "smudge".
+ * @return the definition of the command to be executed for this filter
+ * driver and filter command
+ */
+ private String getFilterCommandDefinition(String filterDriverName,
+ String filterCommandType) {
+ String key = filterDriverName + "." + filterCommandType; //$NON-NLS-1$
+ String filterCommand = filterCommandsByNameDotType.get(key);
+ if (filterCommand != null)
+ return filterCommand;
+ filterCommand = config.getString(Constants.ATTR_FILTER,
+ filterDriverName, filterCommandType);
+ if (filterCommand != null)
+ filterCommandsByNameDotType.put(key, filterCommand);
+ return filterCommand;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index 73ab04f..0d617ee 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -62,6 +62,7 @@
import java.util.Collections;
import java.util.Comparator;
+import org.eclipse.jgit.api.errors.FilterFailedException;
import org.eclipse.jgit.attributes.AttributesNode;
import org.eclipse.jgit.attributes.AttributesRule;
import org.eclipse.jgit.diff.RawText;
@@ -76,6 +77,7 @@
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.CoreConfig;
+import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
import org.eclipse.jgit.lib.CoreConfig.CheckStat;
import org.eclipse.jgit.lib.CoreConfig.SymLinks;
import org.eclipse.jgit.lib.FileMode;
@@ -85,7 +87,9 @@
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.submodule.SubmoduleWalk;
import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FS.ExecutionResult;
import org.eclipse.jgit.util.IO;
+import org.eclipse.jgit.util.Paths;
import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.io.EolCanonicalizingInputStream;
@@ -101,6 +105,8 @@
* @see FileTreeIterator
*/
public abstract class WorkingTreeIterator extends AbstractTreeIterator {
+ private static final int MAX_EXCEPTION_TEXT_SIZE = 10 * 1024;
+
/** An empty entry array, suitable for {@link #init(Entry[])}. */
protected static final Entry[] EOF = {};
@@ -134,8 +140,7 @@
/** If there is a .gitignore file present, the parsed rules from it. */
private IgnoreNode ignoreNode;
- /** If there is a .gitattributes file present, the parsed rules from it. */
- private AttributesNode attributesNode;
+ private String cleanFilterCommand;
/** Repository that is the root level being iterated over */
protected Repository repository;
@@ -147,19 +152,6 @@
private int contentIdOffset;
/**
- * Holds the {@link AttributesNode} that is stored in
- * $GIT_DIR/info/attributes file.
- */
- private AttributesNode infoAttributeNode;
-
- /**
- * Holds the {@link AttributesNode} that is stored in global attribute file.
- *
- * @see CoreConfig#getAttributesFile()
- */
- private AttributesNode globalAttributeNode;
-
- /**
* Create a new iterator with no parent.
*
* @param options
@@ -202,8 +194,7 @@
protected WorkingTreeIterator(final WorkingTreeIterator p) {
super(p);
state = p.state;
- infoAttributeNode = p.infoAttributeNode;
- globalAttributeNode = p.globalAttributeNode;
+ repository = p.repository;
}
/**
@@ -223,10 +214,6 @@
else
entry = null;
ignoreNode = new RootIgnoreNode(entry, repo);
-
- infoAttributeNode = new InfoAttributesNode(repo);
-
- globalAttributeNode = new GlobalAttributesNode(repo);
}
/**
@@ -370,7 +357,8 @@
private InputStream possiblyFilteredInputStream(final Entry e,
final InputStream is, final long len) throws IOException {
- if (!mightNeedCleaning()) {
+ boolean mightNeedCleaning = mightNeedCleaning();
+ if (!mightNeedCleaning) {
canonLen = len;
return is;
}
@@ -388,7 +376,8 @@
return new ByteArrayInputStream(raw, 0, n);
}
- if (isBinary(e)) {
+ // TODO: fix autocrlf causing mightneedcleaning
+ if (!mightNeedCleaning && isBinary(e)) {
canonLen = len;
return is;
}
@@ -412,10 +401,12 @@
}
}
- private boolean mightNeedCleaning() {
+ private boolean mightNeedCleaning() throws IOException {
switch (getOptions().getAutoCRLF()) {
case FALSE:
default:
+ if (getCleanFilterCommand() != null)
+ return true;
return false;
case TRUE:
@@ -437,8 +428,7 @@
}
}
- private static ByteBuffer filterClean(byte[] src, int n)
- throws IOException {
+ private ByteBuffer filterClean(byte[] src, int n) throws IOException {
InputStream in = new ByteArrayInputStream(src);
try {
return IO.readWholeStream(filterClean(in), n);
@@ -447,8 +437,42 @@
}
}
- private static InputStream filterClean(InputStream in) {
- return new EolCanonicalizingInputStream(in, true);
+ private InputStream filterClean(InputStream in) throws IOException {
+ in = handleAutoCRLF(in);
+ String filterCommand = getCleanFilterCommand();
+ if (filterCommand != null) {
+ FS fs = repository.getFS();
+ ProcessBuilder filterProcessBuilder = fs.runInShell(filterCommand,
+ new String[0]);
+ filterProcessBuilder.directory(repository.getWorkTree());
+ filterProcessBuilder.environment().put(Constants.GIT_DIR_KEY,
+ repository.getDirectory().getAbsolutePath());
+ ExecutionResult result;
+ try {
+ result = fs.execute(filterProcessBuilder, in);
+ } catch (IOException | InterruptedException e) {
+ throw new IOException(new FilterFailedException(e,
+ filterCommand, getEntryPathString()));
+ }
+ int rc = result.getRc();
+ if (rc != 0) {
+ throw new IOException(new FilterFailedException(rc,
+ filterCommand, getEntryPathString(),
+ result.getStdout().toByteArray(MAX_EXCEPTION_TEXT_SIZE),
+ RawParseUtils.decode(result.getStderr()
+ .toByteArray(MAX_EXCEPTION_TEXT_SIZE))));
+ }
+ return result.getStdout().openInputStream();
+ }
+ return in;
+ }
+
+ private InputStream handleAutoCRLF(InputStream in) {
+ AutoCRLF autoCRLF = getOptions().getAutoCRLF();
+ if (autoCRLF == AutoCRLF.TRUE || autoCRLF == AutoCRLF.INPUT) {
+ in = new EolCanonicalizingInputStream(in, true);
+ }
+ return in;
}
/**
@@ -507,6 +531,7 @@
System.arraycopy(e.encodedName, 0, path, pathOffset, nameLen);
pathLen = pathOffset + nameLen;
canonLen = -1;
+ cleanFilterCommand = null;
}
/**
@@ -667,67 +692,14 @@
return attributesNode;
}
- /**
- * Retrieves the {@link AttributesNode} that holds the information located
- * in $GIT_DIR/info/attributes file.
- *
- * @return the {@link AttributesNode} that holds the information located in
- * $GIT_DIR/info/attributes file.
- * @throws IOException
- * if an error is raised while parsing the attributes file
- * @since 3.7
- */
- public AttributesNode getInfoAttributesNode() throws IOException {
- if (infoAttributeNode instanceof InfoAttributesNode)
- infoAttributeNode = ((InfoAttributesNode) infoAttributeNode).load();
- return infoAttributeNode;
- }
-
- /**
- * Retrieves the {@link AttributesNode} that holds the information located
- * in system-wide file.
- *
- * @return the {@link AttributesNode} that holds the information located in
- * system-wide file.
- * @throws IOException
- * IOException if an error is raised while parsing the
- * attributes file
- * @see CoreConfig#getAttributesFile()
- * @since 3.7
- */
- public AttributesNode getGlobalAttributesNode() throws IOException {
- if (globalAttributeNode instanceof GlobalAttributesNode)
- globalAttributeNode = ((GlobalAttributesNode) globalAttributeNode)
- .load();
- return globalAttributeNode;
- }
-
private static final Comparator<Entry> ENTRY_CMP = new Comparator<Entry>() {
- public int compare(final Entry o1, final Entry o2) {
- final byte[] a = o1.encodedName;
- final byte[] b = o2.encodedName;
- final int aLen = o1.encodedNameLen;
- final int bLen = o2.encodedNameLen;
- int cPos;
-
- for (cPos = 0; cPos < aLen && cPos < bLen; cPos++) {
- final int cmp = (a[cPos] & 0xff) - (b[cPos] & 0xff);
- if (cmp != 0)
- return cmp;
- }
-
- if (cPos < aLen)
- return (a[cPos] & 0xff) - lastPathChar(o2);
- if (cPos < bLen)
- return lastPathChar(o1) - (b[cPos] & 0xff);
- return lastPathChar(o1) - lastPathChar(o2);
+ public int compare(Entry a, Entry b) {
+ return Paths.compare(
+ a.encodedName, 0, a.encodedNameLen, a.getMode().getBits(),
+ b.encodedName, 0, b.encodedNameLen, b.getMode().getBits());
}
};
- static int lastPathChar(final Entry e) {
- return e.getMode() == FileMode.TREE ? '/' : '\0';
- }
-
/**
* Constructor helper.
*
@@ -1296,68 +1268,6 @@
}
}
- /**
- * Attributes node loaded from global system-wide file.
- */
- private static class GlobalAttributesNode extends AttributesNode {
- final Repository repository;
-
- GlobalAttributesNode(Repository repository) {
- this.repository = repository;
- }
-
- AttributesNode load() throws IOException {
- AttributesNode r = new AttributesNode();
-
- FS fs = repository.getFS();
- String path = repository.getConfig().get(CoreConfig.KEY)
- .getAttributesFile();
- if (path != null) {
- File attributesFile;
- if (path.startsWith("~/")) //$NON-NLS-1$
- attributesFile = fs.resolve(fs.userHome(),
- path.substring(2));
- else
- attributesFile = fs.resolve(null, path);
- loadRulesFromFile(r, attributesFile);
- }
- return r.getRules().isEmpty() ? null : r;
- }
- }
-
- /** Magic type indicating there may be rules for the top level. */
- private static class InfoAttributesNode extends AttributesNode {
- final Repository repository;
-
- InfoAttributesNode(Repository repository) {
- this.repository = repository;
- }
-
- AttributesNode load() throws IOException {
- AttributesNode r = new AttributesNode();
-
- FS fs = repository.getFS();
-
- File attributes = fs.resolve(repository.getDirectory(),
- "info/attributes"); //$NON-NLS-1$
- loadRulesFromFile(r, attributes);
-
- return r.getRules().isEmpty() ? null : r;
- }
-
- }
-
- private static void loadRulesFromFile(AttributesNode r, File attrs)
- throws FileNotFoundException, IOException {
- if (attrs.exists()) {
- FileInputStream in = new FileInputStream(attrs);
- try {
- r.parse(in);
- } finally {
- in.close();
- }
- }
- }
private static final class IteratorState {
/** Options used to process the working tree. */
@@ -1390,4 +1300,18 @@
}
}
}
+
+ /**
+ * @return the clean filter command for the current entry or
+ * <code>null</code> if no such command is defined
+ * @throws IOException
+ * @since 4.2
+ */
+ public String getCleanFilterCommand() throws IOException {
+ if (cleanFilterCommand == null && state.walk != null) {
+ cleanFilterCommand = state.walk
+ .getFilterCommand(Constants.ATTR_FILTER_TYPE_CLEAN);
+ }
+ return cleanFilterCommand;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathFilterGroup.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathFilterGroup.java
index bdfde0b..7601956 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathFilterGroup.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathFilterGroup.java
@@ -245,9 +245,9 @@
int hash = hasher.nextHash();
if (fullpaths.contains(rp, hasher.length(), hash))
return true;
- if (!hasher.hasNext())
- if (prefixes.contains(rp, hasher.length(), hash))
- return true;
+ if (!hasher.hasNext() && walker.isSubtree()
+ && prefixes.contains(rp, hasher.length(), hash))
+ return true;
}
final int cmp = walker.isPathPrefix(max, max.length);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java
index 0454e7e..9d0ad73 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java
@@ -74,9 +74,9 @@
private static final int BLOCK_MASK = BLOCK_SIZE - 1;
- private T[][] directory;
+ T[][] directory;
- private int size;
+ int size;
private int tailDirIdx;
@@ -282,11 +282,11 @@
return new MyIterator();
}
- private static final int toDirectoryIndex(int index) {
+ static final int toDirectoryIndex(int index) {
return index >>> BLOCK_BITS;
}
- private static final int toBlockIndex(int index) {
+ static final int toBlockIndex(int index) {
return index & BLOCK_MASK;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
index 35fc99e..e14096e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
@@ -42,7 +42,6 @@
*/
package org.eclipse.jgit.util;
-import java.io.IOException;
import java.util.regex.Pattern;
import org.eclipse.jgit.lib.Constants;
@@ -90,12 +89,10 @@
* The commit message
* @return the change id SHA1 string (without the 'I') or null if the
* message is not complete enough
- * @throws IOException
*/
public static ObjectId computeChangeId(final ObjectId treeId,
final ObjectId firstParentId, final PersonIdent author,
- final PersonIdent committer, final String message)
- throws IOException {
+ final PersonIdent committer, final String message) {
String cleanMessage = clean(message);
if (cleanMessage.length() == 0)
return null;
@@ -116,8 +113,7 @@
b.append("\n\n"); //$NON-NLS-1$
b.append(cleanMessage);
try (ObjectInserter f = new ObjectInserter.Formatter()) {
- return f.idFor(Constants.OBJ_COMMIT, //
- b.toString().getBytes(Constants.CHARACTER_ENCODING));
+ return f.idFor(Constants.OBJ_COMMIT, Constants.encode(b.toString()));
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index e5219b2..253acbb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -44,15 +44,13 @@
package org.eclipse.jgit.util;
import java.io.BufferedReader;
-import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
-import java.io.OutputStreamWriter;
import java.io.PrintStream;
-import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -60,12 +58,14 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
@@ -110,6 +110,53 @@
}
}
+ /**
+ * Result of an executed process. The caller is responsible to close the
+ * contained {@link TemporaryBuffer}s
+ *
+ * @since 4.2
+ */
+ public static class ExecutionResult {
+ private TemporaryBuffer stdout;
+
+ private TemporaryBuffer stderr;
+
+ private int rc;
+
+ /**
+ * @param stdout
+ * @param stderr
+ * @param rc
+ */
+ public ExecutionResult(TemporaryBuffer stdout, TemporaryBuffer stderr,
+ int rc) {
+ this.stdout = stdout;
+ this.stderr = stderr;
+ this.rc = rc;
+ }
+
+ /**
+ * @return buffered standard output stream
+ */
+ public TemporaryBuffer getStdout() {
+ return stdout;
+ }
+
+ /**
+ * @return buffered standard error stream
+ */
+ public TemporaryBuffer getStderr() {
+ return stderr;
+ }
+
+ /**
+ * @return the return code of the process
+ */
+ public int getRc() {
+ return rc;
+ }
+ }
+
private final static Logger LOG = LoggerFactory.getLogger(FS.class);
/** The auto-detected implementation selected for this operating system and JRE. */
@@ -404,8 +451,10 @@
* as component array
* @param encoding
* to be used to parse the command's output
- * @return the one-line output of the command
+ * @return the one-line output of the command or {@code null} if there is
+ * none
*/
+ @Nullable
protected static String readPipe(File dir, String[] command, String encoding) {
return readPipe(dir, command, encoding, null);
}
@@ -422,9 +471,11 @@
* @param env
* Map of environment variables to be merged with those of the
* current process
- * @return the one-line output of the command
+ * @return the one-line output of the command or {@code null} if there is
+ * none
* @since 4.0
*/
+ @Nullable
protected static String readPipe(File dir, String[] command, String encoding, Map<String, String> env) {
final boolean debug = LOG.isDebugEnabled();
try {
@@ -438,36 +489,30 @@
pb.environment().putAll(env);
}
Process p = pb.start();
- BufferedReader lineRead = new BufferedReader(
- new InputStreamReader(p.getInputStream(), encoding));
p.getOutputStream().close();
GobblerThread gobbler = new GobblerThread(p, command, dir);
gobbler.start();
String r = null;
- try {
+ try (BufferedReader lineRead = new BufferedReader(
+ new InputStreamReader(p.getInputStream(), encoding))) {
r = lineRead.readLine();
if (debug) {
LOG.debug("readpipe may return '" + r + "'"); //$NON-NLS-1$ //$NON-NLS-2$
- LOG.debug("(ignoring remaing output:"); //$NON-NLS-1$
- }
- String l;
- while ((l = lineRead.readLine()) != null) {
- if (debug) {
+ LOG.debug("remaining output:\n"); //$NON-NLS-1$
+ String l;
+ while ((l = lineRead.readLine()) != null) {
LOG.debug(l);
}
}
- } finally {
- p.getErrorStream().close();
- lineRead.close();
}
for (;;) {
try {
int rc = p.waitFor();
gobbler.join();
- if (rc == 0 && r != null && r.length() > 0
- && !gobbler.fail.get())
+ if (rc == 0 && !gobbler.fail.get()) {
return r;
+ }
if (debug) {
LOG.debug("readpipe rc=" + rc); //$NON-NLS-1$
}
@@ -477,7 +522,7 @@
}
}
} catch (IOException e) {
- LOG.debug("Caught exception in FS.readPipe()", e); //$NON-NLS-1$
+ LOG.error("Caught exception in FS.readPipe()", e); //$NON-NLS-1$
}
if (debug) {
LOG.debug("readpipe returns null"); //$NON-NLS-1$
@@ -489,52 +534,39 @@
private final Process p;
private final String desc;
private final String dir;
- private final boolean debug = LOG.isDebugEnabled();
- private final AtomicBoolean fail = new AtomicBoolean();
+ final AtomicBoolean fail = new AtomicBoolean();
- private GobblerThread(Process p, String[] command, File dir) {
+ GobblerThread(Process p, String[] command, File dir) {
this.p = p;
- if (debug) {
- this.desc = Arrays.asList(command).toString();
- this.dir = dir.toString();
- } else {
- this.desc = null;
- this.dir = null;
- }
+ this.desc = Arrays.toString(command);
+ this.dir = Objects.toString(dir);
}
public void run() {
- InputStream is = p.getErrorStream();
- try {
+ StringBuilder err = new StringBuilder();
+ try (InputStream is = p.getErrorStream()) {
int ch;
- if (debug) {
- while ((ch = is.read()) != -1) {
- System.err.print((char) ch);
- }
- } else {
- while (is.read() != -1) {
- // ignore
- }
+ while ((ch = is.read()) != -1) {
+ err.append((char) ch);
}
} catch (IOException e) {
- logError(e);
- fail.set(true);
- }
- try {
- is.close();
- } catch (IOException e) {
- logError(e);
- fail.set(true);
+ if (p.exitValue() != 0) {
+ logError(e);
+ fail.set(true);
+ } else {
+ // ignore. git terminated faster and stream was just closed
+ }
+ } finally {
+ if (err.length() > 0) {
+ LOG.error(err.toString());
+ }
}
}
private void logError(Throwable t) {
- if (!debug) {
- return;
- }
String msg = MessageFormat.format(
JGitText.get().exceptionCaughtDuringExcecutionOfCommand, desc, dir);
- LOG.debug(msg, t);
+ LOG.error(msg, t);
}
}
@@ -556,6 +588,14 @@
return null;
}
+ // Bug 480782: Check if the discovered git executable is JGit CLI
+ String v = readPipe(gitExe.getParentFile(),
+ new String[] { "git", "--version" }, //$NON-NLS-1$ //$NON-NLS-2$
+ Charset.defaultCharset().name());
+ if (v != null && v.startsWith("jgit")) { //$NON-NLS-1$
+ return null;
+ }
+
// Trick Git into printing the path to the config file by using "echo"
// as the editor.
Map<String, String> env = new HashMap<>();
@@ -871,52 +911,86 @@
* Runs the given process until termination, clearing its stdout and stderr
* streams on-the-fly.
*
- * @param hookProcessBuilder
- * The process builder configured for this hook.
+ * @param processBuilder
+ * The process builder configured for this process.
* @param outRedirect
- * A print stream on which to redirect the hook's stdout. Can be
- * <code>null</code>, in which case the hook's standard output
- * will be lost.
+ * A OutputStream on which to redirect the processes stdout. Can
+ * be <code>null</code>, in which case the processes standard
+ * output will be lost.
* @param errRedirect
- * A print stream on which to redirect the hook's stderr. Can be
- * <code>null</code>, in which case the hook's standard error
- * will be lost.
+ * A OutputStream on which to redirect the processes stderr. Can
+ * be <code>null</code>, in which case the processes standard
+ * error will be lost.
* @param stdinArgs
* A string to pass on to the standard input of the hook. Can be
* <code>null</code>.
- * @return the exit value of this hook.
+ * @return the exit value of this process.
* @throws IOException
- * if an I/O error occurs while executing this hook.
+ * if an I/O error occurs while executing this process.
* @throws InterruptedException
* if the current thread is interrupted while waiting for the
* process to end.
- * @since 3.7
+ * @since 4.2
*/
- protected int runProcess(ProcessBuilder hookProcessBuilder,
+ public int runProcess(ProcessBuilder processBuilder,
OutputStream outRedirect, OutputStream errRedirect, String stdinArgs)
throws IOException, InterruptedException {
+ InputStream in = (stdinArgs == null) ? null : new ByteArrayInputStream(
+ stdinArgs.getBytes(Constants.CHARACTER_ENCODING));
+ return runProcess(processBuilder, outRedirect, errRedirect, in);
+ }
+
+ /**
+ * Runs the given process until termination, clearing its stdout and stderr
+ * streams on-the-fly.
+ *
+ * @param processBuilder
+ * The process builder configured for this process.
+ * @param outRedirect
+ * An OutputStream on which to redirect the processes stdout. Can
+ * be <code>null</code>, in which case the processes standard
+ * output will be lost.
+ * @param errRedirect
+ * An OutputStream on which to redirect the processes stderr. Can
+ * be <code>null</code>, in which case the processes standard
+ * error will be lost.
+ * @param inRedirect
+ * An InputStream from which to redirect the processes stdin. Can
+ * be <code>null</code>, in which case the process doesn't get
+ * any data over stdin. It is assumed that the whole InputStream
+ * will be consumed by the process. The method will close the
+ * inputstream after all bytes are read.
+ * @return the return code of this process.
+ * @throws IOException
+ * if an I/O error occurs while executing this process.
+ * @throws InterruptedException
+ * if the current thread is interrupted while waiting for the
+ * process to end.
+ * @since 4.2
+ */
+ public int runProcess(ProcessBuilder processBuilder,
+ OutputStream outRedirect, OutputStream errRedirect,
+ InputStream inRedirect) throws IOException,
+ InterruptedException {
final ExecutorService executor = Executors.newFixedThreadPool(2);
Process process = null;
// We'll record the first I/O exception that occurs, but keep on trying
// to dispose of our open streams and file handles
IOException ioException = null;
try {
- process = hookProcessBuilder.start();
+ process = processBuilder.start();
final Callable<Void> errorGobbler = new StreamGobbler(
process.getErrorStream(), errRedirect);
final Callable<Void> outputGobbler = new StreamGobbler(
process.getInputStream(), outRedirect);
executor.submit(errorGobbler);
executor.submit(outputGobbler);
- if (stdinArgs != null) {
- final PrintWriter stdinWriter = new PrintWriter(
- process.getOutputStream());
- stdinWriter.print(stdinArgs);
- stdinWriter.flush();
- // We are done with this hook's input. Explicitly close its
- // stdin now to kick off any blocking read the hook might have.
- stdinWriter.close();
+ OutputStream outputStream = process.getOutputStream();
+ if (inRedirect != null) {
+ new StreamGobbler(inRedirect, outputStream)
+ .call();
}
+ outputStream.close();
return process.waitFor();
} catch (IOException e) {
ioException = e;
@@ -935,6 +1009,9 @@
// A process doesn't clean its own resources even when destroyed
// Explicitly try and close all three streams, preserving the
// outer I/O exception if any.
+ if (inRedirect != null) {
+ inRedirect.close();
+ }
try {
process.getErrorStream().close();
} catch (IOException e) {
@@ -975,10 +1052,10 @@
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
- if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
+ if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being canceled
- if (!pool.awaitTermination(5, TimeUnit.SECONDS))
+ if (!pool.awaitTermination(60, TimeUnit.SECONDS))
hasShutdown = false;
}
} catch (InterruptedException ie) {
@@ -1005,6 +1082,31 @@
*/
public abstract ProcessBuilder runInShell(String cmd, String[] args);
+ /**
+ * Execute a command defined by a {@link ProcessBuilder}.
+ *
+ * @param pb
+ * The command to be executed
+ * @param in
+ * The standard input stream passed to the process
+ * @return The result of the executed command
+ * @throws InterruptedException
+ * @throws IOException
+ * @since 4.2
+ */
+ public ExecutionResult execute(ProcessBuilder pb, InputStream in)
+ throws IOException, InterruptedException {
+ TemporaryBuffer stdout = new TemporaryBuffer.LocalFile(null);
+ TemporaryBuffer stderr = new TemporaryBuffer.Heap(1024, 1024 * 1024);
+ try {
+ int rc = runProcess(pb, stdout, stderr, in);
+ return new ExecutionResult(stdout, stderr, rc);
+ } finally {
+ stdout.close();
+ stderr.close();
+ }
+ }
+
private static class Holder<V> {
final V value;
@@ -1194,30 +1296,27 @@
* </p>
*/
private static class StreamGobbler implements Callable<Void> {
- private final BufferedReader reader;
+ private InputStream in;
- private final BufferedWriter writer;
+ private OutputStream out;
public StreamGobbler(InputStream stream, OutputStream output) {
- this.reader = new BufferedReader(new InputStreamReader(stream));
- if (output == null)
- this.writer = null;
- else
- this.writer = new BufferedWriter(new OutputStreamWriter(output));
+ this.in = stream;
+ this.out = output;
}
public Void call() throws IOException {
boolean writeFailure = false;
-
- String line = null;
- while ((line = reader.readLine()) != null) {
- // Do not try to write again after a failure, but keep reading
- // as long as possible to prevent the input stream from choking.
- if (!writeFailure && writer != null) {
+ byte buffer[] = new byte[4096];
+ int readBytes;
+ while ((readBytes = in.read(buffer)) != -1) {
+ // Do not try to write again after a failure, but keep
+ // reading as long as possible to prevent the input stream
+ // from choking.
+ if (!writeFailure && out != null) {
try {
- writer.write(line);
- writer.newLine();
- writer.flush();
+ out.write(buffer, 0, readBytes);
+ out.flush();
} catch (IOException e) {
writeFailure = true;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
index f0a2e72..defe14f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
@@ -171,7 +171,8 @@
createSymLink(linkName, tempFile.getPath());
supportSymlinks = Boolean.TRUE;
linkName.delete();
- } catch (IOException | UnsupportedOperationException e) {
+ } catch (IOException | UnsupportedOperationException
+ | InternalError e) {
supportSymlinks = Boolean.FALSE;
} finally {
if (tempFile != null)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
index 2450be4..ec581b3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
@@ -162,17 +162,15 @@
errRedirect, stdinArgs);
}
- @Override
- public boolean supportsSymlinks() {
- return true;
- }
-
/**
* @since 3.7
*/
@Override
public File findHook(Repository repository, String hookName) {
final File gitdir = repository.getDirectory();
+ if (gitdir == null) {
+ return null;
+ }
final Path hookPath = gitdir.toPath().resolve(Constants.HOOKS)
.resolve(hookName);
if (Files.isExecutable(hookPath))
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
index 548d239..aa101f7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -398,21 +398,30 @@
* Create a symbolic link
*
* @param path
+ * the path of the symbolic link to create
* @param target
+ * the target of the symbolic link
+ * @return the path to the symbolic link
* @throws IOException
- * @since 3.0
+ * @since 4.2
*/
- public static void createSymLink(File path, String target)
+ public static Path createSymLink(File path, String target)
throws IOException {
Path nioPath = path.toPath();
if (Files.exists(nioPath, LinkOption.NOFOLLOW_LINKS)) {
- Files.delete(nioPath);
+ BasicFileAttributes attrs = Files.readAttributes(nioPath,
+ BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
+ if (attrs.isRegularFile() || attrs.isSymbolicLink()) {
+ delete(path);
+ } else {
+ delete(path, EMPTY_DIRECTORIES_ONLY | RECURSIVE);
+ }
}
if (SystemReader.getInstance().isWindows()) {
target = target.replace('/', '\\');
}
Path nioTarget = new File(target).toPath();
- Files.createSymbolicLink(nioPath, nioTarget);
+ return Files.createSymbolicLink(nioPath, nioTarget);
}
/**
@@ -730,4 +739,29 @@
}
return name;
}
+
+ /**
+ * Best-effort variation of {@link File#getCanonicalFile()} returning the
+ * input file if the file cannot be canonicalized instead of throwing
+ * {@link IOException}.
+ *
+ * @param file
+ * to be canonicalized; may be {@code null}
+ * @return canonicalized file, or the unchanged input file if
+ * canonicalization failed or if {@code file == null}
+ * @throws SecurityException
+ * if {@link File#getCanonicalFile()} throws one
+ * @since 4.2
+ */
+ public static File canonicalize(File file) {
+ if (file == null) {
+ return null;
+ }
+ try {
+ return file.getCanonicalFile();
+ } catch (IOException e) {
+ return file;
+ }
+ }
+
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Paths.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Paths.java
new file mode 100644
index 0000000..6be7ddb
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Paths.java
@@ -0,0 +1,188 @@
+/*
+ * 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.lib.FileMode.TYPE_MASK;
+import static org.eclipse.jgit.lib.FileMode.TYPE_TREE;
+
+/**
+ * Utility functions for paths inside of a Git repository.
+ *
+ * @since 4.2
+ */
+public class Paths {
+ /**
+ * Remove trailing {@code '/'} if present.
+ *
+ * @param path
+ * input path to potentially remove trailing {@code '/'} from.
+ * @return null if {@code path == null}; {@code path} after removing a
+ * trailing {@code '/'}.
+ */
+ public static String stripTrailingSeparator(String path) {
+ if (path == null || path.isEmpty()) {
+ return path;
+ }
+
+ int i = path.length();
+ if (path.charAt(path.length() - 1) != '/') {
+ return path;
+ }
+ do {
+ i--;
+ } while (path.charAt(i - 1) == '/');
+ return path.substring(0, i);
+ }
+
+ /**
+ * Compare two paths according to Git path sort ordering rules.
+ *
+ * @param aPath
+ * first path buffer. The range {@code [aPos, aEnd)} is used.
+ * @param aPos
+ * index into {@code aPath} where the first path starts.
+ * @param aEnd
+ * 1 past last index of {@code aPath}.
+ * @param aMode
+ * mode of the first file. Trees are sorted as though
+ * {@code aPath[aEnd] == '/'}, even if aEnd does not exist.
+ * @param bPath
+ * second path buffer. The range {@code [bPos, bEnd)} is used.
+ * @param bPos
+ * index into {@code bPath} where the second path starts.
+ * @param bEnd
+ * 1 past last index of {@code bPath}.
+ * @param bMode
+ * mode of the second file. Trees are sorted as though
+ * {@code bPath[bEnd] == '/'}, even if bEnd does not exist.
+ * @return <0 if {@code aPath} sorts before {@code bPath};
+ * 0 if the paths are the same;
+ * >0 if {@code aPath} sorts after {@code bPath}.
+ */
+ public static int compare(byte[] aPath, int aPos, int aEnd, int aMode,
+ byte[] bPath, int bPos, int bEnd, int bMode) {
+ int cmp = coreCompare(
+ aPath, aPos, aEnd, aMode,
+ bPath, bPos, bEnd, bMode);
+ if (cmp == 0) {
+ cmp = lastPathChar(aMode) - lastPathChar(bMode);
+ }
+ return cmp;
+ }
+
+ /**
+ * Compare two paths, checking for identical name.
+ * <p>
+ * Unlike {@code compare} this method returns {@code 0} when the paths have
+ * the same characters in their names, even if the mode differs. It is
+ * intended for use in validation routines detecting duplicate entries.
+ * <p>
+ * Returns {@code 0} if the names are identical and a conflict exists
+ * between {@code aPath} and {@code bPath}, as they share the same name.
+ * <p>
+ * Returns {@code <0} if all possibles occurrences of {@code aPath} sort
+ * before {@code bPath} and no conflict can happen. In a properly sorted
+ * tree there are no other occurrences of {@code aPath} and therefore there
+ * are no duplicate names.
+ * <p>
+ * Returns {@code >0} when it is possible for a duplicate occurrence of
+ * {@code aPath} to appear later, after {@code bPath}. Callers should
+ * continue to examine candidates for {@code bPath} until the method returns
+ * one of the other return values.
+ *
+ * @param aPath
+ * first path buffer. The range {@code [aPos, aEnd)} is used.
+ * @param aPos
+ * index into {@code aPath} where the first path starts.
+ * @param aEnd
+ * 1 past last index of {@code aPath}.
+ * @param bPath
+ * second path buffer. The range {@code [bPos, bEnd)} is used.
+ * @param bPos
+ * index into {@code bPath} where the second path starts.
+ * @param bEnd
+ * 1 past last index of {@code bPath}.
+ * @param bMode
+ * mode of the second file. Trees are sorted as though
+ * {@code bPath[bEnd] == '/'}, even if bEnd does not exist.
+ * @return <0 if no duplicate name could exist;
+ * 0 if the paths have the same name;
+ * >0 other {@code bPath} should still be checked by caller.
+ */
+ public static int compareSameName(
+ byte[] aPath, int aPos, int aEnd,
+ byte[] bPath, int bPos, int bEnd, int bMode) {
+ return coreCompare(
+ aPath, aPos, aEnd, TYPE_TREE,
+ bPath, bPos, bEnd, bMode);
+ }
+
+ private static int coreCompare(
+ byte[] aPath, int aPos, int aEnd, int aMode,
+ byte[] bPath, int bPos, int bEnd, int bMode) {
+ while (aPos < aEnd && bPos < bEnd) {
+ int cmp = (aPath[aPos++] & 0xff) - (bPath[bPos++] & 0xff);
+ if (cmp != 0) {
+ return cmp;
+ }
+ }
+ if (aPos < aEnd) {
+ return (aPath[aPos] & 0xff) - lastPathChar(bMode);
+ }
+ if (bPos < bEnd) {
+ return lastPathChar(aMode) - (bPath[bPos] & 0xff);
+ }
+ return 0;
+ }
+
+ private static int lastPathChar(int mode) {
+ if ((mode & TYPE_MASK) == TYPE_TREE) {
+ return '/';
+ }
+ return 0;
+ }
+
+ private Paths() {
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
index 45c339f..f2955f7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
@@ -44,6 +44,8 @@
package org.eclipse.jgit.util;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.lib.ObjectChecker.author;
import static org.eclipse.jgit.lib.ObjectChecker.committer;
import static org.eclipse.jgit.lib.ObjectChecker.encoding;
@@ -60,6 +62,7 @@
import java.util.HashMap;
import java.util.Map;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.PersonIdent;
@@ -70,7 +73,7 @@
*
* @since 2.2
*/
- public static final Charset UTF8_CHARSET = Charset.forName("UTF-8"); //$NON-NLS-1$
+ public static final Charset UTF8_CHARSET = UTF_8;
private static final byte[] digits10;
@@ -81,8 +84,9 @@
private static final Map<String, Charset> encodingAliases;
static {
- encodingAliases = new HashMap<String, Charset>();
- encodingAliases.put("latin-1", Charset.forName("ISO-8859-1")); //$NON-NLS-1$ //$NON-NLS-2$
+ encodingAliases = new HashMap<>();
+ encodingAliases.put("latin-1", ISO_8859_1); //$NON-NLS-1$
+ encodingAliases.put("iso-latin-1", ISO_8859_1); //$NON-NLS-1$
digits10 = new byte['9' + 1];
Arrays.fill(digits10, (byte) -1);
@@ -671,35 +675,60 @@
}
/**
+ * Parse the "encoding " header as a string.
+ * <p>
+ * Locates the "encoding " header (if present) and returns its value.
+ *
+ * @param b
+ * buffer to scan.
+ * @return the encoding header as specified in the commit; null if the
+ * header was not present and should be assumed.
+ * @since 4.2
+ */
+ @Nullable
+ public static String parseEncodingName(final byte[] b) {
+ int enc = encoding(b, 0);
+ if (enc < 0) {
+ return null;
+ }
+ int lf = nextLF(b, enc);
+ return decode(UTF_8, b, enc, lf - 1);
+ }
+
+ /**
* Parse the "encoding " header into a character set reference.
* <p>
* Locates the "encoding " header (if present) by first calling
* {@link #encoding(byte[], int)} and then returns the proper character set
* to apply to this buffer to evaluate its contents as character data.
* <p>
- * If no encoding header is present, {@link Constants#CHARSET} is assumed.
+ * If no encoding header is present {@code UTF-8} is assumed.
*
* @param b
* buffer to scan.
* @return the Java character set representation. Never null.
+ * @throws IllegalCharsetNameException
+ * if the character set requested by the encoding header is
+ * malformed and unsupportable.
+ * @throws UnsupportedCharsetException
+ * if the JRE does not support the character set requested by
+ * the encoding header.
*/
public static Charset parseEncoding(final byte[] b) {
- final int enc = encoding(b, 0);
- if (enc < 0)
- return Constants.CHARSET;
- final int lf = nextLF(b, enc);
- String decoded = decode(Constants.CHARSET, b, enc, lf - 1);
+ String enc = parseEncodingName(b);
+ if (enc == null) {
+ return UTF_8;
+ }
+
+ String name = enc.trim();
try {
- return Charset.forName(decoded);
- } catch (IllegalCharsetNameException badName) {
- Charset aliased = charsetForAlias(decoded);
- if (aliased != null)
+ return Charset.forName(name);
+ } catch (IllegalCharsetNameException
+ | UnsupportedCharsetException badName) {
+ Charset aliased = charsetForAlias(name);
+ if (aliased != null) {
return aliased;
- throw badName;
- } catch (UnsupportedCharsetException badName) {
- Charset aliased = charsetForAlias(decoded);
- if (aliased != null)
- return aliased;
+ }
throw badName;
}
}
@@ -738,7 +767,15 @@
* parsed.
*/
public static PersonIdent parsePersonIdent(final byte[] raw, final int nameB) {
- final Charset cs = parseEncoding(raw);
+ Charset cs;
+ try {
+ cs = parseEncoding(raw);
+ } catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
+ // Assume UTF-8 for person identities, usually this is correct.
+ // If not decode() will fall back to the ISO-8859-1 encoding.
+ cs = UTF_8;
+ }
+
final int emailB = nextLF(raw, nameB, '<');
final int emailE = nextLF(raw, emailB, '>');
if (emailB >= raw.length || raw[emailB] == '\n' ||
@@ -886,7 +923,7 @@
*/
public static String decode(final byte[] buffer, final int start,
final int end) {
- return decode(Constants.CHARSET, buffer, start, end);
+ return decode(UTF_8, buffer, start, end);
}
/**
@@ -960,23 +997,21 @@
public static String decodeNoFallback(final Charset cs,
final byte[] buffer, final int start, final int end)
throws CharacterCodingException {
- final ByteBuffer b = ByteBuffer.wrap(buffer, start, end - start);
+ ByteBuffer b = ByteBuffer.wrap(buffer, start, end - start);
b.mark();
// Try our built-in favorite. The assumption here is that
// decoding will fail if the data is not actually encoded
// using that encoder.
- //
try {
- return decode(b, Constants.CHARSET);
+ return decode(b, UTF_8);
} catch (CharacterCodingException e) {
b.reset();
}
- if (!cs.equals(Constants.CHARSET)) {
+ if (!cs.equals(UTF_8)) {
// Try the suggested encoding, it might be right since it was
// provided by the caller.
- //
try {
return decode(b, cs);
} catch (CharacterCodingException e) {
@@ -986,9 +1021,8 @@
// Try the default character set. A small group of people
// might actually use the same (or very similar) locale.
- //
- final Charset defcs = Charset.defaultCharset();
- if (!defcs.equals(cs) && !defcs.equals(Constants.CHARSET)) {
+ Charset defcs = Charset.defaultCharset();
+ if (!defcs.equals(cs) && !defcs.equals(UTF_8)) {
try {
return decode(b, defcs);
} catch (CharacterCodingException e) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
index 4695111..0853e95 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
@@ -80,9 +80,9 @@
return (RefList<T>) EMPTY;
}
- private final Ref[] list;
+ final Ref[] list;
- private final int cnt;
+ final int cnt;
RefList(Ref[] list, int cnt) {
this.list = list;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java
index 5cc7e92..c72727b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java
@@ -78,10 +78,10 @@
* All reference names in this map must start with this prefix. If the
* prefix is not the empty string, it must end with a '/'.
*/
- private final String prefix;
+ final String prefix;
/** Immutable collection of the packed references at construction time. */
- private RefList<Ref> packed;
+ RefList<Ref> packed;
/**
* Immutable collection of the loose references at construction time.
@@ -91,7 +91,7 @@
* are typically unresolved, so they only tell us who their target is, but
* not the current value of the target.
*/
- private RefList<Ref> loose;
+ RefList<Ref> loose;
/**
* Immutable collection of resolved symbolic references.
@@ -101,11 +101,11 @@
* from {@link #loose}. Every entry in this list must be matched by an entry
* in {@code loose}, otherwise it might be omitted by the map.
*/
- private RefList<Ref> resolved;
+ RefList<Ref> resolved;
- private int size;
+ int size;
- private boolean sizeIsValid;
+ boolean sizeIsValid;
private Set<Entry<String, Ref>> entrySet;
@@ -280,7 +280,7 @@
return name;
}
- private String toMapKey(Ref ref) {
+ String toMapKey(Ref ref) {
String name = ref.getName();
if (0 < prefix.length())
name = name.substring(prefix.length());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
index 4795c89..9860ef0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
@@ -339,4 +339,19 @@
public void checkPath(String path) throws CorruptObjectException {
platformChecker.checkPath(path);
}
+
+ /**
+ * Check tree path entry for validity.
+ * <p>
+ * Scans a multi-directory path string such as {@code "src/main.c"}.
+ *
+ * @param path
+ * path string to scan.
+ * @throws CorruptObjectException
+ * path is invalid.
+ * @since 4.2
+ */
+ public void checkPath(byte[] path) throws CorruptObjectException {
+ platformChecker.checkPath(path, 0, path.length);
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
index e2738c0..3cd5929 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
@@ -69,7 +69,7 @@
protected static final int DEFAULT_IN_CORE_LIMIT = 1024 * 1024;
/** Chain of data, if we are still completely in-core; otherwise null. */
- private ArrayList<Block> blocks;
+ ArrayList<Block> blocks;
/**
* Maximum number of bytes we will permit storing in memory.
@@ -247,6 +247,37 @@
}
/**
+ * Convert this buffer's contents into a contiguous byte array. If this size
+ * of the buffer exceeds the limit only return the first {@code limit} bytes
+ * <p>
+ * The buffer is only complete after {@link #close()} has been invoked.
+ *
+ * @param limit
+ * the maximum number of bytes to be returned
+ *
+ * @return the byte array limited to {@code limit} bytes.
+ * @throws IOException
+ * an error occurred reading from a local temporary file
+ * @throws OutOfMemoryError
+ * the buffer cannot fit in memory
+ *
+ * @since 4.2
+ */
+ public byte[] toByteArray(int limit) throws IOException {
+ final long len = Math.min(length(), limit);
+ if (Integer.MAX_VALUE < len)
+ throw new OutOfMemoryError(
+ JGitText.get().lengthExceedsMaximumArraySize);
+ final byte[] out = new byte[(int) len];
+ int outPtr = 0;
+ for (final Block b : blocks) {
+ System.arraycopy(b.buffer, 0, out, outPtr, b.count);
+ outPtr += b.count;
+ }
+ return out;
+ }
+
+ /**
* Send this buffer to an output stream.
* <p>
* This method may only be invoked after {@link #close()} has completed
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java
index 24b8b53..8d39a22 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/StreamCopyThread.java
@@ -47,6 +47,7 @@
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
+import java.util.concurrent.atomic.AtomicInteger;
/** Thread to copy from an input stream to an output stream. */
public class StreamCopyThread extends Thread {
@@ -58,6 +59,8 @@
private volatile boolean done;
+ private final AtomicInteger flushCount = new AtomicInteger(0);
+
/**
* Create a thread to copy data from an input stream to an output stream.
*
@@ -82,6 +85,7 @@
* the request.
*/
public void flush() {
+ flushCount.incrementAndGet();
interrupt();
}
@@ -109,22 +113,30 @@
public void run() {
try {
final byte[] buf = new byte[BUFFER_SIZE];
- int interruptCounter = 0;
+ int flushCountBeforeRead = 0;
+ boolean readInterrupted = false;
for (;;) {
try {
- if (interruptCounter > 0) {
+ if (readInterrupted) {
dst.flush();
- interruptCounter--;
+ readInterrupted = false;
+ if (!flushCount.compareAndSet(flushCountBeforeRead, 0)) {
+ // There was a flush() call since last blocked read.
+ // Set interrupt status, so next blocked read will throw
+ // an InterruptedIOException and we will flush again.
+ interrupt();
+ }
}
if (done)
break;
+ flushCountBeforeRead = flushCount.get();
final int n;
try {
n = src.read(buf);
} catch (InterruptedIOException wakey) {
- interruptCounter++;
+ readInterrupted = true;
continue;
}
if (n < 0)
@@ -141,7 +153,7 @@
// set interrupt status, which will be checked
// when we block in src.read
- if (writeInterrupted)
+ if (writeInterrupted || flushCount.get() > 0)
interrupt();
break;
}
diff --git a/pom.xml b/pom.xml
index fa77335..38060d0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,7 +51,7 @@
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
<packaging>pom</packaging>
- <version>4.1.2.201602141800-r</version>
+ <version>4.2.1-SNAPSHOT</version>
<name>JGit - Parent</name>
<url>${jgit-url}</url>
@@ -192,7 +192,7 @@
<maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>
<bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
- <jgit-last-release-version>4.0.0.201506090130-r</jgit-last-release-version>
+ <jgit-last-release-version>4.1.0.201509280440-r</jgit-last-release-version>
<jsch-version>0.1.53</jsch-version>
<javaewah-version>0.7.9</javaewah-version>
<junit-version>4.11</junit-version>
@@ -202,7 +202,7 @@
<osgi-core-version>4.3.1</osgi-core-version>
<servlet-api-version>3.1.0</servlet-api-version>
<jetty-version>9.2.13.v20150730</jetty-version>
- <clirr-version>2.6.1</clirr-version>
+ <japicmp-version>0.5.3</japicmp-version>
<httpclient-version>4.3.6</httpclient-version>
<slf4j-version>1.7.2</slf4j-version>
<log4j-version>1.2.15</log4j-version>
@@ -355,16 +355,6 @@
</plugin>
<plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
- <version>${clirr-version}</version>
- <configuration>
- <comparisonVersion>${jgit-last-release-version}</comparisonVersion>
- <minSeverity>info</minSeverity>
- </configuration>
- </plugin>
-
- <plugin>
<groupId>org.eclipse.cbi.maven.plugins</groupId>
<artifactId>eclipse-jarsigner-plugin</artifactId>
<version>1.1.2</version>
@@ -529,18 +519,17 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
- </plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>clirr-maven-plugin</artifactId>
+ <version>2.5</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
+ <version>3.0.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
+ <version>2.18.1</version>
<configuration>
<aggregate>true</aggregate>
<alwaysGenerateSurefireReport>false</alwaysGenerateSurefireReport>
diff --git a/tools/default.defs b/tools/default.defs
new file mode 100644
index 0000000..3481fa1
--- /dev/null
+++ b/tools/default.defs
@@ -0,0 +1,42 @@
+def java_sources(
+ name,
+ srcs,
+ visibility = ['PUBLIC']
+ ):
+ java_library(
+ name = name,
+ resources = srcs,
+ visibility = visibility,
+ )
+
+def maven_jar(
+ name,
+ group,
+ artifact,
+ version,
+ bin_sha1,
+ src_sha1,
+ visibility = ['PUBLIC']):
+ jar_name = '%s__jar' % name
+ src_name = '%s__src' % name
+
+ remote_file(
+ name = jar_name,
+ sha1 = bin_sha1,
+ url = 'mvn:%s:%s:jar:%s' % (group, artifact, version),
+ out = '%s.jar' % jar_name,
+ )
+
+ remote_file(
+ name = src_name,
+ sha1 = src_sha1,
+ url = 'mvn:%s:%s:src:%s' % (group, artifact, version),
+ out = '%s.jar' % src_name,
+ )
+
+ prebuilt_jar(
+ name = name,
+ binary_jar = ':' + jar_name,
+ source_jar = ':' + src_name,
+ visibility = visibility)
+
diff --git a/tools/git.defs b/tools/git.defs
new file mode 100644
index 0000000..557dff2
--- /dev/null
+++ b/tools/git.defs
@@ -0,0 +1,9 @@
+def git_version():
+ import subprocess
+ cmd = ['git', 'describe', '--always', '--match', 'v[0-9].*', '--dirty']
+ p = subprocess.Popen(cmd, stdout = subprocess.PIPE)
+ v = p.communicate()[0].strip()
+ r = p.returncode
+ if r != 0:
+ raise subprocess.CalledProcessError(r, ' '.join(cmd))
+ return v
diff --git a/tools/maven-central/deploy.rb b/tools/maven-central/deploy.rb
index d620a88..8e7adc8 100755
--- a/tools/maven-central/deploy.rb
+++ b/tools/maven-central/deploy.rb
@@ -53,7 +53,6 @@
group + '.archive',
group + '.http.apache',
group + '.http.server',
- group + '.java7',
group + '.junit',
group + '.junit.http',
group + '.pgm',
diff --git a/tools/maven-central/download.rb b/tools/maven-central/download.rb
index de4ecd4..b7ea215 100755
--- a/tools/maven-central/download.rb
+++ b/tools/maven-central/download.rb
@@ -13,7 +13,6 @@
group + '.archive',
group + '.http.apache',
group + '.http.server',
- group + '.java7',
group + '.junit',
group + '.junit.http',
group + '.pgm',
diff --git a/tools/version.sh b/tools/version.sh
index a2f8129..81ffe06 100755
--- a/tools/version.sh
+++ b/tools/version.sh
@@ -149,17 +149,6 @@
$seen_version = 0;
$old_argv = $ARGV;
}
- if ($seen_version < 5) {
- $seen_version++ if
- s{<(version)>.*</\1>}{<${1}>'"$POM_V"'</${1}>};
- }
- ' org.eclipse.jgit.packaging/org.eclipse.jgit.updatesite/pom.xml
-
-perl -pi~ -e '
- if ($ARGV ne $old_argv) {
- $seen_version = 0;
- $old_argv = $ARGV;
- }
if (!$seen_version) {
$seen_version = 1 if
s{<(version)>.*</\1>}{<${1}>'"$POM_V"'</${1}>};