summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF12
-rw-r--r--org.eclipse.jgit.ant.test/pom.xml2
-rw-r--r--org.eclipse.jgit.ant/META-INF/MANIFEST.MF6
-rw-r--r--org.eclipse.jgit.ant/pom.xml102
-rw-r--r--org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs6
-rw-r--r--org.eclipse.jgit.archive/META-INF/MANIFEST.MF13
-rw-r--r--org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.archive/pom.xml89
-rw-r--r--org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF10
-rw-r--r--org.eclipse.jgit.http.apache/pom.xml102
-rw-r--r--org.eclipse.jgit.http.server/META-INF/MANIFEST.MF26
-rw-r--r--org.eclipse.jgit.http.server/pom.xml88
-rw-r--r--org.eclipse.jgit.http.test/META-INF/MANIFEST.MF36
-rw-r--r--org.eclipse.jgit.http.test/pom.xml2
-rw-r--r--org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF20
-rw-r--r--org.eclipse.jgit.junit.http/pom.xml2
-rw-r--r--org.eclipse.jgit.junit/META-INF/MANIFEST.MF32
-rw-r--r--org.eclipse.jgit.junit/pom.xml2
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java7
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java14
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java17
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java6
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java58
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.xml4
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/feature.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.source.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.jgit.packaging/org.eclipse.jgit.target/pom.xml2
-rw-r--r--org.eclipse.jgit.packaging/pom.xml2
-rw-r--r--org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF34
-rw-r--r--org.eclipse.jgit.pgm.test/pom.xml2
-rw-r--r--org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java8
-rw-r--r--org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CheckoutTest.java9
-rw-r--r--org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.java133
-rw-r--r--org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs6
-rw-r--r--org.eclipse.jgit.pgm/META-INF/MANIFEST.MF65
-rw-r--r--org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit.pgm/pom.xml2
-rw-r--r--org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties1
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java4
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Reset.java35
-rw-r--r--org.eclipse.jgit.test/META-INF/MANIFEST.MF83
-rw-r--r--org.eclipse.jgit.test/build.properties1
-rw-r--r--org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java275
-rw-r--r--org.eclipse.jgit.test/org.eclipse.jgit.test-WalkEncryptionTest-Proxy.launch20
-rw-r--r--org.eclipse.jgit.test/org.eclipse.jgit.test-WalkEncryptionTest.launch20
-rw-r--r--org.eclipse.jgit.test/pom.xml30
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/jgit-s3-config.disabled.properties48
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/jgit-s3-config.policy.bucket.json20
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/jgit-s3-config.policy.user.json24
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/jgit-s3-connection-v-0.properties11
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/jgit-s3-connection-v-1.properties14
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/jgit-s3-connection-v-2.properties48
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/log4j.properties9
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java47
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java50
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/FastIgnoreRuleTest.java1
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreNodeTest.java4
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/IgnoreRuleSpecialCasesTest.java55
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java53
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java8
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java1
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcTestCase.java4
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java271
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparerTest.java136
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java4
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java416
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java4
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java4
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java1295
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java21
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java171
-rw-r--r--org.eclipse.jgit.ui/META-INF/MANIFEST.MF18
-rw-r--r--org.eclipse.jgit.ui/pom.xml2
-rw-r--r--org.eclipse.jgit/.settings/.api_filters22
-rw-r--r--org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs6
-rw-r--r--org.eclipse.jgit/META-INF/MANIFEST.MF77
-rw-r--r--org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF4
-rw-r--r--org.eclipse.jgit/pom.xml94
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java67
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/diff/HistogramDiff.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java55
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java33
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java11
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java156
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/Strings.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java21
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java23
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/BitmapIndexImpl.java211
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/DeltaBaseCache.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java13
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndex.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexBuilder.java14
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java10
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexV1.java5
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV2.java10
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObject.java12
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java67
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java11
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java510
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapWalker.java125
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/BitmapIndex.java23
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java278
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java56
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java18
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TestProtocol.java12
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java10
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java26
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java500
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java10
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java204
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java38
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java14
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java2
-rw-r--r--pom.xml23
150 files changed, 6056 insertions, 995 deletions
diff --git a/.gitignore b/.gitignore
index ea8c4bf7f3..139e5aee6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
/target
+/.project
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
index 8f5d0b90d3..c3b9a3790a 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 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.ant.test
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.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.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.junit;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.0,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 a514e3dbc5..f8bf0838b3 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-SNAPSHOT</version>
+ <version>4.2.0-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 4986f0fbb0..0cdf8bac2a 100644
--- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF
@@ -2,11 +2,11 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.jgit.ant
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.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.0,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.0";
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 cb0fcb0a17..1a445ea877 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-SNAPSHOT</version>
+ <version>4.2.0-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 4e28e0b26b..45d6d2c4c0 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/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
index 4b1e81d40d..2bd0164225 100644
--- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.archive
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
@@ -12,16 +12,15 @@ Import-Package: org.apache.commons.compress.archivers;version="[1.4,2.0)",
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.0,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.nls;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.0,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.0";
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 cc3181962d..8d7846b6a5 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.archive - Sources
Bundle-SymbolicName: org.eclipse.jgit.archive.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.1.2.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.1.2.qualifier";roots="."
+Bundle-Version: 4.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.archive;version="4.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml
index 1127a773fb..c93da4bf49 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-SNAPSHOT</version>
+ <version>4.2.0-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/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
index 700badbca4..07f364c535 100644
--- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.jgit.http.apache
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-Localization: plugin
Bundle-Vendor: %Provider-Name
@@ -19,10 +19,10 @@ Import-Package: org.apache.http;version="[4.1.0,5.0.0)",
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.0,4.3.0)",
+ org.eclipse.jgit.transport.http;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.0,4.3.0)"
+Export-Package: org.eclipse.jgit.transport.http.apache;version="4.2.0";
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 dee349cd80..68d3c22691 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-SNAPSHOT</version>
+ <version>4.2.0-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.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF
index 85e1dd7d42..78c41c487c 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 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.http.server
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.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.0",
+ org.eclipse.jgit.http.server.glue;version="4.2.0";
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.0";
uses:="org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.lib,
org.eclipse.jgit.transport,
@@ -17,12 +17,12 @@ Bundle-ActivationPolicy: lazy
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.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.nls;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.0,4.3.0)"
diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml
index 8707e01534..9859a1d126 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-SNAPSHOT</version>
+ <version>4.2.0-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/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
index cff5d24fa2..f8bd4915f9 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 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.http.test
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.qualifier
Bundle-Vendor: %provider_name
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
@@ -22,23 +22,23 @@ Import-Package: javax.servlet;version="[2.5.0,3.2.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.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.0,4.3.0)",
+ org.eclipse.jgit.http.server;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.http.server.glue;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.http.server.resolver;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.junit;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.junit.http;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.nls;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.storage.file;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport.http;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport.http.apache;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.0,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 8f7cd03fd7..dd52a89e6c 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-SNAPSHOT</version>
+ <version>4.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.http.test</artifactId>
diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
index aa1dc8b2f8..32bca1bda0 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 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.junit.http
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.qualifier
Bundle-Localization: plugin
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
@@ -20,16 +20,16 @@ Import-Package: javax.servlet;version="[2.5.0,3.2.0)",
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.0,4.3.0)",
+ org.eclipse.jgit.http.server;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.junit;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.2.0,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.0";
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 40cdca158d..a61e6801a9 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-SNAPSHOT</version>
+ <version>4.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.junit.http</artifactId>
diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
index 048f65d8f2..7449004ba8 100644
--- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF
@@ -2,27 +2,27 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.junit
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.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.0,4.3.0)",
+ org.eclipse.jgit.api.errors;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.dircache;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.errors;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.merge;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.storage.file;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.treewalk;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util.io;version="[4.2.0,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.0";
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 53f1bdcc85..bf281e62b2 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-SNAPSHOT</version>
+ <version>4.2.0-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 136c64726f..521593ea80 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.io.Writer;
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,10 @@ public abstract class JGitTestUtil {
FileUtils.delete(path);
}
+ 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 b5348f9980..bb5f9efb8f 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 static org.junit.Assert.fail;
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,12 @@ public abstract class LocalDiskRepositoryTestCase {
/** A fake (but stable) identity for committer fields in the test. */
protected PersonIdent committer;
+ /** A {@link SystemReader} used to coordinate time, envars, etc. */
+ 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 +171,8 @@ public abstract class LocalDiskRepositoryTestCase {
/** 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 +277,10 @@ public abstract class LocalDiskRepositoryTestCase {
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 d24dd44fff..03a2b1a584 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.storage.file.FileBasedConfig;
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 @@ public class MockSystemReader extends SystemReader {
}
}
+ 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,17 @@ public class MockSystemReader extends SystemReader {
@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.
+ */
+ 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 ac4539a848..28c61778c7 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.FileOutputStream;
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,11 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
return JGitTestUtil.writeTrashFile(db, name, data);
}
+ 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 {
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 925a6b0216..251e65f553 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 @@ public class TestRepository<R extends Repository> {
private final ObjectInserter inserter;
- private long now;
+ private final MockSystemReader mockSystemReader;
/**
* Wrap a repository with test building tools.
@@ -148,7 +148,7 @@ public class TestRepository<R extends Repository> {
* @throws IOException
*/
public TestRepository(R db) throws IOException {
- this(db, new RevWalk(db));
+ this(db, new RevWalk(db), new MockSystemReader());
}
/**
@@ -161,11 +161,28 @@ public class TestRepository<R extends Repository> {
* @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
+ */
+ 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 +203,25 @@ public class TestRepository<R extends Repository> {
return git;
}
- /** @return current time adjusted by {@link #tick(int)}. */
+ /** @return current date. */
+ 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 +231,18 @@ public class TestRepository<R extends Repository> {
* 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 +420,8 @@ public class TestRepository<R extends Repository> {
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 +456,7 @@ public class TestRepository<R extends Repository> {
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 +691,7 @@ public class TestRepository<R extends Repository> {
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) {
@@ -1100,7 +1128,7 @@ public class TestRepository<R extends Repository> {
c.setAuthor(author);
if (committer != null) {
if (updateCommitterTime)
- committer = new PersonIdent(committer, new Date(now));
+ committer = new PersonIdent(committer, getDate());
c.setCommitter(committer);
}
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 43575f525a..99e153edc6 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.qualifier"
+ version="4.2.0.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 f7ef5ee250..e0bdd3871e 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-SNAPSHOT</version>
+ <version>4.2.0-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 f54ec78c50..ac37d07715 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.qualifier"
+ version="4.2.0.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 8be8b18b92..b1f8302fd5 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-SNAPSHOT</version>
+ <version>4.2.0-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 8dbf9f8a3c..00f368cd73 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.qualifier"
+ version="4.2.0.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 aa1d85cdc4..2bef9a6d31 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-SNAPSHOT</version>
+ <version>4.2.0-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 084c49f16c..254852f2c7 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.qualifier"
+ version="4.2.0.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.0" 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 6010467d6e..91e00170b1 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-SNAPSHOT</version>
+ <version>4.2.0-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 8e13dc9396..f7766ea3a2 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.qualifier"
+ version="4.2.0.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 b72f82f451..cc3b182797 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-SNAPSHOT</version>
+ <version>4.2.0-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 d7c1f6ad78..b6e6869feb 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-SNAPSHOT</version>
+ <version>4.2.0-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 9a7e6e0ba8..967d6c23d5 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.qualifier"
+ version="4.2.0.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 d710643114..8fd1da658f 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-SNAPSHOT</version>
+ <version>4.2.0-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 60492325ca..572ac376ee 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 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: JGit Target Platform Bundle
Bundle-SymbolicName: org.eclipse.jgit.target
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.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 e8e036ed44..8699688649 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-SNAPSHOT</version>
+ <version>4.2.0-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 e1f71cbd71..dd329b4b08 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-SNAPSHOT</version>
+ <version>4.2.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>JGit Tycho Parent</name>
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index 08a08a828e..db23c3b55f 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -2,27 +2,27 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.pgm.test
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.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.0,4.3.0)",
+ org.eclipse.jgit.api.errors;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.diff;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.dircache;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.junit;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.merge;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.pgm;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.pgm.internal;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.pgm.opt;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.storage.file;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.treewalk;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util.io;version="[4.2.0,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/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml
index 132645b97c..955674a062 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-SNAPSHOT</version>
+ <version>4.2.0-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 50ddfe04d8..559a6d5d40 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
@@ -164,6 +164,14 @@ public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase {
.replaceAll("\t", "\\\\t");
}
+ 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]);
+ }
+
protected void assertArrayOfLinesEquals(String[] expected, String[] actual) {
assertEquals(toText(expected), toText(actual));
}
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 387eb2bbb4..7bf4c26c38 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
@@ -556,15 +556,6 @@ public class CheckoutTest extends CLIRepositoryTestCase {
// 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);
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 0000000000..0785c5c5ff
--- /dev/null
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ResetTest.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.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.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 testResetSelf() throws Exception {
+ RevCommit commit = git.commit().setMessage("initial commit").call();
+ assertStringArrayEquals("",
+ execute("git reset --hard " + commit.getId().name()));
+ assertEquals(commit.getId(),
+ git.getRepository().getRef("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().getRef("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().getRef("HEAD").getObjectId());
+ }
+
+ @Test
+ public void testResetPathDoubleDash() throws Exception {
+ resetPath(true);
+ }
+
+ @Test
+ public void testResetPathNoDoubleDash() throws Exception {
+ resetPath(false);
+ }
+
+ private void resetPath(boolean useDoubleDash) 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", commit.getId().name(),
+ (useDoubleDash) ? " --" : "");
+ assertStringArrayEquals("", execute(cmd));
+ assertEquals(commit.getId(),
+ git.getRepository().getRef("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/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs
index 4e28e0b26b..45d6d2c4c0 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/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
index 3a78d94df0..567fd05750 100644
--- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.pgm
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.qualifier
Bundle-Vendor: %provider_name
Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin
@@ -10,38 +10,38 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7
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.0,4.3.0)",
+ org.eclipse.jgit.api.errors;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.archive;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.awtui;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.blame;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.diff;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.dircache;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.errors;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.gitrepo;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.merge;version="4.2.0",
+ org.eclipse.jgit.nls;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.notes;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revplot;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revwalk.filter;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.storage.file;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.storage.pack;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.treewalk;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util.io;version="[4.2.0,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.0";
uses:="org.eclipse.jgit.transport,
org.eclipse.jgit.util",
- org.eclipse.jgit.pgm;version="4.1.2";
+ org.eclipse.jgit.pgm;version="4.2.0";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.pgm.opt,
@@ -52,15 +52,14 @@ Export-Package: org.eclipse.jgit.console;version="4.1.2";
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.0";
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.0";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test",
+ org.eclipse.jgit.pgm.opt;version="4.2.0";
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 303ebf44f7..a3fef2e29a 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-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit.pgm - Sources
Bundle-SymbolicName: org.eclipse.jgit.pgm.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.1.2.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.1.2.qualifier";roots="."
+Bundle-Version: 4.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="4.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml
index 42fde6fe9a..ca2ead2925 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-SNAPSHOT</version>
+ <version>4.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.pgm</artifactId>
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 f7591fd80b..64afdad51e 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
@@ -192,6 +192,7 @@ 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
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 9b191e6796..db88008e10 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
@@ -58,12 +58,16 @@ class Repo extends TextBuiltin {
@Argument(required = true, 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 6d1b1c5481..6ba076290e 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.StopOptionHandler;
@Command(common = true, usage = "usage_reset")
class Reset extends TextBuiltin {
@@ -61,24 +65,33 @@ class Reset extends TextBuiltin {
@Option(name = "--hard", usage = "usage_resetHard")
private boolean hard = false;
- @Argument(required = true, metaVar = "metaVar_name", usage = "usage_reset")
+ @Argument(required = true, index = 0, metaVar = "metaVar_name", usage = "usage_reset")
private String commit;
+ @Argument(index = 1)
+ @Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = StopOptionHandler.class)
+ private List<String> paths = new ArrayList<String>();
+
@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");
+ command.setMode(mode);
+ }
command.call();
}
}
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 8f2f4284f0..37fd367171 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -2,54 +2,55 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.test
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.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.0,4.3.0)",
+ org.eclipse.jgit.api.errors;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.attributes;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.awtui;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.blame;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.diff;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.dircache;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.errors;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.events;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.fnmatch;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.gitrepo;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.hooks;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.ignore;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.ignore.internal;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.dfs;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.internal.storage.pack;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.junit;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.merge;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.nls;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.notes;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.patch;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.pgm;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.pgm.internal;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revplot;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revwalk.filter;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.storage.file;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.storage.pack;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.submodule;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport.http;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport.resolver;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.treewalk;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.treewalk.filter;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util.io;version="[4.2.0,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 afc4855d67..786046c58a 100644
--- a/org.eclipse.jgit.test/build.properties
+++ b/org.eclipse.jgit.test/build.properties
@@ -4,3 +4,4 @@ source.. = tst/,\
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 0000000000..db5f1b2eb6
--- /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.test-WalkEncryptionTest-Proxy.launch b/org.eclipse.jgit.test/org.eclipse.jgit.test-WalkEncryptionTest-Proxy.launch
new file mode 100644
index 0000000000..fe3a013720
--- /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 0000000000..3b4a5a24e1
--- /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 c174ba270b..539caff149 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-SNAPSHOT</version>
+ <version>4.2.0-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 0000000000..d540977e94
--- /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 0000000000..3020b09a00
--- /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 0000000000..830d0888c0
--- /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 0000000000..2402a4985a
--- /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 0000000000..d0d16118e9
--- /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 0000000000..731b3247d2
--- /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 0000000000..14620ffae4
--- /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/PushCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
index 19f074ea55..ccf1a51f1b 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.assertNotNull;
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.GitAPIException;
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.RefSpec;
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 {
@@ -108,6 +113,48 @@ public class PushCommandTest extends RepositoryTestCase {
}
@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");
+
+ 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:file://" + db2.getDirectory().toPath() //
+ + "/, 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();
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 66e7256432..b6649b3f05 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.junit.RepositoryTestCase;
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 {
@@ -692,6 +694,54 @@ public class RepoCommandTest extends RepositoryTestCase {
}
}
+ @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 2c04787e3d..480e326507 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 @@ public class FastIgnoreRuleTest {
@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 9722ac6750..5893d8c407 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
@@ -63,6 +63,7 @@ import org.eclipse.jgit.treewalk.FileTreeIterator;
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 +469,9 @@ public class IgnoreNodeTest extends RepositoryTestCase {
@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 ", "");
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 f8eb126826..567f3d866c 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 @@ public class IgnoreRuleSpecialCasesTest {
@Test
public void testSpecialGroupCase9() throws Exception {
- assertMatch("][", "][", true);
+ assertMatch("][", "][", false);
}
@Test
@@ -968,6 +968,59 @@ public class IgnoreRuleSpecialCasesTest {
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 fc8cbaa437..11a092468c 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.io.IOException;
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 @@ public class DfsInserterTest {
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/GcBasicPackingTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcBasicPackingTest.java
index bbd41237e2..f549fb5cdf 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 @@ public class GcBasicPackingTest extends GcTestCase {
assertEquals(4, stats.numberOfLooseObjects);
assertEquals(0, stats.numberOfPackedObjects);
assertEquals(0, stats.numberOfPackFiles);
+ assertEquals(0, stats.numberOfBitmaps);
}
@Theory
@@ -102,6 +103,7 @@ public class GcBasicPackingTest extends GcTestCase {
assertEquals(0, stats.numberOfLooseObjects);
assertEquals(8, stats.numberOfPackedObjects);
assertEquals(1, stats.numberOfPackFiles);
+ assertEquals(2, stats.numberOfBitmaps);
}
@Theory
@@ -118,6 +120,7 @@ public class GcBasicPackingTest extends GcTestCase {
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 @@ public class GcBasicPackingTest extends GcTestCase {
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 @@ public class GcBasicPackingTest extends GcTestCase {
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/GcReflogTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java
index 2a096fd1c4..3c781a9474 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 @@ public class GcReflogTest extends GcTestCase {
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 a764f0fddd..5abf625489 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;
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 abstract class GcTestCase extends LocalDiskRepositoryTestCase {
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/pack/GcCommitSelectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/pack/GcCommitSelectionTest.java
new file mode 100644
index 0000000000..5fda070867
--- /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 0000000000..b0f92ffa0c
--- /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/junit/TestRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java
index fbb9eecdff..b69b8e01e0 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
@@ -307,9 +307,9 @@ public class TestRepositoryTest {
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();
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 7a115e1076..6d62528f85 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,7 @@ import org.eclipse.jgit.revwalk.RevCommit;
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.Test;
public class DirCacheCheckoutTest extends RepositoryTestCase {
@@ -923,6 +924,299 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
}
@Test
+ public void testCheckoutChangeLinkToEmptyDir() throws Exception {
+ 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 {
+ 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 {
+ 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 {
+ 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();
+ assertFalse(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();
+ assertFalse(st.isClean());
+ assertEquals(1, st.getAdded().size());
+ assertTrue(st.getAdded().contains(fname + "/dir/file1"));
+ }
+
+ @Test
public void testCheckoutOutChangesAutoCRLFfalse() throws IOException {
setupCase(mk("foo"), mkmap("foo/bar", "foo\nbar"), mk("foo"));
checkout();
@@ -983,6 +1277,14 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
}
@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 +1317,102 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
}
@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 {
+ 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,10 +1608,11 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
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.setRecursive(false);
walk.addTree(new FileTreeIterator(db));
String expectedValue;
String path;
@@ -1223,11 +1622,11 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
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()) {
+ 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;
@@ -1241,6 +1640,15 @@ public class DirCacheCheckoutTest extends RepositoryTestCase {
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++;
+ }
+ }
+ if (walk.isSubtree()) {
+ walk.enterSubtree();
}
}
assertEquals("WorkDir has not the right size.", i.size(), nrFiles);
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 643ba26d9a..8ab972837c 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 @@ public class RevWalkFilterTest extends RevWalkTestCase {
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 881deb1f5a..30586ee1e2 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 @@ public abstract class RevWalkTestCase extends RepositoryTestCase {
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/transport/WalkEncryptionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java
new file mode 100644
index 0000000000..90d78e4b62
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java
@@ -0,0 +1,1295 @@
+/*
+ * 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.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.URL;
+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;
+
+import static org.eclipse.jgit.transport.WalkEncryptionTest.Util.*;
+
+/**
+ * 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 {
+ String service = "http://checkip.amazonaws.com";
+ URL url = new URL(service);
+ BufferedReader reader = new BufferedReader(
+ new InputStreamReader(url.openStream()));
+ try {
+ return reader.readLine();
+ } finally {
+ reader.close();
+ }
+ }
+
+ /**
+ * 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/util/HookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HookTest.java
index b14a9bf2fa..8aa14c5218 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
@@ -92,9 +92,11 @@ public class HookTest extends RepositoryTestCase {
fail("expected commit-msg hook to abort commit");
} catch (AbortedByHookException e) {
assertEquals("unexpected error message from commit-msg hook",
- "Rejected by \"commit-msg\" hook.\nstderr\n",
+ "Rejected by \"commit-msg\" hook.\nstderr"
+ + System.lineSeparator(),
e.getMessage());
- assertEquals("unexpected output from commit-msg hook", "test\n",
+ assertEquals("unexpected output from commit-msg hook",
+ "test" + System.lineSeparator(),
out.toString());
}
}
@@ -112,7 +114,8 @@ public class HookTest extends RepositoryTestCase {
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" + System.lineSeparator(),
+ out.toString("UTF-8"));
}
@Test
@@ -144,9 +147,11 @@ public class HookTest extends RepositoryTestCase {
new String[] {
"arg1", "arg2" },
new PrintStream(out), new PrintStream(err), "stdin");
- assertEquals("unexpected hook output", "test arg1 arg2\nstdin\n",
+ assertEquals("unexpected hook output", "test arg1 arg2"
+ + System.lineSeparator() + "stdin" + System.lineSeparator(),
out.toString("UTF-8"));
- assertEquals("unexpected output on stderr stream", "stderr\n",
+ assertEquals("unexpected output on stderr stream",
+ "stderr" + System.lineSeparator(),
err.toString("UTF-8"));
assertEquals("unexpected exit code", 0, res.getExitCode());
assertEquals("unexpected process status", ProcessResult.Status.OK,
@@ -170,9 +175,11 @@ public class HookTest extends RepositoryTestCase {
fail("expected pre-commit hook to abort commit");
} catch (AbortedByHookException e) {
assertEquals("unexpected error message from pre-commit hook",
- "Rejected by \"pre-commit\" hook.\nstderr\n",
+ "Rejected by \"pre-commit\" hook.\nstderr"
+ + System.lineSeparator(),
e.getMessage());
- assertEquals("unexpected output from pre-commit hook", "test\n",
+ assertEquals("unexpected output from pre-commit hook",
+ "test" + System.lineSeparator(),
out.toString());
}
}
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 0000000000..82beab2dc8
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RunExternalScriptTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.junit.Before;
+import org.junit.Test;
+
+public class RunExternalScriptTest {
+ private ByteArrayOutputStream out;
+
+ private ByteArrayOutputStream err;
+
+ private String sep = System.getProperty("line.separator");
+
+ @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("/bin/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("/bin/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("/bin/bash",
+ 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("/bin/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("/bin/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("/bin/sh", script.getPath()), null, err,
+ (InputStream) null);
+ assertEquals(0, rc);
+ assertEquals("", new String(out.toByteArray()));
+ assertEquals("hi" + sep, 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("/bin/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,,," + sep, 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("/bin/sh", script.getPath(), "a", "b", "c"),
+ out, err, (InputStream) null);
+ assertEquals(127, rc);
+ }
+
+ 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/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index 3df4347016..4e2db1bfcc 100644
--- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
@@ -3,14 +3,14 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit.ui
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.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.0"
+Import-Package: org.eclipse.jgit.errors;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.lib;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.nls;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revplot;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.revwalk;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.transport;version="[4.2.0,4.3.0)",
+ org.eclipse.jgit.util;version="[4.2.0,4.3.0)"
diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml
index 79c30f0ac9..6a56f8cf33 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-SNAPSHOT</version>
+ <version>4.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.jgit.ui</artifactId>
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index a1e79e2d29..ed330b1517 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -1,5 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.jgit" version="2">
+ <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/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 +35,12 @@
</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 4e28e0b26b..195987db64 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.NonByDefault
+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/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index 24798be02a..b6899b2801 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -2,11 +2,11 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %plugin_name
Bundle-SymbolicName: org.eclipse.jgit
-Bundle-Version: 4.1.2.qualifier
+Bundle-Version: 4.2.0.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.api;version="4.2.0";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.diff,
@@ -20,60 +20,60 @@ Export-Package: org.eclipse.jgit.api;version="4.1.2";
org.eclipse.jgit.submodule,
org.eclipse.jgit.transport,
org.eclipse.jgit.merge",
- org.eclipse.jgit.api.errors;version="4.1.2";
+ org.eclipse.jgit.api.errors;version="4.2.0";
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.attributes;version="4.2.0",
+ org.eclipse.jgit.blame;version="4.2.0";
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.0";
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.0";
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.0";
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";
+ org.eclipse.jgit.events;version="4.2.0";
uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.fnmatch;version="4.1.2",
- org.eclipse.jgit.gitrepo;version="4.1.2";
+ org.eclipse.jgit.fnmatch;version="4.2.0",
+ org.eclipse.jgit.gitrepo;version="4.2.0";
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";
+ org.eclipse.jgit.gitrepo.internal;version="4.2.0";x-internal:=true,
+ org.eclipse.jgit.hooks;version="4.2.0";
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";
+ org.eclipse.jgit.ignore;version="4.2.0",
+ org.eclipse.jgit.ignore.internal;version="4.2.0";x-friends:="org.eclipse.jgit.test",
+ org.eclipse.jgit.internal;version="4.2.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
+ org.eclipse.jgit.internal.storage.dfs;version="4.2.0";
x-friends:="org.eclipse.jgit.test,
org.eclipse.jgit.http.server",
- org.eclipse.jgit.internal.storage.file;version="4.1.2";
+ org.eclipse.jgit.internal.storage.file;version="4.2.0";
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",
- 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.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
+ org.eclipse.jgit.lib;version="4.2.0";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.util,
@@ -83,45 +83,45 @@ Export-Package: org.eclipse.jgit.api;version="4.1.2";
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.0";
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.0",
+ org.eclipse.jgit.notes;version="4.2.0";
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";
+ org.eclipse.jgit.patch;version="4.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.diff",
- org.eclipse.jgit.revplot;version="4.1.2";
+ org.eclipse.jgit.revplot;version="4.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.revwalk",
- org.eclipse.jgit.revwalk;version="4.1.2";
+ org.eclipse.jgit.revwalk;version="4.2.0";
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";
+ org.eclipse.jgit.revwalk.filter;version="4.2.0";
uses:="org.eclipse.jgit.revwalk,
org.eclipse.jgit.lib,
org.eclipse.jgit.util",
- org.eclipse.jgit.storage.file;version="4.1.2";
+ org.eclipse.jgit.storage.file;version="4.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.util",
- org.eclipse.jgit.storage.pack;version="4.1.2";
+ org.eclipse.jgit.storage.pack;version="4.2.0";
uses:="org.eclipse.jgit.lib",
- org.eclipse.jgit.submodule;version="4.1.2";
+ org.eclipse.jgit.submodule;version="4.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.treewalk.filter,
org.eclipse.jgit.treewalk",
- org.eclipse.jgit.transport;version="4.1.2";
+ org.eclipse.jgit.transport;version="4.2.0";
uses:="org.eclipse.jgit.transport.resolver,
org.eclipse.jgit.revwalk,
org.eclipse.jgit.internal.storage.pack,
@@ -133,29 +133,28 @@ Export-Package: org.eclipse.jgit.api;version="4.1.2";
org.eclipse.jgit.transport.http,
org.eclipse.jgit.errors,
org.eclipse.jgit.storage.pack",
- org.eclipse.jgit.transport.http;version="4.1.2";
+ org.eclipse.jgit.transport.http;version="4.2.0";
uses:="javax.net.ssl",
- org.eclipse.jgit.transport.resolver;version="4.1.2";
+ org.eclipse.jgit.transport.resolver;version="4.2.0";
uses:="org.eclipse.jgit.lib,
org.eclipse.jgit.transport",
- org.eclipse.jgit.treewalk;version="4.1.2";
+ org.eclipse.jgit.treewalk;version="4.2.0";
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";
+ org.eclipse.jgit.treewalk.filter;version="4.2.0";
uses:="org.eclipse.jgit.treewalk",
- org.eclipse.jgit.util;version="4.1.2";
+ org.eclipse.jgit.util;version="4.2.0";
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.0"
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 c5476a85cf..a03d7df6ce 100644
--- a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF
@@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2
Bundle-Name: org.eclipse.jgit - Sources
Bundle-SymbolicName: org.eclipse.jgit.source
Bundle-Vendor: Eclipse.org - JGit
-Bundle-Version: 4.1.2.qualifier
-Eclipse-SourceBundle: org.eclipse.jgit;version="4.1.2.qualifier";roots="."
+Bundle-Version: 4.2.0.qualifier
+Eclipse-SourceBundle: org.eclipse.jgit;version="4.2.0.qualifier";roots="."
diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml
index 8791389dac..4f98323e5d 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-SNAPSHOT</version>
+ <version>4.2.0-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 34bbb415ba..51e44fd778 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -228,6 +228,7 @@ emptyCommit=No changes
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}
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 0000000000..254920e7a3
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/annotations/Nullable.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+/**
+ * JGit's replacement for the {@code javax.annotations.Nullable}.
+ * <p>
+ * Denotes that a local variable, parameter, field, method return value can be
+ * {@code null}.
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@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/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
index 8d8aada622..8d85bfcb15 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -457,7 +457,7 @@ public class CheckoutCommand extends GitCommand<Ref> {
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/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
index 6de25a052a..8ef550871f 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 @@ public class StashApplyCommand extends GitCommand<ObjectId> {
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/diff/ContentSource.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
index 3c780e7d88..0dc4b05787 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/ContentSource.java
@@ -148,7 +148,7 @@ public abstract class ContentSource {
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 e57faaf858..2f5c9ea84c 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 @@ import java.util.List;
*/
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 @@ public class HistogramDiff extends LowLevelDiffAlgorithm {
* 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/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index 00252547db..0036ab5089 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -447,7 +447,7 @@ public class DirCacheCheckout {
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);
}
// commit the index builder - a new index is persisted
@@ -1127,6 +1127,13 @@ public class DirCacheCheckout {
* 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 +1150,42 @@ public class DirCacheCheckout {
*/
public static void checkoutEntry(Repository repo, DirCacheEntry entry,
ObjectReader or) throws IOException {
+ checkoutEntry(repo, entry, or, false);
+ }
+
+ /**
+ * 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 {
ObjectLoader ol = or.open(entry.getObjectId());
File f = new File(repo.getWorkTree(), entry.getPathString());
File parentDir = f.getParentFile();
@@ -1153,6 +1196,9 @@ public class DirCacheCheckout {
&& 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));
@@ -1183,11 +1229,18 @@ public class DirCacheCheckout {
}
}
try {
+ if (deleteRecursive && f.isDirectory()) {
+ FileUtils.delete(f, FileUtils.RECURSIVE);
+ }
FileUtils.rename(tmpFile, f);
} catch (IOException e) {
throw new IOException(MessageFormat.format(
JGitText.get().renameFileFailed, tmpFile.getPath(),
f.getPath()));
+ } finally {
+ if (tmpFile.exists()) {
+ FileUtils.delete(tmpFile);
+ }
}
entry.setLastModified(f.lastModified());
}
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 f139afc00b..0cbb83d6e2 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 @@ public class DirCacheTree {
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/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
index 790f4db672..1d2d3bfaaf 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -106,6 +106,7 @@ public class RepoCommand extends GitCommand<RevCommit> {
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 +315,30 @@ public class RepoCommand extends GitCommand<RevCommit> {
}
/**
+ * 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 +454,14 @@ public class RepoCommand extends GitCommand<RevCommit> {
// 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);
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 1494576ab8..6f7a21a73f 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 @@ public class Hooks {
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 0000000000..2e6582819f
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java
@@ -0,0 +1,156 @@
+/*
+ * 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() {
+ 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 f972828bc6..e354c7114c 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 @@ public class Strings {
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 9067e82954..e39469bd8c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -287,6 +287,7 @@ public class JGitText extends TranslationBundle {
/***/ public String emptyPathNotPermitted;
/***/ public String emptyRef;
/***/ public String encryptionError;
+ /***/ public String encryptionOnlyPBE;
/***/ public String endOfFileInEscape;
/***/ public String entryNotFoundByPath;
/***/ public String enumValueNotSupported2;
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 488eee9794..e5ae9800fa 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 @@ public class DfsInserter extends ObjectInserter {
/** 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 @@ public class DfsInserter extends ObjectInserter {
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 @@ public class DfsInserter extends ObjectInserter {
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 b92f784f29..5f491ff2fd 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.Map;
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;
@@ -181,6 +182,28 @@ public abstract class DfsObjDatabase extends ObjectDatabase {
}
/**
+ * 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/InMemoryRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
index 8e7af0d290..832e4fb6a8 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
@@ -43,7 +43,7 @@ public class InMemoryRepository extends DfsRepository {
}
}
- private static final AtomicInteger packId = new AtomicInteger();
+ static final AtomicInteger packId = new AtomicInteger();
private final DfsObjDatabase objdb;
@@ -60,7 +60,7 @@ public class InMemoryRepository extends DfsRepository {
this(new Builder().setRepositoryDescription(repoDesc));
}
- private InMemoryRepository(Builder builder) {
+ InMemoryRepository(Builder builder) {
super(builder);
objdb = new MemObjDatabase(this);
refdb = new MemRefDatabase();
@@ -139,7 +139,7 @@ public class InMemoryRepository extends DfsRepository {
}
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) {
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 0c3c7361a9..b27bcc4258 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 @@ import org.eclipse.jgit.util.BlockList;
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 @@ public class BitmapIndexImpl implements BitmapIndex {
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 @@ public class BitmapIndexImpl implements BitmapIndex {
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 @@ public class BitmapIndexImpl implements BitmapIndex {
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 @@ public class BitmapIndexImpl implements BitmapIndex {
}
}
- 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 @@ public class BitmapIndexImpl implements BitmapIndex {
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;
}
- }
- final class CompressedBitmap implements Bitmap {
- private final EWAHCompressedBitmap bitmap;
+ 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();
+ }
+ }
- private CompressedBitmap(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;
+
+ /**
+ * 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 @@ public class BitmapIndexImpl implements BitmapIndex {
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 @@ public class BitmapIndexImpl implements BitmapIndex {
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 @@ public class BitmapIndexImpl implements BitmapIndex {
}
}
- 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 @@ public class BitmapIndexImpl implements BitmapIndex {
}
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 @@ public class BitmapIndexImpl implements BitmapIndex {
}
}
- 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 2f30496e2f..a95dea74b6 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 @@ import org.eclipse.jgit.storage.file.WindowCacheConfig;
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/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index c5723c0594..e7005c247e 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
@@ -877,6 +877,11 @@ public class GC {
*/
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 +891,15 @@ public class GC {
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 +909,8 @@ public class GC {
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();
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 06eb42cbbc..50297a97a0 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
@@ -120,11 +120,11 @@ public class LockFile {
private boolean haveLck;
- private FileOutputStream os;
+ FileOutputStream os;
private boolean needSnapshot;
- private boolean fsync;
+ boolean fsync;
private FileSnapshot commitSnapshot;
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 ae4de84a07..e743cb4aff 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 @@ public abstract class PackBitmapIndex {
* 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 93f891864a..4ff09a148f 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 @@ public class PackBitmapIndexBuilder extends BasePackBitmapIndex {
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 @@ public class PackBitmapIndexBuilder extends BasePackBitmapIndex {
return PackBitmapIndexV1.OPT_FULL;
}
- /** @return the number of bitmaps. */
+ @Override
public int getBitmapCount() {
return getBitmaps().size();
}
@@ -330,7 +330,7 @@ public class PackBitmapIndexBuilder extends BasePackBitmapIndex {
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 @@ public class PackBitmapIndexBuilder extends BasePackBitmapIndex {
}
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 6b96b07ed1..7cd68b625e 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 @@ public class PackBitmapIndexRemapper extends PackBitmapIndex
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 class PackBitmapIndexRemapper extends PackBitmapIndex
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 @@ public class PackBitmapIndexRemapper extends PackBitmapIndex
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 a38a26dec0..a7ab00db2d 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 @@ class PackBitmapIndexV1 extends BasePackBitmapIndex {
}
@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 589a811735..b385b8ab73 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 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> {
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/PackIndexV1.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndexV1.java
index ab3297ad2a..e5a729dbf3 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 @@ class PackIndexV1 extends PackIndex {
private final long[] idxHeader;
- private byte[][] idxdata;
+ byte[][] idxdata;
private long objectCnt;
@@ -233,9 +233,9 @@ class PackIndexV1 extends PackIndex {
}
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 cb8c91a5a7..d87336f99c 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 @@ class PackIndexV2 extends PackIndex {
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 @@ class PackIndexV2 extends PackIndex {
}
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/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
index bb5b044405..7851678a88 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
@@ -138,7 +138,7 @@ public class RefDirectory extends RefDatabase {
private final File gitDir;
- private final File refsDir;
+ final File refsDir;
private final ReflogWriter logWriter;
@@ -155,7 +155,7 @@ public class RefDirectory extends RefDatabase {
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.
@@ -925,7 +925,7 @@ public class RefDirectory extends RefDatabase {
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;
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 e4cc697962..2cc2563962 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 @@ public class UnpackedObject {
}
}
- 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 @@ public class UnpackedObject {
}
}
- 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 @@ public class UnpackedObject {
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 @@ public class UnpackedObject {
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 @@ public class UnpackedObject {
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;
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 8ea0c23eaf..42927426b9 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 class DeltaTask implements Callable<Object> {
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 @@ final class DeltaTask implements Callable<Object> {
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 @@ final class DeltaTask implements Callable<Object> {
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 @@ final class DeltaTask implements Callable<Object> {
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 @@ final class DeltaTask implements Callable<Object> {
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 @@ final class DeltaTask implements Callable<Object> {
});
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 @@ final class DeltaTask implements Callable<Object> {
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 @@ final class DeltaTask implements Callable<Object> {
}
private final Block block;
- private final LinkedList<Slice> slices;
+ final LinkedList<Slice> slices;
private ObjectReader or;
private DeltaWindow dw;
@@ -278,14 +296,16 @@ final class DeltaTask implements Callable<Object> {
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 @@ final class DeltaTask implements Callable<Object> {
}
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 683d1cd6e9..19b6b080da 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
@@ -218,7 +218,7 @@ public class PackWriter implements AutoCloseable {
}
@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 +249,7 @@ public class PackWriter implements AutoCloseable {
/** {@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;
@@ -1306,8 +1306,7 @@ public class PackWriter implements AutoCloseable {
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;
@@ -2015,10 +2014,10 @@ public class PackWriter implements AutoCloseable {
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 756d4b0005..77311abaa5 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.Iterator;
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 @@ class PackWriterBitmapPreparer {
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 @@ class PackWriterBitmapPreparer {
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);
-
- for (BitmapBuilder bitmapableCommits : result.paths) {
- int cardinality = bitmapableCommits.cardinality();
-
- List<List<BitmapCommit>> running = new ArrayList<
- List<BitmapCommit>>();
+ int totalWants = selectionHelper.peeledWants.size();
+
+ for (BitmapBuilderEntry entry : selectionHelper.tipCommitBitmaps) {
+ BitmapBuilder bitmap = entry.getBuilder();
+ int cardinality = bitmap.cardinality();
+
+ // 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);
+ // 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;
+ }
+ }
}
- 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;
- }
+ if (longestAncestorChain == null) {
+ longestAncestorChain = new ArrayList<BitmapCommit>();
+ chains.add(longestAncestorChain);
}
- match.add(new BitmapCommit(c, !match.isEmpty(), flags));
+ 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 @@ class PackWriterBitmapPreparer {
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 @@ class PackWriterBitmapPreparer {
}
}
- 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;
+
+ BitmapBuilderEntry(RevCommit commit, BitmapBuilder builder) {
+ this.commit = commit;
+ this.builder = builder;
+ }
- private WalkResult(Set<? extends ObjectId> peeledWant,
+ 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 @@ class PackWriterBitmapPreparer {
}
};
}
+
+ 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 debb2f2abc..d9ac9ef16b 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 @@ final class PackWriterBitmapWalker {
}
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 @@ final class PackWriterBitmapWalker {
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);
+
+ @Override
+ public final boolean include(RevWalk walker, RevCommit cmit) {
+ 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;
}
- };
- }
- static abstract class BitmapRevFilter extends RevFilter {
- private long countOfLoadedCommits;
+ 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;
+ }
+ }
- protected abstract boolean load(RevCommit cmit);
+ /**
+ * 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) {
- if (load(cmit)) {
- countOfLoadedCommits++;
+ 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())
+
+ 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;
- }
}
}
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 3c0e2c128e..9ddff25480 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 @@ public interface BitmapIndex {
* @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 @@ public interface BitmapIndex {
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 @@ public interface BitmapIndex {
/** @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/ObjectIdOwnerMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
index c9b483f7f0..95b16d9176 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdOwnerMap.java
@@ -83,16 +83,16 @@ public class ObjectIdOwnerMap<V extends ObjectIdOwnerMap.Entry> implements
* 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/ObjectIdSubclassMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java
index 69972dc013..48aa109e7c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectIdSubclassMap.java
@@ -63,13 +63,13 @@ import java.util.NoSuchElementException;
public class ObjectIdSubclassMap<V extends ObjectId> implements Iterable<V> {
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/merge/MergeResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeResult.java
index dc3c772efb..106f9c7796 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 @@ import org.eclipse.jgit.util.IntList;
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 @@ public class MergeResult<S extends Sequence> implements Iterable<MergeChunk> {
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/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
index 1176d958b0..c8504937a7 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 @@ public class RevWalk implements Iterable<RevCommit>, AutoCloseable {
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/pack/PackConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackConfig.java
index a8835b76c9..d594e97671 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 class PackConfig {
*/
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 @@ public class PackConfig {
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 @@ public class PackConfig {
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 @@ public class PackConfig {
* 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 @@ public class PackConfig {
}
/**
+ * 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 @@ public class PackConfig {
// 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 @@ public class PackConfig {
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 d3cdba5bf3..4069a64535 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.ProxySelector;
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 @@ public class AmazonS3 {
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 @@ public class AmazonS3 {
/** 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 class AmazonS3 {
*
*/
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 @@ public class AmazonS3 {
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 @@ public class AmazonS3 {
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 @@ public class AmazonS3 {
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 @@ public class AmazonS3 {
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 @@ public class AmazonS3 {
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 @@ public class AmazonS3 {
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/Daemon.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java
index 03f7c72835..d9e0b937e8 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 @@ public class Daemon {
private boolean run;
- private Thread acceptThread;
+ Thread acceptThread;
private int timeout;
@@ -87,9 +87,9 @@ public class Daemon {
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 @@ public class Daemon {
}
}
- 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/JschSession.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
index b4a09020b5..85109a5bf0 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 @@ import com.jcraft.jsch.Session;
* 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 @@ public class JschSession implements RemoteSession {
private class JschProcess extends Process {
private ChannelExec channel;
- private final int timeout;
+ final int timeout;
private InputStream inputStream;
@@ -141,7 +141,7 @@ public class JschSession implements RemoteSession {
* @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 {
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 918df94de9..6e5fc9f009 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 @@ public abstract class PackParser {
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;
@@ -1141,13 +1141,13 @@ public abstract class PackParser {
}
// 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/PushCertificateStore.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java
index d8672d5a2b..8947f2779d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateStore.java
@@ -107,11 +107,11 @@ public class PushCertificateStore implements AutoCloseable {
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 +121,8 @@ public class PushCertificateStore implements AutoCloseable {
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 +270,7 @@ public class PushCertificateStore implements AutoCloseable {
};
}
- private void load() throws IOException {
+ void load() throws IOException {
close();
reader = db.newObjectReader();
Ref ref = db.getRefDatabase().exactRef(REF_NAME);
@@ -283,7 +283,7 @@ public class PushCertificateStore implements AutoCloseable {
}
}
- 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;
}
@@ -532,7 +532,7 @@ public class PushCertificateStore implements AutoCloseable {
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/TestProtocol.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TestProtocol.java
index 5243010502..5fd2f84b7e 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 @@ public class TestProtocol<C> extends TransportProtocol {
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 @@ public class TestProtocol<C> extends TransportProtocol {
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 1ef3fbf627..5aae5ea21a 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 @@ import org.eclipse.jgit.lib.RefUpdate;
/** 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 @@ public class TrackingRefUpdate {
}
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 f4de82147d..f0c513427a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
@@ -72,13 +72,13 @@ public class TransferConfig {
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) {
+ 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$
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 218562254c..cc7db47df5 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.IOException;
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.Map;
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;
@@ -557,8 +561,13 @@ public abstract class Transport {
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));
@@ -761,6 +770,9 @@ public abstract class Transport {
/** Assists with authentication the connection. */
private CredentialsProvider credentialsProvider;
+ private PrintStream hookOutRedirect;
+
+ private PrePushHook prePush;
/**
* Create a new transport instance.
*
@@ -778,6 +790,7 @@ public abstract class Transport {
this.uri = uri;
this.objectChecker = tc.newObjectChecker();
this.credentialsProvider = CredentialsProvider.getDefault();
+ prePush = Hooks.prePush(local, hookOutRedirect);
}
/**
@@ -1196,6 +1209,15 @@ public abstract class Transport {
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);
}
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 745cdb72d5..7729c11ff9 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 @@ public class TransportAmazonS3 extends HttpTransport implements WalkTransport {
};
/** 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.
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 b23771e952..594827886b 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 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
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/WalkEncryption.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkEncryption.java
index e55b984380..fe03bdc867 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.IOException;
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 @@ abstract class WalkEncryption {
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 @@ abstract class WalkEncryption {
}
@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 @@ abstract class WalkEncryption {
}
}
- 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);
+ }
+
+ // 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);
+ }
+ }
+
+ // 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$
+ }
+
+ /**
+ * 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 {
+
+ static final String VERSION = "2"; //$NON-NLS-1$
+
+ static final String ALGORITHM = "PBEWithMD5AndDES"; //$NON-NLS-1$
+
+ 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 static byte[] salt = { (byte) 0xA4, (byte) 0x0B, (byte) 0xC8,
- (byte) 0x34, (byte) 0xD6, (byte) 0x95, (byte) 0xF3, (byte) 0x13 };
+ private final String cryptoAlg;
- private final String algorithmName;
+ private final SecretKey secretKey;
- private final SecretKey skey;
+ private final AlgorithmParameterSpec paramSpec;
- private final PBEParameterSpec aspec;
+ JetS3tV2(final String algo, final String key)
+ throws GeneralSecurityException {
+ cryptoAlg = algo;
- ObjectEncryptionV2(final String algo, final String key)
- throws InvalidKeySpecException, NoSuchAlgorithmException {
- algorithmName = 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();
- final PBEKeySpec s;
- s = new PBEKeySpec(key.toCharArray(), salt, ITERATION_COUNT, 32);
- skey = SecretKeyFactory.getInstance(algo).generateSecret(s);
- aspec = new PBEParameterSpec(salt, ITERATION_COUNT);
}
@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 @@ abstract class WalkEncryption {
@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) {
+ final Cipher cipher = Cipher.getInstance(cryptoAlg);
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
+ return new CipherInputStream(in, cipher);
+ } catch (GeneralSecurityException e) {
throw error(e);
- } catch (NoSuchPaddingException e) {
- throw error(e);
- } catch (InvalidKeyException 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);
- } catch (InvalidAlgorithmParameterException 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 dc9dee55a4..1c6b8b7363 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 @@ import org.eclipse.jgit.util.FileUtils;
*/
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 @@ class WalkFetchConnection extends BaseFetchConnection {
*/
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;
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 deecb8e15f..4eaf3f9d8a 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 @@ class WalkPushConnection extends BaseConnection implements PushConnection {
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/util/BlockList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/BlockList.java
index 0454e7e0d9..9d0ad736fa 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 @@ public class BlockList<T> extends AbstractList<T> {
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 @@ public class BlockList<T> extends AbstractList<T> {
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/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index e5219b2a92..e407dd8be9 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.text.MessageFormat;
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,7 +110,7 @@ public abstract class FS {
}
}
- private final static Logger LOG = LoggerFactory.getLogger(FS.class);
+ final static Logger LOG = LoggerFactory.getLogger(FS.class);
/** The auto-detected implementation selected for this operating system and JRE. */
public static final FS DETECTED = detect();
@@ -404,8 +404,10 @@ public abstract class FS {
* 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 +424,11 @@ public abstract class FS {
* @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 +442,30 @@ public abstract class FS {
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 +475,7 @@ public abstract class FS {
}
}
} 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 +487,39 @@ public abstract class FS {
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 +541,14 @@ public abstract class FS {
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 +864,88 @@ public abstract class FS {
* 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. If binary is set to <code>false</code>
+ * then it is expected that the process emits text data which
+ * should be processed line by line.
+ * @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. If binary is set to
+ * <code>false</code> then it is expected that the process
+ * expects text data which should be processed line by line.
+ * @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;
@@ -1194,30 +1223,27 @@ public abstract class FS {
* </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/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
index 548d239c8d..6d0318c029 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -399,20 +399,25 @@ public class FileUtils {
*
* @param path
* @param target
+ * @return path to the created 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);
+ if (Files.isRegularFile(nioPath)) {
+ 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 +735,29 @@ public class FileUtils {
}
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/RefList.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefList.java
index 4695111de9..0853e95366 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 @@ public class RefList<T extends Ref> implements Iterable<Ref> {
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 5cc7e92c52..c72727b542 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 @@ public class RefMap extends AbstractMap<String, Ref> {
* 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 @@ public class RefMap extends AbstractMap<String, Ref> {
* 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 @@ public class RefMap extends AbstractMap<String, Ref> {
* 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 @@ public class RefMap extends AbstractMap<String, Ref> {
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/TemporaryBuffer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
index e2738c03f9..ca47f50fd9 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 @@ public abstract class TemporaryBuffer extends OutputStream {
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.
diff --git a/pom.xml b/pom.xml
index 760d66fdbd..6b41708354 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-SNAPSHOT</version>
+ <version>4.2.0-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>