diff options
396 files changed, 13691 insertions, 7636 deletions
diff --git a/Documentation/technical/reftable.md b/Documentation/technical/reftable.md index 47c61a350d..1236a79098 100644 --- a/Documentation/technical/reftable.md +++ b/Documentation/technical/reftable.md @@ -89,6 +89,10 @@ Reference names are an uninterpreted sequence of bytes that must pass [ref-fmt]: https://git-scm.com/docs/git-check-ref-format +### Key unicity + +Each entry must have a unique key; repeated keys are disallowed. + ### Network byte order All multi-byte, fixed width fields are in network byte order. @@ -566,6 +570,10 @@ supplied for the update. [update-ref]: https://git-scm.com/docs/git-update-ref#_logging_updates +Contrary to traditional reflog (which is a file), renames are encoded as a +combination of ref deletion and ref creation. + + #### Reading the log Readers accessing the log must first read the footer (below) to @@ -771,12 +779,12 @@ directory. This prevents loose references from being stored. A collection of reftable files are stored in the `$GIT_DIR/reftable/` directory: - 00000001.log - 00000001.ref - 00000002.ref + 00000001-00000001.log + 00000002-00000002.ref + 00000003-00000003.ref where reftable files are named by a unique name such as produced by -the function `${update_index}.ref`. +the function `${min_update_index}-${max_update_index}.ref`. Log-only files use the `.log` extension, while ref-only and mixed ref and log files use `.ref`. extension. @@ -786,9 +794,9 @@ files, one per line, in order, from oldest (base) to newest (most recent): $ cat .git/refs - 00000001.log - 00000001.ref - 00000002.ref + 00000001-00000001.log + 00000002-00000002.ref + 00000003-00000003.ref Readers must read `$GIT_DIR/refs` to determine which files are relevant right now, and search through the stack in reverse order @@ -815,8 +823,8 @@ new reftable and atomically appending it to the stack: 1. Acquire `refs.lock`. 2. Read `refs` to determine current reftables. 3. Select `update_index` to be most recent file's `max_update_index + 1`. -4. Prepare temp reftable `${update_index}_XXXXXX`, including log entries. -5. Rename `${update_index}_XXXXXX` to `${update_index}.ref`. +4. Prepare temp reftable `tmp_XXXXXX`, including log entries. +5. Rename `tmp_XXXXXX` to `${update_index}-${update_index}.ref`. 6. Copy `refs` to `refs.lock`, appending file from (5). 7. Rename `refs.lock` to `refs`. @@ -861,12 +869,13 @@ is going to compact B and C, leaving A and D alone. Ownership of these locks prevents other processes from trying to compact these files. 3. Release `refs.lock`. -4. Compact `B` and `C` into a temp file `${min_update_index}_XXXXXX`. +4. Compact `B` and `C` into a temp file `${min_update_index}-${max_update_index}_XXXXXX`. 5. Reacquire lock `refs.lock`. 6. Verify that `B` and `C` are still in the stack, in that order. This should always be the case, assuming that other processes are adhering to the locking protocol. -7. Rename `${min_update_index}_XXXXXX` to `${min_update_index}_2.ref`. +7. Rename `${min_update_index}-${max_update_index}_XXXXXX` to + `${min_update_index}-${max_update_index}.ref`. 8. Write the new stack to `refs.lock`, replacing `B` and `C` with the file from (4). 9. Rename `refs.lock` to `refs`. @@ -875,6 +884,9 @@ is going to compact B and C, leaving A and D alone. This strategy permits compactions to proceed independently of updates. +Each reftable (compacted or not) is uniquely identified by its name, so open +reftables can be cached by their name. + ## Alternatives considered ### bzip packed-refs @@ -9,9 +9,14 @@ http_archive( urls = ["https://github.com/bazelbuild/bazel-skylib/archive/0.8.0.tar.gz"], ) -load("@bazel_skylib//lib:versions.bzl", "versions") +# Check Bazel version when invoked by Bazel directly +load("//tools:bazelisk_version.bzl", "bazelisk_version") -versions.check(minimum_bazel_version = "0.29.0") +bazelisk_version(name = "bazelisk_version") + +load("@bazelisk_version//:check.bzl", "check_bazel_version") + +check_bazel_version() load("//tools:bazlets.bzl", "load_bazlets") @@ -125,7 +130,7 @@ maven_jar( ) maven_jar( - name = "servlet-api-3_1", + name = "servlet-api", artifact = "javax.servlet:javax.servlet-api:3.1.0", sha1 = "3cd63d075497751784b2fa84be59432f4905bf7c", ) @@ -198,69 +203,69 @@ maven_jar( sha1 = "3edcfe49d2c6053a70a2a47e4e1c2f94998a49cf", ) -JETTY_VER = "9.4.20.v20190813" +JETTY_VER = "9.4.22.v20191022" maven_jar( name = "jetty-servlet", artifact = "org.eclipse.jetty:jetty-servlet:" + JETTY_VER, - sha1 = "d5d6610321bd173aead473e994f170989d633b25", - src_sha1 = "09aa4fce2579d0905e3bde0b3bc923a032394805", + sha1 = "62285df7713347586d55f3f93a96299d1b721714", + src_sha1 = "fe2d1f1dc7a82ced141df935a0db5b5cadd76f4a", ) maven_jar( name = "jetty-security", artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VER, - sha1 = "300c2e6dd62291c512bdaf3ecfefc1e305e26088", - src_sha1 = "ec03ce3b6a8c0c3dd2bd8b32bc51419caa10ad62", + sha1 = "f7b3b61f09b34a69fd6df4f267f3907813c9224c", + src_sha1 = "5a1b33c5dde638ce9dbc2e07f0cff862e5029195", ) maven_jar( name = "jetty-server", artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VER, - sha1 = "d4ee11134bca83db85919a1710fce022c67df3b7", - src_sha1 = "0db81f86709a8184c793acd309c27dccdb5d439c", + sha1 = "f30b9b2cd6f63b073b63c2ac5e7e7f17b63b0908", + src_sha1 = "97fbdf8eade55f05d7e99c16fd90d394b248f717", ) maven_jar( name = "jetty-http", artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VER, - sha1 = "edda2fd904a881114aba79e2f881c6f4004e8148", - src_sha1 = "3e187c60d578c529f4baa3bbfc727d4b7ca7b93c", + sha1 = "f96f87fc73c2b586ff40689cbce6ae62d70f18fa", + src_sha1 = "0e51a30d0e3309acfc6ee548b90ff55165fbfa5c", ) maven_jar( name = "jetty-io", artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VER, - sha1 = "b246c5e350d0aa1b310c07ec362755c34a1cc8cb", - src_sha1 = "d12619b4df0d202847096a8429b0f96f123c7c77", + sha1 = "0f08e62908f94d1238be386302236a42204d566a", + src_sha1 = "d31c00383f13c95404ef606f57513569868acd6b", ) maven_jar( name = "jetty-util", artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VER, - sha1 = "8ee753d673a124ba2880361871ab13f6863b2d40", - src_sha1 = "2827925d01d95f42d02adf177d2474fbc8a3d5e0", + sha1 = "ffe0bf81a2a4a534b79dd981f971c7346a563095", + src_sha1 = "42f8abc84a6c4c9d2441d2dfcc60591e3296dc26", ) -BOUNCYCASTLE_VER = "1.61" +BOUNCYCASTLE_VER = "1.64" maven_jar( name = "bcpg", artifact = "org.bouncycastle:bcpg-jdk15on:" + BOUNCYCASTLE_VER, - sha1 = "422656435514ab8a28752b117d5d2646660a0ace", - src_sha1 = "836da34e11114cbce8fa99f54175f8f3278d1cce", + sha1 = "56956a8c63ccadf62e7c678571cf86f30bd84441", + src_sha1 = "b241337df9516b35637d9be84451e2f03a81d186", ) maven_jar( name = "bcprov", artifact = "org.bouncycastle:bcprov-jdk15on:" + BOUNCYCASTLE_VER, - sha1 = "00df4b474e71be02c1349c3292d98886f888d1f7", - src_sha1 = "3bf88046a16098ea6cc41576dd50d512854d39e1", + sha1 = "1467dac1b787b5ad2a18201c0c281df69882259e", + src_sha1 = "2881bfaf2c15e9e64b62c2a143db90db7a0d6035", ) maven_jar( name = "bcpkix", artifact = "org.bouncycastle:bcpkix-jdk15on:" + BOUNCYCASTLE_VER, - sha1 = "89bb3aa5b98b48e584eee2a7401b7682a46779b4", - src_sha1 = "a0498d09200a18737eccc05aa81bbd05c1be0f8c", + sha1 = "3dac163e20110817d850d17e0444852a6d7d0bd7", + src_sha1 = "5c87199786c06e1a53adf16b1998386bad52da89", ) @@ -224,7 +224,7 @@ java_library( "//org.eclipse.jgit.lfs.server.test:__pkg__", "//org.eclipse.jgit.pgm:__pkg__", ], - exports = ["@servlet-api-3_1//jar"], + exports = ["@servlet-api//jar"], ) java_library( diff --git a/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs index 2ca78ff2d0..3dd5840397 100644 --- a/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.ant.test/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF index 74ed2712ae..8b25269460 100644 --- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF @@ -5,13 +5,13 @@ Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ant.test Bundle-SymbolicName: org.eclipse.jgit.ant.test Bundle-Vendor: %Bundle-Vendor -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: org.apache.tools.ant, - org.eclipse.jgit.ant.tasks;version="[5.5.2,5.6.0)", - org.eclipse.jgit.junit;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", + org.eclipse.jgit.ant.tasks;version="[5.6.1,5.7.0)", + org.eclipse.jgit.junit;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)", org.hamcrest.core;version="[1.1.0,2.0.0)", org.junit;version="[4.12,5.0.0)" diff --git a/org.eclipse.jgit.ant.test/pom.xml b/org.eclipse.jgit.ant.test/pom.xml index a5d6304288..0551d02333 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ant.test</artifactId> diff --git a/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs index 94a1c4f10b..4335e66bf0 100644 --- a/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.ant/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning diff --git a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF index fac3286de1..f599b80003 100644 --- a/org.eclipse.jgit.ant/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant/META-INF/MANIFEST.MF @@ -3,13 +3,13 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ant Bundle-SymbolicName: org.eclipse.jgit.ant -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: org.apache.tools.ant, - org.eclipse.jgit.storage.file;version="[5.5.2,5.6.0)" + org.eclipse.jgit.storage.file;version="[5.6.1,5.7.0)" Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.ant;version="5.5.2", - org.eclipse.jgit.ant.tasks;version="5.5.2"; +Export-Package: org.eclipse.jgit.ant;version="5.6.1", + org.eclipse.jgit.ant.tasks;version="5.6.1"; uses:="org.apache.tools.ant, org.apache.tools.ant.types" diff --git a/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF index a1ba9cebec..7ae660af93 100644 --- a/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ant/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.ant - Sources Bundle-SymbolicName: org.eclipse.jgit.ant.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ant;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ant;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit.ant/pom.xml b/org.eclipse.jgit.ant/pom.xml index 1c1c494c26..0a309101b0 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ant</artifactId> @@ -71,7 +71,7 @@ <dependency> <groupId>org.apache.ant</groupId> <artifactId>ant</artifactId> - <version>1.10.5</version> + <version>1.10.7</version> </dependency> </dependencies> 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 ef6f5e732f..bc7ba1e50e 100644 --- a/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.archive/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning diff --git a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF index 14167a64a3..71e5e2ad1e 100644 --- a/org.eclipse.jgit.archive/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.archive/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.archive Bundle-SymbolicName: org.eclipse.jgit.archive -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-1.8 @@ -13,17 +13,17 @@ 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="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.nls;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", + org.eclipse.jgit.api;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.nls;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.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="5.5.2"; +Export-Package: org.eclipse.jgit.archive;version="5.6.1"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.api, org.apache.commons.compress.archivers, org.osgi.framework", - org.eclipse.jgit.archive.internal;version="5.5.2";x-internal:=true + org.eclipse.jgit.archive.internal;version="5.6.1";x-internal:=true diff --git a/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.archive/META-INF/SOURCE-MANIFEST.MF index 21facee5f0..facf5245b0 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: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.archive;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.archive;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit.archive/pom.xml b/org.eclipse.jgit.archive/pom.xml index 61d25a605a..4624634d54 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.archive</artifactId> diff --git a/org.eclipse.jgit.benchmarks/pom.xml b/org.eclipse.jgit.benchmarks/pom.xml index 0aade5203b..0bb5b84eb7 100644 --- a/org.eclipse.jgit.benchmarks/pom.xml +++ b/org.eclipse.jgit.benchmarks/pom.xml @@ -47,7 +47,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.eclipse.jgit</groupId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> <artifactId>org.eclipse.jgit.benchmarks</artifactId> <packaging>jar</packaging> @@ -131,6 +131,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> + <version>3.2.1</version> <executions> <execution> <phase>package</phase> diff --git a/org.eclipse.jgit.coverage/pom.xml b/org.eclipse.jgit.coverage/pom.xml index be76c03d8a..35f1e13c37 100644 --- a/org.eclipse.jgit.coverage/pom.xml +++ b/org.eclipse.jgit.coverage/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -18,88 +18,88 @@ <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ant</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.archive</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.http.apache</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.http.server</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.lfs</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.lfs.server</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.pgm</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ui</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ssh.apache</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.test</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ant.test</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.http.test</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.pgm.test</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.lfs.test</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.lfs.server.test</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> </dependencies> diff --git a/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs index 94a1c4f10b..4335e66bf0 100644 --- a/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.http.apache/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning diff --git a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF index 84da9f8cb8..f91a230c8f 100644 --- a/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.apache/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.http.apache Bundle-SymbolicName: org.eclipse.jgit.http.apache -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor @@ -23,11 +23,11 @@ Import-Package: org.apache.http;version="[4.3.0,5.0.0)", org.apache.http.impl.client;version="[4.3.0,5.0.0)", org.apache.http.impl.conn;version="[4.3.0,5.0.0)", org.apache.http.params;version="[4.3.0,5.0.0)", - org.eclipse.jgit.annotations;version="[5.5.2,5.6.0)", - org.eclipse.jgit.nls;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.http;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)" -Export-Package: org.eclipse.jgit.transport.http.apache;version="5.5.2"; + org.eclipse.jgit.annotations;version="[5.6.1,5.7.0)", + org.eclipse.jgit.nls;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.http;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)" +Export-Package: org.eclipse.jgit.transport.http.apache;version="5.6.1"; uses:="org.apache.http.client, org.eclipse.jgit.transport.http, org.apache.http.entity, diff --git a/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF index 3666a28d00..5efd836d3a 100644 --- a/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.http.apache/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.http.apache - Sources Bundle-SymbolicName: org.eclipse.jgit.http.apache.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.http.apache;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit.http.apache/pom.xml b/org.eclipse.jgit.http.apache/pom.xml index a8f55769d6..b1cf0f7d27 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.http.apache</artifactId> diff --git a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java index f92c5df792..9d9e2f882d 100644 --- a/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java +++ b/org.eclipse.jgit.http.apache/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java @@ -92,6 +92,7 @@ import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.client.SystemDefaultCredentialsProvider; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.transport.http.HttpConnection; @@ -165,6 +166,8 @@ public class HttpClientConnection implements HttpConnection { new BasicHttpClientConnectionManager(registry)); } clientBuilder.setDefaultRequestConfig(configBuilder.build()); + clientBuilder.setDefaultCredentialsProvider( + new SystemDefaultCredentialsProvider()); client = clientBuilder.build(); } diff --git a/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs index 94a1c4f10b..4335e66bf0 100644 --- a/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.http.server/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning diff --git a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF index 8d71a4de47..d0a9ee2376 100644 --- a/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.server/META-INF/MANIFEST.MF @@ -3,13 +3,13 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.http.server Bundle-SymbolicName: org.eclipse.jgit.http.server -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.http.server;version="5.5.2", - org.eclipse.jgit.http.server.glue;version="5.5.2"; +Export-Package: org.eclipse.jgit.http.server;version="5.6.1", + org.eclipse.jgit.http.server.glue;version="5.6.1"; uses:="javax.servlet,javax.servlet.http", - org.eclipse.jgit.http.server.resolver;version="5.5.2"; + org.eclipse.jgit.http.server.resolver;version="5.6.1"; uses:="org.eclipse.jgit.transport.resolver, org.eclipse.jgit.lib, org.eclipse.jgit.transport, @@ -18,13 +18,14 @@ Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.8 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="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.dfs;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.transport.parser;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.nls;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.resolver;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)" + org.eclipse.jgit.annotations;version="[5.6.1,5.7.0)", + org.eclipse.jgit.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.dfs;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.transport.parser;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.nls;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.resolver;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)" diff --git a/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF index 39c887719d..11e46e3351 100644 --- a/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.http.server/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.http.server - Sources Bundle-SymbolicName: org.eclipse.jgit.http.server.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.http.server;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit.http.server/pom.xml b/org.eclipse.jgit.http.server/pom.xml index 2d4f758497..902a22b53c 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.http.server</artifactId> diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java index 1c5e7ec598..e9462eeb4c 100644 --- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java @@ -92,6 +92,8 @@ public class GitFilter extends MetaFilter { private UploadPackFactory<HttpServletRequest> uploadPackFactory = new DefaultUploadPackFactory(); + private UploadPackErrorHandler uploadPackErrorHandler; + private ReceivePackFactory<HttpServletRequest> receivePackFactory = new DefaultReceivePackFactory(); private final List<Filter> uploadPackFilters = new LinkedList<>(); @@ -150,6 +152,17 @@ public class GitFilter extends MetaFilter { } /** + * Set a custom error handler for git-upload-pack. + * + * @param h + * A custom error handler for git-upload-pack. + */ + public void setUploadPackErrorHandler(UploadPackErrorHandler h) { + assertNotInitialized(); + this.uploadPackErrorHandler = h; + } + + /** * Add upload-pack filter * * @param filter @@ -212,7 +225,7 @@ public class GitFilter extends MetaFilter { b = b.through(new UploadPackServlet.Factory(uploadPackFactory)); for (Filter f : uploadPackFilters) b = b.through(f); - b.with(new UploadPackServlet()); + b.with(new UploadPackServlet(uploadPackErrorHandler)); } if (receivePackFactory != ReceivePackFactory.DISABLED) { diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackErrorHandler.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackErrorHandler.java new file mode 100644 index 0000000000..03be0873b0 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackErrorHandler.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019, Google LLC and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.http.server; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jgit.transport.ServiceMayNotContinueException; +import org.eclipse.jgit.transport.UploadPack; + +/** + * Handle git-upload-pack errors. + * + * <p> + * This is an entry point for customizing an error handler for git-upload-pack. + * Right before calling {@link UploadPack#uploadWithExceptionPropagation}, JGit + * will call this handler if specified through {@link GitFilter}. The + * implementation of this handler is responsible for calling + * {@link UploadPackRunnable} and handling exceptions for clients. + * + * <p> + * If a custom handler is not specified, JGit will use the default error + * handler. + * + * @since 5.6 + */ +public interface UploadPackErrorHandler { + /** + * @param req + * The HTTP request + * @param rsp + * The HTTP response + * @param r + * A continuation that handles a git-upload-pack request. + * @throws IOException + */ + void upload(HttpServletRequest req, HttpServletResponse rsp, + UploadPackRunnable r) throws IOException; + + /** Process a git-upload-pack request. */ + public interface UploadPackRunnable { + /** + * See {@link UploadPack#uploadWithExceptionPropagation}. + * + * @throws ServiceMayNotContinueException + * @throws IOException + */ + void upload() throws ServiceMayNotContinueException, IOException; + } +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java index 0f4037144a..54561e0cfc 100644 --- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java @@ -70,7 +70,8 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - +import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.http.server.UploadPackErrorHandler.UploadPackRunnable; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.InternalHttpServerGlue; import org.eclipse.jgit.transport.PacketLineOut; @@ -181,53 +182,71 @@ class UploadPackServlet extends HttpServlet { } } + private final UploadPackErrorHandler handler; + + UploadPackServlet(@Nullable UploadPackErrorHandler handler) { + this.handler = handler != null ? handler + : this::defaultUploadPackHandler; + } + /** {@inheritDoc} */ @Override - public void doPost(final HttpServletRequest req, - final HttpServletResponse rsp) throws IOException { + public void doPost(HttpServletRequest req, HttpServletResponse rsp) + throws IOException { if (!UPLOAD_PACK_REQUEST_TYPE.equals(req.getContentType())) { rsp.sendError(SC_UNSUPPORTED_MEDIA_TYPE); return; } - SmartOutputStream out = new SmartOutputStream(req, rsp, false) { - @Override - public void flush() throws IOException { - doFlush(); - } - }; + UploadPackRunnable r = () -> { + UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER); + @SuppressWarnings("resource") + SmartOutputStream out = new SmartOutputStream(req, rsp, false) { + @Override + public void flush() throws IOException { + doFlush(); + } + }; - UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER); - try { up.setBiDirectionalPipe(false); rsp.setContentType(UPLOAD_PACK_RESULT_TYPE); - up.upload(getInputStream(req), out, null); - out.close(); - - } catch (ServiceMayNotContinueException e) { - if (e.isOutput()) { + try { + up.upload(getInputStream(req), out, null); + out.close(); + } catch (ServiceMayNotContinueException e) { + if (e.isOutput()) { + consumeRequestBody(req); + out.close(); + } + throw e; + } catch (UploadPackInternalServerErrorException e) { + // Special case exception, error message was sent to client. + log(up.getRepository(), e.getCause()); consumeRequestBody(req); out.close(); - } else if (!rsp.isCommitted()) { - rsp.reset(); - sendError(req, rsp, e.getStatusCode(), e.getMessage()); } - return; + }; - } catch (UploadPackInternalServerErrorException e) { - // Special case exception, error message was sent to client. - log(up.getRepository(), e.getCause()); - consumeRequestBody(req); - out.close(); + handler.upload(req, rsp, r); + } + private void defaultUploadPackHandler(HttpServletRequest req, + HttpServletResponse rsp, UploadPackRunnable r) throws IOException { + try { + r.upload(); + } catch (ServiceMayNotContinueException e) { + if (!e.isOutput() && !rsp.isCommitted()) { + rsp.reset(); + sendError(req, rsp, e.getStatusCode(), e.getMessage()); + } } catch (Throwable e) { + UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER); log(up.getRepository(), e); if (!rsp.isCommitted()) { rsp.reset(); sendError(req, rsp, SC_INTERNAL_SERVER_ERROR); } - return; } } diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinderImpl.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinderImpl.java index f16749775f..574e94a892 100644 --- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinderImpl.java +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/glue/ServletBinderImpl.java @@ -86,10 +86,10 @@ abstract class ServletBinderImpl implements ServletBinder { * @return the configured servlet, or singleton returning 404 if none. */ protected HttpServlet getServlet() { - if (httpServlet != null) + if (httpServlet != null) { return httpServlet; - else - return new ErrorServlet(HttpServletResponse.SC_NOT_FOUND); + } + return new ErrorServlet(HttpServletResponse.SC_NOT_FOUND); } /** diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultUploadPackFactory.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultUploadPackFactory.java index a69fab0afd..b9e6882556 100644 --- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultUploadPackFactory.java +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/DefaultUploadPackFactory.java @@ -83,8 +83,7 @@ public class DefaultUploadPackFactory implements up.setExtraParameters(Arrays.asList(params)); } return up; - } else { - throw new ServiceNotEnabledException(); } + throw new ServiceNotEnabledException(); } } diff --git a/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs index 2ca78ff2d0..3dd5840397 100644 --- a/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.http.test/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF index cec2a09c08..2a740d493f 100644 --- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.http.test Bundle-SymbolicName: org.eclipse.jgit.http.test -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-1.8 @@ -28,25 +28,25 @@ Import-Package: javax.servlet;version="[2.5.0,3.2.0)", org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)", org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)", org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)", - org.eclipse.jgit.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.http.server;version="[5.5.2,5.6.0)", - org.eclipse.jgit.http.server.glue;version="[5.5.2,5.6.0)", - org.eclipse.jgit.http.server.resolver;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.dfs;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.reftable;version="[5.5.2,5.6.0)", - org.eclipse.jgit.junit;version="[5.5.2,5.6.0)", - org.eclipse.jgit.junit.http;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.nls;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.http;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.http.apache;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.resolver;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", + org.eclipse.jgit.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.http.server;version="[5.6.1,5.7.0)", + org.eclipse.jgit.http.server.glue;version="[5.6.1,5.7.0)", + org.eclipse.jgit.http.server.resolver;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.dfs;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.reftable;version="[5.6.1,5.7.0)", + org.eclipse.jgit.junit;version="[5.6.1,5.7.0)", + org.eclipse.jgit.junit.http;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.nls;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.http;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.http.apache;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.resolver;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)", org.hamcrest;version="[1.1.0,2.0.0)", org.hamcrest.core;version="[1.1.0,2.0.0)", org.junit;version="[4.12,5.0.0)", diff --git a/org.eclipse.jgit.http.test/pom.xml b/org.eclipse.jgit.http.test/pom.xml index 5ab6a7e143..1c5069c5e6 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.http.test</artifactId> diff --git a/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/RefsUnreadableInMemoryRepository.java b/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/RefsUnreadableInMemoryRepository.java index 78f909eeac..6f85979785 100644 --- a/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/RefsUnreadableInMemoryRepository.java +++ b/org.eclipse.jgit.http.test/src/org/eclipse/jgit/http/test/RefsUnreadableInMemoryRepository.java @@ -43,10 +43,14 @@ package org.eclipse.jgit.http.test; import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; -import org.eclipse.jgit.internal.storage.reftable.Reftable; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefDatabase; /** @@ -82,12 +86,43 @@ class RefsUnreadableInMemoryRepository extends InMemoryRepository { } private class RefsUnreadableRefDatabase extends MemRefDatabase { + + /** {@inheritDoc} */ + @Override + public Ref exactRef(String name) throws IOException { + if (failing) { + throw new IOException("disk failed, no refs found"); + } + return super.exactRef(name); + } + + /** {@inheritDoc} */ + @Override + public Map<String, Ref> getRefs(String prefix) throws IOException { + if (failing) { + throw new IOException("disk failed, no refs found"); + } + + return super.getRefs(prefix); + } + + /** {@inheritDoc} */ + @Override + public List<Ref> getRefsByPrefix(String prefix) throws IOException { + if (failing) { + throw new IOException("disk failed, no refs found"); + } + + return super.getRefsByPrefix(prefix); + } + + /** {@inheritDoc} */ @Override - protected Reftable reader() throws IOException { + public Set<Ref> getTipsWithSha1(ObjectId id) throws IOException { if (failing) { throw new IOException("disk failed, no refs found"); } - return super.reader(); + return super.getTipsWithSha1(id); } } } diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java index 3401e264c0..99aa06b17c 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java @@ -331,9 +331,8 @@ public class SmartClientSmartServerTest extends AllFactoriesHttpTestCase { String fragment = u.getRawFragment(); if (fragment != null) { return u.getRawPath() + '#' + fragment; - } else { - return u.getRawPath(); } + return u.getRawPath(); } catch (URISyntaxException e) { return url; } diff --git a/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs index 2ca78ff2d0..3dd5840397 100644 --- a/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.junit.http/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF index a7254a3b62..3f8d93d537 100644 --- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.junit.http Bundle-SymbolicName: org.eclipse.jgit.junit.http -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy @@ -22,16 +22,16 @@ Import-Package: javax.servlet;version="[2.5.0,3.2.0)", org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)", org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)", org.eclipse.jetty.util.ssl;version="[9.4.5,10.0.0)", - org.eclipse.jgit.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.http.server;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.junit;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.resolver;version="[5.5.2,5.6.0)", + org.eclipse.jgit.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.http.server;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.junit;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.resolver;version="[5.6.1,5.7.0)", org.junit;version="[4.12,5.0.0)" -Export-Package: org.eclipse.jgit.junit.http;version="5.5.2"; +Export-Package: org.eclipse.jgit.junit.http;version="5.6.1"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.junit, javax.servlet.http, diff --git a/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF index 6f5590bcac..47641db404 100644 --- a/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.junit.http/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.junit.http - Sources Bundle-SymbolicName: org.eclipse.jgit.junit.http.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.junit.http;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit.junit.http/pom.xml b/org.eclipse.jgit.junit.http/pom.xml index e4b2c6be37..440c5de8f2 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.junit.http</artifactId> diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java index 9aef086b78..33cbd2b595 100644 --- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java +++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java @@ -205,7 +205,7 @@ public class AppServer { } private SslContextFactory createTestSslContextFactory(String hostName) { - SslContextFactory factory = new SslContextFactory(true); + SslContextFactory.Client factory = new SslContextFactory.Client(true); String dName = "CN=,OU=,O=,ST=,L=,C="; @@ -308,10 +308,10 @@ public class AppServer { @Override protected String[] loadRoleInfo(UserPrincipal user) { - if (users.get(user.getName()) == null) + if (users.get(user.getName()) == null) { return null; - else - return new String[] { role }; + } + return new String[] { role }; } @Override diff --git a/org.eclipse.jgit.junit.ssh/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.junit.ssh/.settings/org.eclipse.jdt.core.prefs index 2ca78ff2d0..3dd5840397 100644 --- a/org.eclipse.jgit.junit.ssh/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.junit.ssh/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error diff --git a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF index ff2edd3730..1ad0d75ffa 100644 --- a/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit.ssh/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.junit.ssh Bundle-SymbolicName: org.eclipse.jgit.junit.ssh -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy @@ -30,8 +30,8 @@ Import-Package: org.apache.sshd.common;version="[2.2.0,2.3.0)", org.apache.sshd.server.shell;version="[2.2.0,2.3.0)", org.apache.sshd.server.subsystem;version="[2.2.0,2.3.0)", org.apache.sshd.server.subsystem.sftp;version="[2.2.0,2.3.0)", - org.eclipse.jgit.annotations;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="[5.5.2,5.6.0)", + org.eclipse.jgit.annotations;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="[5.6.1,5.7.0)", org.slf4j;version="[1.7.0,2.0.0)" -Export-Package: org.eclipse.jgit.junit.ssh;version="5.5.2" +Export-Package: org.eclipse.jgit.junit.ssh;version="5.6.1" diff --git a/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF index c828888b57..c078cdcb43 100644 --- a/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.junit.ssh/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.junit.ssh - Sources Bundle-SymbolicName: org.eclipse.jgit.junit.ssh.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.junit.ssh;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit.junit.ssh/pom.xml b/org.eclipse.jgit.junit.ssh/pom.xml index 3b28c00bae..60f5b263ff 100644 --- a/org.eclipse.jgit.junit.ssh/pom.xml +++ b/org.eclipse.jgit.junit.ssh/pom.xml @@ -50,7 +50,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.junit.ssh</artifactId> diff --git a/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs index b6750293dc..530f8f6070 100644 --- a/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.junit/.settings/org.eclipse.jdt.core.prefs @@ -103,7 +103,7 @@ org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning diff --git a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF index 4de3e46fdb..807a55659a 100644 --- a/org.eclipse.jgit.junit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit/META-INF/MANIFEST.MF @@ -3,35 +3,35 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.junit Bundle-SymbolicName: org.eclipse.jgit.junit -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.8 -Import-Package: org.eclipse.jgit.annotations;version="[5.5.2,5.6.0)", - org.eclipse.jgit.api;version="[5.5.2,5.6.0)", - org.eclipse.jgit.api.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.dircache;version="[5.5.2,5.6.0)", - org.eclipse.jgit.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.pack;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.merge;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="5.5.2", - org.eclipse.jgit.treewalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.treewalk.filter;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util.io;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util.time;version="[5.5.2,5.6.0)", +Import-Package: org.eclipse.jgit.annotations;version="[5.6.1,5.7.0)", + org.eclipse.jgit.api;version="[5.6.1,5.7.0)", + org.eclipse.jgit.api.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.dircache;version="[5.6.1,5.7.0)", + org.eclipse.jgit.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.pack;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.merge;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="5.6.1", + org.eclipse.jgit.treewalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.treewalk.filter;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util.io;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util.time;version="[5.6.1,5.7.0)", org.junit;version="[4.12,5.0.0)", org.junit.rules;version="[4.12,5.0.0)", org.junit.runner;version="[4.12,5.0.0)", org.junit.runners;version="[4.12,5.0.0)", org.junit.runners.model;version="[4.12,5.0.0)", org.slf4j;version="[1.7.0,2.0.0)" -Export-Package: org.eclipse.jgit.junit;version="5.5.2"; +Export-Package: org.eclipse.jgit.junit;version="5.6.1"; uses:="org.eclipse.jgit.dircache, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, @@ -44,4 +44,4 @@ Export-Package: org.eclipse.jgit.junit;version="5.5.2"; org.junit.runners.model, org.junit.runner, org.eclipse.jgit.util.time", - org.eclipse.jgit.junit.time;version="5.5.2";uses:="org.eclipse.jgit.util.time" + org.eclipse.jgit.junit.time;version="5.6.1";uses:="org.eclipse.jgit.util.time" diff --git a/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF index 9568f93759..3f88869304 100644 --- a/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.junit/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.junit - Sources Bundle-SymbolicName: org.eclipse.jgit.junit.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.junit;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.junit;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit.junit/pom.xml b/org.eclipse.jgit.junit/pom.xml index 1ccc2202d2..8ce04e5a35 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.junit</artifactId> 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 362007a982..240c4429eb 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 @@ -782,9 +782,8 @@ public class TestRepository<R extends Repository> implements AutoCloseable { } update(Constants.HEAD, result); return pool.parseCommit(result); - } else { - throw new IOException("Merge conflict"); } + throw new IOException("Merge conflict"); } /** diff --git a/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs index 2ca78ff2d0..3dd5840397 100644 --- a/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.lfs.server.test/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error diff --git a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF index bcd5cf02f5..163ff4b6d9 100644 --- a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs.server.test Bundle-SymbolicName: org.eclipse.jgit.lfs.server.test -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-1.8 @@ -28,24 +28,24 @@ Import-Package: javax.servlet;version="[3.1.0,4.0.0)", org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)", org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)", org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)", - org.eclipse.jgit.api;version="[5.5.2,5.6.0)", - org.eclipse.jgit.api.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.junit;version="[5.5.2,5.6.0)", - org.eclipse.jgit.junit.http;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.server;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.server.fs;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.test;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="[5.5.2,5.6.0)", - org.eclipse.jgit.treewalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.treewalk.filter;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", + org.eclipse.jgit.api;version="[5.6.1,5.7.0)", + org.eclipse.jgit.api.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.junit;version="[5.6.1,5.7.0)", + org.eclipse.jgit.junit.http;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.server;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.server.fs;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.test;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="[5.6.1,5.7.0)", + org.eclipse.jgit.treewalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.treewalk.filter;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)", org.hamcrest.core;version="[1.1.0,2.0.0)", org.junit;version="[4.12,5.0.0)", org.junit.rules;version="[4.12,5.0.0)", diff --git a/org.eclipse.jgit.lfs.server.test/pom.xml b/org.eclipse.jgit.lfs.server.test/pom.xml index a116a6db48..acf88d8f76 100644 --- a/org.eclipse.jgit.lfs.server.test/pom.xml +++ b/org.eclipse.jgit.lfs.server.test/pom.xml @@ -50,7 +50,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.lfs.server.test</artifactId> diff --git a/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs index 525ac67142..9fd92b1098 100644 --- a/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.lfs.server/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning diff --git a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF index f519f26f7a..e51e56b7dd 100644 --- a/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server/META-INF/MANIFEST.MF @@ -3,19 +3,19 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs.server Bundle-SymbolicName: org.eclipse.jgit.lfs.server -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.lfs.server;version="5.5.2"; +Export-Package: org.eclipse.jgit.lfs.server;version="5.6.1"; uses:="javax.servlet.http, org.eclipse.jgit.lfs.lib", - org.eclipse.jgit.lfs.server.fs;version="5.5.2"; + org.eclipse.jgit.lfs.server.fs;version="5.6.1"; uses:="javax.servlet, javax.servlet.http, org.eclipse.jgit.lfs.server, org.eclipse.jgit.lfs.lib", - org.eclipse.jgit.lfs.server.internal;version="5.5.2";x-internal:=true, - org.eclipse.jgit.lfs.server.s3;version="5.5.2"; + org.eclipse.jgit.lfs.server.internal;version="5.6.1";x-internal:=true, + org.eclipse.jgit.lfs.server.s3;version="5.6.1"; uses:="org.eclipse.jgit.lfs.server, org.eclipse.jgit.lfs.lib" Bundle-RequiredExecutionEnvironment: JavaSE-1.8 @@ -25,15 +25,15 @@ Import-Package: com.google.gson;version="[2.8.0,3.0.0)", javax.servlet.http;version="[3.1.0,4.0.0)", org.apache.http;version="[4.3.0,5.0.0)", org.apache.http.client;version="[4.3.0,5.0.0)", - org.eclipse.jgit.annotations;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.internal;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.nls;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.http;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.http.apache;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", + org.eclipse.jgit.annotations;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.internal;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.nls;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.http;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.http.apache;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)", org.slf4j;version="[1.7.0,2.0.0)" diff --git a/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF index 55cdc0bff6..b97d9e3c65 100644 --- a/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.lfs.server - Sources Bundle-SymbolicName: org.eclipse.jgit.lfs.server.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.lfs.server;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit.lfs.server/pom.xml b/org.eclipse.jgit.lfs.server/pom.xml index 01a0b8d5c0..0336332207 100644 --- a/org.eclipse.jgit.lfs.server/pom.xml +++ b/org.eclipse.jgit.lfs.server/pom.xml @@ -50,7 +50,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.lfs.server</artifactId> diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java index 0a7c37ca55..ad9ef78036 100644 --- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java @@ -110,9 +110,8 @@ public class FileLfsRepository implements LargeFileRepository { Path p = getPath(id); if (Files.exists(p)) { return Files.size(p); - } else { - return -1; } + return -1; } /** diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/SignerV4.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/SignerV4.java index 7b76cecf0c..4bcca4a9a1 100644 --- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/SignerV4.java +++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/s3/SignerV4.java @@ -352,9 +352,8 @@ class SignerV4 { String encodedPath = urlEncode(path, true); if (encodedPath.startsWith("/")) { //$NON-NLS-1$ return encodedPath; - } else { - return "/" + encodedPath; //$NON-NLS-1$ } + return "/" + encodedPath; //$NON-NLS-1$ } private static byte[] hash(String s) { diff --git a/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs index 2ca78ff2d0..3dd5840397 100644 --- a/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.lfs.test/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF index cf10aa641f..3ce6084dd9 100644 --- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF @@ -3,22 +3,22 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs.test Bundle-SymbolicName: org.eclipse.jgit.lfs.test -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-1.8 -Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[5.5.2,5.6.0)", - org.eclipse.jgit.junit;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.treewalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.treewalk.filter;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", +Import-Package: org.eclipse.jgit.internal.storage.dfs;version="[5.6.1,5.7.0)", + org.eclipse.jgit.junit;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.treewalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.treewalk.filter;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)", org.hamcrest.core;version="[1.1.0,2.0.0)", org.junit;version="[4.12,5.0.0)", org.junit.runner;version="[4.12,5.0.0)", org.junit.runners;version="[4.12,5.0.0)" -Export-Package: org.eclipse.jgit.lfs.test;version="5.5.2";x-friends:="org.eclipse.jgit.lfs.server.test" +Export-Package: org.eclipse.jgit.lfs.test;version="5.6.1";x-friends:="org.eclipse.jgit.lfs.server.test" diff --git a/org.eclipse.jgit.lfs.test/pom.xml b/org.eclipse.jgit.lfs.test/pom.xml index 8166a07081..8a559cc91f 100644 --- a/org.eclipse.jgit.lfs.test/pom.xml +++ b/org.eclipse.jgit.lfs.test/pom.xml @@ -50,7 +50,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.lfs.test</artifactId> diff --git a/org.eclipse.jgit.lfs/.settings/.api_filters b/org.eclipse.jgit.lfs/.settings/.api_filters deleted file mode 100644 index 9747df8aa2..0000000000 --- a/org.eclipse.jgit.lfs/.settings/.api_filters +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<component id="org.eclipse.jgit.lfs" version="2"> - <resource path="src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java" type="org.eclipse.jgit.lfs.lib.AnyLongObjectId"> - <filter id="1141899266"> - <message_arguments> - <message_argument value="5.4"/> - <message_argument value="5.5"/> - <message_argument value="isEqual(AnyLongObjectId, AnyLongObjectId)"/> - </message_arguments> - </filter> - </resource> -</component> diff --git a/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs index 525ac67142..9fd92b1098 100644 --- a/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.lfs/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning diff --git a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF index da1fbd7741..453aad46b9 100644 --- a/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs/META-INF/MANIFEST.MF @@ -3,33 +3,33 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.lfs Bundle-SymbolicName: org.eclipse.jgit.lfs -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor -Export-Package: org.eclipse.jgit.lfs;version="5.5.2", - org.eclipse.jgit.lfs.errors;version="5.5.2", - org.eclipse.jgit.lfs.internal;version="5.5.2";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server", - org.eclipse.jgit.lfs.lib;version="5.5.2" +Export-Package: org.eclipse.jgit.lfs;version="5.6.1", + org.eclipse.jgit.lfs.errors;version="5.6.1", + org.eclipse.jgit.lfs.internal;version="5.6.1";x-friends:="org.eclipse.jgit.lfs.test,org.eclipse.jgit.lfs.server.fs,org.eclipse.jgit.lfs.server", + org.eclipse.jgit.lfs.lib;version="5.6.1" Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: com.google.gson;version="[2.8.2,3.0.0)", com.google.gson.stream;version="[2.8.2,3.0.0)", org.apache.http.impl.client;version="[4.2.6,5.0.0)", org.apache.http.impl.conn;version="[4.2.6,5.0.0)", - org.eclipse.jgit.annotations;version="[5.5.2,5.6.0)";resolution:=optional, - org.eclipse.jgit.api.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.attributes;version="[5.5.2,5.6.0)", - org.eclipse.jgit.diff;version="[5.5.2,5.6.0)", - org.eclipse.jgit.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.hooks;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.nls;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.storage.pack;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.http;version="[5.5.2,5.6.0)", - org.eclipse.jgit.treewalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.treewalk.filter;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util.io;version="[5.5.2,5.6.0)" + org.eclipse.jgit.annotations;version="[5.6.1,5.7.0)";resolution:=optional, + org.eclipse.jgit.api.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.attributes;version="[5.6.1,5.7.0)", + org.eclipse.jgit.diff;version="[5.6.1,5.7.0)", + org.eclipse.jgit.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.hooks;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.nls;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.storage.pack;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.http;version="[5.6.1,5.7.0)", + org.eclipse.jgit.treewalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.treewalk.filter;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util.io;version="[5.6.1,5.7.0)" diff --git a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF index 562747d66e..8093dae564 100644 --- a/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.lfs/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.lfs - Sources Bundle-SymbolicName: org.eclipse.jgit.lfs.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.lfs;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit.lfs/pom.xml b/org.eclipse.jgit.lfs/pom.xml index 1f2afd958c..bf5b745e04 100644 --- a/org.eclipse.jgit.lfs/pom.xml +++ b/org.eclipse.jgit.lfs/pom.xml @@ -50,7 +50,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.lfs</artifactId> diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/BuiltinLFS.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/BuiltinLFS.java index 56e3a12ddc..e90d92976a 100644 --- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/BuiltinLFS.java +++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/BuiltinLFS.java @@ -83,9 +83,8 @@ public class BuiltinLFS extends LfsFactory { Attribute attribute) throws IOException { if (isEnabled(db) && (attribute == null || isEnabled(db, attribute))) { return LfsBlobFilter.smudgeLfsBlob(db, loader); - } else { - return loader; } + return loader; } @Override @@ -93,9 +92,8 @@ public class BuiltinLFS extends LfsFactory { long length, Attribute attribute) throws IOException { if (isEnabled(db, attribute)) { return new LfsInputStream(LfsBlobFilter.cleanLfsBlob(db, input)); - } else { - return new LfsInputStream(input, length); } + return new LfsInputStream(input, length); } @Override @@ -108,6 +106,16 @@ public class BuiltinLFS extends LfsFactory { return null; } + @Override + @Nullable + public PrePushHook getPrePushHook(Repository repo, PrintStream outputStream, + PrintStream errorStream) { + if (isEnabled(repo)) { + return new LfsPrePushHook(repo, outputStream, errorStream); + } + return null; + } + /** * @param db * the repository diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java index 80da802db4..2329ade290 100644 --- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java +++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java @@ -138,32 +138,30 @@ public class CleanFilter extends FilterCommand { aOut.write(buf, 0, length); size += length; return length; + } + aOut.close(); + AnyLongObjectId loid = aOut.getId(); + aOut = null; + Path mediaFile = lfsUtil.getMediaFile(loid); + if (Files.isRegularFile(mediaFile)) { + long fsSize = Files.size(mediaFile); + if (fsSize != size) { + throw new CorruptMediaFile(mediaFile, size, fsSize); + } + FileUtils.delete(tmpFile.toFile()); } else { - aOut.close(); - AnyLongObjectId loid = aOut.getId(); - aOut = null; - Path mediaFile = lfsUtil.getMediaFile(loid); - if (Files.isRegularFile(mediaFile)) { - long fsSize = Files.size(mediaFile); - if (fsSize != size) { - throw new CorruptMediaFile(mediaFile, size, fsSize); - } else { - FileUtils.delete(tmpFile.toFile()); - } - } else { - Path parent = mediaFile.getParent(); - if (parent != null) { - FileUtils.mkdirs(parent.toFile(), true); - } - FileUtils.rename(tmpFile.toFile(), mediaFile.toFile(), - StandardCopyOption.ATOMIC_MOVE); + Path parent = mediaFile.getParent(); + if (parent != null) { + FileUtils.mkdirs(parent.toFile(), true); } - LfsPointer lfsPointer = new LfsPointer(loid, size); - lfsPointer.encode(out); - in.close(); - out.close(); - return -1; + FileUtils.rename(tmpFile.toFile(), mediaFile.toFile(), + StandardCopyOption.ATOMIC_MOVE); } + LfsPointer lfsPointer = new LfsPointer(loid, size); + lfsPointer.encode(out); + in.close(); + out.close(); + return -1; } catch (IOException e) { if (aOut != null) { aOut.abort(); diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java index 3e6a26159b..b3e304fea2 100644 --- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java +++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/LfsPrePushHook.java @@ -107,6 +107,20 @@ public class LfsPrePushHook extends PrePushHook { super(repo, outputStream); } + /** + * @param repo + * the repository + * @param outputStream + * not used by this implementation + * @param errorStream + * not used by this implementation + * @since 5.6 + */ + public LfsPrePushHook(Repository repo, PrintStream outputStream, + PrintStream errorStream) { + super(repo, outputStream, errorStream); + } + @Override public void setRefs(Collection<RemoteRefUpdate> toRefs) { this.refs = toRefs; diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java index feb8b4ae5a..184658d4d2 100644 --- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java +++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConnectionFactory.java @@ -179,9 +179,8 @@ public class LfsConnectionFactory { remoteUrl, u); additionalHeaders.putAll(action.header); return action.href; - } else { - return remoteUrl + Protocol.INFO_LFS_ENDPOINT; } + return remoteUrl + Protocol.INFO_LFS_ENDPOINT; } private static Protocol.ExpiringAction getSshAuthentication( @@ -262,9 +261,8 @@ public class LfsConnectionFactory { if (path.endsWith(org.eclipse.jgit.lib.Constants.DOT_GIT)) { return path.substring(0, path.length() - 4); - } else { - return path; } + return path; } /** diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java index b095d20e63..a9bd27f5c5 100644 --- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java +++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/lib/AnyLongObjectId.java @@ -303,10 +303,10 @@ public abstract class AnyLongObjectId implements Comparable<AnyLongObjectId> { /** {@inheritDoc} */ @Override public final boolean equals(Object o) { - if (o instanceof AnyLongObjectId) + if (o instanceof AnyLongObjectId) { return equals((AnyLongObjectId) o); - else - return false; + } + return false; } /** diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.properties index 169ef7ef6a..d47cc013dc 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.properties +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.properties @@ -30,7 +30,6 @@ http://www.eclipse.org/org/documents/edl-v10.html\n # "licenseURL" property - URL of the "Feature License" # do not translate value - just change to point to a locale-specific HTML page licenseURL=license.html - # "license" property - text of the "Feature Update License" # should be plain text version of license agreement pointed to be "licenseURL" license=\ @@ -69,7 +68,7 @@ downloadable archives ("Downloads").\n\ include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\ features ("Features").\n\ - Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\ - (Javaâ„¢ ARchive) in a directory named "plugins".\n\ + (Java\u2122 ARchive) in a directory named "plugins".\n\ - A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\ associated material. Each Feature may be packaged as a sub-directory in a\n\ directory named "features". Within a Feature, files named "feature.xml" may\n\ diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml index 2a1a0b64ab..fcabd079d3 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="5.5.2.qualifier" + version="5.6.1.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/license.html index 008b8018db..004b6dec6b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/license.html +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/license.html @@ -5,13 +5,10 @@ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> <title>Eclipse Foundation Software User Agreement</title> </head> - <body lang="EN-US"> <h2>Eclipse Foundation Software User Agreement</h2> <p>November 22, 2017</p> - <h3>Usage Of Content</h3> - <p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY @@ -24,9 +21,7 @@ AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p> - <h3>Applicable Licenses</h3> - <p> Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the @@ -35,13 +30,11 @@ href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>. For purposes of the EPL, "Program" will mean the Content. </p> - <p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p> - <ul> <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical @@ -62,7 +55,6 @@ "feature.xml" may contain a list of the names and version numbers of Included Features.</li> </ul> - <p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and @@ -70,7 +62,6 @@ "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module including, but not limited to the following locations:</p> - <ul> <li>The top-level (root) directory</li> <li>Plug-in and Fragment directories</li> @@ -79,7 +70,6 @@ certain Plug-ins</li> <li>Feature directories</li> </ul> - <p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during @@ -92,12 +82,10 @@ Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in that directory.</p> - <p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p> - <ul> <li>Eclipse Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>) @@ -118,16 +106,12 @@ href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>) </li> </ul> - <p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p> - - <h3>Use of Provisioning Technology</h3> - <p> The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse Update @@ -140,7 +124,6 @@ href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a> ("Specification"). </p> - <p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the applicable license agreements relating to the Installable Software @@ -149,7 +132,6 @@ Technology in such a manner and making it available in accordance with the Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p> - <ol> <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning @@ -171,19 +153,16 @@ provisioning Technology will complete installation of the Installable Software.</li> </ol> - <h3>Cryptography</h3> - <p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted.</p> - <p> <small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small> </p> </body> -</html> +</html>
\ No newline at end of file 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 9f2a30dde7..7ede04b03c 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.properties index 480e9c3888..b2fd6ed5cf 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.properties +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/feature.properties @@ -30,7 +30,6 @@ http://www.eclipse.org/org/documents/edl-v10.html\n # "licenseURL" property - URL of the "Feature License" # do not translate value - just change to point to a locale-specific HTML page licenseURL=license.html - # "license" property - text of the "Feature Update License" # should be plain text version of license agreement pointed to be "licenseURL" license=\ @@ -69,7 +68,7 @@ downloadable archives ("Downloads").\n\ include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\ features ("Features").\n\ - Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\ - (Javaâ„¢ ARchive) in a directory named "plugins".\n\ + (Java\u2122 ARchive) in a directory named "plugins".\n\ - A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\ associated material. Each Feature may be packaged as a sub-directory in a\n\ directory named "features". Within a Feature, files named "feature.xml" may\n\ 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 4096f8d9a7..c51335b2d0 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="5.5.2.qualifier" + version="5.6.1.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -23,7 +23,7 @@ </url> <requires> - <import plugin="org.eclipse.jgit" version="5.5.2" match="equivalent"/> + <import plugin="org.eclipse.jgit" version="5.6.1" match="equivalent"/> </requires> <plugin diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/license.html index 008b8018db..004b6dec6b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/license.html +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.http.apache.feature/license.html @@ -5,13 +5,10 @@ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> <title>Eclipse Foundation Software User Agreement</title> </head> - <body lang="EN-US"> <h2>Eclipse Foundation Software User Agreement</h2> <p>November 22, 2017</p> - <h3>Usage Of Content</h3> - <p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY @@ -24,9 +21,7 @@ AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p> - <h3>Applicable Licenses</h3> - <p> Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the @@ -35,13 +30,11 @@ href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>. For purposes of the EPL, "Program" will mean the Content. </p> - <p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p> - <ul> <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical @@ -62,7 +55,6 @@ "feature.xml" may contain a list of the names and version numbers of Included Features.</li> </ul> - <p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and @@ -70,7 +62,6 @@ "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module including, but not limited to the following locations:</p> - <ul> <li>The top-level (root) directory</li> <li>Plug-in and Fragment directories</li> @@ -79,7 +70,6 @@ certain Plug-ins</li> <li>Feature directories</li> </ul> - <p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during @@ -92,12 +82,10 @@ Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in that directory.</p> - <p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p> - <ul> <li>Eclipse Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>) @@ -118,16 +106,12 @@ href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>) </li> </ul> - <p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p> - - <h3>Use of Provisioning Technology</h3> - <p> The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse Update @@ -140,7 +124,6 @@ href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a> ("Specification"). </p> - <p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the applicable license agreements relating to the Installable Software @@ -149,7 +132,6 @@ Technology in such a manner and making it available in accordance with the Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p> - <ol> <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning @@ -171,19 +153,16 @@ provisioning Technology will complete installation of the Installable Software.</li> </ol> - <h3>Cryptography</h3> - <p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted.</p> - <p> <small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small> </p> </body> -</html> +</html>
\ No newline at end of file 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 200a1e5111..db347c6aef 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.properties index 291b29e3b7..acf33a9cef 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.properties +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.properties @@ -31,7 +31,6 @@ http://www.eclipse.org/org/documents/edl-v10.html\n # "licenseURL" property - URL of the "Feature License" # do not translate value - just change to point to a locale-specific HTML page licenseURL=license.html - # "license" property - text of the "Feature Update License" # should be plain text version of license agreement pointed to be "licenseURL" license=\ @@ -70,7 +69,7 @@ downloadable archives ("Downloads").\n\ include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\ features ("Features").\n\ - Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\ - (Javaâ„¢ ARchive) in a directory named "plugins".\n\ + (Java\u2122 ARchive) in a directory named "plugins".\n\ - A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\ associated material. Each Feature may be packaged as a sub-directory in a\n\ directory named "features". Within a Feature, files named "feature.xml" may\n\ 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 aa43cefd29..1e1ec530a7 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="5.5.2.qualifier" + version="5.6.1.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -24,7 +24,7 @@ <requires> <import plugin="com.jcraft.jsch"/> - <import plugin="org.eclipse.jgit" version="5.5.2" match="equivalent"/> + <import plugin="org.eclipse.jgit" version="5.6.1" match="equivalent"/> </requires> <plugin diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/license.html index 008b8018db..004b6dec6b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/license.html +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/license.html @@ -5,13 +5,10 @@ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> <title>Eclipse Foundation Software User Agreement</title> </head> - <body lang="EN-US"> <h2>Eclipse Foundation Software User Agreement</h2> <p>November 22, 2017</p> - <h3>Usage Of Content</h3> - <p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY @@ -24,9 +21,7 @@ AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p> - <h3>Applicable Licenses</h3> - <p> Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the @@ -35,13 +30,11 @@ href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>. For purposes of the EPL, "Program" will mean the Content. </p> - <p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p> - <ul> <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical @@ -62,7 +55,6 @@ "feature.xml" may contain a list of the names and version numbers of Included Features.</li> </ul> - <p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and @@ -70,7 +62,6 @@ "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module including, but not limited to the following locations:</p> - <ul> <li>The top-level (root) directory</li> <li>Plug-in and Fragment directories</li> @@ -79,7 +70,6 @@ certain Plug-ins</li> <li>Feature directories</li> </ul> - <p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during @@ -92,12 +82,10 @@ Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in that directory.</p> - <p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p> - <ul> <li>Eclipse Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>) @@ -118,16 +106,12 @@ href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>) </li> </ul> - <p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p> - - <h3>Use of Provisioning Technology</h3> - <p> The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse Update @@ -140,7 +124,6 @@ href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a> ("Specification"). </p> - <p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the applicable license agreements relating to the Installable Software @@ -149,7 +132,6 @@ Technology in such a manner and making it available in accordance with the Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p> - <ol> <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning @@ -171,19 +153,16 @@ provisioning Technology will complete installation of the Installable Software.</li> </ol> - <h3>Cryptography</h3> - <p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted.</p> - <p> <small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small> </p> </body> -</html> +</html>
\ No newline at end of file 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 23d3450a1a..34a4e95e96 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.properties index 8387585cda..5d953fa4c1 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.properties +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.properties @@ -30,7 +30,6 @@ http://www.eclipse.org/org/documents/edl-v10.html\n # "licenseURL" property - URL of the "Feature License" # do not translate value - just change to point to a locale-specific HTML page licenseURL=license.html - # "license" property - text of the "Feature Update License" # should be plain text version of license agreement pointed to be "licenseURL" license=\ @@ -69,7 +68,7 @@ downloadable archives ("Downloads").\n\ include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\ features ("Features").\n\ - Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\ - (Javaâ„¢ ARchive) in a directory named "plugins".\n\ + (Java\u2122 ARchive) in a directory named "plugins".\n\ - A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\ associated material. Each Feature may be packaged as a sub-directory in a\n\ directory named "features". Within a Feature, files named "feature.xml" may\n\ @@ -174,4 +173,4 @@ permitted.\n\ \n\ Java and all Java-based trademarks are trademarks of Oracle Corporation in the\n\ United States, other countries, or both.\n -########### end of license property ########################################## +########### end of license property ##########################################
\ No newline at end of file diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml index 781e94af2b..749752107d 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/feature.xml @@ -2,7 +2,7 @@ <feature id="org.eclipse.jgit.lfs" label="%featureName" - version="5.5.2.qualifier" + version="5.6.1.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -23,7 +23,7 @@ </url> <requires> - <import feature="org.eclipse.jgit" version="5.5.2" match="equivalent"/> + <import feature="org.eclipse.jgit" version="5.6.1" match="equivalent"/> </requires> <plugin diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/license.html index 008b8018db..004b6dec6b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/license.html +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/license.html @@ -5,13 +5,10 @@ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> <title>Eclipse Foundation Software User Agreement</title> </head> - <body lang="EN-US"> <h2>Eclipse Foundation Software User Agreement</h2> <p>November 22, 2017</p> - <h3>Usage Of Content</h3> - <p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY @@ -24,9 +21,7 @@ AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p> - <h3>Applicable Licenses</h3> - <p> Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the @@ -35,13 +30,11 @@ href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>. For purposes of the EPL, "Program" will mean the Content. </p> - <p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p> - <ul> <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical @@ -62,7 +55,6 @@ "feature.xml" may contain a list of the names and version numbers of Included Features.</li> </ul> - <p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and @@ -70,7 +62,6 @@ "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module including, but not limited to the following locations:</p> - <ul> <li>The top-level (root) directory</li> <li>Plug-in and Fragment directories</li> @@ -79,7 +70,6 @@ certain Plug-ins</li> <li>Feature directories</li> </ul> - <p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during @@ -92,12 +82,10 @@ Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in that directory.</p> - <p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p> - <ul> <li>Eclipse Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>) @@ -118,16 +106,12 @@ href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>) </li> </ul> - <p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p> - - <h3>Use of Provisioning Technology</h3> - <p> The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse Update @@ -140,7 +124,6 @@ href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a> ("Specification"). </p> - <p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the applicable license agreements relating to the Installable Software @@ -149,7 +132,6 @@ Technology in such a manner and making it available in accordance with the Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p> - <ol> <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning @@ -171,19 +153,16 @@ provisioning Technology will complete installation of the Installable Software.</li> </ol> - <h3>Cryptography</h3> - <p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted.</p> - <p> <small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small> </p> </body> -</html> +</html>
\ No newline at end of file diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml index b5fb886ede..58adaf51aa 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.lfs.feature/pom.xml @@ -50,7 +50,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.properties index ef9031ebce..450cff4a05 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.properties +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/feature.properties @@ -30,7 +30,6 @@ http://www.eclipse.org/org/documents/edl-v10.html\n # "licenseURL" property - URL of the "Feature License" # do not translate value - just change to point to a locale-specific HTML page licenseURL=license.html - # "license" property - text of the "Feature Update License" # should be plain text version of license agreement pointed to be "licenseURL" license=\ @@ -69,7 +68,7 @@ downloadable archives ("Downloads").\n\ include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\ features ("Features").\n\ - Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\ - (Javaâ„¢ ARchive) in a directory named "plugins".\n\ + (Java\u2122 ARchive) in a directory named "plugins".\n\ - A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\ associated material. Each Feature may be packaged as a sub-directory in a\n\ directory named "features". Within a Feature, files named "feature.xml" may\n\ @@ -174,4 +173,4 @@ permitted.\n\ \n\ Java and all Java-based trademarks are trademarks of Oracle Corporation in the\n\ United States, other countries, or both.\n -########### end of license property ########################################## +########### end of license property ##########################################
\ No newline at end of file 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 8656890e8a..b6dd351538 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="5.5.2.qualifier" + version="5.6.1.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -35,9 +35,9 @@ version="0.0.0"/> <requires> - <import feature="org.eclipse.jgit" version="5.5.2" match="equivalent"/> - <import feature="org.eclipse.jgit.lfs" version="5.5.2" match="equivalent"/> - <import feature="org.eclipse.jgit.ssh.apache" version="5.5.2" match="equivalent"/> + <import feature="org.eclipse.jgit" version="5.6.1" match="equivalent"/> + <import feature="org.eclipse.jgit.lfs" version="5.6.1" match="equivalent"/> + <import feature="org.eclipse.jgit.ssh.apache" version="5.6.1" match="equivalent"/> </requires> <plugin diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/license.html index 008b8018db..004b6dec6b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/license.html +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.pgm.feature/license.html @@ -5,13 +5,10 @@ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> <title>Eclipse Foundation Software User Agreement</title> </head> - <body lang="EN-US"> <h2>Eclipse Foundation Software User Agreement</h2> <p>November 22, 2017</p> - <h3>Usage Of Content</h3> - <p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY @@ -24,9 +21,7 @@ AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p> - <h3>Applicable Licenses</h3> - <p> Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the @@ -35,13 +30,11 @@ href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>. For purposes of the EPL, "Program" will mean the Content. </p> - <p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p> - <ul> <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical @@ -62,7 +55,6 @@ "feature.xml" may contain a list of the names and version numbers of Included Features.</li> </ul> - <p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and @@ -70,7 +62,6 @@ "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module including, but not limited to the following locations:</p> - <ul> <li>The top-level (root) directory</li> <li>Plug-in and Fragment directories</li> @@ -79,7 +70,6 @@ certain Plug-ins</li> <li>Feature directories</li> </ul> - <p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during @@ -92,12 +82,10 @@ Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in that directory.</p> - <p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p> - <ul> <li>Eclipse Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>) @@ -118,16 +106,12 @@ href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>) </li> </ul> - <p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p> - - <h3>Use of Provisioning Technology</h3> - <p> The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse Update @@ -140,7 +124,6 @@ href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a> ("Specification"). </p> - <p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the applicable license agreements relating to the Installable Software @@ -149,7 +132,6 @@ Technology in such a manner and making it available in accordance with the Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p> - <ol> <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning @@ -171,19 +153,16 @@ provisioning Technology will complete installation of the Installable Software.</li> </ol> - <h3>Cryptography</h3> - <p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted.</p> - <p> <small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small> </p> </body> -</html> +</html>
\ No newline at end of file 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 b4fe972526..2f70e48182 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/pom.xml index 63c76bf7a3..672fbfb1b6 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.repository</artifactId> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.properties index c04dc630de..5043c3234e 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.properties +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/feature.properties @@ -31,7 +31,6 @@ http://www.eclipse.org/org/documents/edl-v10.html\n # "licenseURL" property - URL of the "Feature License" # do not translate value - just change to point to a locale-specific HTML page licenseURL=license.html - # "license" property - text of the "Feature Update License" # should be plain text version of license agreement pointed to be "licenseURL" license=\ @@ -70,7 +69,7 @@ downloadable archives ("Downloads").\n\ include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\ features ("Features").\n\ - Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\ - (Javaâ„¢ ARchive) in a directory named "plugins".\n\ + (Java\u2122 ARchive) in a directory named "plugins".\n\ - A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\ associated material. Each Feature may be packaged as a sub-directory in a\n\ directory named "features". Within a Feature, files named "feature.xml" may\n\ @@ -175,4 +174,4 @@ permitted.\n\ \n\ Java and all Java-based trademarks are trademarks of Oracle Corporation in the\n\ United States, other countries, or both.\n -########### end of license property ########################################## +########### end of license property ##########################################
\ No newline at end of file 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 8781c66ab3..283b5e8fcf 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="5.5.2.qualifier" + version="5.6.1.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -23,7 +23,7 @@ </url> <requires> - <import feature="org.eclipse.jgit" version="5.5.2" match="equivalent"/> + <import feature="org.eclipse.jgit" version="5.6.1" match="equivalent"/> </requires> <plugin diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/license.html index 008b8018db..004b6dec6b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/license.html +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.source.feature/license.html @@ -5,13 +5,10 @@ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> <title>Eclipse Foundation Software User Agreement</title> </head> - <body lang="EN-US"> <h2>Eclipse Foundation Software User Agreement</h2> <p>November 22, 2017</p> - <h3>Usage Of Content</h3> - <p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY @@ -24,9 +21,7 @@ AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p> - <h3>Applicable Licenses</h3> - <p> Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the @@ -35,13 +30,11 @@ href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>. For purposes of the EPL, "Program" will mean the Content. </p> - <p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p> - <ul> <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical @@ -62,7 +55,6 @@ "feature.xml" may contain a list of the names and version numbers of Included Features.</li> </ul> - <p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and @@ -70,7 +62,6 @@ "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module including, but not limited to the following locations:</p> - <ul> <li>The top-level (root) directory</li> <li>Plug-in and Fragment directories</li> @@ -79,7 +70,6 @@ certain Plug-ins</li> <li>Feature directories</li> </ul> - <p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during @@ -92,12 +82,10 @@ Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in that directory.</p> - <p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p> - <ul> <li>Eclipse Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>) @@ -118,16 +106,12 @@ href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>) </li> </ul> - <p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p> - - <h3>Use of Provisioning Technology</h3> - <p> The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse Update @@ -140,7 +124,6 @@ href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a> ("Specification"). </p> - <p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the applicable license agreements relating to the Installable Software @@ -149,7 +132,6 @@ Technology in such a manner and making it available in accordance with the Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p> - <ol> <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning @@ -171,19 +153,16 @@ provisioning Technology will complete installation of the Installable Software.</li> </ol> - <h3>Cryptography</h3> - <p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted.</p> - <p> <small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small> </p> </body> -</html> +</html>
\ No newline at end of file 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 9ce5ec4400..6774fcf843 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> @@ -63,7 +63,7 @@ <dependency> <groupId>org.eclipse.jgit.feature</groupId> <artifactId>org.eclipse.jgit</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.properties b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.properties index 2b086129ff..e412fc2179 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.properties +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.properties @@ -30,7 +30,6 @@ http://www.eclipse.org/org/documents/edl-v10.html\n # "licenseURL" property - URL of the "Feature License" # do not translate value - just change to point to a locale-specific HTML page licenseURL=license.html - # "license" property - text of the "Feature Update License" # should be plain text version of license agreement pointed to be "licenseURL" license=\ @@ -69,7 +68,7 @@ downloadable archives ("Downloads").\n\ include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and\n\ features ("Features").\n\ - Each Plug-in or Fragment may be packaged as a sub-directory or JAR\n\ - (Javaâ„¢ ARchive) in a directory named "plugins".\n\ + (Java\u2122 ARchive) in a directory named "plugins".\n\ - A Feature is a bundle of one or more Plug-ins and/or Fragments and\n\ associated material. Each Feature may be packaged as a sub-directory in a\n\ directory named "features". Within a Feature, files named "feature.xml" may\n\ @@ -174,4 +173,4 @@ permitted.\n\ \n\ Java and all Java-based trademarks are trademarks of Oracle Corporation in the\n\ United States, other countries, or both.\n -########### end of license property ########################################## +########### end of license property ##########################################
\ No newline at end of file diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml index a55f941399..03418de919 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/feature.xml @@ -2,7 +2,7 @@ <feature id="org.eclipse.jgit.ssh.apache" label="%featureName" - version="5.5.2.qualifier" + version="5.6.1.qualifier" provider-name="%providerName"> <description url="http://www.eclipse.org/jgit/"> @@ -23,7 +23,7 @@ </url> <requires> - <import feature="org.eclipse.jgit" version="5.5.2" match="equivalent"/> + <import feature="org.eclipse.jgit" version="5.6.1" match="equivalent"/> </requires> <plugin diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/license.html b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/license.html index 008b8018db..004b6dec6b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/license.html +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/license.html @@ -5,13 +5,10 @@ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> <title>Eclipse Foundation Software User Agreement</title> </head> - <body lang="EN-US"> <h2>Eclipse Foundation Software User Agreement</h2> <p>November 22, 2017</p> - <h3>Usage Of Content</h3> - <p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY @@ -24,9 +21,7 @@ AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p> - <h3>Applicable Licenses</h3> - <p> Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the @@ -35,13 +30,11 @@ href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>. For purposes of the EPL, "Program" will mean the Content. </p> - <p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</p> - <ul> <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical @@ -62,7 +55,6 @@ "feature.xml" may contain a list of the names and version numbers of Included Features.</li> </ul> - <p>The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and @@ -70,7 +62,6 @@ "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module including, but not limited to the following locations:</p> - <ul> <li>The top-level (root) directory</li> <li>Plug-in and Fragment directories</li> @@ -79,7 +70,6 @@ certain Plug-ins</li> <li>Feature directories</li> </ul> - <p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during @@ -92,12 +82,10 @@ Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in that directory.</p> - <p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p> - <ul> <li>Eclipse Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>) @@ -118,16 +106,12 @@ href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>) </li> </ul> - <p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p> - - <h3>Use of Provisioning Technology</h3> - <p> The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse Update @@ -140,7 +124,6 @@ href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a> ("Specification"). </p> - <p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the applicable license agreements relating to the Installable Software @@ -149,7 +132,6 @@ Technology in such a manner and making it available in accordance with the Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p> - <ol> <li>A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning @@ -171,19 +153,16 @@ provisioning Technology will complete installation of the Installable Software.</li> </ol> - <h3>Cryptography</h3> - <p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted.</p> - <p> <small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small> </p> </body> -</html> +</html>
\ No newline at end of file diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml index 9ebafcae5c..a6bcd4b664 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.ssh.apache.feature/pom.xml @@ -50,7 +50,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <groupId>org.eclipse.jgit.feature</groupId> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/META-INF/MANIFEST.MF index 5954a34338..7e790d2098 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: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target index 771682c415..4a0d80d7f6 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.target @@ -1,26 +1,26 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.10" sequenceNumber="1567671414"> +<target name="jgit-4.10" sequenceNumber="1575495623"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.jetty.client" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.client.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util.source" version="9.4.20.v20190813"/> - <repository id="jetty-9.4.20" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.20.v20190813/"/> + <unit id="org.eclipse.jetty.client" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.client.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util.source" version="9.4.22.v20191022"/> + <repository id="jetty-9.4.22" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.22.v20191022/"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.google.gson" version="2.8.2.v20180104-1110"/> @@ -39,8 +39,8 @@ <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/> <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/> <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/> - <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/> - <unit id="org.apache.ant.source" version="1.10.5.v20190526-1402"/> + <unit id="org.apache.ant" version="1.10.7.v20190926-0324"/> + <unit id="org.apache.ant.source" version="1.10.7.v20190926-0324"/> <unit id="org.apache.commons.codec" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.codec.source" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.compress" version="1.18.0.v20181121-2221"/> @@ -57,12 +57,12 @@ <unit id="org.apache.sshd.osgi.source" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp.source" version="2.2.0.v20190425-2127"/> - <unit id="org.bouncycastle.bcpg" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpg.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov.source" version="1.61.0.v20190602-1335"/> + <unit id="org.bouncycastle.bcpg" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpg.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov.source" version="1.64.0.v20191109-0815"/> <unit id="org.hamcrest" version="1.1.0.v20090501071000"/> <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/> <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/> @@ -82,7 +82,7 @@ <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/> <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/> <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/> - <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20190827152740/repository"/> + <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20191126223242/repository"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="org.eclipse.osgi" version="0.0.0"/> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd index e5fce09c0e..e85e619ed7 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.10.tpd @@ -1,7 +1,7 @@ target "jgit-4.10" with source configurePhase -include "projects/jetty-9.4.20.tpd" -include "orbit/R20190827152740-2019-09.tpd" +include "projects/jetty-9.4.22.tpd" +include "orbit/R20191126223242-2019-12.tpd" location "http://download.eclipse.org/releases/2018-12/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target index 2466f8995e..3d3bb38512 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.target @@ -1,26 +1,26 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.11" sequenceNumber="1567671414"> +<target name="jgit-4.11" sequenceNumber="1575495623"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.jetty.client" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.client.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util.source" version="9.4.20.v20190813"/> - <repository id="jetty-9.4.20" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.20.v20190813/"/> + <unit id="org.eclipse.jetty.client" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.client.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util.source" version="9.4.22.v20191022"/> + <repository id="jetty-9.4.22" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.22.v20191022/"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.google.gson" version="2.8.2.v20180104-1110"/> @@ -39,8 +39,8 @@ <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/> <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/> <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/> - <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/> - <unit id="org.apache.ant.source" version="1.10.5.v20190526-1402"/> + <unit id="org.apache.ant" version="1.10.7.v20190926-0324"/> + <unit id="org.apache.ant.source" version="1.10.7.v20190926-0324"/> <unit id="org.apache.commons.codec" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.codec.source" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.compress" version="1.18.0.v20181121-2221"/> @@ -57,12 +57,12 @@ <unit id="org.apache.sshd.osgi.source" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp.source" version="2.2.0.v20190425-2127"/> - <unit id="org.bouncycastle.bcpg" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpg.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov.source" version="1.61.0.v20190602-1335"/> + <unit id="org.bouncycastle.bcpg" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpg.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov.source" version="1.64.0.v20191109-0815"/> <unit id="org.hamcrest" version="1.1.0.v20090501071000"/> <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/> <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/> @@ -82,7 +82,7 @@ <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/> <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/> <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/> - <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20190827152740/repository"/> + <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20191126223242/repository"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="org.eclipse.osgi" version="0.0.0"/> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd index 09d29c0d43..cd09465a4b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.11.tpd @@ -1,7 +1,7 @@ target "jgit-4.11" with source configurePhase -include "projects/jetty-9.4.20.tpd" -include "orbit/R20190827152740-2019-09.tpd" +include "projects/jetty-9.4.22.tpd" +include "orbit/R20191126223242-2019-12.tpd" location "http://download.eclipse.org/releases/2019-03/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target index 4f06536f12..380636cfa9 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.target @@ -1,26 +1,26 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.12" sequenceNumber="1567671414"> +<target name="jgit-4.12" sequenceNumber="1575495623"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.jetty.client" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.client.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util.source" version="9.4.20.v20190813"/> - <repository id="jetty-9.4.20" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.20.v20190813/"/> + <unit id="org.eclipse.jetty.client" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.client.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util.source" version="9.4.22.v20191022"/> + <repository id="jetty-9.4.22" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.22.v20191022/"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.google.gson" version="2.8.2.v20180104-1110"/> @@ -39,8 +39,8 @@ <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/> <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/> <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/> - <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/> - <unit id="org.apache.ant.source" version="1.10.5.v20190526-1402"/> + <unit id="org.apache.ant" version="1.10.7.v20190926-0324"/> + <unit id="org.apache.ant.source" version="1.10.7.v20190926-0324"/> <unit id="org.apache.commons.codec" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.codec.source" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.compress" version="1.18.0.v20181121-2221"/> @@ -57,12 +57,12 @@ <unit id="org.apache.sshd.osgi.source" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp.source" version="2.2.0.v20190425-2127"/> - <unit id="org.bouncycastle.bcpg" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpg.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov.source" version="1.61.0.v20190602-1335"/> + <unit id="org.bouncycastle.bcpg" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpg.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov.source" version="1.64.0.v20191109-0815"/> <unit id="org.hamcrest" version="1.1.0.v20090501071000"/> <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/> <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/> @@ -82,7 +82,7 @@ <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/> <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/> <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/> - <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20190827152740/repository"/> + <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20191126223242/repository"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="org.eclipse.osgi" version="0.0.0"/> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd index 3286f77aab..8904b99c65 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.12.tpd @@ -1,7 +1,7 @@ target "jgit-4.12" with source configurePhase -include "projects/jetty-9.4.20.tpd" -include "orbit/R20190827152740-2019-09.tpd" +include "projects/jetty-9.4.22.tpd" +include "orbit/R20191126223242-2019-12.tpd" location "http://download.eclipse.org/releases/2019-06/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13-staging.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13-staging.tpd deleted file mode 100644 index e82ed5f95e..0000000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13-staging.tpd +++ /dev/null @@ -1,8 +0,0 @@ -target "jgit-4.13-staging" with source configurePhase - -include "projects/jetty-9.4.20.tpd" -include "orbit/R20190827152740-2019-09.tpd" - -location "http://download.eclipse.org/staging/2019-09/" { - org.eclipse.osgi lazy -} diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target new file mode 100644 index 0000000000..e0fb34239e --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.target @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?pde?> +<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> +<target name="jgit-4.13" sequenceNumber="1575495624"> + <locations> + <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> + <unit id="org.eclipse.jetty.client" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.client.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util.source" version="9.4.22.v20191022"/> + <repository id="jetty-9.4.22" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.22.v20191022/"/> + </location> + <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> + <unit id="com.google.gson" version="2.8.2.v20180104-1110"/> + <unit id="com.google.gson.source" version="2.8.2.v20180104-1110"/> + <unit id="com.jcraft.jsch" version="0.1.55.v20190404-1902"/> + <unit id="com.jcraft.jsch.source" version="0.1.55.v20190404-1902"/> + <unit id="com.jcraft.jzlib" version="1.1.1.v201205102305"/> + <unit id="com.jcraft.jzlib.source" version="1.1.1.v201205102305"/> + <unit id="javaewah" version="1.1.6.v20160919-1400"/> + <unit id="javaewah.source" version="1.1.6.v20160919-1400"/> + <unit id="javax.servlet" version="3.1.0.v201410161800"/> + <unit id="javax.servlet.source" version="3.1.0.v201410161800"/> + <unit id="net.bytebuddy.byte-buddy" version="1.9.0.v20181107-1410"/> + <unit id="net.bytebuddy.byte-buddy-agent" version="1.9.0.v20181106-1534"/> + <unit id="net.bytebuddy.byte-buddy-agent.source" version="1.9.0.v20181106-1534"/> + <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/> + <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/> + <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/> + <unit id="org.apache.ant" version="1.10.7.v20190926-0324"/> + <unit id="org.apache.ant.source" version="1.10.7.v20190926-0324"/> + <unit id="org.apache.commons.codec" version="1.10.0.v20180409-1845"/> + <unit id="org.apache.commons.codec.source" version="1.10.0.v20180409-1845"/> + <unit id="org.apache.commons.compress" version="1.18.0.v20181121-2221"/> + <unit id="org.apache.commons.compress.source" version="1.18.0.v20181121-2221"/> + <unit id="org.apache.commons.logging" version="1.2.0.v20180409-1502"/> + <unit id="org.apache.commons.logging.source" version="1.2.0.v20180409-1502"/> + <unit id="org.apache.httpcomponents.httpclient" version="4.5.6.v20190503-0009"/> + <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.6.v20190503-0009"/> + <unit id="org.apache.httpcomponents.httpcore" version="4.4.10.v20190123-2214"/> + <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.10.v20190123-2214"/> + <unit id="org.apache.log4j" version="1.2.15.v201012070815"/> + <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/> + <unit id="org.apache.sshd.osgi" version="2.2.0.v20190425-2127"/> + <unit id="org.apache.sshd.osgi.source" version="2.2.0.v20190425-2127"/> + <unit id="org.apache.sshd.sftp" version="2.2.0.v20190425-2127"/> + <unit id="org.apache.sshd.sftp.source" version="2.2.0.v20190425-2127"/> + <unit id="org.bouncycastle.bcpg" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpg.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov.source" version="1.64.0.v20191109-0815"/> + <unit id="org.hamcrest" version="1.1.0.v20090501071000"/> + <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/> + <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/> + <unit id="org.hamcrest.library" version="1.3.0.v20180524-2246"/> + <unit id="org.hamcrest.library.source" version="1.3.0.v20180524-2246"/> + <unit id="org.junit" version="4.12.0.v201504281640"/> + <unit id="org.junit.source" version="4.12.0.v201504281640"/> + <unit id="org.kohsuke.args4j" version="2.33.0.v20160323-2218"/> + <unit id="org.kohsuke.args4j.source" version="2.33.0.v20160323-2218"/> + <unit id="org.mockito" version="2.23.0.v20190527-1420"/> + <unit id="org.mockito.source" version="2.23.0.v20190527-1420"/> + <unit id="org.objenesis" version="2.6.0.v20180420-1519"/> + <unit id="org.objenesis.source" version="2.6.0.v20180420-1519"/> + <unit id="org.slf4j.api" version="1.7.2.v20121108-1250"/> + <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/> + <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/> + <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/> + <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/> + <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/> + <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20191126223242/repository"/> + </location> + <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> + <unit id="org.eclipse.osgi" version="0.0.0"/> + <repository location="http://download.eclipse.org/releases/2019-09/"/> + </location> + </locations> +</target> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd new file mode 100644 index 0000000000..1e5f36f776 --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13.tpd @@ -0,0 +1,8 @@ +target "jgit-4.13" with source configurePhase + +include "projects/jetty-9.4.22.tpd" +include "orbit/R20191126223242-2019-12.tpd" + +location "http://download.eclipse.org/releases/2019-09/" { + org.eclipse.osgi lazy +} diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13-staging.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14-staging.target index 8572d7c45e..f3b5965c42 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.13-staging.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14-staging.target @@ -1,26 +1,26 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.13-staging" sequenceNumber="1567671414"> +<target name="jgit-4.14-staging" sequenceNumber="1575495626"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.jetty.client" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.client.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util.source" version="9.4.20.v20190813"/> - <repository id="jetty-9.4.20" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.20.v20190813/"/> + <unit id="org.eclipse.jetty.client" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.client.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util.source" version="9.4.22.v20191022"/> + <repository id="jetty-9.4.22" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.22.v20191022/"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.google.gson" version="2.8.2.v20180104-1110"/> @@ -39,8 +39,8 @@ <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/> <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/> <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/> - <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/> - <unit id="org.apache.ant.source" version="1.10.5.v20190526-1402"/> + <unit id="org.apache.ant" version="1.10.7.v20190926-0324"/> + <unit id="org.apache.ant.source" version="1.10.7.v20190926-0324"/> <unit id="org.apache.commons.codec" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.codec.source" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.compress" version="1.18.0.v20181121-2221"/> @@ -57,12 +57,12 @@ <unit id="org.apache.sshd.osgi.source" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp.source" version="2.2.0.v20190425-2127"/> - <unit id="org.bouncycastle.bcpg" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpg.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov.source" version="1.61.0.v20190602-1335"/> + <unit id="org.bouncycastle.bcpg" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpg.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov.source" version="1.64.0.v20191109-0815"/> <unit id="org.hamcrest" version="1.1.0.v20090501071000"/> <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/> <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/> @@ -82,11 +82,11 @@ <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/> <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/> <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/> - <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20190827152740/repository"/> + <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20191126223242/repository"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="org.eclipse.osgi" version="0.0.0"/> - <repository location="http://download.eclipse.org/staging/2019-09/"/> + <repository location="http://download.eclipse.org/staging/2019-12/"/> </location> </locations> </target> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14-staging.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14-staging.tpd new file mode 100644 index 0000000000..d58281b75c --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.14-staging.tpd @@ -0,0 +1,8 @@ +target "jgit-4.14-staging" with source configurePhase + +include "projects/jetty-9.4.22.tpd" +include "orbit/R20191126223242-2019-12.tpd" + +location "http://download.eclipse.org/staging/2019-12/" { + org.eclipse.osgi lazy +} diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target index e8044e4ed5..0c82ed63a3 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target @@ -1,26 +1,26 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.6" sequenceNumber="1567671414"> +<target name="jgit-4.6" sequenceNumber="1575495636"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.jetty.client" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.client.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util.source" version="9.4.20.v20190813"/> - <repository id="jetty-9.4.20" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.20.v20190813/"/> + <unit id="org.eclipse.jetty.client" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.client.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util.source" version="9.4.22.v20191022"/> + <repository id="jetty-9.4.22" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.22.v20191022/"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.google.gson" version="2.8.2.v20180104-1110"/> @@ -39,8 +39,8 @@ <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/> <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/> <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/> - <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/> - <unit id="org.apache.ant.source" version="1.10.5.v20190526-1402"/> + <unit id="org.apache.ant" version="1.10.7.v20190926-0324"/> + <unit id="org.apache.ant.source" version="1.10.7.v20190926-0324"/> <unit id="org.apache.commons.codec" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.codec.source" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.compress" version="1.18.0.v20181121-2221"/> @@ -57,12 +57,12 @@ <unit id="org.apache.sshd.osgi.source" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp.source" version="2.2.0.v20190425-2127"/> - <unit id="org.bouncycastle.bcpg" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpg.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov.source" version="1.61.0.v20190602-1335"/> + <unit id="org.bouncycastle.bcpg" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpg.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov.source" version="1.64.0.v20191109-0815"/> <unit id="org.hamcrest" version="1.1.0.v20090501071000"/> <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/> <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/> @@ -82,7 +82,7 @@ <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/> <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/> <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/> - <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20190827152740/repository"/> + <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20191126223242/repository"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="org.eclipse.osgi" version="0.0.0"/> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd index edc1983e29..f29a8252b1 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.tpd @@ -1,7 +1,7 @@ target "jgit-4.6" with source configurePhase -include "projects/jetty-9.4.20.tpd" -include "orbit/R20190827152740-2019-09.tpd" +include "projects/jetty-9.4.22.tpd" +include "orbit/R20191126223242-2019-12.tpd" location "http://download.eclipse.org/releases/neon/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target index 8c6b45bc4e..1d7acecb5b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target @@ -1,26 +1,26 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.7" sequenceNumber="1567671414"> +<target name="jgit-4.7" sequenceNumber="1575495628"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.jetty.client" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.client.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util.source" version="9.4.20.v20190813"/> - <repository id="jetty-9.4.20" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.20.v20190813/"/> + <unit id="org.eclipse.jetty.client" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.client.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util.source" version="9.4.22.v20191022"/> + <repository id="jetty-9.4.22" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.22.v20191022/"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.google.gson" version="2.8.2.v20180104-1110"/> @@ -39,8 +39,8 @@ <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/> <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/> <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/> - <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/> - <unit id="org.apache.ant.source" version="1.10.5.v20190526-1402"/> + <unit id="org.apache.ant" version="1.10.7.v20190926-0324"/> + <unit id="org.apache.ant.source" version="1.10.7.v20190926-0324"/> <unit id="org.apache.commons.codec" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.codec.source" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.compress" version="1.18.0.v20181121-2221"/> @@ -57,12 +57,12 @@ <unit id="org.apache.sshd.osgi.source" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp.source" version="2.2.0.v20190425-2127"/> - <unit id="org.bouncycastle.bcpg" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpg.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov.source" version="1.61.0.v20190602-1335"/> + <unit id="org.bouncycastle.bcpg" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpg.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov.source" version="1.64.0.v20191109-0815"/> <unit id="org.hamcrest" version="1.1.0.v20090501071000"/> <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/> <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/> @@ -82,7 +82,7 @@ <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/> <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/> <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/> - <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20190827152740/repository"/> + <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20191126223242/repository"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="org.eclipse.osgi" version="0.0.0"/> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd index 56cb3e9005..97a2b12e2d 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.tpd @@ -1,7 +1,7 @@ target "jgit-4.7" with source configurePhase -include "projects/jetty-9.4.20.tpd" -include "orbit/R20190827152740-2019-09.tpd" +include "projects/jetty-9.4.22.tpd" +include "orbit/R20191126223242-2019-12.tpd" location "http://download.eclipse.org/releases/oxygen/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target index f3d8876219..8b6bd8caff 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target @@ -1,26 +1,26 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.8" sequenceNumber="1567671414"> +<target name="jgit-4.8" sequenceNumber="1575495623"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.jetty.client" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.client.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util.source" version="9.4.20.v20190813"/> - <repository id="jetty-9.4.20" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.20.v20190813/"/> + <unit id="org.eclipse.jetty.client" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.client.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util.source" version="9.4.22.v20191022"/> + <repository id="jetty-9.4.22" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.22.v20191022/"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.google.gson" version="2.8.2.v20180104-1110"/> @@ -39,8 +39,8 @@ <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/> <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/> <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/> - <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/> - <unit id="org.apache.ant.source" version="1.10.5.v20190526-1402"/> + <unit id="org.apache.ant" version="1.10.7.v20190926-0324"/> + <unit id="org.apache.ant.source" version="1.10.7.v20190926-0324"/> <unit id="org.apache.commons.codec" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.codec.source" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.compress" version="1.18.0.v20181121-2221"/> @@ -57,12 +57,12 @@ <unit id="org.apache.sshd.osgi.source" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp.source" version="2.2.0.v20190425-2127"/> - <unit id="org.bouncycastle.bcpg" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpg.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov.source" version="1.61.0.v20190602-1335"/> + <unit id="org.bouncycastle.bcpg" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpg.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov.source" version="1.64.0.v20191109-0815"/> <unit id="org.hamcrest" version="1.1.0.v20090501071000"/> <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/> <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/> @@ -82,7 +82,7 @@ <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/> <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/> <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/> - <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20190827152740/repository"/> + <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20191126223242/repository"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="org.eclipse.osgi" version="0.0.0"/> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd index 9a9b5572a4..1fea5c19ee 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd @@ -1,7 +1,7 @@ target "jgit-4.8" with source configurePhase -include "projects/jetty-9.4.20.tpd" -include "orbit/R20190827152740-2019-09.tpd" +include "projects/jetty-9.4.22.tpd" +include "orbit/R20191126223242-2019-12.tpd" location "http://download.eclipse.org/releases/photon/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target index 4a6d011e9c..67c389bbb7 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.target @@ -1,26 +1,26 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.9" sequenceNumber="1567671414"> +<target name="jgit-4.9" sequenceNumber="1575495623"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.jetty.client" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.client.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.continuation.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.http.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.io.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.security.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.server.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.servlet.source" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util" version="9.4.20.v20190813"/> - <unit id="org.eclipse.jetty.util.source" version="9.4.20.v20190813"/> - <repository id="jetty-9.4.20" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.20.v20190813/"/> + <unit id="org.eclipse.jetty.client" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.client.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.continuation.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.http.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.io.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.security.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.server.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.servlet.source" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util" version="9.4.22.v20191022"/> + <unit id="org.eclipse.jetty.util.source" version="9.4.22.v20191022"/> + <repository id="jetty-9.4.22" location="https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.22.v20191022/"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.google.gson" version="2.8.2.v20180104-1110"/> @@ -39,8 +39,8 @@ <unit id="net.bytebuddy.byte-buddy.source" version="1.9.0.v20181107-1410"/> <unit id="net.i2p.crypto.eddsa" version="0.3.0.v20181102-1323"/> <unit id="net.i2p.crypto.eddsa.source" version="0.3.0.v20181102-1323"/> - <unit id="org.apache.ant" version="1.10.5.v20190526-1402"/> - <unit id="org.apache.ant.source" version="1.10.5.v20190526-1402"/> + <unit id="org.apache.ant" version="1.10.7.v20190926-0324"/> + <unit id="org.apache.ant.source" version="1.10.7.v20190926-0324"/> <unit id="org.apache.commons.codec" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.codec.source" version="1.10.0.v20180409-1845"/> <unit id="org.apache.commons.compress" version="1.18.0.v20181121-2221"/> @@ -57,12 +57,12 @@ <unit id="org.apache.sshd.osgi.source" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp" version="2.2.0.v20190425-2127"/> <unit id="org.apache.sshd.sftp.source" version="2.2.0.v20190425-2127"/> - <unit id="org.bouncycastle.bcpg" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpg.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcpkix.source" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov" version="1.61.0.v20190602-1335"/> - <unit id="org.bouncycastle.bcprov.source" version="1.61.0.v20190602-1335"/> + <unit id="org.bouncycastle.bcpg" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpg.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcpkix.source" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov" version="1.64.0.v20191109-0815"/> + <unit id="org.bouncycastle.bcprov.source" version="1.64.0.v20191109-0815"/> <unit id="org.hamcrest" version="1.1.0.v20090501071000"/> <unit id="org.hamcrest.core" version="1.3.0.v20180420-1519"/> <unit id="org.hamcrest.core.source" version="1.3.0.v20180420-1519"/> @@ -82,7 +82,7 @@ <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/> <unit id="org.tukaani.xz" version="1.8.0.v20180207-1613"/> <unit id="org.tukaani.xz.source" version="1.8.0.v20180207-1613"/> - <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20190827152740/repository"/> + <repository location="https://download.eclipse.org/tools/orbit/downloads/drops/R20191126223242/repository"/> </location> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="org.eclipse.osgi" version="0.0.0"/> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd index 8874e2e6b0..af165488b1 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd @@ -1,7 +1,7 @@ target "jgit-4.9" with source configurePhase -include "projects/jetty-9.4.20.tpd" -include "orbit/R20190827152740-2019-09.tpd" +include "projects/jetty-9.4.22.tpd" +include "orbit/R20191126223242-2019-12.tpd" location "http://download.eclipse.org/releases/2018-09/" { org.eclipse.osgi lazy diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20191126223242-2019-12.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20191126223242-2019-12.tpd new file mode 100644 index 0000000000..679e919cdb --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20191126223242-2019-12.tpd @@ -0,0 +1,65 @@ +target "R20191126223242-2019-12" with source configurePhase +// see http://download.eclipse.org/tools/orbit/downloads/ + +location "https://download.eclipse.org/tools/orbit/downloads/drops/R20191126223242/repository" { + com.google.gson [2.8.2.v20180104-1110,2.8.2.v20180104-1110] + com.google.gson.source [2.8.2.v20180104-1110,2.8.2.v20180104-1110] + com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902] + com.jcraft.jsch.source [0.1.55.v20190404-1902,0.1.55.v20190404-1902] + com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305] + com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305] + javaewah [1.1.6.v20160919-1400,1.1.6.v20160919-1400] + javaewah.source [1.1.6.v20160919-1400,1.1.6.v20160919-1400] + javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800] + javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800] + net.bytebuddy.byte-buddy [1.9.0.v20181107-1410,1.9.0.v20181107-1410] + net.bytebuddy.byte-buddy-agent [1.9.0.v20181106-1534,1.9.0.v20181106-1534] + net.bytebuddy.byte-buddy-agent.source [1.9.0.v20181106-1534,1.9.0.v20181106-1534] + net.bytebuddy.byte-buddy.source [1.9.0.v20181107-1410,1.9.0.v20181107-1410] + net.i2p.crypto.eddsa [0.3.0.v20181102-1323,0.3.0.v20181102-1323] + net.i2p.crypto.eddsa.source [0.3.0.v20181102-1323,0.3.0.v20181102-1323] + org.apache.ant [1.10.7.v20190926-0324,1.10.7.v20190926-0324] + org.apache.ant.source [1.10.7.v20190926-0324,1.10.7.v20190926-0324] + org.apache.commons.codec [1.10.0.v20180409-1845,1.10.0.v20180409-1845] + org.apache.commons.codec.source [1.10.0.v20180409-1845,1.10.0.v20180409-1845] + org.apache.commons.compress [1.18.0.v20181121-2221,1.18.0.v20181121-2221] + org.apache.commons.compress.source [1.18.0.v20181121-2221,1.18.0.v20181121-2221] + org.apache.commons.logging [1.2.0.v20180409-1502,1.2.0.v20180409-1502] + org.apache.commons.logging.source [1.2.0.v20180409-1502,1.2.0.v20180409-1502] + org.apache.httpcomponents.httpclient [4.5.6.v20190503-0009,4.5.6.v20190503-0009] + org.apache.httpcomponents.httpclient.source [4.5.6.v20190503-0009,4.5.6.v20190503-0009] + org.apache.httpcomponents.httpcore [4.4.10.v20190123-2214,4.4.10.v20190123-2214] + org.apache.httpcomponents.httpcore.source [4.4.10.v20190123-2214,4.4.10.v20190123-2214] + org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815] + org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815] + org.apache.sshd.osgi [2.2.0.v20190425-2127,2.2.0.v20190425-2127] + org.apache.sshd.osgi.source [2.2.0.v20190425-2127,2.2.0.v20190425-2127] + org.apache.sshd.sftp [2.2.0.v20190425-2127,2.2.0.v20190425-2127] + org.apache.sshd.sftp.source [2.2.0.v20190425-2127,2.2.0.v20190425-2127] + org.bouncycastle.bcpg [1.64.0.v20191109-0815,1.64.0.v20191109-0815] + org.bouncycastle.bcpg.source [1.64.0.v20191109-0815,1.64.0.v20191109-0815] + org.bouncycastle.bcpkix [1.64.0.v20191109-0815,1.64.0.v20191109-0815] + org.bouncycastle.bcpkix.source [1.64.0.v20191109-0815,1.64.0.v20191109-0815] + org.bouncycastle.bcprov [1.64.0.v20191109-0815,1.64.0.v20191109-0815] + org.bouncycastle.bcprov.source [1.64.0.v20191109-0815,1.64.0.v20191109-0815] + org.hamcrest [1.1.0.v20090501071000,1.1.0.v20090501071000] + org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519] + org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519] + org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246] + org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246] + org.junit [4.12.0.v201504281640,4.12.0.v201504281640] + org.junit.source [4.12.0.v201504281640,4.12.0.v201504281640] + org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218] + org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218] + org.mockito [2.23.0.v20190527-1420,2.23.0.v20190527-1420] + org.mockito.source [2.23.0.v20190527-1420,2.23.0.v20190527-1420] + org.objenesis [2.6.0.v20180420-1519,2.6.0.v20180420-1519] + org.objenesis.source [2.6.0.v20180420-1519,2.6.0.v20180420-1519] + org.slf4j.api [1.7.2.v20121108-1250,1.7.2.v20121108-1250] + org.slf4j.api.source [1.7.2.v20121108-1250,1.7.2.v20121108-1250] + org.slf4j.impl.log4j12 [1.7.2.v20131105-2200,1.7.2.v20131105-2200] + org.slf4j.impl.log4j12.source [1.7.2.v20131105-2200,1.7.2.v20131105-2200] + org.tukaani.xz [1.8.0.v20180207-1613,1.8.0.v20180207-1613] + org.tukaani.xz.source [1.8.0.v20180207-1613,1.8.0.v20180207-1613] +} + 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 c0cf0645e2..fdfb981e3e 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.target</artifactId> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.20.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.20.tpd deleted file mode 100644 index b29179a8ec..0000000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.20.tpd +++ /dev/null @@ -1,20 +0,0 @@ -target "jetty-9.4.20" with source configurePhase - -location jetty-9.4.20 "https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.20.v20190813/" { - org.eclipse.jetty.client [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.client.source [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.continuation [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.continuation.source [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.http [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.http.source [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.io [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.io.source [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.security [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.security.source [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.server [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.server.source [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.servlet [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.servlet.source [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.util [9.4.20.v20190813,9.4.20.v20190813] - org.eclipse.jetty.util.source [9.4.20.v20190813,9.4.20.v20190813] -} diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.22.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.22.tpd new file mode 100644 index 0000000000..562e017d32 --- /dev/null +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.22.tpd @@ -0,0 +1,20 @@ +target "jetty-9.4.22" with source configurePhase + +location jetty-9.4.22 "https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.22.v20191022/" { + org.eclipse.jetty.client [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.client.source [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.continuation [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.continuation.source [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.http [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.http.source [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.io [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.io.source [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.security [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.security.source [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.server [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.server.source [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.servlet [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.servlet.source [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.util [9.4.22.v20191022,9.4.22.v20191022] + org.eclipse.jetty.util.source [9.4.22.v20191022,9.4.22.v20191022] +} diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml index 13b2dd33aa..e2f2838a75 100644 --- a/org.eclipse.jgit.packaging/pom.xml +++ b/org.eclipse.jgit.packaging/pom.xml @@ -49,13 +49,13 @@ <groupId>org.eclipse.jgit</groupId> <artifactId>jgit.tycho.parent</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> <packaging>pom</packaging> <name>JGit Tycho Parent</name> <properties> - <tycho-version>1.4.0</tycho-version> + <tycho-version>1.5.1</tycho-version> <tycho-extras-version>${tycho-version}</tycho-extras-version> <target-platform>jgit-4.6</target-platform> </properties> diff --git a/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs index 2ca78ff2d0..3dd5840397 100644 --- a/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.pgm.test/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF index 2cb36e1ff0..5339f2ed82 100644 --- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF @@ -3,28 +3,28 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.pgm.test Bundle-SymbolicName: org.eclipse.jgit.pgm.test -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.8 -Import-Package: org.eclipse.jgit.api;version="[5.5.2,5.6.0)", - org.eclipse.jgit.api.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.diff;version="[5.5.2,5.6.0)", - org.eclipse.jgit.dircache;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.file;version="5.5.2", - org.eclipse.jgit.junit;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.merge;version="[5.5.2,5.6.0)", - org.eclipse.jgit.pgm;version="[5.5.2,5.6.0)", - org.eclipse.jgit.pgm.internal;version="[5.5.2,5.6.0)", - org.eclipse.jgit.pgm.opt;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="[5.5.2,5.6.0)", - org.eclipse.jgit.treewalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util.io;version="[5.5.2,5.6.0)", +Import-Package: org.eclipse.jgit.api;version="[5.6.1,5.7.0)", + org.eclipse.jgit.api.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.diff;version="[5.6.1,5.7.0)", + org.eclipse.jgit.dircache;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.file;version="5.6.1", + org.eclipse.jgit.junit;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.merge;version="[5.6.1,5.7.0)", + org.eclipse.jgit.pgm;version="[5.6.1,5.7.0)", + org.eclipse.jgit.pgm.internal;version="[5.6.1,5.7.0)", + org.eclipse.jgit.pgm.opt;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="[5.6.1,5.7.0)", + org.eclipse.jgit.treewalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util.io;version="[5.6.1,5.7.0)", org.hamcrest.core;bundle-version="[1.1.0,2.0.0)", org.junit;version="[4.12,5.0.0)", org.junit.rules;version="[4.12,5.0.0)", diff --git a/org.eclipse.jgit.pgm.test/pom.xml b/org.eclipse.jgit.pgm.test/pom.xml index 49535d6714..b7a80948df 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.pgm.test</artifactId> diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/BlameTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/BlameTest.java index e806872c14..6da1e463f0 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/BlameTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/BlameTest.java @@ -42,8 +42,14 @@ */ package org.eclipse.jgit.pgm; +import static org.junit.Assert.assertTrue; + import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.MergeResult; import org.eclipse.jgit.lib.CLIRepositoryTestCase; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.revwalk.RevCommit; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -85,7 +91,7 @@ public class BlameTest extends CLIRepositoryTestCase { git.add().addFilepattern("inIndex.txt").call(); } assertStringArrayEquals( - " (Not Committed Yet 1) index", + "00000000 (Not Committed Yet 2009-08-15 20:12:58 -0330 1) index", execute("git blame inIndex.txt")); } @@ -119,4 +125,36 @@ public class BlameTest extends CLIRepositoryTestCase { thrown.expectMessage("no such path 'sub/does_not_exist.txt' in HEAD"); execute("git blame sub/does_not_exist.txt"); } + + @Test + public void testBlameMergeConflict() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("file", "Origin\n"); + git.add().addFilepattern("file").call(); + git.commit().setMessage("initial commit").call(); + git.checkout().setCreateBranch(true) + .setName("side").call(); + writeTrashFile("file", + "Conflicting change from side branch\n"); + git.add().addFilepattern("file").call(); + RevCommit side = git.commit().setMessage("side commit") + .setCommitter(new PersonIdent("gitter", "")).call(); + git.checkout().setName(Constants.MASTER).call(); + writeTrashFile("file", "Change on master branch\n"); + git.add().addFilepattern("file").call(); + git.commit().setMessage("Commit conflict on master") + .setCommitter(new PersonIdent("gitter", "")).call(); + MergeResult result = git.merge() + .include("side", side).call(); + assertTrue("Expected conflict on 'file'", + result.getConflicts().containsKey("file")); + } + String[] expected = { + "00000000 (Not Committed Yet 2009-08-15 20:12:58 -0330 1) <<<<<<< HEAD", + "0f5b671c (gitter 2009-08-15 20:12:58 -0330 2) Change on master branch", + "00000000 (Not Committed Yet 2009-08-15 20:12:58 -0330 3) =======", + "ae78cff6 (gitter 2009-08-15 20:12:58 -0330 4) Conflicting change from side branch", + "00000000 (Not Committed Yet 2009-08-15 20:12:58 -0330 5) >>>>>>> side" }; + assertArrayOfLinesEquals(expected, execute("git blame file")); + } } diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java index c31f28c256..0ecbd656ed 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java @@ -44,6 +44,7 @@ package org.eclipse.jgit.pgm; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; @@ -54,7 +55,13 @@ import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.MockSystemReader; import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.transport.RefSpec; +import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.util.SystemReader; import org.junit.Before; @@ -90,10 +97,10 @@ public class CloneTest extends CLIRepositoryTestCase { assertEquals("expected 1 branch", 1, branches.size()); } - private void createInitialCommit() throws Exception { + private RevCommit createInitialCommit() throws Exception { JGitTestUtil.writeTrashFile(db, "hello.txt", "world"); git.add().addFilepattern("hello.txt").call(); - git.commit().setMessage("Initial commit").call(); + return git.commit().setMessage("Initial commit").call(); } @Test @@ -154,4 +161,37 @@ public class CloneTest extends CLIRepositoryTestCase { assertEquals("expected 1 branch", 1, branches.size()); assertTrue("expected bare repository", git2.getRepository().isBare()); } + + @Test + public void testCloneMirror() throws Exception { + ObjectId head = createInitialCommit(); + // create a non-standard ref + RefUpdate ru = db.updateRef("refs/meta/foo/bar"); + ru.setNewObjectId(head); + ru.update(); + + File gitDir = db.getDirectory(); + String sourcePath = gitDir.getAbsolutePath(); + String targetPath = (new File(sourcePath)).getParentFile() + .getParentFile().getAbsolutePath() + File.separator + + "target.git"; + String cmd = "git clone --mirror " + shellQuote(sourcePath) + " " + + shellQuote(targetPath); + String[] result = execute(cmd); + assertArrayEquals( + new String[] { "Cloning into '" + targetPath + "'...", "", "" }, + result); + Git git2 = Git.open(new File(targetPath)); + List<Ref> branches = git2.branchList().call(); + assertEquals("expected 1 branch", 1, branches.size()); + assertTrue("expected bare repository", git2.getRepository().isBare()); + StoredConfig config = git2.getRepository().getConfig(); + RemoteConfig rc = new RemoteConfig(config, "origin"); + assertTrue("expected mirror configuration", rc.isMirror()); + RefSpec fetchRefSpec = rc.getFetchRefSpecs().get(0); + assertTrue("exected force udpate", fetchRefSpec.isForceUpdate()); + assertEquals("refs/*", fetchRefSpec.getSource()); + assertEquals("refs/*", fetchRefSpec.getDestination()); + assertNotNull(git2.getRepository().exactRef("refs/meta/foo/bar")); + } } 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 ef6f5e732f..bc7ba1e50e 100644 --- a/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.pgm/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning diff --git a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF index 0a9074a2cf..484ec54fc6 100644 --- a/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.pgm/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.pgm Bundle-SymbolicName: org.eclipse.jgit.pgm -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy Bundle-Localization: plugin @@ -28,50 +28,50 @@ Import-Package: javax.servlet;version="[3.1.0,4.0.0)", org.eclipse.jetty.util.log;version="[9.4.5,10.0.0)", org.eclipse.jetty.util.security;version="[9.4.5,10.0.0)", org.eclipse.jetty.util.thread;version="[9.4.5,10.0.0)", - org.eclipse.jgit.api;version="[5.5.2,5.6.0)", - org.eclipse.jgit.api.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.archive;version="[5.5.2,5.6.0)", - org.eclipse.jgit.awtui;version="[5.5.2,5.6.0)", - org.eclipse.jgit.blame;version="[5.5.2,5.6.0)", - org.eclipse.jgit.diff;version="[5.5.2,5.6.0)", - org.eclipse.jgit.dircache;version="[5.5.2,5.6.0)", - org.eclipse.jgit.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.gitrepo;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.ketch;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.dfs;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.io;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.pack;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.reftable;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.reftree;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.server;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.server.fs;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs.server.s3;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.merge;version="[5.5.2,5.6.0)", - org.eclipse.jgit.nls;version="[5.5.2,5.6.0)", - org.eclipse.jgit.notes;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revplot;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk.filter;version="[5.5.2,5.6.0)", - org.eclipse.jgit.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.storage.pack;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.http.apache;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.resolver;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.sshd;version="[5.5.2,5.6.0)", - org.eclipse.jgit.treewalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.treewalk.filter;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util.io;version="[5.5.2,5.6.0)", + org.eclipse.jgit.api;version="[5.6.1,5.7.0)", + org.eclipse.jgit.api.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.archive;version="[5.6.1,5.7.0)", + org.eclipse.jgit.awtui;version="[5.6.1,5.7.0)", + org.eclipse.jgit.blame;version="[5.6.1,5.7.0)", + org.eclipse.jgit.diff;version="[5.6.1,5.7.0)", + org.eclipse.jgit.dircache;version="[5.6.1,5.7.0)", + org.eclipse.jgit.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.gitrepo;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.ketch;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.dfs;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.io;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.pack;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.reftable;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.reftree;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.server;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.server.fs;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs.server.s3;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.merge;version="[5.6.1,5.7.0)", + org.eclipse.jgit.nls;version="[5.6.1,5.7.0)", + org.eclipse.jgit.notes;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revplot;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk.filter;version="[5.6.1,5.7.0)", + org.eclipse.jgit.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.storage.pack;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.http.apache;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.resolver;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.sshd;version="[5.6.1,5.7.0)", + org.eclipse.jgit.treewalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.treewalk.filter;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util.io;version="[5.6.1,5.7.0)", org.kohsuke.args4j;version="[2.33.0,3.0.0)", org.kohsuke.args4j.spi;version="[2.33.0,3.0.0)" -Export-Package: org.eclipse.jgit.console;version="5.5.2"; +Export-Package: org.eclipse.jgit.console;version="5.6.1"; uses:="org.eclipse.jgit.transport, org.eclipse.jgit.util", - org.eclipse.jgit.pgm;version="5.5.2"; + org.eclipse.jgit.pgm;version="5.6.1"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.pgm.opt, @@ -82,11 +82,11 @@ Export-Package: org.eclipse.jgit.console;version="5.5.2"; org.eclipse.jgit.treewalk, javax.swing, org.eclipse.jgit.transport", - org.eclipse.jgit.pgm.debug;version="5.5.2"; + org.eclipse.jgit.pgm.debug;version="5.6.1"; uses:="org.eclipse.jgit.util.io, org.eclipse.jgit.pgm", - org.eclipse.jgit.pgm.internal;version="5.5.2";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test", - org.eclipse.jgit.pgm.opt;version="5.5.2"; + org.eclipse.jgit.pgm.internal;version="5.6.1";x-friends:="org.eclipse.jgit.pgm.test,org.eclipse.jgit.test", + org.eclipse.jgit.pgm.opt;version="5.6.1"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.kohsuke.args4j.spi, diff --git a/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.pgm/META-INF/SOURCE-MANIFEST.MF index 1ce53a586f..4b231dd218 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: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.pgm;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin index 39fbe2ed75..062b9643a3 100644 --- a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin +++ b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin @@ -8,6 +8,7 @@ org.eclipse.jgit.pgm.Clean org.eclipse.jgit.pgm.Clone org.eclipse.jgit.pgm.Commit org.eclipse.jgit.pgm.Config +org.eclipse.jgit.pgm.ConvertRefStorage org.eclipse.jgit.pgm.Daemon org.eclipse.jgit.pgm.Describe org.eclipse.jgit.pgm.Diff diff --git a/org.eclipse.jgit.pgm/pom.xml b/org.eclipse.jgit.pgm/pom.xml index c7bcaf1e6c..f4c0005cce 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-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 f02944265a..02f0543206 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 @@ -223,6 +223,9 @@ 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_AlwaysFallback=Show uniquely abbreviated commit object as fallback 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_mirrorClone=Set up a mirror of the source repository. This implies --bare. Compared to --bare, --mirror not only maps \ +local branches of the source to local branches of the target, it maps all refs (including remote-tracking branches, notes etc.) \ +and sets up a refspec configuration such that all these refs are overwritten by a git remote update in the target repository. usage_Blame=Show what revision and author last modified each line usage_Clean=Remove untracked files from the working tree usage_CommandLineClientForamazonsS3Service=Command line client for Amazon's S3 service @@ -323,6 +326,8 @@ usage_configList=List all variables set in config file usage_configLocal=use local configuration in .git/config usage_configSystem=use system-wide configuration in $(prefix)/etc/gitconfig usage_configureTheServiceInDaemonServicename=configure the service in daemon.servicename +usage_convertRefStorage=Convert ref storage to reftable +usage_convertRefStorageFormat=Format to convert to (reftable or refdir) usage_createBranchAndCheckout=create branch and check out usage_deleteBranchEvenIfNotMerged=delete branch (even if not merged) usage_deleteFullyMergedBranch=delete fully merged branch diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java index f8442facb7..039d0946b2 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java @@ -136,18 +136,15 @@ public class ConsoleCredentialsProvider extends CredentialsProvider { if (v != null) { item.setValue(new String(v)); return true; - } else { - return false; - } - } else { - String v = cons.readLine("%s: ", item.getPromptText()); //$NON-NLS-1$ - if (v != null) { - item.setValue(v); - return true; - } else { - return false; } + return false; + } + String v = cons.readLine("%s: ", item.getPromptText()); //$NON-NLS-1$ + if (v != null) { + item.setValue(v); + return true; } + return false; } private boolean get(CredentialItem.CharArrayType item) { @@ -156,18 +153,15 @@ public class ConsoleCredentialsProvider extends CredentialsProvider { if (v != null) { item.setValueNoCopy(v); return true; - } else { - return false; - } - } else { - String v = cons.readLine("%s: ", item.getPromptText()); //$NON-NLS-1$ - if (v != null) { - item.setValueNoCopy(v.toCharArray()); - return true; - } else { - return false; } + return false; + } + String v = cons.readLine("%s: ", item.getPromptText()); //$NON-NLS-1$ + if (v != null) { + item.setValueNoCopy(v.toCharArray()); + return true; } + return false; } private boolean get(CredentialItem.InformationalMessage item) { @@ -182,8 +176,7 @@ public class ConsoleCredentialsProvider extends CredentialsProvider { if (r != null) { item.setValue(CLIText.get().answerYes.equalsIgnoreCase(r)); return true; - } else { - return false; } + return false; } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java index b67b04c5be..1a4c111bcb 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java @@ -50,7 +50,6 @@ import static java.lang.Integer.valueOf; import static java.lang.Long.valueOf; import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH; -import java.io.File; import java.io.IOException; import java.text.MessageFormat; import java.text.SimpleDateFormat; @@ -60,11 +59,11 @@ import java.util.List; import java.util.Map; import java.util.regex.Pattern; +import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.blame.BlameGenerator; import org.eclipse.jgit.blame.BlameResult; import org.eclipse.jgit.diff.RawText; import org.eclipse.jgit.diff.RawTextComparator; -import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; @@ -134,6 +133,9 @@ class Blame extends TextBuiltin { private BlameResult blame; + /** Used to get a current time stamp for lines without commit. */ + private final PersonIdent dummyDate = new PersonIdent("", ""); //$NON-NLS-1$ //$NON-NLS-2$ + /** {@inheritDoc} */ @Override protected void run() { @@ -186,28 +188,7 @@ class Blame extends TextBuiltin { } generator.push(null, rev); } else { - ObjectId head = db.resolve(Constants.HEAD); - if (head == null) { - throw die(MessageFormat.format(CLIText.get().noSuchRef, - Constants.HEAD)); - } - generator.push(null, head); - if (!db.isBare()) { - DirCache dc = db.readDirCache(); - int entry = dc.findEntry(file); - if (0 <= entry) { - generator.push(null, dc.getEntry(entry).getObjectId()); - } else { - throw die(MessageFormat.format( - CLIText.get().noSuchPathInRef, file, - Constants.HEAD)); - } - - File inTree = new File(db.getWorkTree(), file); - if (db.getFS().isFile(inTree)) { - generator.push(null, new RawText(inTree)); - } - } + generator.prepareHead(); } blame = BlameResult.create(generator); @@ -236,6 +217,10 @@ class Blame extends TextBuiltin { authorWidth = Math.max(authorWidth, author(line).length()); dateWidth = Math.max(dateWidth, date(line).length()); pathWidth = Math.max(pathWidth, path(line).length()); + } else if (c == null) { + authorWidth = Math.max(authorWidth, author(line).length()); + dateWidth = Math.max(dateWidth, date(line).length()); + pathWidth = Math.max(pathWidth, path(line).length()); } while (line + 1 < end && sameCommit(blame.getSourceCommit(line + 1), c)) { @@ -280,7 +265,7 @@ class Blame extends TextBuiltin { } while (++line < end && sameCommit(blame.getSourceCommit(line), c)); } - } catch (NoWorkTreeException | IOException e) { + } catch (NoWorkTreeException | NoHeadException | IOException e) { throw die(e.getMessage(), e); } } @@ -373,10 +358,12 @@ class Blame extends TextBuiltin { } private String date(int line) { - if (blame.getSourceCommit(line) == null) - return ""; //$NON-NLS-1$ - - PersonIdent author = blame.getSourceAuthor(line); + PersonIdent author; + if (blame.getSourceCommit(line) == null) { + author = dummyDate; + } else { + author = blame.getSourceAuthor(line); + } if (author == null) return ""; //$NON-NLS-1$ @@ -394,28 +381,37 @@ class Blame extends TextBuiltin { if (r != null) return r; - if (showBlankBoundary && commit.getParentCount() == 0) - commit = null; - if (commit == null) { - int len = showLongRevision ? OBJECT_ID_STRING_LENGTH : (abbrev + 1); - StringBuilder b = new StringBuilder(len); - for (int i = 0; i < len; i++) - b.append(' '); - r = b.toString(); - - } else if (!root && commit.getParentCount() == 0) { - if (showLongRevision) - r = "^" + commit.name().substring(0, OBJECT_ID_STRING_LENGTH - 1); //$NON-NLS-1$ - else - r = "^" + reader.abbreviate(commit, abbrev).name(); //$NON-NLS-1$ + if (showLongRevision) { + r = ObjectId.zeroId().name(); + } else { + r = ObjectId.zeroId().abbreviate(abbrev + 1).name(); + } } else { - if (showLongRevision) - r = commit.name(); - else - r = reader.abbreviate(commit, abbrev + 1).name(); + if (showBlankBoundary && commit.getParentCount() == 0) + commit = null; + + if (commit == null) { + int len = showLongRevision ? OBJECT_ID_STRING_LENGTH + : (abbrev + 1); + StringBuilder b = new StringBuilder(len); + for (int i = 0; i < len; i++) + b.append(' '); + r = b.toString(); + + } else if (!root && commit.getParentCount() == 0) { + if (showLongRevision) + r = "^" + commit.name().substring(0, //$NON-NLS-1$ + OBJECT_ID_STRING_LENGTH - 1); + else + r = "^" + reader.abbreviate(commit, abbrev).name(); //$NON-NLS-1$ + } else { + if (showLongRevision) + r = commit.name(); + else + r = reader.abbreviate(commit, abbrev + 1).name(); + } } - abbreviatedCommits.put(commit, r); return r; } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java index fe2462012b..a6a031e2c7 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Clone.java @@ -74,6 +74,9 @@ class Clone extends AbstractFetchCommand implements CloneCommand.Callback { @Option(name = "--bare", usage = "usage_bareClone") private boolean isBare; + @Option(name = "--mirror", usage = "usage_mirrorClone") + private boolean isMirror; + @Option(name = "--quiet", usage = "usage_quiet") private Boolean quiet; @@ -103,7 +106,7 @@ class Clone extends AbstractFetchCommand implements CloneCommand.Callback { if (localName == null) { try { localName = uri.getHumanishName(); - if (isBare) { + if (isBare || isMirror) { localName = localName + Constants.DOT_GIT_EXT; } localNameF = new File(SystemReader.getInstance().getProperty( @@ -120,6 +123,7 @@ class Clone extends AbstractFetchCommand implements CloneCommand.Callback { CloneCommand command = Git.cloneRepository(); command.setURI(sourceUri).setRemote(remoteName).setBare(isBare) + .setMirror(isMirror) .setNoCheckout(noCheckout).setBranch(branch) .setCloneSubmodules(cloneSubmodules); diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ConvertRefStorage.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ConvertRefStorage.java new file mode 100644 index 0000000000..2fd689b004 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/ConvertRefStorage.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019, Google LLC + * 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 org.eclipse.jgit.internal.storage.file.FileRepository; +import org.kohsuke.args4j.Option; + +@Command(common=true, usage="usage_convertRefStorage") +class ConvertRefStorage extends TextBuiltin { + + @Option(name = "--format", usage = "usage_convertRefStorageFormat") + private String format = "reftable"; //$NON-NLS-1$ + + /** {@inheritDoc} */ + @Override + protected void run() throws Exception { + ((FileRepository) db).convertRefStorage(format, true, true); + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java index c3887fe9c3..23ee9337b6 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java @@ -306,8 +306,8 @@ class Status extends TextBuiltin { } outw.flush(); return list.size(); - } else - return 0; + } + return 0; } /** diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java index 248eaac8ad..27a7347f3a 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/BenchmarkReftable.java @@ -51,14 +51,18 @@ import static org.eclipse.jgit.lib.Ref.Storage.NEW; import static org.eclipse.jgit.lib.Ref.Storage.PACKED; import java.io.BufferedReader; +import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; +import java.util.List; +import org.eclipse.jgit.internal.storage.file.FileReftableStack; import org.eclipse.jgit.internal.storage.io.BlockSource; import org.eclipse.jgit.internal.storage.reftable.RefCursor; import org.eclipse.jgit.internal.storage.reftable.ReftableReader; +import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdRef; import org.eclipse.jgit.lib.Ref; @@ -74,7 +78,8 @@ class BenchmarkReftable extends TextBuiltin { enum Test { SCAN, SEEK_COLD, SEEK_HOT, - BY_ID_COLD, BY_ID_HOT; + BY_ID_COLD, BY_ID_HOT, + WRITE_STACK, } @Option(name = "--tries") @@ -116,6 +121,9 @@ class BenchmarkReftable extends TextBuiltin { case BY_ID_HOT: byIdHot(ObjectId.fromString(objectId)); break; + case WRITE_STACK: + writeStack(); + break; } } @@ -124,6 +132,33 @@ class BenchmarkReftable extends TextBuiltin { } @SuppressWarnings({ "nls", "boxing" }) + private void writeStack() throws Exception { + File dir = new File(reftablePath); + File stackFile = new File(reftablePath + ".stack"); + + dir.mkdirs(); + + long start = System.currentTimeMillis(); + try (FileReftableStack stack = new FileReftableStack(stackFile, dir, + null, () -> new Config())) { + + List<Ref> refs = readLsRemote().asList(); + for (Ref r : refs) { + final long j = stack.getMergedReftable().maxUpdateIndex() + 1; + if (!stack.addReftable(w -> { + w.setMaxUpdateIndex(j).setMinUpdateIndex(j).begin() + .writeRef(r); + })) { + throw new IOException("should succeed"); + } + } + long dt = System.currentTimeMillis() - start; + printf("%12s %10d ms avg %6d us/write", "reftable", dt, + (dt * 1000) / refs.size()); + } + } + + @SuppressWarnings({ "nls", "boxing" }) private void scan() throws Exception { long start, tot; diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java index 8948c27537..0d30f3661c 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java @@ -189,9 +189,8 @@ class RebuildCommitGraph extends TextBuiltin { // rewritten. queue.add(t); continue REWRITE; - } else { - newParents[k] = p.newId; } + newParents[k] = p.newId; } else { // We have the old parent object. Use it. // diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java index a2ea8c20b4..1242bb754b 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java @@ -138,9 +138,8 @@ class TextHashFunctions extends TextBuiltin { Arrays.fill(buf16, (byte) 0); System.arraycopy(raw, ptr, buf16, 0, end - ptr); return rabin(buf16, 0); - } else { - return rabin(raw, ptr); } + return rabin(raw, ptr); } private int rabin(byte[] raw, int ptr) { diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java index 6cbc1b082b..0320ed1174 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/WriteReftable.java @@ -128,9 +128,9 @@ class WriteReftable extends TextBuiltin { cfg.setMaxIndexLevels(indexLevels); } - ReftableWriter w = new ReftableWriter(cfg); + ReftableWriter w = new ReftableWriter(cfg, os); w.setMinUpdateIndex(min(logs)).setMaxUpdateIndex(max(logs)); - w.begin(os); + w.begin(); w.sortAndWriteRefs(refs); for (LogEntry e : logs) { w.writeLog(e.ref, e.updateIndex, e.who, diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java index b97aa5b7af..d3aa38cf23 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/CmdLineParser.java @@ -299,10 +299,10 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser { /** {@inheritDoc} */ @Override protected OptionHandler createOptionHandler(OptionDef o, Setter setter) { - if (o instanceof NamedOptionDef) + if (o instanceof NamedOptionDef) { return super.createOptionHandler(o, setter); - else - return super.createOptionHandler(new MyOptionDef(o), setter); + } + return super.createOptionHandler(new MyOptionDef(o), setter); } diff --git a/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.core.prefs index 794592dee1..822846c4d0 100644 --- a/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.ssh.apache.test/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error diff --git a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF index 81969e723f..b3a343ead2 100644 --- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ssh.apache.test Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.test -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-1.8 @@ -15,15 +15,15 @@ Import-Package: org.apache.sshd.client.config.hosts;version="[2.2.0,2.3.0)", org.apache.sshd.common.session;version="[2.2.0,2.3.0)", org.apache.sshd.common.util.net;version="[2.2.0,2.3.0)", org.apache.sshd.common.util.security;version="[2.2.0,2.3.0)", - org.eclipse.jgit.api.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.transport.sshd.proxy;version="[5.5.2,5.6.0)", - org.eclipse.jgit.junit;version="[5.5.2,5.6.0)", - org.eclipse.jgit.junit.ssh;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.ssh;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.sshd;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", + org.eclipse.jgit.api.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.transport.sshd.proxy;version="[5.6.1,5.7.0)", + org.eclipse.jgit.junit;version="[5.6.1,5.7.0)", + org.eclipse.jgit.junit.ssh;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.ssh;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.sshd;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)", org.junit;version="[4.12,5.0.0)", org.junit.experimental.theories;version="[4.12,5.0.0)", org.junit.runner;version="[4.12,5.0.0)" diff --git a/org.eclipse.jgit.ssh.apache.test/pom.xml b/org.eclipse.jgit.ssh.apache.test/pom.xml index 0f2504c84f..c65a1dfd47 100644 --- a/org.eclipse.jgit.ssh.apache.test/pom.xml +++ b/org.eclipse.jgit.ssh.apache.test/pom.xml @@ -50,7 +50,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ssh.apache.test</artifactId> diff --git a/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.core.prefs index 13c32a6d94..15ef2aad5d 100644 --- a/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.ssh.apache/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF index 6a11b18976..5f9490db8b 100644 --- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF @@ -6,9 +6,9 @@ Bundle-SymbolicName: org.eclipse.jgit.ssh.apache Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-ActivationPolicy: lazy -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.8 -Export-Package: org.eclipse.jgit.internal.transport.sshd;version="5.5.2";x-internal:=true; +Export-Package: org.eclipse.jgit.internal.transport.sshd;version="5.6.1";x-internal:=true; uses:="org.apache.sshd.client, org.apache.sshd.client.auth, org.apache.sshd.client.auth.keyboard, @@ -23,9 +23,9 @@ Export-Package: org.eclipse.jgit.internal.transport.sshd;version="5.5.2";x-inter org.apache.sshd.common.signature, org.apache.sshd.common.util.buffer, org.eclipse.jgit.transport", - org.eclipse.jgit.internal.transport.sshd.auth;version="5.5.2";x-internal:=true, - org.eclipse.jgit.internal.transport.sshd.proxy;version="5.5.2";x-friends:="org.eclipse.jgit.ssh.apache.test", - org.eclipse.jgit.transport.sshd;version="5.5.2"; + org.eclipse.jgit.internal.transport.sshd.auth;version="5.6.1";x-internal:=true, + org.eclipse.jgit.internal.transport.sshd.proxy;version="5.6.1";x-friends:="org.eclipse.jgit.ssh.apache.test", + org.eclipse.jgit.transport.sshd;version="5.6.1"; uses:="org.eclipse.jgit.transport, org.apache.sshd.client.config.hosts, org.apache.sshd.common.keyprovider, @@ -75,12 +75,12 @@ Import-Package: net.i2p.crypto.eddsa;version="[0.3.0,0.4.0)", org.apache.sshd.common.util.net;version="[2.2.0,2.3.0)", org.apache.sshd.common.util.security;version="[2.2.0,2.3.0)", org.apache.sshd.server.auth;version="[2.2.0,2.3.0)", - org.eclipse.jgit.annotations;version="[5.5.2,5.6.0)", - org.eclipse.jgit.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.fnmatch;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.transport.ssh;version="[5.5.2,5.6.0)", - org.eclipse.jgit.nls;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", + org.eclipse.jgit.annotations;version="[5.6.1,5.7.0)", + org.eclipse.jgit.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.fnmatch;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.transport.ssh;version="[5.6.1,5.7.0)", + org.eclipse.jgit.nls;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)", org.slf4j;version="[1.7.0,2.0.0)" diff --git a/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF index 8991b5b608..5ff8d335ea 100644 --- a/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.ssh.apache - Sources Bundle-SymbolicName: org.eclipse.jgit.ssh.apache.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ssh.apache;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit.ssh.apache/pom.xml b/org.eclipse.jgit.ssh.apache/pom.xml index f412d63fb7..b780189b32 100644 --- a/org.eclipse.jgit.ssh.apache/pom.xml +++ b/org.eclipse.jgit.ssh.apache/pom.xml @@ -50,7 +50,7 @@ <parent> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.ssh.apache</artifactId> diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java index 1954abc75b..79bd3faa01 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java @@ -179,9 +179,8 @@ public class JGitClientSession extends ClientSessionImpl { } catch (Exception other) { throw new IOException(other.getLocalizedMessage(), other); } - } else { - return super.sendIdentification(ident); } + return super.sendIdentification(ident); } @Override @@ -205,9 +204,8 @@ public class JGitClientSession extends ClientSessionImpl { } catch (Exception other) { throw new IOException(other.getLocalizedMessage(), other); } - } else { - return super.sendKexInit(); } + return super.sendKexInit(); } /** diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java index f4849ce4a3..9c0a793124 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java @@ -453,9 +453,8 @@ public class OpenSshServerKeyDatabase prompt); items.add(answer); return provider.get(uri, items) && answer.getValue(); - } else { - return provider.get(uri, items); } + return provider.get(uri, items); } private Check checkMode(SocketAddress remoteAddress, boolean changed) { diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpParser.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpParser.java index b9b32b1300..02771b501c 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpParser.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/HttpParser.java @@ -207,11 +207,10 @@ public final class HttpParser { next++; } return next; - } else { - // This token must be the name of the next authentication - // scheme. - return start; } + // This token must be the name of the next authentication + // scheme. + return start; } int nextStart = skipWhiteSpace(header, next + 1); if (nextStart >= length) { @@ -244,11 +243,10 @@ public final class HttpParser { // token, and the equals sign is part of the token challenge.setToken(header.substring(start, end + 1)); return nextStart + 1; - } else { - // Key without value... - challenge.addArgument(header.substring(start, end), null); - start = nextStart + 1; } + // Key without value... + challenge.addArgument(header.substring(start, end), null); + start = nextStart + 1; } else { if (header.charAt(nextStart) == '"') { int nextEnd[] = { nextStart + 1 }; diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/Socks5ClientConnector.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/Socks5ClientConnector.java index 27d6f418b8..b3681d14a5 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/Socks5ClientConnector.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/proxy/Socks5ClientConnector.java @@ -281,11 +281,10 @@ public class Socks5ClientConnector extends AbstractClientProxyConnector { } if (i == proposals.length) { return proposals; - } else { - byte[] result = new byte[i]; - System.arraycopy(proposals, 0, result, 0, i); - return result; } + byte[] result = new byte[i]; + System.arraycopy(proposals, 0, result, 0, i); + return result; } private void sendConnectInfo(IoSession session) throws Exception { diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java index 1e8d7d1e1e..3fc955ab25 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSession.java @@ -354,9 +354,8 @@ public class SshdSession implements RemoteSession { if (path.charAt(0) != '/') { if (cwd.charAt(cwd.length() - 1) == '/') { return cwd + path; - } else { - return cwd + '/' + path; } + return cwd + '/' + path; } return path; } diff --git a/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs index 2ca78ff2d0..3dd5840397 100644 --- a/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error diff --git a/org.eclipse.jgit.test/BUILD b/org.eclipse.jgit.test/BUILD index 3f664f93f3..3d487960c4 100644 --- a/org.eclipse.jgit.test/BUILD +++ b/org.eclipse.jgit.test/BUILD @@ -24,6 +24,7 @@ HELPERS = glob( "revwalk/RevQueueTestCase.java", "revwalk/RevWalkTestCase.java", "transport/ObjectIdMatcher.java", + "transport/RequestValidatorTestCase.java", "transport/SpiTransport.java", "treewalk/filter/AlwaysCloneTreeFilter.java", "test/resources/SampleDataRepositoryTestCase.java", diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF index 42c9c573a9..8612e361f1 100644 --- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.test Bundle-SymbolicName: org.eclipse.jgit.test -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy @@ -18,57 +18,58 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", org.apache.commons.compress.compressors.gzip;version="[1.15.0,2.0)", org.apache.commons.compress.compressors.xz;version="[1.15.0,2.0)", org.bouncycastle.util.encoders;version="[1.61.0,2.0.0)", - org.eclipse.jgit.annotations;version="[5.5.2,5.6.0)", - org.eclipse.jgit.api;version="[5.5.2,5.6.0)", - org.eclipse.jgit.api.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.archive;version="[5.5.2,5.6.0)", - org.eclipse.jgit.attributes;version="[5.5.2,5.6.0)", - org.eclipse.jgit.awtui;version="[5.5.2,5.6.0)", - org.eclipse.jgit.blame;version="[5.5.2,5.6.0)", - org.eclipse.jgit.diff;version="[5.5.2,5.6.0)", - org.eclipse.jgit.dircache;version="[5.5.2,5.6.0)", - org.eclipse.jgit.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.events;version="[5.5.2,5.6.0)", - org.eclipse.jgit.fnmatch;version="[5.5.2,5.6.0)", - org.eclipse.jgit.gitrepo;version="[5.5.2,5.6.0)", - org.eclipse.jgit.hooks;version="[5.5.2,5.6.0)", - org.eclipse.jgit.ignore;version="[5.5.2,5.6.0)", - org.eclipse.jgit.ignore.internal;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.fsck;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.dfs;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.io;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.pack;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.reftable;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.storage.reftree;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.transport.http;version="[5.5.2,5.6.0)", - org.eclipse.jgit.internal.transport.parser;version="[5.5.2,5.6.0)", - org.eclipse.jgit.junit;version="[5.5.2,5.6.0)", - org.eclipse.jgit.junit.ssh;version="[5.5.2,5.6.0)", - org.eclipse.jgit.junit.time;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lfs;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.merge;version="[5.5.2,5.6.0)", - org.eclipse.jgit.nls;version="[5.5.2,5.6.0)", - org.eclipse.jgit.notes;version="[5.5.2,5.6.0)", - org.eclipse.jgit.patch;version="[5.5.2,5.6.0)", - org.eclipse.jgit.pgm;version="[5.5.2,5.6.0)", - org.eclipse.jgit.pgm.internal;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revplot;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk.filter;version="[5.5.2,5.6.0)", - org.eclipse.jgit.storage.file;version="[5.5.2,5.6.0)", - org.eclipse.jgit.storage.pack;version="[5.5.2,5.6.0)", - org.eclipse.jgit.submodule;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.http;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport.resolver;version="[5.5.2,5.6.0)", - org.eclipse.jgit.treewalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.treewalk.filter;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util.io;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util.sha1;version="[5.5.2,5.6.0)", + org.eclipse.jgit.annotations;version="[5.6.1,5.7.0)", + org.eclipse.jgit.api;version="[5.6.1,5.7.0)", + org.eclipse.jgit.api.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.archive;version="[5.6.1,5.7.0)", + org.eclipse.jgit.attributes;version="[5.6.1,5.7.0)", + org.eclipse.jgit.awtui;version="[5.6.1,5.7.0)", + org.eclipse.jgit.blame;version="[5.6.1,5.7.0)", + org.eclipse.jgit.diff;version="[5.6.1,5.7.0)", + org.eclipse.jgit.dircache;version="[5.6.1,5.7.0)", + org.eclipse.jgit.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.events;version="[5.6.1,5.7.0)", + org.eclipse.jgit.fnmatch;version="[5.6.1,5.7.0)", + org.eclipse.jgit.gitrepo;version="[5.6.1,5.7.0)", + org.eclipse.jgit.hooks;version="[5.6.1,5.7.0)", + org.eclipse.jgit.ignore;version="[5.6.1,5.7.0)", + org.eclipse.jgit.ignore.internal;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.fsck;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.dfs;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.io;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.pack;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.reftable;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.storage.reftree;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.transport.http;version="[5.6.1,5.7.0)", + org.eclipse.jgit.internal.transport.parser;version="[5.6.1,5.7.0)", + org.eclipse.jgit.junit;version="[5.6.1,5.7.0)", + org.eclipse.jgit.junit.ssh;version="[5.6.1,5.7.0)", + org.eclipse.jgit.junit.time;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lfs;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib.internal;version="[5.6.1,5.7.0)", + org.eclipse.jgit.merge;version="[5.6.1,5.7.0)", + org.eclipse.jgit.nls;version="[5.6.1,5.7.0)", + org.eclipse.jgit.notes;version="[5.6.1,5.7.0)", + org.eclipse.jgit.patch;version="[5.6.1,5.7.0)", + org.eclipse.jgit.pgm;version="[5.6.1,5.7.0)", + org.eclipse.jgit.pgm.internal;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revplot;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk.filter;version="[5.6.1,5.7.0)", + org.eclipse.jgit.storage.file;version="[5.6.1,5.7.0)", + org.eclipse.jgit.storage.pack;version="[5.6.1,5.7.0)", + org.eclipse.jgit.submodule;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.http;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport.resolver;version="[5.6.1,5.7.0)", + org.eclipse.jgit.treewalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.treewalk.filter;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util.io;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util.sha1;version="[5.6.1,5.7.0)", org.junit;version="[4.12,5.0.0)", org.junit.experimental.theories;version="[4.12,5.0.0)", org.junit.rules;version="[4.12,5.0.0)", @@ -83,4 +84,4 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", org.tukaani.xz;version="[1.6.0,2.0)" Require-Bundle: org.hamcrest.core;bundle-version="[1.1.0,2.0.0)", org.hamcrest.library;bundle-version="[1.1.0,2.0.0)" -Export-Package: org.eclipse.jgit.transport.ssh;version="5.5.2";x-friends:="org.eclipse.jgit.ssh.apache.test" +Export-Package: org.eclipse.jgit.transport.ssh;version="5.6.1";x-friends:="org.eclipse.jgit.ssh.apache.test" diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml index 91c3418b1b..e19312f012 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit.test</artifactId> diff --git a/org.eclipse.jgit.test/src/org/eclipse/jgit/events/ChangeRecorder.java b/org.eclipse.jgit.test/src/org/eclipse/jgit/events/ChangeRecorder.java index 228df35c76..e1f6b12258 100644 --- a/org.eclipse.jgit.test/src/org/eclipse/jgit/events/ChangeRecorder.java +++ b/org.eclipse.jgit.test/src/org/eclipse/jgit/events/ChangeRecorder.java @@ -43,7 +43,6 @@ package org.eclipse.jgit.events; -import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import java.util.Arrays; @@ -99,10 +98,12 @@ public class ChangeRecorder implements WorkingTreeModifiedListener { Arrays.sort(expectedModified); Arrays.sort(actuallyDeleted); Arrays.sort(expectedDeleted); - assertArrayEquals("Unexpected modifications reported", expectedModified, - actuallyModified); - assertArrayEquals("Unexpected deletions reported", expectedDeleted, - actuallyDeleted); + assertEquals("Unexpected modifications reported", + Arrays.toString(expectedModified), + Arrays.toString(actuallyModified)); + assertEquals("Unexpected deletions reported", + Arrays.toString(expectedDeleted), + Arrays.toString(actuallyDeleted)); reset(); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java index b28e26a639..52a9dfa3e2 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java @@ -700,26 +700,26 @@ public class AddCommandTest extends RepositoryTestCase { writer.print("content b"); } - ObjectInserter newObjectInserter = db.newObjectInserter(); DirCache dc = db.lockDirCache(); - DirCacheBuilder builder = dc.builder(); + try (ObjectInserter newObjectInserter = db.newObjectInserter()) { + DirCacheBuilder builder = dc.builder(); - addEntryToBuilder("b.txt", file2, newObjectInserter, builder, 0); - addEntryToBuilder("a.txt", file, newObjectInserter, builder, 1); + addEntryToBuilder("b.txt", file2, newObjectInserter, builder, 0); + addEntryToBuilder("a.txt", file, newObjectInserter, builder, 1); - try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { - writer.print("other content"); - } - addEntryToBuilder("a.txt", file, newObjectInserter, builder, 3); - - try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { - writer.print("our content"); - } - addEntryToBuilder("a.txt", file, newObjectInserter, builder, 2) - .getObjectId(); + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { + writer.print("other content"); + } + addEntryToBuilder("a.txt", file, newObjectInserter, builder, 3); - builder.commit(); + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { + writer.print("our content"); + } + addEntryToBuilder("a.txt", file, newObjectInserter, builder, 2) + .getObjectId(); + builder.commit(); + } assertEquals( "[a.txt, mode:100644, stage:1, content:content]" + "[a.txt, mode:100644, stage:2, content:our content]" + @@ -1132,41 +1132,42 @@ public class AddCommandTest extends RepositoryTestCase { } }; - Git git = Git.open(db.getDirectory(), executableFs); String path = "a.txt"; String path2 = "a.sh"; writeTrashFile(path, "content"); writeTrashFile(path2, "binary: content"); - git.add().addFilepattern(path).addFilepattern(path2).call(); - RevCommit commit1 = git.commit().setMessage("commit").call(); - try (TreeWalk walk = new TreeWalk(db)) { - walk.addTree(commit1.getTree()); - walk.next(); - assertEquals(path2, walk.getPathString()); - assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0)); - walk.next(); - assertEquals(path, walk.getPathString()); - assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0)); + try (Git git = Git.open(db.getDirectory(), executableFs)) { + git.add().addFilepattern(path).addFilepattern(path2).call(); + RevCommit commit1 = git.commit().setMessage("commit").call(); + try (TreeWalk walk = new TreeWalk(db)) { + walk.addTree(commit1.getTree()); + walk.next(); + assertEquals(path2, walk.getPathString()); + assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0)); + walk.next(); + assertEquals(path, walk.getPathString()); + assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0)); + } } - config = db.getConfig(); config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_FILEMODE, false); config.save(); - Git git2 = Git.open(db.getDirectory(), executableFs); writeTrashFile(path2, "content2"); writeTrashFile(path, "binary: content2"); - git2.add().addFilepattern(path).addFilepattern(path2).call(); - RevCommit commit2 = git2.commit().setMessage("commit2").call(); - try (TreeWalk walk = new TreeWalk(db)) { - walk.addTree(commit2.getTree()); - walk.next(); - assertEquals(path2, walk.getPathString()); - assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0)); - walk.next(); - assertEquals(path, walk.getPathString()); - assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0)); + try (Git git2 = Git.open(db.getDirectory(), executableFs)) { + git2.add().addFilepattern(path).addFilepattern(path2).call(); + RevCommit commit2 = git2.commit().setMessage("commit2").call(); + try (TreeWalk walk = new TreeWalk(db)) { + walk.addTree(commit2.getTree()); + walk.next(); + assertEquals(path2, walk.getPathString()); + assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0)); + walk.next(); + assertEquals(path, walk.getPathString()); + assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0)); + } } } @@ -1291,18 +1292,19 @@ public class AddCommandTest extends RepositoryTestCase { FileRepositoryBuilder nestedBuilder = new FileRepositoryBuilder(); nestedBuilder.setWorkTree(gitLinkDir); - Repository nestedRepo = nestedBuilder.build(); - nestedRepo.create(); + try (Repository nestedRepo = nestedBuilder.build()) { + nestedRepo.create(); - writeTrashFile(path, "README1.md", "content"); - writeTrashFile(path, "README2.md", "content"); + writeTrashFile(path, "README1.md", "content"); + writeTrashFile(path, "README2.md", "content"); - // Commit these changes in the subrepo - try (Git git = new Git(nestedRepo)) { - git.add().addFilepattern(".").call(); - git.commit().setMessage("subrepo commit").call(); - } catch (GitAPIException e) { - throw new RuntimeException(e); + // Commit these changes in the subrepo + try (Git git = new Git(nestedRepo)) { + git.add().addFilepattern(".").call(); + git.commit().setMessage("subrepo commit").call(); + } catch (GitAPIException e) { + throw new RuntimeException(e); + } } } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java index 7e73084e8e..4d1375a2f5 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BlameCommandTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, GitHub Inc. + * Copyright (C) 2011, 2019 GitHub Inc. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -44,6 +44,7 @@ package org.eclipse.jgit.api; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.File; @@ -462,6 +463,39 @@ public class BlameCommandTest extends RepositoryTestCase { } @Test + public void testUnresolvedMergeConflict() throws Exception { + try (Git git = new Git(db)) { + RevCommit base = commitFile("file.txt", "Origin\n", "master"); + + RevCommit master = commitFile("file.txt", + "Change on master branch\n", "master"); + + git.checkout().setName("side").setCreateBranch(true) + .setStartPoint(base).call(); + RevCommit side = commitFile("file.txt", + "Conflicting change on side\n", "side"); + + checkoutBranch("refs/heads/master"); + MergeResult result = git.merge().include(side).call(); + + // The merge results in a conflict, which we do not resolve + assertTrue("Expected a conflict", + result.getConflicts().containsKey("file.txt")); + + BlameCommand command = new BlameCommand(db); + command.setFilePath("file.txt"); + BlameResult lines = command.call(); + + assertEquals(5, lines.getResultContents().size()); + assertNull(lines.getSourceCommit(0)); + assertEquals(master, lines.getSourceCommit(1)); + assertNull(lines.getSourceCommit(2)); + assertEquals(side, lines.getSourceCommit(3)); + assertNull(lines.getSourceCommit(4)); + } + } + + @Test public void testWhitespaceMerge() throws Exception { try (Git git = new Git(db)) { RevCommit base = commitFile("file.txt", join("0", "1", "2"), "master"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java index fbc2cf67e1..76958f1ddf 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java @@ -58,6 +58,8 @@ import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.MultipleParentsNotAllowedException; import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.events.ChangeRecorder; +import org.eclipse.jgit.events.ListenerHandle; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; @@ -325,6 +327,59 @@ public class CherryPickCommandTest extends RepositoryTestCase { } @Test + public void testCherryPickConflictFiresModifiedEvent() throws Exception { + ListenerHandle listener = null; + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPick(git); + ChangeRecorder recorder = new ChangeRecorder(); + listener = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + CherryPickResult result = git.cherryPick() + .include(sideCommit.getId()).call(); + assertEquals(CherryPickStatus.CONFLICTING, result.getStatus()); + recorder.assertEvent(new String[] { "a" }, ChangeRecorder.EMPTY); + } finally { + if (listener != null) { + listener.remove(); + } + } + } + + @Test + public void testCherryPickNewFileFiresModifiedEvent() throws Exception { + ListenerHandle listener = null; + try (Git git = new Git(db)) { + writeTrashFile("test.txt", "a"); + git.add().addFilepattern("test.txt").call(); + git.commit().setMessage("commit1").call(); + git.checkout().setCreateBranch(true).setName("a").call(); + + writeTrashFile("side.txt", "side"); + git.add().addFilepattern("side.txt").call(); + RevCommit side = git.commit().setMessage("side").call(); + assertNotNull(side); + + assertNotNull(git.checkout().setName(Constants.MASTER).call()); + writeTrashFile("test.txt", "b"); + assertNotNull(git.add().addFilepattern("test.txt").call()); + assertNotNull(git.commit().setMessage("commit2").call()); + + ChangeRecorder recorder = new ChangeRecorder(); + listener = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + CherryPickResult result = git.cherryPick() + .include(side.getId()).call(); + assertEquals(CherryPickStatus.OK, result.getStatus()); + recorder.assertEvent(new String[] { "side.txt" }, + ChangeRecorder.EMPTY); + } finally { + if (listener != null) { + listener.remove(); + } + } + } + + @Test public void testCherryPickOurCommitName() throws Exception { try (Git git = new Git(db)) { RevCommit sideCommit = prepareCherryPick(git); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java index 2270a6a8be..3224bbb784 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java @@ -67,6 +67,7 @@ import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.revwalk.RevBlob; @@ -96,10 +97,15 @@ public class CloneCommandTest extends RepositoryTestCase { writeTrashFile("Test.txt", "Hello world"); git.add().addFilepattern("Test.txt").call(); git.commit().setMessage("Initial commit").call(); - git.tag().setName("tag-initial").setMessage("Tag initial").call(); + Ref head = git.tag().setName("tag-initial").setMessage("Tag initial") + .call(); // create a test branch and switch to it git.checkout().setCreateBranch(true).setName("test").call(); + // create a non-standard ref + RefUpdate ru = db.updateRef("refs/meta/foo/bar"); + ru.setNewObjectId(head.getObjectId()); + ru.update(); // commit something on the test branch writeTrashFile("Test.txt", "Some change"); @@ -397,7 +403,6 @@ public class CloneCommandTest extends RepositoryTestCase { @Test public void testBareCloneRepositoryOnlyOneBranch() throws Exception { - // Same thing, but now test with bare repo File directory = createTempDirectory( "testCloneRepositoryWithBranch_bare"); CloneCommand command = Git.cloneRepository(); @@ -425,6 +430,32 @@ public class CloneCommandTest extends RepositoryTestCase { } @Test + public void testBareCloneRepositoryMirror() throws Exception { + File directory = createTempDirectory( + "testCloneRepositoryWithBranch_mirror"); + CloneCommand command = Git.cloneRepository(); + command.setBranch("refs/heads/master"); + command.setMirror(true); // implies bare repository + command.setDirectory(directory); + command.setURI(fileUri()); + Git git2 = command.call(); + addRepoToClose(git2.getRepository()); + assertNotNull(git2); + assertNotNull(git2.getRepository().resolve("tag-for-blob")); + assertNotNull(git2.getRepository().resolve("tag-initial")); + assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master"); + assertEquals("refs/heads/master, refs/heads/test", allRefNames( + git2.branchList().setListMode(ListMode.ALL).call())); + assertNotNull(git2.getRepository().exactRef("refs/meta/foo/bar")); + RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(), + Constants.DEFAULT_REMOTE_NAME); + List<RefSpec> specs = cfg.getFetchRefSpecs(); + assertEquals(1, specs.size()); + assertEquals(new RefSpec("+refs/*:refs/*"), + specs.get(0)); + } + + @Test public void testCloneRepositoryOnlyOneTag() throws Exception { File directory = createTempDirectory("testCloneRepositoryWithBranch"); CloneCommand command = Git.cloneRepository(); @@ -646,25 +677,27 @@ public class CloneCommandTest extends RepositoryTestCase { assertEquals(sub1Head, pathStatus.getHeadId()); assertEquals(sub1Head, pathStatus.getIndexId()); - SubmoduleWalk walk = SubmoduleWalk.forIndex(git2.getRepository()); - assertTrue(walk.next()); - try (Repository clonedSub1 = walk.getRepository()) { - assertNotNull(clonedSub1); - assertEquals(new File(git2.getRepository().getWorkTree(), - walk.getPath()), clonedSub1.getWorkTree()); - assertEquals( - new File(new File(git2.getRepository().getDirectory(), - "modules"), walk.getPath()), - clonedSub1.getDirectory()); - status = new SubmoduleStatusCommand(clonedSub1); - statuses = status.call(); + try (SubmoduleWalk walk = SubmoduleWalk + .forIndex(git2.getRepository())) { + assertTrue(walk.next()); + try (Repository clonedSub1 = walk.getRepository()) { + assertNotNull(clonedSub1); + assertEquals(new File(git2.getRepository().getWorkTree(), + walk.getPath()), clonedSub1.getWorkTree()); + assertEquals( + new File(new File(git2.getRepository().getDirectory(), + "modules"), walk.getPath()), + clonedSub1.getDirectory()); + status = new SubmoduleStatusCommand(clonedSub1); + statuses = status.call(); + } + assertFalse(walk.next()); } pathStatus = statuses.get(path); assertNotNull(pathStatus); assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType()); assertEquals(sub2Head, pathStatus.getHeadId()); assertEquals(sub2Head, pathStatus.getIndexId()); - assertFalse(walk.next()); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java index c028ca300c..2c51f7b9b7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java @@ -40,6 +40,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.eclipse.jgit.api; import static java.nio.charset.StandardCharsets.UTF_8; @@ -50,14 +51,10 @@ import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import java.io.File; -import java.io.IOException; import java.io.PrintWriter; import org.eclipse.jgit.api.errors.GitAPIException; -import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.NoMessageException; -import org.eclipse.jgit.errors.IncorrectObjectTypeException; -import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; @@ -76,13 +73,12 @@ import org.junit.Test; */ public class CommitAndLogCommandTest extends RepositoryTestCase { @Test - public void testSomeCommits() throws JGitInternalException, IOException, - GitAPIException { - + public void testSomeCommits() throws Exception { // do 4 commits try (Git git = new Git(db)) { git.commit().setMessage("initial commit").call(); - git.commit().setMessage("second commit").setCommitter(committer).call(); + git.commit().setMessage("second commit").setCommitter(committer) + .call(); git.commit().setMessage("third commit").setAuthor(author).call(); git.commit().setMessage("fourth commit").setAuthor(author) .setCommitter(committer).call(); @@ -90,79 +86,28 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { // check that all commits came in correctly PersonIdent defaultCommitter = new PersonIdent(db); - PersonIdent expectedAuthors[] = new PersonIdent[] { defaultCommitter, - committer, author, author }; + PersonIdent expectedAuthors[] = new PersonIdent[] { + defaultCommitter, committer, author, author }; PersonIdent expectedCommitters[] = new PersonIdent[] { defaultCommitter, committer, defaultCommitter, committer }; String expectedMessages[] = new String[] { "initial commit", "second commit", "third commit", "fourth commit" }; int l = expectedAuthors.length - 1; for (RevCommit c : commits) { - assertEquals(expectedAuthors[l].getName(), c.getAuthorIdent() - .getName()); - assertEquals(expectedCommitters[l].getName(), c.getCommitterIdent() - .getName()); + assertEquals(expectedAuthors[l].getName(), + c.getAuthorIdent().getName()); + assertEquals(expectedCommitters[l].getName(), + c.getCommitterIdent().getName()); assertEquals(c.getFullMessage(), expectedMessages[l]); l--; } assertEquals(l, -1); ReflogReader reader = db.getReflogReader(Constants.HEAD); - assertTrue(reader.getLastEntry().getComment().startsWith("commit:")); + assertTrue( + reader.getLastEntry().getComment().startsWith("commit:")); reader = db.getReflogReader(db.getBranch()); - assertTrue(reader.getLastEntry().getComment().startsWith("commit:")); - } - } - - @Test - public void testLogWithFilter() throws IOException, JGitInternalException, - GitAPIException { - - try (Git git = new Git(db)) { - // create first file - File file = new File(db.getWorkTree(), "a.txt"); - FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { - writer.print("content1"); - } - - // First commit - a.txt file - git.add().addFilepattern("a.txt").call(); - git.commit().setMessage("commit1").setCommitter(committer).call(); - - // create second file - file = new File(db.getWorkTree(), "b.txt"); - FileUtils.createNewFile(file); - try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { - writer.print("content2"); - } - - // Second commit - b.txt file - git.add().addFilepattern("b.txt").call(); - git.commit().setMessage("commit2").setCommitter(committer).call(); - - // First log - a.txt filter - int count = 0; - for (RevCommit c : git.log().addPath("a.txt").call()) { - assertEquals("commit1", c.getFullMessage()); - count++; - } - assertEquals(1, count); - - // Second log - b.txt filter - count = 0; - for (RevCommit c : git.log().addPath("b.txt").call()) { - assertEquals("commit2", c.getFullMessage()); - count++; - } - assertEquals(1, count); - - // Third log - without filter - count = 0; - for (RevCommit c : git.log().call()) { - assertEquals(committer, c.getCommitterIdent()); - count++; - } - assertEquals(2, count); + assertTrue( + reader.getLastEntry().getComment().startsWith("commit:")); } } @@ -204,19 +149,20 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { } @Test - public void testMergeEmptyBranches() throws IOException, - JGitInternalException, GitAPIException { + public void testMergeEmptyBranches() throws Exception { try (Git git = new Git(db)) { git.commit().setMessage("initial commit").call(); RefUpdate r = db.updateRef("refs/heads/side"); r.setNewObjectId(db.resolve(Constants.HEAD)); assertEquals(r.forceUpdate(), RefUpdate.Result.NEW); - RevCommit second = git.commit().setMessage("second commit").setCommitter(committer).call(); + RevCommit second = git.commit().setMessage("second commit") + .setCommitter(committer).call(); db.updateRef(Constants.HEAD).link("refs/heads/side"); - RevCommit firstSide = git.commit().setMessage("first side commit").setAuthor(author).call(); + RevCommit firstSide = git.commit().setMessage("first side commit") + .setAuthor(author).call(); - write(new File(db.getDirectory(), Constants.MERGE_HEAD), ObjectId - .toString(db.resolve("refs/heads/master"))); + write(new File(db.getDirectory(), Constants.MERGE_HEAD), + ObjectId.toString(db.resolve("refs/heads/master"))); write(new File(db.getDirectory(), Constants.MERGE_MSG), "merging"); RevCommit commit = git.commit().call(); @@ -228,8 +174,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { } @Test - public void testAddUnstagedChanges() throws IOException, - JGitInternalException, GitAPIException { + public void testAddUnstagedChanges() throws Exception { File file = new File(db.getWorkTree(), "a.txt"); FileUtils.createNewFile(file); try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { @@ -260,7 +205,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { } @Test - public void testModeChange() throws IOException, GitAPIException { + public void testModeChange() throws Exception { assumeFalse(System.getProperty("os.name").startsWith("Windows"));// SKIP try (Git git = new Git(db)) { // create file @@ -278,7 +223,8 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { FS fs = db.getFS(); fs.setExecute(file, true); git.add().addFilepattern("a.txt").call(); - git.commit().setMessage("mode change").setCommitter(committer).call(); + git.commit().setMessage("mode change").setCommitter(committer) + .call(); // pure mode change should be committable with -o option fs.setExecute(file, false); @@ -289,34 +235,32 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { } @Test - public void testCommitRange() throws GitAPIException, - JGitInternalException, MissingObjectException, - IncorrectObjectTypeException { + public void testCommitRange() throws Exception { // do 4 commits and set the range to the second and fourth one try (Git git = new Git(db)) { git.commit().setMessage("first commit").call(); RevCommit second = git.commit().setMessage("second commit") .setCommitter(committer).call(); git.commit().setMessage("third commit").setAuthor(author).call(); - RevCommit last = git.commit().setMessage("fourth commit").setAuthor( - author) - .setCommitter(committer).call(); - Iterable<RevCommit> commits = git.log().addRange(second.getId(), - last.getId()).call(); + RevCommit last = git.commit().setMessage("fourth commit") + .setAuthor(author).setCommitter(committer).call(); + Iterable<RevCommit> commits = git.log() + .addRange(second.getId(), last.getId()).call(); // check that we have the third and fourth commit PersonIdent defaultCommitter = new PersonIdent(db); - PersonIdent expectedAuthors[] = new PersonIdent[] { author, author }; + PersonIdent expectedAuthors[] = new PersonIdent[] { author, + author }; PersonIdent expectedCommitters[] = new PersonIdent[] { defaultCommitter, committer }; String expectedMessages[] = new String[] { "third commit", "fourth commit" }; int l = expectedAuthors.length - 1; for (RevCommit c : commits) { - assertEquals(expectedAuthors[l].getName(), c.getAuthorIdent() - .getName()); - assertEquals(expectedCommitters[l].getName(), c.getCommitterIdent() - .getName()); + assertEquals(expectedAuthors[l].getName(), + c.getAuthorIdent().getName()); + assertEquals(expectedCommitters[l].getName(), + c.getCommitterIdent().getName()); assertEquals(c.getFullMessage(), expectedMessages[l]); l--; } @@ -325,8 +269,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { } @Test - public void testCommitAmend() throws JGitInternalException, IOException, - GitAPIException { + public void testCommitAmend() throws Exception { try (Git git = new Git(db)) { git.commit().setMessage("first comit").call(); // typo git.commit().setAmend(true).setMessage("first commit").call(); @@ -348,15 +291,14 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { } @Test - public void testInsertChangeId() throws JGitInternalException, - GitAPIException { + public void testInsertChangeId() throws Exception { try (Git git = new Git(db)) { String messageHeader = "Some header line\n\nSome detail explanation\n"; String changeIdTemplate = "\nChange-Id: I" + ObjectId.zeroId().getName() + "\n"; String messageFooter = "Some foooter lines\nAnother footer line\n"; - RevCommit commit = git.commit().setMessage( - messageHeader + messageFooter) + RevCommit commit = git.commit() + .setMessage(messageHeader + messageFooter) .setInsertChangeId(true).call(); // we should find a real change id (at the end of the file) byte[] chars = commit.getFullMessage().getBytes(UTF_8); @@ -364,11 +306,12 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { String lastLine = RawParseUtils.decode(chars, lastLineBegin + 1, chars.length); assertTrue(lastLine.contains("Change-Id:")); - assertFalse(lastLine.contains( - "Change-Id: I" + ObjectId.zeroId().getName())); + assertFalse(lastLine + .contains("Change-Id: I" + ObjectId.zeroId().getName())); - commit = git.commit().setMessage( - messageHeader + changeIdTemplate + messageFooter) + commit = git.commit() + .setMessage( + messageHeader + changeIdTemplate + messageFooter) .setInsertChangeId(true).call(); // we should find a real change id (in the line as dictated by the // template) @@ -383,11 +326,12 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { String line = RawParseUtils.decode(chars, lineStart, lineEnd); assertTrue(line.contains("Change-Id:")); - assertFalse(line.contains( - "Change-Id: I" + ObjectId.zeroId().getName())); + assertFalse(line + .contains("Change-Id: I" + ObjectId.zeroId().getName())); - commit = git.commit().setMessage( - messageHeader + changeIdTemplate + messageFooter) + commit = git.commit() + .setMessage( + messageHeader + changeIdTemplate + messageFooter) .setInsertChangeId(false).call(); // we should find the untouched template chars = commit.getFullMessage().getBytes(UTF_8); @@ -400,8 +344,8 @@ public class CommitAndLogCommandTest extends RepositoryTestCase { line = RawParseUtils.decode(chars, lineStart, lineEnd); - assertTrue(commit.getFullMessage().contains( - "Change-Id: I" + ObjectId.zeroId().getName())); + assertTrue(commit.getFullMessage() + .contains("Change-Id: I" + ObjectId.zeroId().getName())); } } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java index 3bde0eb33f..b5661e8440 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java @@ -148,9 +148,10 @@ public class CommitCommandTest extends RepositoryTestCase { writeTrashFile(path, "content"); git.add().addFilepattern(path).call(); RevCommit commit1 = git.commit().setMessage("commit").call(); - TreeWalk walk = TreeWalk.forPath(db, path, commit1.getTree()); - assertNotNull(walk); - assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0)); + try (TreeWalk walk = TreeWalk.forPath(db, path, commit1.getTree())) { + assertNotNull(walk); + assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0)); + } FS nonExecutableFs = new FS() { @@ -204,9 +205,10 @@ public class CommitCommandTest extends RepositoryTestCase { writeTrashFile(path, "content2"); RevCommit commit2 = git2.commit().setOnly(path).setMessage("commit2") .call(); - walk = TreeWalk.forPath(db, path, commit2.getTree()); - assertNotNull(walk); - assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0)); + try (TreeWalk walk = TreeWalk.forPath(db, path, commit2.getTree())) { + assertNotNull(walk); + assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0)); + } } @Test @@ -225,15 +227,16 @@ public class CommitCommandTest extends RepositoryTestCase { assertNotNull(repo); addRepoToClose(repo); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertEquals(path, generator.getPath()); - assertEquals(commit, generator.getObjectId()); - assertEquals(uri, generator.getModulesUrl()); - assertEquals(path, generator.getModulesPath()); - assertEquals(uri, generator.getConfigUrl()); - try (Repository subModRepo = generator.getRepository()) { - assertNotNull(subModRepo); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertEquals(path, generator.getPath()); + assertEquals(commit, generator.getObjectId()); + assertEquals(uri, generator.getModulesUrl()); + assertEquals(path, generator.getModulesPath()); + assertEquals(uri, generator.getConfigUrl()); + try (Repository subModRepo = generator.getRepository()) { + assertNotNull(subModRepo); + } } assertEquals(commit, repo.resolve(Constants.HEAD)); @@ -275,15 +278,16 @@ public class CommitCommandTest extends RepositoryTestCase { assertNotNull(repo); addRepoToClose(repo); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertEquals(path, generator.getPath()); - assertEquals(commit2, generator.getObjectId()); - assertEquals(uri, generator.getModulesUrl()); - assertEquals(path, generator.getModulesPath()); - assertEquals(uri, generator.getConfigUrl()); - try (Repository subModRepo = generator.getRepository()) { - assertNotNull(subModRepo); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertEquals(path, generator.getPath()); + assertEquals(commit2, generator.getObjectId()); + assertEquals(uri, generator.getModulesUrl()); + assertEquals(path, generator.getModulesPath()); + assertEquals(uri, generator.getConfigUrl()); + try (Repository subModRepo = generator.getRepository()) { + assertNotNull(subModRepo); + } } assertEquals(commit2, repo.resolve(Constants.HEAD)); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java index 47806cb99d..d0dfd1ab92 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java @@ -142,8 +142,6 @@ public class EolRepositoryTest extends RepositoryTestCase { protected String CONTENT_MIXED; - private TreeWalk walk; - /** work tree root .gitattributes */ private File dotGitattributes; @@ -689,27 +687,25 @@ public class EolRepositoryTest extends RepositoryTestCase { private void collectRepositoryState() throws Exception { dirCache = db.readDirCache(); - walk = beginWalk(); - if (dotGitattributes != null) - collectEntryContentAndAttributes(F, ".gitattributes", null); - collectEntryContentAndAttributes(F, fileCRLF.getName(), entryCRLF); - collectEntryContentAndAttributes(F, fileLF.getName(), entryLF); - collectEntryContentAndAttributes(F, fileMixed.getName(), entryMixed); - endWalk(); - } - - private TreeWalk beginWalk() throws Exception { - TreeWalk newWalk = new TreeWalk(db); - newWalk.addTree(new FileTreeIterator(db)); - newWalk.addTree(new DirCacheIterator(db.readDirCache())); - return newWalk; - } - - private void endWalk() throws IOException { - assertFalse("Not all files tested", walk.next()); + try (TreeWalk walk = new TreeWalk(db)) { + walk.addTree(new FileTreeIterator(db)); + walk.addTree(new DirCacheIterator(db.readDirCache())); + if (dotGitattributes != null) { + collectEntryContentAndAttributes(walk, F, ".gitattributes", + null); + } + collectEntryContentAndAttributes(walk, F, fileCRLF.getName(), + entryCRLF); + collectEntryContentAndAttributes(walk, F, fileLF.getName(), + entryLF); + collectEntryContentAndAttributes(walk, F, fileMixed.getName(), + entryMixed); + assertFalse("Not all files tested", walk.next()); + } } - private void collectEntryContentAndAttributes(FileMode type, String pathName, + private void collectEntryContentAndAttributes(TreeWalk walk, FileMode type, + String pathName, ActualEntry e) throws IOException { assertTrue("walk has entry", walk.next()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchAndPullCommandsRecurseSubmodulesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchAndPullCommandsRecurseSubmodulesTest.java index 73a705b252..08ded559f5 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchAndPullCommandsRecurseSubmodulesTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchAndPullCommandsRecurseSubmodulesTest.java @@ -343,19 +343,22 @@ public class FetchAndPullCommandsRecurseSubmodulesTest extends RepositoryTestCas private void assertSubmoduleFetchHeads(ObjectId expectedHead1, ObjectId expectedHead2) throws Exception { + Object newHead1 = null; + ObjectId newHead2 = null; try (SubmoduleWalk walk = SubmoduleWalk .forIndex(git2.getRepository())) { assertTrue(walk.next()); - Repository r = walk.getRepository(); - ObjectId newHead1 = r.resolve(Constants.FETCH_HEAD); - ObjectId newHead2; - try (SubmoduleWalk walk2 = SubmoduleWalk.forIndex(r)) { - assertTrue(walk2.next()); - newHead2 = walk2.getRepository().resolve(Constants.FETCH_HEAD); + try (Repository r = walk.getRepository()) { + newHead1 = r.resolve(Constants.FETCH_HEAD); + try (SubmoduleWalk walk2 = SubmoduleWalk.forIndex(r)) { + assertTrue(walk2.next()); + try (Repository r2 = walk2.getRepository()) { + newHead2 = r2.resolve(Constants.FETCH_HEAD); + } + } } - - assertEquals(expectedHead1, newHead1); - assertEquals(expectedHead2, newHead2); } + assertEquals(expectedHead1, newHead1); + assertEquals(expectedHead2, newHead2); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogFilterTest.java new file mode 100644 index 0000000000..988ca58906 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogFilterTest.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2019, John Tipper <John_Tipper@hotmail.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.api; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Iterator; + +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.util.FileUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Testing the log command with include and exclude filters + */ +public class LogFilterTest extends RepositoryTestCase { + private Git git; + + @Before + public void setup() throws Exception { + super.setUp(); + git = new Git(db); + + // create first file + File file = new File(db.getWorkTree(), "a.txt"); + FileUtils.createNewFile(file); + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { + writer.print("content1"); + } + + // First commit - a.txt file + git.add().addFilepattern("a.txt").call(); + git.commit().setMessage("commit1").setCommitter(committer).call(); + + // create second file + file = new File(db.getWorkTree(), "b.txt"); + FileUtils.createNewFile(file); + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { + writer.print("content2"); + } + + // Second commit - b.txt file + git.add().addFilepattern("b.txt").call(); + git.commit().setMessage("commit2").setCommitter(committer).call(); + + // create third file + Path includeSubdir = Paths.get(db.getWorkTree().toString(), + "subdir-include"); + includeSubdir.toFile().mkdirs(); + file = Paths.get(includeSubdir.toString(), "c.txt").toFile(); + FileUtils.createNewFile(file); + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { + writer.print("content3"); + } + + // Third commit - c.txt file + git.add().addFilepattern("subdir-include").call(); + git.commit().setMessage("commit3").setCommitter(committer).call(); + + // create fourth file + Path excludeSubdir = Paths.get(db.getWorkTree().toString(), + "subdir-exclude"); + excludeSubdir.toFile().mkdirs(); + file = Paths.get(excludeSubdir.toString(), "d.txt").toFile(); + FileUtils.createNewFile(file); + try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) { + writer.print("content4"); + } + + // Fourth commit - d.txt file + git.add().addFilepattern("subdir-exclude").call(); + git.commit().setMessage("commit4").setCommitter(committer).call(); + } + + @After + @Override + public void tearDown() throws Exception { + git.close(); + super.tearDown(); + } + + @Test + public void testLogWithFilterCanDistinguishFilesByPath() throws Exception { + int count = 0; + for (RevCommit c : git.log().addPath("a.txt").call()) { + assertEquals("commit1", c.getFullMessage()); + count++; + } + assertEquals(1, count); + + count = 0; + for (RevCommit c : git.log().addPath("b.txt").call()) { + assertEquals("commit2", c.getFullMessage()); + count++; + } + assertEquals(1, count); + } + + @Test + public void testLogWithFilterCanIncludeFilesInDirectory() throws Exception { + int count = 0; + for (RevCommit c : git.log().addPath("subdir-include").call()) { + assertEquals("commit3", c.getFullMessage()); + count++; + } + assertEquals(1, count); + } + + @Test + public void testLogWithFilterCanExcludeFilesInDirectory() throws Exception { + int count = 0; + Iterator it = git.log().excludePath("subdir-exclude").call().iterator(); + while (it.hasNext()) { + it.next(); + count++; + } + // of all the commits, we expect to filter out only d.txt + assertEquals(3, count); + } + + @Test + public void testLogWithoutFilter() throws Exception { + int count = 0; + for (RevCommit c : git.log().call()) { + assertEquals(committer, c.getCommitterIdent()); + count++; + } + assertEquals(4, count); + } + + @Test + public void testLogWithFilterCanExcludeAndIncludeFilesInDifferentDirectories() + throws Exception { + int count = 0; + Iterator it = git.log().addPath("subdir-include") + .excludePath("subdir-exclude").call().iterator(); + while (it.hasNext()) { + it.next(); + count++; + } + // we expect to include c.txt + assertEquals(1, count); + } + + @Test + public void testLogWithFilterExcludeAndIncludeSameFileIncludesNothing() + throws Exception { + int count = 0; + Iterator it = git.log().addPath("subdir-exclude") + .excludePath("subdir-exclude").call().iterator(); + + while (it.hasNext()) { + it.next(); + count++; + } + // we expect the exclude to trump everything + assertEquals(0, count); + } + + @Test + public void testLogWithFilterCanExcludeFileAndDirectory() throws Exception { + int count = 0; + Iterator it = git.log().excludePath("b.txt") + .excludePath("subdir-exclude").call().iterator(); + + while (it.hasNext()) { + it.next(); + count++; + } + // we expect a.txt and c.txt + assertEquals(2, count); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java index 4401bcedb3..7c8ec23848 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java @@ -57,12 +57,9 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; -import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Set; import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler; @@ -78,6 +75,7 @@ import org.eclipse.jgit.errors.AmbiguousObjectException; import org.eclipse.jgit.errors.IllegalTodoFileModification; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.events.ChangeRecorder; import org.eclipse.jgit.events.ListenerHandle; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.AbbreviatedObjectId; @@ -2014,10 +2012,9 @@ public class RebaseCommandTest extends RepositoryTestCase { checkoutBranch("refs/heads/topic"); writeTrashFile("sub/file0", "unstaged modified file0"); - Set<String> modifiedFiles = new HashSet<>(); + ChangeRecorder recorder = new ChangeRecorder(); ListenerHandle handle = db.getListenerList() - .addWorkingTreeModifiedListener( - event -> modifiedFiles.addAll(event.getModified())); + .addWorkingTreeModifiedListener(recorder); try { // rebase assertEquals(Status.OK, git.rebase() @@ -2035,9 +2032,8 @@ public class RebaseCommandTest extends RepositoryTestCase { + "[sub/file0, mode:100644, content:file0]", indexState(CONTENT)); assertEquals(RepositoryState.SAFE, db.getRepositoryState()); - List<String> modified = new ArrayList<>(modifiedFiles); - Collections.sort(modified); - assertEquals("[file1, sub/file0]", modified.toString()); + recorder.assertEvent(new String[] { "file1", "file2", "sub/file0" }, + new String[0]); } @Test @@ -2136,10 +2132,12 @@ public class RebaseCommandTest extends RepositoryTestCase { private List<DiffEntry> getStashedDiff() throws AmbiguousObjectException, IncorrectObjectTypeException, IOException, MissingObjectException { ObjectId stashId = db.resolve("stash@{0}"); - RevWalk revWalk = new RevWalk(db); - RevCommit stashCommit = revWalk.parseCommit(stashId); - List<DiffEntry> diffs = diffWorkingAgainstHead(stashCommit, revWalk); - return diffs; + try (RevWalk revWalk = new RevWalk(db)) { + RevCommit stashCommit = revWalk.parseCommit(stashId); + List<DiffEntry> diffs = diffWorkingAgainstHead(stashCommit, + revWalk); + return diffs; + } } private TreeWalk createTreeWalk() { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java index 5868482c88..adc64d227e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java @@ -69,83 +69,90 @@ public class AttributesHandlerTest extends RepositoryTestCase { private static final FileMode F = FileMode.REGULAR_FILE; - private TreeWalk walk; - @Test public void testExpandNonMacro1() throws Exception { setupRepo(null, null, null, "*.txt text"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("text")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("text")); + assertFalse("Not all files tested", walk.next()); + } } @Test public void testExpandNonMacro2() throws Exception { setupRepo(null, null, null, "*.txt -text"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("-text")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("-text")); + assertFalse("Not all files tested", walk.next()); + } } @Test public void testExpandNonMacro3() throws Exception { setupRepo(null, null, null, "*.txt !text"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("")); + assertFalse("Not all files tested", walk.next()); + } } @Test public void testExpandNonMacro4() throws Exception { setupRepo(null, null, null, "*.txt text=auto"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("text=auto")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("text=auto")); + assertFalse("Not all files tested", walk.next()); + } } @Test public void testExpandBuiltInMacro1() throws Exception { setupRepo(null, null, null, "*.txt binary"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("binary -diff -merge -text")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", + attrs("binary -diff -merge -text")); + assertFalse("Not all files tested", walk.next()); + } } @Test public void testExpandBuiltInMacro2() throws Exception { setupRepo(null, null, null, "*.txt -binary"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("-binary diff merge text")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", + attrs("-binary diff merge text")); + assertFalse("Not all files tested", walk.next()); + } } @Test public void testExpandBuiltInMacro3() throws Exception { setupRepo(null, null, null, "*.txt !binary"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("")); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -153,44 +160,48 @@ public class AttributesHandlerTest extends RepositoryTestCase { setupRepo( "[attr]foo a -b !c d=e", null, null, "*.txt foo"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("foo a -b d=e")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("foo a -b d=e")); + assertFalse("Not all files tested", walk.next()); + } } @Test public void testCustomGlobalMacro2() throws Exception { setupRepo("[attr]foo a -b !c d=e", null, null, "*.txt -foo"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("-foo -a b d=e")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("-foo -a b d=e")); + assertFalse("Not all files tested", walk.next()); + } } @Test public void testCustomGlobalMacro3() throws Exception { setupRepo("[attr]foo a -b !c d=e", null, null, "*.txt !foo"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("")); + assertFalse("Not all files tested", walk.next()); + } } @Test public void testCustomGlobalMacro4() throws Exception { setupRepo("[attr]foo a -b !c d=e", null, null, "*.txt foo=bar"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("foo=bar a -b d=bar")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("foo=bar a -b d=bar")); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -198,11 +209,12 @@ public class AttributesHandlerTest extends RepositoryTestCase { setupRepo("[attr]foo bar1", "[attr]foo bar2", null, "*.txt foo"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("foo bar2")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("foo bar2")); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -211,12 +223,13 @@ public class AttributesHandlerTest extends RepositoryTestCase { null, "[attr]foo bar3", "*.txt foo"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("foo bar3")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("foo bar3")); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -224,12 +237,13 @@ public class AttributesHandlerTest extends RepositoryTestCase { setupRepo("[attr]foo bar1", "[attr]foo bar2", "[attr]foo bar3", "*.txt foo"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("foo bar2")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("foo bar2")); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -238,11 +252,12 @@ public class AttributesHandlerTest extends RepositoryTestCase { "[attr]foo x bar -foo", null, null, "*.txt foo"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("foo x bar")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("foo x bar")); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -250,11 +265,12 @@ public class AttributesHandlerTest extends RepositoryTestCase { setupRepo( "[attr]foo x -bar\n[attr]bar y -foo", null, null, "*.txt foo"); - walk = beginWalk(); - assertIteration(D, "sub"); - assertIteration(F, "sub/.gitattributes"); - assertIteration(F, "sub/a.txt", attrs("foo x -bar -y")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/.gitattributes"); + assertIteration(walk, F, "sub/a.txt", attrs("foo x -bar -y")); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -266,23 +282,30 @@ public class AttributesHandlerTest extends RepositoryTestCase { // apply to any of the files here. It would match for a // further subdirectory sub/sub. The sub/ rules must match // only for directories. - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "sub", attrs("global")); - assertIteration(F, "sub/.gitattributes", attrs("init top_sub")); - assertIteration(F, "sub/a.txt", attrs("init foo top top_sub")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "sub", attrs("global")); + assertIteration(walk, F, "sub/.gitattributes", + attrs("init top_sub")); + assertIteration(walk, F, "sub/a.txt", + attrs("init foo top top_sub")); + assertFalse("Not all files tested", walk.next()); + } // All right, let's see that they *do* apply in sub/sub: writeTrashFile("sub/sub/b.txt", "b"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "sub", attrs("global")); - assertIteration(F, "sub/.gitattributes", attrs("init top_sub")); - assertIteration(F, "sub/a.txt", attrs("init foo top top_sub")); - assertIteration(D, "sub/sub", attrs("init subsub2 top_sub global")); - assertIteration(F, "sub/sub/b.txt", - attrs("init foo subsub top top_sub")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "sub", attrs("global")); + assertIteration(walk, F, "sub/.gitattributes", + attrs("init top_sub")); + assertIteration(walk, F, "sub/a.txt", + attrs("init foo top top_sub")); + assertIteration(walk, D, "sub/sub", + attrs("init subsub2 top_sub global")); + assertIteration(walk, F, "sub/sub/b.txt", + attrs("init foo subsub top top_sub")); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -293,16 +316,17 @@ public class AttributesHandlerTest extends RepositoryTestCase { writeTrashFile("sub/b.jar", "bj"); writeTrashFile("sub/b.xml", "bx"); // On foo.xml/bar.jar we must not have 'xml' - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "foo.xml", attrs("xml")); - assertIteration(F, "foo.xml/bar.jar", attrs("jar")); - assertIteration(F, "foo.xml/bar.xml", attrs("xml")); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - assertIteration(F, "sub/b.jar", attrs("jar")); - assertIteration(F, "sub/b.xml", attrs("xml")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "foo.xml", attrs("xml")); + assertIteration(walk, F, "foo.xml/bar.jar", attrs("jar")); + assertIteration(walk, F, "foo.xml/bar.xml", attrs("xml")); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertIteration(walk, F, "sub/b.jar", attrs("jar")); + assertIteration(walk, F, "sub/b.xml", attrs("xml")); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -314,18 +338,19 @@ public class AttributesHandlerTest extends RepositoryTestCase { writeTrashFile("sub/b.jar", "bj"); writeTrashFile("sub/b.xml", "bx"); writeTrashFile("sub/foo/b.jar", "bf"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "foo", attrs("xml")); - assertIteration(F, "foo/bar.jar", attrs("jar")); - assertIteration(F, "foo/bar.xml"); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - assertIteration(F, "sub/b.jar", attrs("jar")); - assertIteration(F, "sub/b.xml"); - assertIteration(D, "sub/foo", attrs("sub xml")); - assertIteration(F, "sub/foo/b.jar", attrs("jar")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "foo", attrs("xml")); + assertIteration(walk, F, "foo/bar.jar", attrs("jar")); + assertIteration(walk, F, "foo/bar.xml"); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertIteration(walk, F, "sub/b.jar", attrs("jar")); + assertIteration(walk, F, "sub/b.xml"); + assertIteration(walk, D, "sub/foo", attrs("sub xml")); + assertIteration(walk, F, "sub/foo/b.jar", attrs("jar")); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -337,18 +362,19 @@ public class AttributesHandlerTest extends RepositoryTestCase { writeTrashFile("sub/b.xml", "bx"); writeTrashFile("sub/foo/b.jar", "bf"); // On foo.xml/bar.jar we must not have 'xml' - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "foo"); - assertIteration(F, "foo/bar.jar", attrs("jar xml")); - assertIteration(F, "foo/bar.xml", attrs("xml")); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - assertIteration(F, "sub/b.jar", attrs("jar")); - assertIteration(F, "sub/b.xml"); - assertIteration(D, "sub/foo"); - assertIteration(F, "sub/foo/b.jar", attrs("jar")); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "foo"); + assertIteration(walk, F, "foo/bar.jar", attrs("jar xml")); + assertIteration(walk, F, "foo/bar.xml", attrs("xml")); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertIteration(walk, F, "sub/b.jar", attrs("jar")); + assertIteration(walk, F, "sub/b.xml"); + assertIteration(walk, D, "sub/foo"); + assertIteration(walk, F, "sub/foo/b.jar", attrs("jar")); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -357,27 +383,29 @@ public class AttributesHandlerTest extends RepositoryTestCase { writeTrashFile("sub/a.txt", "1"); writeTrashFile("foo/sext", "2"); writeTrashFile("foo/s.txt", "3"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "foo"); - assertIteration(F, "foo/s.txt", attrs("bar")); - assertIteration(F, "foo/sext", attrs("bar")); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "foo"); + assertIteration(walk, F, "foo/s.txt", attrs("bar")); + assertIteration(walk, F, "foo/sext", attrs("bar")); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertFalse("Not all files tested", walk.next()); + } } @Test public void testPrefixMatchNot() throws Exception { setupRepo(null, null, "sub/new bar", null); writeTrashFile("sub/new/foo.txt", "1"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - assertIteration(D, "sub/new", attrs("bar")); - assertIteration(F, "sub/new/foo.txt"); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertIteration(walk, D, "sub/new", attrs("bar")); + assertIteration(walk, F, "sub/new/foo.txt"); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -385,14 +413,15 @@ public class AttributesHandlerTest extends RepositoryTestCase { setupRepo(null, null, "s[t-v]b/n[de]w bar", null); writeTrashFile("sub/new/foo.txt", "1"); writeTrashFile("sub/ndw", "2"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - assertIteration(F, "sub/ndw", attrs("bar")); - assertIteration(D, "sub/new", attrs("bar")); - assertIteration(F, "sub/new/foo.txt"); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertIteration(walk, F, "sub/ndw", attrs("bar")); + assertIteration(walk, D, "sub/new", attrs("bar")); + assertIteration(walk, F, "sub/new/foo.txt"); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -400,15 +429,16 @@ public class AttributesHandlerTest extends RepositoryTestCase { setupRepo(null, null, "sub/new/* bar", null); writeTrashFile("sub/new/foo.txt", "1"); writeTrashFile("sub/new/lower/foo.txt", "2"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - assertIteration(D, "sub/new"); - assertIteration(F, "sub/new/foo.txt", attrs("bar")); - assertIteration(D, "sub/new/lower", attrs("bar")); - assertIteration(F, "sub/new/lower/foo.txt"); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertIteration(walk, D, "sub/new"); + assertIteration(walk, F, "sub/new/foo.txt", attrs("bar")); + assertIteration(walk, D, "sub/new/lower", attrs("bar")); + assertIteration(walk, F, "sub/new/lower/foo.txt"); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -417,20 +447,21 @@ public class AttributesHandlerTest extends RepositoryTestCase { writeTrashFile("sub/new/foo.txt", "1"); writeTrashFile("foo/sub/new/foo.txt", "2"); writeTrashFile("sub/sub/new/foo.txt", "3"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "foo"); - assertIteration(D, "foo/sub"); - assertIteration(D, "foo/sub/new"); - assertIteration(F, "foo/sub/new/foo.txt"); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - assertIteration(D, "sub/new", attrs("bar")); - assertIteration(F, "sub/new/foo.txt"); - assertIteration(D, "sub/sub"); - assertIteration(D, "sub/sub/new"); - assertIteration(F, "sub/sub/new/foo.txt"); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "foo"); + assertIteration(walk, D, "foo/sub"); + assertIteration(walk, D, "foo/sub/new"); + assertIteration(walk, F, "foo/sub/new/foo.txt"); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertIteration(walk, D, "sub/new", attrs("bar")); + assertIteration(walk, F, "sub/new/foo.txt"); + assertIteration(walk, D, "sub/sub"); + assertIteration(walk, D, "sub/sub/new"); + assertIteration(walk, F, "sub/sub/new/foo.txt"); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -438,17 +469,18 @@ public class AttributesHandlerTest extends RepositoryTestCase { setupRepo(null, null, "**/sub/new/ bar", null); writeTrashFile("sub/new/foo.txt", "1"); writeTrashFile("foo/sub/new/foo.txt", "2"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "foo"); - assertIteration(D, "foo/sub"); - assertIteration(D, "foo/sub/new", attrs("bar")); - assertIteration(F, "foo/sub/new/foo.txt"); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - assertIteration(D, "sub/new", attrs("bar")); - assertIteration(F, "sub/new/foo.txt"); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "foo"); + assertIteration(walk, D, "foo/sub"); + assertIteration(walk, D, "foo/sub/new", attrs("bar")); + assertIteration(walk, F, "foo/sub/new/foo.txt"); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertIteration(walk, D, "sub/new", attrs("bar")); + assertIteration(walk, F, "sub/new/foo.txt"); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -457,20 +489,21 @@ public class AttributesHandlerTest extends RepositoryTestCase { writeTrashFile("sub/new/foo.txt", "1"); writeTrashFile("foo/sub/new/foo.txt", "2"); writeTrashFile("sub/sub/new/foo.txt", "3"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "foo"); - assertIteration(D, "foo/sub"); - assertIteration(D, "foo/sub/new", attrs("bar")); - assertIteration(F, "foo/sub/new/foo.txt"); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - assertIteration(D, "sub/new", attrs("bar")); - assertIteration(F, "sub/new/foo.txt"); - assertIteration(D, "sub/sub"); - assertIteration(D, "sub/sub/new", attrs("bar")); - assertIteration(F, "sub/sub/new/foo.txt"); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "foo"); + assertIteration(walk, D, "foo/sub"); + assertIteration(walk, D, "foo/sub/new", attrs("bar")); + assertIteration(walk, F, "foo/sub/new/foo.txt"); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertIteration(walk, D, "sub/new", attrs("bar")); + assertIteration(walk, F, "sub/new/foo.txt"); + assertIteration(walk, D, "sub/sub"); + assertIteration(walk, D, "sub/sub/new", attrs("bar")); + assertIteration(walk, F, "sub/sub/new/foo.txt"); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -479,20 +512,21 @@ public class AttributesHandlerTest extends RepositoryTestCase { writeTrashFile("sub/new/foo.txt", "1"); writeTrashFile("foo/sub/new/foo.txt", "2"); writeTrashFile("sub/sub/new/foo.txt", "3"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "foo"); - assertIteration(D, "foo/sub"); - assertIteration(D, "foo/sub/new", attrs("bar")); - assertIteration(F, "foo/sub/new/foo.txt"); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - assertIteration(D, "sub/new", attrs("bar")); - assertIteration(F, "sub/new/foo.txt"); - assertIteration(D, "sub/sub"); - assertIteration(D, "sub/sub/new", attrs("bar")); - assertIteration(F, "sub/sub/new/foo.txt"); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "foo"); + assertIteration(walk, D, "foo/sub"); + assertIteration(walk, D, "foo/sub/new", attrs("bar")); + assertIteration(walk, F, "foo/sub/new/foo.txt"); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertIteration(walk, D, "sub/new", attrs("bar")); + assertIteration(walk, F, "sub/new/foo.txt"); + assertIteration(walk, D, "sub/sub"); + assertIteration(walk, D, "sub/sub/new", attrs("bar")); + assertIteration(walk, F, "sub/sub/new/foo.txt"); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -500,17 +534,18 @@ public class AttributesHandlerTest extends RepositoryTestCase { setupRepo(null, null, "s[uv]b/n*/ bar", null); writeTrashFile("sub/new/foo.txt", "1"); writeTrashFile("foo/sub/new/foo.txt", "2"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "foo"); - assertIteration(D, "foo/sub"); - assertIteration(D, "foo/sub/new"); - assertIteration(F, "foo/sub/new/foo.txt"); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - assertIteration(D, "sub/new", attrs("bar")); - assertIteration(F, "sub/new/foo.txt"); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "foo"); + assertIteration(walk, D, "foo/sub"); + assertIteration(walk, D, "foo/sub/new"); + assertIteration(walk, F, "foo/sub/new/foo.txt"); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertIteration(walk, D, "sub/new", attrs("bar")); + assertIteration(walk, F, "sub/new/foo.txt"); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -519,30 +554,32 @@ public class AttributesHandlerTest extends RepositoryTestCase { writeTrashFile("sub/new/foo.txt", "1"); writeTrashFile("foo/sub/new/foo.txt", "2"); writeTrashFile("foo/new", "3"); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(D, "foo"); - assertIteration(F, "foo/new"); - assertIteration(D, "foo/sub"); - assertIteration(D, "foo/sub/new", attrs("bar")); - assertIteration(F, "foo/sub/new/foo.txt"); - assertIteration(D, "sub"); - assertIteration(F, "sub/a.txt"); - assertIteration(D, "sub/new", attrs("bar")); - assertIteration(F, "sub/new/foo.txt"); - endWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, D, "foo"); + assertIteration(walk, F, "foo/new"); + assertIteration(walk, D, "foo/sub"); + assertIteration(walk, D, "foo/sub/new", attrs("bar")); + assertIteration(walk, F, "foo/sub/new/foo.txt"); + assertIteration(walk, D, "sub"); + assertIteration(walk, F, "sub/a.txt"); + assertIteration(walk, D, "sub/new", attrs("bar")); + assertIteration(walk, F, "sub/new/foo.txt"); + assertFalse("Not all files tested", walk.next()); + } } private static Collection<Attribute> attrs(String s) { return new AttributesRule("*", s).getAttributes(); } - private void assertIteration(FileMode type, String pathName) + private void assertIteration(TreeWalk walk, FileMode type, String pathName) throws IOException { - assertIteration(type, pathName, Collections.<Attribute> emptyList()); + assertIteration(walk, type, pathName, + Collections.<Attribute> emptyList()); } - private void assertIteration(FileMode type, String pathName, + private void assertIteration(TreeWalk walk, FileMode type, String pathName, Collection<Attribute> expectedAttrs) throws IOException { assertTrue("walk has entry", walk.next()); assertEquals(pathName, walk.getPathString()); @@ -611,8 +648,4 @@ public class AttributesHandlerTest extends RepositoryTestCase { newWalk.addTree(new FileTreeIterator(db)); return newWalk; } - - private void endWalk() throws IOException { - assertFalse("Not all files tested", walk.next()); - } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java index 837de74818..cb37d8978a 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeDirCacheIteratorTest.java @@ -78,8 +78,6 @@ public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase { private Git git; - private TreeWalk walk; - @Override @Before public void setUp() throws Exception { @@ -105,23 +103,25 @@ public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase { // Adds file to index git.add().addFilepattern(".").call(); - walk = beginWalk(); - - assertIteration(F, ".gitattributes"); - assertIteration(F, "readme.txt", asList(EOL_LF)); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, F, "readme.txt", asList(EOL_LF)); - assertIteration(D, "src"); + assertIteration(walk, D, "src"); - assertIteration(D, "src/config"); - assertIteration(F, "src/config/.gitattributes"); - assertIteration(F, "src/config/readme.txt", asList(DELTA_UNSET)); - assertIteration(F, "src/config/windows.file", null); - assertIteration(F, "src/config/windows.txt", asList(DELTA_UNSET)); + assertIteration(walk, D, "src/config"); + assertIteration(walk, F, "src/config/.gitattributes"); + assertIteration(walk, F, "src/config/readme.txt", + asList(DELTA_UNSET)); + assertIteration(walk, F, "src/config/windows.file", null); + assertIteration(walk, F, "src/config/windows.txt", + asList(DELTA_UNSET)); - assertIteration(F, "windows.file", null); - assertIteration(F, "windows.txt", asList(EOL_LF)); + assertIteration(walk, F, "windows.file", null); + assertIteration(walk, F, "windows.txt", asList(EOL_LF)); - endWalk(); + assertFalse("Not all files tested", walk.next()); + } } /** @@ -138,17 +138,18 @@ public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase { // Adds file to index git.add().addFilepattern(".").call(); - walk = beginWalk(); - assertIteration(F, "l0.txt"); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, "l0.txt"); - assertIteration(D, "level1"); - assertIteration(F, "level1/l1.txt"); + assertIteration(walk, D, "level1"); + assertIteration(walk, F, "level1/l1.txt"); - assertIteration(D, "level1/level2"); - assertIteration(F, "level1/level2/l2.txt"); + assertIteration(walk, D, "level1/level2"); + assertIteration(walk, F, "level1/level2/l2.txt"); - endWalk(); + assertFalse("Not all files tested", walk.next()); + } } /** @@ -166,18 +167,19 @@ public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase { // Adds file to index git.add().addFilepattern(".").call(); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); - assertIteration(F, "l0.txt"); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, F, "l0.txt"); - assertIteration(D, "level1"); - assertIteration(F, "level1/l1.txt"); + assertIteration(walk, D, "level1"); + assertIteration(walk, F, "level1/l1.txt"); - assertIteration(D, "level1/level2"); - assertIteration(F, "level1/level2/l2.txt"); + assertIteration(walk, D, "level1/level2"); + assertIteration(walk, F, "level1/level2/l2.txt"); - endWalk(); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -191,18 +193,19 @@ public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase { // Adds file to index git.add().addFilepattern(".").call(); - walk = beginWalk(); - assertIteration(F, ".gitattributes"); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); - assertIteration(D, "levelA"); - assertIteration(F, "levelA/.gitattributes"); - assertIteration(F, "levelA/lA.txt"); + assertIteration(walk, D, "levelA"); + assertIteration(walk, F, "levelA/.gitattributes"); + assertIteration(walk, F, "levelA/lA.txt"); - assertIteration(D, "levelB"); - assertIteration(F, "levelB/.gitattributes"); + assertIteration(walk, D, "levelB"); + assertIteration(walk, F, "levelB/.gitattributes"); - endWalk(); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -215,25 +218,27 @@ public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase { // Adds file to index git.add().addFilepattern(".").call(); - walk = beginWalk(); - assertIteration(F, "gitattributes"); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, "gitattributes"); - assertIteration(F, "l0.txt"); + assertIteration(walk, F, "l0.txt"); - assertIteration(D, "levelA"); - assertIteration(F, "levelA/file.gitattributes"); - assertIteration(F, "levelA/lA.txt"); + assertIteration(walk, D, "levelA"); + assertIteration(walk, F, "levelA/file.gitattributes"); + assertIteration(walk, F, "levelA/lA.txt"); - endWalk(); + assertFalse("Not all files tested", walk.next()); + } } - private void assertIteration(FileMode type, String pathName) + private void assertIteration(TreeWalk walk, FileMode type, String pathName) throws IOException { - assertIteration(type, pathName, Collections.<Attribute> emptyList()); + assertIteration(walk, type, pathName, + Collections.<Attribute> emptyList()); } - private void assertIteration(FileMode type, String pathName, + private void assertIteration(TreeWalk walk, FileMode type, String pathName, List<Attribute> nodeAttrs) throws IOException { assertTrue("walk has entry", walk.next()); assertEquals(pathName, walk.getPathString()); @@ -243,14 +248,14 @@ public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase { AttributesNode attributesNode = itr.getEntryAttributesNode(db .newObjectReader()); - assertAttributesNode(pathName, attributesNode, nodeAttrs); + assertAttributesNode(walk, pathName, attributesNode, nodeAttrs); if (D.equals(type)) walk.enterSubtree(); } - private void assertAttributesNode(String pathName, + private void assertAttributesNode(TreeWalk walk, String pathName, AttributesNode attributesNode, List<Attribute> nodeAttrs) throws IOException { if (attributesNode == null) @@ -292,8 +297,4 @@ public class AttributesNodeDirCacheIteratorTest extends RepositoryTestCase { newWalk.addTree(new DirCacheIterator(db.readDirCache())); return newWalk; } - - private void endWalk() throws IOException { - assertFalse("Not all files tested", walk.next()); - } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java index b159cca0d5..9991ae59b0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesNodeWorkingTreeIteratorTest.java @@ -77,8 +77,6 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { private static Attribute DELTA_UNSET = new Attribute("delta", State.UNSET); - private TreeWalk walk; - @Test public void testRules() throws Exception { @@ -102,24 +100,26 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { writeTrashFile("src/config/windows.file", ""); writeTrashFile("src/config/windows.txt", ""); - walk = beginWalk(); - - assertIteration(F, ".gitattributes"); - assertIteration(F, "global.txt", asList(EOL_LF)); - assertIteration(F, "readme.txt", asList(EOL_LF)); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, F, "global.txt", asList(EOL_LF)); + assertIteration(walk, F, "readme.txt", asList(EOL_LF)); - assertIteration(D, "src"); + assertIteration(walk, D, "src"); - assertIteration(D, "src/config"); - assertIteration(F, "src/config/.gitattributes"); - assertIteration(F, "src/config/readme.txt", asList(DELTA_UNSET)); - assertIteration(F, "src/config/windows.file", null); - assertIteration(F, "src/config/windows.txt", asList(DELTA_UNSET)); + assertIteration(walk, D, "src/config"); + assertIteration(walk, F, "src/config/.gitattributes"); + assertIteration(walk, F, "src/config/readme.txt", + asList(DELTA_UNSET)); + assertIteration(walk, F, "src/config/windows.file", null); + assertIteration(walk, F, "src/config/windows.txt", + asList(DELTA_UNSET)); - assertIteration(F, "windows.file", null); - assertIteration(F, "windows.txt", asList(EOL_LF)); + assertIteration(walk, F, "windows.file", null); + assertIteration(walk, F, "windows.txt", asList(EOL_LF)); - endWalk(); + assertFalse("Not all files tested", walk.next()); + } } /** @@ -134,17 +134,17 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { writeTrashFile("level1/l1.txt", ""); writeTrashFile("level1/level2/l2.txt", ""); - walk = beginWalk(); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, "l0.txt"); - assertIteration(F, "l0.txt"); + assertIteration(walk, D, "level1"); + assertIteration(walk, F, "level1/l1.txt"); - assertIteration(D, "level1"); - assertIteration(F, "level1/l1.txt"); + assertIteration(walk, D, "level1/level2"); + assertIteration(walk, F, "level1/level2/l2.txt"); - assertIteration(D, "level1/level2"); - assertIteration(F, "level1/level2/l2.txt"); - - endWalk(); + assertFalse("Not all files tested", walk.next()); + } } /** @@ -160,18 +160,18 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { writeTrashFile("level1/l1.txt", ""); writeTrashFile("level1/level2/l2.txt", ""); - walk = beginWalk(); - - assertIteration(F, ".gitattributes"); - assertIteration(F, "l0.txt"); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); + assertIteration(walk, F, "l0.txt"); - assertIteration(D, "level1"); - assertIteration(F, "level1/l1.txt"); + assertIteration(walk, D, "level1"); + assertIteration(walk, F, "level1/l1.txt"); - assertIteration(D, "level1/level2"); - assertIteration(F, "level1/level2/l2.txt"); + assertIteration(walk, D, "level1/level2"); + assertIteration(walk, F, "level1/level2/l2.txt"); - endWalk(); + assertFalse("Not all files tested", walk.next()); + } } @Test @@ -183,26 +183,27 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { writeTrashFile("levelA/lA.txt", ""); - walk = beginWalk(); - - assertIteration(F, ".gitattributes"); + try (TreeWalk walk = beginWalk()) { + assertIteration(walk, F, ".gitattributes"); - assertIteration(D, "levelA"); - assertIteration(F, "levelA/.gitattributes"); - assertIteration(F, "levelA/lA.txt"); + assertIteration(walk, D, "levelA"); + assertIteration(walk, F, "levelA/.gitattributes"); + assertIteration(walk, F, "levelA/lA.txt"); - assertIteration(D, "levelB"); - assertIteration(F, "levelB/.gitattributes"); + assertIteration(walk, D, "levelB"); + assertIteration(walk, F, "levelB/.gitattributes"); - endWalk(); + assertFalse("Not all files tested", walk.next()); + } } - private void assertIteration(FileMode type, String pathName) + private void assertIteration(TreeWalk walk, FileMode type, String pathName) throws IOException { - assertIteration(type, pathName, Collections.<Attribute> emptyList()); + assertIteration(walk, type, pathName, + Collections.<Attribute> emptyList()); } - private void assertIteration(FileMode type, String pathName, + private void assertIteration(TreeWalk walk, FileMode type, String pathName, List<Attribute> nodeAttrs) throws IOException { assertTrue("walk has entry", walk.next()); @@ -212,13 +213,13 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { assertNotNull("has tree", itr); AttributesNode attributesNode = itr.getEntryAttributesNode(); - assertAttributesNode(pathName, attributesNode, nodeAttrs); + assertAttributesNode(walk, pathName, attributesNode, nodeAttrs); if (D.equals(type)) walk.enterSubtree(); } - private void assertAttributesNode(String pathName, + private void assertAttributesNode(TreeWalk walk, String pathName, AttributesNode attributesNode, List<Attribute> nodeAttrs) throws IOException { if (attributesNode == null) @@ -259,8 +260,4 @@ public class AttributesNodeWorkingTreeIteratorTest extends RepositoryTestCase { newWalk.addTree(new FileTreeIterator(db)); return newWalk; } - - private void endWalk() throws IOException { - assertFalse("Not all files tested", walk.next()); - } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java index d6aead4a52..0291fcc1e9 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/TreeWalkAttributeTest.java @@ -131,6 +131,12 @@ public class TreeWalkAttributeTest extends RepositoryTestCase { @Override @After public void tearDown() throws Exception { + if (walk != null) { + walk.close(); + } + if (ci_walk != null) { + ci_walk.close(); + } super.tearDown(); if (customAttributeFile != null) customAttributeFile.delete(); 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 cbc0761463..45046a3999 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.TreeWalk; import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.SystemReader; +import org.junit.After; import org.junit.Test; /** @@ -79,6 +80,13 @@ public class IgnoreNodeTest extends RepositoryTestCase { private TreeWalk walk; + @After + public void closeWalk() { + if (walk != null) { + walk.close(); + } + } + @Test public void testSimpleRootGitIgnoreGlobalIgnore() throws IOException { writeIgnoreFile(".gitignore", "x"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java index 5a5ae1d7a3..cfc275a7de 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java @@ -723,7 +723,7 @@ public class DfsGarbageCollectorTest { DfsPackDescription t1 = odb.newPack(INSERT); try (DfsOutputStream out = odb.writeFile(t1, REFTABLE)) { - new ReftableWriter().begin(out).finish(); + new ReftableWriter(out).begin().finish(); t1.addFileExt(REFTABLE); } odb.commitPack(Collections.singleton(t1), null); @@ -755,7 +755,7 @@ public class DfsGarbageCollectorTest { DfsPackDescription t1 = odb.newPack(INSERT); try (DfsOutputStream out = odb.writeFile(t1, REFTABLE)) { - new ReftableWriter().begin(out).finish(); + new ReftableWriter(out).begin().finish(); t1.addFileExt(REFTABLE); } odb.commitPack(Collections.singleton(t1), null); @@ -795,10 +795,10 @@ public class DfsGarbageCollectorTest { Ref next = new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, "refs/heads/next", commit0.copy()); try (DfsOutputStream out = odb.writeFile(t1, REFTABLE)) { - ReftableWriter w = new ReftableWriter(); + ReftableWriter w = new ReftableWriter(out); w.setMinUpdateIndex(42); w.setMaxUpdateIndex(42); - w.begin(out); + w.begin(); w.sortAndWriteRefs(Collections.singleton(next)); w.finish(); t1.addFileExt(REFTABLE); @@ -877,10 +877,10 @@ public class DfsGarbageCollectorTest { Ref newNext = new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, NEXT, commit1); try (DfsOutputStream out = odb.writeFile(t1, REFTABLE)) { - ReftableWriter w = new ReftableWriter(); - w.setMinUpdateIndex(1); - w.setMaxUpdateIndex(1); - w.begin(out); + ReftableWriter w = new ReftableWriter(out) + .setMinUpdateIndex(1) + .setMaxUpdateIndex(1) + .begin(); w.writeRef(newNext, 1); w.finish(); t1.addFileExt(REFTABLE); @@ -929,10 +929,10 @@ public class DfsGarbageCollectorTest { Ref newNext = new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, NEXT, commit1); try (DfsOutputStream out = odb.writeFile(t1, REFTABLE)) { - ReftableWriter w = new ReftableWriter(); - w.setMinUpdateIndex(1); - w.setMaxUpdateIndex(1); - w.begin(out); + ReftableWriter w = new ReftableWriter(out) + .setMinUpdateIndex(1) + .setMaxUpdateIndex(1) + .begin(); w.writeRef(newNext, 1); w.finish(); t1.addFileExt(REFTABLE); 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 e71ee6d25f..4d36144212 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 @@ -92,18 +92,22 @@ public class DfsInserterTest { @Test public void testReadFromInserterSmallObjects() throws IOException { - ObjectInserter ins = db.newObjectInserter(); - ObjectId id1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("foo")); - ObjectId id2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("bar")); - assertEquals(0, db.getObjectDatabase().listPacks().size()); + try (ObjectInserter ins = db.newObjectInserter()) { + ObjectId id1 = ins.insert(Constants.OBJ_BLOB, + Constants.encode("foo")); + ObjectId id2 = ins.insert(Constants.OBJ_BLOB, + Constants.encode("bar")); + assertEquals(0, db.getObjectDatabase().listPacks().size()); - ObjectReader reader = ins.newReader(); - assertSame(ins, reader.getCreatedFromInserter()); - assertEquals("foo", readString(reader.open(id1))); - assertEquals("bar", readString(reader.open(id2))); - assertEquals(0, db.getObjectDatabase().listPacks().size()); - ins.flush(); - assertEquals(1, db.getObjectDatabase().listPacks().size()); + try (ObjectReader reader = ins.newReader()) { + assertSame(ins, reader.getCreatedFromInserter()); + assertEquals("foo", readString(reader.open(id1))); + assertEquals("bar", readString(reader.open(id2))); + assertEquals(0, db.getObjectDatabase().listPacks().size()); + ins.flush(); + assertEquals(1, db.getObjectDatabase().listPacks().size()); + } + } } @Test @@ -114,17 +118,19 @@ public class DfsInserterTest { .setBlockLimit(2048)); byte[] data = new TestRng(JGitTestUtil.getName()).nextBytes(8192); - DfsInserter ins = (DfsInserter) db.newObjectInserter(); - ins.setCompressionLevel(Deflater.NO_COMPRESSION); - ObjectId id1 = ins.insert(Constants.OBJ_BLOB, data); - assertEquals(0, db.getObjectDatabase().listPacks().size()); + try (DfsInserter ins = (DfsInserter) db.newObjectInserter()) { + ins.setCompressionLevel(Deflater.NO_COMPRESSION); + ObjectId id1 = ins.insert(Constants.OBJ_BLOB, data); + assertEquals(0, db.getObjectDatabase().listPacks().size()); - ObjectReader reader = ins.newReader(); - assertSame(ins, reader.getCreatedFromInserter()); - assertTrue(Arrays.equals(data, readStream(reader.open(id1)))); - assertEquals(0, db.getObjectDatabase().listPacks().size()); - ins.flush(); + try (ObjectReader reader = ins.newReader()) { + assertSame(ins, reader.getCreatedFromInserter()); + assertTrue(Arrays.equals(data, readStream(reader.open(id1)))); + assertEquals(0, db.getObjectDatabase().listPacks().size()); + } + ins.flush(); + } List<DfsPackDescription> packs = db.getObjectDatabase().listPacks(); assertEquals(1, packs.size()); assertTrue(packs.get(0).getFileSize(PackExt.PACK) > 2048); @@ -132,48 +138,58 @@ public class DfsInserterTest { @Test public void testReadFromFallback() throws IOException { - ObjectInserter ins = db.newObjectInserter(); - ObjectId id1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("foo")); - ins.flush(); - ObjectId id2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("bar")); - assertEquals(1, db.getObjectDatabase().listPacks().size()); - - ObjectReader reader = ins.newReader(); - assertSame(ins, reader.getCreatedFromInserter()); - assertEquals("foo", readString(reader.open(id1))); - assertEquals("bar", readString(reader.open(id2))); - assertEquals(1, db.getObjectDatabase().listPacks().size()); - ins.flush(); - assertEquals(2, db.getObjectDatabase().listPacks().size()); + try (ObjectInserter ins = db.newObjectInserter()) { + ObjectId id1 = ins.insert(Constants.OBJ_BLOB, + Constants.encode("foo")); + ins.flush(); + ObjectId id2 = ins.insert(Constants.OBJ_BLOB, + Constants.encode("bar")); + assertEquals(1, db.getObjectDatabase().listPacks().size()); + + try (ObjectReader reader = ins.newReader()) { + assertSame(ins, reader.getCreatedFromInserter()); + assertEquals("foo", readString(reader.open(id1))); + assertEquals("bar", readString(reader.open(id2))); + assertEquals(1, db.getObjectDatabase().listPacks().size()); + } + ins.flush(); + assertEquals(2, db.getObjectDatabase().listPacks().size()); + } } @Test public void testReaderResolve() throws IOException { - ObjectInserter ins = db.newObjectInserter(); - ObjectId id1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("foo")); - ins.flush(); - ObjectId id2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("bar")); - String abbr1 = ObjectId.toString(id1).substring(0, 4); - String abbr2 = ObjectId.toString(id2).substring(0, 4); - assertFalse(abbr1.equals(abbr2)); - - ObjectReader reader = ins.newReader(); - assertSame(ins, reader.getCreatedFromInserter()); - Collection<ObjectId> objs; - objs = reader.resolve(AbbreviatedObjectId.fromString(abbr1)); - assertEquals(1, objs.size()); - assertEquals(id1, objs.iterator().next()); - - objs = reader.resolve(AbbreviatedObjectId.fromString(abbr2)); - assertEquals(1, objs.size()); - assertEquals(id2, objs.iterator().next()); + try (ObjectInserter ins = db.newObjectInserter()) { + ObjectId id1 = ins.insert(Constants.OBJ_BLOB, + Constants.encode("foo")); + ins.flush(); + ObjectId id2 = ins.insert(Constants.OBJ_BLOB, + Constants.encode("bar")); + String abbr1 = ObjectId.toString(id1).substring(0, 4); + String abbr2 = ObjectId.toString(id2).substring(0, 4); + assertFalse(abbr1.equals(abbr2)); + + try (ObjectReader reader = ins.newReader()) { + assertSame(ins, reader.getCreatedFromInserter()); + Collection<ObjectId> objs; + objs = reader.resolve(AbbreviatedObjectId.fromString(abbr1)); + assertEquals(1, objs.size()); + assertEquals(id1, objs.iterator().next()); + + objs = reader.resolve(AbbreviatedObjectId.fromString(abbr2)); + assertEquals(1, objs.size()); + 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(); + ObjectId fooId; + try (ObjectInserter ins = db.newObjectInserter()) { + fooId = ins.insert(Constants.OBJ_BLOB, Constants.encode("foo")); + ins.flush(); + } assertEquals(1, db.getObjectDatabase().listPacks().size()); // Make pack 0 garbage. @@ -187,36 +203,40 @@ public class DfsInserterTest { @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()); + ObjectId fooId; + try (ObjectInserter ins = db.newObjectInserter()) { + 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); + // 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)); + // 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(); + // 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<>(); + try (DfsReader reader = new DfsReader(db.getObjectDatabase())) { + DfsPackFile packs[] = db.getObjectDatabase().getPacks(); + Set<PackSource> pack_sources = new HashSet<>(); - assertEquals(2, packs.length); + assertEquals(2, packs.length); - pack_sources.add(packs[0].getPackDescription().getPackSource()); - pack_sources.add(packs[1].getPackDescription().getPackSource()); + 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)); + 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)); + } } @Test @@ -237,17 +257,20 @@ public class DfsInserterTest { assertEquals(2, db.getObjectDatabase().listPacks().size()); // Verify that we have a foo in both INSERT packs. - DfsReader reader = new DfsReader(db.getObjectDatabase()); - DfsPackFile packs[] = db.getObjectDatabase().getPacks(); - - assertEquals(2, packs.length); - DfsPackFile p1 = packs[0]; - assertEquals(PackSource.INSERT, p1.getPackDescription().getPackSource()); - assertTrue(p1.hasObject(reader, fooId)); - - DfsPackFile p2 = packs[1]; - assertEquals(PackSource.INSERT, p2.getPackDescription().getPackSource()); - assertTrue(p2.hasObject(reader, fooId)); + try (DfsReader reader = new DfsReader(db.getObjectDatabase())) { + DfsPackFile packs[] = db.getObjectDatabase().getPacks(); + + assertEquals(2, packs.length); + DfsPackFile p1 = packs[0]; + assertEquals(PackSource.INSERT, + p1.getPackDescription().getPackSource()); + assertTrue(p1.hasObject(reader, fooId)); + + DfsPackFile p2 = packs[1]; + assertEquals(PackSource.INSERT, + p2.getPackDescription().getPackSource()); + assertTrue(p2.hasObject(reader, fooId)); + } } private static String readString(ObjectLoader loader) throws IOException { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java index 79cf4d5aff..cb5b07a4db 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java @@ -61,6 +61,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import java.io.File; @@ -109,19 +110,29 @@ import org.junit.runners.Parameterized.Parameters; @SuppressWarnings("boxing") @RunWith(Parameterized.class) public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { - @Parameter + @Parameter(0) public boolean atomic; - @Parameters(name = "atomic={0}") + @Parameter(1) + public boolean useReftable; + + @Parameters(name = "atomic={0} reftable={1}") public static Collection<Object[]> data() { - return Arrays.asList(new Object[][]{ {Boolean.FALSE}, {Boolean.TRUE} }); + return Arrays.asList(new Object[][] { { Boolean.FALSE, Boolean.FALSE }, + { Boolean.TRUE, Boolean.FALSE }, + { Boolean.FALSE, Boolean.TRUE }, + { Boolean.TRUE, Boolean.TRUE }, }); } private Repository diskRepo; + private TestRepository<Repository> repo; + private RefDirectory refdir; + private RevCommit A; - private RevCommit B; + + private RevCommit B; // B descends from A. /** * When asserting the number of RefsChangedEvents you must account for one @@ -143,11 +154,18 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { public void setUp() throws Exception { super.setUp(); - diskRepo = createBareRepository(); + FileRepository fileRepo = createBareRepository(); + if (useReftable) { + fileRepo.convertToReftable(false, false); + } + + diskRepo = fileRepo; setLogAllRefUpdates(true); - refdir = (RefDirectory) diskRepo.getRefDatabase(); - refdir.setRetrySleepMs(Arrays.asList(0, 0)); + if (!useReftable) { + refdir = (RefDirectory) diskRepo.getRefDatabase(); + refdir.setRetrySleepMs(Arrays.asList(0, 0)); + } repo = new TestRepository<>(diskRepo); A = repo.commit().create(); @@ -166,11 +184,12 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void packedRefsFileIsSorted() throws IOException { assumeTrue(atomic); + assumeFalse(useReftable); for (int i = 0; i < 2; i++) { BatchRefUpdate bu = diskRepo.getRefDatabase().newBatchUpdate(); - String b1 = String.format("refs/heads/a%d",i); - String b2 = String.format("refs/heads/b%d",i); + String b1 = String.format("refs/heads/a%d", i); + String b2 = String.format("refs/heads/b%d", i); bu.setAtomic(atomic); ReceiveCommand c1 = new ReceiveCommand(ObjectId.zeroId(), A, b1); ReceiveCommand c2 = new ReceiveCommand(ObjectId.zeroId(), B, b2); @@ -183,70 +202,65 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { } File packed = new File(diskRepo.getDirectory(), "packed-refs"); - String packedStr = new String(Files.readAllBytes(packed.toPath()), UTF_8); + String packedStr = new String(Files.readAllBytes(packed.toPath()), + UTF_8); int a2 = packedStr.indexOf("refs/heads/a1"); int b1 = packedStr.indexOf("refs/heads/b0"); - assertTrue(a2 < b1); + assertTrue(a2 < b1); } @Test public void simpleNoForce() throws IOException { - writeLooseRef("refs/heads/master", A); - writeLooseRef("refs/heads/masters", B); + writeLooseRefs("refs/heads/master", A, "refs/heads/masters", B); List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), - new ReceiveCommand(B, A, "refs/heads/masters", UPDATE_NONFASTFORWARD)); + new ReceiveCommand(B, A, "refs/heads/masters", + UPDATE_NONFASTFORWARD)); execute(newBatchUpdate(cmds)); if (atomic) { assertResults(cmds, TRANSACTION_ABORTED, REJECTED_NONFASTFORWARD); - assertRefs( - "refs/heads/master", A, - "refs/heads/masters", B); + assertRefs("refs/heads/master", A, "refs/heads/masters", B); assertEquals(1, refsChangedEvents); } else { assertResults(cmds, OK, REJECTED_NONFASTFORWARD); - assertRefs( - "refs/heads/master", B, - "refs/heads/masters", B); + assertRefs("refs/heads/master", B, "refs/heads/masters", B); assertEquals(2, refsChangedEvents); } } @Test public void simpleForce() throws IOException { - writeLooseRef("refs/heads/master", A); - writeLooseRef("refs/heads/masters", B); + writeLooseRefs("refs/heads/master", A, "refs/heads/masters", B); List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), - new ReceiveCommand(B, A, "refs/heads/masters", UPDATE_NONFASTFORWARD)); + new ReceiveCommand(B, A, "refs/heads/masters", + UPDATE_NONFASTFORWARD)); execute(newBatchUpdate(cmds).setAllowNonFastForwards(true)); assertResults(cmds, OK, OK); - assertRefs( - "refs/heads/master", B, - "refs/heads/masters", A); - assertEquals(atomic ? 2 : 3, refsChangedEvents); + assertRefs("refs/heads/master", B, "refs/heads/masters", A); + assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); } @Test - public void nonFastForwardDoesNotDoExpensiveMergeCheck() throws IOException { + public void nonFastForwardDoesNotDoExpensiveMergeCheck() + throws IOException { writeLooseRef("refs/heads/master", B); - List<ReceiveCommand> cmds = Arrays.asList( - new ReceiveCommand(B, A, "refs/heads/master", UPDATE_NONFASTFORWARD)); + List<ReceiveCommand> cmds = Arrays.asList(new ReceiveCommand(B, A, + "refs/heads/master", UPDATE_NONFASTFORWARD)); try (RevWalk rw = new RevWalk(diskRepo) { - @Override - public boolean isMergedInto(RevCommit base, RevCommit tip) { - throw new AssertionError("isMergedInto() should not be called"); - } - }) { - newBatchUpdate(cmds) - .setAllowNonFastForwards(true) - .execute(rw, new StrictWorkMonitor()); + @Override + public boolean isMergedInto(RevCommit base, RevCommit tip) { + throw new AssertionError("isMergedInto() should not be called"); + } + }) { + newBatchUpdate(cmds).setAllowNonFastForwards(true).execute(rw, + new StrictWorkMonitor()); } assertResults(cmds, OK); @@ -256,8 +270,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void fileDirectoryConflict() throws IOException { - writeLooseRef("refs/heads/master", A); - writeLooseRef("refs/heads/masters", B); + writeLooseRefs("refs/heads/master", A, "refs/heads/masters", B); List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), @@ -266,29 +279,24 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { execute(newBatchUpdate(cmds).setAllowNonFastForwards(true), false); if (atomic) { - // Atomic update sees that master and master/x are conflicting, then marks - // the first one in the list as LOCK_FAILURE and aborts the rest. - assertResults(cmds, - LOCK_FAILURE, TRANSACTION_ABORTED, TRANSACTION_ABORTED); - assertRefs( - "refs/heads/master", A, - "refs/heads/masters", B); + // Atomic update sees that master and master/x are conflicting, then + // marks the first one in the list as LOCK_FAILURE and aborts the rest. + assertResults(cmds, LOCK_FAILURE, TRANSACTION_ABORTED, + TRANSACTION_ABORTED); + assertRefs("refs/heads/master", A, "refs/heads/masters", B); assertEquals(1, refsChangedEvents); } else { - // Non-atomic updates are applied in order: master succeeds, then master/x - // fails due to conflict. + // Non-atomic updates are applied in order: master succeeds, then + // master/x fails due to conflict. assertResults(cmds, OK, LOCK_FAILURE, LOCK_FAILURE); - assertRefs( - "refs/heads/master", B, - "refs/heads/masters", B); + assertRefs("refs/heads/master", B, "refs/heads/masters", B); assertEquals(2, refsChangedEvents); } } @Test public void conflictThanksToDelete() throws IOException { - writeLooseRef("refs/heads/master", A); - writeLooseRef("refs/heads/masters", B); + writeLooseRefs("refs/heads/master", A, "refs/heads/masters", B); List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), @@ -297,12 +305,10 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { execute(newBatchUpdate(cmds).setAllowNonFastForwards(true)); assertResults(cmds, OK, OK, OK); - assertRefs( - "refs/heads/master", B, - "refs/heads/masters/x", A); + assertRefs("refs/heads/master", B, "refs/heads/masters/x", A); if (atomic) { assertEquals(2, refsChangedEvents); - } else { + } else if (!useReftable) { // The non-atomic case actually produces 5 events, but that's an // implementation detail. We expect at least 4 events, one for the // initial read due to writeLooseRef(), and then one for each @@ -315,8 +321,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { public void updateToMissingObject() throws IOException { writeLooseRef("refs/heads/master", A); - ObjectId bad = - ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); + ObjectId bad = ObjectId + .fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, bad, "refs/heads/master", UPDATE), new ReceiveCommand(zeroId(), B, "refs/heads/foo2", CREATE)); @@ -328,9 +334,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertEquals(1, refsChangedEvents); } else { assertResults(cmds, REJECTED_MISSING_OBJECT, OK); - assertRefs( - "refs/heads/master", A, - "refs/heads/foo2", B); + assertRefs("refs/heads/master", A, "refs/heads/foo2", B); assertEquals(2, refsChangedEvents); } } @@ -339,8 +343,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { public void addMissingObject() throws IOException { writeLooseRef("refs/heads/master", A); - ObjectId bad = - ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); + ObjectId bad = ObjectId + .fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), new ReceiveCommand(zeroId(), bad, "refs/heads/foo2", CREATE)); @@ -390,9 +394,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertEquals(1, refsChangedEvents); } else { assertResults(cmds, LOCK_FAILURE, OK); - assertRefs( - "refs/heads/master", A, - "refs/heads/foo2", B); + assertRefs("refs/heads/master", A, "refs/heads/foo2", B); assertEquals(2, refsChangedEvents); } } @@ -421,9 +423,10 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { public void noRefLog() throws IOException { writeRef("refs/heads/master", A); - Map<String, ReflogEntry> oldLogs = - getLastReflogs("refs/heads/master", "refs/heads/branch"); - assertEquals(Collections.singleton("refs/heads/master"), oldLogs.keySet()); + Map<String, ReflogEntry> oldLogs = getLastReflogs("refs/heads/master", + "refs/heads/branch"); + assertEquals(Collections.singleton("refs/heads/master"), + oldLogs.keySet()); List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), @@ -431,10 +434,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { execute(newBatchUpdate(cmds).setAllowNonFastForwards(true)); assertResults(cmds, OK, OK); - assertRefs( - "refs/heads/master", B, - "refs/heads/branch", B); - assertEquals(atomic ? 2 : 3, refsChangedEvents); + assertRefs("refs/heads/master", B, "refs/heads/branch", B); + assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); assertReflogUnchanged(oldLogs, "refs/heads/master"); assertReflogUnchanged(oldLogs, "refs/heads/branch"); } @@ -444,24 +445,19 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { writeRef("refs/heads/master", A); writeRef("refs/heads/branch2", A); - Map<String, ReflogEntry> oldLogs = getLastReflogs( - "refs/heads/master", "refs/heads/branch1", "refs/heads/branch2"); + Map<String, ReflogEntry> oldLogs = getLastReflogs("refs/heads/master", + "refs/heads/branch1", "refs/heads/branch2"); List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), new ReceiveCommand(zeroId(), B, "refs/heads/branch1", CREATE)); - execute( - newBatchUpdate(cmds) - .setAllowNonFastForwards(true) - .setRefLogMessage("a reflog", false)); + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true) + .setRefLogMessage("a reflog", false)); assertResults(cmds, OK, OK); - assertRefs( - "refs/heads/master", B, - "refs/heads/branch1", B, + assertRefs("refs/heads/master", B, "refs/heads/branch1", B, "refs/heads/branch2", A); - assertEquals(atomic ? 3 : 4, refsChangedEvents); - assertReflogEquals( - reflog(A, B, new PersonIdent(diskRepo), "a reflog"), + assertEquals(batchesRefUpdates() ? 3 : 4, refsChangedEvents); + assertReflogEquals(reflog(A, B, new PersonIdent(diskRepo), "a reflog"), getLastReflog("refs/heads/master")); assertReflogEquals( reflog(zeroId(), B, new PersonIdent(diskRepo), "a reflog"), @@ -476,21 +472,19 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), - new ReceiveCommand(B, A, "refs/heads/branch1", UPDATE_NONFASTFORWARD), + new ReceiveCommand(B, A, "refs/heads/branch1", + UPDATE_NONFASTFORWARD), new ReceiveCommand(zeroId(), A, "refs/heads/branch2", CREATE)); - execute( - newBatchUpdate(cmds) - .setAllowNonFastForwards(true) - .setRefLogMessage(null, true)); + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true) + .setRefLogMessage(null, true)); assertResults(cmds, OK, OK, OK); - assertRefs( - "refs/heads/master", B, - "refs/heads/branch1", A, + assertRefs("refs/heads/master", B, "refs/heads/branch1", A, "refs/heads/branch2", A); - assertEquals(atomic ? 3 : 5, refsChangedEvents); + assertEquals(batchesRefUpdates() ? 3 : 5, refsChangedEvents); assertReflogEquals( - // Always forced; setAllowNonFastForwards(true) bypasses the check. + // Always forced; setAllowNonFastForwards(true) bypasses the + // check. reflog(A, B, new PersonIdent(diskRepo), "forced-update"), getLastReflog("refs/heads/master")); assertReflogEquals( @@ -505,8 +499,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { public void reflogAppendStatusFastForward() throws IOException { writeRef("refs/heads/master", A); - List<ReceiveCommand> cmds = Arrays.asList( - new ReceiveCommand(A, B, "refs/heads/master", UPDATE)); + List<ReceiveCommand> cmds = Arrays + .asList(new ReceiveCommand(A, B, "refs/heads/master", UPDATE)); execute(newBatchUpdate(cmds).setRefLogMessage(null, true)); assertResults(cmds, OK); @@ -527,15 +521,15 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", true)); assertResults(cmds, OK, OK); - assertRefs( - "refs/heads/master", B, - "refs/heads/branch", A); - assertEquals(atomic ? 2 : 3, refsChangedEvents); + assertRefs("refs/heads/master", B, "refs/heads/branch", A); + assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); assertReflogEquals( - reflog(A, B, new PersonIdent(diskRepo), "a reflog: fast-forward"), + reflog(A, B, new PersonIdent(diskRepo), + "a reflog: fast-forward"), getLastReflog("refs/heads/master")); assertReflogEquals( - reflog(zeroId(), A, new PersonIdent(diskRepo), "a reflog: created"), + reflog(zeroId(), A, new PersonIdent(diskRepo), + "a reflog: created"), getLastReflog("refs/heads/branch")); } @@ -546,33 +540,26 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE)); - PersonIdent ident = new PersonIdent("A Reflog User", "reflog@example.com"); - execute( - newBatchUpdate(cmds) - .setRefLogMessage("a reflog", false) - .setRefLogIdent(ident)); + PersonIdent ident = new PersonIdent("A Reflog User", + "reflog@example.com"); + execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", false) + .setRefLogIdent(ident)); assertResults(cmds, OK, OK); - assertEquals(atomic ? 2 : 3, refsChangedEvents); - assertRefs( - "refs/heads/master", B, - "refs/heads/branch", B); - assertReflogEquals( - reflog(A, B, ident, "a reflog"), - getLastReflog("refs/heads/master"), - true); - assertReflogEquals( - reflog(zeroId(), B, ident, "a reflog"), - getLastReflog("refs/heads/branch"), - true); + assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); + assertRefs("refs/heads/master", B, "refs/heads/branch", B); + assertReflogEquals(reflog(A, B, ident, "a reflog"), + getLastReflog("refs/heads/master"), true); + assertReflogEquals(reflog(zeroId(), B, ident, "a reflog"), + getLastReflog("refs/heads/branch"), true); } @Test public void reflogDelete() throws IOException { writeRef("refs/heads/master", A); writeRef("refs/heads/branch", A); - assertEquals( - 2, getLastReflogs("refs/heads/master", "refs/heads/branch").size()); + assertEquals(2, getLastReflogs("refs/heads/master", "refs/heads/branch") + .size()); List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, zeroId(), "refs/heads/master", DELETE), @@ -581,10 +568,16 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK, OK); assertRefs("refs/heads/branch", B); - assertEquals(atomic ? 3 : 4, refsChangedEvents); - assertNull(getLastReflog("refs/heads/master")); - assertReflogEquals( - reflog(A, B, new PersonIdent(diskRepo), "a reflog"), + assertEquals(batchesRefUpdates() ? 3 : 4, refsChangedEvents); + if (useReftable) { + // reftable retains reflog entries for deleted branches. + assertReflogEquals( + reflog(A, zeroId(), new PersonIdent(diskRepo), "a reflog"), + getLastReflog("refs/heads/master")); + } else { + assertNull(getLastReflog("refs/heads/master")); + } + assertReflogEquals(reflog(A, B, new PersonIdent(diskRepo), "a reflog"), getLastReflog("refs/heads/branch")); } @@ -599,8 +592,11 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK, OK); assertRefs("refs/heads/master/x", A); - assertEquals(atomic ? 2 : 3, refsChangedEvents); - assertNull(getLastReflog("refs/heads/master")); + assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); + if (!useReftable) { + // reftable retains reflog entries for deleted branches. + assertNull(getLastReflog("refs/heads/master")); + } assertReflogEquals( reflog(zeroId(), A, new PersonIdent(diskRepo), "a reflog"), getLastReflog("refs/heads/master/x")); @@ -610,8 +606,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { public void reflogOnLockFailure() throws IOException { writeRef("refs/heads/master", A); - Map<String, ReflogEntry> oldLogs = - getLastReflogs("refs/heads/master", "refs/heads/branch"); + Map<String, ReflogEntry> oldLogs = getLastReflogs("refs/heads/master", + "refs/heads/branch"); List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), @@ -642,29 +638,23 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE)); cmds.get(0).setRefLogMessage("custom log", false); PersonIdent ident = new PersonIdent(diskRepo); - execute( - newBatchUpdate(cmds) - .setRefLogIdent(ident) - .setRefLogMessage("a reflog", true)); + execute(newBatchUpdate(cmds).setRefLogIdent(ident) + .setRefLogMessage("a reflog", true)); assertResults(cmds, OK, OK); - assertEquals(atomic ? 2 : 3, refsChangedEvents); - assertReflogEquals( - reflog(A, B, ident, "custom log"), - getLastReflog("refs/heads/master"), - true); - assertReflogEquals( - reflog(zeroId(), B, ident, "a reflog: created"), - getLastReflog("refs/heads/branch"), - true); + assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); + assertReflogEquals(reflog(A, B, ident, "custom log"), + getLastReflog("refs/heads/master"), true); + assertReflogEquals(reflog(zeroId(), B, ident, "a reflog: created"), + getLastReflog("refs/heads/branch"), true); } @Test public void overrideDisableRefLog() throws Exception { writeRef("refs/heads/master", A); - Map<String, ReflogEntry> oldLogs = - getLastReflogs("refs/heads/master", "refs/heads/branch"); + Map<String, ReflogEntry> oldLogs = getLastReflogs("refs/heads/master", + "refs/heads/branch"); List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), @@ -673,20 +663,22 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", true)); assertResults(cmds, OK, OK); - assertEquals(atomic ? 2 : 3, refsChangedEvents); + assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); assertReflogUnchanged(oldLogs, "refs/heads/master"); assertReflogEquals( - reflog(zeroId(), B, new PersonIdent(diskRepo), "a reflog: created"), + reflog(zeroId(), B, new PersonIdent(diskRepo), + "a reflog: created"), getLastReflog("refs/heads/branch")); } @Test public void refLogNotWrittenWithoutConfigOption() throws Exception { + assumeFalse(useReftable); setLogAllRefUpdates(false); writeRef("refs/heads/master", A); - Map<String, ReflogEntry> oldLogs = - getLastReflogs("refs/heads/master", "refs/heads/branch"); + Map<String, ReflogEntry> oldLogs = getLastReflogs("refs/heads/master", + "refs/heads/branch"); assertTrue(oldLogs.isEmpty()); List<ReceiveCommand> cmds = Arrays.asList( @@ -701,22 +693,20 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void forceRefLogInUpdate() throws Exception { + assumeFalse(useReftable); setLogAllRefUpdates(false); writeRef("refs/heads/master", A); - assertTrue( - getLastReflogs("refs/heads/master", "refs/heads/branch").isEmpty()); + assertTrue(getLastReflogs("refs/heads/master", "refs/heads/branch") + .isEmpty()); List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE)); - execute( - newBatchUpdate(cmds) - .setRefLogMessage("a reflog", false) - .setForceRefLog(true)); + execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", false) + .setForceRefLog(true)); assertResults(cmds, OK, OK); - assertReflogEquals( - reflog(A, B, new PersonIdent(diskRepo), "a reflog"), + assertReflogEquals(reflog(A, B, new PersonIdent(diskRepo), "a reflog"), getLastReflog("refs/heads/master")); assertReflogEquals( reflog(zeroId(), B, new PersonIdent(diskRepo), "a reflog"), @@ -725,11 +715,12 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void forceRefLogInCommand() throws Exception { + assumeFalse(useReftable); setLogAllRefUpdates(false); writeRef("refs/heads/master", A); - Map<String, ReflogEntry> oldLogs = - getLastReflogs("refs/heads/master", "refs/heads/branch"); + Map<String, ReflogEntry> oldLogs = getLastReflogs("refs/heads/master", + "refs/heads/branch"); assertTrue(oldLogs.isEmpty()); List<ReceiveCommand> cmds = Arrays.asList( @@ -747,6 +738,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void packedRefsLockFailure() throws Exception { + assumeFalse(useReftable); + writeLooseRef("refs/heads/master", A); List<ReceiveCommand> cmds = Arrays.asList( @@ -765,11 +758,10 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertRefs("refs/heads/master", A); assertEquals(1, refsChangedEvents); } else { - // Only operates on loose refs, doesn't care that packed-refs is locked. + // Only operates on loose refs, doesn't care that packed-refs is + // locked. assertResults(cmds, OK, OK); - assertRefs( - "refs/heads/master", B, - "refs/heads/branch", B); + assertRefs("refs/heads/master", B, "refs/heads/branch", B); assertEquals(3, refsChangedEvents); } } finally { @@ -779,6 +771,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void oneRefLockFailure() throws Exception { + assumeFalse(useReftable); + writeLooseRef("refs/heads/master", A); List<ReceiveCommand> cmds = Arrays.asList( @@ -799,9 +793,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertEquals(1, refsChangedEvents); } else { assertResults(cmds, OK, LOCK_FAILURE); - assertRefs( - "refs/heads/branch", B, - "refs/heads/master", A); + assertRefs("refs/heads/branch", B, "refs/heads/master", A); assertEquals(2, refsChangedEvents); } } finally { @@ -811,10 +803,11 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void singleRefUpdateDoesNotRequirePackedRefsLock() throws Exception { + assumeFalse(useReftable); writeLooseRef("refs/heads/master", A); - List<ReceiveCommand> cmds = Arrays.asList( - new ReceiveCommand(A, B, "refs/heads/master", UPDATE)); + List<ReceiveCommand> cmds = Arrays + .asList(new ReceiveCommand(A, B, "refs/heads/master", UPDATE)); LockFile myLock = refdir.lockPackedRefs(); try { @@ -832,6 +825,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void atomicUpdateRespectsInProcessLock() throws Exception { assumeTrue(atomic); + assumeFalse(useReftable); writeLooseRef("refs/heads/master", A); @@ -854,7 +848,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { long timeoutSecs = 10; long startNanos = System.nanoTime(); - // Hold onto the lock until we observe the worker thread has attempted to + // Hold onto the lock until we observe the worker thread has + // attempted to // acquire it. while (l.getQueueLength() == 0) { long elapsedNanos = System.nanoTime() - startNanos; @@ -864,7 +859,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { Thread.sleep(3); } - // Once we unlock, the worker thread should finish the update promptly. + // Once we unlock, the worker thread should finish the update + // promptly. l.unlock(); t.join(SECONDS.toMillis(timeoutSecs)); assertFalse(t.isAlive()); @@ -876,9 +872,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK, OK); assertEquals(2, refsChangedEvents); - assertRefs( - "refs/heads/master", B, - "refs/heads/branch", B); + assertRefs("refs/heads/master", B, "refs/heads/branch", B); } private void setLogAllRefUpdates(boolean enable) throws Exception { @@ -890,7 +884,38 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { } private void writeLooseRef(String name, AnyObjectId id) throws IOException { - write(new File(diskRepo.getDirectory(), name), id.name() + "\n"); + if (useReftable) { + writeRef(name, id); + } else { + write(new File(diskRepo.getDirectory(), name), id.name() + "\n"); + } + } + + private void writeLooseRefs(String name1, AnyObjectId id1, String name2, + AnyObjectId id2) throws IOException { + if (useReftable) { + BatchRefUpdate bru = diskRepo.getRefDatabase().newBatchUpdate(); + + Ref r1 = diskRepo.exactRef(name1); + ReceiveCommand c1 = new ReceiveCommand( + r1 != null ? r1.getObjectId() : ObjectId.zeroId(), + id1.toObjectId(), name1, r1 == null ? CREATE : UPDATE); + + Ref r2 = diskRepo.exactRef(name2); + ReceiveCommand c2 = new ReceiveCommand( + r2 != null ? r2.getObjectId() : ObjectId.zeroId(), + id2.toObjectId(), name2, r2 == null ? CREATE : UPDATE); + + bru.addCommand(c1, c2); + try (RevWalk rw = new RevWalk(diskRepo)) { + bru.execute(rw, NullProgressMonitor.INSTANCE); + } + assertEquals(c2.getResult(), ReceiveCommand.Result.OK); + assertEquals(c1.getResult(), ReceiveCommand.Result.OK); + } else { + writeLooseRef(name1, id1); + writeLooseRef(name2, id2); + } } private void writeRef(String name, AnyObjectId id) throws IOException { @@ -900,16 +925,16 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { u.setNewObjectId(id); RefUpdate.Result r = u.update(); switch (r) { - case NEW: - case FORCED: - return; - default: - throw new IOException("Got " + r + " while updating " + name); + case NEW: + case FORCED: + return; + default: + throw new IOException("Got " + r + " while updating " + name); } } private BatchRefUpdate newBatchUpdate(List<ReceiveCommand> cmds) { - BatchRefUpdate u = refdir.newBatchUpdate(); + BatchRefUpdate u = diskRepo.getRefDatabase().newBatchUpdate(); if (atomic) { assertTrue(u.isAtomic()); } else { @@ -923,10 +948,11 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { execute(u, false); } - private void execute(BatchRefUpdate u, boolean strictWork) throws IOException { + private void execute(BatchRefUpdate u, boolean strictWork) + throws IOException { try (RevWalk rw = new RevWalk(diskRepo)) { - u.execute(rw, - strictWork ? new StrictWorkMonitor() : NullProgressMonitor.INSTANCE); + u.execute(rw, strictWork ? new StrictWorkMonitor() + : NullProgressMonitor.INSTANCE); } } @@ -941,15 +967,18 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { expected.put((String) args[i], (AnyObjectId) args[i + 1]); } - Map<String, Ref> refs = refdir.getRefs(RefDatabase.ALL); + Map<String, Ref> refs = diskRepo.getRefDatabase() + .getRefs(RefDatabase.ALL); Ref actualHead = refs.remove(Constants.HEAD); if (actualHead != null) { String actualLeafName = actualHead.getLeaf().getName(); assertEquals( - "expected HEAD to point to refs/heads/master, got: " + actualLeafName, + "expected HEAD to point to refs/heads/master, got: " + + actualLeafName, "refs/heads/master", actualLeafName); AnyObjectId expectedMaster = expected.get("refs/heads/master"); - assertNotNull("expected master ref since HEAD exists", expectedMaster); + assertNotNull("expected master ref since HEAD exists", + expectedMaster); assertEquals(expectedMaster, actualHead.getObjectId()); } @@ -961,11 +990,11 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { } enum Result { - OK(ReceiveCommand.Result.OK), - LOCK_FAILURE(ReceiveCommand.Result.LOCK_FAILURE), - REJECTED_NONFASTFORWARD(ReceiveCommand.Result.REJECTED_NONFASTFORWARD), - REJECTED_MISSING_OBJECT(ReceiveCommand.Result.REJECTED_MISSING_OBJECT), - TRANSACTION_ABORTED(ReceiveCommand::isTransactionAborted); + OK(ReceiveCommand.Result.OK), LOCK_FAILURE( + ReceiveCommand.Result.LOCK_FAILURE), REJECTED_NONFASTFORWARD( + ReceiveCommand.Result.REJECTED_NONFASTFORWARD), REJECTED_MISSING_OBJECT( + ReceiveCommand.Result.REJECTED_MISSING_OBJECT), TRANSACTION_ABORTED( + ReceiveCommand::isTransactionAborted); @SuppressWarnings("ImmutableEnumChecker") final Predicate<? super ReceiveCommand> p; @@ -979,8 +1008,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { } } - private void assertResults( - List<ReceiveCommand> cmds, Result... expected) { + private void assertResults(List<ReceiveCommand> cmds, Result... expected) { if (expected.length != cmds.size()) { throw new IllegalArgumentException( "expected " + cmds.size() + " result args"); @@ -988,12 +1016,10 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { for (int i = 0; i < cmds.size(); i++) { ReceiveCommand c = cmds.get(i); Result r = expected[i]; - assertTrue( - String.format( - "result of command (%d) should be %s: %s %s%s", - Integer.valueOf(i), r, c, - c.getResult(), - c.getMessage() != null ? " (" + c.getMessage() + ")" : ""), + assertTrue(String.format( + "result of command (%d) should be %s, got %s %s%s", + Integer.valueOf(i), r, c, c.getResult(), + c.getMessage() != null ? " (" + c.getMessage() + ")" : ""), r.p.test(c)); } } @@ -1022,18 +1048,18 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { return LockFile.getLockFile(refdir.fileFor(refName)); } - private void assertReflogUnchanged( - Map<String, ReflogEntry> old, String name) throws IOException { + private void assertReflogUnchanged(Map<String, ReflogEntry> old, + String name) throws IOException { assertReflogEquals(old.get(name), getLastReflog(name), true); } - private static void assertReflogEquals( - ReflogEntry expected, ReflogEntry actual) { + private static void assertReflogEquals(ReflogEntry expected, + ReflogEntry actual) { assertReflogEquals(expected, actual, false); } - private static void assertReflogEquals( - ReflogEntry expected, ReflogEntry actual, boolean strictTime) { + private static void assertReflogEquals(ReflogEntry expected, + ReflogEntry actual, boolean strictTime) { if (expected == null) { assertNull(actual); return; @@ -1044,9 +1070,9 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { if (strictTime) { assertEquals(expected.getWho(), actual.getWho()); } else { - assertEquals(expected.getWho().getName(), actual.getWho().getName()); - assertEquals( - expected.getWho().getEmailAddress(), + assertEquals(expected.getWho().getName(), + actual.getWho().getName()); + assertEquals(expected.getWho().getEmailAddress(), actual.getWho().getEmailAddress()); } assertEquals(expected.getComment(), actual.getComment()); @@ -1081,4 +1107,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { } }; } + + private boolean batchesRefUpdates() { + return atomic || useReftable; + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableStackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableStackTest.java new file mode 100644 index 0000000000..a2710e1534 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableStackTest.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2019 Google LLC + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.internal.storage.file; + +import static org.eclipse.jgit.lib.Ref.Storage.PACKED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import org.eclipse.jgit.internal.storage.file.FileReftableStack.Segment; +import org.eclipse.jgit.internal.storage.reftable.MergedReftable; +import org.eclipse.jgit.internal.storage.reftable.RefCursor; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdRef; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.util.FileUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class FileReftableStackTest { + + private static Ref newRef(String name, ObjectId id) { + return new ObjectIdRef.PeeledNonTag(PACKED, name, id); + } + + private File reftableDir; + + @Before + public void setup() throws Exception { + reftableDir = FileUtils.createTempDir("rtstack", "", null); + } + + @After + public void tearDown() throws Exception { + if (reftableDir != null) { + FileUtils.delete(reftableDir, FileUtils.RECURSIVE); + } + } + + void writeBranches(FileReftableStack stack, String template, int start, + int N) throws IOException { + for (int i = 0; i < N; i++) { + while (true) { + final long next = stack.getMergedReftable().maxUpdateIndex() + + 1; + + String name = String.format(template, + Integer.valueOf(start + i)); + Ref r = newRef(name, ObjectId.zeroId()); + boolean ok = stack.addReftable(rw -> { + rw.setMinUpdateIndex(next).setMaxUpdateIndex(next).begin() + .writeRef(r); + }); + if (ok) { + break; + } + } + } + } + + public void testCompaction(int N) throws Exception { + try (FileReftableStack stack = new FileReftableStack( + new File(reftableDir, "refs"), reftableDir, null, + () -> new Config())) { + writeBranches(stack, "refs/heads/branch%d", 0, N); + MergedReftable table = stack.getMergedReftable(); + for (int i = 1; i < N; i++) { + String name = String.format("refs/heads/branch%d", + Integer.valueOf(i)); + RefCursor c = table.seekRef(name); + assertTrue(c.next()); + assertEquals(ObjectId.zeroId(), c.getRef().getObjectId()); + } + + List<String> files = Arrays.asList(reftableDir.listFiles()).stream() + .map(File::getName).collect(Collectors.toList()); + Collections.sort(files); + + assertTrue(files.size() < 20); + + FileReftableStack.CompactionStats stats = stack.getStats(); + assertEquals(0, stats.failed); + assertTrue(stats.attempted < N); + assertTrue(stats.refCount < FileReftableStack.log(N) * N); + } + } + + @Test + public void testCompaction9() throws Exception { + testCompaction(9); + } + + @Test + public void testCompaction1024() throws Exception { + testCompaction(1024); + } + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + @SuppressWarnings({ "resource", "unused" }) + @Test + public void missingReftable() throws Exception { + try (FileReftableStack stack = new FileReftableStack( + new File(reftableDir, "refs"), reftableDir, null, + () -> new Config())) { + outer: for (int i = 0; i < 10; i++) { + final long next = stack.getMergedReftable().maxUpdateIndex() + + 1; + String name = String.format("branch%d", Integer.valueOf(i)); + Ref r = newRef(name, ObjectId.zeroId()); + boolean ok = stack.addReftable(rw -> { + rw.setMinUpdateIndex(next).setMaxUpdateIndex(next).begin() + .writeRef(r); + }); + assertTrue(ok); + + List<File> files = Arrays.asList(reftableDir.listFiles()); + for (int j = 0; j < files.size(); j++) { + File f = files.get(j); + if (f.getName().endsWith(".ref")) { + assertTrue(f.delete()); + break outer; + } + } + } + } + thrown.expect(FileNotFoundException.class); + new FileReftableStack(new File(reftableDir, "refs"), reftableDir, null, + () -> new Config()); + } + + @Test + public void testSegments() { + long in[] = { 1024, 1024, 1536, 100, 64, 50, 25, 24 }; + List<Segment> got = FileReftableStack.segmentSizes(in); + Segment want[] = { new Segment(0, 3, 10, 3584), + new Segment(3, 5, 6, 164), new Segment(5, 6, 5, 50), + new Segment(6, 8, 4, 49), }; + assertEquals(got.size(), want.length); + for (int i = 0; i < want.length; i++) { + assertTrue(want[i].equals(got.get(i))); + } + } + + @Test + public void testLog2() throws Exception { + assertEquals(10, FileReftableStack.log(1024)); + assertEquals(10, FileReftableStack.log(1025)); + assertEquals(10, FileReftableStack.log(2047)); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java new file mode 100644 index 0000000000..cdc64fa1b2 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/FileReftableTest.java @@ -0,0 +1,568 @@ +/* + * Copyright (C) 2019, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.internal.storage.file; + +import static org.eclipse.jgit.lib.RefUpdate.Result.FAST_FORWARD; +import static org.eclipse.jgit.lib.RefUpdate.Result.FORCED; +import static org.eclipse.jgit.lib.RefUpdate.Result.IO_FAILURE; +import static org.eclipse.jgit.lib.RefUpdate.Result.LOCK_FAILURE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefRename; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.RefUpdate.Result; +import org.eclipse.jgit.lib.ReflogEntry; +import org.eclipse.jgit.lib.ReflogReader; +import org.eclipse.jgit.lib.RepositoryCache; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; +import org.eclipse.jgit.transport.ReceiveCommand; +import org.junit.Test; + +public class FileReftableTest extends SampleDataRepositoryTestCase { + String bCommit; + + @Override + public void setUp() throws Exception { + super.setUp(); + Ref b = db.exactRef("refs/heads/b"); + bCommit = b.getObjectId().getName(); + db.convertToReftable(false, false); + } + + @SuppressWarnings("boxing") + @Test + public void testRacyReload() throws Exception { + ObjectId id = db.resolve("master"); + int retry = 0; + try (FileRepository repo1 = new FileRepository(db.getDirectory()); + FileRepository repo2 = new FileRepository(db.getDirectory())) { + FileRepository repos[] = { repo1, repo2 }; + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 2; j++) { + FileRepository repo = repos[j]; + RefUpdate u = repo.getRefDatabase().newUpdate( + String.format("branch%d", i * 10 + j), false); + + u.setNewObjectId(id); + RefUpdate.Result r = u.update(); + if (!r.equals(Result.NEW)) { + retry++; + u = repo.getRefDatabase().newUpdate( + String.format("branch%d", i * 10 + j), false); + + u.setNewObjectId(id); + r = u.update(); + assertEquals(r, Result.NEW); + } + } + } + + // only the first one succeeds + assertEquals(retry, 19); + } + } + + @Test + public void additionalRefsAreRemoved() { + assertFalse(new File(db.getDirectory(), Constants.HEAD).exists()); + } + + @Test + public void testCompactFully() throws Exception { + ObjectId c1 = db.resolve("master^^"); + ObjectId c2 = db.resolve("master^"); + for (int i = 0; i < 5; i++) { + RefUpdate u = db.updateRef("refs/heads/master"); + u.setForceUpdate(true); + u.setNewObjectId((i%2) == 0 ? c1 : c2); + assertEquals(u.update(), FORCED); + } + + File tableDir = new File(db.getDirectory(), Constants.REFTABLE); + assertTrue(tableDir.listFiles().length > 1); + ((FileReftableDatabase)db.getRefDatabase()).compactFully(); + assertEquals(tableDir.listFiles().length,1); + } + + @Test + public void testConvert() throws Exception { + Ref h = db.exactRef("HEAD"); + assertTrue(h.isSymbolic()); + assertEquals("refs/heads/master", h.getTarget().getName()); + + Ref b = db.exactRef("refs/heads/b"); + assertFalse(b.isSymbolic()); + assertTrue(b.isPeeled()); + assertEquals(bCommit, b.getObjectId().name()); + + assertTrue(db.getRefDatabase().hasFastTipsWithSha1()); + } + + @Test + public void testConvertToRefdir() throws Exception { + db.convertToPackedRefs(false); + assertTrue(db.getRefDatabase() instanceof RefDirectory); + Ref h = db.exactRef("HEAD"); + assertTrue(h.isSymbolic()); + assertEquals("refs/heads/master", h.getTarget().getName()); + + Ref b = db.exactRef("refs/heads/b"); + assertFalse(b.isSymbolic()); + assertTrue(b.isPeeled()); + assertEquals(bCommit, b.getObjectId().name()); + + assertFalse(db.getRefDatabase().hasFastTipsWithSha1()); + } + + @Test + public void testBatchrefUpdate() throws Exception { + ObjectId cur = db.resolve("master"); + ObjectId prev = db.resolve("master^"); + + PersonIdent person = new PersonIdent("name", "mail@example.com"); + ReceiveCommand rc1 = new ReceiveCommand(ObjectId.zeroId(), cur, "refs/heads/batch1"); + ReceiveCommand rc2 = new ReceiveCommand(ObjectId.zeroId(), prev, "refs/heads/batch2"); + String msg = "message"; + try (RevWalk rw = new RevWalk(db)) { + db.getRefDatabase().newBatchUpdate() + .addCommand(rc1, rc2) + .setAtomic(true) + .setRefLogIdent(person) + .setRefLogMessage(msg, false) + .execute(rw, NullProgressMonitor.INSTANCE); + } + + assertEquals(rc1.getResult(), ReceiveCommand.Result.OK); + assertEquals(rc2.getResult(), ReceiveCommand.Result.OK); + + ReflogEntry e = db.getReflogReader("refs/heads/batch1").getLastEntry(); + assertEquals(msg, e.getComment()); + assertEquals(person, e.getWho()); + assertEquals(cur, e.getNewId()); + + e = db.getReflogReader("refs/heads/batch2").getLastEntry(); + assertEquals(msg, e.getComment()); + assertEquals(person, e.getWho()); + assertEquals(prev, e.getNewId()); + + assertEquals(cur, db.exactRef("refs/heads/batch1").getObjectId()); + assertEquals(prev, db.exactRef("refs/heads/batch2").getObjectId()); + } + + @Test + public void testFastforwardStatus() throws Exception { + ObjectId cur = db.resolve("master"); + ObjectId prev = db.resolve("master^"); + RefUpdate u = db.updateRef("refs/heads/master"); + + u.setNewObjectId(prev); + u.setForceUpdate(true); + assertEquals(FORCED, u.update()); + + RefUpdate u2 = db.updateRef("refs/heads/master"); + + u2.setNewObjectId(cur); + assertEquals(FAST_FORWARD, u2.update()); + } + + @Test + public void testUpdateChecksOldValue() throws Exception { + ObjectId cur = db.resolve("master"); + ObjectId prev = db.resolve("master^"); + RefUpdate u1 = db.updateRef("refs/heads/master"); + RefUpdate u2 = db.updateRef("refs/heads/master"); + + u1.setExpectedOldObjectId(cur); + u1.setNewObjectId(prev); + u1.setForceUpdate(true); + + u2.setExpectedOldObjectId(cur); + u2.setNewObjectId(prev); + u2.setForceUpdate(true); + + assertEquals(FORCED, u1.update()); + assertEquals(LOCK_FAILURE, u2.update()); + } + + @Test + public void testWritesymref() throws Exception { + writeSymref(Constants.HEAD, "refs/heads/a"); + assertNotNull(db.exactRef("refs/heads/b")); + } + + @Test + public void testFastforwardStatus2() throws Exception { + writeSymref(Constants.HEAD, "refs/heads/a"); + ObjectId bId = db.exactRef("refs/heads/b").getObjectId(); + RefUpdate u = db.updateRef("refs/heads/a"); + u.setNewObjectId(bId); + u.setRefLogMessage("Setup", false); + assertEquals(FAST_FORWARD, u.update()); + } + + @Test + public void testDelete() throws Exception { + RefUpdate up = db.getRefDatabase().newUpdate("refs/heads/a", false); + up.setForceUpdate(true); + RefUpdate.Result res = up.delete(); + assertEquals(res, FORCED); + assertNull(db.exactRef("refs/heads/a")); + } + + @Test + public void testDeleteWithoutHead() throws IOException { + // Prepare repository without HEAD + RefUpdate refUpdate = db.updateRef(Constants.HEAD, true); + refUpdate.setForceUpdate(true); + refUpdate.setNewObjectId(ObjectId.zeroId()); + + RefUpdate.Result updateResult = refUpdate.update(); + assertEquals(FORCED, updateResult); + + Ref r = db.exactRef("HEAD"); + assertEquals(ObjectId.zeroId(), r.getObjectId()); + RefUpdate.Result deleteHeadResult = db.updateRef(Constants.HEAD) + .delete(); + + // why does doDelete say NEW ? + assertEquals(RefUpdate.Result.NO_CHANGE, deleteHeadResult); + + // Any result is ok as long as it's not an NPE + db.updateRef(Constants.R_HEADS + "master").delete(); + } + + @Test + public void testUpdateRefDetached() throws Exception { + ObjectId pid = db.resolve("refs/heads/master"); + ObjectId ppid = db.resolve("refs/heads/master^"); + RefUpdate updateRef = db.updateRef("HEAD", true); + updateRef.setForceUpdate(true); + updateRef.setNewObjectId(ppid); + RefUpdate.Result update = updateRef.update(); + assertEquals(FORCED, update); + assertEquals(ppid, db.resolve("HEAD")); + Ref ref = db.exactRef("HEAD"); + assertEquals("HEAD", ref.getName()); + assertTrue("is detached", !ref.isSymbolic()); + + // the branch HEAD referred to is left untouched + assertEquals(pid, db.resolve("refs/heads/master")); + ReflogReader reflogReader = db.getReflogReader("HEAD"); + ReflogEntry e = reflogReader.getReverseEntries().get(0); + assertEquals(ppid, e.getNewId()); + assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress()); + assertEquals("GIT_COMMITTER_NAME", e.getWho().getName()); + assertEquals(1250379778000L, e.getWho().getWhen().getTime()); + assertEquals(pid, e.getOldId()); + } + + @Test + public void testWriteReflog() throws Exception { + ObjectId pid = db.resolve("refs/heads/master^"); + RefUpdate updateRef = db.updateRef("refs/heads/master"); + updateRef.setNewObjectId(pid); + String msg = "REFLOG!"; + updateRef.setRefLogMessage(msg, true); + PersonIdent person = new PersonIdent("name", "mail@example.com"); + updateRef.setRefLogIdent(person); + updateRef.setForceUpdate(true); + RefUpdate.Result update = updateRef.update(); + assertEquals(FORCED, update); // internal + ReflogReader r = db.getReflogReader("refs/heads/master"); + + ReflogEntry e = r.getLastEntry(); + assertEquals(e.getNewId(), pid); + assertEquals(e.getComment(), "REFLOG!: FORCED"); + assertEquals(e.getWho(), person); + } + + @Test + public void testLooseDelete() throws IOException { + final String newRef = "refs/heads/abc"; + assertNull(db.exactRef(newRef)); + + RefUpdate ref = db.updateRef(newRef); + ObjectId nonZero = db.resolve(Constants.HEAD); + assertNotEquals(nonZero, ObjectId.zeroId()); + ref.setNewObjectId(nonZero); + assertEquals(RefUpdate.Result.NEW, ref.update()); + + ref = db.updateRef(newRef); + ref.setNewObjectId(db.resolve(Constants.HEAD)); + + assertEquals(ref.delete(), RefUpdate.Result.NO_CHANGE); + + // Differs from RefupdateTest. Deleting a loose ref leaves reflog trail. + ReflogReader reader = db.getReflogReader("refs/heads/abc"); + assertEquals(ObjectId.zeroId(), reader.getReverseEntry(1).getOldId()); + assertEquals(nonZero, reader.getReverseEntry(1).getNewId()); + assertEquals(nonZero, reader.getReverseEntry(0).getOldId()); + assertEquals(ObjectId.zeroId(), reader.getReverseEntry(0).getNewId()); + } + + private static class SubclassedId extends ObjectId { + SubclassedId(AnyObjectId src) { + super(src); + } + } + + @Test + public void testNoCacheObjectIdSubclass() throws IOException { + final String newRef = "refs/heads/abc"; + final RefUpdate ru = updateRef(newRef); + final SubclassedId newid = new SubclassedId(ru.getNewObjectId()); + ru.setNewObjectId(newid); + RefUpdate.Result update = ru.update(); + assertEquals(RefUpdate.Result.NEW, update); + Ref r = db.exactRef(newRef); + assertEquals(newRef, r.getName()); + assertNotNull(r.getObjectId()); + assertNotSame(newid, r.getObjectId()); + assertSame(ObjectId.class, r.getObjectId().getClass()); + assertEquals(newid, r.getObjectId()); + List<ReflogEntry> reverseEntries1 = db.getReflogReader("refs/heads/abc") + .getReverseEntries(); + ReflogEntry entry1 = reverseEntries1.get(0); + assertEquals(1, reverseEntries1.size()); + assertEquals(ObjectId.zeroId(), entry1.getOldId()); + assertEquals(r.getObjectId(), entry1.getNewId()); + + assertEquals(new PersonIdent(db).toString(), + entry1.getWho().toString()); + assertEquals("", entry1.getComment()); + List<ReflogEntry> reverseEntries2 = db.getReflogReader("HEAD") + .getReverseEntries(); + assertEquals(0, reverseEntries2.size()); + } + + @Test + public void testDeleteSymref() throws IOException { + RefUpdate dst = updateRef("refs/heads/abc"); + assertEquals(RefUpdate.Result.NEW, dst.update()); + ObjectId id = dst.getNewObjectId(); + + RefUpdate u = db.updateRef("refs/symref"); + assertEquals(RefUpdate.Result.NEW, u.link(dst.getName())); + + Ref ref = db.exactRef(u.getName()); + assertNotNull(ref); + assertTrue(ref.isSymbolic()); + assertEquals(dst.getName(), ref.getLeaf().getName()); + assertEquals(id, ref.getLeaf().getObjectId()); + + u = db.updateRef(u.getName()); + u.setDetachingSymbolicRef(); + u.setForceUpdate(true); + assertEquals(FORCED, u.delete()); + + assertNull(db.exactRef(u.getName())); + ref = db.exactRef(dst.getName()); + assertNotNull(ref); + assertFalse(ref.isSymbolic()); + assertEquals(id, ref.getObjectId()); + } + + @Test + public void writeUnbornHead() throws Exception { + RefUpdate.Result r = db.updateRef("HEAD").link("refs/heads/unborn"); + assertEquals(FORCED, r); + + Ref head = db.exactRef("HEAD"); + assertTrue(head.isSymbolic()); + assertEquals(head.getTarget().getName(), "refs/heads/unborn"); + } + + /** + * Update the HEAD ref when the referenced branch is unborn + * + * @throws Exception + */ + @Test + public void testUpdateRefDetachedUnbornHead() throws Exception { + ObjectId ppid = db.resolve("refs/heads/master^"); + writeSymref("HEAD", "refs/heads/unborn"); + RefUpdate updateRef = db.updateRef("HEAD", true); + updateRef.setForceUpdate(true); + updateRef.setNewObjectId(ppid); + RefUpdate.Result update = updateRef.update(); + assertEquals(RefUpdate.Result.NEW, update); + assertEquals(ppid, db.resolve("HEAD")); + Ref ref = db.exactRef("HEAD"); + assertEquals("HEAD", ref.getName()); + assertTrue("is detached", !ref.isSymbolic()); + + // the branch HEAD referred to is left untouched + assertNull(db.resolve("refs/heads/unborn")); + ReflogReader reflogReader = db.getReflogReader("HEAD"); + ReflogEntry e = reflogReader.getReverseEntries().get(0); + assertEquals(ObjectId.zeroId(), e.getOldId()); + assertEquals(ppid, e.getNewId()); + assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress()); + assertEquals("GIT_COMMITTER_NAME", e.getWho().getName()); + assertEquals(1250379778000L, e.getWho().getWhen().getTime()); + } + + @Test + public void testDeleteNotFound() throws IOException { + RefUpdate ref = updateRef("refs/heads/doesnotexist"); + assertNull(db.exactRef(ref.getName())); + assertEquals(RefUpdate.Result.NEW, ref.delete()); + assertNull(db.exactRef(ref.getName())); + } + + @Test + public void testRenameSymref() throws IOException { + db.resolve("HEAD"); + RefRename r = db.renameRef("HEAD", "KOPF"); + assertEquals(IO_FAILURE, r.rename()); + } + + @Test + public void testRenameCurrentBranch() throws IOException { + ObjectId rb = db.resolve("refs/heads/b"); + writeSymref(Constants.HEAD, "refs/heads/b"); + ObjectId oldHead = db.resolve(Constants.HEAD); + assertEquals("internal test condition, b == HEAD", oldHead, rb); + RefRename renameRef = db.renameRef("refs/heads/b", + "refs/heads/new/name"); + RefUpdate.Result result = renameRef.rename(); + assertEquals(RefUpdate.Result.RENAMED, result); + assertEquals(rb, db.resolve("refs/heads/new/name")); + assertNull(db.resolve("refs/heads/b")); + assertEquals(rb, db.resolve(Constants.HEAD)); + + List<String> names = new ArrayList<>(); + names.add("HEAD"); + names.add("refs/heads/b"); + names.add("refs/heads/new/name"); + + for (String nm : names) { + ReflogReader rd = db.getReflogReader(nm); + assertNotNull(rd); + ReflogEntry last = rd.getLastEntry(); + ObjectId id = last.getNewId(); + assertTrue(ObjectId.zeroId().equals(id) || rb.equals(id)); + + id = last.getNewId(); + assertTrue(ObjectId.zeroId().equals(id) || rb.equals(id)); + + String want = "Branch: renamed b to new/name"; + assertEquals(want, last.getComment()); + } + } + + @Test + public void isGitRepository() { + assertTrue(RepositoryCache.FileKey.isGitRepository(db.getDirectory(), db.getFS())); + } + + @Test + public void testRenameDestExists() throws IOException { + ObjectId rb = db.resolve("refs/heads/b"); + writeSymref(Constants.HEAD, "refs/heads/b"); + ObjectId oldHead = db.resolve(Constants.HEAD); + assertEquals("internal test condition, b == HEAD", oldHead, rb); + RefRename renameRef = db.renameRef("refs/heads/b", "refs/heads/a"); + RefUpdate.Result result = renameRef.rename(); + assertEquals(RefUpdate.Result.LOCK_FAILURE, result); + } + + @Test + public void testRenameAtomic() throws IOException { + ObjectId prevId = db.resolve("refs/heads/master^"); + + RefRename rename = db.renameRef("refs/heads/master", + "refs/heads/newmaster"); + + RefUpdate updateRef = db.updateRef("refs/heads/master"); + updateRef.setNewObjectId(prevId); + updateRef.setForceUpdate(true); + assertEquals(FORCED, updateRef.update()); + assertEquals(RefUpdate.Result.LOCK_FAILURE, rename.rename()); + } + + @Test + public void reftableRefsStorageClass() throws IOException { + Ref b = db.exactRef("refs/heads/b"); + assertEquals(Ref.Storage.PACKED, b.getStorage()); + } + + private RefUpdate updateRef(String name) throws IOException { + final RefUpdate ref = db.updateRef(name); + ref.setNewObjectId(db.resolve(Constants.HEAD)); + return ref; + } + + private void writeSymref(String src, String dst) throws IOException { + RefUpdate u = db.updateRef(src); + switch (u.link(dst)) { + case NEW: + case FORCED: + case NO_CHANGE: + break; + default: + fail("link " + src + " to " + dst); + } + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java index d5bc61a692..9016a02b0b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileSnapshotTest.java @@ -295,9 +295,8 @@ public class PackFileSnapshotTest extends RepositoryTestCase { Files.copy(src, dstOut); return dst; } - } else { - return Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING); } + return Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING); } private Path copyPack(Path base, String srcSuffix, String dstSuffix) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java index 1e2341b6a5..3f281c49d2 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java @@ -468,22 +468,22 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { @Test public void testDeltaStatistics() throws Exception { config.setDeltaCompress(true); + // TestRepository will close repo FileRepository repo = createBareRepository(); ArrayList<RevObject> blobs = new ArrayList<>(); try (TestRepository<FileRepository> testRepo = new TestRepository<>( repo)) { blobs.add(testRepo.blob(genDeltableData(1000))); blobs.add(testRepo.blob(genDeltableData(1005))); - } - - try (PackWriter pw = new PackWriter(repo)) { - NullProgressMonitor m = NullProgressMonitor.INSTANCE; - pw.preparePack(blobs.iterator()); - pw.writePack(m, m, os); - PackStatistics stats = pw.getStatistics(); - assertEquals(1, stats.getTotalDeltas()); - assertTrue("Delta bytes not set.", - stats.byObjectType(OBJ_BLOB).getDeltaBytes() > 0); + try (PackWriter pw = new PackWriter(repo)) { + NullProgressMonitor m = NullProgressMonitor.INSTANCE; + pw.preparePack(blobs.iterator()); + pw.writePack(m, m, os); + PackStatistics stats = pw.getStatistics(); + assertEquals(1, stats.getTotalDeltas()); + assertTrue("Delta bytes not set.", + stats.byObjectType(OBJ_BLOB).getDeltaBytes() > 0); + } } } @@ -535,6 +535,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { @Test public void testExclude() throws Exception { + // TestRepository closes repo FileRepository repo = createBareRepository(); try (TestRepository<FileRepository> testRepo = new TestRepository<>( @@ -568,98 +569,102 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { @Test public void testShallowIsMinimalDepth1() throws Exception { - FileRepository repo = setupRepoForShallowFetch(); - - PackIndex idx = writeShallowPack(repo, 1, wants(c2), NONE, NONE); - assertContent(idx, Arrays.asList(c2.getId(), c2.getTree().getId(), - contentA.getId(), contentB.getId())); - - // Client already has blobs A and B, verify those are not packed. - idx = writeShallowPack(repo, 1, wants(c5), haves(c2), shallows(c2)); - assertContent(idx, Arrays.asList(c5.getId(), c5.getTree().getId(), - contentC.getId(), contentD.getId(), contentE.getId())); + try (FileRepository repo = setupRepoForShallowFetch()) { + PackIndex idx = writeShallowPack(repo, 1, wants(c2), NONE, NONE); + assertContent(idx, Arrays.asList(c2.getId(), c2.getTree().getId(), + contentA.getId(), contentB.getId())); + + // Client already has blobs A and B, verify those are not packed. + idx = writeShallowPack(repo, 1, wants(c5), haves(c2), shallows(c2)); + assertContent(idx, Arrays.asList(c5.getId(), c5.getTree().getId(), + contentC.getId(), contentD.getId(), contentE.getId())); + } } @Test public void testShallowIsMinimalDepth2() throws Exception { - FileRepository repo = setupRepoForShallowFetch(); - - PackIndex idx = writeShallowPack(repo, 2, wants(c2), NONE, NONE); - assertContent(idx, - Arrays.asList(c1.getId(), c2.getId(), c1.getTree().getId(), - c2.getTree().getId(), contentA.getId(), - contentB.getId())); - - // Client already has blobs A and B, verify those are not packed. - idx = writeShallowPack(repo, 2, wants(c5), haves(c1, c2), shallows(c1)); - assertContent(idx, - Arrays.asList(c4.getId(), c5.getId(), c4.getTree().getId(), - c5.getTree().getId(), contentC.getId(), - contentD.getId(), contentE.getId())); + try (FileRepository repo = setupRepoForShallowFetch()) { + PackIndex idx = writeShallowPack(repo, 2, wants(c2), NONE, NONE); + assertContent(idx, + Arrays.asList(c1.getId(), c2.getId(), c1.getTree().getId(), + c2.getTree().getId(), contentA.getId(), + contentB.getId())); + + // Client already has blobs A and B, verify those are not packed. + idx = writeShallowPack(repo, 2, wants(c5), haves(c1, c2), + shallows(c1)); + assertContent(idx, + Arrays.asList(c4.getId(), c5.getId(), c4.getTree().getId(), + c5.getTree().getId(), contentC.getId(), + contentD.getId(), contentE.getId())); + } } @Test public void testShallowFetchShallowParentDepth1() throws Exception { - FileRepository repo = setupRepoForShallowFetch(); - - PackIndex idx = writeShallowPack(repo, 1, wants(c5), NONE, NONE); - assertContent(idx, - Arrays.asList(c5.getId(), c5.getTree().getId(), - contentA.getId(), contentB.getId(), contentC.getId(), - contentD.getId(), contentE.getId())); - - idx = writeShallowPack(repo, 1, wants(c4), haves(c5), shallows(c5)); - assertContent(idx, Arrays.asList(c4.getId(), c4.getTree().getId())); + try (FileRepository repo = setupRepoForShallowFetch()) { + PackIndex idx = writeShallowPack(repo, 1, wants(c5), NONE, NONE); + assertContent(idx, Arrays.asList(c5.getId(), c5.getTree().getId(), + contentA.getId(), contentB.getId(), contentC.getId(), + contentD.getId(), contentE.getId())); + + idx = writeShallowPack(repo, 1, wants(c4), haves(c5), shallows(c5)); + assertContent(idx, Arrays.asList(c4.getId(), c4.getTree().getId())); + } } @Test public void testShallowFetchShallowParentDepth2() throws Exception { - FileRepository repo = setupRepoForShallowFetch(); - - PackIndex idx = writeShallowPack(repo, 2, wants(c5), NONE, NONE); - assertContent(idx, - Arrays.asList(c4.getId(), c5.getId(), c4.getTree().getId(), - c5.getTree().getId(), contentA.getId(), - contentB.getId(), contentC.getId(), contentD.getId(), - contentE.getId())); - - idx = writeShallowPack(repo, 2, wants(c3), haves(c4, c5), shallows(c4)); - assertContent(idx, Arrays.asList(c2.getId(), c3.getId(), - c2.getTree().getId(), c3.getTree().getId())); + try (FileRepository repo = setupRepoForShallowFetch()) { + PackIndex idx = writeShallowPack(repo, 2, wants(c5), NONE, NONE); + assertContent(idx, + Arrays.asList(c4.getId(), c5.getId(), c4.getTree().getId(), + c5.getTree().getId(), contentA.getId(), + contentB.getId(), contentC.getId(), + contentD.getId(), contentE.getId())); + + idx = writeShallowPack(repo, 2, wants(c3), haves(c4, c5), + shallows(c4)); + assertContent(idx, Arrays.asList(c2.getId(), c3.getId(), + c2.getTree().getId(), c3.getTree().getId())); + } } @Test public void testShallowFetchShallowAncestorDepth1() throws Exception { - FileRepository repo = setupRepoForShallowFetch(); - - PackIndex idx = writeShallowPack(repo, 1, wants(c5), NONE, NONE); - assertContent(idx, - Arrays.asList(c5.getId(), c5.getTree().getId(), - contentA.getId(), contentB.getId(), contentC.getId(), - contentD.getId(), contentE.getId())); - - idx = writeShallowPack(repo, 1, wants(c3), haves(c5), shallows(c5)); - assertContent(idx, Arrays.asList(c3.getId(), c3.getTree().getId())); + try (FileRepository repo = setupRepoForShallowFetch()) { + PackIndex idx = writeShallowPack(repo, 1, wants(c5), NONE, NONE); + assertContent(idx, Arrays.asList(c5.getId(), c5.getTree().getId(), + contentA.getId(), contentB.getId(), contentC.getId(), + contentD.getId(), contentE.getId())); + + idx = writeShallowPack(repo, 1, wants(c3), haves(c5), shallows(c5)); + assertContent(idx, Arrays.asList(c3.getId(), c3.getTree().getId())); + } } @Test public void testShallowFetchShallowAncestorDepth2() throws Exception { - FileRepository repo = setupRepoForShallowFetch(); - - PackIndex idx = writeShallowPack(repo, 2, wants(c5), NONE, NONE); - assertContent(idx, - Arrays.asList(c4.getId(), c5.getId(), c4.getTree().getId(), - c5.getTree().getId(), contentA.getId(), - contentB.getId(), contentC.getId(), contentD.getId(), - contentE.getId())); - - idx = writeShallowPack(repo, 2, wants(c2), haves(c4, c5), shallows(c4)); - assertContent(idx, Arrays.asList(c1.getId(), c2.getId(), - c1.getTree().getId(), c2.getTree().getId())); + try (FileRepository repo = setupRepoForShallowFetch()) { + PackIndex idx = writeShallowPack(repo, 2, wants(c5), NONE, NONE); + assertContent(idx, + Arrays.asList(c4.getId(), c5.getId(), c4.getTree().getId(), + c5.getTree().getId(), contentA.getId(), + contentB.getId(), contentC.getId(), + contentD.getId(), contentE.getId())); + + idx = writeShallowPack(repo, 2, wants(c2), haves(c4, c5), + shallows(c4)); + assertContent(idx, Arrays.asList(c1.getId(), c2.getId(), + c1.getTree().getId(), c2.getTree().getId())); + } } private FileRepository setupRepoForShallowFetch() throws Exception { FileRepository repo = createBareRepository(); + // TestRepository will close the repo, but we need to return an open + // one! + repo.incrementOpen(); try (TestRepository<Repository> r = new TestRepository<>(repo)) { BranchBuilder bb = r.branch("refs/heads/master"); contentA = r.blob("A"); @@ -680,8 +685,9 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { private static PackIndex writePack(FileRepository repo, Set<? extends ObjectId> want, Set<ObjectIdSet> excludeObjects) throws IOException { - RevWalk walk = new RevWalk(repo); - return writePack(repo, walk, 0, want, NONE, excludeObjects); + try (RevWalk walk = new RevWalk(repo)) { + return writePack(repo, walk, 0, want, NONE, excludeObjects); + } } private static PackIndex writeShallowPack(FileRepository repo, int depth, @@ -689,9 +695,10 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { Set<? extends ObjectId> shallow) throws IOException { // During negotiation, UploadPack would have set up a DepthWalk and // marked the client's "shallow" commits. Emulate that here. - DepthWalk.RevWalk walk = new DepthWalk.RevWalk(repo, depth - 1); - walk.assumeShallow(shallow); - return writePack(repo, walk, depth, want, have, EMPTY_ID_SET); + try (DepthWalk.RevWalk walk = new DepthWalk.RevWalk(repo, depth - 1)) { + walk.assumeShallow(shallow); + return writePack(repo, walk, depth, want, have, EMPTY_ID_SET); + } } private static PackIndex writePack(FileRepository repo, RevWalk walk, @@ -707,6 +714,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { if (depth > 0) { pw.setShallowPack(depth, null); } + // ow doesn't need to be closed; caller closes walk. ObjectWalk ow = walk.toObjectWalkWithSameObjects(); pw.preparePack(NullProgressMonitor.INSTANCE, ow, want, have, NONE); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java index 3a43564180..bd2c203f5c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java @@ -45,9 +45,12 @@ package org.eclipse.jgit.internal.storage.file; -import static org.eclipse.jgit.junit.Assert.assertEquals; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.eclipse.jgit.junit.Assert.assertEquals; import static org.eclipse.jgit.lib.Constants.LOCK_SUFFIX; +import static org.eclipse.jgit.lib.RefUpdate.Result.FORCED; +import static org.eclipse.jgit.lib.RefUpdate.Result.IO_FAILURE; +import static org.eclipse.jgit.lib.RefUpdate.Result.LOCK_FAILURE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -82,7 +85,6 @@ import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; import org.junit.Test; public class RefUpdateTest extends SampleDataRepositoryTestCase { - private void writeSymref(String src, String dst) throws IOException { RefUpdate u = db.updateRef(src); switch (u.link(dst)) { @@ -233,6 +235,17 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { } @Test + public void testWriteReflog() throws IOException { + ObjectId pid = db.resolve("refs/heads/master^"); + RefUpdate updateRef = db.updateRef("refs/heads/master"); + updateRef.setNewObjectId(pid); + updateRef.setForceUpdate(true); + Result update = updateRef.update(); + assertEquals(Result.FORCED, update); + assertEquals(1,db.getReflogReader("refs/heads/master").getReverseEntries().size()); + } + + @Test public void testLooseDelete() throws IOException { final String newRef = "refs/heads/abc"; RefUpdate ref = updateRef(newRef); @@ -379,6 +392,8 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { refUpdate.setNewObjectId(ObjectId.zeroId()); Result updateResult = refUpdate.update(); assertEquals(Result.FORCED, updateResult); + + assertEquals(ObjectId.zeroId(), db.exactRef("HEAD").getObjectId()); Result deleteHeadResult = db.updateRef(Constants.HEAD).delete(); assertEquals(Result.NO_CHANGE, deleteHeadResult); @@ -903,6 +918,45 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase { } @Test + public void testUpdateChecksOldValue() throws Exception { + ObjectId cur = db.resolve("master"); + ObjectId prev = db.resolve("master^"); + RefUpdate u1 = db.updateRef("refs/heads/master"); + RefUpdate u2 = db.updateRef("refs/heads/master"); + + u1.setExpectedOldObjectId(cur); + u1.setNewObjectId(prev); + u1.setForceUpdate(true); + + u2.setExpectedOldObjectId(cur); + u2.setNewObjectId(prev); + u2.setForceUpdate(true); + + assertEquals(FORCED, u1.update()); + assertEquals(LOCK_FAILURE, u2.update()); + } + + @Test + public void testRenameAtomic() throws IOException { + ObjectId prevId = db.resolve("refs/heads/master^"); + + RefRename rename = db.renameRef("refs/heads/master", "refs/heads/newmaster"); + + RefUpdate updateRef = db.updateRef("refs/heads/master"); + updateRef.setNewObjectId(prevId); + updateRef.setForceUpdate(true); + assertEquals(FORCED, updateRef.update()); + assertEquals(RefUpdate.Result.LOCK_FAILURE, rename.rename()); + } + + @Test + public void testRenameSymref() throws IOException { + db.resolve("HEAD"); + RefRename r = db.renameRef("HEAD", "KOPF"); + assertEquals(IO_FAILURE, r.rename()); + } + + @Test public void testRenameRefNameColission1avoided() throws IOException { // setup ObjectId rb = db.resolve("refs/heads/b"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java index 43f30d8ca8..5100c1ce29 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java @@ -145,13 +145,14 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { } File theDir = new File(repo1Parent, Constants.DOT_GIT); - FileRepository r = (FileRepository) new FileRepositoryBuilder() - .setGitDir(theDir).build(); - assertEqualsPath(theDir, r.getDirectory()); - assertEqualsPath(repo1Parent, r.getWorkTree()); - assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); - assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase() - .getDirectory()); + try (FileRepository r = (FileRepository) new FileRepositoryBuilder() + .setGitDir(theDir).build()) { + assertEqualsPath(theDir, r.getDirectory()); + assertEqualsPath(repo1Parent, r.getWorkTree()); + assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); + assertEqualsPath(new File(theDir, Constants.OBJECTS), + r.getObjectDatabase().getDirectory()); + } } /** @@ -170,14 +171,15 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { } File theDir = new File(repo1Parent, Constants.DOT_GIT); - FileRepository r = (FileRepository) new FileRepositoryBuilder() + try (FileRepository r = (FileRepository) new FileRepositoryBuilder() .setGitDir(theDir).setWorkTree(repo1Parent.getParentFile()) - .build(); - assertEqualsPath(theDir, r.getDirectory()); - assertEqualsPath(repo1Parent.getParentFile(), r.getWorkTree()); - assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); - assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase() - .getDirectory()); + .build()) { + assertEqualsPath(theDir, r.getDirectory()); + assertEqualsPath(repo1Parent.getParentFile(), r.getWorkTree()); + assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); + assertEqualsPath(new File(theDir, Constants.OBJECTS), + r.getObjectDatabase().getDirectory()); + } } /** @@ -195,13 +197,14 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { } File theDir = new File(repo1Parent, Constants.DOT_GIT); - FileRepository r = (FileRepository) new FileRepositoryBuilder() - .setWorkTree(repo1Parent).build(); - assertEqualsPath(theDir, r.getDirectory()); - assertEqualsPath(repo1Parent, r.getWorkTree()); - assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); - assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase() - .getDirectory()); + try (FileRepository r = (FileRepository) new FileRepositoryBuilder() + .setWorkTree(repo1Parent).build()) { + assertEqualsPath(theDir, r.getDirectory()); + assertEqualsPath(repo1Parent, r.getWorkTree()); + assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); + assertEqualsPath(new File(theDir, Constants.OBJECTS), + r.getObjectDatabase().getDirectory()); + } } /** @@ -224,13 +227,14 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { } File theDir = new File(repo1Parent, Constants.DOT_GIT); - FileRepository r = (FileRepository) new FileRepositoryBuilder() - .setGitDir(theDir).build(); - assertEqualsPath(theDir, r.getDirectory()); - assertEqualsPath(workdir, r.getWorkTree()); - assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); - assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase() - .getDirectory()); + try (FileRepository r = (FileRepository) new FileRepositoryBuilder() + .setGitDir(theDir).build()) { + assertEqualsPath(theDir, r.getDirectory()); + assertEqualsPath(workdir, r.getWorkTree()); + assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); + assertEqualsPath(new File(theDir, Constants.OBJECTS), + r.getObjectDatabase().getDirectory()); + } } /** @@ -253,13 +257,14 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { } File theDir = new File(repo1Parent, Constants.DOT_GIT); - FileRepository r = (FileRepository) new FileRepositoryBuilder() - .setGitDir(theDir).build(); - assertEqualsPath(theDir, r.getDirectory()); - assertEqualsPath(workdir, r.getWorkTree()); - assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); - assertEqualsPath(new File(theDir, Constants.OBJECTS), r.getObjectDatabase() - .getDirectory()); + try (FileRepository r = (FileRepository) new FileRepositoryBuilder() + .setGitDir(theDir).build()) { + assertEqualsPath(theDir, r.getDirectory()); + assertEqualsPath(workdir, r.getWorkTree()); + assertEqualsPath(new File(theDir, "index"), r.getIndexFile()); + assertEqualsPath(new File(theDir, Constants.OBJECTS), + r.getObjectDatabase().getDirectory()); + } } /** @@ -306,17 +311,20 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { // open when we create it we won't write the object file out as a loose // object (as it already exists in the pack). // - final Repository newdb = createBareRepository(); - try (ObjectInserter oi = newdb.newObjectInserter()) { - final ObjectId treeId = oi.insert(new TreeFormatter()); - assertEquals("4b825dc642cb6eb9a060e54bf8d69288fbee4904", - treeId.name()); + try (Repository newdb = createBareRepository()) { + try (ObjectInserter oi = newdb.newObjectInserter()) { + final ObjectId treeId = oi.insert(new TreeFormatter()); + assertEquals("4b825dc642cb6eb9a060e54bf8d69288fbee4904", + treeId.name()); + } + + final File o = new File( + new File(new File(newdb.getDirectory(), Constants.OBJECTS), + "4b"), + "825dc642cb6eb9a060e54bf8d69288fbee4904"); + assertTrue("Exists " + o, o.isFile()); + assertTrue("Read-only " + o, !o.canWrite()); } - - final File o = new File(new File(new File(newdb.getDirectory(), - Constants.OBJECTS), "4b"), "825dc642cb6eb9a060e54bf8d69288fbee4904"); - assertTrue("Exists " + o, o.isFile()); - assertTrue("Read-only " + o, !o.canWrite()); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java index 11d6439931..53d13f1d60 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/MergedReftableTest.java @@ -187,6 +187,19 @@ public class MergedReftableTest { } } + @Test + public void tableByIDDeletion() throws IOException { + List<Ref> delta1 = Arrays.asList( + ref("refs/heads/apple", 1), + ref("refs/heads/master", 2)); + List<Ref> delta2 = Arrays.asList(ref("refs/heads/master", 3)); + + MergedReftable mr = merge(write(delta1), write(delta2)); + try (RefCursor rc = mr.byObjectId(id(2))) { + assertFalse(rc.next()); + } + } + @SuppressWarnings("boxing") @Test public void fourTableScan() throws IOException { @@ -225,29 +238,6 @@ public class MergedReftableTest { } @Test - public void scanDuplicates() throws IOException { - List<Ref> delta1 = Arrays.asList( - ref("refs/heads/apple", 1), - ref("refs/heads/banana", 2)); - List<Ref> delta2 = Arrays.asList( - ref("refs/heads/apple", 3), - ref("refs/heads/apple", 4)); - - MergedReftable mr = merge(write(delta1, 1000), write(delta2, 2000)); - try (RefCursor rc = mr.allRefs()) { - assertTrue(rc.next()); - assertEquals("refs/heads/apple", rc.getRef().getName()); - assertEquals(id(3), rc.getRef().getObjectId()); - assertEquals(2000, rc.getRef().getUpdateIndex()); - assertTrue(rc.next()); - assertEquals("refs/heads/banana", rc.getRef().getName()); - assertEquals(id(2), rc.getRef().getObjectId()); - assertEquals(1000, rc.getRef().getUpdateIndex()); - assertFalse(rc.next()); - } - } - - @Test public void scanIncludeDeletes() throws IOException { List<Ref> delta1 = Arrays.asList(ref("refs/heads/next", 4)); List<Ref> delta2 = Arrays.asList(delete("refs/heads/next")); @@ -297,10 +287,10 @@ public class MergedReftableTest { @Test public void missedUpdate() throws IOException { ByteArrayOutputStream buf = new ByteArrayOutputStream(); - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(buf) .setMinUpdateIndex(1) .setMaxUpdateIndex(3) - .begin(buf); + .begin(); writer.writeRef(ref("refs/heads/a", 1), 1); writer.writeRef(ref("refs/heads/c", 3), 3); writer.finish(); @@ -337,13 +327,13 @@ public class MergedReftableTest { List<Ref> delta2 = Arrays.asList(delete("refs/heads/next")); List<Ref> delta3 = Arrays.asList(ref("refs/heads/master", 8)); - ReftableCompactor compactor = new ReftableCompactor(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ReftableCompactor compactor = new ReftableCompactor(out); compactor.addAll(Arrays.asList( read(write(delta1)), read(write(delta2)), read(write(delta3)))); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - compactor.compact(out); + compactor.compact(); byte[] table = out.toByteArray(); ReftableReader reader = read(table); @@ -414,7 +404,7 @@ public class MergedReftableTest { } private static MergedReftable merge(byte[]... table) { - List<Reftable> stack = new ArrayList<>(table.length); + List<ReftableReader> stack = new ArrayList<>(table.length); for (byte[] b : table) { stack.add(read(b)); } @@ -461,10 +451,10 @@ public class MergedReftableTest { private byte[] write(Collection<Ref> refs, long updateIndex) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - new ReftableWriter() + new ReftableWriter(buffer) .setMinUpdateIndex(updateIndex) .setMaxUpdateIndex(updateIndex) - .begin(buffer) + .begin() .sortAndWriteRefs(refs) .finish(); return buffer.toByteArray(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java index 1ea73097fe..9a7f240951 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableCompactorTest.java @@ -67,9 +67,10 @@ public class ReftableCompactorTest { @Test public void noTables() throws IOException { - ReftableCompactor compactor = new ReftableCompactor(); + ReftableCompactor compactor; try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { - compactor.compact(out); + compactor = new ReftableCompactor(out); + compactor.compact(); } Stats stats = compactor.getStats(); assertEquals(0, stats.minUpdateIndex()); @@ -81,10 +82,10 @@ public class ReftableCompactorTest { public void oneTable() throws IOException { byte[] inTab; try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) { - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(inBuf) .setMinUpdateIndex(0) .setMaxUpdateIndex(0) - .begin(inBuf); + .begin(); writer.writeRef(ref(MASTER, 1)); writer.finish(); @@ -92,10 +93,11 @@ public class ReftableCompactorTest { } byte[] outTab; - ReftableCompactor compactor = new ReftableCompactor(); + ReftableCompactor compactor; try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) { + compactor = new ReftableCompactor(outBuf); compactor.tryAddFirst(read(inTab)); - compactor.compact(outBuf); + compactor.compact(); outTab = outBuf.toByteArray(); } Stats stats = compactor.getStats(); @@ -116,10 +118,10 @@ public class ReftableCompactorTest { public void twoTablesOneRef() throws IOException { byte[] inTab1; try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) { - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(inBuf) .setMinUpdateIndex(0) .setMaxUpdateIndex(0) - .begin(inBuf); + .begin(); writer.writeRef(ref(MASTER, 1)); writer.finish(); @@ -128,10 +130,10 @@ public class ReftableCompactorTest { byte[] inTab2; try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) { - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(inBuf) .setMinUpdateIndex(1) .setMaxUpdateIndex(1) - .begin(inBuf); + .begin(); writer.writeRef(ref(MASTER, 2)); writer.finish(); @@ -139,10 +141,11 @@ public class ReftableCompactorTest { } byte[] outTab; - ReftableCompactor compactor = new ReftableCompactor(); + ReftableCompactor compactor; try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) { + compactor = new ReftableCompactor(outBuf); compactor.addAll(Arrays.asList(read(inTab1), read(inTab2))); - compactor.compact(outBuf); + compactor.compact(); outTab = outBuf.toByteArray(); } Stats stats = compactor.getStats(); @@ -163,10 +166,10 @@ public class ReftableCompactorTest { public void twoTablesTwoRefs() throws IOException { byte[] inTab1; try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) { - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(inBuf) .setMinUpdateIndex(0) .setMaxUpdateIndex(0) - .begin(inBuf); + .begin(); writer.writeRef(ref(MASTER, 1)); writer.writeRef(ref(NEXT, 2)); @@ -176,10 +179,10 @@ public class ReftableCompactorTest { byte[] inTab2; try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) { - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(inBuf) .setMinUpdateIndex(1) .setMaxUpdateIndex(1) - .begin(inBuf); + .begin(); writer.writeRef(ref(MASTER, 3)); writer.finish(); @@ -187,10 +190,11 @@ public class ReftableCompactorTest { } byte[] outTab; - ReftableCompactor compactor = new ReftableCompactor(); + ReftableCompactor compactor; try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) { + compactor = new ReftableCompactor(outBuf); compactor.addAll(Arrays.asList(read(inTab1), read(inTab2))); - compactor.compact(outBuf); + compactor.compact(); outTab = outBuf.toByteArray(); } Stats stats = compactor.getStats(); @@ -216,10 +220,10 @@ public class ReftableCompactorTest { public void twoTablesIncludeOneDelete() throws IOException { byte[] inTab1; try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) { - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(inBuf) .setMinUpdateIndex(0) .setMaxUpdateIndex(0) - .begin(inBuf); + .begin(); writer.writeRef(ref(MASTER, 1)); writer.finish(); @@ -228,10 +232,10 @@ public class ReftableCompactorTest { byte[] inTab2; try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) { - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(inBuf) .setMinUpdateIndex(1) .setMaxUpdateIndex(1) - .begin(inBuf); + .begin(); writer.writeRef(tombstone(MASTER)); writer.finish(); @@ -239,11 +243,12 @@ public class ReftableCompactorTest { } byte[] outTab; - ReftableCompactor compactor = new ReftableCompactor(); + ReftableCompactor compactor; try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) { + compactor = new ReftableCompactor(outBuf); compactor.setIncludeDeletes(true); compactor.addAll(Arrays.asList(read(inTab1), read(inTab2))); - compactor.compact(outBuf); + compactor.compact(); outTab = outBuf.toByteArray(); } Stats stats = compactor.getStats(); @@ -261,10 +266,10 @@ public class ReftableCompactorTest { public void twoTablesNotIncludeOneDelete() throws IOException { byte[] inTab1; try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) { - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(inBuf) .setMinUpdateIndex(0) .setMaxUpdateIndex(0) - .begin(inBuf); + .begin(); writer.writeRef(ref(MASTER, 1)); writer.finish(); @@ -273,10 +278,10 @@ public class ReftableCompactorTest { byte[] inTab2; try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) { - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(inBuf) .setMinUpdateIndex(1) .setMaxUpdateIndex(1) - .begin(inBuf); + .begin(); writer.writeRef(tombstone(MASTER)); writer.finish(); @@ -284,11 +289,12 @@ public class ReftableCompactorTest { } byte[] outTab; - ReftableCompactor compactor = new ReftableCompactor(); + ReftableCompactor compactor; try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) { + compactor = new ReftableCompactor(outBuf); compactor.setIncludeDeletes(false); compactor.addAll(Arrays.asList(read(inTab1), read(inTab2))); - compactor.compact(outBuf); + compactor.compact(); outTab = outBuf.toByteArray(); } Stats stats = compactor.getStats(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java index 0e33fa6e76..ec8b7593f0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftable/ReftableTest.java @@ -66,6 +66,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.io.BlockSource; @@ -76,6 +78,7 @@ import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.ReflogEntry; import org.eclipse.jgit.lib.SymbolicRef; +import org.hamcrest.Matchers; import org.junit.Test; public class ReftableTest { @@ -134,9 +137,9 @@ public class ReftableTest { byte[] table; ReftableConfig cfg = new ReftableConfig(); cfg.setIndexObjects(false); - ReftableWriter writer = new ReftableWriter().setConfig(cfg); try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) { - writer.begin(buf); + ReftableWriter writer = new ReftableWriter(buf).setConfig(cfg); + writer.begin(); assertEquals(92, writer.estimateTotalBytes()); writer.writeRef(exp); assertEquals(expBytes, writer.estimateTotalBytes()); @@ -146,12 +149,13 @@ public class ReftableTest { assertEquals(expBytes, table.length); } - @SuppressWarnings("boxing") @Test public void estimateCurrentBytesWithIndex() throws IOException { List<Ref> refs = new ArrayList<>(); for (int i = 1; i <= 5670; i++) { - refs.add(ref(String.format("refs/heads/%04d", i), i)); + @SuppressWarnings("boxing") + Ref ref = ref(String.format("refs/heads/%04d", i), i); + refs.add(ref); } ReftableConfig cfg = new ReftableConfig(); @@ -160,9 +164,9 @@ public class ReftableTest { int expBytes = 147860; byte[] table; - ReftableWriter writer = new ReftableWriter().setConfig(cfg); try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) { - writer.begin(buf); + ReftableWriter writer = new ReftableWriter(buf).setConfig(cfg); + writer.begin(); writer.sortAndWriteRefs(refs); assertEquals(expBytes, writer.estimateTotalBytes()); writer.finish(); @@ -174,6 +178,69 @@ public class ReftableTest { } @Test + public void hasObjMapRefs() throws IOException { + ArrayList<Ref> refs = new ArrayList<>(); + refs.add(ref(MASTER, 1)); + byte[] table = write(refs); + ReftableReader t = read(table); + assertTrue(t.hasObjectMap()); + } + + @Test + public void hasObjMapRefsSmallTable() throws IOException { + ArrayList<Ref> refs = new ArrayList<>(); + ReftableConfig cfg = new ReftableConfig(); + cfg.setIndexObjects(false); + refs.add(ref(MASTER, 1)); + byte[] table = write(refs); + ReftableReader t = read(table); + assertTrue(t.hasObjectMap()); + } + + @Test + public void hasObjLogs() throws IOException { + PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + String msg = "test"; + ReftableConfig cfg = new ReftableConfig(); + cfg.setIndexObjects(false); + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + ReftableWriter writer = new ReftableWriter(buffer) + .setMinUpdateIndex(1) + .setConfig(cfg) + .setMaxUpdateIndex(1) + .begin(); + + writer.writeLog("master", 1, who, ObjectId.zeroId(), id(1), msg); + writer.finish(); + byte[] table = buffer.toByteArray(); + + ReftableReader t = read(table); + assertTrue(t.hasObjectMap()); + } + + @Test + public void hasObjMapRefsNoIndexObjects() throws IOException { + ArrayList<Ref> refs = new ArrayList<>(); + ReftableConfig cfg = new ReftableConfig(); + cfg.setIndexObjects(false); + cfg.setRefBlockSize(256); + cfg.setAlignBlocks(true); + + // Fill up 5 blocks. + int N = 256 * 5 / 25; + for (int i= 0; i < N; i++) { + @SuppressWarnings("boxing") + Ref ref = ref(String.format("%02d/xxxxxxxxxx", i), i); + refs.add(ref); + } + byte[] table = write(refs, cfg); + + ReftableReader t = read(table); + assertFalse(t.hasObjectMap()); + } + + @Test public void oneIdRef() throws IOException { Ref exp = ref(MASTER, 1); byte[] table = write(exp); @@ -361,12 +428,13 @@ public class ReftableTest { } } - @SuppressWarnings("boxing") @Test public void indexScan() throws IOException { List<Ref> refs = new ArrayList<>(); for (int i = 1; i <= 5670; i++) { - refs.add(ref(String.format("refs/heads/%04d", i), i)); + @SuppressWarnings("boxing") + Ref ref = ref(String.format("refs/heads/%04d", i), i); + refs.add(ref); } byte[] table = write(refs); @@ -375,12 +443,13 @@ public class ReftableTest { assertScan(refs, read(table)); } - @SuppressWarnings("boxing") @Test public void indexSeek() throws IOException { List<Ref> refs = new ArrayList<>(); for (int i = 1; i <= 5670; i++) { - refs.add(ref(String.format("refs/heads/%04d", i), i)); + @SuppressWarnings("boxing") + Ref ref = ref(String.format("refs/heads/%04d", i), i); + refs.add(ref); } byte[] table = write(refs); @@ -389,12 +458,13 @@ public class ReftableTest { assertSeek(refs, read(table)); } - @SuppressWarnings("boxing") @Test public void noIndexScan() throws IOException { List<Ref> refs = new ArrayList<>(); for (int i = 1; i <= 567; i++) { - refs.add(ref(String.format("refs/heads/%03d", i), i)); + @SuppressWarnings("boxing") + Ref ref = ref(String.format("refs/heads/%03d", i), i); + refs.add(ref); } byte[] table = write(refs); @@ -404,12 +474,13 @@ public class ReftableTest { assertScan(refs, read(table)); } - @SuppressWarnings("boxing") @Test public void noIndexSeek() throws IOException { List<Ref> refs = new ArrayList<>(); for (int i = 1; i <= 567; i++) { - refs.add(ref(String.format("refs/heads/%03d", i), i)); + @SuppressWarnings("boxing") + Ref ref = ref(String.format("refs/heads/%03d", i), i); + refs.add(ref); } byte[] table = write(refs); @@ -418,27 +489,29 @@ public class ReftableTest { } @Test - public void invalidRefWriteOrder() throws IOException { + public void invalidRefWriteOrderSortAndWrite() { Ref master = ref(MASTER, 1); - Ref next = ref(NEXT, 2); - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(new ByteArrayOutputStream()) .setMinUpdateIndex(1) .setMaxUpdateIndex(1) - .begin(new ByteArrayOutputStream()); + .begin(); + + List<Ref> refs = new ArrayList<>(); + refs.add(master); + refs.add(master); - writer.writeRef(next); IllegalArgumentException e = assertThrows( IllegalArgumentException.class, - () -> writer.writeRef(master)); + () -> writer.sortAndWriteRefs(refs)); assertThat(e.getMessage(), containsString("records must be increasing")); } @Test public void invalidReflogWriteOrderUpdateIndex() throws IOException { - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(new ByteArrayOutputStream()) .setMinUpdateIndex(1) .setMaxUpdateIndex(2) - .begin(new ByteArrayOutputStream()); + .begin(); PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); String msg = "test"; @@ -451,10 +524,10 @@ public class ReftableTest { @Test public void invalidReflogWriteOrderName() throws IOException { - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(new ByteArrayOutputStream()) .setMinUpdateIndex(1) .setMaxUpdateIndex(1) - .begin(new ByteArrayOutputStream()); + .begin(); PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); String msg = "test"; @@ -473,10 +546,10 @@ public class ReftableTest { String msg = "test"; ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(buffer) .setMinUpdateIndex(1) .setMaxUpdateIndex(1) - .begin(buffer); + .begin(); writer.writeRef(master); writer.writeRef(next); @@ -523,16 +596,96 @@ public class ReftableTest { } @Test + public void reflogReader() throws IOException { + Ref master = ref(MASTER, 1); + Ref next = ref(NEXT, 2); + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + ReftableWriter writer = new ReftableWriter(buffer).setMinUpdateIndex(1) + .setMaxUpdateIndex(1).begin(); + + writer.writeRef(master); + writer.writeRef(next); + + PersonIdent who1 = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + writer.writeLog(MASTER, 3, who1, ObjectId.zeroId(), id(1), "1"); + PersonIdent who2 = new PersonIdent("Log", "Ger", 1500079710, -8 * 60); + writer.writeLog(MASTER, 2, who2, id(1), id(2), "2"); + PersonIdent who3 = new PersonIdent("Log", "Ger", 1500079711, -8 * 60); + writer.writeLog(MASTER, 1, who3, id(2), id(3), "3"); + + writer.finish(); + byte[] table = buffer.toByteArray(); + + ReentrantLock lock = new ReentrantLock(); + ReftableReader t = read(table); + ReftableReflogReader rlr = new ReftableReflogReader(lock, t, MASTER); + + assertEquals(rlr.getLastEntry().getWho(), who1); + List<PersonIdent> all = rlr.getReverseEntries().stream() + .map(x -> x.getWho()).collect(Collectors.toList()); + Matchers.contains(all, who3, who2, who1); + + assertEquals(rlr.getReverseEntry(1).getWho(), who2); + + List<ReflogEntry> reverse2 = rlr.getReverseEntries(2); + Matchers.contains(reverse2, who3, who2); + + List<PersonIdent> more = rlr.getReverseEntries(4).stream() + .map(x -> x.getWho()).collect(Collectors.toList()); + assertEquals(all, more); + } + + @Test + public void allRefs() throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + ReftableConfig cfg = new ReftableConfig(); + cfg.setRefBlockSize(1024); + cfg.setLogBlockSize(1024); + cfg.setAlignBlocks(true); + ReftableWriter writer = new ReftableWriter(buffer) + .setMinUpdateIndex(1) + .setMaxUpdateIndex(1) + .setConfig(cfg) + .begin(); + PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); + + // Fill out the 1st ref block. + List<String> names = new ArrayList<>(); + for (int i = 0; i < 4; i++) { + @SuppressWarnings("boxing") + String name = new String(new char[220]).replace("\0", String.format("%c", i + 'a')); + names.add(name); + writer.writeRef(ref(name, i)); + } + + // Add some log data. + writer.writeLog(MASTER, 1, who, ObjectId.zeroId(), id(1), "msg"); + writer.finish(); + byte[] table = buffer.toByteArray(); + + ReftableReader t = read(table); + RefCursor c = t.allRefs(); + + int j = 0; + while (c.next()) { + assertEquals(names.get(j), c.getRef().getName()); + j++; + } + } + + + @Test public void reflogSeek() throws IOException { PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); String msg = "test"; String msgNext = "test next"; ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(buffer) .setMinUpdateIndex(1) .setMaxUpdateIndex(1) - .begin(buffer); + .begin(); writer.writeLog(MASTER, 1, who, ObjectId.zeroId(), id(1), msg); writer.writeLog(NEXT, 1, who, ObjectId.zeroId(), id(2), msgNext); @@ -572,10 +725,10 @@ public class ReftableTest { PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(buffer) .setMinUpdateIndex(1) .setMaxUpdateIndex(1) - .begin(buffer); + .begin(); writer.writeLog("branchname", 1, who, ObjectId.zeroId(), id(1), "branchname"); @@ -596,10 +749,10 @@ public class ReftableTest { String msg = "test"; ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - ReftableWriter writer = new ReftableWriter() + ReftableWriter writer = new ReftableWriter(buffer) .setMinUpdateIndex(1) .setMaxUpdateIndex(1) - .begin(buffer); + .begin(); writer.writeLog(MASTER, 1, who, ObjectId.zeroId(), id(1), msg); writer.writeLog(NEXT, 1, who, ObjectId.zeroId(), id(2), msg); writer.finish(); @@ -640,7 +793,6 @@ public class ReftableTest { } } - @SuppressWarnings("boxing") @Test public void logScan() throws IOException { ReftableConfig cfg = new ReftableConfig(); @@ -648,11 +800,12 @@ public class ReftableTest { cfg.setLogBlockSize(2048); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - ReftableWriter writer = new ReftableWriter(cfg); - writer.setMinUpdateIndex(1).setMaxUpdateIndex(1).begin(buffer); + ReftableWriter writer = new ReftableWriter(cfg, buffer); + writer.setMinUpdateIndex(1).setMaxUpdateIndex(1).begin(); List<Ref> refs = new ArrayList<>(); for (int i = 1; i <= 5670; i++) { + @SuppressWarnings("boxing") Ref ref = ref(String.format("refs/heads/%04d", i), i); refs.add(ref); writer.writeRef(ref); @@ -685,12 +838,13 @@ public class ReftableTest { } } - @SuppressWarnings("boxing") @Test public void byObjectIdOneRefNoIndex() throws IOException { List<Ref> refs = new ArrayList<>(); for (int i = 1; i <= 200; i++) { - refs.add(ref(String.format("refs/heads/%02d", i), i)); + @SuppressWarnings("boxing") + Ref ref = ref(String.format("refs/heads/%02d", i), i); + refs.add(ref); } refs.add(ref("refs/heads/master", 100)); @@ -718,12 +872,13 @@ public class ReftableTest { } } - @SuppressWarnings("boxing") @Test public void byObjectIdOneRefWithIndex() throws IOException { List<Ref> refs = new ArrayList<>(); for (int i = 1; i <= 5200; i++) { - refs.add(ref(String.format("refs/heads/%02d", i), i)); + @SuppressWarnings("boxing") + Ref ref = ref(String.format("refs/heads/%02d", i), i); + refs.add(ref); } refs.add(ref("refs/heads/master", 100)); @@ -768,7 +923,7 @@ public class ReftableTest { cfg.setRefBlockSize(64); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - ReftableWriter writer = new ReftableWriter(cfg).begin(buffer); + ReftableWriter writer = new ReftableWriter(cfg, buffer).begin(); writer.writeRef(ref("refs/heads/i-am-not-a-teapot", 1)); writer.finish(); fail("expected BlockSizeTooSmallException"); @@ -852,9 +1007,14 @@ public class ReftableTest { } private byte[] write(Collection<Ref> refs) throws IOException { + return write(refs, new ReftableConfig()); + } + + private byte[] write(Collection<Ref> refs, ReftableConfig cfg) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - stats = new ReftableWriter() - .begin(buffer) + stats = new ReftableWriter(buffer) + .setConfig(cfg) + .begin() .sortAndWriteRefs(refs) .finish() .getStats(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java index c3f5baa67b..50e0ed27c0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/reftree/RefTreeDatabaseTest.java @@ -441,8 +441,9 @@ public class RefTreeDatabaseTest { ReceiveCommand cmd = command(null, B, "refs/txn/tmp"); BatchRefUpdate batch = refdb.newBatchUpdate(); batch.addCommand(cmd); - batch.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); - + try (RevWalk rw = new RevWalk(repo)) { + batch.execute(rw, NullProgressMonitor.INSTANCE); + } assertEquals(REJECTED_OTHER_REASON, cmd.getResult()); assertEquals(MessageFormat.format(JGitText.get().invalidRefName, "refs/txn/tmp"), cmd.getMessage()); @@ -461,8 +462,9 @@ public class RefTreeDatabaseTest { ReceiveCommand cmd = command(null, B, "refs/heads/pu.lock"); BatchRefUpdate batch = refdb.newBatchUpdate(); batch.addCommand(cmd); - batch.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); - + try (RevWalk rw = new RevWalk(repo)) { + batch.execute(rw, NullProgressMonitor.INSTANCE); + } assertEquals(REJECTED_OTHER_REASON, cmd.getResult()); assertEquals(JGitText.get().funnyRefname, cmd.getMessage()); assertEquals(txnId, getTxnCommitted()); @@ -481,7 +483,9 @@ public class RefTreeDatabaseTest { ReceiveCommand cmd = command(null, B, ORIG_HEAD); BatchRefUpdate batch = refdb.newBatchUpdate(); batch.addCommand(cmd); - batch.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); + try (RevWalk rw = new RevWalk(repo)) { + batch.execute(rw, NullProgressMonitor.INSTANCE); + } assertEquals(REJECTED_OTHER_REASON, cmd.getResult()); assertEquals( MessageFormat.format(JGitText.get().invalidRefName, ORIG_HEAD), @@ -500,7 +504,9 @@ public class RefTreeDatabaseTest { command(B, A, "refs/heads/masters")); BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); batchUpdate.addCommand(commands); - batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); + try (RevWalk rw = new RevWalk(repo)) { + batchUpdate.execute(rw, NullProgressMonitor.INSTANCE); + } assertEquals(txnId, getTxnCommitted()); assertEquals(REJECTED_NONFASTFORWARD, @@ -523,7 +529,9 @@ public class RefTreeDatabaseTest { BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); batchUpdate.setAllowNonFastForwards(true); batchUpdate.addCommand(commands); - batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); + try (RevWalk rw = new RevWalk(repo)) { + batchUpdate.execute(rw, NullProgressMonitor.INSTANCE); + } assertNotEquals(txnId, getTxnCommitted()); Map<String, Ref> refs = refdb.getRefs(ALL); @@ -547,13 +555,15 @@ public class RefTreeDatabaseTest { BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); batchUpdate.setAllowNonFastForwards(true); batchUpdate.addCommand(commands); - batchUpdate.execute(new RevWalk(repo) { + try (RevWalk rw = new RevWalk(repo) { @Override public boolean isMergedInto(RevCommit base, RevCommit tip) { fail("isMergedInto() should not be called"); return false; } - }, NullProgressMonitor.INSTANCE); + }) { + batchUpdate.execute(rw, NullProgressMonitor.INSTANCE); + } assertNotEquals(txnId, getTxnCommitted()); Map<String, Ref> refs = refdb.getRefs(ALL); @@ -574,7 +584,9 @@ public class RefTreeDatabaseTest { BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); batchUpdate.setAllowNonFastForwards(true); batchUpdate.addCommand(commands); - batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); + try (RevWalk rw = new RevWalk(repo)) { + batchUpdate.execute(rw, NullProgressMonitor.INSTANCE); + } assertEquals(txnId, getTxnCommitted()); assertEquals(LOCK_FAILURE, commands.get(0).getResult()); @@ -601,7 +613,9 @@ public class RefTreeDatabaseTest { BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); batchUpdate.setAllowNonFastForwards(true); batchUpdate.addCommand(commands); - batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); + try (RevWalk rw = new RevWalk(repo)) { + batchUpdate.execute(rw, NullProgressMonitor.INSTANCE); + } assertNotEquals(txnId, getTxnCommitted()); assertEquals(OK, commands.get(0).getResult()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java index 057e0c881b..46fd902b6c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java @@ -341,48 +341,56 @@ public class DirCacheCheckoutMaliciousPathTest extends RepositoryTestCase { String... path) throws GitAPIException, IOException { try (Git git = new Git(db); RevWalk revWalk = new RevWalk(git.getRepository())) { - ObjectInserter newObjectInserter; - newObjectInserter = git.getRepository().newObjectInserter(); - ObjectId blobId = newObjectInserter.insert(Constants.OBJ_BLOB, + ObjectId blobId; + try (ObjectInserter newObjectInserter = git.getRepository() + .newObjectInserter()) { + blobId = newObjectInserter.insert(Constants.OBJ_BLOB, "data".getBytes(UTF_8)); - newObjectInserter = git.getRepository().newObjectInserter(); + } FileMode mode = FileMode.REGULAR_FILE; ObjectId insertId = blobId; - for (int i = path.length - 1; i >= 0; --i) { - TreeFormatter treeFormatter = new TreeFormatter(); - treeFormatter.append("goodpath", mode, insertId); - insertId = newObjectInserter.insert(treeFormatter); - mode = FileMode.TREE; + try (ObjectInserter newObjectInserter = git.getRepository() + .newObjectInserter()) { + for (int i = path.length - 1; i >= 0; --i) { + TreeFormatter treeFormatter = new TreeFormatter(); + treeFormatter.append("goodpath", mode, insertId); + insertId = newObjectInserter.insert(treeFormatter); + mode = FileMode.TREE; + } } - newObjectInserter = git.getRepository().newObjectInserter(); - CommitBuilder commitBuilder = new CommitBuilder(); - commitBuilder.setAuthor(author); - commitBuilder.setCommitter(committer); - commitBuilder.setMessage("foo#1"); - commitBuilder.setTreeId(insertId); - ObjectId firstCommitId = newObjectInserter.insert(commitBuilder); - - newObjectInserter = git.getRepository().newObjectInserter(); - mode = FileMode.REGULAR_FILE; - insertId = blobId; - for (int i = path.length - 1; i >= 0; --i) { - TreeFormatter treeFormatter = new TreeFormatter(); - treeFormatter.append(path[i].getBytes(UTF_8), 0, - path[i].getBytes(UTF_8).length, - mode, insertId, true); - insertId = newObjectInserter.insert(treeFormatter); - mode = FileMode.TREE; + ObjectId firstCommitId; + try (ObjectInserter newObjectInserter = git.getRepository() + .newObjectInserter()) { + CommitBuilder commitBuilder = new CommitBuilder(); + commitBuilder.setAuthor(author); + commitBuilder.setCommitter(committer); + commitBuilder.setMessage("foo#1"); + commitBuilder.setTreeId(insertId); + firstCommitId = newObjectInserter.insert(commitBuilder); } + ObjectId commitId; + try (ObjectInserter newObjectInserter = git.getRepository() + .newObjectInserter()) { + mode = FileMode.REGULAR_FILE; + insertId = blobId; + for (int i = path.length - 1; i >= 0; --i) { + TreeFormatter treeFormatter = new TreeFormatter(); + treeFormatter.append(path[i].getBytes(UTF_8), 0, + path[i].getBytes(UTF_8).length, mode, insertId, + true); + insertId = newObjectInserter.insert(treeFormatter); + mode = FileMode.TREE; + } - // Create another commit - commitBuilder = new CommitBuilder(); - commitBuilder.setAuthor(author); - commitBuilder.setCommitter(committer); - commitBuilder.setMessage("foo#2"); - commitBuilder.setTreeId(insertId); - commitBuilder.setParentId(firstCommitId); - ObjectId commitId = newObjectInserter.insert(commitBuilder); - + // Create another commit + CommitBuilder commitBuilder = new CommitBuilder(); + commitBuilder.setAuthor(author); + commitBuilder.setCommitter(committer); + commitBuilder.setMessage("foo#2"); + commitBuilder.setTreeId(insertId); + commitBuilder.setParentId(firstCommitId); + commitId = newObjectInserter.insert(commitBuilder); + } if (!secondCheckout) git.checkout().setStartPoint(revWalk.parseCommit(firstCommitId)) .setName("refs/heads/master").setCreateBranch(true).call(); 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 8092c3134b..a272c8f2ee 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 @@ -349,9 +349,11 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { DirCacheEditor editor = dirCache.editor(); for (java.util.Map.Entry<String,String> e : indexEntries.entrySet()) { writeTrashFile(e.getKey(), e.getValue()); - ObjectInserter inserter = db.newObjectInserter(); - final ObjectId id = inserter.insert(Constants.OBJ_BLOB, + ObjectId id; + try (ObjectInserter inserter = db.newObjectInserter()) { + id = inserter.insert(Constants.OBJ_BLOB, Constants.encode(e.getValue())); + } editor.add(new DirCacheEditor.DeletePath(e.getKey())); editor.add(new DirCacheEditor.PathEdit(e.getKey()) { @Override diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java index fa7f5ab522..014a587723 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffSubmoduleTest.java @@ -60,9 +60,11 @@ import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.internal.storage.file.FileRepository; import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.submodule.SubmoduleWalk.IgnoreSubmoduleMode; import org.eclipse.jgit.treewalk.FileTreeIterator; import org.junit.Before; +import org.junit.Test; import org.junit.experimental.theories.DataPoints; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; @@ -295,4 +297,79 @@ public class IndexDiffSubmoduleTest extends RepositoryTestCase { indexDiff.getAdded().toString()); } + @Test + public void testIndexDiffTwoSubmodules() throws Exception { + // Create a second submodule + try (Repository submodule2 = createWorkRepository()) { + JGitTestUtil.writeTrashFile(submodule2, "fileInSubmodule2", + "submodule2"); + Git subGit = Git.wrap(submodule2); + subGit.add().addFilepattern("fileInSubmodule2").call(); + subGit.commit().setMessage("add file to submodule2").call(); + + try (Repository sub2 = Git.wrap(db) + .submoduleAdd().setPath("modules/submodule2") + .setURI(submodule2.getDirectory().toURI().toString()) + .call()) { + writeTrashFile("fileInRoot", "root+"); + Git rootGit = Git.wrap(db); + rootGit.add().addFilepattern("fileInRoot").call(); + rootGit.commit().setMessage("add submodule2 and root file") + .call(); + // Now change files in both submodules + JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", + "submodule changed"); + JGitTestUtil.writeTrashFile(sub2, "fileInSubmodule2", + "submodule2 changed"); + // Set up .gitmodules + FileBasedConfig gitmodules = new FileBasedConfig( + new File(db.getWorkTree(), Constants.DOT_GIT_MODULES), + db.getFS()); + gitmodules.load(); + gitmodules.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, + "modules/submodule", ConfigConstants.CONFIG_KEY_IGNORE, + "all"); + gitmodules.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, + "modules/submodule2", ConfigConstants.CONFIG_KEY_IGNORE, + "none"); + gitmodules.save(); + IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD, + new FileTreeIterator(db)); + assertTrue(indexDiff.diff()); + String[] modified = indexDiff.getModified() + .toArray(new String[0]); + Arrays.sort(modified); + assertEquals("[.gitmodules, modules/submodule2]", + Arrays.toString(modified)); + // Try again with "dirty" + gitmodules.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, + "modules/submodule", ConfigConstants.CONFIG_KEY_IGNORE, + "dirty"); + gitmodules.save(); + indexDiff = new IndexDiff(db, Constants.HEAD, + new FileTreeIterator(db)); + assertTrue(indexDiff.diff()); + modified = indexDiff.getModified().toArray(new String[0]); + Arrays.sort(modified); + assertEquals("[.gitmodules, modules/submodule2]", + Arrays.toString(modified)); + // Test the config override + StoredConfig cfg = db.getConfig(); + cfg.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, + "modules/submodule", ConfigConstants.CONFIG_KEY_IGNORE, + "none"); + cfg.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, + "modules/submodule2", ConfigConstants.CONFIG_KEY_IGNORE, + "all"); + cfg.save(); + indexDiff = new IndexDiff(db, Constants.HEAD, + new FileTreeIterator(db)); + assertTrue(indexDiff.diff()); + modified = indexDiff.getModified().toArray(new String[0]); + Arrays.sort(modified); + assertEquals("[.gitmodules, modules/submodule]", + Arrays.toString(modified)); + } + } + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java index ba5aaf1b18..cf954070e0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java @@ -81,10 +81,12 @@ public class IndexDiffTest extends RepositoryTestCase { static PathEdit add(final Repository db, final File workdir, final String path) throws FileNotFoundException, IOException { - ObjectInserter inserter = db.newObjectInserter(); final File f = new File(workdir, path); - final ObjectId id = inserter.insert(Constants.OBJ_BLOB, + ObjectId id; + try (ObjectInserter inserter = db.newObjectInserter()) { + id = inserter.insert(Constants.OBJ_BLOB, IO.readFully(f)); + } return new PathEdit(path) { @Override public void apply(DirCacheEntry ent) { @@ -122,9 +124,11 @@ public class IndexDiffTest extends RepositoryTestCase { public void testMissing() throws Exception { File file2 = writeTrashFile("file2", "file2"); File file3 = writeTrashFile("dir/file3", "dir/file3"); - Git git = Git.wrap(db); - git.add().addFilepattern("file2").addFilepattern("dir/file3").call(); - git.commit().setMessage("commit").call(); + try (Git git = new Git(db)) { + git.add().addFilepattern("file2").addFilepattern("dir/file3") + .call(); + git.commit().setMessage("commit").call(); + } assertTrue(file2.delete()); assertTrue(file3.delete()); IndexDiff diff = new IndexDiff(db, Constants.HEAD, diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdSerializerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdSerializerTest.java index d98b792d75..f0733f4782 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdSerializerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdSerializerTest.java @@ -88,9 +88,8 @@ public class ObjectIdSerializerTest { try (InputStream in = new FileInputStream(file)) { if (objectId == null) { return ObjectIdSerializer.read(in); - } else { - return ObjectIdSerializer.readWithoutMarker(in); } + return ObjectIdSerializer.readWithoutMarker(in); } } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java index cbb47fa829..3f77ca25a3 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefDatabaseConflictingNamesTest.java @@ -67,9 +67,8 @@ public class RefDatabaseConflictingNamesTest { existing.put("refs/heads/a/b", null /* not used */); existing.put("refs/heads/q", null /* not used */); return existing; - } else { - return Collections.emptyMap(); } + return Collections.emptyMap(); } @Override diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java index f2f277c6ea..9be71c3a02 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java @@ -45,7 +45,7 @@ package org.eclipse.jgit.lib; -import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; @@ -78,7 +78,10 @@ public class ReflogConfigTest extends RepositoryTestCase { // set the logAllRefUpdates parameter to true and check it cfg.setBoolean("core", null, "logallrefupdates", true); cfg.save(); - assertTrue(cfg.get(CoreConfig.KEY).isLogAllRefUpdates()); + assertEquals(CoreConfig.LogRefUpdates.TRUE, + cfg.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, + CoreConfig.LogRefUpdates.FALSE)); // do one commit and check that reflog size is increased to 1 commit("A Commit\n", commitTime, tz); @@ -90,13 +93,32 @@ public class ReflogConfigTest extends RepositoryTestCase { // set the logAllRefUpdates parameter to false and check it cfg.setBoolean("core", null, "logallrefupdates", false); cfg.save(); - assertFalse(cfg.get(CoreConfig.KEY).isLogAllRefUpdates()); + assertEquals(CoreConfig.LogRefUpdates.FALSE, + cfg.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, + CoreConfig.LogRefUpdates.TRUE)); // do one commit and check that reflog size is 2 commit("A Commit\n", commitTime, tz); + commitTime += 60 * 1000; assertTrue( "Reflog for HEAD should contain two entries", db.getReflogReader(Constants.HEAD).getReverseEntries().size() == 2); + + // set the logAllRefUpdates parameter to false and check it + cfg.setEnum("core", null, "logallrefupdates", + CoreConfig.LogRefUpdates.ALWAYS); + cfg.save(); + assertEquals(CoreConfig.LogRefUpdates.ALWAYS, + cfg.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, + CoreConfig.LogRefUpdates.FALSE)); + + // do one commit and check that reflog size is 3 + commit("A Commit\n", commitTime, tz); + assertTrue("Reflog for HEAD should contain three entries", + db.getReflogReader(Constants.HEAD).getReverseEntries() + .size() == 3); } private void commit(String commitMsg, long commitTime, int tz) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocatorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocatorTest.java new file mode 100644 index 0000000000..220b2becba --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocatorTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2019, Thomas Wolf <thomas.wolf@paranor.ch> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.lib.internal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Locale; + +import org.junit.Test; + +public class BouncyCastleGpgKeyLocatorTest { + + private static final String USER_ID = "Heinrich Heine <heinrichh@uni-duesseldorf.de>"; + + private static boolean match(String userId, String pattern) { + return BouncyCastleGpgKeyLocator.containsSigningKey(userId, pattern); + } + + @Test + public void testFullMatch() throws Exception { + assertTrue(match(USER_ID, + "=Heinrich Heine <heinrichh@uni-duesseldorf.de>")); + assertFalse(match(USER_ID, "=Heinrich Heine")); + assertFalse(match(USER_ID, "= ")); + assertFalse(match(USER_ID, "=heinrichh@uni-duesseldorf.de")); + } + + @Test + public void testEmpty() throws Exception { + assertFalse(match(USER_ID, "")); + assertFalse(match(USER_ID, null)); + assertFalse(match("", "")); + assertFalse(match(null, "")); + assertFalse(match(null, null)); + assertFalse(match("", "something")); + assertFalse(match(null, "something")); + } + + @Test + public void testFullEmail() throws Exception { + assertTrue(match(USER_ID, "<heinrichh@uni-duesseldorf.de>")); + assertTrue(match(USER_ID + " ", "<heinrichh@uni-duesseldorf.de>")); + assertFalse(match(USER_ID, "<>")); + assertFalse(match(USER_ID, "<h>")); + assertFalse(match(USER_ID, "<heinrichh>")); + assertFalse(match(USER_ID, "<uni-duesseldorf>")); + assertFalse(match(USER_ID, "<h@u>")); + assertFalse(match(USER_ID, "<HeinrichH@uni-duesseldorf.de>")); + assertFalse(match(USER_ID.substring(0, USER_ID.length() - 1), + "<heinrichh@uni-duesseldorf.de>")); + assertFalse(match("", "<>")); + assertFalse(match("", "<heinrichh@uni-duesseldorf.de>")); + } + + @Test + public void testPartialEmail() throws Exception { + assertTrue(match(USER_ID, "@heinrichh@uni-duesseldorf.de")); + assertTrue(match(USER_ID, "@heinrichh")); + assertTrue(match(USER_ID, "@duesseldorf")); + assertTrue(match(USER_ID, "@uni-d")); + assertTrue(match(USER_ID, "@h")); + assertTrue(match(USER_ID, "@.")); + assertTrue(match(USER_ID, "@h@u")); + assertFalse(match(USER_ID, "@ ")); + assertFalse(match(USER_ID, "@")); + assertFalse(match(USER_ID, "@Heine")); + assertFalse(match(USER_ID, "@HeinrichH")); + assertFalse(match(USER_ID, "@Heinrich")); + assertFalse(match("", "@")); + assertFalse(match("", "@h")); + } + + private void substringTests(String prefix) throws Exception { + assertTrue(match(USER_ID, prefix + "heinrichh@uni-duesseldorf.de")); + assertTrue(match(USER_ID, prefix + "heinrich")); + assertTrue(match(USER_ID, prefix + "HEIN")); + assertTrue(match(USER_ID, prefix + "Heine <")); + assertTrue(match(USER_ID, prefix + "UNI")); + assertTrue(match(USER_ID, prefix + "uni")); + assertTrue(match(USER_ID, prefix + "rich He")); + assertTrue(match(USER_ID, prefix + "h@u")); + assertTrue(match(USER_ID, prefix + USER_ID)); + assertTrue(match(USER_ID, prefix + USER_ID.toUpperCase(Locale.ROOT))); + assertFalse(match(USER_ID, prefix + "")); + assertFalse(match(USER_ID, prefix + " ")); + assertFalse(match(USER_ID, prefix + "yy")); + assertFalse(match("", prefix + "")); + assertFalse(match("", prefix + "uni")); + } + + @Test + public void testSubstringPlain() throws Exception { + substringTests(""); + } + + @Test + public void testSubstringAsterisk() throws Exception { + substringTests("*"); + } + + @Test + public void testExplicitFingerprint() throws Exception { + assertFalse(match("John Fade <j.fade@example.com>", "0xfade")); + assertFalse(match("John Fade <0xfade@example.com>", "0xfade")); + assertFalse(match("", "0xfade")); + } + + @Test + public void testImplicitFingerprint() throws Exception { + assertTrue(match("John Fade <j.fade@example.com>", "fade")); + assertTrue(match("John Fade <0xfade@example.com>", "fade")); + assertTrue(match("John Fade <j.fade@example.com>", "FADE")); + assertTrue(match("John Fade <0xfade@example.com>", "FADE")); + } + + @Test + public void testZeroX() throws Exception { + assertTrue(match("John Fade <0xfade@example.com>", "0x")); + assertTrue(match("John Fade <0xfade@example.com>", "*0x")); + assertTrue(match("John Fade <0xfade@example.com>", "*0xfade")); + assertTrue(match("John Fade <0xfade@example.com>", "*0xFADE")); + assertTrue(match("John Fade <0xfade@example.com>", "@0xfade")); + assertFalse(match("John Fade <0xfade@example.com>", "@0xFADE")); + assertFalse(match("", "0x")); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java index 19f6dcbc59..aa4392fcac 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java @@ -106,23 +106,24 @@ public class CherryPickTest extends RepositoryTestCase { boolean merge = twm.merge(new ObjectId[] { O, T }); assertTrue(merge); - final TreeWalk tw = new TreeWalk(db); - tw.setRecursive(true); - tw.reset(twm.getResultTreeId()); + try (TreeWalk tw = new TreeWalk(db)) { + tw.setRecursive(true); + tw.reset(twm.getResultTreeId()); - assertTrue(tw.next()); - assertEquals("a", tw.getPathString()); - assertCorrectId(treeO, tw); + assertTrue(tw.next()); + assertEquals("a", tw.getPathString()); + assertCorrectId(treeO, tw); - assertTrue(tw.next()); - assertEquals("o", tw.getPathString()); - assertCorrectId(treeO, tw); + assertTrue(tw.next()); + assertEquals("o", tw.getPathString()); + assertCorrectId(treeO, tw); - assertTrue(tw.next()); - assertEquals("t", tw.getPathString()); - assertCorrectId(treeT, tw); + assertTrue(tw.next()); + assertEquals("t", tw.getPathString()); + assertCorrectId(treeT, tw); - assertFalse(tw.next()); + assertFalse(tw.next()); + } } @Test @@ -168,19 +169,20 @@ public class CherryPickTest extends RepositoryTestCase { boolean merge = twm.merge(new ObjectId[] { B, T }); assertTrue(merge); - final TreeWalk tw = new TreeWalk(db); - tw.setRecursive(true); - tw.reset(twm.getResultTreeId()); + try (TreeWalk tw = new TreeWalk(db)) { + tw.setRecursive(true); + tw.reset(twm.getResultTreeId()); - assertTrue(tw.next()); - assertEquals("a", tw.getPathString()); - assertCorrectId(treeB, tw); + assertTrue(tw.next()); + assertEquals("a", tw.getPathString()); + assertCorrectId(treeB, tw); - assertTrue(tw.next()); - assertEquals("t", tw.getPathString()); - assertCorrectId(treeT, tw); + assertTrue(tw.next()); + assertEquals("t", tw.getPathString()); + assertCorrectId(treeT, tw); - assertFalse(tw.next()); + assertFalse(tw.next()); + } } private static void assertCorrectId(DirCache treeT, TreeWalk tw) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CrissCrossMergeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CrissCrossMergeTest.java index a67c750dba..5c6636c89e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CrissCrossMergeTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CrissCrossMergeTest.java @@ -881,9 +881,9 @@ public class CrissCrossMergeTest extends RepositoryTestCase { } StringBuilder result = new StringBuilder(); - ObjectReader or = r.newObjectReader(); - try (BufferedReader br = new BufferedReader( - new InputStreamReader(or.open(blobId).openStream(), UTF_8))) { + try (ObjectReader or = r.newObjectReader(); + BufferedReader br = new BufferedReader(new InputStreamReader( + or.open(blobId).openStream(), UTF_8))) { String line; boolean first = true; while ((line = br.readLine()) != null) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java index 62495fb023..3379a25377 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java @@ -1365,8 +1365,8 @@ public class MergerTest extends RepositoryTestCase { } private String readBlob(ObjectId treeish, String path) throws Exception { - try (TestRepository<?> tr = new TestRepository<>(db)) { - RevWalk rw = tr.getRevWalk(); + try (TestRepository<?> tr = new TestRepository<>(db); + RevWalk rw = tr.getRevWalk()) { RevTree tree = rw.parseTree(treeish); RevObject obj = tr.get(tree, path); if (obj == null) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java index dd2c2e84b6..6c0b165a4f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java @@ -174,23 +174,24 @@ public class SimpleMergeTest extends SampleDataRepositoryTestCase { boolean merge = ourMerger.merge(new ObjectId[] { o, t }); assertTrue(merge); - final TreeWalk tw = new TreeWalk(db); - tw.setRecursive(true); - tw.reset(ourMerger.getResultTreeId()); + try (TreeWalk tw = new TreeWalk(db)) { + tw.setRecursive(true); + tw.reset(ourMerger.getResultTreeId()); - assertTrue(tw.next()); - assertEquals("Makefile", tw.getPathString()); - assertCorrectId(treeO, tw); + assertTrue(tw.next()); + assertEquals("Makefile", tw.getPathString()); + assertCorrectId(treeO, tw); - assertTrue(tw.next()); - assertEquals("libelf-po/a", tw.getPathString()); - assertCorrectId(treeO, tw); + assertTrue(tw.next()); + assertEquals("libelf-po/a", tw.getPathString()); + assertCorrectId(treeO, tw); - assertTrue(tw.next()); - assertEquals("libelf/c", tw.getPathString()); - assertCorrectId(treeT, tw); + assertTrue(tw.next()); + assertEquals("libelf/c", tw.getPathString()); + assertCorrectId(treeT, tw); - assertFalse(tw.next()); + assertFalse(tw.next()); + } } @Test @@ -226,19 +227,20 @@ public class SimpleMergeTest extends SampleDataRepositoryTestCase { boolean merge = ourMerger.merge(new ObjectId[] { o, t }); assertTrue(merge); - final TreeWalk tw = new TreeWalk(db); - tw.setRecursive(true); - tw.reset(ourMerger.getResultTreeId()); + try (TreeWalk tw = new TreeWalk(db)) { + tw.setRecursive(true); + tw.reset(ourMerger.getResultTreeId()); - assertTrue(tw.next()); - assertEquals("d/o", tw.getPathString()); - assertCorrectId(treeO, tw); + assertTrue(tw.next()); + assertEquals("d/o", tw.getPathString()); + assertCorrectId(treeO, tw); - assertTrue(tw.next()); - assertEquals("d/t", tw.getPathString()); - assertCorrectId(treeT, tw); + assertTrue(tw.next()); + assertEquals("d/t", tw.getPathString()); + assertCorrectId(treeT, tw); - assertFalse(tw.next()); + assertFalse(tw.next()); + } } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revplot/AbstractPlotRendererTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revplot/AbstractPlotRendererTest.java index f265315338..ac157b6b87 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revplot/AbstractPlotRendererTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revplot/AbstractPlotRendererTest.java @@ -44,7 +44,6 @@ package org.eclipse.jgit.revplot; import static org.junit.Assert.assertEquals; -import java.io.IOException; import java.util.LinkedList; import java.util.List; @@ -55,7 +54,6 @@ import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.Repository; import org.junit.Before; import org.junit.Test; @@ -83,23 +81,18 @@ public class AbstractPlotRendererTest extends RepositoryTestCase { git.commit().setMessage("commit on master").call(); MergeResult mergeCall = merge(db.resolve("topic")); ObjectId start = mergeCall.getNewHead(); - PlotCommitList<PlotLane> commitList = createCommitList(start); + try (PlotWalk walk = new PlotWalk(db)) { + walk.markStart(walk.parseCommit(start)); + PlotCommitList<PlotLane> commitList = new PlotCommitList<>(); + commitList.source(walk); + commitList.fillTo(1000); - for (int i = 0; i < commitList.size(); i++) - plotRenderer.paintCommit(commitList.get(i), 30); + for (int i = 0; i < commitList.size(); i++) + plotRenderer.paintCommit(commitList.get(i), 30); - List<Integer> indentations = plotRenderer.indentations; - assertEquals(indentations.get(2), indentations.get(3)); - } - - private PlotCommitList<PlotLane> createCommitList(ObjectId start) - throws IOException { - TestPlotWalk walk = new TestPlotWalk(db); - walk.markStart(walk.parseCommit(start)); - PlotCommitList<PlotLane> commitList = new PlotCommitList<>(); - commitList.source(walk); - commitList.fillTo(1000); - return commitList; + List<Integer> indentations = plotRenderer.indentations; + assertEquals(indentations.get(2), indentations.get(3)); + } } private MergeResult merge(ObjectId includeId) throws GitAPIException { @@ -107,12 +100,6 @@ public class AbstractPlotRendererTest extends RepositoryTestCase { .include(includeId).call(); } - private static class TestPlotWalk extends PlotWalk { - public TestPlotWalk(Repository repo) { - super(repo); - } - } - private static class TestPlotRenderer extends AbstractPlotRenderer<PlotLane, Object> { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revplot/PlotCommitListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revplot/PlotCommitListTest.java index 7297de3646..0c367f457e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revplot/PlotCommitListTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revplot/PlotCommitListTest.java @@ -135,18 +135,19 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit b = commit(a); final RevCommit c = commit(b); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(c.getId())); - - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); - - CommitListAssert test = new CommitListAssert(pcl); - test.commit(c).lanePos(0).parents(b); - test.commit(b).lanePos(0).parents(a); - test.commit(a).lanePos(0).parents(); - test.noMoreCommits(); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(c.getId())); + + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); + + CommitListAssert test = new CommitListAssert(pcl); + test.commit(c).lanePos(0).parents(b); + test.commit(b).lanePos(0).parents(a); + test.commit(a).lanePos(0).parents(); + test.noMoreCommits(); + } } @Test @@ -156,19 +157,20 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit c = commit(a); final RevCommit d = commit(b, c); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(d.getId())); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(d.getId())); - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); - CommitListAssert test = new CommitListAssert(pcl); - test.commit(d).lanePos(0).parents(b, c); - test.commit(c).lanePos(1).parents(a); - test.commit(b).lanePos(0).parents(a); - test.commit(a).lanePos(0).parents(); - test.noMoreCommits(); + CommitListAssert test = new CommitListAssert(pcl); + test.commit(d).lanePos(0).parents(b, c); + test.commit(c).lanePos(1).parents(a); + test.commit(b).lanePos(0).parents(a); + test.commit(a).lanePos(0).parents(); + test.noMoreCommits(); + } } @Test @@ -177,20 +179,21 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit b = commit(a); final RevCommit c = commit(a); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(b.getId())); - pw.markStart(pw.lookupCommit(c.getId())); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(b.getId())); + pw.markStart(pw.lookupCommit(c.getId())); - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); - Set<Integer> childPositions = asSet(0, 1); - CommitListAssert test = new CommitListAssert(pcl); - test.commit(c).lanePos(childPositions).parents(a); - test.commit(b).lanePos(childPositions).parents(a); - test.commit(a).lanePos(0).parents(); - test.noMoreCommits(); + Set<Integer> childPositions = asSet(0, 1); + CommitListAssert test = new CommitListAssert(pcl); + test.commit(c).lanePos(childPositions).parents(a); + test.commit(b).lanePos(childPositions).parents(a); + test.commit(a).lanePos(0).parents(); + test.noMoreCommits(); + } } @Test @@ -200,22 +203,23 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit c = commit(a); final RevCommit d = commit(a); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(b.getId())); - pw.markStart(pw.lookupCommit(c.getId())); - pw.markStart(pw.lookupCommit(d.getId())); - - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); - - Set<Integer> childPositions = asSet(0, 1, 2); - CommitListAssert test = new CommitListAssert(pcl); - test.commit(d).lanePos(childPositions).parents(a); - test.commit(c).lanePos(childPositions).parents(a); - test.commit(b).lanePos(childPositions).parents(a); - test.commit(a).lanePos(0).parents(); - test.noMoreCommits(); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(b.getId())); + pw.markStart(pw.lookupCommit(c.getId())); + pw.markStart(pw.lookupCommit(d.getId())); + + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); + + Set<Integer> childPositions = asSet(0, 1, 2); + CommitListAssert test = new CommitListAssert(pcl); + test.commit(d).lanePos(childPositions).parents(a); + test.commit(c).lanePos(childPositions).parents(a); + test.commit(b).lanePos(childPositions).parents(a); + test.commit(a).lanePos(0).parents(); + test.noMoreCommits(); + } } @Test @@ -228,34 +232,35 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit f = commit(a); final RevCommit g = commit(f); - PlotWalk pw = new PlotWalk(db); - // TODO: when we add unnecessary commit's as tips (e.g. a commit which - // is a parent of another tip) the walk will return those commits twice. - // Find out why! - // pw.markStart(pw.lookupCommit(a.getId())); - pw.markStart(pw.lookupCommit(b.getId())); - pw.markStart(pw.lookupCommit(c.getId())); - pw.markStart(pw.lookupCommit(d.getId())); - pw.markStart(pw.lookupCommit(e.getId())); - // pw.markStart(pw.lookupCommit(f.getId())); - pw.markStart(pw.lookupCommit(g.getId())); - - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); - - Set<Integer> childPositions = asSet(0, 1, 2, 3, 4); - CommitListAssert test = new CommitListAssert(pcl); - int posG = test.commit(g).lanePos(childPositions).parents(f) - .getLanePos(); - test.commit(f).lanePos(posG).parents(a); - - test.commit(e).lanePos(childPositions).parents(a); - test.commit(d).lanePos(childPositions).parents(a); - test.commit(c).lanePos(childPositions).parents(a); - test.commit(b).lanePos(childPositions).parents(a); - test.commit(a).lanePos(0).parents(); - test.noMoreCommits(); + try (PlotWalk pw = new PlotWalk(db)) { + // TODO: when we add unnecessary commit's as tips (e.g. a commit + // which is a parent of another tip) the walk will return those + // commits twice. Find out why! + // pw.markStart(pw.lookupCommit(a.getId())); + pw.markStart(pw.lookupCommit(b.getId())); + pw.markStart(pw.lookupCommit(c.getId())); + pw.markStart(pw.lookupCommit(d.getId())); + pw.markStart(pw.lookupCommit(e.getId())); + // pw.markStart(pw.lookupCommit(f.getId())); + pw.markStart(pw.lookupCommit(g.getId())); + + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); + + Set<Integer> childPositions = asSet(0, 1, 2, 3, 4); + CommitListAssert test = new CommitListAssert(pcl); + int posG = test.commit(g).lanePos(childPositions).parents(f) + .getLanePos(); + test.commit(f).lanePos(posG).parents(a); + + test.commit(e).lanePos(childPositions).parents(a); + test.commit(d).lanePos(childPositions).parents(a); + test.commit(c).lanePos(childPositions).parents(a); + test.commit(b).lanePos(childPositions).parents(a); + test.commit(a).lanePos(0).parents(); + test.noMoreCommits(); + } } @Test @@ -270,25 +275,26 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit h = commit(f); final RevCommit i = commit(h); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(i.getId())); - pw.markStart(pw.lookupCommit(g.getId())); - - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); - Set<Integer> childPositions = asSet(0, 1); - CommitListAssert test = new CommitListAssert(pcl); - int posI = test.commit(i).lanePos(childPositions).parents(h) - .getLanePos(); - test.commit(h).lanePos(posI).parents(f); - test.commit(g).lanePos(childPositions).parents(a); - test.commit(f).lanePos(posI).parents(e, d); - test.commit(e).lanePos(posI).parents(c); - test.commit(d).lanePos(2).parents(b); - test.commit(c).lanePos(posI).parents(b); - test.commit(b).lanePos(posI).parents(a); - test.commit(a).lanePos(0).parents(); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(i.getId())); + pw.markStart(pw.lookupCommit(g.getId())); + + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); + Set<Integer> childPositions = asSet(0, 1); + CommitListAssert test = new CommitListAssert(pcl); + int posI = test.commit(i).lanePos(childPositions).parents(h) + .getLanePos(); + test.commit(h).lanePos(posI).parents(f); + test.commit(g).lanePos(childPositions).parents(a); + test.commit(f).lanePos(posI).parents(e, d); + test.commit(e).lanePos(posI).parents(c); + test.commit(d).lanePos(2).parents(b); + test.commit(c).lanePos(posI).parents(b); + test.commit(b).lanePos(posI).parents(a); + test.commit(a).lanePos(0).parents(); + } } // test the history of the egit project between 9fdaf3c1 and e76ad9170f @@ -330,67 +336,71 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit merge_fixed_logged_npe = commit(sort_roots, fix_logged_npe); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(merge_fixed_logged_npe.getId())); - - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); - - CommitListAssert test = new CommitListAssert(pcl); - - // Note: all positions of side branches are rather arbitrary, but some - // may not overlap. Testing for the positions yielded by the current - // implementation, which was manually checked to not overlap. - final int mainPos = 0; - test.commit(merge_fixed_logged_npe).parents(sort_roots, fix_logged_npe) - .lanePos(mainPos); - test.commit(fix_logged_npe).parents(merge_changeset_implementation) - .lanePos(1); - test.commit(sort_roots).parents(merge_update_eclipse).lanePos(mainPos); - test.commit(merge_update_eclipse).parents(add_a_clear, update_eclipse) - .lanePos(mainPos); - test.commit(add_a_clear).parents(fix_broken).lanePos(mainPos); - test.commit(fix_broken).parents(merge_disable_comment).lanePos(mainPos); - test.commit(merge_disable_comment) - .parents(merge_resolve_handler, disable_comment) - .lanePos(mainPos); - test.commit(disable_comment).parents(clone_operation).lanePos(2); - test.commit(merge_resolve_handler) - .parents(clone_operation, resolve_handler).lanePos(mainPos); - test.commit(update_eclipse).parents(add_Maven).lanePos(3); - test.commit(clone_operation).parents(merge_changeset_implementation) - .lanePos(mainPos); - test.commit(merge_changeset_implementation) - .parents(merge_disable_source, changeset_implementation) - .lanePos(mainPos); - test.commit(merge_disable_source) - .parents(update_eclipse_iplog2, disable_source) - .lanePos(mainPos); - test.commit(update_eclipse_iplog2).parents(merge_use_remote) - .lanePos(mainPos); - test.commit(disable_source).parents(merge_use_remote).lanePos(1); - test.commit(merge_use_remote).parents(update_eclipse_iplog, use_remote) - .lanePos(mainPos); - test.commit(changeset_implementation).parents(clear_repositorycache) - .lanePos(2); - test.commit(update_eclipse_iplog).parents(merge_add_Maven) - .lanePos(mainPos); - test.commit(merge_add_Maven).parents(findToolBar_layout, add_Maven) - .lanePos(mainPos); - test.commit(findToolBar_layout).parents(clear_repositorycache) - .lanePos(mainPos); - test.commit(use_remote).parents(clear_repositorycache).lanePos(1); - test.commit(add_Maven).parents(clear_repositorycache).lanePos(3); - test.commit(clear_repositorycache).parents(merge_remove) - .lanePos(mainPos); - test.commit(resolve_handler).parents(merge_fix).lanePos(4); - test.commit(merge_remove).parents(add_simple, remove_unused) - .lanePos(mainPos); - test.commit(remove_unused).parents(merge_fix).lanePos(1); - test.commit(add_simple).parents(merge_fix).lanePos(mainPos); - test.commit(merge_fix).parents().lanePos(mainPos); - test.noMoreCommits(); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(merge_fixed_logged_npe.getId())); + + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); + + CommitListAssert test = new CommitListAssert(pcl); + + // Note: all positions of side branches are rather arbitrary, but + // some + // may not overlap. Testing for the positions yielded by the current + // implementation, which was manually checked to not overlap. + final int mainPos = 0; + test.commit(merge_fixed_logged_npe) + .parents(sort_roots, fix_logged_npe).lanePos(mainPos); + test.commit(fix_logged_npe).parents(merge_changeset_implementation) + .lanePos(1); + test.commit(sort_roots).parents(merge_update_eclipse) + .lanePos(mainPos); + test.commit(merge_update_eclipse) + .parents(add_a_clear, update_eclipse).lanePos(mainPos); + test.commit(add_a_clear).parents(fix_broken).lanePos(mainPos); + test.commit(fix_broken).parents(merge_disable_comment) + .lanePos(mainPos); + test.commit(merge_disable_comment) + .parents(merge_resolve_handler, disable_comment) + .lanePos(mainPos); + test.commit(disable_comment).parents(clone_operation).lanePos(2); + test.commit(merge_resolve_handler) + .parents(clone_operation, resolve_handler).lanePos(mainPos); + test.commit(update_eclipse).parents(add_Maven).lanePos(3); + test.commit(clone_operation).parents(merge_changeset_implementation) + .lanePos(mainPos); + test.commit(merge_changeset_implementation) + .parents(merge_disable_source, changeset_implementation) + .lanePos(mainPos); + test.commit(merge_disable_source) + .parents(update_eclipse_iplog2, disable_source) + .lanePos(mainPos); + test.commit(update_eclipse_iplog2).parents(merge_use_remote) + .lanePos(mainPos); + test.commit(disable_source).parents(merge_use_remote).lanePos(1); + test.commit(merge_use_remote) + .parents(update_eclipse_iplog, use_remote).lanePos(mainPos); + test.commit(changeset_implementation).parents(clear_repositorycache) + .lanePos(2); + test.commit(update_eclipse_iplog).parents(merge_add_Maven) + .lanePos(mainPos); + test.commit(merge_add_Maven).parents(findToolBar_layout, add_Maven) + .lanePos(mainPos); + test.commit(findToolBar_layout).parents(clear_repositorycache) + .lanePos(mainPos); + test.commit(use_remote).parents(clear_repositorycache).lanePos(1); + test.commit(add_Maven).parents(clear_repositorycache).lanePos(3); + test.commit(clear_repositorycache).parents(merge_remove) + .lanePos(mainPos); + test.commit(resolve_handler).parents(merge_fix).lanePos(4); + test.commit(merge_remove).parents(add_simple, remove_unused) + .lanePos(mainPos); + test.commit(remove_unused).parents(merge_fix).lanePos(1); + test.commit(add_simple).parents(merge_fix).lanePos(mainPos); + test.commit(merge_fix).parents().lanePos(mainPos); + test.noMoreCommits(); + } } // test a history where a merge commit has two time the same parent @@ -403,20 +413,21 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit s1 = commit(m2); final RevCommit s2 = commit(s1); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(m3)); - pw.markStart(pw.lookupCommit(s2)); - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); - - CommitListAssert test = new CommitListAssert(pcl); - test.commit(s2).nrOfPassingLanes(0); - test.commit(s1).nrOfPassingLanes(0); - test.commit(m3).nrOfPassingLanes(1); - test.commit(m2).nrOfPassingLanes(0); - test.commit(m1).nrOfPassingLanes(0); - test.noMoreCommits(); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(m3)); + pw.markStart(pw.lookupCommit(s2)); + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); + + CommitListAssert test = new CommitListAssert(pcl); + test.commit(s2).nrOfPassingLanes(0); + test.commit(s1).nrOfPassingLanes(0); + test.commit(m3).nrOfPassingLanes(1); + test.commit(m2).nrOfPassingLanes(0); + test.commit(m1).nrOfPassingLanes(0); + test.noMoreCommits(); + } } /** @@ -465,30 +476,31 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit a4 = commit(a3); final RevCommit a5 = commit(a3, a4); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(b3.getId())); - pw.markStart(pw.lookupCommit(c.getId())); - pw.markStart(pw.lookupCommit(e.getId())); - pw.markStart(pw.lookupCommit(a5.getId())); - - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); - - // test that the commits b1, b2 and b3 are on the same position - int bPos = pcl.get(9).lane.position; // b1 - assertEquals("b2 is an a different position", bPos, - pcl.get(7).lane.position); - assertEquals("b3 is on a different position", bPos, - pcl.get(4).lane.position); - - // test that nothing blocks the connections between b1, b2 and b3 - assertNotEquals("b lane is blocked by c", bPos, - pcl.get(8).lane.position); - assertNotEquals("b lane is blocked by a2", bPos, - pcl.get(6).lane.position); - assertNotEquals("b lane is blocked by d", bPos, - pcl.get(5).lane.position); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(b3.getId())); + pw.markStart(pw.lookupCommit(c.getId())); + pw.markStart(pw.lookupCommit(e.getId())); + pw.markStart(pw.lookupCommit(a5.getId())); + + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); + + // test that the commits b1, b2 and b3 are on the same position + int bPos = pcl.get(9).lane.position; // b1 + assertEquals("b2 is an a different position", bPos, + pcl.get(7).lane.position); + assertEquals("b3 is on a different position", bPos, + pcl.get(4).lane.position); + + // test that nothing blocks the connections between b1, b2 and b3 + assertNotEquals("b lane is blocked by c", bPos, + pcl.get(8).lane.position); + assertNotEquals("b lane is blocked by a2", bPos, + pcl.get(6).lane.position); + assertNotEquals("b lane is blocked by d", bPos, + pcl.get(5).lane.position); + } } /** @@ -517,23 +529,24 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit a4 = commit(a3, b2); final RevCommit b3 = commit(b2); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(a4)); - pw.markStart(pw.lookupCommit(b3)); - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); - - Set<Integer> positions = asSet(0, 1); - CommitListAssert test = new CommitListAssert(pcl); - int posB = test.commit(b3).lanePos(positions).getLanePos(); - int posA = test.commit(a4).lanePos(positions).getLanePos(); - test.commit(b2).lanePos(posB); - test.commit(a3).lanePos(posA); - test.commit(a2).lanePos(posA); - test.commit(b1).lanePos(posB); - test.commit(a1).lanePos(posA); - test.noMoreCommits(); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(a4)); + pw.markStart(pw.lookupCommit(b3)); + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); + + Set<Integer> positions = asSet(0, 1); + CommitListAssert test = new CommitListAssert(pcl); + int posB = test.commit(b3).lanePos(positions).getLanePos(); + int posA = test.commit(a4).lanePos(positions).getLanePos(); + test.commit(b2).lanePos(posB); + test.commit(a3).lanePos(posA); + test.commit(a2).lanePos(posA); + test.commit(b1).lanePos(posB); + test.commit(a1).lanePos(posA); + test.noMoreCommits(); + } } /** @@ -562,25 +575,26 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit b3 = commit(b2); final RevCommit a4 = commit(a3); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(a4)); - pw.markStart(pw.lookupCommit(b3)); - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); - - Set<Integer> positions = asSet(0, 1); - CommitListAssert test = new CommitListAssert(pcl); - int posA = test.commit(a4).lanePos(positions).getLanePos(); - int posB = test.commit(b3).lanePos(positions).getLanePos(); - test.commit(a3).lanePos(posA); - test.commit(b2).lanePos(posB); - test.commit(a2).lanePos(posA); - // b1 is not repositioned, uses "detour lane" - // (drawn as a double arc in the ascii graph above) - test.commit(b1).lanePos(posB); - test.commit(a1).lanePos(posA); - test.noMoreCommits(); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(a4)); + pw.markStart(pw.lookupCommit(b3)); + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); + + Set<Integer> positions = asSet(0, 1); + CommitListAssert test = new CommitListAssert(pcl); + int posA = test.commit(a4).lanePos(positions).getLanePos(); + int posB = test.commit(b3).lanePos(positions).getLanePos(); + test.commit(a3).lanePos(posA); + test.commit(b2).lanePos(posB); + test.commit(a2).lanePos(posA); + // b1 is not repositioned, uses "detour lane" + // (drawn as a double arc in the ascii graph above) + test.commit(b1).lanePos(posB); + test.commit(a1).lanePos(posA); + test.noMoreCommits(); + } } /** @@ -611,24 +625,25 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit a4 = commit(a3, b1); final RevCommit b2 = commit(b1); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(a4)); - pw.markStart(pw.lookupCommit(b2)); - pw.markStart(pw.lookupCommit(c)); - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); - - Set<Integer> positions = asSet(0, 1, 2); - CommitListAssert test = new CommitListAssert(pcl); - int posB = test.commit(b2).lanePos(positions).getLanePos(); - int posA = test.commit(a4).lanePos(positions).getLanePos(); - test.commit(a3).lanePos(posA); - test.commit(c).lanePos(positions); - test.commit(a2).lanePos(posA); - test.commit(b1).lanePos(posB); // repositioned to go around c - test.commit(a1).lanePos(posA); - test.noMoreCommits(); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(a4)); + pw.markStart(pw.lookupCommit(b2)); + pw.markStart(pw.lookupCommit(c)); + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); + + Set<Integer> positions = asSet(0, 1, 2); + CommitListAssert test = new CommitListAssert(pcl); + int posB = test.commit(b2).lanePos(positions).getLanePos(); + int posA = test.commit(a4).lanePos(positions).getLanePos(); + test.commit(a3).lanePos(posA); + test.commit(c).lanePos(positions); + test.commit(a2).lanePos(posA); + test.commit(b1).lanePos(posB); // repositioned to go around c + test.commit(a1).lanePos(posA); + test.noMoreCommits(); + } } /** @@ -651,22 +666,24 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit a3 = commit(a2); final RevCommit b1 = commit(a1); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(a3)); - pw.markStart(pw.lookupCommit(b1)); - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(2); // don't process a1 - - Set<Integer> positions = asSet(0, 1); - CommitListAssert test = new CommitListAssert(pcl); - PlotLane laneB = test.commit(b1).lanePos(positions).current.getLane(); - int posA = test.commit(a3).lanePos(positions).getLanePos(); - test.commit(a2).lanePos(posA); - assertArrayEquals( - "Although the parent of b1, a1, is not processed yet, the b lane should still be drawn", - new PlotLane[] { laneB }, test.current.passingLanes); - test.noMoreCommits(); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(a3)); + pw.markStart(pw.lookupCommit(b1)); + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(2); // don't process a1 + + Set<Integer> positions = asSet(0, 1); + CommitListAssert test = new CommitListAssert(pcl); + PlotLane laneB = test.commit(b1).lanePos(positions).current + .getLane(); + int posA = test.commit(a3).lanePos(positions).getLanePos(); + test.commit(a2).lanePos(posA); + assertArrayEquals( + "Although the parent of b1, a1, is not processed yet, the b lane should still be drawn", + new PlotLane[] { laneB }, test.current.passingLanes); + test.noMoreCommits(); + } } @Test @@ -674,17 +691,18 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit a = commit(); final RevCommit b = commit(); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(a)); - pw.markStart(pw.lookupCommit(b)); - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); - - CommitListAssert test = new CommitListAssert(pcl); - test.commit(b).lanePos(0); - test.commit(a).lanePos(0); - test.noMoreCommits(); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(a)); + pw.markStart(pw.lookupCommit(b)); + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); + + CommitListAssert test = new CommitListAssert(pcl); + test.commit(b).lanePos(0); + test.commit(a).lanePos(0); + test.noMoreCommits(); + } } @Test @@ -693,17 +711,18 @@ public class PlotCommitListTest extends RevWalkTestCase { final RevCommit b1 = commit(); final RevCommit b2 = commit(b1); - PlotWalk pw = new PlotWalk(db); - pw.markStart(pw.lookupCommit(a)); - pw.markStart(pw.lookupCommit(b2)); - PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); - pcl.source(pw); - pcl.fillTo(Integer.MAX_VALUE); - - CommitListAssert test = new CommitListAssert(pcl); - test.commit(b2).lanePos(0); - test.commit(b1).lanePos(0); - test.commit(a).lanePos(0); - test.noMoreCommits(); + try (PlotWalk pw = new PlotWalk(db)) { + pw.markStart(pw.lookupCommit(a)); + pw.markStart(pw.lookupCommit(b2)); + PlotCommitList<PlotLane> pcl = new PlotCommitList<>(); + pcl.source(pw); + pcl.fillTo(Integer.MAX_VALUE); + + CommitListAssert test = new CommitListAssert(pcl); + test.commit(b2).lanePos(0); + test.commit(b1).lanePos(0); + test.commit(a).lanePos(0); + test.noMoreCommits(); + } } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/BitmapCalculatorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/BitmapCalculatorTest.java deleted file mode 100644 index c5d4d4238d..0000000000 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/BitmapCalculatorTest.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2019, Google LLC. - * 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.revwalk; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.eclipse.jgit.internal.storage.file.FileRepository; -import org.eclipse.jgit.internal.storage.file.GC; -import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; -import org.eclipse.jgit.junit.TestRepository; -import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder; -import org.eclipse.jgit.lib.NullProgressMonitor; -import org.eclipse.jgit.lib.ProgressMonitor; -import org.junit.Before; -import org.junit.Test; - -public class BitmapCalculatorTest extends LocalDiskRepositoryTestCase { - TestRepository<FileRepository> repo; - - /** {@inheritDoc} */ - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - FileRepository db = createWorkRepository(); - repo = new TestRepository<>(db); - } - - @Test - public void addOnlyCommits() throws Exception { - RevBlob abBlob = repo.blob("a_b_content"); - RevCommit root = repo.commit().add("a/b", abBlob).create(); - repo.update("refs/heads/master", root); - - // GC creates bitmap index with ALL objects - GC gc = new GC(repo.getRepository()); - gc.setAuto(false); - gc.gc(); - - // These objects are not in the bitmap index. - RevBlob acBlob = repo.blob("a_c_content"); - RevCommit head = repo.commit().parent(root).add("a/c", acBlob).create(); - repo.update("refs/heads/master", head); - - BitmapCalculator bitmapWalker = new BitmapCalculator(repo.getRevWalk()); - BitmapBuilder bitmap = bitmapWalker - .getBitmap(head, NullProgressMonitor.INSTANCE); - - assertTrue(bitmap.contains(root.getId())); - assertTrue(bitmap.contains(root.getTree().getId())); - assertTrue(bitmap.contains(abBlob.getId())); - - // BitmapCalculator added only the commit, no other objects. - assertTrue(bitmap.contains(head.getId())); - assertFalse(bitmap.contains(head.getTree().getId())); - assertFalse(bitmap.contains(acBlob.getId())); - } - - @Test - public void walkUntilBitmap() throws Exception { - RevCommit root = repo.commit().create(); - repo.update("refs/heads/master", root); - - // GC creates bitmap index with ALL objects - GC gc = new GC(repo.getRepository()); - gc.setAuto(false); - gc.gc(); - - // These objects are not in the bitmap index. - RevCommit commit1 = repo.commit(root); - RevCommit commit2 = repo.commit(commit1); - repo.update("refs/heads/master", commit2); - - CounterProgressMonitor monitor = new CounterProgressMonitor(); - BitmapCalculator bitmapWalker = new BitmapCalculator(repo.getRevWalk()); - BitmapBuilder bitmap = bitmapWalker.getBitmap(commit2, monitor); - - assertTrue(bitmap.contains(root)); - assertTrue(bitmap.contains(commit1)); - assertTrue(bitmap.contains(commit2)); - assertEquals(2, monitor.getUpdates()); - } - - @Test - public void noNeedToWalk() throws Exception { - RevCommit root = repo.commit().create(); - RevCommit commit1 = repo.commit(root); - RevCommit commit2 = repo.commit(commit1); - repo.update("refs/heads/master", commit2); - - // GC creates bitmap index with ALL objects - GC gc = new GC(repo.getRepository()); - gc.setAuto(false); - gc.gc(); - - CounterProgressMonitor monitor = new CounterProgressMonitor(); - BitmapCalculator bitmapWalker = new BitmapCalculator(repo.getRevWalk()); - BitmapBuilder bitmap = bitmapWalker.getBitmap(commit2, monitor); - - assertTrue(bitmap.contains(root)); - assertTrue(bitmap.contains(commit1)); - assertTrue(bitmap.contains(commit2)); - assertEquals(0, monitor.getUpdates()); - } - - private static class CounterProgressMonitor implements ProgressMonitor { - - private int counter; - - @Override - public void start(int totalTasks) { - // Nothing to do in tests - } - - @Override - public void beginTask(String title, int totalWork) { - // Nothing to to in tests - } - - @Override - public void update(int completed) { - counter += 1; - } - - @Override - public void endTask() { - // Nothing to do in tests - } - - @Override - public boolean isCancelled() { - return false; - } - - int getUpdates() { - return counter; - } - } -}
\ No newline at end of file diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java index 1fc7a55457..d46f48bcd9 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FirstParentRevWalkTest.java @@ -49,6 +49,7 @@ import static org.junit.Assert.assertNull; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.revwalk.filter.MessageRevFilter; import org.eclipse.jgit.revwalk.filter.RevFilter; +import org.eclipse.jgit.treewalk.filter.PathFilterGroup; import org.junit.Test; public class FirstParentRevWalkTest extends RevWalkTestCase { @@ -425,4 +426,39 @@ public class FirstParentRevWalkTest extends RevWalkTestCase { markStart(a); assertNull(rw.next()); } + + @Test + public void testWithTopoSortAndTreeFilter() throws Exception { + RevCommit a = commit(); + RevCommit b = commit(tree(file("0", blob("b"))), a); + RevCommit c = commit(tree(file("0", blob("c"))), b, a); + RevCommit d = commit(tree(file("0", blob("d"))), c); + + rw.reset(); + rw.setFirstParent(true); + rw.sort(RevSort.TOPO, true); + rw.setTreeFilter(PathFilterGroup.createFromStrings("0")); + markStart(d); + assertCommit(d, rw.next()); + assertCommit(c, rw.next()); + assertCommit(b, rw.next()); + assertNull(rw.next()); + } + + @Test + public void testWithTopoSortAndTreeFilter2() throws Exception { + RevCommit a = commit(); + RevCommit b = commit(tree(file("0", blob("b"))), a); + RevCommit c = commit(tree(file("0", blob("c"))), a, b); + RevCommit d = commit(tree(file("0", blob("d"))), c); + + rw.reset(); + rw.setFirstParent(true); + rw.sort(RevSort.TOPO, true); + rw.setTreeFilter(PathFilterGroup.createFromStrings("0")); + markStart(d); + assertCommit(d, rw.next()); + assertCommit(c, rw.next()); + assertNull(rw.next()); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ReachabilityCheckerTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ReachabilityCheckerTestCase.java index dd73e35727..092033449b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ReachabilityCheckerTestCase.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ReachabilityCheckerTestCase.java @@ -47,6 +47,7 @@ import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Optional; +import java.util.stream.Stream; import org.eclipse.jgit.internal.storage.file.FileRepository; import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; @@ -83,11 +84,11 @@ public abstract class ReachabilityCheckerTestCase ReachabilityChecker checker = getChecker(repo); assertReachable("reachable from one tip", - checker.areAllReachable(Arrays.asList(a), Arrays.asList(c2))); + checker.areAllReachable(Arrays.asList(a), Stream.of(c2))); assertReachable("reachable from another tip", - checker.areAllReachable(Arrays.asList(a), Arrays.asList(b2))); + checker.areAllReachable(Arrays.asList(a), Stream.of(b2))); assertReachable("reachable from itself", - checker.areAllReachable(Arrays.asList(a), Arrays.asList(b2))); + checker.areAllReachable(Arrays.asList(a), Stream.of(b2))); } @Test @@ -104,13 +105,13 @@ public abstract class ReachabilityCheckerTestCase assertReachable("reachable through one branch", checker.areAllReachable(Arrays.asList(b1), - Arrays.asList(merge))); + Stream.of(merge))); assertReachable("reachable through another branch", checker.areAllReachable(Arrays.asList(c1), - Arrays.asList(merge))); + Stream.of(merge))); assertReachable("reachable, before the branching", checker.areAllReachable(Arrays.asList(a), - Arrays.asList(merge))); + Stream.of(merge))); } @Test @@ -123,7 +124,7 @@ public abstract class ReachabilityCheckerTestCase ReachabilityChecker checker = getChecker(repo); assertUnreachable("unreachable from the future", - checker.areAllReachable(Arrays.asList(b2), Arrays.asList(b1))); + checker.areAllReachable(Arrays.asList(b2), Stream.of(b1))); } @Test @@ -137,7 +138,7 @@ public abstract class ReachabilityCheckerTestCase ReachabilityChecker checker = getChecker(repo); assertUnreachable("unreachable from different branch", - checker.areAllReachable(Arrays.asList(c1), Arrays.asList(b2))); + checker.areAllReachable(Arrays.asList(c1), Stream.of(b2))); } @Test @@ -152,7 +153,7 @@ public abstract class ReachabilityCheckerTestCase ReachabilityChecker checker = getChecker(repo); assertReachable("reachable with long chain in the middle", checker - .areAllReachable(Arrays.asList(root), Arrays.asList(head))); + .areAllReachable(Arrays.asList(root), Stream.of(head))); } private static void assertReachable(String msg, @@ -164,5 +165,4 @@ public abstract class ReachabilityCheckerTestCase Optional<RevCommit> result) { assertTrue(msg, result.isPresent()); } - } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java index b814984935..d6b63ab236 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java @@ -107,18 +107,18 @@ public class RevCommitParseTest extends RepositoryTestCase { body.append("\n"); - final RevWalk rw = new RevWalk(db); final RevCommit c; c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); assertNull(c.getTree()); assertNull(c.parents); - c.parseCanonical(rw, body.toString().getBytes(UTF_8)); - assertNotNull(c.getTree()); - assertEquals(treeId, c.getTree().getId()); - assertSame(rw.lookupTree(treeId), c.getTree()); - + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, body.toString().getBytes(UTF_8)); + assertNotNull(c.getTree()); + assertEquals(treeId, c.getTree().getId()); + assertSame(rw.lookupTree(treeId), c.getTree()); + } assertNotNull(c.parents); assertEquals(0, c.parents.length); assertEquals("", c.getFullMessage()); @@ -148,8 +148,10 @@ public class RevCommitParseTest extends RepositoryTestCase { final RevCommit c; c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), b.toString().getBytes(UTF_8)); - return c; + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toString().getBytes(UTF_8)); + return c; + } } @Test @@ -161,8 +163,9 @@ public class RevCommitParseTest extends RepositoryTestCase { final RevCommit c; c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), b.toString().getBytes(UTF_8)); - + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toString().getBytes(UTF_8)); + } assertEquals("", c.getFullMessage()); assertEquals("", c.getShortMessage()); } @@ -176,8 +179,9 @@ public class RevCommitParseTest extends RepositoryTestCase { final RevCommit c; c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), b.toString().getBytes(UTF_8)); - + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toString().getBytes(UTF_8)); + } assertEquals(new PersonIdent("", "a_u_thor@example.com", 1218123387000l, 7), c.getAuthorIdent()); assertEquals(new PersonIdent("", "", 1218123390000l, -5), c.getCommitterIdent()); } @@ -194,8 +198,9 @@ public class RevCommitParseTest extends RepositoryTestCase { b.write("\u304d\u308c\u3044\n".getBytes(UTF_8)); final RevCommit c; c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id - c.parseCanonical(new RevWalk(db), b.toByteArray()); - + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertSame(UTF_8, c.getEncoding()); assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName()); assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage()); @@ -214,8 +219,9 @@ public class RevCommitParseTest extends RepositoryTestCase { b.write("\u304d\u308c\u3044\n".getBytes(UTF_8)); final RevCommit c; c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id - c.parseCanonical(new RevWalk(db), b.toByteArray()); - + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertSame(UTF_8, c.getEncoding()); assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName()); assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage()); @@ -240,7 +246,9 @@ public class RevCommitParseTest extends RepositoryTestCase { b.write("Hi\n".getBytes("EUC-JP")); final RevCommit c; c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id - c.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertEquals("EUC-JP", c.getEncoding().name()); assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName()); @@ -270,7 +278,9 @@ public class RevCommitParseTest extends RepositoryTestCase { b.write("Hi\n".getBytes(UTF_8)); final RevCommit c; c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id - c.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertEquals("EUC-JP", c.getEncoding().name()); assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName()); @@ -301,7 +311,9 @@ public class RevCommitParseTest extends RepositoryTestCase { b.write("Hi\n".getBytes(UTF_8)); final RevCommit c; c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id - c.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertEquals("ISO-8859-1", c.getEncoding().name()); assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName()); @@ -323,7 +335,9 @@ public class RevCommitParseTest extends RepositoryTestCase { RevCommit c = new RevCommit( id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertEquals("'utf8'", c.getEncodingName()); assertEquals("Sm\u00f6rg\u00e5sbord\n", c.getFullMessage()); @@ -347,7 +361,9 @@ public class RevCommitParseTest extends RepositoryTestCase { RevCommit c = new RevCommit( id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertEquals("utf-8logoutputencoding=gbk", c.getEncodingName()); assertEquals("message\n", c.getFullMessage()); assertEquals("message", c.getShortMessage()); @@ -374,7 +390,9 @@ public class RevCommitParseTest extends RepositoryTestCase { RevCommit c = new RevCommit( id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertEquals("it_IT.UTF8", c.getEncodingName()); assertEquals("message\n", c.getFullMessage()); assertEquals("message", c.getShortMessage()); @@ -507,7 +525,9 @@ public class RevCommitParseTest extends RepositoryTestCase { final RevCommit c; c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), commit.getBytes(UTF_8)); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, commit.getBytes(UTF_8)); + } String gpgSig = new String(c.getRawGpgSignature(), UTF_8); assertTrue(gpgSig.startsWith("-----BEGIN")); assertTrue(gpgSig.endsWith("END PGP SIGNATURE-----")); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java index 1b45473066..bbc559b2db 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java @@ -91,17 +91,18 @@ public class RevTagParseTest extends RepositoryTestCase { b.append("tagger A U. Thor <a_u_thor@example.com> 1218123387 +0700\n"); b.append("\n"); - final RevWalk rw = new RevWalk(db); final RevTag c; c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); assertNull(c.getObject()); assertNull(c.getTagName()); - c.parseCanonical(rw, b.toString().getBytes(UTF_8)); - assertNotNull(c.getObject()); - assertEquals(id, c.getObject().getId()); - assertSame(rw.lookupAny(id, typeCode), c.getObject()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toString().getBytes(UTF_8)); + assertNotNull(c.getObject()); + assertEquals(id, c.getObject().getId()); + assertSame(rw.lookupAny(id, typeCode), c.getObject()); + } } @Test @@ -134,18 +135,18 @@ public class RevTagParseTest extends RepositoryTestCase { body.append("\n"); - final RevWalk rw = new RevWalk(db); final RevTag c; c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); assertNull(c.getObject()); assertNull(c.getTagName()); - c.parseCanonical(rw, body.toString().getBytes(UTF_8)); - assertNotNull(c.getObject()); - assertEquals(treeId, c.getObject().getId()); - assertSame(rw.lookupTree(treeId), c.getObject()); - + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, body.toString().getBytes(UTF_8)); + assertNotNull(c.getObject()); + assertEquals(treeId, c.getObject().getId()); + assertSame(rw.lookupTree(treeId), c.getObject()); + } assertNotNull(c.getTagName()); assertEquals(name, c.getTagName()); assertEquals("", c.getFullMessage()); @@ -182,17 +183,18 @@ public class RevTagParseTest extends RepositoryTestCase { body.append("\n"); body.append(message); - final RevWalk rw = new RevWalk(db); final RevTag c; c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); assertNull(c.getObject()); assertNull(c.getTagName()); - c.parseCanonical(rw, body.toString().getBytes(UTF_8)); - assertNotNull(c.getObject()); - assertEquals(treeId, c.getObject().getId()); - assertSame(rw.lookupTree(treeId), c.getObject()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, body.toString().getBytes(UTF_8)); + assertNotNull(c.getObject()); + assertEquals(treeId, c.getObject().getId()); + assertSame(rw.lookupTree(treeId), c.getObject()); + } assertNotNull(c.getTagName()); assertEquals(name, c.getTagName()); @@ -213,7 +215,9 @@ public class RevTagParseTest extends RepositoryTestCase { final RevTag c; c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), b.toString().getBytes(UTF_8)); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toString().getBytes(UTF_8)); + } return c; } @@ -234,7 +238,9 @@ public class RevTagParseTest extends RepositoryTestCase { b.write("\u304d\u308c\u3044\n".getBytes(UTF_8)); final RevTag c; c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName()); assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage()); @@ -257,7 +263,9 @@ public class RevTagParseTest extends RepositoryTestCase { b.write("\u304d\u308c\u3044\n".getBytes(UTF_8)); final RevTag c; c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName()); assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage()); @@ -287,7 +295,9 @@ public class RevTagParseTest extends RepositoryTestCase { b.write("Hi\n".getBytes("EUC-JP")); final RevTag c; c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName()); assertEquals("\u304d\u308c\u3044", c.getShortMessage()); @@ -320,7 +330,9 @@ public class RevTagParseTest extends RepositoryTestCase { b.write("Hi\n".getBytes(UTF_8)); final RevTag c; c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName()); assertEquals("\u304d\u308c\u3044", c.getShortMessage()); @@ -355,7 +367,9 @@ public class RevTagParseTest extends RepositoryTestCase { b.write("Hi\n".getBytes(UTF_8)); final RevTag c; c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - c.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + c.parseCanonical(rw, b.toByteArray()); + } assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName()); assertEquals("\u304d\u308c\u3044", c.getShortMessage()); @@ -374,7 +388,9 @@ public class RevTagParseTest extends RepositoryTestCase { b.write("message\n".getBytes(UTF_8)); RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - t.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + t.parseCanonical(rw, b.toByteArray()); + } assertEquals("t", t.getTaggerIdent().getName()); assertEquals("message", t.getShortMessage()); @@ -393,7 +409,9 @@ public class RevTagParseTest extends RepositoryTestCase { b.write("message\n".getBytes(UTF_8)); RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); - t.parseCanonical(new RevWalk(db), b.toByteArray()); + try (RevWalk rw = new RevWalk(db)) { + t.parseCanonical(rw, b.toByteArray()); + } assertEquals("t", t.getTaggerIdent().getName()); assertEquals("message", t.getShortMessage()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/TreeRevFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/TreeRevFilterTest.java index 9548992a2b..a345459b3b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/TreeRevFilterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/TreeRevFilterTest.java @@ -46,25 +46,15 @@ package org.eclipse.jgit.revwalk; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import java.util.Collections; - import org.eclipse.jgit.revwalk.filter.OrRevFilter; import org.eclipse.jgit.revwalk.filter.RevFilter; import org.eclipse.jgit.revwalk.filter.SkipRevFilter; -import org.eclipse.jgit.treewalk.filter.AndTreeFilter; -import org.eclipse.jgit.treewalk.filter.PathFilterGroup; import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.junit.Test; public class TreeRevFilterTest extends RevWalkTestCase { - private RevFilter treeRevFilter(String path) { - return new TreeRevFilter(rw, treeFilter(path)); - } - - private static TreeFilter treeFilter(String path) { - return AndTreeFilter.create( - PathFilterGroup.createFromStrings(Collections.singleton(path)), - TreeFilter.ANY_DIFF); + private RevFilter treeRevFilter() { + return new TreeRevFilter(rw, TreeFilter.ANY_DIFF); } @Test @@ -73,7 +63,7 @@ public class TreeRevFilterTest extends RevWalkTestCase { RevCommit a = commit(tree(file("d/f", blob("a")))); RevCommit b = commit(tree(file("d/f", blob("a"))), a); RevCommit c = commit(tree(file("d/f", blob("b"))), b); - rw.setRevFilter(treeRevFilter("d/f")); + rw.setRevFilter(treeRevFilter()); markStart(c); assertCommit(c, rw.next()); @@ -91,7 +81,7 @@ public class TreeRevFilterTest extends RevWalkTestCase { RevCommit b = commit(tree(file("d/f", blob("a"))), a); RevCommit c = commit(tree(file("d/f", blob("b"))), b); RevCommit d = commit(tree(file("d/f", blob("b"))), c); - rw.setRevFilter(treeRevFilter("d/f")); + rw.setRevFilter(treeRevFilter()); markStart(d); // d was skipped @@ -111,7 +101,7 @@ public class TreeRevFilterTest extends RevWalkTestCase { RevCommit b = commit(tree(file("d/f", blob("a"))), a); RevCommit c = commit(tree(file("d/f", blob("b"))), b); RevCommit d = commit(tree(file("d/f", blob("b"))), c); - rw.setRevFilter(treeRevFilter("d")); + rw.setRevFilter(treeRevFilter()); markStart(d); // d was skipped @@ -136,7 +126,7 @@ public class TreeRevFilterTest extends RevWalkTestCase { RevCommit g = commit(tree(file("d/f", blob("b"))), f); RevCommit h = commit(tree(file("d/f", blob("b"))), g); RevCommit i = commit(tree(file("d/f", blob("c"))), h); - rw.setRevFilter(treeRevFilter("d/f")); + rw.setRevFilter(treeRevFilter()); markStart(i); assertCommit(i, rw.next()); @@ -156,7 +146,7 @@ public class TreeRevFilterTest extends RevWalkTestCase { @Test public void testPathFilterOrOtherFilter() throws Exception { - RevFilter pathFilter = treeRevFilter("d/f"); + RevFilter pathFilter = treeRevFilter(); RevFilter skipFilter = SkipRevFilter.create(1); RevFilter orFilter = OrRevFilter.create(skipFilter, pathFilter); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java index 1ff64a2e28..80e9e6b14b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java @@ -135,20 +135,20 @@ public class SubmoduleAddTest extends RepositoryTestCase { subCommit = repo.resolve(Constants.HEAD); } - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - generator.loadModulesConfig(); - assertTrue(generator.next()); - assertEquals(path, generator.getModuleName()); - assertEquals(path, generator.getPath()); - assertEquals(commit, generator.getObjectId()); - assertEquals(uri, generator.getModulesUrl()); - assertEquals(path, generator.getModulesPath()); - assertEquals(uri, generator.getConfigUrl()); - try (Repository subModRepo = generator.getRepository()) { - assertNotNull(subModRepo); - assertEquals(subCommit, commit); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + generator.loadModulesConfig(); + assertTrue(generator.next()); + assertEquals(path, generator.getModuleName()); + assertEquals(path, generator.getPath()); + assertEquals(commit, generator.getObjectId()); + assertEquals(uri, generator.getModulesUrl()); + assertEquals(path, generator.getModulesPath()); + assertEquals(uri, generator.getConfigUrl()); + try (Repository subModRepo = generator.getRepository()) { + assertNotNull(subModRepo); + assertEquals(subCommit, commit); + } } - Status status = Git.wrap(db).status().call(); assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES)); assertTrue(status.getAdded().contains(path)); @@ -175,20 +175,20 @@ public class SubmoduleAddTest extends RepositoryTestCase { subCommit = repo.resolve(Constants.HEAD); } - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - generator.loadModulesConfig(); - assertTrue(generator.next()); - assertEquals(name, generator.getModuleName()); - assertEquals(path, generator.getPath()); - assertEquals(commit, generator.getObjectId()); - assertEquals(uri, generator.getModulesUrl()); - assertEquals(path, generator.getModulesPath()); - assertEquals(uri, generator.getConfigUrl()); - try (Repository subModRepo = generator.getRepository()) { - assertNotNull(subModRepo); - assertEquals(subCommit, commit); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + generator.loadModulesConfig(); + assertTrue(generator.next()); + assertEquals(name, generator.getModuleName()); + assertEquals(path, generator.getPath()); + assertEquals(commit, generator.getObjectId()); + assertEquals(uri, generator.getModulesUrl()); + assertEquals(path, generator.getModulesPath()); + assertEquals(uri, generator.getConfigUrl()); + try (Repository subModRepo = generator.getRepository()) { + assertNotNull(subModRepo); + assertEquals(subCommit, commit); + } } - Status status = Git.wrap(db).status().call(); assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES)); assertTrue(status.getAdded().contains(path)); @@ -269,24 +269,25 @@ public class SubmoduleAddTest extends RepositoryTestCase { assertNotNull(repo); addRepoToClose(repo); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertEquals(path, generator.getPath()); - assertEquals(commit, generator.getObjectId()); - assertEquals(uri, generator.getModulesUrl()); - assertEquals(path, generator.getModulesPath()); - String fullUri = db.getDirectory().getAbsolutePath(); - if (File.separatorChar == '\\') { - fullUri = fullUri.replace('\\', '/'); - } - assertEquals(fullUri, generator.getConfigUrl()); - try (Repository subModRepo = generator.getRepository()) { - assertNotNull(subModRepo); - assertEquals(fullUri, - subModRepo.getConfig().getString( - ConfigConstants.CONFIG_REMOTE_SECTION, - Constants.DEFAULT_REMOTE_NAME, - ConfigConstants.CONFIG_KEY_URL)); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertEquals(path, generator.getPath()); + assertEquals(commit, generator.getObjectId()); + assertEquals(uri, generator.getModulesUrl()); + assertEquals(path, generator.getModulesPath()); + String fullUri = db.getDirectory().getAbsolutePath(); + if (File.separatorChar == '\\') { + fullUri = fullUri.replace('\\', '/'); + } + assertEquals(fullUri, generator.getConfigUrl()); + try (Repository subModRepo = generator.getRepository()) { + assertNotNull(subModRepo); + assertEquals(fullUri, + subModRepo.getConfig().getString( + ConfigConstants.CONFIG_REMOTE_SECTION, + Constants.DEFAULT_REMOTE_NAME, + ConfigConstants.CONFIG_KEY_URL)); + } } assertEquals(commit, repo.resolve(Constants.HEAD)); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleDeinitTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleDeinitTest.java index 815ce9b350..bb0085106d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleDeinitTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleDeinitTest.java @@ -107,7 +107,6 @@ public class SubmoduleDeinitTest extends RepositoryTestCase { assertEquals(1, updated.size()); File submoduleDir = assertSubmoduleIsInitialized(); - SubmoduleWalk generator; write(new File(submoduleDir, "untracked"), "untracked"); @@ -115,8 +114,9 @@ public class SubmoduleDeinitTest extends RepositoryTestCase { assertEquals(path, result.getPath()); assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.DIRTY, result.getStatus()); - generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + } assertTrue(submoduleDir.isDirectory()); assertNotEquals(0, submoduleDir.list().length); } @@ -132,33 +132,36 @@ public class SubmoduleDeinitTest extends RepositoryTestCase { assertEquals(1, updated.size()); File submoduleDir = assertSubmoduleIsInitialized(); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - generator.next(); - - //want to create a commit inside the repo... - try (Repository submoduleLocalRepo = generator.getRepository()) { - JGitTestUtil.writeTrashFile(submoduleLocalRepo, "file.txt", - "new data"); - Git.wrap(submoduleLocalRepo).commit().setAll(true) - .setMessage("local commit").call(); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + generator.next(); + + // want to create a commit inside the repo... + try (Repository submoduleLocalRepo = generator.getRepository()) { + JGitTestUtil.writeTrashFile(submoduleLocalRepo, "file.txt", + "new data"); + Git.wrap(submoduleLocalRepo).commit().setAll(true) + .setMessage("local commit").call(); + } } SubmoduleDeinitResult result = runDeinit(new SubmoduleDeinitCommand(db).addPath("sub")); assertEquals(path, result.getPath()); assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.DIRTY, result.getStatus()); - generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + } assertTrue(submoduleDir.isDirectory()); assertNotEquals(0, submoduleDir.list().length); } private File assertSubmoduleIsInitialized() throws IOException { - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - File submoduleDir = new File(db.getWorkTree(), generator.getPath()); - assertTrue(submoduleDir.isDirectory()); - assertNotEquals(0, submoduleDir.list().length); - return submoduleDir; + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + File submoduleDir = new File(db.getWorkTree(), generator.getPath()); + assertTrue(submoduleDir.isDirectory()); + assertNotEquals(0, submoduleDir.list().length); + return submoduleDir; + } } @Test @@ -180,8 +183,9 @@ public class SubmoduleDeinitTest extends RepositoryTestCase { assertEquals(path, result.getPath()); assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.FORCED, result.getStatus()); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + } assertTrue(submoduleDir.isDirectory()); assertEquals(0, submoduleDir.list().length); } @@ -202,8 +206,9 @@ public class SubmoduleDeinitTest extends RepositoryTestCase { assertEquals(path, result.getPath()); assertEquals(SubmoduleDeinitCommand.SubmoduleDeinitStatus.SUCCESS, result.getStatus()); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + } assertTrue(submoduleDir.isDirectory()); assertEquals(0, submoduleDir.list().length); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java index c7a009c5bf..9fe2fc6fdc 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java @@ -86,11 +86,11 @@ public class SubmoduleInitTest extends RepositoryTestCase { ConfigInvalidException, GitAPIException { final String path = addSubmoduleToIndex(); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertNull(generator.getConfigUrl()); - assertNull(generator.getConfigUpdate()); - + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertNull(generator.getConfigUrl()); + assertNull(generator.getConfigUpdate()); + } FileBasedConfig modulesConfig = new FileBasedConfig(new File( db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS()); modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, @@ -109,10 +109,11 @@ public class SubmoduleInitTest extends RepositoryTestCase { assertEquals(1, modules.size()); assertEquals(path, modules.iterator().next()); - generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertEquals(url, generator.getConfigUrl()); - assertEquals(update, generator.getConfigUpdate()); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertEquals(url, generator.getConfigUrl()); + assertEquals(update, generator.getConfigUpdate()); + } } @Test @@ -126,11 +127,11 @@ public class SubmoduleInitTest extends RepositoryTestCase { base); config.save(); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertNull(generator.getConfigUrl()); - assertNull(generator.getConfigUpdate()); - + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertNull(generator.getConfigUrl()); + assertNull(generator.getConfigUpdate()); + } FileBasedConfig modulesConfig = new FileBasedConfig(new File( db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS()); modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, @@ -149,10 +150,12 @@ public class SubmoduleInitTest extends RepositoryTestCase { assertEquals(1, modules.size()); assertEquals(path, modules.iterator().next()); - generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertEquals("git://server/repo.git/sub.git", generator.getConfigUrl()); - assertEquals(update, generator.getConfigUpdate()); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertEquals("git://server/repo.git/sub.git", + generator.getConfigUrl()); + assertEquals(update, generator.getConfigUpdate()); + } } @Test @@ -167,11 +170,11 @@ public class SubmoduleInitTest extends RepositoryTestCase { base); config.save(); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertNull(generator.getConfigUrl()); - assertNull(generator.getConfigUpdate()); - + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertNull(generator.getConfigUrl()); + assertNull(generator.getConfigUpdate()); + } FileBasedConfig modulesConfig = new FileBasedConfig(new File( db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS()); modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, @@ -190,10 +193,11 @@ public class SubmoduleInitTest extends RepositoryTestCase { assertEquals(1, modules.size()); assertEquals(path, modules.iterator().next()); - generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertEquals("git://server/sub.git", generator.getConfigUrl()); - assertEquals(update, generator.getConfigUpdate()); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertEquals("git://server/sub.git", generator.getConfigUrl()); + assertEquals(update, generator.getConfigUpdate()); + } } @Test @@ -208,11 +212,11 @@ public class SubmoduleInitTest extends RepositoryTestCase { base); config.save(); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertNull(generator.getConfigUrl()); - assertNull(generator.getConfigUpdate()); - + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertNull(generator.getConfigUrl()); + assertNull(generator.getConfigUpdate()); + } FileBasedConfig modulesConfig = new FileBasedConfig(new File( db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS()); modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, @@ -231,10 +235,11 @@ public class SubmoduleInitTest extends RepositoryTestCase { assertEquals(1, modules.size()); assertEquals(path, modules.iterator().next()); - generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertEquals("git://server2/sub.git", generator.getConfigUrl()); - assertEquals(update, generator.getConfigUpdate()); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertEquals("git://server2/sub.git", generator.getConfigUrl()); + assertEquals(update, generator.getConfigUpdate()); + } } @Test @@ -250,11 +255,11 @@ public class SubmoduleInitTest extends RepositoryTestCase { Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL); config.save(); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertNull(generator.getConfigUrl()); - assertNull(generator.getConfigUpdate()); - + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertNull(generator.getConfigUrl()); + assertNull(generator.getConfigUpdate()); + } FileBasedConfig modulesConfig = new FileBasedConfig(new File( db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS()); modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, @@ -273,10 +278,11 @@ public class SubmoduleInitTest extends RepositoryTestCase { assertEquals(1, modules.size()); assertEquals(path, modules.iterator().next()); - generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertEquals(base + "/sub.git", generator.getConfigUrl()); - assertEquals(update, generator.getConfigUpdate()); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertEquals(base + "/sub.git", generator.getConfigUrl()); + assertEquals(update, generator.getConfigUpdate()); + } } @Test @@ -291,11 +297,11 @@ public class SubmoduleInitTest extends RepositoryTestCase { base); config.save(); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertNull(generator.getConfigUrl()); - assertNull(generator.getConfigUpdate()); - + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertNull(generator.getConfigUrl()); + assertNull(generator.getConfigUpdate()); + } FileBasedConfig modulesConfig = new FileBasedConfig(new File( db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS()); modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java index 6f3b52f7bb..1053e31bc9 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java @@ -119,11 +119,11 @@ public class SubmoduleSyncTest extends RepositoryTestCase { addRepoToClose(subRepo); assertNotNull(subRepo); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertNull(generator.getConfigUrl()); - assertEquals(url, generator.getModulesUrl()); - + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertNull(generator.getConfigUrl()); + assertEquals(url, generator.getModulesUrl()); + } SubmoduleSyncCommand command = new SubmoduleSyncCommand(db); Map<String, String> synced = command.call(); assertNotNull(synced); @@ -132,16 +132,17 @@ public class SubmoduleSyncTest extends RepositoryTestCase { assertEquals(path, module.getKey()); assertEquals(url, module.getValue()); - generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertEquals(url, generator.getConfigUrl()); - try (Repository subModRepository = generator.getRepository()) { - StoredConfig submoduleConfig = subModRepository.getConfig(); - assertEquals(url, - submoduleConfig.getString( - ConfigConstants.CONFIG_REMOTE_SECTION, - Constants.DEFAULT_REMOTE_NAME, - ConfigConstants.CONFIG_KEY_URL)); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertEquals(url, generator.getConfigUrl()); + try (Repository subModRepository = generator.getRepository()) { + StoredConfig submoduleConfig = subModRepository.getConfig(); + assertEquals(url, + submoduleConfig.getString( + ConfigConstants.CONFIG_REMOTE_SECTION, + Constants.DEFAULT_REMOTE_NAME, + ConfigConstants.CONFIG_KEY_URL)); + } } } @@ -190,11 +191,11 @@ public class SubmoduleSyncTest extends RepositoryTestCase { assertNotNull(subRepo); addRepoToClose(subRepo); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertNull(generator.getConfigUrl()); - assertEquals(current, generator.getModulesUrl()); - + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertNull(generator.getConfigUrl()); + assertEquals(current, generator.getModulesUrl()); + } modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path, ConfigConstants.CONFIG_KEY_URL, "../sub.git"); modulesConfig.save(); @@ -207,16 +208,17 @@ public class SubmoduleSyncTest extends RepositoryTestCase { assertEquals(path, module.getKey()); assertEquals("git://server/sub.git", module.getValue()); - generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - assertEquals("git://server/sub.git", generator.getConfigUrl()); - try (Repository subModRepository1 = generator.getRepository()) { - StoredConfig submoduleConfig = subModRepository1.getConfig(); - assertEquals("git://server/sub.git", - submoduleConfig.getString( - ConfigConstants.CONFIG_REMOTE_SECTION, - Constants.DEFAULT_REMOTE_NAME, - ConfigConstants.CONFIG_KEY_URL)); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + assertEquals("git://server/sub.git", generator.getConfigUrl()); + try (Repository subModRepository1 = generator.getRepository()) { + StoredConfig submoduleConfig = subModRepository1.getConfig(); + assertEquals("git://server/sub.git", + submoduleConfig.getString( + ConfigConstants.CONFIG_REMOTE_SECTION, + Constants.DEFAULT_REMOTE_NAME, + ConfigConstants.CONFIG_KEY_URL)); + } } } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java index bbce413ef3..6f358b47fd 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleUpdateTest.java @@ -119,11 +119,12 @@ public class SubmoduleUpdateTest extends RepositoryTestCase { assertEquals(1, updated.size()); assertEquals(path, updated.iterator().next()); - SubmoduleWalk generator = SubmoduleWalk.forIndex(db); - assertTrue(generator.next()); - try (Repository subRepo = generator.getRepository()) { - assertNotNull(subRepo); - assertEquals(commit, subRepo.resolve(Constants.HEAD)); + try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) { + assertTrue(generator.next()); + try (Repository subRepo = generator.getRepository()) { + assertNotNull(subRepo); + assertEquals(commit, subRepo.resolve(Constants.HEAD)); + } } } @@ -181,10 +182,11 @@ public class SubmoduleUpdateTest extends RepositoryTestCase { }); editor.commit(); - Repository subRepo = Git.init().setBare(false) + try (Repository subRepo = Git.init().setBare(false) .setDirectory(new File(db.getWorkTree(), path)).call() - .getRepository(); - assertNotNull(subRepo); + .getRepository()) { + assertNotNull(subRepo); + } SubmoduleUpdateCommand command = new SubmoduleUpdateCommand(db); Collection<String> updated = command.call(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java index ea1ace364e..0b6047f881 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java @@ -98,10 +98,11 @@ public class SubmoduleWalkTest extends RepositoryTestCase { @Test public void repositoryWithNoSubmodules() throws IOException { - SubmoduleWalk gen = SubmoduleWalk.forIndex(db); - assertFalse(gen.next()); - assertNull(gen.getPath()); - assertEquals(ObjectId.zeroId(), gen.getObjectId()); + try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) { + assertFalse(gen.next()); + assertNull(gen.getPath()); + assertEquals(ObjectId.zeroId(), gen.getObjectId()); + } } @Test @@ -129,20 +130,21 @@ public class SubmoduleWalkTest extends RepositoryTestCase { }); editor.commit(); - SubmoduleWalk gen = SubmoduleWalk.forIndex(db); - assertTrue(gen.next()); - assertEquals(path, gen.getPath()); - assertEquals(id, gen.getObjectId()); - assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); - assertNull(gen.getConfigUpdate()); - assertNull(gen.getConfigUrl()); - assertNull(gen.getModulesPath()); - assertNull(gen.getModulesUpdate()); - assertNull(gen.getModulesUrl()); - assertNull(gen.getRepository()); + try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) { + assertTrue(gen.next()); + assertEquals(path, gen.getPath()); + assertEquals(id, gen.getObjectId()); + assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); + assertNull(gen.getConfigUpdate()); + assertNull(gen.getConfigUrl()); + assertNull(gen.getModulesPath()); + assertNull(gen.getModulesUpdate()); + assertNull(gen.getModulesUrl()); + assertNull(gen.getRepository()); + assertFalse(gen.next()); + } Status status = Git.wrap(db).status().call(); - assertTrue(!status.isClean()); - assertFalse(gen.next()); + assertFalse(status.isClean()); } @Test @@ -178,24 +180,25 @@ public class SubmoduleWalkTest extends RepositoryTestCase { }); editor.commit(); - SubmoduleWalk gen = SubmoduleWalk.forIndex(db); - assertTrue(gen.next()); - assertEquals(path, gen.getPath()); - assertEquals(id, gen.getObjectId()); - assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); - assertNull(gen.getConfigUpdate()); - assertNull(gen.getConfigUrl()); - assertNull(gen.getModulesPath()); - assertNull(gen.getModulesUpdate()); - assertNull(gen.getModulesUrl()); - try (Repository subRepo = gen.getRepository()) { - assertNotNull(subRepo); - assertEquals(modulesGitDir.getAbsolutePath(), - subRepo.getDirectory().getAbsolutePath()); - assertEquals(new File(db.getWorkTree(), path).getAbsolutePath(), - subRepo.getWorkTree().getAbsolutePath()); + try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) { + assertTrue(gen.next()); + assertEquals(path, gen.getPath()); + assertEquals(id, gen.getObjectId()); + assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); + assertNull(gen.getConfigUpdate()); + assertNull(gen.getConfigUrl()); + assertNull(gen.getModulesPath()); + assertNull(gen.getModulesUpdate()); + assertNull(gen.getModulesUrl()); + try (Repository subRepo = gen.getRepository()) { + assertNotNull(subRepo); + assertEquals(modulesGitDir.getAbsolutePath(), + subRepo.getDirectory().getAbsolutePath()); + assertEquals(new File(db.getWorkTree(), path).getAbsolutePath(), + subRepo.getWorkTree().getAbsolutePath()); + } + assertFalse(gen.next()); } - assertFalse(gen.next()); } @Test @@ -232,23 +235,24 @@ public class SubmoduleWalkTest extends RepositoryTestCase { }); editor.commit(); - SubmoduleWalk gen = SubmoduleWalk.forIndex(db); - assertTrue(gen.next()); - assertEquals(path, gen.getPath()); - assertEquals(id, gen.getObjectId()); - assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); - assertNull(gen.getConfigUpdate()); - assertNull(gen.getConfigUrl()); - assertNull(gen.getModulesPath()); - assertNull(gen.getModulesUpdate()); - assertNull(gen.getModulesUrl()); - try (Repository subRepo = gen.getRepository()) { - assertNotNull(subRepo); - assertEqualsFile(modulesGitDir, subRepo.getDirectory()); - assertEqualsFile(new File(db.getWorkTree(), path), - subRepo.getWorkTree()); - subRepo.close(); - assertFalse(gen.next()); + try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) { + assertTrue(gen.next()); + assertEquals(path, gen.getPath()); + assertEquals(id, gen.getObjectId()); + assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); + assertNull(gen.getConfigUpdate()); + assertNull(gen.getConfigUrl()); + assertNull(gen.getModulesPath()); + assertNull(gen.getModulesUpdate()); + assertNull(gen.getModulesUrl()); + try (Repository subRepo = gen.getRepository()) { + assertNotNull(subRepo); + assertEqualsFile(modulesGitDir, subRepo.getDirectory()); + assertEqualsFile(new File(db.getWorkTree(), path), + subRepo.getWorkTree()); + subRepo.close(); + assertFalse(gen.next()); + } } } @@ -270,18 +274,19 @@ public class SubmoduleWalkTest extends RepositoryTestCase { }); editor.commit(); - SubmoduleWalk gen = SubmoduleWalk.forIndex(db); - assertTrue(gen.next()); - assertEquals(path, gen.getPath()); - assertEquals(id, gen.getObjectId()); - assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); - assertNull(gen.getConfigUpdate()); - assertNull(gen.getConfigUrl()); - assertNull(gen.getModulesPath()); - assertNull(gen.getModulesUpdate()); - assertNull(gen.getModulesUrl()); - assertNull(gen.getRepository()); - assertFalse(gen.next()); + try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) { + assertTrue(gen.next()); + assertEquals(path, gen.getPath()); + assertEquals(id, gen.getObjectId()); + assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); + assertNull(gen.getConfigUpdate()); + assertNull(gen.getConfigUrl()); + assertNull(gen.getModulesPath()); + assertNull(gen.getModulesUpdate()); + assertNull(gen.getModulesUrl()); + assertNull(gen.getRepository()); + assertFalse(gen.next()); + } } @Test @@ -312,12 +317,13 @@ public class SubmoduleWalkTest extends RepositoryTestCase { }); editor.commit(); - SubmoduleWalk gen = SubmoduleWalk.forIndex(db); - gen.setFilter(PathFilter.create(path1)); - assertTrue(gen.next()); - assertEquals(path1, gen.getPath()); - assertEquals(id1, gen.getObjectId()); - assertFalse(gen.next()); + try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) { + gen.setFilter(PathFilter.create(path1)); + assertTrue(gen.next()); + assertEquals(path1, gen.getPath()); + assertEquals(id1, gen.getObjectId()); + assertFalse(gen.next()); + } } @Test @@ -358,18 +364,19 @@ public class SubmoduleWalkTest extends RepositoryTestCase { }); editor.commit(); - SubmoduleWalk gen = SubmoduleWalk.forIndex(db); - assertTrue(gen.next()); - assertEquals(path, gen.getPath()); - assertEquals(subId, gen.getObjectId()); - assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); - assertNull(gen.getConfigUpdate()); - assertNull(gen.getConfigUrl()); - assertEquals("sub", gen.getModulesPath()); - assertNull(gen.getModulesUpdate()); - assertEquals("git://example.com/sub", gen.getModulesUrl()); - assertNull(gen.getRepository()); - assertFalse(gen.next()); + try (SubmoduleWalk gen = SubmoduleWalk.forIndex(db)) { + assertTrue(gen.next()); + assertEquals(path, gen.getPath()); + assertEquals(subId, gen.getObjectId()); + assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); + assertNull(gen.getConfigUpdate()); + assertNull(gen.getConfigUrl()); + assertEquals("sub", gen.getModulesPath()); + assertNull(gen.getModulesUpdate()); + assertEquals("git://example.com/sub", gen.getModulesUrl()); + assertNull(gen.getRepository()); + assertFalse(gen.next()); + } } @Test @@ -397,17 +404,19 @@ public class SubmoduleWalkTest extends RepositoryTestCase { }) .create()); - SubmoduleWalk gen = SubmoduleWalk.forPath(db, commit.getTree(), "sub"); - assertEquals(path, gen.getPath()); - assertEquals(subId, gen.getObjectId()); - assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); - assertNull(gen.getConfigUpdate()); - assertNull(gen.getConfigUrl()); - assertEquals("sub", gen.getModulesPath()); - assertNull(gen.getModulesUpdate()); - assertEquals("git://example.com/sub", gen.getModulesUrl()); - assertNull(gen.getRepository()); - assertFalse(gen.next()); + try (SubmoduleWalk gen = SubmoduleWalk.forPath(db, commit.getTree(), + "sub")) { + assertEquals(path, gen.getPath()); + assertEquals(subId, gen.getObjectId()); + assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); + assertNull(gen.getConfigUpdate()); + assertNull(gen.getConfigUrl()); + assertEquals("sub", gen.getModulesPath()); + assertNull(gen.getModulesUpdate()); + assertEquals("git://example.com/sub", gen.getModulesUrl()); + assertNull(gen.getRepository()); + assertFalse(gen.next()); + } } @Test @@ -437,17 +446,18 @@ public class SubmoduleWalkTest extends RepositoryTestCase { final CanonicalTreeParser p = new CanonicalTreeParser(); p.reset(testDb.getRevWalk().getObjectReader(), commit.getTree()); - SubmoduleWalk gen = SubmoduleWalk.forPath(db, p, "sub"); - assertEquals(path, gen.getPath()); - assertEquals(subId, gen.getObjectId()); - assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); - assertNull(gen.getConfigUpdate()); - assertNull(gen.getConfigUrl()); - assertEquals("sub", gen.getModulesPath()); - assertNull(gen.getModulesUpdate()); - assertEquals("git://example.com/sub", gen.getModulesUrl()); - assertNull(gen.getRepository()); - assertFalse(gen.next()); + try (SubmoduleWalk gen = SubmoduleWalk.forPath(db, p, "sub")) { + assertEquals(path, gen.getPath()); + assertEquals(subId, gen.getObjectId()); + assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); + assertNull(gen.getConfigUpdate()); + assertNull(gen.getConfigUrl()); + assertEquals("sub", gen.getModulesPath()); + assertNull(gen.getModulesUpdate()); + assertEquals("git://example.com/sub", gen.getModulesUrl()); + assertNull(gen.getRepository()); + assertFalse(gen.next()); + } } @Test @@ -477,16 +487,17 @@ public class SubmoduleWalkTest extends RepositoryTestCase { final CanonicalTreeParser p = new CanonicalTreeParser(); p.reset(testDb.getRevWalk().getObjectReader(), commit.getTree()); - SubmoduleWalk gen = SubmoduleWalk.forPath(db, p, "sub"); - assertEquals(path, gen.getPath()); - assertEquals(subId, gen.getObjectId()); - assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); - assertNull(gen.getConfigUpdate()); - assertNull(gen.getConfigUrl()); - assertEquals("sub", gen.getModulesPath()); - assertNull(gen.getModulesUpdate()); - assertEquals("git://example.com/sub", gen.getModulesUrl()); - assertNull(gen.getRepository()); - assertFalse(gen.next()); + try (SubmoduleWalk gen = SubmoduleWalk.forPath(db, p, "sub")) { + assertEquals(path, gen.getPath()); + assertEquals(subId, gen.getObjectId()); + assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); + assertNull(gen.getConfigUpdate()); + assertNull(gen.getConfigUrl()); + assertEquals("sub", gen.getModulesPath()); + assertNull(gen.getModulesUpdate()); + assertEquals("git://example.com/sub", gen.getModulesUrl()); + assertNull(gen.getRepository()); + assertFalse(gen.next()); + } } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java index c1e078d10d..d6c7a6199d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/AtomicPushTest.java @@ -55,10 +55,9 @@ import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; -import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.resolver.ReceivePackFactory; import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; @@ -73,8 +72,8 @@ public class AtomicPushTest { private Object ctx = new Object(); private InMemoryRepository server; private InMemoryRepository client; - private ObjectId obj1; - private ObjectId obj2; + private ObjectId commit1; + private ObjectId commit2; @Before public void setUp() throws Exception { @@ -92,10 +91,11 @@ public class AtomicPushTest { }); uri = testProtocol.register(ctx, server); - try (ObjectInserter ins = client.newObjectInserter()) { - obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test")); - obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file")); - ins.flush(); + try (TestRepository<?> clientRepo = new TestRepository<>(client)) { + commit1 = clientRepo.commit().noFiles().message("test commit 1") + .create(); + commit2 = clientRepo.commit().noFiles().message("test commit 2") + .create(); } } @@ -149,13 +149,13 @@ public class AtomicPushTest { List<RemoteRefUpdate> cmds = new ArrayList<>(); cmds.add(new RemoteRefUpdate( null, null, - obj1, "refs/heads/one", + commit1, "refs/heads/one", true /* force update */, null /* no local tracking ref */, ObjectId.zeroId())); cmds.add(new RemoteRefUpdate( null, null, - obj2, "refs/heads/two", + commit2, "refs/heads/two", true /* force update */, null /* no local tracking ref */, ObjectId.zeroId())); @@ -176,16 +176,16 @@ public class AtomicPushTest { List<RemoteRefUpdate> cmds = new ArrayList<>(); cmds.add(new RemoteRefUpdate( null, null, - obj1, "refs/heads/one", + commit1, "refs/heads/one", true /* force update */, null /* no local tracking ref */, ObjectId.zeroId())); cmds.add(new RemoteRefUpdate( null, null, - obj2, "refs/heads/two", + commit2, "refs/heads/two", true /* force update */, null /* no local tracking ref */, - obj1)); + commit1)); return cmds; } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java index ea15ebe7de..947ca97615 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/HttpAuthTest.java @@ -133,16 +133,15 @@ public class HttpAuthTest { @Override public String getHeaderField(String name) { - if (!headerFields.containsKey(name)) + if (!headerFields.containsKey(name)) { return null; - else { - int n = headerFields.get(name).size(); + } + int n = headerFields.get(name).size(); - if (n > 0) - return headerFields.get(name).get(n - 1); - else - return null; + if (n > 0) { + return headerFields.get(name).get(n - 1); } + return null; } @Override diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateParserTest.java index 4bf26b6288..5db4563ba6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateParserTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushCertificateParserTest.java @@ -145,7 +145,7 @@ public class PushCertificateParserTest { ObjectId newId = ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); String line = oldId.name() + " " + newId.name() + " refs/heads/master"; - ReceiveCommand cmd = BaseReceivePack.parseCommand(line); + ReceiveCommand cmd = ReceivePack.parseCommand(line); parser.addCommand(cmd); parser.addCommand(line); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushOptionsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushOptionsTest.java index fd1c3bf8b8..18946e0d50 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushOptionsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushOptionsTest.java @@ -62,10 +62,9 @@ import org.eclipse.jgit.api.errors.TransportException; import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; import org.eclipse.jgit.junit.RepositoryTestCase; -import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.revwalk.RevCommit; @@ -79,8 +78,8 @@ public class PushOptionsTest extends RepositoryTestCase { private Object ctx = new Object(); private InMemoryRepository server; private InMemoryRepository client; - private ObjectId obj1; - private ObjectId obj2; + private ObjectId commit1; + private ObjectId commit2; private ReceivePack receivePack; @Override @@ -101,10 +100,11 @@ public class PushOptionsTest extends RepositoryTestCase { uri = testProtocol.register(ctx, server); - try (ObjectInserter ins = client.newObjectInserter()) { - obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test")); - obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file")); - ins.flush(); + try (TestRepository<?> clientRepo = new TestRepository<>(client)) { + commit1 = clientRepo.commit().noFiles().message("test commit 1") + .create(); + commit2 = clientRepo.commit().noFiles().message("test commit 2") + .create(); } } @@ -121,12 +121,12 @@ public class PushOptionsTest extends RepositoryTestCase { private List<RemoteRefUpdate> commands(boolean atomicSafe) throws IOException { List<RemoteRefUpdate> cmds = new ArrayList<>(); - cmds.add(new RemoteRefUpdate(null, null, obj1, "refs/heads/one", + cmds.add(new RemoteRefUpdate(null, null, commit1, "refs/heads/one", true /* force update */, null /* no local tracking ref */, ObjectId.zeroId())); - cmds.add(new RemoteRefUpdate(null, null, obj2, "refs/heads/two", + cmds.add(new RemoteRefUpdate(null, null, commit2, "refs/heads/two", true /* force update */, null /* no local tracking ref */, - atomicSafe ? ObjectId.zeroId() : obj1)); + atomicSafe ? ObjectId.zeroId() : commit1)); return cmds; } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReachableCommitRequestValidatorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReachableCommitRequestValidatorTest.java new file mode 100644 index 0000000000..20b490b263 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReachableCommitRequestValidatorTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2019, Google LLC. + * 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 org.eclipse.jgit.transport.UploadPack.RequestValidator; + +/** + * Client may ask for any commit reachable from a reference advertised by + * the server. + */ +public class ReachableCommitRequestValidatorTest extends RequestValidatorTestCase { + + @Override + protected RequestValidator createValidator() { + return new UploadPack.ReachableCommitRequestValidator(); + } + + @Override + protected boolean isReachableCommitValid() { + return true; + } + + @Override + protected boolean isUnreachableCommitValid() { + return false; + } + + @Override + protected boolean isReachableBlobValid_withBitmaps() { + return true; + } + + @Override + protected boolean isReachableBlobValid_withoutBitmaps() { + return false; + } + + @Override + protected boolean isUnreachableBlobValid() { + return false; + } + + @Override + protected boolean isAdvertisedTipValid() { + return true; + } + + @Override + protected boolean isUnadvertisedTipCommitValid() { + return false; + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReachableCommitTipRequestValidatorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReachableCommitTipRequestValidatorTest.java new file mode 100644 index 0000000000..5e5391dac7 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReachableCommitTipRequestValidatorTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019, Google LLC. + * 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 org.eclipse.jgit.transport.UploadPack.RequestValidator; + +/** + * Client may ask for any commit reachable from any reference, even if that + * reference wasn't advertised. + */ +public class ReachableCommitTipRequestValidatorTest + extends RequestValidatorTestCase { + + @Override + protected RequestValidator createValidator() { + return new UploadPack.ReachableCommitTipRequestValidator(); + } + + @Override + protected boolean isReachableCommitValid() { + return true; + } + + @Override + protected boolean isUnreachableCommitValid() { + return false; + } + + @Override + protected boolean isAdvertisedTipValid() { + return true; + } + + @Override + protected boolean isReachableBlobValid_withBitmaps() { + return true; + } + + @Override + protected boolean isReachableBlobValid_withoutBitmaps() { + return false; + } + + @Override + protected boolean isUnreachableBlobValid() { + return false; + } + + @Override + protected boolean isUnadvertisedTipCommitValid() { + return true; + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java index 5d208eea73..89ac2fe96d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java @@ -174,7 +174,7 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas ReceivePack rp = super.createReceivePack(dst); rp.setAdvertiseRefsHook(new AdvertiseRefsHook() { @Override - public void advertiseRefs(BaseReceivePack rp2) + public void advertiseRefs(ReceivePack rp2) throws ServiceMayNotContinueException { rp.setAdvertisedRefs(rp.getRepository().getAllRefs(), null); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BaseReceivePackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackTest.java index 7578c6e3eb..156746d79f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BaseReceivePackTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackTest.java @@ -49,14 +49,14 @@ import org.eclipse.jgit.errors.PackProtocolException; import org.eclipse.jgit.lib.ObjectId; import org.junit.Test; -/** Tests for base receive-pack utilities. */ -public class BaseReceivePackTest { +/** Tests for receive-pack utilities. */ +public class ReceivePackTest { @Test public void parseCommand() throws Exception { String o = "0000000000000000000000000000000000000000"; String n = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; String r = "refs/heads/master"; - ReceiveCommand cmd = BaseReceivePack.parseCommand(o + " " + n + " " + r); + ReceiveCommand cmd = ReceivePack.parseCommand(o + " " + n + " " + r); assertEquals(ObjectId.zeroId(), cmd.getOldId()); assertEquals("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef", cmd.getNewId().name()); @@ -76,7 +76,7 @@ public class BaseReceivePackTest { private void assertParseCommandFails(String input) { try { - BaseReceivePack.parseCommand(input); + ReceivePack.parseCommand(input); fail(); } catch (PackProtocolException e) { // Expected. diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RequestValidatorTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RequestValidatorTestCase.java new file mode 100644 index 0000000000..c1e7bcfcbe --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RequestValidatorTestCase.java @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2019, Google LLC. + * 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 java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jgit.errors.PackProtocolException; +import org.eclipse.jgit.errors.TransportException; +import org.eclipse.jgit.internal.storage.dfs.DfsGarbageCollector; +import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; +import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevBlob; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.transport.UploadPack.RequestValidator; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public abstract class RequestValidatorTestCase { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private RevCommit reachableCommit; + + private RevCommit tipAdvertisedCommit; + + private RevCommit tipUnadvertisedCommit; + + private RevCommit unreachableCommit; + + private RevBlob reachableBlob; + + private RevBlob unreachableBlob; + + private InMemoryRepository repo; + + protected abstract RequestValidator createValidator(); + + @Before + public void setUp() throws Exception { + repo = new InMemoryRepository(new DfsRepositoryDescription()); + try (TestRepository<InMemoryRepository> git = new TestRepository<>( + repo)) { + reachableBlob = git.blob("foo"); + reachableCommit = git + .commit(git.tree(git.file("foo", reachableBlob))); + tipAdvertisedCommit = git.commit(reachableCommit); + git.update("advertised", tipAdvertisedCommit); + + tipUnadvertisedCommit = git.commit(reachableCommit); + git.update("unadvertised", tipUnadvertisedCommit); + + unreachableBlob = git.blob("unreachableFoo"); + unreachableCommit = git + .commit(git.tree(git.file("foo", unreachableBlob))); + } + } + + /** + * @return true if a commit reachable from a visible tip (but not directly + * the tip) is valid + */ + protected abstract boolean isReachableCommitValid(); + + /** @return true if a commit not reachable from any tip is valid */ + protected abstract boolean isUnreachableCommitValid(); + + /** + * @return true if the commit directly pointed by an advertised ref is valid + */ + protected abstract boolean isAdvertisedTipValid(); + + /** + * @return true if the object directly pointed by a non-advertised ref is + * valid + */ + protected abstract boolean isUnadvertisedTipCommitValid(); + + // UploadPack doesn't allow to ask for blobs when there is no + // bitmap. Test both cases separately. + /** + * @return true if a reachable blob is valid (and the repo has bitmaps) + */ + protected abstract boolean isReachableBlobValid_withBitmaps(); + + /** + * @return true if a reachable blob is valid (and the repo does NOT have + * bitmaps) + */ + protected abstract boolean isReachableBlobValid_withoutBitmaps(); + + /** + * @return true if a blob unreachable from any tip is valid + */ + protected abstract boolean isUnreachableBlobValid(); + + @Test + public void validateReachableCommitWithBitmaps() + throws PackProtocolException, IOException { + if (!isReachableCommitValid()) { + thrown.expect(TransportException.class); + thrown.expectMessage(Matchers + .containsString( + "want " + reachableCommit.name() + " not valid")); + + } + createValidator().checkWants(getUploadPack(getRepoWithBitmaps()), + Arrays.asList(reachableCommit)); + } + + @Test + public void validateReachableCommitWithoutBitmaps() + throws PackProtocolException, IOException { + if (!isReachableCommitValid()) { + thrown.expect(TransportException.class); + thrown.expectMessage(Matchers.containsString( + "want " + reachableCommit.name() + " not valid")); + + } + createValidator().checkWants(getUploadPack(getRepoWithoutBitmaps()), + Arrays.asList(reachableCommit)); + } + + @Test + public void validateAdvertisedTipWithBitmaps() + throws PackProtocolException, IOException { + if (!isAdvertisedTipValid()) { + thrown.expect(TransportException.class); + thrown.expectMessage(Matchers.containsString( + "want " + tipAdvertisedCommit.name() + " not valid")); + + } + createValidator().checkWants(getUploadPack(getRepoWithBitmaps()), + Arrays.asList(tipAdvertisedCommit)); + } + + @Test + public void validateAdvertisedTipWithoutBitmaps() + throws PackProtocolException, IOException { + if (!isAdvertisedTipValid()) { + thrown.expect(TransportException.class); + thrown.expectMessage(Matchers.containsString( + "want " + tipAdvertisedCommit.name() + " not valid")); + + } + createValidator().checkWants(getUploadPack(getRepoWithoutBitmaps()), + Arrays.asList(tipAdvertisedCommit)); + } + + @Test + public void validateUnadvertisedTipWithBitmaps() + throws PackProtocolException, IOException { + if (!isUnadvertisedTipCommitValid()) { + thrown.expect(TransportException.class); + thrown.expectMessage(Matchers.containsString( + "want " + tipUnadvertisedCommit.name() + " not valid")); + + } + createValidator().checkWants(getUploadPack(getRepoWithBitmaps()), + Arrays.asList(tipUnadvertisedCommit)); + } + + @Test + public void validateUnadvertisedTipWithoutBitmaps() + throws PackProtocolException, IOException { + if (!isUnadvertisedTipCommitValid()) { + thrown.expect(TransportException.class); + thrown.expectMessage(Matchers.containsString( + "want " + tipUnadvertisedCommit.name() + " not valid")); + + } + createValidator().checkWants(getUploadPack(getRepoWithoutBitmaps()), + Arrays.asList(tipUnadvertisedCommit)); + } + + @Test + public void validateUnreachableCommitWithBitmaps() + throws PackProtocolException, IOException { + if (!isUnreachableCommitValid()) { + thrown.expect(TransportException.class); + thrown.expectMessage(Matchers.containsString( + "want " + unreachableCommit.name() + " not valid")); + + } + createValidator().checkWants(getUploadPack(getRepoWithBitmaps()), + Arrays.asList(unreachableCommit)); + } + + @Test + public void validateUnreachableCommitWithoutBitmaps() + throws PackProtocolException, IOException { + if (!isUnreachableCommitValid()) { + thrown.expect(TransportException.class); + thrown.expectMessage(Matchers.containsString( + "want " + unreachableCommit.name() + " not valid")); + + } + createValidator().checkWants(getUploadPack(getRepoWithoutBitmaps()), + Arrays.asList(unreachableCommit)); + } + + @Test + public void validateReachableBlobWithBitmaps() + throws PackProtocolException, IOException { + if (!isReachableBlobValid_withBitmaps()) { + thrown.expect(TransportException.class); + thrown.expectMessage(Matchers.containsString( + "want " + reachableBlob.name() + " not valid")); + } + createValidator().checkWants(getUploadPack(getRepoWithBitmaps()), + Arrays.asList(reachableBlob)); + } + + @Test + public void validateReachableBlobWithoutBitmaps() + throws PackProtocolException, IOException { + if (!isReachableBlobValid_withoutBitmaps()) { + thrown.expect(TransportException.class); + thrown.expectMessage(Matchers.containsString( + "want " + reachableBlob.name() + " not valid")); + } + createValidator().checkWants(getUploadPack(getRepoWithoutBitmaps()), + Arrays.asList(reachableBlob)); + } + + @Test + public void validateUnreachableBlobWithBitmaps() + throws PackProtocolException, IOException { + if (!isUnreachableBlobValid()) { + thrown.expect(TransportException.class); + thrown.expectMessage(Matchers.containsString( + "want " + unreachableBlob.name() + " not valid")); + } + createValidator().checkWants(getUploadPack(getRepoWithBitmaps()), + Arrays.asList(unreachableBlob)); + } + + @Test + public void validateUnreachableBlobWithoutBitmaps() + throws PackProtocolException, IOException { + if (!isUnreachableBlobValid()) { + thrown.expect(TransportException.class); + thrown.expectMessage(Matchers.containsString( + "want " + unreachableBlob.name() + " not valid")); + } + createValidator().checkWants(getUploadPack(getRepoWithoutBitmaps()), + Arrays.asList(unreachableBlob)); + } + + private UploadPack getUploadPack(Repository repository) throws IOException { + UploadPack uploadPack = new UploadPack(repository); + + Ref advertisedRef = repo.getRefDatabase().findRef("advertised"); + Map<String, Ref> advertisedRefs = new HashMap<>(); + advertisedRefs.put(advertisedRef.getName(), advertisedRef); + + uploadPack.setAdvertisedRefs(advertisedRefs); + return uploadPack; + } + + private Repository getRepoWithBitmaps() throws IOException { + new DfsGarbageCollector(repo).pack(null); + repo.scanForRepoChanges(); + return repo; + } + + private Repository getRepoWithoutBitmaps() { + return repo; + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TipRequestValidatorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TipRequestValidatorTest.java new file mode 100644 index 0000000000..565d0e6e95 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TipRequestValidatorTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2019, Google LLC. + * 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 org.eclipse.jgit.transport.UploadPack.RequestValidator; + +/** + * Client may ask for objects that are the tip of any reference, even if not + * advertised. + */ +public class TipRequestValidatorTest extends RequestValidatorTestCase { + + @Override + protected RequestValidator createValidator() { + return new UploadPack.TipRequestValidator(); + } + + @Override + protected boolean isReachableCommitValid() { + return false; + } + + @Override + protected boolean isUnreachableCommitValid() { + return false; + } + + @Override + protected boolean isReachableBlobValid_withBitmaps() { + return false; + } + + @Override + protected boolean isReachableBlobValid_withoutBitmaps() { + return false; + } + + @Override + protected boolean isUnreachableBlobValid() { + return false; + } + + @Override + protected boolean isAdvertisedTipValid() { + return true; + } + + @Override + protected boolean isUnadvertisedTipCommitValid() { + return true; + } + +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackReachabilityTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackReachabilityTest.java new file mode 100644 index 0000000000..7122082d81 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackReachabilityTest.java @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2019, Google LLC. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.transport; + +import static org.eclipse.jgit.lib.MoreAsserts.assertThrows; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Collections; + +import org.eclipse.jgit.errors.TransportException; +import org.eclipse.jgit.internal.storage.dfs.DfsGarbageCollector; +import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; +import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevBlob; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.transport.UploadPack.RequestPolicy; +import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; +import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; +import org.eclipse.jgit.transport.resolver.UploadPackFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +/** + * Test combinations of: + * <ul> + * <li>Fetch a blob or a commit</li> + * <li>Fetched object is reachable or not</li> + * <li>With and without bitmaps</li> + * </ul> + */ +public class UploadPackReachabilityTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private URIish uri; + + private TestProtocol<Object> testProtocol; + + private Object ctx = new Object(); + + private InMemoryRepository server; + + private InMemoryRepository client; + + private TestRepository<InMemoryRepository> remote; + + @Before + public void setUp() throws Exception { + server = newRepo("server"); + client = newRepo("client"); + + remote = new TestRepository<>(server); + } + + @After + public void tearDown() { + Transport.unregister(testProtocol); + } + + @Test + public void testFetchUnreachableBlobWithBitmap() throws Exception { + RevBlob blob = remote.blob("foo"); + remote.commit(remote.tree(remote.file("foo", blob))); + generateBitmaps(server); + + testProtocol = generateReachableCommitUploadPackProtocol(); + uri = testProtocol.register(ctx, server); + + assertFalse(client.getObjectDatabase().has(blob.toObjectId())); + + try (Transport tn = testProtocol.open(uri, client, "server")) { + TransportException e = assertThrows(TransportException.class, + () -> tn.fetch(NullProgressMonitor.INSTANCE, Collections + .singletonList(new RefSpec(blob.name())))); + assertThat(e.getMessage(), + containsString("want " + blob.name() + " not valid")); + } + } + + @Test + public void testFetchReachableBlobWithoutBitmap() throws Exception { + RevBlob blob = remote.blob("foo"); + RevCommit commit = remote.commit(remote.tree(remote.file("foo", blob))); + remote.update("master", commit); + + testProtocol = generateReachableCommitUploadPackProtocol(); + uri = testProtocol.register(ctx, server); + + assertFalse(client.getObjectDatabase().has(blob.toObjectId())); + + try (Transport tn = testProtocol.open(uri, client, "server")) { + TransportException e = assertThrows(TransportException.class, + () -> tn.fetch(NullProgressMonitor.INSTANCE, Collections + .singletonList(new RefSpec(blob.name())))); + assertThat(e.getMessage(), + containsString( + "want " + blob.name() + " not valid")); + } + } + + @Test + public void testFetchReachableBlobWithoutBitmapButFilterAllowed() throws Exception { + InMemoryRepository server2 = newRepo("server2"); + try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>( + server2)) { + RevBlob blob = remote2.blob("foo"); + RevCommit commit = remote2.commit(remote2.tree(remote2.file("foo", blob))); + remote2.update("master", commit); + + server2.getConfig().setBoolean("uploadpack", null, "allowfilter", + true); + + testProtocol = new TestProtocol<>((Object req, Repository db) -> { + UploadPack up = new UploadPack(db); + up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT); + return up; + }, null); + uri = testProtocol.register(ctx, server2); + + assertFalse(client.getObjectDatabase().has(blob.toObjectId())); + + try (Transport tn = testProtocol.open(uri, client, "server2")) { + tn.fetch(NullProgressMonitor.INSTANCE, + Collections.singletonList(new RefSpec(blob.name()))); + assertTrue(client.getObjectDatabase().has(blob.toObjectId())); + } + } + } + + @Test + public void testFetchUnreachableBlobWithoutBitmap() throws Exception { + RevBlob blob = remote.blob("foo"); + remote.commit(remote.tree(remote.file("foo", blob))); + + testProtocol = generateReachableCommitUploadPackProtocol(); + uri = testProtocol.register(ctx, server); + + assertFalse(client.getObjectDatabase().has(blob.toObjectId())); + + try (Transport tn = testProtocol.open(uri, client, "server")) { + TransportException e = assertThrows(TransportException.class, () -> + tn.fetch(NullProgressMonitor.INSTANCE, + Collections.singletonList(new RefSpec(blob.name())))); + assertThat(e.getMessage(), + containsString("want " + blob.name() + " not valid")); + } + } + + @Test + public void testFetchReachableBlobWithBitmap() throws Exception { + RevBlob blob = remote.blob("foo"); + RevCommit commit = remote.commit(remote.tree(remote.file("foo", blob))); + remote.update("master", commit); + generateBitmaps(server); + + testProtocol = generateReachableCommitUploadPackProtocol(); + uri = testProtocol.register(ctx, server); + + assertFalse(client.getObjectDatabase().has(blob.toObjectId())); + + try (Transport tn = testProtocol.open(uri, client, "server")) { + tn.fetch(NullProgressMonitor.INSTANCE, + Collections.singletonList(new RefSpec(blob.name()))); + assertTrue(client.getObjectDatabase().has(blob.toObjectId())); + } + } + + @Test + public void testFetchReachableCommitWithBitmap() throws Exception { + RevCommit commit = remote + .commit(remote.tree(remote.file("foo", remote.blob("foo")))); + remote.update("master", commit); + generateBitmaps(server); + + testProtocol = generateReachableCommitUploadPackProtocol(); + uri = testProtocol.register(ctx, server); + + assertFalse(client.getObjectDatabase().has(commit.toObjectId())); + + try (Transport tn = testProtocol.open(uri, client, "server")) { + tn.fetch(NullProgressMonitor.INSTANCE, + Collections.singletonList(new RefSpec(commit.name()))); + assertTrue(client.getObjectDatabase().has(commit.toObjectId())); + } + } + + @Test + public void testFetchReachableCommitWithoutBitmap() throws Exception { + RevCommit commit = remote + .commit(remote.tree(remote.file("foo", remote.blob("foo")))); + remote.update("master", commit); + generateBitmaps(server); + + testProtocol = generateReachableCommitUploadPackProtocol(); + uri = testProtocol.register(ctx, server); + + assertFalse(client.getObjectDatabase().has(commit.toObjectId())); + + try (Transport tn = testProtocol.open(uri, client, "server")) { + tn.fetch(NullProgressMonitor.INSTANCE, + Collections.singletonList(new RefSpec(commit.name()))); + assertTrue(client.getObjectDatabase().has(commit.toObjectId())); + } + } + + @Test + public void testFetchUnreachableCommitWithBitmap() throws Exception { + RevCommit commit = remote + .commit(remote.tree(remote.file("foo", remote.blob("foo")))); + generateBitmaps(server); + + testProtocol = generateReachableCommitUploadPackProtocol(); + uri = testProtocol.register(ctx, server); + + assertFalse(client.getObjectDatabase().has(commit.toObjectId())); + + try (Transport tn = testProtocol.open(uri, client, "server")) { + TransportException e = assertThrows(TransportException.class, + () -> tn.fetch(NullProgressMonitor.INSTANCE, + Collections.singletonList(new RefSpec(commit.name())))); + assertThat(e.getMessage(), + containsString("want " + commit.name() + " not valid")); + } + } + + @Test + public void testFetchUnreachableCommitWithoutBitmap() throws Exception { + RevCommit commit = remote + .commit(remote.tree(remote.file("foo", remote.blob("foo")))); + + testProtocol = generateReachableCommitUploadPackProtocol(); + uri = testProtocol.register(ctx, server); + + assertFalse(client.getObjectDatabase().has(commit.toObjectId())); + + try (Transport tn = testProtocol.open(uri, client, "server")) { + TransportException e = assertThrows(TransportException.class, + () -> tn.fetch(NullProgressMonitor.INSTANCE, Collections + .singletonList(new RefSpec(commit.name())))); + assertThat(e.getMessage(), + containsString("want " + commit.name() + " not valid")); + } + } + + private static InMemoryRepository newRepo(String name) { + return new InMemoryRepository(new DfsRepositoryDescription(name)); + } + + private void generateBitmaps(InMemoryRepository repo) throws Exception { + new DfsGarbageCollector(repo).pack(null); + repo.scanForRepoChanges(); + } + + private static TestProtocol<Object> generateReachableCommitUploadPackProtocol() { + return new TestProtocol<>(new UploadPackFactory<Object>() { + @Override + public UploadPack create(Object req, Repository db) + throws ServiceNotEnabledException, + ServiceNotAuthorizedException { + UploadPack up = new UploadPack(db); + up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT); + return up; + } + }, null); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackRefSortingForReachabilityTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackRefSortingForReachabilityTest.java new file mode 100644 index 0000000000..0875a33287 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackRefSortingForReachabilityTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019, Google LLC. + * 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.hamcrest.Matchers.contains; +import static org.junit.Assert.assertThat; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdRef.Unpeeled; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Ref.Storage; +import org.junit.Test; + +public class UploadPackRefSortingForReachabilityTest { + + @Test + public void sortReferences() { + List<Ref> refs = Stream.of("refs/changes/12/12", "refs/changes/12/1", + "refs/heads/master", "refs/heads/something", + "refs/changes/55/1", "refs/tags/v1.1") + .map(s -> new Unpeeled(Storage.LOOSE, s, ObjectId.zeroId())) + .collect(Collectors.toList()); + Stream<Ref> sorted = UploadPack.importantRefsFirst(refs); + List<String> collected = sorted.map(Ref::getName) + .collect(Collectors.toList()); + assertThat(collected, + contains("refs/heads/master", "refs/heads/something", + "refs/tags/v1.1", "refs/changes/12/12", + "refs/changes/12/1", "refs/changes/55/1")); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java index 528a63f9c0..108e5edb78 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java @@ -98,14 +98,6 @@ public class UploadPackTest { repo.scanForRepoChanges(); } - private static TestProtocol<Object> generateReachableCommitUploadPackProtocol() { - return new TestProtocol<>((Object req, Repository db) -> { - UploadPack up = new UploadPack(db); - up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT); - return up; - }, null); - } - @Test public void testFetchParentOfShallowCommit() throws Exception { RevCommit commit0 = remote.commit().message("0").create(); @@ -134,95 +126,6 @@ public class UploadPackTest { } @Test - public void testFetchUnreachableBlobWithBitmap() throws Exception { - RevBlob blob = remote.blob("foo"); - remote.commit(remote.tree(remote.file("foo", blob))); - generateBitmaps(server); - - testProtocol = generateReachableCommitUploadPackProtocol(); - uri = testProtocol.register(ctx, server); - - assertFalse(client.getObjectDatabase().has(blob.toObjectId())); - - try (Transport tn = testProtocol.open(uri, client, "server")) { - TransportException e = assertThrows(TransportException.class, - () -> tn.fetch(NullProgressMonitor.INSTANCE, Collections - .singletonList(new RefSpec(blob.name())))); - assertThat(e.getMessage(), - containsString("want " + blob.name() + " not valid")); - } - } - - @Test - public void testFetchReachableBlobWithBitmap() throws Exception { - RevBlob blob = remote.blob("foo"); - RevCommit commit = remote.commit(remote.tree(remote.file("foo", blob))); - remote.update("master", commit); - generateBitmaps(server); - - testProtocol = generateReachableCommitUploadPackProtocol(); - uri = testProtocol.register(ctx, server); - - assertFalse(client.getObjectDatabase().has(blob.toObjectId())); - - try (Transport tn = testProtocol.open(uri, client, "server")) { - tn.fetch(NullProgressMonitor.INSTANCE, - Collections.singletonList(new RefSpec(blob.name()))); - assertTrue(client.getObjectDatabase().has(blob.toObjectId())); - } - } - - @Test - public void testFetchReachableBlobWithoutBitmap() throws Exception { - RevBlob blob = remote.blob("foo"); - RevCommit commit = remote.commit(remote.tree(remote.file("foo", blob))); - remote.update("master", commit); - - testProtocol = generateReachableCommitUploadPackProtocol(); - uri = testProtocol.register(ctx, server); - - assertFalse(client.getObjectDatabase().has(blob.toObjectId())); - - try (Transport tn = testProtocol.open(uri, client, "server")) { - TransportException e = assertThrows(TransportException.class, - () -> tn.fetch(NullProgressMonitor.INSTANCE, Collections - .singletonList(new RefSpec(blob.name())))); - assertThat(e.getMessage(), - containsString( - "want " + blob.name() + " not valid")); - } - } - - @Test - public void testFetchReachableBlobWithoutBitmapButFilterAllowed() throws Exception { - InMemoryRepository server2 = newRepo("server2"); - try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>( - server2)) { - RevBlob blob = remote2.blob("foo"); - RevCommit commit = remote2.commit(remote2.tree(remote2.file("foo", blob))); - remote2.update("master", commit); - - server2.getConfig().setBoolean("uploadpack", null, "allowfilter", - true); - - testProtocol = new TestProtocol<>((Object req, Repository db) -> { - UploadPack up = new UploadPack(db); - up.setRequestPolicy(RequestPolicy.REACHABLE_COMMIT); - return up; - }, null); - uri = testProtocol.register(ctx, server2); - - assertFalse(client.getObjectDatabase().has(blob.toObjectId())); - - try (Transport tn = testProtocol.open(uri, client, "server2")) { - tn.fetch(NullProgressMonitor.INSTANCE, - Collections.singletonList(new RefSpec(blob.name()))); - assertTrue(client.getObjectDatabase().has(blob.toObjectId())); - } - } - } - - @Test public void testFetchWithBlobNoneFilter() throws Exception { InMemoryRepository server2 = newRepo("server2"); try (TestRepository<InMemoryRepository> remote2 = new TestRepository<>( @@ -559,7 +462,9 @@ public class UploadPackTest { assertThat(lines, containsInAnyOrder("ls-refs", "fetch", "server-option")); } - private void checkUnadvertisedIfUnallowed(String fetchCapability) throws Exception { + private void checkUnadvertisedIfUnallowed(String configSection, + String configName, String fetchCapability) throws Exception { + server.getConfig().setBoolean(configSection, null, configName, false); ByteArrayInputStream recvStream = uploadPackV2Setup(null, PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); @@ -570,9 +475,9 @@ public class UploadPackTest { String line; while (!PacketLineIn.isEnd((line = pckIn.readString()))) { if (line.startsWith("fetch=")) { - assertThat( - Arrays.asList(line.substring(6).split(" ")), - hasItems("shallow")); + List<String> fetchItems = Arrays.asList(line.substring(6).split(" ")); + assertThat(fetchItems, hasItems("shallow")); + assertFalse(fetchItems.contains(fetchCapability)); lines.add("fetch"); } else { lines.add(line); @@ -584,7 +489,7 @@ public class UploadPackTest { @Test public void testV2CapabilitiesAllowFilter() throws Exception { checkAdvertisedIfAllowed("uploadpack", "allowfilter", "filter"); - checkUnadvertisedIfUnallowed("filter"); + checkUnadvertisedIfUnallowed("uploadpack", "allowfilter", "filter"); } @Test @@ -594,13 +499,18 @@ public class UploadPackTest { @Test public void testV2CapabilitiesRefInWantNotAdvertisedIfUnallowed() throws Exception { - checkUnadvertisedIfUnallowed("ref-in-want"); + checkUnadvertisedIfUnallowed("uploadpack", "allowrefinwant", + "ref-in-want"); } @Test - public void testV2CapabilitiesAllowSidebandAll() throws Exception { - checkAdvertisedIfAllowed("uploadpack", "allowsidebandall", "sideband-all"); - checkUnadvertisedIfUnallowed("sideband-all"); + public void testV2CapabilitiesAdvertiseSidebandAll() throws Exception { + server.getConfig().setBoolean("uploadpack", null, "allowsidebandall", + true); + checkAdvertisedIfAllowed("uploadpack", "advertisesidebandall", + "sideband-all"); + checkUnadvertisedIfUnallowed("uploadpack", "advertisesidebandall", + "sideband-all"); } @Test @@ -2112,12 +2022,12 @@ public class UploadPackTest { ByteArrayInputStream recvStream = uploadPackV2( "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "sideband-all\n", "want " + fooChild.toObjectId().getName() + "\n", "want " + barChild.toObjectId().getName() + "\n", "have " + fooParent.toObjectId().getName() + "\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); assertThat(pckIn.readString(), is("\001acknowledgments")); @@ -2133,11 +2043,11 @@ public class UploadPackTest { server.getConfig().setBoolean("uploadpack", null, "allowsidebandall", true); ByteArrayInputStream recvStream = uploadPackV2("command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + commit.getName() + "\n", "sideband-all\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); String s; @@ -2174,18 +2084,18 @@ public class UploadPackTest { assertThat(protocolsSupported, hasItems("https")); if (!protocolsSupported.contains("https")) return null; - return new PackInfo("myhash", "myuri"); + return new PackInfo("myhash", "myuri", 100); } }); }, "command=fetch\n", - PacketLineIn.DELIM, + PacketLineIn.delimiter(), "want " + commit2.getName() + "\n", "sideband-all\n", "packfile-uris https\n", "done\n", - PacketLineIn.END); + PacketLineIn.end()); PacketLineIn pckIn = new PacketLineIn(recvStream); String s; 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 index 4750d15b3d..d1d7a1d81d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/WalkEncryptionTest.java @@ -239,9 +239,8 @@ public class WalkEncryptionTest { loadEnvVar(ENV_SECRET_KEY, SECRET_KEY, props); loadEnvVar(ENV_BUCKET_NAME, TEST_BUCKET, props); return props; - } else { - return null; } + return null; } static Properties fromEnvFile() throws Exception { @@ -250,12 +249,10 @@ public class WalkEncryptionTest { props.load(new FileInputStream(ENV_CONFIG_FILE)); if (checkTestProps(props)) { return props; - } else { - throw new Error("Environment config file is incomplete."); } - } else { - return null; + throw new Error("Environment config file is incomplete."); } + return null; } static Properties fromSysProps() { @@ -266,9 +263,8 @@ public class WalkEncryptionTest { loadSysProp(SYS_SECRET_KEY, SECRET_KEY, props); loadSysProp(SYS_BUCKET_NAME, TEST_BUCKET, props); return props; - } else { - return null; } + return null; } static Properties fromSysFile() throws Exception { @@ -277,12 +273,10 @@ public class WalkEncryptionTest { 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; + throw new Error("System props config file is incomplete."); } + return null; } static Properties fromConfigFile(String path) throws Exception { @@ -292,12 +286,10 @@ public class WalkEncryptionTest { props.load(new FileInputStream(file)); if (checkTestProps(props)) { return props; - } else { - throw new Error("Props config file is incomplete: " + path); } - } else { - return null; + throw new Error("Props config file is incomplete: " + path); } + return null; } /** diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/EmptyTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/EmptyTreeIteratorTest.java index 58aa608ff5..4deb188784 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/EmptyTreeIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/EmptyTreeIteratorTest.java @@ -65,12 +65,13 @@ public class EmptyTreeIteratorTest extends RepositoryTestCase { @Test public void testCreateSubtreeIterator() throws Exception { final EmptyTreeIterator etp = new EmptyTreeIterator(); - final ObjectReader reader = db.newObjectReader(); - final AbstractTreeIterator sub = etp.createSubtreeIterator(reader); - assertNotNull(sub); - assertTrue(sub.first()); - assertTrue(sub.eof()); - assertTrue(sub instanceof EmptyTreeIterator); + try (ObjectReader reader = db.newObjectReader()) { + final AbstractTreeIterator sub = etp.createSubtreeIterator(reader); + assertNotNull(sub); + assertTrue(sub.first()); + assertTrue(sub.eof()); + assertTrue(sub instanceof EmptyTreeIterator); + } } @Test @@ -121,8 +122,9 @@ public class EmptyTreeIteratorTest extends RepositoryTestCase { called[0] = true; } }; - final ObjectReader reader = db.newObjectReader(); - parent.createSubtreeIterator(reader).stopWalk(); + try (ObjectReader reader = db.newObjectReader()) { + parent.createSubtreeIterator(reader).stopWalk(); + } assertTrue(called[0]); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java index a3ce4ae94f..ffa6e5d252 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java @@ -217,29 +217,29 @@ public class FileTreeIteratorTest extends RepositoryTestCase { assertFalse(top.eof()); assertEquals(FileMode.TREE.getBits(), top.mode); - final ObjectReader reader = db.newObjectReader(); - final AbstractTreeIterator sub = top.createSubtreeIterator(reader); - assertTrue(sub instanceof FileTreeIterator); - final FileTreeIterator subfti = (FileTreeIterator) sub; - assertTrue(sub.first()); - assertFalse(sub.eof()); - assertEquals(paths[2], nameOf(sub)); - assertEquals(paths[2].length(), subfti.getEntryLength()); - assertEquals(mtime[2], subfti.getEntryLastModifiedInstant()); - - sub.next(1); - assertTrue(sub.eof()); - - top.next(1); - assertFalse(top.first()); - assertFalse(top.eof()); - assertEquals(FileMode.REGULAR_FILE.getBits(), top.mode); - assertEquals(paths[3], nameOf(top)); - assertEquals(paths[3].length(), top.getEntryLength()); - assertEquals(mtime[3], top.getEntryLastModifiedInstant()); - - top.next(1); - assertTrue(top.eof()); + try (ObjectReader reader = db.newObjectReader()) { + final AbstractTreeIterator sub = top.createSubtreeIterator(reader); + assertTrue(sub instanceof FileTreeIterator); + final FileTreeIterator subfti = (FileTreeIterator) sub; + assertTrue(sub.first()); + assertFalse(sub.eof()); + assertEquals(paths[2], nameOf(sub)); + assertEquals(paths[2].length(), subfti.getEntryLength()); + assertEquals(mtime[2], subfti.getEntryLastModifiedInstant()); + + sub.next(1); + assertTrue(sub.eof()); + top.next(1); + assertFalse(top.first()); + assertFalse(top.eof()); + assertEquals(FileMode.REGULAR_FILE.getBits(), top.mode); + assertEquals(paths[3], nameOf(top)); + assertEquals(paths[3].length(), top.getEntryLength()); + assertEquals(mtime[3], top.getEntryLastModifiedInstant()); + + top.next(1); + assertTrue(top.eof()); + } } @Test @@ -272,22 +272,23 @@ public class FileTreeIteratorTest extends RepositoryTestCase { git.add().addFilepattern("file").call(); } DirCacheEntry dce = db.readDirCache().getEntry("file"); - TreeWalk tw = new TreeWalk(db); - FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(), db - .getConfig().get(WorkingTreeOptions.KEY)); - tw.addTree(fti); - DirCacheIterator dci = new DirCacheIterator(db.readDirCache()); - tw.addTree(dci); - fti.setDirCacheIterator(tw, 1); - while (tw.next() && !tw.getPathString().equals("file")) { - // - } - assertEquals(MetadataDiff.EQUAL, fti.compareMetadata(dce)); - ObjectId fromRaw = ObjectId.fromRaw(fti.idBuffer(), fti.idOffset()); - assertEquals("6b584e8ece562ebffc15d38808cd6b98fc3d97ea", - fromRaw.getName()); - try (ObjectReader objectReader = db.newObjectReader()) { - assertFalse(fti.isModified(dce, false, objectReader)); + try (TreeWalk tw = new TreeWalk(db)) { + FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(), + db.getConfig().get(WorkingTreeOptions.KEY)); + tw.addTree(fti); + DirCacheIterator dci = new DirCacheIterator(db.readDirCache()); + tw.addTree(dci); + fti.setDirCacheIterator(tw, 1); + while (tw.next() && !tw.getPathString().equals("file")) { + // + } + assertEquals(MetadataDiff.EQUAL, fti.compareMetadata(dce)); + ObjectId fromRaw = ObjectId.fromRaw(fti.idBuffer(), fti.idOffset()); + assertEquals("6b584e8ece562ebffc15d38808cd6b98fc3d97ea", + fromRaw.getName()); + try (ObjectReader objectReader = db.newObjectReader()) { + assertFalse(fti.isModified(dce, false, objectReader)); + } } } @@ -624,9 +625,8 @@ public class FileTreeIteratorTest extends RepositoryTestCase { @Test public void testCustomFileModeStrategy() throws Exception { - Repository nestedRepo = createNestedRepo(); - - try (Git git = new Git(nestedRepo)) { + try (Repository nestedRepo = createNestedRepo(); + Git git = new Git(nestedRepo)) { // validate that our custom strategy is honored WorkingTreeIterator customIterator = new FileTreeIterator( nestedRepo, NO_GITLINKS_STRATEGY); @@ -641,9 +641,8 @@ public class FileTreeIteratorTest extends RepositoryTestCase { @Test public void testCustomFileModeStrategyFromParentIterator() throws Exception { - Repository nestedRepo = createNestedRepo(); - - try (Git git = new Git(nestedRepo)) { + try (Repository nestedRepo = createNestedRepo(); + Git git = new Git(nestedRepo)) { FileTreeIterator customIterator = new FileTreeIterator(nestedRepo, NO_GITLINKS_STRATEGY); File r = new File(nestedRepo.getWorkTree(), "sub"); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java index 54c217276d..e6a5322374 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java @@ -84,16 +84,17 @@ public class NameConflictTreeWalkTest extends RepositoryTestCase { assertEquals(1, tree1.getEntryCount()); } - final TreeWalk tw = new TreeWalk(db); - tw.addTree(new DirCacheIterator(tree0)); - tw.addTree(new DirCacheIterator(tree1)); - - assertModes("a", REGULAR_FILE, MISSING, tw); - assertModes("a.b", EXECUTABLE_FILE, MISSING, tw); - assertModes("a", MISSING, TREE, tw); - tw.enterSubtree(); - assertModes("a/b", MISSING, REGULAR_FILE, tw); - assertModes("a0b", SYMLINK, MISSING, tw); + try (TreeWalk tw = new TreeWalk(db)) { + tw.addTree(new DirCacheIterator(tree0)); + tw.addTree(new DirCacheIterator(tree1)); + + assertModes("a", REGULAR_FILE, MISSING, tw); + assertModes("a.b", EXECUTABLE_FILE, MISSING, tw); + assertModes("a", MISSING, TREE, tw); + tw.enterSubtree(); + assertModes("a/b", MISSING, REGULAR_FILE, tw); + assertModes("a0b", SYMLINK, MISSING, tw); + } } @Test @@ -115,20 +116,21 @@ public class NameConflictTreeWalkTest extends RepositoryTestCase { assertEquals(1, tree1.getEntryCount()); } - final NameConflictTreeWalk tw = new NameConflictTreeWalk(db); - tw.addTree(new DirCacheIterator(tree0)); - tw.addTree(new DirCacheIterator(tree1)); - - assertModes("a", REGULAR_FILE, TREE, tw); - assertTrue(tw.isDirectoryFileConflict()); - assertTrue(tw.isSubtree()); - tw.enterSubtree(); - assertModes("a/b", MISSING, REGULAR_FILE, tw); - assertTrue(tw.isDirectoryFileConflict()); - assertModes("a.b", EXECUTABLE_FILE, MISSING, tw); - assertFalse(tw.isDirectoryFileConflict()); - assertModes("a0b", SYMLINK, MISSING, tw); - assertFalse(tw.isDirectoryFileConflict()); + try (NameConflictTreeWalk tw = new NameConflictTreeWalk(db)) { + tw.addTree(new DirCacheIterator(tree0)); + tw.addTree(new DirCacheIterator(tree1)); + + assertModes("a", REGULAR_FILE, TREE, tw); + assertTrue(tw.isDirectoryFileConflict()); + assertTrue(tw.isSubtree()); + tw.enterSubtree(); + assertModes("a/b", MISSING, REGULAR_FILE, tw); + assertTrue(tw.isDirectoryFileConflict()); + assertModes("a.b", EXECUTABLE_FILE, MISSING, tw); + assertFalse(tw.isDirectoryFileConflict()); + assertModes("a0b", SYMLINK, MISSING, tw); + assertFalse(tw.isDirectoryFileConflict()); + } } @Test @@ -151,20 +153,21 @@ public class NameConflictTreeWalkTest extends RepositoryTestCase { assertEquals(2, tree1.getEntryCount()); } - final NameConflictTreeWalk tw = new NameConflictTreeWalk(db); - tw.addTree(new DirCacheIterator(tree0)); - tw.addTree(new DirCacheIterator(tree1)); - - assertModes("a", REGULAR_FILE, TREE, tw); - assertTrue(tw.isSubtree()); - assertTrue(tw.isDirectoryFileConflict()); - tw.enterSubtree(); - assertModes("a/b", MISSING, REGULAR_FILE, tw); - assertTrue(tw.isDirectoryFileConflict()); - assertModes("a.b", EXECUTABLE_FILE, EXECUTABLE_FILE, tw); - assertFalse(tw.isDirectoryFileConflict()); - assertModes("a0b", SYMLINK, MISSING, tw); - assertFalse(tw.isDirectoryFileConflict()); + try (NameConflictTreeWalk tw = new NameConflictTreeWalk(db)) { + tw.addTree(new DirCacheIterator(tree0)); + tw.addTree(new DirCacheIterator(tree1)); + + assertModes("a", REGULAR_FILE, TREE, tw); + assertTrue(tw.isSubtree()); + assertTrue(tw.isDirectoryFileConflict()); + tw.enterSubtree(); + assertModes("a/b", MISSING, REGULAR_FILE, tw); + assertTrue(tw.isDirectoryFileConflict()); + assertModes("a.b", EXECUTABLE_FILE, EXECUTABLE_FILE, tw); + assertFalse(tw.isDirectoryFileConflict()); + assertModes("a0b", SYMLINK, MISSING, tw); + assertFalse(tw.isDirectoryFileConflict()); + } } @Test @@ -187,20 +190,21 @@ public class NameConflictTreeWalkTest extends RepositoryTestCase { assertEquals(3, tree1.getEntryCount()); } - final NameConflictTreeWalk tw = new NameConflictTreeWalk(db); - tw.addTree(new DirCacheIterator(tree0)); - tw.addTree(new DirCacheIterator(tree1)); - - assertModes("a", REGULAR_FILE, TREE, tw); - assertTrue(tw.isSubtree()); - assertTrue(tw.isDirectoryFileConflict()); - tw.enterSubtree(); - assertModes("a/b", MISSING, REGULAR_FILE, tw); - assertTrue(tw.isDirectoryFileConflict()); - assertModes("a.b", MISSING, EXECUTABLE_FILE, tw); - assertFalse(tw.isDirectoryFileConflict()); - assertModes("a0b", SYMLINK, SYMLINK, tw); - assertFalse(tw.isDirectoryFileConflict()); + try (NameConflictTreeWalk tw = new NameConflictTreeWalk(db)) { + tw.addTree(new DirCacheIterator(tree0)); + tw.addTree(new DirCacheIterator(tree1)); + + assertModes("a", REGULAR_FILE, TREE, tw); + assertTrue(tw.isSubtree()); + assertTrue(tw.isDirectoryFileConflict()); + tw.enterSubtree(); + assertModes("a/b", MISSING, REGULAR_FILE, tw); + assertTrue(tw.isDirectoryFileConflict()); + assertModes("a.b", MISSING, EXECUTABLE_FILE, tw); + assertFalse(tw.isDirectoryFileConflict()); + assertModes("a0b", SYMLINK, SYMLINK, tw); + assertFalse(tw.isDirectoryFileConflict()); + } } @Test @@ -224,26 +228,27 @@ public class NameConflictTreeWalkTest extends RepositoryTestCase { assertEquals(4, tree1.getEntryCount()); } - final NameConflictTreeWalk tw = new NameConflictTreeWalk(db); - tw.addTree(new DirCacheIterator(tree0)); - tw.addTree(new DirCacheIterator(tree1)); - - assertModes("0", REGULAR_FILE, REGULAR_FILE, tw); - assertFalse(tw.isDirectoryFileConflict()); - assertModes("a", REGULAR_FILE, TREE, tw); - assertTrue(tw.isSubtree()); - assertTrue(tw.isDirectoryFileConflict()); - tw.enterSubtree(); - assertModes("a/b", MISSING, REGULAR_FILE, tw); - assertTrue(tw.isDirectoryFileConflict()); - assertModes("a/c", MISSING, TREE, tw); - assertTrue(tw.isDirectoryFileConflict()); - tw.enterSubtree(); - assertModes("a/c/e", MISSING, REGULAR_FILE, tw); - assertTrue(tw.isDirectoryFileConflict()); - - assertModes("a.b", MISSING, REGULAR_FILE, tw); - assertFalse(tw.isDirectoryFileConflict()); + try (NameConflictTreeWalk tw = new NameConflictTreeWalk(db)) { + tw.addTree(new DirCacheIterator(tree0)); + tw.addTree(new DirCacheIterator(tree1)); + + assertModes("0", REGULAR_FILE, REGULAR_FILE, tw); + assertFalse(tw.isDirectoryFileConflict()); + assertModes("a", REGULAR_FILE, TREE, tw); + assertTrue(tw.isSubtree()); + assertTrue(tw.isDirectoryFileConflict()); + tw.enterSubtree(); + assertModes("a/b", MISSING, REGULAR_FILE, tw); + assertTrue(tw.isDirectoryFileConflict()); + assertModes("a/c", MISSING, TREE, tw); + assertTrue(tw.isDirectoryFileConflict()); + tw.enterSubtree(); + assertModes("a/c/e", MISSING, REGULAR_FILE, tw); + assertTrue(tw.isDirectoryFileConflict()); + + assertModes("a.b", MISSING, REGULAR_FILE, tw); + assertFalse(tw.isDirectoryFileConflict()); + } } private static void assertModes(final String path, final FileMode mode0, diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/IndexDiffFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/IndexDiffFilterTest.java index 2f797e361a..964ffcaa83 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/IndexDiffFilterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/IndexDiffFilterTest.java @@ -101,13 +101,14 @@ public class IndexDiffFilterTest extends RepositoryTestCase { RevCommit commit = writeFileInFolderAndCommit(); deleteAll(); writeFileWithFolderName(); - TreeWalk treeWalk = createTreeWalk(commit); - assertTrue(treeWalk.next()); - assertEquals("folder", treeWalk.getPathString()); - assertTrue(treeWalk.next()); - assertEquals("folder/file", treeWalk.getPathString()); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertTrue(treeWalk.next()); + assertEquals("folder", treeWalk.getPathString()); + assertTrue(treeWalk.next()); + assertEquals("folder/file", treeWalk.getPathString()); + assertFalse(treeWalk.next()); + } } @Test @@ -115,24 +116,26 @@ public class IndexDiffFilterTest extends RepositoryTestCase { RevCommit commit = writeFileInFolderAndCommit(); deleteAll(); writeFileWithFolderName(); - TreeWalk treeWalk = createNonRecursiveTreeWalk(commit); - - assertTrue(treeWalk.next()); - assertEquals("folder", treeWalk.getPathString()); - assertTrue(treeWalk.next()); - assertEquals("folder", treeWalk.getPathString()); - assertTrue(treeWalk.isSubtree()); - treeWalk.enterSubtree(); - assertTrue(treeWalk.next()); - assertEquals("folder/file", treeWalk.getPathString()); - assertFalse(treeWalk.next()); + + try (TreeWalk treeWalk = createNonRecursiveTreeWalk(commit)) { + assertTrue(treeWalk.next()); + assertEquals("folder", treeWalk.getPathString()); + assertTrue(treeWalk.next()); + assertEquals("folder", treeWalk.getPathString()); + assertTrue(treeWalk.isSubtree()); + treeWalk.enterSubtree(); + assertTrue(treeWalk.next()); + assertEquals("folder/file", treeWalk.getPathString()); + assertFalse(treeWalk.next()); + } } @Test public void testFileCommitted() throws Exception { RevCommit commit = writeFileAndCommit(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test @@ -153,89 +156,100 @@ public class IndexDiffFilterTest extends RepositoryTestCase { "<<<<<<< HEAD\nside\n=======\nmaster\n>>>>>>> master\n"); writeTrashFile(FILE, "master"); - TreeWalk treeWalk = createTreeWalk(side); - int count = 0; - while (treeWalk.next()) - count++; - assertEquals(2, count); + try (TreeWalk treeWalk = createTreeWalk(side)) { + int count = 0; + while (treeWalk.next()) + count++; + assertEquals(2, count); + } } @Test public void testFileInFolderCommitted() throws Exception { RevCommit commit = writeFileInFolderAndCommit(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test public void testEmptyFolderCommitted() throws Exception { RevCommit commit = createEmptyFolderAndCommit(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test public void testFileCommittedChangedNotModified() throws Exception { RevCommit commit = writeFileAndCommit(); writeFile(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test public void testFileInFolderCommittedChangedNotModified() throws Exception { RevCommit commit = writeFileInFolderAndCommit(); writeFileInFolder(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test public void testFileCommittedModified() throws Exception { RevCommit commit = writeFileAndCommit(); writeFileModified(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE); + } } @Test public void testFileInFolderCommittedModified() throws Exception { RevCommit commit = writeFileInFolderAndCommit(); writeFileInFolderModified(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE_IN_FOLDER); + } } @Test public void testFileCommittedDeleted() throws Exception { RevCommit commit = writeFileAndCommit(); deleteFile(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE); + } } @Test public void testFileInFolderCommittedDeleted() throws Exception { RevCommit commit = writeFileInFolderAndCommit(); deleteFileInFolder(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE_IN_FOLDER); + } } @Test public void testFileInFolderCommittedAllDeleted() throws Exception { RevCommit commit = writeFileInFolderAndCommit(); deleteAll(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE_IN_FOLDER); + } } @Test public void testEmptyFolderCommittedDeleted() throws Exception { RevCommit commit = createEmptyFolderAndCommit(); deleteFolder(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test @@ -243,8 +257,9 @@ public class IndexDiffFilterTest extends RepositoryTestCase { throws Exception { RevCommit commit = writeFileAndCommit(); writeFileModifiedAndCommit(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE); + } } @Test @@ -252,8 +267,9 @@ public class IndexDiffFilterTest extends RepositoryTestCase { throws Exception { RevCommit commit = writeFileInFolderAndCommit(); writeFileInFolderModifiedAndCommit(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE_IN_FOLDER); + } } @Test @@ -261,8 +277,9 @@ public class IndexDiffFilterTest extends RepositoryTestCase { throws Exception { RevCommit commit = writeFileAndCommit(); deleteFileAndCommit(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE); + } } @Test @@ -270,8 +287,9 @@ public class IndexDiffFilterTest extends RepositoryTestCase { throws Exception { RevCommit commit = writeFileInFolderAndCommit(); deleteFileInFolderAndCommit(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE_IN_FOLDER); + } } @Test @@ -279,8 +297,9 @@ public class IndexDiffFilterTest extends RepositoryTestCase { throws Exception { RevCommit commit = writeFileInFolderAndCommit(); deleteAllAndCommit(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE_IN_FOLDER); + } } @Test @@ -288,96 +307,108 @@ public class IndexDiffFilterTest extends RepositoryTestCase { throws Exception { RevCommit commit = createEmptyFolderAndCommit(); deleteFolderAndCommit(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test public void testFileUntracked() throws Exception { RevCommit commit = writeFileAndCommit(); writeFileUntracked(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, UNTRACKED_FILE); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, UNTRACKED_FILE); + } } @Test public void testFileInFolderUntracked() throws Exception { RevCommit commit = writeFileInFolderAndCommit(); writeFileInFolderUntracked(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, UNTRACKED_FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, UNTRACKED_FILE_IN_FOLDER); + } } @Test public void testEmptyFolderUntracked() throws Exception { RevCommit commit = createEmptyFolderAndCommit(); createEmptyFolderUntracked(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test public void testFileIgnored() throws Exception { RevCommit commit = writeFileAndCommit(); writeFileIgnored(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test public void testFileInFolderIgnored() throws Exception { RevCommit commit = writeFileInFolderAndCommit(); writeFileInFolderIgnored(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test public void testFileInFolderAllIgnored() throws Exception { RevCommit commit = writeFileInFolderAndCommit(); writeFileInFolderAllIgnored(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test public void testEmptyFolderIgnored() throws Exception { RevCommit commit = createEmptyFolderAndCommit(); createEmptyFolderIgnored(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test public void testFileIgnoredNotHonored() throws Exception { RevCommit commit = writeFileAndCommit(); writeFileIgnored(); - TreeWalk treeWalk = createTreeWalkDishonorIgnores(commit); - assertPaths(treeWalk, IGNORED_FILE, GITIGNORE); + try (TreeWalk treeWalk = createTreeWalkDishonorIgnores(commit)) { + assertPaths(treeWalk, IGNORED_FILE, GITIGNORE); + } } @Test public void testFileCommittedModifiedIgnored() throws Exception { RevCommit commit = writeFileAndCommit(); writeFileModifiedIgnored(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE); + } } @Test public void testFileInFolderCommittedModifiedIgnored() throws Exception { RevCommit commit = writeFileInFolderAndCommit(); writeFileInFolderModifiedIgnored(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE_IN_FOLDER); + } } @Test public void testFileInFolderCommittedModifiedAllIgnored() throws Exception { RevCommit commit = writeFileInFolderAndCommit(); writeFileInFolderModifiedAllIgnored(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE_IN_FOLDER); + } } @Test @@ -386,8 +417,9 @@ public class IndexDiffFilterTest extends RepositoryTestCase { RevCommit commit = writeFileAndCommit(); deleteFileAndCommit(); rewriteFileIgnored(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE); + } } @Test @@ -396,8 +428,9 @@ public class IndexDiffFilterTest extends RepositoryTestCase { RevCommit commit = writeFileInFolderAndCommit(); deleteFileInFolderAndCommit(); rewriteFileInFolderIgnored(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE_IN_FOLDER); + } } @Test @@ -406,8 +439,9 @@ public class IndexDiffFilterTest extends RepositoryTestCase { RevCommit commit = writeFileInFolderAndCommit(); deleteAllAndCommit(); rewriteFileInFolderAllIgnored(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FILE_IN_FOLDER); + } } @Test @@ -416,15 +450,17 @@ public class IndexDiffFilterTest extends RepositoryTestCase { RevCommit commit = createEmptyFolderAndCommit(); deleteFolderAndCommit(); recreateEmptyFolderIgnored(); - TreeWalk treeWalk = createTreeWalk(commit); - assertFalse(treeWalk.next()); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertFalse(treeWalk.next()); + } } @Test public void testFileInFolderCommittedNonRecursive() throws Exception { RevCommit commit = writeFileInFolderAndCommit(); - TreeWalk treeWalk = createNonRecursiveTreeWalk(commit); - assertPaths(treeWalk, FOLDER); + try (TreeWalk treeWalk = createNonRecursiveTreeWalk(commit)) { + assertPaths(treeWalk, FOLDER); + } } @Test @@ -432,8 +468,9 @@ public class IndexDiffFilterTest extends RepositoryTestCase { RevCommit commit = writeFileInFolderAndCommit(); deleteAll(); writeFileWithFolderName(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FOLDER, FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FOLDER, FILE_IN_FOLDER); + } } @Test @@ -442,8 +479,9 @@ public class IndexDiffFilterTest extends RepositoryTestCase { RevCommit commit = writeFileInFolderAndCommit(); deleteAll(); writeFileWithFolderNameAndCommit(); - TreeWalk treeWalk = createTreeWalk(commit); - assertPaths(treeWalk, FOLDER, FILE_IN_FOLDER); + try (TreeWalk treeWalk = createTreeWalk(commit)) { + assertPaths(treeWalk, FOLDER, FILE_IN_FOLDER); + } } private void writeFile() throws Exception { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java index 89a2fc44c7..c9a339352b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FSTest.java @@ -254,7 +254,9 @@ public class FSTest { formatter.format(t1.toInstant()), Long.valueOf(resolutionNs)), t2.compareTo(t1) > 0); } finally { - Files.delete(f); + if (f != null) { + Files.delete(f); + } } } } 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 e5fcbf9d7c..70a2dbbfe8 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 @@ -58,6 +58,8 @@ import org.eclipse.jgit.hooks.PostCommitHook; import org.eclipse.jgit.hooks.PreCommitHook; import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.revwalk.RevCommit; import org.junit.Assume; import org.junit.Test; @@ -221,6 +223,75 @@ public class HookTest extends RepositoryTestCase { } @Test + public void testRunHookHooksPathRelative() throws Exception { + assumeSupportedPlatform(); + + writeHookFile(PreCommitHook.NAME, + "#!/bin/sh\necho \"Wrong hook $1 $2\"\nread INPUT\necho $INPUT\n" + + "echo $GIT_DIR\necho $GIT_WORK_TREE\necho 1>&2 \"stderr\""); + writeHookFile("../../" + PreCommitHook.NAME, + "#!/bin/sh\necho \"test $1 $2\"\nread INPUT\necho $INPUT\n" + + "echo $GIT_DIR\necho $GIT_WORK_TREE\necho 1>&2 \"stderr\""); + StoredConfig cfg = db.getConfig(); + cfg.load(); + cfg.setString(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_HOOKS_PATH, "."); + cfg.save(); + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayOutputStream err = new ByteArrayOutputStream()) { + ProcessResult res = FS.DETECTED.runHookIfPresent(db, + PreCommitHook.NAME, new String[] { "arg1", "arg2" }, + new PrintStream(out), new PrintStream(err), "stdin"); + + assertEquals("unexpected hook output", + "test arg1 arg2\nstdin\n" + + db.getDirectory().getAbsolutePath() + '\n' + + db.getWorkTree().getAbsolutePath() + '\n', + out.toString("UTF-8")); + assertEquals("unexpected output on stderr stream", "stderr\n", + err.toString("UTF-8")); + assertEquals("unexpected exit code", 0, res.getExitCode()); + assertEquals("unexpected process status", ProcessResult.Status.OK, + res.getStatus()); + } + } + + @Test + public void testRunHookHooksPathAbsolute() throws Exception { + assumeSupportedPlatform(); + + writeHookFile(PreCommitHook.NAME, + "#!/bin/sh\necho \"Wrong hook $1 $2\"\nread INPUT\necho $INPUT\n" + + "echo $GIT_DIR\necho $GIT_WORK_TREE\necho 1>&2 \"stderr\""); + writeHookFile("../../" + PreCommitHook.NAME, + "#!/bin/sh\necho \"test $1 $2\"\nread INPUT\necho $INPUT\n" + + "echo $GIT_DIR\necho $GIT_WORK_TREE\necho 1>&2 \"stderr\""); + StoredConfig cfg = db.getConfig(); + cfg.load(); + cfg.setString(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_HOOKS_PATH, + db.getWorkTree().getAbsolutePath()); + cfg.save(); + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayOutputStream err = new ByteArrayOutputStream()) { + ProcessResult res = FS.DETECTED.runHookIfPresent(db, + PreCommitHook.NAME, new String[] { "arg1", "arg2" }, + new PrintStream(out), new PrintStream(err), "stdin"); + + assertEquals("unexpected hook output", + "test arg1 arg2\nstdin\n" + + db.getDirectory().getAbsolutePath() + '\n' + + db.getWorkTree().getAbsolutePath() + '\n', + out.toString("UTF-8")); + assertEquals("unexpected output on stderr stream", "stderr\n", + err.toString("UTF-8")); + assertEquals("unexpected exit code", 0, res.getExitCode()); + assertEquals("unexpected process status", ProcessResult.Status.OK, + res.getStatus()); + } + } + + @Test public void testFailedPreCommitHookBlockCommit() throws Exception { assumeSupportedPlatform(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HttpSupportTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HttpSupportTest.java new file mode 100644 index 0000000000..cbe4eb2eb0 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/HttpSupportTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019, Thomas Wolf <thomas.wolf@paranor.ch> and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.net.URL; +import java.util.Collections; +import java.util.List; + +import org.junit.Test; + +public class HttpSupportTest { + + private static class TestProxySelector extends ProxySelector { + + private static final Proxy DUMMY = new Proxy(Proxy.Type.HTTP, + InetSocketAddress.createUnresolved("localhost", 0)); + + @Override + public List<Proxy> select(URI uri) { + if ("http".equals(uri.getScheme()) + && "somehost".equals(uri.getHost())) { + return Collections.singletonList(DUMMY); + } + return Collections.singletonList(Proxy.NO_PROXY); + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + // Empty + } + } + + @Test + public void testMalformedUri() throws Exception { + // Valid URL, but backslash is not allowed in a URI in the userinfo part + // per RFC 3986: https://tools.ietf.org/html/rfc3986#section-3.2.1 . + // Test that conversion to URI to call the ProxySelector does not throw + // an exception. + Proxy proxy = HttpSupport.proxyFor(new TestProxySelector(), new URL( + "http://infor\\c.jones@somehost/somewhere/someproject.git")); + assertNotNull(proxy); + assertEquals(Proxy.Type.HTTP, proxy.type()); + } + + @Test + public void testCorrectUri() throws Exception { + // Backslash escaped as %5C is correct. + Proxy proxy = HttpSupport.proxyFor(new TestProxySelector(), new URL( + "http://infor%5Cc.jones@somehost/somewhere/someproject.git")); + assertNotNull(proxy); + assertEquals(Proxy.Type.HTTP, proxy.type()); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringGitPathStyleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringGitPathStyleTest.java index 9a0c96e171..c09b136ca6 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringGitPathStyleTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringGitPathStyleTest.java @@ -45,6 +45,7 @@ package org.eclipse.jgit.util; import static java.nio.charset.StandardCharsets.ISO_8859_1; import static org.eclipse.jgit.util.QuotedString.GIT_PATH; +import static org.eclipse.jgit.util.QuotedString.GIT_PATH_MINIMAL; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; @@ -67,6 +68,12 @@ public class QuotedStringGitPathStyleTest { assertEquals(exp, r); } + private static void assertDequoteMinimal(String exp, String in) { + final byte[] b = ('"' + in + '"').getBytes(ISO_8859_1); + final String r = GIT_PATH_MINIMAL.dequote(b, 0, b.length); + assertEquals(exp, r); + } + @Test public void testQuote_Empty() { assertEquals("\"\"", GIT_PATH.quote("")); @@ -206,4 +213,75 @@ public class QuotedStringGitPathStyleTest { assertSame("abc@2x.png", GIT_PATH.quote("abc@2x.png")); assertDequote("abc@2x.png", "abc\\1002x.png"); } + + @Test + public void testNoQuote() { + assertSame("\u00c5ngstr\u00f6m", + GIT_PATH_MINIMAL.quote("\u00c5ngstr\u00f6m")); + } + + @Test + public void testQuoteMinimal() { + assertEquals("\"\u00c5n\\\\str\u00f6m\"", + GIT_PATH_MINIMAL.quote("\u00c5n\\str\u00f6m")); + } + + @Test + public void testDequoteMinimal() { + assertEquals("\u00c5n\\str\u00f6m", GIT_PATH_MINIMAL + .dequote(GIT_PATH_MINIMAL.quote("\u00c5n\\str\u00f6m"))); + + } + + @Test + public void testRoundtripMinimal() { + assertEquals("\u00c5ngstr\u00f6m", GIT_PATH_MINIMAL + .dequote(GIT_PATH_MINIMAL.quote("\u00c5ngstr\u00f6m"))); + + } + + @Test + public void testQuoteMinimalDequoteNormal() { + assertEquals("\u00c5n\\str\u00f6m", GIT_PATH + .dequote(GIT_PATH_MINIMAL.quote("\u00c5n\\str\u00f6m"))); + + } + + @Test + public void testQuoteNormalDequoteMinimal() { + assertEquals("\u00c5n\\str\u00f6m", GIT_PATH_MINIMAL + .dequote(GIT_PATH.quote("\u00c5n\\str\u00f6m"))); + + } + + @Test + public void testRoundtripMinimalDequoteNormal() { + assertEquals("\u00c5ngstr\u00f6m", + GIT_PATH.dequote(GIT_PATH_MINIMAL.quote("\u00c5ngstr\u00f6m"))); + + } + + @Test + public void testRoundtripNormalDequoteMinimal() { + assertEquals("\u00c5ngstr\u00f6m", + GIT_PATH_MINIMAL.dequote(GIT_PATH.quote("\u00c5ngstr\u00f6m"))); + + } + + @Test + public void testDequote_UTF8_Minimal() { + assertDequoteMinimal("\u00c5ngstr\u00f6m", + "\\303\\205ngstr\\303\\266m"); + } + + @Test + public void testDequote_RawUTF8_Minimal() { + assertDequoteMinimal("\u00c5ngstr\u00f6m", "\303\205ngstr\303\266m"); + } + + @Test + public void testDequote_RawLatin1_Minimal() { + assertDequoteMinimal("\u00c5ngstr\u00f6m", "\305ngstr\366m"); + } + } diff --git a/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs index 525ac67142..9fd92b1098 100644 --- a/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit.ui/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF index b143d51720..02ca5f6b75 100644 --- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF @@ -4,14 +4,14 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit.ui Bundle-SymbolicName: org.eclipse.jgit.ui -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Vendor: %Bundle-Vendor Bundle-RequiredExecutionEnvironment: JavaSE-1.8 -Export-Package: org.eclipse.jgit.awtui;version="5.5.2" -Import-Package: org.eclipse.jgit.errors;version="[5.5.2,5.6.0)", - org.eclipse.jgit.lib;version="[5.5.2,5.6.0)", - org.eclipse.jgit.nls;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revplot;version="[5.5.2,5.6.0)", - org.eclipse.jgit.revwalk;version="[5.5.2,5.6.0)", - org.eclipse.jgit.transport;version="[5.5.2,5.6.0)", - org.eclipse.jgit.util;version="[5.5.2,5.6.0)" +Export-Package: org.eclipse.jgit.awtui;version="5.6.1" +Import-Package: org.eclipse.jgit.errors;version="[5.6.1,5.7.0)", + org.eclipse.jgit.lib;version="[5.6.1,5.7.0)", + org.eclipse.jgit.nls;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revplot;version="[5.6.1,5.7.0)", + org.eclipse.jgit.revwalk;version="[5.6.1,5.7.0)", + org.eclipse.jgit.transport;version="[5.6.1,5.7.0)", + org.eclipse.jgit.util;version="[5.6.1,5.7.0)" diff --git a/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF index 5e75347f77..5b649f43d0 100644 --- a/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF +++ b/org.eclipse.jgit.ui/META-INF/SOURCE-MANIFEST.MF @@ -3,5 +3,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.jgit.ui - Sources Bundle-SymbolicName: org.eclipse.jgit.ui.source Bundle-Vendor: Eclipse.org - JGit -Bundle-Version: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit.ui;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit.ui;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit.ui/pom.xml b/org.eclipse.jgit.ui/pom.xml index fe7af76d8e..0f4d1c54a9 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-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 58ec3cb418..2a71030e21 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -1,39 +1,10 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <component id="org.eclipse.jgit" version="2"> - <resource path="META-INF/MANIFEST.MF"> - <filter id="924844039"> + <resource path="META-INF/MANIFEST.MF" type="org.eclipse.jgit.transport.BaseReceivePack"> + <filter id="305324134"> <message_arguments> - <message_argument value="5.5.2"/> - <message_argument value="5.5.0"/> - </message_arguments> - </filter> - </resource> - <resource path="src/org/eclipse/jgit/dircache/DirCacheEntry.java" type="org.eclipse.jgit.dircache.DirCacheEntry"> - <filter id="1142947843"> - <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="getLastModifiedInstant()"/> - </message_arguments> - </filter> - <filter id="1142947843"> - <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="mightBeRacilyClean(Instant)"/> - </message_arguments> - </filter> - <filter id="1142947843"> - <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="setLastModified(Instant)"/> - </message_arguments> - </filter> - </resource> - <resource path="src/org/eclipse/jgit/lib/AnyObjectId.java" type="org.eclipse.jgit.lib.AnyObjectId"> - <filter id="1141899266"> - <message_arguments> - <message_argument value="5.4"/> - <message_argument value="5.5"/> - <message_argument value="isEqual(AnyObjectId, AnyObjectId)"/> + <message_argument value="org.eclipse.jgit.transport.BaseReceivePack"/> + <message_argument value="org.eclipse.jgit_5.6.1"/> </message_arguments> </filter> </resource> @@ -52,24 +23,6 @@ <message_argument value="CONFIG_JMX_SECTION"/> </message_arguments> </filter> - <filter id="1142947843"> - <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="CONFIG_FILESYSTEM_SECTION"/> - </message_arguments> - </filter> - <filter id="1142947843"> - <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="CONFIG_KEY_MIN_RACY_THRESHOLD"/> - </message_arguments> - </filter> - <filter id="1142947843"> - <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="CONFIG_KEY_TIMESTAMP_RESOLUTION"/> - </message_arguments> - </filter> </resource> <resource path="src/org/eclipse/jgit/lib/Constants.java" type="org.eclipse.jgit.lib.Constants"> <filter id="1142947843"> @@ -79,6 +32,14 @@ </message_arguments> </filter> </resource> + <resource path="src/org/eclipse/jgit/revwalk/ReachabilityChecker.java" type="org.eclipse.jgit.revwalk.ReachabilityChecker"> + <filter id="403804204"> + <message_arguments> + <message_argument value="org.eclipse.jgit.revwalk.ReachabilityChecker"/> + <message_argument value="areAllReachable(Collection<RevCommit>, Stream<RevCommit>)"/> + </message_arguments> + </filter> + </resource> <resource path="src/org/eclipse/jgit/storage/file/WindowCacheStats.java" type="org.eclipse.jgit.storage.file.WindowCacheStats"> <filter id="337809484"> <message_arguments> @@ -88,79 +49,74 @@ </message_arguments> </filter> </resource> - <resource path="src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java" type="org.eclipse.jgit.treewalk.WorkingTreeIterator"> - <filter id="1142947843"> - <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="getEntryLastModifiedInstant()"/> - </message_arguments> - </filter> - </resource> - <resource path="src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java" type="org.eclipse.jgit.treewalk.WorkingTreeIterator$Entry"> - <filter id="336695337"> + <resource path="src/org/eclipse/jgit/storage/pack/PackStatistics.java" type="org.eclipse.jgit.storage.pack.PackStatistics$Accumulator"> + <filter id="336658481"> <message_arguments> - <message_argument value="org.eclipse.jgit.treewalk.WorkingTreeIterator.Entry"/> - <message_argument value="getLastModifiedInstant()"/> + <message_argument value="org.eclipse.jgit.storage.pack.PackStatistics.Accumulator"/> + <message_argument value="offloadedPackfileSize"/> </message_arguments> </filter> - <filter id="1142947843"> + <filter id="336658481"> <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="getLastModifiedInstant()"/> + <message_argument value="org.eclipse.jgit.storage.pack.PackStatistics.Accumulator"/> + <message_argument value="offloadedPackfiles"/> </message_arguments> </filter> </resource> - <resource path="src/org/eclipse/jgit/util/FS.java" type="org.eclipse.jgit.util.FS"> - <filter id="338792546"> + <resource path="src/org/eclipse/jgit/transport/AbstractAdvertiseRefsHook.java" type="org.eclipse.jgit.transport.AbstractAdvertiseRefsHook"> + <filter comment="Merged BaseReceivePack into ReceivePack, replace BaseReceivePack with ReceivePack" id="338792546"> <message_arguments> - <message_argument value="org.eclipse.jgit.util.FS"/> - <message_argument value="getFsTimerResolution(Path)"/> + <message_argument value="org.eclipse.jgit.transport.AbstractAdvertiseRefsHook"/> + <message_argument value="advertiseRefs(BaseReceivePack)"/> </message_arguments> </filter> - <filter id="1142947843"> + </resource> + <resource path="src/org/eclipse/jgit/transport/AdvertiseRefsHook.java" type="org.eclipse.jgit.transport.AdvertiseRefsHook"> + <filter comment="Merged BaseReceivePack into ReceivePack, replace BaseReceivePack with ReceivePack" id="403804204"> <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="getFileStoreAttributes(Path)"/> + <message_argument value="org.eclipse.jgit.transport.AdvertiseRefsHook"/> + <message_argument value="advertiseRefs(ReceivePack)"/> </message_arguments> </filter> - <filter id="1142947843"> + <filter comment="Merged BaseReceivePack into ReceivePack, replace BaseReceivePack with ReceivePack" id="405901410"> <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="lastModifiedInstant(File)"/> + <message_argument value="org.eclipse.jgit.transport.AdvertiseRefsHook"/> + <message_argument value="advertiseRefs(BaseReceivePack)"/> </message_arguments> </filter> - <filter id="1142947843"> + </resource> + <resource path="src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java" type="org.eclipse.jgit.transport.AdvertiseRefsHookChain"> + <filter comment="Merged BaseReceivePack into ReceivePack, replace BaseReceivePack with ReceivePack" id="338792546"> <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="lastModifiedInstant(Path)"/> + <message_argument value="org.eclipse.jgit.transport.AdvertiseRefsHookChain"/> + <message_argument value="advertiseRefs(BaseReceivePack)"/> </message_arguments> </filter> - <filter id="1142947843"> + </resource> + <resource path="src/org/eclipse/jgit/transport/ReceiveCommand.java" type="org.eclipse.jgit.transport.ReceiveCommand"> + <filter comment="Merged BaseReceivePack into ReceivePack, replace BaseReceivePack with ReceivePack" id="338792546"> <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="setAsyncFileStoreAttributes(boolean)"/> + <message_argument value="org.eclipse.jgit.transport.ReceiveCommand"/> + <message_argument value="execute(BaseReceivePack)"/> </message_arguments> </filter> - <filter id="1142947843"> + </resource> + <resource path="src/org/eclipse/jgit/transport/ReceivePack.java" type="org.eclipse.jgit.transport.ReceivePack"> + <filter comment="Merged BaseReceivePack into ReceivePack, replace BaseReceivePack with ReceivePack" id="338792546"> <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="setLastModified(Path, Instant)"/> + <message_argument value="org.eclipse.jgit.transport.ReceivePack"/> + <message_argument value="getLockMessageProcessName()"/> </message_arguments> </filter> - </resource> - <resource path="src/org/eclipse/jgit/util/FS.java" type="org.eclipse.jgit.util.FS$Attributes"> - <filter id="1142947843"> + <filter comment="Merged BaseReceivePack into ReceivePack, replace BaseReceivePack with ReceivePack" id="338849923"> <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="getLastModifiedInstant()"/> + <message_argument value="org.eclipse.jgit.transport.ReceivePack"/> </message_arguments> </filter> - </resource> - <resource path="src/org/eclipse/jgit/util/FS.java" type="org.eclipse.jgit.util.FS$FileStoreAttributes"> - <filter id="1142947843"> + <filter id="421572723"> <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="FileStoreAttributes"/> + <message_argument value="org.eclipse.jgit.transport.ReceivePack"/> + <message_argument value="enableCapabilities()"/> </message_arguments> </filter> </resource> @@ -172,28 +128,11 @@ </message_arguments> </filter> </resource> - <resource path="src/org/eclipse/jgit/util/References.java" type="org.eclipse.jgit.util.References"> - <filter id="1108344834"> + <resource path="src/org/eclipse/jgit/util/QuotedString.java" type="org.eclipse.jgit.util.QuotedString"> + <filter id="336658481"> <message_arguments> - <message_argument value="5.4"/> - <message_argument value="5.5"/> - <message_argument value="org.eclipse.jgit.util.References"/> - </message_arguments> - </filter> - </resource> - <resource path="src/org/eclipse/jgit/util/SimpleLruCache.java" type="org.eclipse.jgit.util.SimpleLruCache"> - <filter id="1109393411"> - <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="org.eclipse.jgit.util.SimpleLruCache"/> - </message_arguments> - </filter> - </resource> - <resource path="src/org/eclipse/jgit/util/Stats.java" type="org.eclipse.jgit.util.Stats"> - <filter id="1109393411"> - <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="org.eclipse.jgit.util.Stats"/> + <message_argument value="org.eclipse.jgit.util.QuotedString"/> + <message_argument value="GIT_PATH_MINIMAL"/> </message_arguments> </filter> </resource> @@ -206,18 +145,6 @@ </filter> <filter id="1142947843"> <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="getSystemConfig()"/> - </message_arguments> - </filter> - <filter id="1142947843"> - <message_arguments> - <message_argument value="5.1.9"/> - <message_argument value="getUserConfig()"/> - </message_arguments> - </filter> - <filter id="1142947843"> - <message_arguments> <message_argument value="5.5.2"/> <message_argument value="getJGitConfig()"/> </message_arguments> diff --git a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs index ef6f5e732f..bc7ba1e50e 100644 --- a/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.jgit/.settings/org.eclipse.jdt.core.prefs @@ -92,7 +92,7 @@ org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index 69cdf30459..08aa0477f4 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF @@ -3,12 +3,12 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Automatic-Module-Name: org.eclipse.jgit Bundle-SymbolicName: org.eclipse.jgit -Bundle-Version: 5.5.2.qualifier +Bundle-Version: 5.6.1.qualifier Bundle-Localization: plugin Bundle-Vendor: %Bundle-Vendor Bundle-ActivationPolicy: lazy -Export-Package: org.eclipse.jgit.annotations;version="5.5.2", - org.eclipse.jgit.api;version="5.5.2"; +Export-Package: org.eclipse.jgit.annotations;version="5.6.1", + org.eclipse.jgit.api;version="5.6.1"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.diff, @@ -22,53 +22,53 @@ Export-Package: org.eclipse.jgit.annotations;version="5.5.2", org.eclipse.jgit.submodule, org.eclipse.jgit.transport, org.eclipse.jgit.merge", - org.eclipse.jgit.api.errors;version="5.5.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors", - org.eclipse.jgit.attributes;version="5.5.2", - org.eclipse.jgit.blame;version="5.5.2"; + org.eclipse.jgit.api.errors;version="5.6.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.errors", + org.eclipse.jgit.attributes;version="5.6.1", + org.eclipse.jgit.blame;version="5.6.1"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.diff", - org.eclipse.jgit.diff;version="5.5.2"; + org.eclipse.jgit.diff;version="5.6.1"; uses:="org.eclipse.jgit.patch, org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.util", - org.eclipse.jgit.dircache;version="5.5.2"; + org.eclipse.jgit.dircache;version="5.6.1"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.util, org.eclipse.jgit.events, org.eclipse.jgit.attributes", - org.eclipse.jgit.errors;version="5.5.2"; + org.eclipse.jgit.errors;version="5.6.1"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.internal.storage.pack, org.eclipse.jgit.transport, org.eclipse.jgit.dircache", - org.eclipse.jgit.events;version="5.5.2";uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.fnmatch;version="5.5.2", - org.eclipse.jgit.gitrepo;version="5.5.2"; + org.eclipse.jgit.events;version="5.6.1";uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.fnmatch;version="5.6.1", + org.eclipse.jgit.gitrepo;version="5.6.1"; uses:="org.eclipse.jgit.api, org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.xml.sax.helpers, org.xml.sax", - org.eclipse.jgit.gitrepo.internal;version="5.5.2";x-internal:=true, - org.eclipse.jgit.hooks;version="5.5.2";uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.ignore;version="5.5.2", - org.eclipse.jgit.ignore.internal;version="5.5.2";x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal;version="5.5.2";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test", - org.eclipse.jgit.internal.fsck;version="5.5.2";x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.ketch;version="5.5.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.revwalk;version="5.5.2";x-internal:=true, - org.eclipse.jgit.internal.storage.dfs;version="5.5.2"; + org.eclipse.jgit.gitrepo.internal;version="5.6.1";x-internal:=true, + org.eclipse.jgit.hooks;version="5.6.1";uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.ignore;version="5.6.1", + org.eclipse.jgit.ignore.internal;version="5.6.1";x-friends:="org.eclipse.jgit.test", + org.eclipse.jgit.internal;version="5.6.1";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test", + org.eclipse.jgit.internal.fsck;version="5.6.1";x-friends:="org.eclipse.jgit.test", + org.eclipse.jgit.internal.ketch;version="5.6.1";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", + org.eclipse.jgit.internal.revwalk;version="5.6.1";x-internal:=true, + org.eclipse.jgit.internal.storage.dfs;version="5.6.1"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.http.server, org.eclipse.jgit.http.test, org.eclipse.jgit.lfs.test", - org.eclipse.jgit.internal.storage.file;version="5.5.2"; + org.eclipse.jgit.internal.storage.file;version="5.6.1"; x-friends:="org.eclipse.jgit.test, org.eclipse.jgit.junit, org.eclipse.jgit.junit.http, @@ -77,19 +77,19 @@ Export-Package: org.eclipse.jgit.annotations;version="5.5.2", org.eclipse.jgit.pgm, org.eclipse.jgit.pgm.test, org.eclipse.jgit.ssh.apache", - org.eclipse.jgit.internal.storage.io;version="5.5.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.storage.pack;version="5.5.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.storage.reftable;version="5.5.2"; + org.eclipse.jgit.internal.storage.io;version="5.6.1";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", + org.eclipse.jgit.internal.storage.pack;version="5.6.1";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", + org.eclipse.jgit.internal.storage.reftable;version="5.6.1"; x-friends:="org.eclipse.jgit.http.test, org.eclipse.jgit.junit, org.eclipse.jgit.test, org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.storage.reftree;version="5.5.2";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", - org.eclipse.jgit.internal.submodule;version="5.5.2";x-internal:=true, - org.eclipse.jgit.internal.transport.http;version="5.5.2";x-friends:="org.eclipse.jgit.test", - org.eclipse.jgit.internal.transport.parser;version="5.5.2";x-friends:="org.eclipse.jgit.http.server,org.eclipse.jgit.test", - org.eclipse.jgit.internal.transport.ssh;version="5.5.2";x-friends:="org.eclipse.jgit.ssh.apache", - org.eclipse.jgit.lib;version="5.5.2"; + org.eclipse.jgit.internal.storage.reftree;version="5.6.1";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", + org.eclipse.jgit.internal.submodule;version="5.6.1";x-internal:=true, + org.eclipse.jgit.internal.transport.http;version="5.6.1";x-friends:="org.eclipse.jgit.test", + org.eclipse.jgit.internal.transport.parser;version="5.6.1";x-friends:="org.eclipse.jgit.http.server,org.eclipse.jgit.test", + org.eclipse.jgit.internal.transport.ssh;version="5.6.1";x-friends:="org.eclipse.jgit.ssh.apache", + org.eclipse.jgit.lib;version="5.6.1"; uses:="org.eclipse.jgit.revwalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.util, @@ -99,33 +99,33 @@ Export-Package: org.eclipse.jgit.annotations;version="5.5.2", org.eclipse.jgit.treewalk, org.eclipse.jgit.transport, org.eclipse.jgit.submodule", - org.eclipse.jgit.lib.internal;version="5.5.2";x-internal:=true, - org.eclipse.jgit.merge;version="5.5.2"; + org.eclipse.jgit.lib.internal;version="5.6.1";x-friends:="org.eclipse.jgit.test", + org.eclipse.jgit.merge;version="5.6.1"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.revwalk, org.eclipse.jgit.diff, org.eclipse.jgit.dircache, org.eclipse.jgit.api", - org.eclipse.jgit.nls;version="5.5.2", - org.eclipse.jgit.notes;version="5.5.2"; + org.eclipse.jgit.nls;version="5.6.1", + org.eclipse.jgit.notes;version="5.6.1"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.revwalk, org.eclipse.jgit.merge", - org.eclipse.jgit.patch;version="5.5.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff", - org.eclipse.jgit.revplot;version="5.5.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk", - org.eclipse.jgit.revwalk;version="5.5.2"; + org.eclipse.jgit.patch;version="5.6.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.diff", + org.eclipse.jgit.revplot;version="5.6.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.revwalk", + org.eclipse.jgit.revwalk;version="5.6.1"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.treewalk, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.diff, org.eclipse.jgit.revwalk.filter", - org.eclipse.jgit.revwalk.filter;version="5.5.2";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util", - org.eclipse.jgit.storage.file;version="5.5.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util", - org.eclipse.jgit.storage.pack;version="5.5.2";uses:="org.eclipse.jgit.lib", - org.eclipse.jgit.submodule;version="5.5.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk", - org.eclipse.jgit.transport;version="5.5.2"; + org.eclipse.jgit.revwalk.filter;version="5.6.1";uses:="org.eclipse.jgit.revwalk,org.eclipse.jgit.lib,org.eclipse.jgit.util", + org.eclipse.jgit.storage.file;version="5.6.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.util", + org.eclipse.jgit.storage.pack;version="5.6.1";uses:="org.eclipse.jgit.lib", + org.eclipse.jgit.submodule;version="5.6.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.treewalk.filter,org.eclipse.jgit.treewalk", + org.eclipse.jgit.transport;version="5.6.1"; uses:="org.eclipse.jgit.transport.resolver, org.eclipse.jgit.revwalk, org.eclipse.jgit.internal.storage.pack, @@ -138,24 +138,24 @@ Export-Package: org.eclipse.jgit.annotations;version="5.5.2", org.eclipse.jgit.transport.http, org.eclipse.jgit.errors, org.eclipse.jgit.storage.pack", - org.eclipse.jgit.transport.http;version="5.5.2";uses:="javax.net.ssl", - org.eclipse.jgit.transport.resolver;version="5.5.2";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport", - org.eclipse.jgit.treewalk;version="5.5.2"; + org.eclipse.jgit.transport.http;version="5.6.1";uses:="javax.net.ssl", + org.eclipse.jgit.transport.resolver;version="5.6.1";uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport", + org.eclipse.jgit.treewalk;version="5.6.1"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.revwalk, org.eclipse.jgit.attributes, org.eclipse.jgit.treewalk.filter, org.eclipse.jgit.util, org.eclipse.jgit.dircache", - org.eclipse.jgit.treewalk.filter;version="5.5.2";uses:="org.eclipse.jgit.treewalk", - org.eclipse.jgit.util;version="5.5.2"; + org.eclipse.jgit.treewalk.filter;version="5.6.1";uses:="org.eclipse.jgit.treewalk", + org.eclipse.jgit.util;version="5.6.1"; uses:="org.eclipse.jgit.lib, org.eclipse.jgit.transport.http, org.eclipse.jgit.storage.file, org.ietf.jgss", - org.eclipse.jgit.util.io;version="5.5.2", - org.eclipse.jgit.util.sha1;version="5.5.2", - org.eclipse.jgit.util.time;version="5.5.2" + org.eclipse.jgit.util.io;version="5.6.1", + org.eclipse.jgit.util.sha1;version="5.6.1", + org.eclipse.jgit.util.time;version="5.6.1" Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", com.jcraft.jsch;version="[0.1.37,0.2.0)", @@ -172,6 +172,7 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", org.bouncycastle.openpgp.operator;version="[1.61.0,2.0.0)", org.bouncycastle.openpgp.operator.jcajce;version="[1.61.0,2.0.0)", org.bouncycastle.util.encoders;version="[1.61.0,2.0.0)", + org.bouncycastle.util.io;version="[1.61.0,2.0.0)", org.slf4j;version="[1.7.0,2.0.0)", org.xml.sax, org.xml.sax.helpers diff --git a/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF b/org.eclipse.jgit/META-INF/SOURCE-MANIFEST.MF index 29db604cab..e24b5958a7 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: 5.5.2.qualifier -Eclipse-SourceBundle: org.eclipse.jgit;version="5.5.2.qualifier";roots="." +Bundle-Version: 5.6.1.qualifier +Eclipse-SourceBundle: org.eclipse.jgit;version="5.6.1.qualifier";roots="." diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml index 656d4ff964..cc1b616602 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>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> </parent> <artifactId>org.eclipse.jgit</artifactId> 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 b82512f71b..27d3e6aaa3 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -282,11 +282,13 @@ expectedReceivedContentType=expected Content-Type {0}; received Content-Type {1} expectedReportForRefNotReceived={0}: expected report for ref {1} not received failedAtomicFileCreation=Atomic file creation failed, number of hard links to file {0} was not 2 but {1} failedCreateLockFile=Creating lock file {} failed +failedToConvert=Failed to convert rest: %s failedToDetermineFilterDefinition=An exception occurred while determining filter definitions failedUpdatingRefs=failed updating refs failureDueToOneOfTheFollowing=Failure due to one of the following: failureUpdatingFETCH_HEAD=Failure updating FETCH_HEAD: {0} failureUpdatingTrackingRef=Failure updating tracking ref {0}: {1} +fileAlreadyExists=File already exists: {0} fileCannotBeDeleted=File cannot be deleted: {0} fileIsTooLarge=File is too large: {0} fileModeNotSetForPath=FileMode not set for path {0} @@ -325,6 +327,7 @@ incorrectHashFor=Incorrect hash for {0}; computed {1} as a {2} from {3} bytes. incorrectOBJECT_ID_LENGTH=Incorrect OBJECT_ID_LENGTH. indexFileCorruptedNegativeBucketCount=Invalid negative bucket count read from pack v2 index file: {0} indexFileIsTooLargeForJgit=Index file is too large for jgit +indexNumbersNotIncreasing=index numbers not increasing: ''{0}'': min {1}, last max {2} indexWriteException=Modified index could not be written initFailedBareRepoDifferentDirs=When initializing a bare repo with directory {0} and separate git-dir {1} specified both folders must point to the same location initFailedDirIsNoDirectory=Cannot set directory to ''{0}'' which is not a directory @@ -350,6 +353,7 @@ invalidFilter=Invalid filter: {0} invalidGitdirRef = Invalid .git reference in file ''{0}'' invalidGitModules=Invalid .gitmodules file invalidGitType=invalid git type: {0} +invalidHooksPath=Invalid git config core.hooksPath = {0} invalidId=Invalid id: {0} invalidId0=Invalid id invalidIdLength=Invalid id length {0}; should be {1} @@ -450,8 +454,10 @@ noHMACsupport=No {0} support: {1} noMergeBase=No merge base could be determined. Reason={0}. {1} noMergeHeadSpecified=No merge head specified nonBareLinkFilesNotSupported=Link files are not supported with nonbare repos +nonCommitToHeads=Cannot point a branch to a non-commit object noPathAttributesFound=No Attributes found for {0}. noSuchRef=no such ref +noSuchRefKnown=no such ref: {0} noSuchSubmodule=no such submodule {0} notABoolean=Not a boolean: {0} notABundle=not a bundle @@ -550,7 +556,8 @@ refAlreadyExists=already exists refAlreadyExists1=Ref {0} already exists reflogEntryNotFound=Entry {0} not found in reflog for ''{1}'' refNotResolved=Ref {0} cannot be resolved -refTableRecordsMustIncrease=records must be increasing: last {0}, this {1} +reftableDirExists=reftable dir exists and is nonempty +reftableRecordsMustIncrease=records must be increasing: last {0}, this {1} refUpdateReturnCodeWas=RefUpdate return code was: {0} remoteConfigHasNoURIAssociated=Remote config "{0}" has no URIs associated remoteDoesNotHaveSpec=Remote does not have {0} available for fetch. @@ -579,7 +586,7 @@ repositoryState_conflicts=Conflicts repositoryState_merged=Merged repositoryState_normal=Normal repositoryState_rebase=Rebase -repositoryState_rebaseInteractive=Rebase interactive +repositoryState_rebaseInteractive=Interactive rebase repositoryState_rebaseOrApplyMailbox=Rebase/Apply mailbox repositoryState_rebaseWithMerge=Rebase w/merge requiredHashFunctionNotAvailable=Required hash function {0} not available. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java index f7576e9e9b..a69aa70c6e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, GitHub Inc. + * Copyright (C) 2011, 2019 GitHub Inc. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -42,11 +42,7 @@ */ package org.eclipse.jgit.api; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -56,17 +52,10 @@ import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.blame.BlameGenerator; import org.eclipse.jgit.blame.BlameResult; import org.eclipse.jgit.diff.DiffAlgorithm; -import org.eclipse.jgit.diff.RawText; import org.eclipse.jgit.diff.RawTextComparator; -import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.lib.AnyObjectId; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.CoreConfig.AutoCRLF; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.treewalk.WorkingTreeOptions; -import org.eclipse.jgit.util.IO; -import org.eclipse.jgit.util.io.AutoLFInputStream; /** * Blame command for building a {@link org.eclipse.jgit.blame.BlameResult} for a @@ -221,69 +210,11 @@ public class BlameCommand extends GitCommand<BlameResult> { else if (startCommit != null) gen.push(null, startCommit); else { - gen.push(null, repo.resolve(Constants.HEAD)); - if (!repo.isBare()) { - DirCache dc = repo.readDirCache(); - int entry = dc.findEntry(path); - if (0 <= entry) - gen.push(null, dc.getEntry(entry).getObjectId()); - - File inTree = new File(repo.getWorkTree(), path); - if (repo.getFS().isFile(inTree)) { - RawText rawText = getRawText(inTree); - gen.push(null, rawText); - } - } + gen.prepareHead(); } return gen.computeBlameResult(); } catch (IOException e) { throw new JGitInternalException(e.getMessage(), e); } } - - private RawText getRawText(File inTree) throws IOException, - FileNotFoundException { - RawText rawText; - - WorkingTreeOptions workingTreeOptions = getRepository().getConfig() - .get(WorkingTreeOptions.KEY); - AutoCRLF autoCRLF = workingTreeOptions.getAutoCRLF(); - switch (autoCRLF) { - case FALSE: - case INPUT: - // Git used the repo format on checkout, but other tools - // may change the format to CRLF. We ignore that here. - rawText = new RawText(inTree); - break; - case TRUE: - try (AutoLFInputStream in = new AutoLFInputStream( - new FileInputStream(inTree), true)) { - // Canonicalization should lead to same or shorter length - // (CRLF to LF), so the file size on disk is an upper size bound - rawText = new RawText(toByteArray(in, (int) inTree.length())); - } - break; - default: - throw new IllegalArgumentException( - "Unknown autocrlf option " + autoCRLF); //$NON-NLS-1$ - } - return rawText; - } - - private static byte[] toByteArray(InputStream source, int upperSizeLimit) - throws IOException { - byte[] buffer = new byte[upperSizeLimit]; - try { - int read = IO.readFully(source, buffer, 0); - if (read == upperSizeLimit) - return buffer; - else { - byte[] copy = new byte[read]; - System.arraycopy(buffer, 0, copy, 0, read); - return copy; - } - } finally { - source.close(); - } - } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java index c9dd547b49..aa63725c55 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java @@ -57,6 +57,7 @@ import org.eclipse.jgit.api.errors.UnmergedPathsException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import org.eclipse.jgit.dircache.DirCacheCheckout; import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.events.WorkingTreeModifiedEvent; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; @@ -129,9 +130,10 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> { // get the head commit Ref headRef = repo.exactRef(Constants.HEAD); - if (headRef == null) + if (headRef == null) { throw new NoHeadException( JGitText.get().commitOnRepoWithoutHEADCurrentlyNotSupported); + } newHead = revWalk.parseCommit(headRef.getObjectId()); @@ -140,8 +142,9 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> { // get the commit to be cherry-picked // handle annotated tags ObjectId srcObjectId = src.getPeeledObjectId(); - if (srcObjectId == null) + if (srcObjectId == null) { srcObjectId = src.getObjectId(); + } RevCommit srcCommit = revWalk.parseCommit(srcObjectId); // get the parent of the commit to cherry-pick @@ -157,26 +160,33 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> { merger.setCommitNames(new String[] { "BASE", ourName, //$NON-NLS-1$ cherryPickName }); if (merger.merge(newHead, srcCommit)) { + if (!merger.getModifiedFiles().isEmpty()) { + repo.fireEvent(new WorkingTreeModifiedEvent( + merger.getModifiedFiles(), null)); + } if (AnyObjectId.isEqual(newHead.getTree().getId(), - merger.getResultTreeId())) + merger.getResultTreeId())) { continue; + } DirCacheCheckout dco = new DirCacheCheckout(repo, newHead.getTree(), repo.lockDirCache(), merger.getResultTreeId()); dco.setFailOnConflict(true); dco.setProgressMonitor(monitor); dco.checkout(); - if (!noCommit) + if (!noCommit) { newHead = new Git(getRepository()).commit() .setMessage(srcCommit.getFullMessage()) .setReflogComment(reflogPrefix + " " //$NON-NLS-1$ + srcCommit.getShortMessage()) .setAuthor(srcCommit.getAuthorIdent()) .setNoVerify(true).call(); + } cherryPickedRefs.add(src); } else { - if (merger.failed()) + if (merger.failed()) { return new CherryPickResult(merger.getFailingPaths()); + } // there are merge conflicts @@ -184,10 +194,14 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> { .formatWithConflicts(srcCommit.getFullMessage(), merger.getUnmergedPaths()); - if (!noCommit) + if (!noCommit) { repo.writeCherryPickHead(srcCommit.getId()); + } repo.writeMergeCommitMsg(message); + repo.fireEvent(new WorkingTreeModifiedEvent( + merger.getModifiedFiles(), null)); + return CherryPickResult.CONFLICT; } } @@ -213,10 +227,11 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> { Integer.valueOf(srcCommit.getParentCount()))); srcParent = srcCommit.getParent(0); } else { - if (mainlineParentNumber.intValue() > srcCommit.getParentCount()) + if (mainlineParentNumber.intValue() > srcCommit.getParentCount()) { throw new JGitInternalException(MessageFormat.format( JGitText.get().commitDoesNotHaveGivenParent, srcCommit, mainlineParentNumber)); + } srcParent = srcCommit .getParent(mainlineParentNumber.intValue() - 1); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java index 9f63d0f005..809f2d111a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java @@ -77,8 +77,8 @@ import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.TagOpt; import org.eclipse.jgit.transport.URIish; -import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.FileUtils; /** * Clone a repository into a new working directory @@ -104,7 +104,7 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { private ProgressMonitor monitor = NullProgressMonitor.INSTANCE; - private boolean cloneAllBranches; + private FETCH_TYPE fetchType = FETCH_TYPE.ALL_BRANCHES; private boolean cloneSubmodules; @@ -118,6 +118,10 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { private boolean gitDirExistsInitially; + private enum FETCH_TYPE { + MULTIPLE_BRANCHES, ALL_BRANCHES, MIRROR + } + /** * Callback for status of clone operation. * @@ -282,12 +286,11 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { RemoteConfig config = new RemoteConfig(clonedRepo.getConfig(), remote); config.addURI(u); - final String dst = (bare ? Constants.R_HEADS : Constants.R_REMOTES - + config.getName() + '/') + '*'; - boolean fetchAll = cloneAllBranches || branchesToClone == null - || branchesToClone.isEmpty(); + boolean fetchAll = fetchType == FETCH_TYPE.ALL_BRANCHES + || fetchType == FETCH_TYPE.MIRROR; - config.setFetchRefSpecs(calculateRefSpecs(fetchAll, dst)); + config.setFetchRefSpecs(calculateRefSpecs(fetchType, config.getName())); + config.setMirror(fetchType == FETCH_TYPE.MIRROR); config.update(clonedRepo.getConfig()); clonedRepo.getConfig().save(); @@ -302,26 +305,33 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { return command.call(); } - private List<RefSpec> calculateRefSpecs(boolean fetchAll, String dst) { - RefSpec heads = new RefSpec(); - heads = heads.setForceUpdate(true); - heads = heads.setSourceDestination(Constants.R_HEADS + '*', dst); + private List<RefSpec> calculateRefSpecs(FETCH_TYPE type, + String remoteName) { List<RefSpec> specs = new ArrayList<>(); - if (!fetchAll) { - RefSpec tags = new RefSpec(); - tags = tags.setForceUpdate(true); - tags = tags.setSourceDestination(Constants.R_TAGS + '*', - Constants.R_TAGS + '*'); - for (String selectedRef : branchesToClone) { - if (heads.matchSource(selectedRef)) { - specs.add(heads.expandFromSource(selectedRef)); - } else if (tags.matchSource(selectedRef)) { - specs.add(tags.expandFromSource(selectedRef)); + if (type == FETCH_TYPE.MIRROR) { + specs.add(new RefSpec().setForceUpdate(true).setSourceDestination( + Constants.R_REFS + '*', Constants.R_REFS + '*')); + } else { + RefSpec heads = new RefSpec(); + heads = heads.setForceUpdate(true); + final String dst = (bare ? Constants.R_HEADS + : Constants.R_REMOTES + remoteName + '/') + '*'; + heads = heads.setSourceDestination(Constants.R_HEADS + '*', dst); + if (type == FETCH_TYPE.MULTIPLE_BRANCHES) { + RefSpec tags = new RefSpec().setForceUpdate(true) + .setSourceDestination(Constants.R_TAGS + '*', + Constants.R_TAGS + '*'); + for (String selectedRef : branchesToClone) { + if (heads.matchSource(selectedRef)) { + specs.add(heads.expandFromSource(selectedRef)); + } else if (tags.matchSource(selectedRef)) { + specs.add(tags.expandFromSource(selectedRef)); + } } + } else { + // We'll fetch the tags anyway. + specs.add(heads); } - } else { - // We'll fetch the tags anyway. - specs.add(heads); } return specs; } @@ -609,7 +619,31 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { * @return {@code this} */ public CloneCommand setCloneAllBranches(boolean cloneAllBranches) { - this.cloneAllBranches = cloneAllBranches; + this.fetchType = cloneAllBranches ? FETCH_TYPE.ALL_BRANCHES + : this.fetchType; + return this; + } + + /** + * Set up a mirror of the source repository. This implies that a bare + * repository will be created. Compared to {@link #setBare}, + * {@code #setMirror} not only maps local branches of the source to local + * branches of the target, it maps all refs (including remote-tracking + * branches, notes etc.) and sets up a refspec configuration such that all + * these refs are overwritten by a git remote update in the target + * repository. + * + * @param mirror + * whether to mirror all refs from the source repository + * + * @return {@code this} + * @since 5.6 + */ + public CloneCommand setMirror(boolean mirror) { + if (mirror) { + this.fetchType = FETCH_TYPE.MIRROR; + setBare(true); + } return this; } @@ -641,7 +675,13 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { * @return {@code this} */ public CloneCommand setBranchesToClone(Collection<String> branchesToClone) { - this.branchesToClone = branchesToClone; + if (branchesToClone == null || branchesToClone.isEmpty()) { + // fallback to default + fetchType = FETCH_TYPE.ALL_BRANCHES; + } else { + this.fetchType = FETCH_TYPE.MULTIPLE_BRANCHES; + this.branchesToClone = branchesToClone; + } return this; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java index b55987ead4..915b9860bb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java @@ -143,6 +143,8 @@ public class CommitCommand extends GitCommand<RevCommit> { private HashMap<String, PrintStream> hookOutRedirect = new HashMap<>(3); + private HashMap<String, PrintStream> hookErrRedirect = new HashMap<>(3); + private Boolean allowEmpty; private Boolean signCommit; @@ -188,7 +190,8 @@ public class CommitCommand extends GitCommand<RevCommit> { state.name())); if (!noVerify) { - Hooks.preCommit(repo, hookOutRedirect.get(PreCommitHook.NAME)) + Hooks.preCommit(repo, hookOutRedirect.get(PreCommitHook.NAME), + hookErrRedirect.get(PreCommitHook.NAME)) .call(); } @@ -230,7 +233,8 @@ public class CommitCommand extends GitCommand<RevCommit> { if (!noVerify) { message = Hooks .commitMsg(repo, - hookOutRedirect.get(CommitMsgHook.NAME)) + hookOutRedirect.get(CommitMsgHook.NAME), + hookErrRedirect.get(CommitMsgHook.NAME)) .setCommitMessage(message).call(); } @@ -311,7 +315,8 @@ public class CommitCommand extends GitCommand<RevCommit> { repo.writeRevertHead(null); } Hooks.postCommit(repo, - hookOutRedirect.get(PostCommitHook.NAME)).call(); + hookOutRedirect.get(PostCommitHook.NAME), + hookErrRedirect.get(PostCommitHook.NAME)).call(); return revCommit; } @@ -891,6 +896,23 @@ public class CommitCommand extends GitCommand<RevCommit> { } /** + * Set the error stream for all hook scripts executed by this command + * (pre-commit, commit-msg, post-commit). If not set it defaults to + * {@code System.err}. + * + * @param hookStdErr + * the error stream for hook scripts executed by this command + * @return {@code this} + * @since 5.6 + */ + public CommitCommand setHookErrorStream(PrintStream hookStdErr) { + setHookErrorStream(PreCommitHook.NAME, hookStdErr); + setHookErrorStream(CommitMsgHook.NAME, hookStdErr); + setHookErrorStream(PostCommitHook.NAME, hookStdErr); + return this; + } + + /** * Set the output stream for a selected hook script executed by this command * (pre-commit, commit-msg, post-commit). If not set it defaults to * {@code System.out}. @@ -916,6 +938,30 @@ public class CommitCommand extends GitCommand<RevCommit> { } /** + * Set the error stream for a selected hook script executed by this command + * (pre-commit, commit-msg, post-commit). If not set it defaults to + * {@code System.err}. + * + * @param hookName + * name of the hook to set the output stream for + * @param hookStdErr + * the output stream to use for the selected hook + * @return {@code this} + * @since 5.6 + */ + public CommitCommand setHookErrorStream(String hookName, + PrintStream hookStdErr) { + if (!(PreCommitHook.NAME.equals(hookName) + || CommitMsgHook.NAME.equals(hookName) + || PostCommitHook.NAME.equals(hookName))) { + throw new IllegalArgumentException(MessageFormat + .format(JGitText.get().illegalHookName, hookName)); + } + hookErrRedirect.put(hookName, hookStdErr); + return this; + } + + /** * Sets the signing key * <p> * Per spec of user.signingKey: this will be sent to the GPG program as is, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java index f65b5735de..1c3c79041e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java @@ -136,28 +136,32 @@ public class DiffCommand extends GitCommand<List<DiffEntry>> { } newTree = new DirCacheIterator(repo.readDirCache()); } else { - if (oldTree == null) + if (oldTree == null) { oldTree = new DirCacheIterator(repo.readDirCache()); - if (newTree == null) + } + if (newTree == null) { newTree = new FileTreeIterator(repo); + } } diffFmt.setPathFilter(pathFilter); List<DiffEntry> result = diffFmt.scan(oldTree, newTree); - if (showNameAndStatusOnly) - return result; - else { - if (contextLines >= 0) - diffFmt.setContext(contextLines); - if (destinationPrefix != null) - diffFmt.setNewPrefix(destinationPrefix); - if (sourcePrefix != null) - diffFmt.setOldPrefix(sourcePrefix); - diffFmt.format(result); - diffFmt.flush(); + if (showNameAndStatusOnly) { return result; } + if (contextLines >= 0) { + diffFmt.setContext(contextLines); + } + if (destinationPrefix != null) { + diffFmt.setNewPrefix(destinationPrefix); + } + if (sourcePrefix != null) { + diffFmt.setOldPrefix(sourcePrefix); + } + diffFmt.format(result); + diffFmt.flush(); + return result; } catch (IOException e) { throw new JGitInternalException(e.getMessage(), e); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java index 2c9c5f20cc..9020c58d46 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/FetchCommand.java @@ -360,17 +360,17 @@ public class FetchCommand extends TransportCommand<FetchCommand, FetchResult> { * @return whether to remove refs which no longer exist in the source */ public boolean isRemoveDeletedRefs() { - if (removeDeletedRefs != null) + if (removeDeletedRefs != null) { return removeDeletedRefs.booleanValue(); - else { // fall back to configuration - boolean result = false; - StoredConfig config = repo.getConfig(); - result = config.getBoolean(ConfigConstants.CONFIG_FETCH_SECTION, - null, ConfigConstants.CONFIG_KEY_PRUNE, result); - result = config.getBoolean(ConfigConstants.CONFIG_REMOTE_SECTION, - remote, ConfigConstants.CONFIG_KEY_PRUNE, result); - return result; } + // fall back to configuration + boolean result = false; + StoredConfig config = repo.getConfig(); + result = config.getBoolean(ConfigConstants.CONFIG_FETCH_SECTION, null, + ConfigConstants.CONFIG_KEY_PRUNE, result); + result = config.getBoolean(ConfigConstants.CONFIG_REMOTE_SECTION, + remote, ConfigConstants.CONFIG_KEY_PRUNE, result); + return result; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java index 7ea277157d..474e2f5736 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/GarbageCollectCommand.java @@ -243,9 +243,8 @@ public class GarbageCollectCommand extends GitCommand<Properties> { if (repo instanceof FileRepository) { GC gc = new GC((FileRepository) repo); return toProperties(gc.getStatistics()); - } else { - return new Properties(); } + return new Properties(); } catch (IOException e) { throw new JGitInternalException( JGitText.get().couldNotGetRepoStatistics, e); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java index 66de8ae131..5ea6015afa 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java @@ -64,10 +64,7 @@ import org.eclipse.jgit.revwalk.filter.AndRevFilter; import org.eclipse.jgit.revwalk.filter.MaxCountRevFilter; import org.eclipse.jgit.revwalk.filter.RevFilter; import org.eclipse.jgit.revwalk.filter.SkipRevFilter; -import org.eclipse.jgit.treewalk.filter.AndTreeFilter; -import org.eclipse.jgit.treewalk.filter.PathFilter; -import org.eclipse.jgit.treewalk.filter.PathFilterGroup; -import org.eclipse.jgit.treewalk.filter.TreeFilter; +import org.eclipse.jgit.treewalk.filter.*; /** * A class used to execute a {@code Log} command. It has setters for all @@ -105,6 +102,7 @@ public class LogCommand extends GitCommand<Iterable<RevCommit>> { private RevFilter revFilter; private final List<PathFilter> pathFilters = new ArrayList<>(); + private final List<TreeFilter> excludeTreeFilters = new ArrayList<>(); private int maxCount = -1; @@ -133,9 +131,22 @@ public class LogCommand extends GitCommand<Iterable<RevCommit>> { @Override public Iterable<RevCommit> call() throws GitAPIException, NoHeadException { checkCallable(); - if (!pathFilters.isEmpty()) - walk.setTreeFilter(AndTreeFilter.create( - PathFilterGroup.create(pathFilters), TreeFilter.ANY_DIFF)); + List<TreeFilter> filters = new ArrayList<>(); + if (!pathFilters.isEmpty()) { + filters.add(AndTreeFilter.create(PathFilterGroup.create(pathFilters), TreeFilter.ANY_DIFF)); + } + if (!excludeTreeFilters.isEmpty()) { + for (TreeFilter f : excludeTreeFilters) { + filters.add(AndTreeFilter.create(f, TreeFilter.ANY_DIFF)); + } + } + if (!filters.isEmpty()) { + if (filters.size() == 1) { + filters.add(TreeFilter.ANY_DIFF); + } + walk.setTreeFilter(AndTreeFilter.create(filters)); + + } if (skip > -1 && maxCount > -1) walk.setRevFilter(AndRevFilter.create(SkipRevFilter.create(skip), MaxCountRevFilter.create(maxCount))); @@ -310,6 +321,24 @@ public class LogCommand extends GitCommand<Iterable<RevCommit>> { } /** + * Show all commits that are not within any of the specified paths. The path + * must either name a file or a directory exactly and use <code>/</code> + * (slash) as separator. Note that regular expressions or wildcards are not + * yet supported. If a path is both added and excluded from the search, then + * the exclusion wins. + * + * @param path + * a repository-relative path (with <code>/</code> as separator) + * @return {@code this} + * @since 5.6 + */ + public LogCommand excludePath(String path) { + checkCallable(); + excludeTreeFilters.add(PathFilter.create(path).negate()); + return this; + } + + /** * Skip the number of commits before starting to show the commit output. * * @param skip diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java index f9a9baf919..9a843f63a0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java @@ -409,27 +409,24 @@ public class MergeCommand extends GitCommand<MergeResult> { new ObjectId[] { headCommit.getId(), srcCommit.getId() }, mergeStatus, mergeStrategy, null, msg); - } else { - if (failingPaths != null) { - repo.writeMergeCommitMsg(null); - repo.writeMergeHeads(null); - return new MergeResult(null, merger.getBaseCommitId(), - new ObjectId[] { - headCommit.getId(), srcCommit.getId() }, - MergeStatus.FAILED, mergeStrategy, - lowLevelResults, failingPaths, null); - } else { - String mergeMessageWithConflicts = new MergeMessageFormatter() - .formatWithConflicts(mergeMessage, - unmergedPaths); - repo.writeMergeCommitMsg(mergeMessageWithConflicts); - return new MergeResult(null, merger.getBaseCommitId(), - new ObjectId[] { headCommit.getId(), - srcCommit.getId() }, - MergeStatus.CONFLICTING, mergeStrategy, - lowLevelResults, null); - } } + if (failingPaths != null) { + repo.writeMergeCommitMsg(null); + repo.writeMergeHeads(null); + return new MergeResult(null, merger.getBaseCommitId(), + new ObjectId[] { headCommit.getId(), + srcCommit.getId() }, + MergeStatus.FAILED, mergeStrategy, lowLevelResults, + failingPaths, null); + } + String mergeMessageWithConflicts = new MergeMessageFormatter() + .formatWithConflicts(mergeMessage, unmergedPaths); + repo.writeMergeCommitMsg(mergeMessageWithConflicts); + return new MergeResult(null, merger.getBaseCommitId(), + new ObjectId[] { headCommit.getId(), + srcCommit.getId() }, + MergeStatus.CONFLICTING, mergeStrategy, lowLevelResults, + null); } } catch (org.eclipse.jgit.errors.CheckoutConflictException e) { List<String> conflicts = (dco == null) ? Collections diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java index bdb2d1bbc5..834b68d6d0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java @@ -315,23 +315,24 @@ public class PullCommand extends TransportCommand<PullCommand, PullResult> { Ref r = null; if (fetchRes != null) { r = fetchRes.getAdvertisedRef(remoteBranchName); - if (r == null) + if (r == null) { r = fetchRes.getAdvertisedRef(Constants.R_HEADS + remoteBranchName); + } } if (r == null) { throw new RefNotAdvertisedException(MessageFormat.format( JGitText.get().couldNotGetAdvertisedRef, remote, remoteBranchName)); - } else { - commitToMerge = r.getObjectId(); } + commitToMerge = r.getObjectId(); } else { try { commitToMerge = repo.resolve(remoteBranchName); - if (commitToMerge == null) + if (commitToMerge == null) { throw new RefNotFoundException(MessageFormat.format( JGitText.get().refNotResolved, remoteBranchName)); + } } catch (IOException e) { throw new JGitInternalException( JGitText.get().exceptionCaughtDuringExecutionOfPullCommand, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java index 0dacd4dfbf..715d9768d8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java @@ -509,10 +509,10 @@ public class RebaseCommand extends GitCommand<RebaseResult> { monitor.beginTask(MessageFormat.format( JGitText.get().applyingCommit, commitToPick.getShortMessage()), ProgressMonitor.UNKNOWN); - if (preserveMerges) + if (preserveMerges) { return cherryPickCommitPreservingMerges(commitToPick); - else - return cherryPickCommitFlattening(commitToPick); + } + return cherryPickCommitFlattening(commitToPick); } finally { monitor.endTask(); } @@ -539,11 +539,11 @@ public class RebaseCommand extends GitCommand<RebaseResult> { .call(); switch (cherryPickResult.getStatus()) { case FAILED: - if (operation == Operation.BEGIN) + if (operation == Operation.BEGIN) { return abort(RebaseResult .failed(cherryPickResult.getFailingPaths())); - else - return stop(commitToPick, Status.STOPPED); + } + return stop(commitToPick, Status.STOPPED); case CONFLICTING: return stop(commitToPick, Status.STOPPED); case OK: @@ -599,11 +599,11 @@ public class RebaseCommand extends GitCommand<RebaseResult> { CherryPickResult cherryPickResult = pickCommand.call(); switch (cherryPickResult.getStatus()) { case FAILED: - if (operation == Operation.BEGIN) + if (operation == Operation.BEGIN) { return abort(RebaseResult.failed( cherryPickResult.getFailingPaths())); - else - return stop(commitToPick, Status.STOPPED); + } + return stop(commitToPick, Status.STOPPED); case CONFLICTING: return stop(commitToPick, Status.STOPPED); case OK: diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java index d7c9ad5e04..3031a197a8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java @@ -334,10 +334,10 @@ public class ResetCommand extends GitCommand<Ref> { } private String getRefOrHEAD() { - if (ref != null) + if (ref != null) { return ref; - else - return Constants.HEAD; + } + return Constants.HEAD; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java index ddd60b6fa2..aa0055fb53 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java @@ -58,6 +58,7 @@ import org.eclipse.jgit.api.errors.NoMessageException; import org.eclipse.jgit.api.errors.UnmergedPathsException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import org.eclipse.jgit.dircache.DirCacheCheckout; +import org.eclipse.jgit.events.WorkingTreeModifiedEvent; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; @@ -175,6 +176,10 @@ public class RevertCommand extends GitCommand<RevCommit> { + "This reverts commit " + srcCommit.getId().getName() //$NON-NLS-1$ + ".\n"; //$NON-NLS-1$ if (merger.merge(headCommit, srcParent)) { + if (!merger.getModifiedFiles().isEmpty()) { + repo.fireEvent(new WorkingTreeModifiedEvent( + merger.getModifiedFiles(), null)); + } if (AnyObjectId.isEqual(headCommit.getTree().getId(), merger.getResultTreeId())) continue; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java index 52393695d9..74def9e897 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java @@ -106,10 +106,10 @@ public class SubmoduleSyncCommand extends GitCommand<Map<String, String>> { */ protected String getHeadBranch(Repository subRepo) throws IOException { Ref head = subRepo.exactRef(Constants.HEAD); - if (head != null && head.isSymbolic()) + if (head != null && head.isSymbolic()) { return Repository.shortenRefName(head.getLeaf().getName()); - else - return null; + } + return null; } /** {@inheritDoc} */ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/AbortedByHookException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/AbortedByHookException.java index db6440b55f..30a2d622a7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/AbortedByHookException.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/AbortedByHookException.java @@ -67,19 +67,26 @@ public class AbortedByHookException extends GitAPIException { private final int returnCode; /** + * The stderr output of the hook. + */ + private final String hookStdErr; + + /** * Constructor for AbortedByHookException * - * @param message - * The error details. + * @param hookStdErr + * The error details from the stderr output of the hook * @param hookName * The name of the hook that interrupted the command, must not be * null. * @param returnCode * The return code of the hook process that has been run. */ - public AbortedByHookException(String message, String hookName, + public AbortedByHookException(String hookStdErr, String hookName, int returnCode) { - super(message); + super(MessageFormat.format(JGitText.get().commandRejectedByHook, + hookName, hookStdErr)); + this.hookStdErr = hookStdErr; this.hookName = hookName; this.returnCode = returnCode; } @@ -102,10 +109,13 @@ public class AbortedByHookException extends GitAPIException { return returnCode; } - /** {@inheritDoc} */ - @Override - public String getMessage() { - return MessageFormat.format(JGitText.get().commandRejectedByHook, - hookName, super.getMessage()); + /** + * Get the stderr output of the hook. + * + * @return A string containing the complete stderr output of the hook. + * @since 5.6 + */ + public String getHookStdErr() { + return hookStdErr; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java index 9cec645679..d0aa292df4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, Google Inc. + * Copyright (C) 2011, 2019 Google Inc. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -48,11 +48,17 @@ import static org.eclipse.jgit.lib.FileMode.TYPE_FILE; import static org.eclipse.jgit.lib.FileMode.TYPE_MASK; import java.io.IOException; +import java.io.InputStream; +import java.text.MessageFormat; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.blame.Candidate.BlobCandidate; +import org.eclipse.jgit.blame.Candidate.HeadCandidate; import org.eclipse.jgit.blame.Candidate.ReverseCandidate; import org.eclipse.jgit.blame.ReverseWalk.ReverseCommit; import org.eclipse.jgit.diff.DiffAlgorithm; @@ -63,8 +69,13 @@ import org.eclipse.jgit.diff.HistogramDiff; import org.eclipse.jgit.diff.RawText; import org.eclipse.jgit.diff.RawTextComparator; import org.eclipse.jgit.diff.RenameDetector; +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.dircache.DirCacheIterator; +import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.MutableObjectId; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; @@ -74,9 +85,12 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevFlag; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.TreeWalk.OperationType; import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.treewalk.filter.TreeFilter; +import org.eclipse.jgit.util.IO; /** * Generate author information for lines based on a provided file. @@ -313,6 +327,107 @@ public class BlameGenerator implements AutoCloseable { } /** + * Pushes HEAD, index, and working tree as appropriate for blaming the file + * given in the constructor {@link #BlameGenerator(Repository, String)} + * against HEAD. Includes special handling in case the file is in conflict + * state from an unresolved merge conflict. + * + * @return {@code this} + * @throws NoHeadException + * if the repository has no HEAD + * @throws IOException + * if an error occurs + * @since 5.6 + */ + public BlameGenerator prepareHead() throws NoHeadException, IOException { + Repository repo = getRepository(); + ObjectId head = repo.resolve(Constants.HEAD); + if (head == null) { + throw new NoHeadException(MessageFormat + .format(JGitText.get().noSuchRefKnown, Constants.HEAD)); + } + if (repo.isBare()) { + return push(null, head); + } + DirCache dc = repo.readDirCache(); + try (TreeWalk walk = new TreeWalk(repo)) { + walk.setOperationType(OperationType.CHECKIN_OP); + FileTreeIterator iter = new FileTreeIterator(repo); + int fileTree = walk.addTree(iter); + int indexTree = walk.addTree(new DirCacheIterator(dc)); + iter.setDirCacheIterator(walk, indexTree); + walk.setFilter(resultPath); + walk.setRecursive(true); + if (!walk.next()) { + return this; + } + DirCacheIterator dcIter = walk.getTree(indexTree, + DirCacheIterator.class); + if (dcIter == null) { + // Not found in index + return this; + } + iter = walk.getTree(fileTree, FileTreeIterator.class); + if (iter == null || !isFile(iter.getEntryRawMode())) { + return this; + } + RawText inTree; + long filteredLength = iter.getEntryContentLength(); + try (InputStream stream = iter.openEntryStream()) { + inTree = new RawText(getBytes(iter.getEntryFile().getPath(), + stream, filteredLength)); + } + DirCacheEntry indexEntry = dcIter.getDirCacheEntry(); + if (indexEntry.getStage() == DirCacheEntry.STAGE_0) { + push(null, head); + push(null, indexEntry.getObjectId()); + push(null, inTree); + } else { + // Create a special candidate using the working tree file as + // blob and HEAD and the MERGE_HEADs as parents. + HeadCandidate c = new HeadCandidate(getRepository(), resultPath, + getHeads(repo, head)); + c.sourceText = inTree; + c.regionList = new Region(0, 0, inTree.size()); + remaining = inTree.size(); + push(c); + } + } + return this; + } + + private List<RevCommit> getHeads(Repository repo, ObjectId head) + throws NoWorkTreeException, IOException { + List<ObjectId> mergeIds = repo.readMergeHeads(); + if (mergeIds == null || mergeIds.isEmpty()) { + return Collections.singletonList(revPool.parseCommit(head)); + } + List<RevCommit> heads = new ArrayList<>(mergeIds.size() + 1); + heads.add(revPool.parseCommit(head)); + for (ObjectId id : mergeIds) { + heads.add(revPool.parseCommit(id)); + } + return heads; + } + + private static byte[] getBytes(String path, InputStream in, long maxLength) + throws IOException { + if (maxLength > Integer.MAX_VALUE) { + throw new IOException( + MessageFormat.format(JGitText.get().fileIsTooLarge, path)); + } + int max = (int) maxLength; + byte[] buffer = new byte[max]; + int read = IO.readFully(in, buffer, 0); + if (read == max) { + return buffer; + } + byte[] copy = new byte[read]; + System.arraycopy(buffer, 0, copy, 0, read); + return copy; + } + + /** * Push a candidate object onto the generator's traversal stack. * <p> * Candidates should be pushed in history order from oldest-to-newest. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java index 5fb77501fa..394aba6a59 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameResult.java @@ -267,18 +267,18 @@ public class BlameResult { */ public int computeNext() throws IOException { BlameGenerator gen = generator; - if (gen == null) + if (gen == null) { return -1; + } if (gen.next()) { loadFrom(gen); lastLength = gen.getRegionLength(); return gen.getResultStart(); - } else { - gen.close(); - generator = null; - return -1; } + gen.close(); + generator = null; + return -1; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/Candidate.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/Candidate.java index 457d1d2cea..3ef4943982 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/Candidate.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/Candidate.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, Google Inc. + * Copyright (C) 2011, 2019 Google Inc. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -44,12 +44,14 @@ package org.eclipse.jgit.blame; import java.io.IOException; +import java.util.List; import org.eclipse.jgit.blame.ReverseWalk.ReverseCommit; import org.eclipse.jgit.diff.Edit; import org.eclipse.jgit.diff.EditList; import org.eclipse.jgit.diff.RawText; import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; @@ -392,6 +394,66 @@ class Candidate { } /** + * A {@link Candidate} to blame a working tree file in conflict state. + * <p> + * Contrary to {@link BlobCandidate}, it expects to be given the parent + * commits (typically HEAD and the MERGE_HEADs) and behaves like a merge + * commit during blame. It does <em>not</em> consider a previously pushed + * Candidate as its parent. + * </p> + */ + static final class HeadCandidate extends Candidate { + + private List<RevCommit> parents; + + HeadCandidate(Repository repo, PathFilter path, + List<RevCommit> parents) { + super(repo, null, path); + this.parents = parents; + } + + @Override + void beginResult(RevWalk rw) { + // Blob candidates have nothing to prepare. + } + + @Override + int getParentCount() { + return parents.size(); + } + + @Override + RevCommit getParent(int idx) { + return parents.get(idx); + } + + @Override + boolean has(RevFlag flag) { + return true; // Pretend flag was added; sourceCommit is null. + } + + @Override + void add(RevFlag flag) { + // Do nothing, sourceCommit is null. + } + + @Override + void remove(RevFlag flag) { + // Do nothing, sourceCommit is null. + } + + @Override + int getTime() { + return Integer.MAX_VALUE; + } + + @Override + PersonIdent getAuthor() { + return new PersonIdent(JGitText.get().blameNotCommittedYet, ""); //$NON-NLS-1$ + } + } + + /** * Candidate loaded from a file source, and not a commit. * <p> * The {@link Candidate#sourceCommit} field is always null on this type of diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java index 1cecff6fb0..d764499159 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java @@ -145,6 +145,8 @@ public class DiffFormatter implements AutoCloseable { private Repository repository; + private Boolean quotePaths; + /** * Create a new formatter with a default level of context. * @@ -199,6 +201,11 @@ public class DiffFormatter implements AutoCloseable { this.closeReader = closeReader; this.reader = reader; this.diffCfg = cfg.get(DiffConfig.KEY); + if (quotePaths == null) { + quotePaths = Boolean + .valueOf(cfg.getBoolean(ConfigConstants.CONFIG_CORE_SECTION, + ConfigConstants.CONFIG_KEY_QUOTE_PATH, true)); + } ContentSource cs = ContentSource.create(reader); source = new ContentSource.Pair(cs, cs); @@ -379,6 +386,21 @@ public class DiffFormatter implements AutoCloseable { } /** + * Sets whether or not path names should be quoted. + * <p> + * By default the setting of git config {@code core.quotePath} is active, + * but this can be overridden through this method. + * </p> + * + * @param quote + * whether to quote path names + * @since 5.6 + */ + public void setQuotePaths(boolean quote) { + quotePaths = Boolean.valueOf(quote); + } + + /** * Set the filter to produce only specific paths. * * If the filter is an instance of @@ -489,8 +511,8 @@ public class DiffFormatter implements AutoCloseable { CanonicalTreeParser parser = new CanonicalTreeParser(); parser.reset(reader, tree); return parser; - } else - return new EmptyTreeIterator(); + } + return new EmptyTreeIterator(); } /** @@ -726,8 +748,11 @@ public class DiffFormatter implements AutoCloseable { return id.name(); } - private static String quotePath(String name) { - return QuotedString.GIT_PATH.quote(name); + private String quotePath(String path) { + if (quotePaths == null || quotePaths.booleanValue()) { + return QuotedString.GIT_PATH.quote(path); + } + return QuotedString.GIT_PATH_MINIMAL.quote(path); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/Edit.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/Edit.java index 5c876e87fd..831074d2e1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/Edit.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/Edit.java @@ -125,17 +125,17 @@ public class Edit { */ public final Type getType() { if (beginA < endA) { - if (beginB < endB) + if (beginB < endB) { return Type.REPLACE; - else /* if (beginB == endB) */ - return Type.DELETE; - - } else /* if (beginA == endA) */{ - if (beginB < endB) - return Type.INSERT; - else /* if (beginB == endB) */ - return Type.EMPTY; + } + return Type.DELETE; + + } + if (beginB < endB) { + return Type.INSERT; } + // beginB == endB) + return Type.EMPTY; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java index 6c0d90ebad..219da0e9b9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java @@ -383,15 +383,17 @@ public class RawText extends Sequence { * @return the line delimiter or <code>null</code> */ public String getLineDelimiter() { - if (size() == 0) + if (size() == 0) { return null; + } int e = getEnd(0); - if (content[e - 1] != '\n') + if (content[e - 1] != '\n') { return null; - if (content.length > 1 && e > 1 && content[e - 2] == '\r') + } + if (content.length > 1 && e > 1 && content[e - 2] == '\r') { return "\r\n"; //$NON-NLS-1$ - else - return "\n"; //$NON-NLS-1$ + } + return "\n"; //$NON-NLS-1$ } /** 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 6bc2946078..bbaed3766e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -53,9 +53,11 @@ import java.text.MessageFormat; import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import org.eclipse.jgit.api.errors.CanceledException; import org.eclipse.jgit.api.errors.FilterFailedException; @@ -142,6 +144,8 @@ public class DirCacheCheckout { private ArrayList<String> removed = new ArrayList<>(); + private ArrayList<String> kept = new ArrayList<>(); + private ObjectId mergeCommitTree; private DirCache dc; @@ -432,11 +436,11 @@ public class DirCacheCheckout { if (mtime == null || mtime.equals(Instant.EPOCH)) { entry.setLastModified(f.getEntryLastModifiedInstant()); } - keep(entry, f); + keep(i.getEntryPathString(), entry, f); } } else // The index contains a folder - keep(i.getDirCacheEntry(), f); + keep(i.getEntryPathString(), i.getDirCacheEntry(), f); } else { // There is no entry in the merge commit. Means: we want to delete // what's currently in the index and working tree @@ -496,8 +500,11 @@ public class DirCacheCheckout { dc.unlock(); } finally { if (performingCheckout) { + Set<String> touched = new HashSet<>(conflicts); + touched.addAll(getUpdated().keySet()); + touched.addAll(kept); WorkingTreeModifiedEvent event = new WorkingTreeModifiedEvent( - getUpdated().keySet(), getRemoved()); + touched, getRemoved()); if (!event.isEmpty()) { repo.fireEvent(event); } @@ -517,10 +524,10 @@ public class DirCacheCheckout { prescanOneTree(); if (!conflicts.isEmpty()) { - if (failOnConflict) + if (failOnConflict) { throw new CheckoutConflictException(conflicts.toArray(new String[0])); - else - cleanUpConflicts(); + } + cleanUpConflicts(); } // update our index @@ -826,14 +833,14 @@ public class DirCacheCheckout { break; case 0xDFD: // 3 4 - keep(dce, f); + keep(name, dce, f); break; case 0xF0D: // 18 remove(name); break; case 0xDFF: // 5 5b 6 6b if (equalIdAndMode(iId, iMode, mId, mMode)) - keep(dce, f); // 5 6 + keep(name, dce, f); // 5 6 else conflict(name, dce, h, m); // 5b 6b break; @@ -863,7 +870,7 @@ public class DirCacheCheckout { conflict(name, dce, h, m); // 9 break; case 0xFD0: // keep without a rule - keep(dce, f); + keep(name, dce, f); break; case 0xFFD: // 12 13 14 if (equalIdAndMode(hId, hMode, iId, iMode)) @@ -883,7 +890,7 @@ public class DirCacheCheckout { conflict(name, dce, h, m); break; default: - keep(dce, f); + keep(name, dce, f); } return; } @@ -895,15 +902,14 @@ public class DirCacheCheckout { // the workingtree entry doesn't exist or also contains a folder // -> no problem return; - } else { - // the workingtree entry exists and is not a folder - if (!idEqual(h, m)) { - // Because HEAD and MERGE differ we will try to update the - // workingtree with a folder -> return a conflict - conflict(name, null, null, null); - } - return; } + // the workingtree entry exists and is not a folder + if (!idEqual(h, m)) { + // Because HEAD and MERGE differ we will try to update the + // workingtree with a folder -> return a conflict + conflict(name, null, null, null); + } + return; } if ((ffMask == 0x00F) && f != null && FileMode.TREE.equals(f.getEntryFileMode())) { @@ -969,7 +975,7 @@ public class DirCacheCheckout { if (initialCheckout) update(name, mId, mMode); else - keep(dce, f); + keep(name, dce, f); } else conflict(name, dce, h, m); } @@ -1032,7 +1038,7 @@ public class DirCacheCheckout { // Nothing in Head // Something in Index // -> Merge contains nothing new. Keep the index. - keep(dce, f); + keep(name, dce, f); } else // Merge contains something and it is not the same as Index // Nothing in Head @@ -1083,15 +1089,15 @@ public class DirCacheCheckout { // Something in Head if (!FileMode.TREE.equals(f.getEntryFileMode()) - && FileMode.TREE.equals(iMode)) + && FileMode.TREE.equals(iMode)) { // The workingtree contains a file and the index semantically contains a folder. // Git considers the workingtree file as untracked. Just keep the untracked file. return; - else - // -> file is dirty and tracked but is should be - // removed. That's a conflict - conflict(name, dce, h, m); - } else + } + // -> file is dirty and tracked but is should be + // removed. That's a conflict + conflict(name, dce, h, m); + } else { // file doesn't exist or is clean // Index contains the same as Head // Something different from a submodule in Index @@ -1099,7 +1105,8 @@ public class DirCacheCheckout { // Something in Head // -> Remove from index and delete the file remove(name); - } else + } + } else { // Index contains something different from Head // Something different from a submodule in Index // Nothing in Merge @@ -1108,6 +1115,7 @@ public class DirCacheCheckout { // filesystem). But Merge wants the path to be removed. // Report a conflict conflict(name, dce, h, m); + } } } else { // Something in Merge @@ -1181,7 +1189,7 @@ public class DirCacheCheckout { // to the other one. // -> In all three cases we don't touch index and file. - keep(dce, f); + keep(name, dce, f); } } } @@ -1230,13 +1238,17 @@ public class DirCacheCheckout { } } - private void keep(DirCacheEntry e, WorkingTreeIterator f) + private void keep(String path, DirCacheEntry e, WorkingTreeIterator f) throws IOException { if (e != null && !FileMode.TREE.equals(e.getFileMode())) builder.add(e); if (force) { - if (f.isModified(e, true, this.walk.getObjectReader())) { - checkoutEntry(repo, e, this.walk.getObjectReader()); + if (f.isModified(e, true, walk.getObjectReader())) { + kept.add(path); + checkoutEntry(repo, e, walk.getObjectReader(), false, + new CheckoutMetadata(walk.getEolStreamType(CHECKOUT_OP), + walk.getFilterCommand( + Constants.ATTR_FILTER_TYPE_SMUDGE))); } } } @@ -1340,13 +1352,14 @@ public class DirCacheCheckout { private boolean isModified_IndexTree(String path, ObjectId iId, FileMode iMode, ObjectId tId, FileMode tMode, ObjectId rootTree) throws CorruptObjectException, IOException { - if (iMode != tMode) + if (iMode != tMode) { return true; + } if (FileMode.TREE.equals(iMode) - && (iId == null || ObjectId.zeroId().equals(iId))) + && (iId == null || ObjectId.zeroId().equals(iId))) { return isModifiedSubtree_IndexTree(path, rootTree); - else - return !equalIdAndMode(iId, iMode, tId, tMode); + } + return !equalIdAndMode(iId, iMode, tId, tMode); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java index 0e91f0d748..cbf96e468c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java @@ -824,10 +824,10 @@ public class DirCacheEntry { } private int getExtendedFlags() { - if (isExtended()) + if (isExtended()) { return NB.decodeUInt16(info, infoOffset + P_FLAGS2) << 16; - else - return 0; + } + return 0; } private static void checkPath(byte[] path) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/AbstractHead.java b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/AbstractHead.java index 60669bb955..2c93d55f4d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/AbstractHead.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/AbstractHead.java @@ -82,10 +82,10 @@ abstract class AbstractHead implements Head { /** {@inheritDoc} */ @Override public List<Head> getNextHeads(char c) { - if (matches(c)) + if (matches(c)) { return newHeads; - else - return FileNameMatcher.EMPTY_HEAD_LIST; + } + return FileNameMatcher.EMPTY_HEAD_LIST; } boolean isStar() { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java index bfcc580ba4..8125c356a6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java @@ -304,11 +304,11 @@ public class FileNameMatcher { private static AbstractHead createWildCardHead( final Character invalidWildgetCharacter, final boolean star) { - if (invalidWildgetCharacter != null) + if (invalidWildgetCharacter != null) { return new RestrictedWildCardHead(invalidWildgetCharacter .charValue(), star); - else - return new WildCardHead(star); + } + return new WildCardHead(star); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java index 8e463415b8..febdb92091 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java @@ -293,13 +293,12 @@ public class ManifestParser extends DefaultHandler { String revision = defaultRevision; if (remote == null) { if (defaultRemote == null) { - if (filename != null) + if (filename != null) { throw new SAXException(MessageFormat.format( RepoText.get().errorNoDefaultFilename, filename)); - else - throw new SAXException( - RepoText.get().errorNoDefault); + } + throw new SAXException(RepoText.get().errorNoDefault); } remote = defaultRemote; } else { 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 cb62925a1f..7288678007 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java @@ -761,18 +761,17 @@ public class RepoCommand extends GitCommand<RevCommit> { } catch (GitAPIException | IOException e) { throw new ManifestErrorException(e); } - } else { - try (Git git = new Git(repo)) { - for (RepoProject proj : filteredProjects) { - addSubmodule(proj.getName(), proj.getUrl(), proj.getPath(), - proj.getRevision(), proj.getCopyFiles(), - proj.getLinkFiles(), git); - } - return git.commit().setMessage(RepoText.get().repoCommitMessage) - .call(); - } catch (GitAPIException | IOException e) { - throw new ManifestErrorException(e); + } + try (Git git = new Git(repo)) { + for (RepoProject proj : filteredProjects) { + addSubmodule(proj.getName(), proj.getUrl(), proj.getPath(), + proj.getRevision(), proj.getCopyFiles(), + proj.getLinkFiles(), git); } + return git.commit().setMessage(RepoText.get().repoCommitMessage) + .call(); + } catch (GitAPIException | IOException e) { + throw new ManifestErrorException(e); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java index d79dfa8b2f..684d1e457f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java @@ -422,10 +422,10 @@ public class RepoProject implements Comparable<RepoProject> { } private String getPathWithSlash() { - if (path.endsWith("/")) //$NON-NLS-1$ + if (path.endsWith("/")) { //$NON-NLS-1$ return path; - else - return path + "/"; //$NON-NLS-1$ + } + return path + "/"; //$NON-NLS-1$ } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/CommitMsgHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/CommitMsgHook.java index f33168d814..6dbe0a6609 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/CommitMsgHook.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/CommitMsgHook.java @@ -72,6 +72,9 @@ public class CommitMsgHook extends GitHook<String> { /** * Constructor for CommitMsgHook + * <p> + * This constructor will use the default error stream. + * </p> * * @param repo * The repository @@ -83,6 +86,24 @@ public class CommitMsgHook extends GitHook<String> { super(repo, outputStream); } + /** + * Constructor for CommitMsgHook + * + * @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}. + * @param errorStream + * The error stream the hook must use. {@code null} is allowed, + * in which case the hook will use {@code System.err}. + * @since 5.6 + */ + protected CommitMsgHook(Repository repo, PrintStream outputStream, + PrintStream errorStream) { + super(repo, outputStream, errorStream); + } + /** {@inheritDoc} */ @Override public String call() throws IOException, AbortedByHookException { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java index ad43e2ca83..aa307c9378 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/GitHook.java @@ -50,6 +50,7 @@ import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.util.concurrent.Callable; +import org.bouncycastle.util.io.TeeOutputStream; import org.eclipse.jgit.api.errors.AbortedByHookException; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.util.FS; @@ -79,7 +80,15 @@ abstract class GitHook<T> implements Callable<T> { protected final PrintStream outputStream; /** - * Constructor for GitHook + * The error stream to be used by the hook. + */ + protected final PrintStream errorStream; + + /** + * Constructor for GitHook. + * <p> + * This constructor will use stderr for the error stream. + * </p> * * @param repo * a {@link org.eclipse.jgit.lib.Repository} object. @@ -88,8 +97,26 @@ abstract class GitHook<T> implements Callable<T> { * in which case the hook will use {@code System.out}. */ protected GitHook(Repository repo, PrintStream outputStream) { + this(repo, outputStream, null); + } + + /** + * Constructor for GitHook + * + * @param repo + * a {@link org.eclipse.jgit.lib.Repository} object. + * @param outputStream + * The output stream the hook must use. {@code null} is allowed, + * in which case the hook will use {@code System.out}. + * @param errorStream + * The error stream the hook must use. {@code null} is allowed, + * in which case the hook will use {@code System.err}. + */ + protected GitHook(Repository repo, PrintStream outputStream, + PrintStream errorStream) { this.repo = repo; this.outputStream = outputStream; + this.errorStream = errorStream; } /** @@ -148,6 +175,16 @@ abstract class GitHook<T> implements Callable<T> { } /** + * Get error stream + * + * @return The error stream the hook must use. Never {@code null}, + * {@code System.err} is returned by default. + */ + protected PrintStream getErrorStream() { + return errorStream == null ? System.err : errorStream; + } + + /** * Runs the hook, without performing any validity checks. * * @throws org.eclipse.jgit.api.errors.AbortedByHookException @@ -155,16 +192,23 @@ abstract class GitHook<T> implements Callable<T> { */ protected void doRun() throws AbortedByHookException { final ByteArrayOutputStream errorByteArray = new ByteArrayOutputStream(); + final TeeOutputStream stderrStream = new TeeOutputStream(errorByteArray, + getErrorStream()); PrintStream hookErrRedirect = null; try { - hookErrRedirect = new PrintStream(errorByteArray, false, + hookErrRedirect = new PrintStream(stderrStream, false, UTF_8.name()); } catch (UnsupportedEncodingException e) { // UTF-8 is guaranteed to be available } - ProcessResult result = FS.DETECTED.runHookIfPresent(getRepository(), - getHookName(), getParameters(), getOutputStream(), - hookErrRedirect, getStdinArgs()); + Repository repository = getRepository(); + FS fs = repository.getFS(); + if (fs == null) { + fs = FS.DETECTED; + } + ProcessResult result = fs.runHookIfPresent(repository, getHookName(), + getParameters(), getOutputStream(), hookErrRedirect, + getStdinArgs()); if (result.isExecutedWithError()) { throw new AbortedByHookException( new String(errorByteArray.toByteArray(), UTF_8), @@ -180,7 +224,11 @@ abstract class GitHook<T> implements Callable<T> { * @since 4.11 */ public boolean isNativeHookPresent() { - return FS.DETECTED.findHook(getRepository(), getHookName()) != null; + FS fs = getRepository().getFS(); + if (fs == null) { + fs = FS.DETECTED; + } + return fs.findHook(getRepository(), getHookName()) != null; } } 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 b801d6872b..f29dcd178b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/Hooks.java @@ -57,7 +57,8 @@ import org.eclipse.jgit.util.LfsFactory; public class Hooks { /** - * Create pre-commit hook for the given repository + * Create pre-commit hook for the given repository with the default error + * stream * * @param repo * a {@link org.eclipse.jgit.lib.Repository} object. @@ -71,7 +72,25 @@ public class Hooks { } /** - * Create post-commit hook for the given repository + * Create pre-commit hook for the given repository + * + * @param repo + * a {@link org.eclipse.jgit.lib.Repository} object. + * @param outputStream + * The output stream, or {@code null} to use {@code System.out} + * @param errorStream + * The error stream, or {@code null} to use {@code System.err} + * @return The pre-commit hook for the given repository. + * @since 5.6 + */ + public static PreCommitHook preCommit(Repository repo, + PrintStream outputStream, PrintStream errorStream) { + return new PreCommitHook(repo, outputStream, errorStream); + } + + /** + * Create post-commit hook for the given repository with the default error + * stream * * @param repo * a {@link org.eclipse.jgit.lib.Repository} object. @@ -86,7 +105,25 @@ public class Hooks { } /** - * Create commit-msg hook for the given repository + * Create post-commit hook for the given repository + * + * @param repo + * a {@link org.eclipse.jgit.lib.Repository} object. + * @param outputStream + * The output stream, or {@code null} to use {@code System.out} + * @param errorStream + * The error stream, or {@code null} to use {@code System.err} + * @return The pre-commit hook for the given repository. + * @since 5.6 + */ + public static PostCommitHook postCommit(Repository repo, + PrintStream outputStream, PrintStream errorStream) { + return new PostCommitHook(repo, outputStream, errorStream); + } + + /** + * Create commit-msg hook for the given repository with the default error + * stream * * @param repo * a {@link org.eclipse.jgit.lib.Repository} object. @@ -100,7 +137,25 @@ public class Hooks { } /** - * Create pre-push hook for the given repository + * Create commit-msg hook for the given repository + * + * @param repo + * a {@link org.eclipse.jgit.lib.Repository} object. + * @param outputStream + * The output stream, or {@code null} to use {@code System.out} + * @param errorStream + * The error stream, or {@code null} to use {@code System.err} + * @return The pre-commit hook for the given repository. + * @since 5.6 + */ + public static CommitMsgHook commitMsg(Repository repo, + PrintStream outputStream, PrintStream errorStream) { + return new CommitMsgHook(repo, outputStream, errorStream); + } + + /** + * Create pre-push hook for the given repository with the default error + * stream * * @param repo * a {@link org.eclipse.jgit.lib.Repository} object. @@ -127,4 +182,36 @@ public class Hooks { } return new PrePushHook(repo, outputStream); } + + /** + * Create pre-push hook for the given repository + * + * @param repo + * a {@link org.eclipse.jgit.lib.Repository} object. + * @param outputStream + * The output stream, or {@code null} to use {@code System.out} + * @param errorStream + * The error stream, or {@code null} to use {@code System.err} + * @return The pre-push hook for the given repository. + * @since 5.6 + */ + public static PrePushHook prePush(Repository repo, PrintStream outputStream, + PrintStream errorStream) { + if (LfsFactory.getInstance().isAvailable()) { + PrePushHook hook = LfsFactory.getInstance().getPrePushHook(repo, + outputStream, errorStream); + if (hook != null) { + if (hook.isNativeHookPresent()) { + PrintStream ps = outputStream; + if (ps == null) { + ps = System.out; + } + ps.println(MessageFormat + .format(JGitText.get().lfsHookConflict, repo)); + } + return hook; + } + } + return new PrePushHook(repo, outputStream, errorStream); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java index 24bad16ecb..b6e576fc23 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PostCommitHook.java @@ -61,6 +61,9 @@ public class PostCommitHook extends GitHook<Void> { /** * Constructor for PostCommitHook + * <p> + * This constructor will use the default error stream. + * </p> * * @param repo * The repository @@ -72,6 +75,24 @@ public class PostCommitHook extends GitHook<Void> { super(repo, outputStream); } + /** + * Constructor for PostCommitHook + * + * @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}. + * @param errorStream + * The error stream the hook must use. {@code null} is allowed, + * in which case the hook will use {@code System.err}. + * @since 5.6 + */ + protected PostCommitHook(Repository repo, PrintStream outputStream, + PrintStream errorStream) { + super(repo, outputStream, errorStream); + } + /** {@inheritDoc} */ @Override public Void call() throws IOException, AbortedByHookException { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PreCommitHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PreCommitHook.java index 0d9290da3e..dbdaf8669c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PreCommitHook.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PreCommitHook.java @@ -61,6 +61,9 @@ public class PreCommitHook extends GitHook<Void> { /** * Constructor for PreCommitHook + * <p> + * This constructor will use the default error stream. + * </p> * * @param repo * The repository @@ -72,6 +75,24 @@ public class PreCommitHook extends GitHook<Void> { super(repo, outputStream); } + /** + * Constructor for PreCommitHook + * + * @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}. + * @param errorStream + * The error stream the hook must use. {@code null} is allowed, + * in which case the hook will use {@code System.err}. + * @since 5.6 + */ + protected PreCommitHook(Repository repo, PrintStream outputStream, + PrintStream errorStream) { + super(repo, outputStream, errorStream); + } + /** {@inheritDoc} */ @Override public Void call() throws IOException, AbortedByHookException { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java index 431944f9d4..61180fd021 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/hooks/PrePushHook.java @@ -73,6 +73,9 @@ public class PrePushHook extends GitHook<String> { /** * Constructor for PrePushHook + * <p> + * This constructor will use the default error stream. + * </p> * * @param repo * The repository @@ -84,6 +87,24 @@ public class PrePushHook extends GitHook<String> { super(repo, outputStream); } + /** + * Constructor for PrePushHook + * + * @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}. + * @param errorStream + * The error stream the hook must use. {@code null} is allowed, + * in which case the hook will use {@code System.err}. + * @since 5.6 + */ + protected PrePushHook(Repository repo, PrintStream outputStream, + PrintStream errorStream) { + super(repo, outputStream, errorStream); + } + /** {@inheritDoc} */ @Override protected String getStdinArgs() { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java index 3c0f17ab3d..b7d6acce14 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/internal/PathMatcher.java @@ -291,26 +291,25 @@ public class PathMatcher extends AbstractMatcher { // We had a prefix match here. if (!pathMatch) { return true; + } + if (right == endExcl - 1) { + // Extra slash at the end: actually a full match. + // Must meet directory expectations + return !dirOnly || assumeDirectory; + } + // Prefix matches only if pattern ended with /** + if (wasWild) { + return true; + } + if (lastWildmatch >= 0) { + // Consider pattern **/x and input x/x. + // We've matched the prefix x/ so far: we + // must try to extend the **! + matcher = lastWildmatch + 1; + right = wildmatchBacktrackPos; + wildmatchBacktrackPos = -1; } else { - if (right == endExcl - 1) { - // Extra slash at the end: actually a full match. - // Must meet directory expectations - return !dirOnly || assumeDirectory; - } - // Prefix matches only if pattern ended with /** - if (wasWild) { - return true; - } - if (lastWildmatch >= 0) { - // Consider pattern **/x and input x/x. - // We've matched the prefix x/ so far: we - // must try to extend the **! - matcher = lastWildmatch + 1; - right = wildmatchBacktrackPos; - wildmatchBacktrackPos = -1; - } else { - return false; - } + return false; } } } else if (lastWildmatch != -1) { 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 41923eed18..b18aed9828 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 @@ -192,22 +192,20 @@ public class Strings { } if (pattern.indexOf('?') != -1) { return true; - } else { - // check if the backslash escapes one of the glob special characters - // if not, backslash is not part of a regex and treated literally - int backSlash = pattern.indexOf('\\'); - if (backSlash >= 0) { - int nextIdx = backSlash + 1; - if (pattern.length() == nextIdx) { - return false; - } - char nextChar = pattern.charAt(nextIdx); - if (escapedByBackslash(nextChar)) { - return true; - } else { - return false; - } + } + // check if the backslash escapes one of the glob special characters + // if not, backslash is not part of a regex and treated literally + int backSlash = pattern.indexOf('\\'); + if (backSlash >= 0) { + int nextIdx = backSlash + 1; + if (pattern.length() == nextIdx) { + return false; + } + char nextChar = pattern.charAt(nextIdx); + if (escapedByBackslash(nextChar)) { + return true; } + return false; } return false; } 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 61b145657d..0cea60fd95 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -344,10 +344,12 @@ public class JGitText extends TranslationBundle { /***/ public String failedAtomicFileCreation; /***/ public String failedCreateLockFile; /***/ public String failedToDetermineFilterDefinition; + /***/ public String failedToConvert; /***/ public String failedUpdatingRefs; /***/ public String failureDueToOneOfTheFollowing; /***/ public String failureUpdatingFETCH_HEAD; /***/ public String failureUpdatingTrackingRef; + /***/ public String fileAlreadyExists; /***/ public String fileCannotBeDeleted; /***/ public String fileIsTooLarge; /***/ public String fileModeNotSetForPath; @@ -386,6 +388,7 @@ public class JGitText extends TranslationBundle { /***/ public String incorrectOBJECT_ID_LENGTH; /***/ public String indexFileCorruptedNegativeBucketCount; /***/ public String indexFileIsTooLargeForJgit; + /***/ public String indexNumbersNotIncreasing; /***/ public String indexWriteException; /***/ public String initFailedBareRepoDifferentDirs; /***/ public String initFailedDirIsNoDirectory; @@ -411,6 +414,7 @@ public class JGitText extends TranslationBundle { /***/ public String invalidGitdirRef; /***/ public String invalidGitModules; /***/ public String invalidGitType; + /***/ public String invalidHooksPath; /***/ public String invalidId; /***/ public String invalidId0; /***/ public String invalidIdLength; @@ -511,8 +515,10 @@ public class JGitText extends TranslationBundle { /***/ public String noMergeBase; /***/ public String noMergeHeadSpecified; /***/ public String nonBareLinkFilesNotSupported; + /***/ public String nonCommitToHeads; /***/ public String noPathAttributesFound; /***/ public String noSuchRef; + /***/ public String noSuchRefKnown; /***/ public String noSuchSubmodule; /***/ public String notABoolean; /***/ public String notABundle; @@ -611,7 +617,8 @@ public class JGitText extends TranslationBundle { /***/ public String refAlreadyExists1; /***/ public String reflogEntryNotFound; /***/ public String refNotResolved; - /***/ public String refTableRecordsMustIncrease; + /***/ public String reftableDirExists; + /***/ public String reftableRecordsMustIncrease; /***/ public String refUpdateReturnCodeWas; /***/ public String remoteConfigHasNoURIAssociated; /***/ public String remoteDoesNotHaveSpec; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchReplica.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchReplica.java index 0e8377dd02..52c8f29ddc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchReplica.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchReplica.java @@ -77,6 +77,7 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.transport.ReceiveCommand; import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.SystemReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -532,9 +533,8 @@ public abstract class KetchReplica { queued.add(0, new ReplicaPushRequest(this, cmds)); if (!waitingForRetry()) { - long delay = KetchSystem.delay( - lastRetryMillis, - minRetryMillis, maxRetryMillis); + long delay = FileUtils + .delay(lastRetryMillis, minRetryMillis, maxRetryMillis); if (log.isDebugEnabled()) { log.debug("Retrying {} after {} ms", //$NON-NLS-1$ describeForLog(), Long.valueOf(delay)); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchSystem.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchSystem.java index d1d4f67d86..fd334f149a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchSystem.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/KetchSystem.java @@ -350,25 +350,4 @@ public class KetchSystem { } } - /** - * Compute a delay in a {@code min..max} interval with random jitter. - * - * @param last - * amount of delay waited before the last attempt. This is used - * to seed the next delay interval. Should be 0 if there was no - * prior delay. - * @param min - * shortest amount of allowable delay between attempts. - * @param max - * longest amount of allowable delay between attempts. - * @return new amount of delay to wait before the next attempt. - */ - static long delay(long last, long min, long max) { - long r = Math.max(0, last * 3 - min); - if (r > 0) { - int c = (int) Math.min(r + 1, Integer.MAX_VALUE); - r = RNG.nextInt(c); - } - return Math.max(Math.min(min + r, max), min); - } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LagCheck.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LagCheck.java index 53fd198006..a27a9bc446 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LagCheck.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/ketch/LagCheck.java @@ -132,9 +132,8 @@ class LagCheck implements AutoCloseable { // TODO(sop) Check term to see if my leader was deposed. if (rw.isMergedInto(head, remote)) { return AHEAD; - } else { - return DIVERGENT; } + return DIVERGENT; } catch (IOException err) { KetchReplica.log.error(String.format( "Cannot compare %s", //$NON-NLS-1$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java index c6e2fae42f..16e7a0d537 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java @@ -412,8 +412,7 @@ public final class DfsBlockCache { getStat(statMiss, key).incrementAndGet(); boolean credit = true; try { - v = file.readOneBlock(requestedPosition, ctx, - fileChannel.get()); + v = file.readOneBlock(position, ctx, fileChannel.get()); credit = false; } finally { if (credit) { @@ -450,7 +449,7 @@ public final class DfsBlockCache { } @SuppressWarnings("unchecked") - private void reserveSpace(int reserve, DfsStreamKey key) { + private void reserveSpace(long reserve, DfsStreamKey key) { clockLock.lock(); try { long live = LongStream.of(getCurrentSize()).sum() + reserve; @@ -487,7 +486,7 @@ public final class DfsBlockCache { } } - private void creditSpace(int credit, DfsStreamKey key) { + private void creditSpace(long credit, DfsStreamKey key) { clockLock.lock(); try { getStat(liveBytes, key).addAndGet(-credit); @@ -497,7 +496,7 @@ public final class DfsBlockCache { } @SuppressWarnings("unchecked") - private void addToClock(Ref ref, int credit) { + private void addToClock(Ref ref, long credit) { clockLock.lock(); try { if (credit != 0) { @@ -521,17 +520,20 @@ public final class DfsBlockCache { * * @param key * the stream key of the pack. + * @param position + * the position in the key. The default should be 0. * @param loader * the function to load the reference. * @return the object reference. * @throws IOException * the reference was not in the cache and could not be loaded. */ - <T> Ref<T> getOrLoadRef(DfsStreamKey key, RefLoader<T> loader) + <T> Ref<T> getOrLoadRef( + DfsStreamKey key, long position, RefLoader<T> loader) throws IOException { - int slot = slot(key, 0); + int slot = slot(key, position); HashEntry e1 = table.get(slot); - Ref<T> ref = scanRef(e1, key, 0); + Ref<T> ref = scanRef(e1, key, position); if (ref != null) { getStat(statHit, key).incrementAndGet(); return ref; @@ -543,7 +545,7 @@ public final class DfsBlockCache { try { HashEntry e2 = table.get(slot); if (e2 != e1) { - ref = scanRef(e2, key, 0); + ref = scanRef(e2, key, position); if (ref != null) { getStat(statHit, key).incrementAndGet(); return ref; @@ -574,10 +576,10 @@ public final class DfsBlockCache { } <T> Ref<T> putRef(DfsStreamKey key, long size, T v) { - return put(key, 0, (int) Math.min(size, Integer.MAX_VALUE), v); + return put(key, 0, size, v); } - <T> Ref<T> put(DfsStreamKey key, long pos, int size, T v) { + <T> Ref<T> put(DfsStreamKey key, long pos, long size, T v) { int slot = slot(key, pos); HashEntry e1 = table.get(slot); Ref<T> ref = scanRef(e1, key, pos); @@ -720,12 +722,12 @@ public final class DfsBlockCache { static final class Ref<T> { final DfsStreamKey key; final long position; - final int size; + final long size; volatile T value; Ref next; volatile boolean hot; - Ref(DfsStreamKey key, long position, int size, T v) { + Ref(DfsStreamKey key, long position, long size, T v) { this.key = key; this.position = position; this.size = size; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsCachedPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsCachedPack.java index 3605236e56..9b280747df 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsCachedPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsCachedPack.java @@ -61,6 +61,13 @@ public class DfsCachedPack extends CachedPack { } /** + * @return the pack passed to the constructor + */ + public DfsPackFile getPackFile() { + return pack; + } + + /** * Get the description of the pack. * * @return the description of the pack. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java index f10a1d8127..3e71d079b5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java @@ -744,11 +744,15 @@ public class DfsGarbageCollector { return; } - try (ReftableStack stack = ReftableStack.open(ctx, reftablesBefore)) { - ReftableCompactor compact = new ReftableCompactor(); + try (DfsReftableStack stack = DfsReftableStack.open(ctx, reftablesBefore); + DfsOutputStream out = objdb.writeFile(pack, REFTABLE)) { + ReftableCompactor compact = new ReftableCompactor(out); compact.addAll(stack.readers()); compact.setIncludeDeletes(includeDeletes); - compactReftable(pack, compact); + compact.setConfig(configureReftable(reftableConfig, out)); + compact.compact(); + pack.addFileExt(REFTABLE); + pack.setReftableStats(compact.getStats()); } } @@ -765,24 +769,12 @@ public class DfsGarbageCollector { throws IOException { try (DfsOutputStream out = objdb.writeFile(pack, REFTABLE)) { ReftableConfig cfg = configureReftable(reftableConfig, out); - ReftableWriter writer = new ReftableWriter(cfg) + ReftableWriter writer = new ReftableWriter(cfg, out) .setMinUpdateIndex(reftableInitialMinUpdateIndex) - .setMaxUpdateIndex(reftableInitialMaxUpdateIndex) - .begin(out) - .sortAndWriteRefs(refs) - .finish(); + .setMaxUpdateIndex(reftableInitialMaxUpdateIndex).begin() + .sortAndWriteRefs(refs).finish(); pack.addFileExt(REFTABLE); pack.setReftableStats(writer.getStats()); } } - - private void compactReftable(DfsPackDescription pack, - ReftableCompactor compact) throws IOException { - try (DfsOutputStream out = objdb.writeFile(pack, REFTABLE)) { - compact.setConfig(configureReftable(reftableConfig, out)); - compact.compact(out); - pack.addFileExt(REFTABLE); - pack.setReftableStats(compact.getStats()); - } - } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java index 6f3f2bd8e7..083124e5ed 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java @@ -311,12 +311,16 @@ public class DfsPackCompactor { DfsObjDatabase objdb = repo.getObjectDatabase(); Collections.sort(srcReftables, objdb.reftableComparator()); - try (ReftableStack stack = ReftableStack.open(ctx, srcReftables)) { - initOutDesc(objdb); - ReftableCompactor compact = new ReftableCompactor(); + initOutDesc(objdb); + try (DfsReftableStack stack = DfsReftableStack.open(ctx, srcReftables); + DfsOutputStream out = objdb.writeFile(outDesc, REFTABLE)) { + ReftableCompactor compact = new ReftableCompactor(out); compact.addAll(stack.readers()); compact.setIncludeDeletes(true); - writeReftable(objdb, outDesc, compact); + compact.setConfig(configureReftable(reftableConfig, out)); + compact.compact(); + outDesc.addFileExt(REFTABLE); + outDesc.setReftableStats(compact.getStats()); } } @@ -497,16 +501,6 @@ public class DfsPackCompactor { } } - private void writeReftable(DfsObjDatabase objdb, DfsPackDescription pack, - ReftableCompactor compact) throws IOException { - try (DfsOutputStream out = objdb.writeFile(pack, REFTABLE)) { - compact.setConfig(configureReftable(reftableConfig, out)); - compact.compact(out); - pack.addFileExt(REFTABLE); - pack.setReftableStats(compact.getStats()); - } - } - static ReftableConfig configureReftable(ReftableConfig cfg, DfsOutputStream out) { int bs = out.blockSize(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java index be1387ed0c..d0f9b1c1f4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java @@ -89,6 +89,7 @@ import org.eclipse.jgit.util.LongList; */ public final class DfsPackFile extends BlockBasedFile { private static final int REC_SIZE = Constants.OBJECT_ID_LENGTH + 8; + private static final long REF_POSITION = 0; /** * Lock for initialization of {@link #index} and {@link #corruptObjects}. @@ -194,45 +195,10 @@ public final class DfsPackFile extends BlockBasedFile { try { DfsStreamKey idxKey = desc.getStreamKey(INDEX); - DfsBlockCache.Ref<PackIndex> idxref = cache.getOrLoadRef(idxKey, - () -> { - try { - ctx.stats.readIdx++; - long start = System.nanoTime(); - try (ReadableChannel rc = ctx.db.openFile(desc, - INDEX)) { - InputStream in = Channels - .newInputStream(rc); - int wantSize = 8192; - int bs = rc.blockSize(); - if (0 < bs && bs < wantSize) { - bs = (wantSize / bs) * bs; - } else if (bs <= 0) { - bs = wantSize; - } - PackIndex idx = PackIndex.read( - new BufferedInputStream(in, bs)); - int sz = (int) Math.min( - idx.getObjectCount() * REC_SIZE, - Integer.MAX_VALUE); - ctx.stats.readIdxBytes += rc.position(); - index = idx; - return new DfsBlockCache.Ref<>(idxKey, 0, - sz, idx); - } finally { - ctx.stats.readIdxMicros += elapsedMicros( - start); - } - } catch (EOFException e) { - throw new IOException(MessageFormat.format( - DfsText.get().shortReadOfIndex, - desc.getFileName(INDEX)), e); - } catch (IOException e) { - throw new IOException(MessageFormat.format( - DfsText.get().cannotReadIndex, - desc.getFileName(INDEX)), e); - } - }); + DfsBlockCache.Ref<PackIndex> idxref = cache.getOrLoadRef( + idxKey, + REF_POSITION, + () -> loadPackIndex(ctx, idxKey)); PackIndex idx = idxref.get(); if (index == null && idx != null) { index = idx; @@ -267,44 +233,10 @@ public final class DfsPackFile extends BlockBasedFile { PackIndex idx = idx(ctx); PackReverseIndex revidx = getReverseIdx(ctx); DfsStreamKey bitmapKey = desc.getStreamKey(BITMAP_INDEX); - DfsBlockCache.Ref<PackBitmapIndex> idxref = cache - .getOrLoadRef(bitmapKey, () -> { - ctx.stats.readBitmap++; - long start = System.nanoTime(); - try (ReadableChannel rc = ctx.db.openFile(desc, - BITMAP_INDEX)) { - long size; - PackBitmapIndex bmidx; - try { - InputStream in = Channels.newInputStream(rc); - int wantSize = 8192; - int bs = rc.blockSize(); - if (0 < bs && bs < wantSize) { - bs = (wantSize / bs) * bs; - } else if (bs <= 0) { - bs = wantSize; - } - in = new BufferedInputStream(in, bs); - bmidx = PackBitmapIndex.read(in, idx, revidx); - } finally { - size = rc.position(); - ctx.stats.readIdxBytes += size; - ctx.stats.readIdxMicros += elapsedMicros(start); - } - int sz = (int) Math.min(size, Integer.MAX_VALUE); - bitmapIndex = bmidx; - return new DfsBlockCache.Ref<>(bitmapKey, 0, sz, - bmidx); - } catch (EOFException e) { - throw new IOException(MessageFormat.format( - DfsText.get().shortReadOfIndex, - desc.getFileName(BITMAP_INDEX)), e); - } catch (IOException e) { - throw new IOException(MessageFormat.format( - DfsText.get().cannotReadIndex, - desc.getFileName(BITMAP_INDEX)), e); - } - }); + DfsBlockCache.Ref<PackBitmapIndex> idxref = cache.getOrLoadRef( + bitmapKey, + REF_POSITION, + () -> loadBitmapIndex(ctx, bitmapKey, idx, revidx)); PackBitmapIndex bmidx = idxref.get(); if (bitmapIndex == null && bmidx != null) { bitmapIndex = bmidx; @@ -326,14 +258,10 @@ public final class DfsPackFile extends BlockBasedFile { PackIndex idx = idx(ctx); DfsStreamKey revKey = new DfsStreamKey.ForReverseIndex( desc.getStreamKey(INDEX)); - DfsBlockCache.Ref<PackReverseIndex> revref = cache - .getOrLoadRef(revKey, () -> { - PackReverseIndex revidx = new PackReverseIndex(idx); - int sz = (int) Math.min(idx.getObjectCount() * 8, - Integer.MAX_VALUE); - reverseIndex = revidx; - return new DfsBlockCache.Ref<>(revKey, 0, sz, revidx); - }); + DfsBlockCache.Ref<PackReverseIndex> revref = cache.getOrLoadRef( + revKey, + REF_POSITION, + () -> loadReverseIdx(revKey, idx)); PackReverseIndex revidx = revref.get(); if (reverseIndex == null && revidx != null) { reverseIndex = revidx; @@ -1091,4 +1019,91 @@ public final class DfsPackFile extends BlockBasedFile { list.add(offset); } } + + private DfsBlockCache.Ref<PackIndex> loadPackIndex( + DfsReader ctx, DfsStreamKey idxKey) throws IOException { + try { + ctx.stats.readIdx++; + long start = System.nanoTime(); + try (ReadableChannel rc = ctx.db.openFile(desc, INDEX)) { + InputStream in = Channels.newInputStream(rc); + int wantSize = 8192; + int bs = rc.blockSize(); + if (0 < bs && bs < wantSize) { + bs = (wantSize / bs) * bs; + } else if (bs <= 0) { + bs = wantSize; + } + PackIndex idx = PackIndex.read(new BufferedInputStream(in, bs)); + ctx.stats.readIdxBytes += rc.position(); + index = idx; + return new DfsBlockCache.Ref<>( + idxKey, + REF_POSITION, + idx.getObjectCount() * REC_SIZE, + idx); + } finally { + ctx.stats.readIdxMicros += elapsedMicros(start); + } + } catch (EOFException e) { + throw new IOException(MessageFormat.format( + DfsText.get().shortReadOfIndex, + desc.getFileName(INDEX)), e); + } catch (IOException e) { + throw new IOException(MessageFormat.format( + DfsText.get().cannotReadIndex, + desc.getFileName(INDEX)), e); + } + } + + private DfsBlockCache.Ref<PackReverseIndex> loadReverseIdx( + DfsStreamKey revKey, PackIndex idx) { + PackReverseIndex revidx = new PackReverseIndex(idx); + reverseIndex = revidx; + return new DfsBlockCache.Ref<>( + revKey, + REF_POSITION, + idx.getObjectCount() * 8, + revidx); + } + + private DfsBlockCache.Ref<PackBitmapIndex> loadBitmapIndex( + DfsReader ctx, + DfsStreamKey bitmapKey, + PackIndex idx, + PackReverseIndex revidx) throws IOException { + ctx.stats.readBitmap++; + long start = System.nanoTime(); + try (ReadableChannel rc = ctx.db.openFile(desc, BITMAP_INDEX)) { + long size; + PackBitmapIndex bmidx; + try { + InputStream in = Channels.newInputStream(rc); + int wantSize = 8192; + int bs = rc.blockSize(); + if (0 < bs && bs < wantSize) { + bs = (wantSize / bs) * bs; + } else if (bs <= 0) { + bs = wantSize; + } + in = new BufferedInputStream(in, bs); + bmidx = PackBitmapIndex.read(in, idx, revidx); + } finally { + size = rc.position(); + ctx.stats.readIdxBytes += size; + ctx.stats.readIdxMicros += elapsedMicros(start); + } + bitmapIndex = bmidx; + return new DfsBlockCache.Ref<>( + bitmapKey, REF_POSITION, size, bmidx); + } catch (EOFException e) { + throw new IOException(MessageFormat.format( + DfsText.get().shortReadOfIndex, + desc.getFileName(BITMAP_INDEX)), e); + } catch (IOException e) { + throw new IOException(MessageFormat.format( + DfsText.get().cannotReadIndex, + desc.getFileName(BITMAP_INDEX)), e); + } + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java index 732cd4d1c6..b3b9e39375 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java @@ -191,14 +191,11 @@ public abstract class DfsRefDatabase extends RefDatabase { rw.peel(obj).copy(), hasVersioning() ? leaf.getUpdateIndex() : UNDEFINED_UPDATE_INDEX); - } else { - return new ObjectIdRef.PeeledNonTag( - leaf.getStorage(), - leaf.getName(), - leaf.getObjectId(), - hasVersioning() ? leaf.getUpdateIndex() - : UNDEFINED_UPDATE_INDEX); } + return new ObjectIdRef.PeeledNonTag(leaf.getStorage(), + leaf.getName(), leaf.getObjectId(), + hasVersioning() ? leaf.getUpdateIndex() + : UNDEFINED_UPDATE_INDEX); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableBatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableBatchRefUpdate.java new file mode 100644 index 0000000000..124630edb7 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableBatchRefUpdate.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2019, 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.dfs; + +import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource; +import org.eclipse.jgit.internal.storage.io.BlockSource; +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.internal.storage.reftable.ReftableBatchRefUpdate; +import org.eclipse.jgit.internal.storage.reftable.ReftableCompactor; +import org.eclipse.jgit.internal.storage.reftable.ReftableConfig; +import org.eclipse.jgit.internal.storage.reftable.ReftableReader; +import org.eclipse.jgit.internal.storage.reftable.ReftableWriter; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.transport.ReceiveCommand; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; + +/** + * {@link org.eclipse.jgit.lib.BatchRefUpdate} for + * {@link org.eclipse.jgit.internal.storage.dfs.DfsReftableDatabase}. + */ +public class DfsReftableBatchRefUpdate extends ReftableBatchRefUpdate { + private static final int AVG_BYTES = 36; + + private final DfsReftableDatabase refdb; + + private final DfsObjDatabase odb; + + /** + * Initialize batch update. + * + * @param refdb + * database the update will modify. + * @param odb + * object database to store the reftable. + */ + protected DfsReftableBatchRefUpdate(DfsReftableDatabase refdb, + DfsObjDatabase odb) { + super(refdb, refdb.reftableDatabase, refdb.getLock(), refdb.getRepository()); + this.refdb = refdb; + this.odb = odb; + } + + @Override + protected void applyUpdates(List<Ref> newRefs, List<ReceiveCommand> pending) + throws IOException { + Set<DfsPackDescription> prune = Collections.emptySet(); + DfsPackDescription pack = odb.newPack(PackSource.INSERT); + try (DfsOutputStream out = odb.writeFile(pack, REFTABLE)) { + ReftableConfig cfg = DfsPackCompactor + .configureReftable(refdb.getReftableConfig(), out); + + ReftableWriter.Stats stats; + if (refdb.compactDuringCommit() + && newRefs.size() * AVG_BYTES <= cfg.getRefBlockSize() + && canCompactTopOfStack(cfg)) { + ByteArrayOutputStream tmp = new ByteArrayOutputStream(); + ReftableWriter rw = new ReftableWriter(cfg, tmp); + write(rw, newRefs, pending); + rw.finish(); + stats = compactTopOfStack(out, cfg, tmp.toByteArray()); + prune = toPruneTopOfStack(); + } else { + ReftableWriter rw = new ReftableWriter(cfg, out); + write(rw, newRefs, pending); + rw.finish(); + stats = rw.getStats(); + } + pack.addFileExt(REFTABLE); + pack.setReftableStats(stats); + } + + odb.commitPack(Collections.singleton(pack), prune); + odb.addReftable(pack, prune); + refdb.clearCache(); + } + + private boolean canCompactTopOfStack(ReftableConfig cfg) + throws IOException { + refdb.getLock().lock(); + try { + DfsReftableStack stack = refdb.stack(); + List<ReftableReader> readers = stack.readers(); + if (readers.isEmpty()) { + return false; + } + + int lastIdx = readers.size() - 1; + DfsReftable last = stack.files().get(lastIdx); + DfsPackDescription desc = last.getPackDescription(); + if (desc.getPackSource() != PackSource.INSERT + || !packOnlyContainsReftable(desc)) { + return false; + } + + ReftableReader table = readers.get(lastIdx); + int bs = cfg.getRefBlockSize(); + return table.size() <= 3 * bs; + } finally { + refdb.getLock().unlock(); + } + } + + private ReftableWriter.Stats compactTopOfStack(OutputStream out, + ReftableConfig cfg, byte[] newTable) throws IOException { + refdb.getLock().lock(); + try { + List<ReftableReader> stack = refdb.stack().readers(); + + ReftableReader last = stack.get(stack.size() - 1); + + List<ReftableReader> tables = new ArrayList<>(2); + tables.add(last); + tables.add(new ReftableReader(BlockSource.from(newTable))); + + ReftableCompactor compactor = new ReftableCompactor(out); + compactor.setConfig(cfg); + compactor.setIncludeDeletes(true); + compactor.addAll(tables); + compactor.compact(); + return compactor.getStats(); + } finally { + refdb.getLock().unlock(); + } + } + + private Set<DfsPackDescription> toPruneTopOfStack() throws IOException { + refdb.getLock().lock(); + try { + List<DfsReftable> stack = refdb.stack().files(); + + DfsReftable last = stack.get(stack.size() - 1); + return Collections.singleton(last.getPackDescription()); + } finally { + refdb.getLock().unlock(); + } + } + + private boolean packOnlyContainsReftable(DfsPackDescription desc) { + for (PackExt ext : PackExt.values()) { + if (ext != REFTABLE && desc.hasFileExt(ext)) { + return false; + } + } + return true; + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java index 6050c15992..124131d1d3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableDatabase.java @@ -45,19 +45,17 @@ package org.eclipse.jgit.internal.storage.dfs; import java.io.IOException; import java.util.Arrays; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.locks.ReentrantLock; import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.internal.storage.reftable.MergedReftable; -import org.eclipse.jgit.internal.storage.reftable.RefCursor; -import org.eclipse.jgit.internal.storage.reftable.Reftable; import org.eclipse.jgit.internal.storage.reftable.ReftableConfig; +import org.eclipse.jgit.internal.storage.reftable.ReftableDatabase; import org.eclipse.jgit.lib.BatchRefUpdate; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; @@ -81,13 +79,10 @@ import org.eclipse.jgit.util.RefMap; * and one will fail. */ public class DfsReftableDatabase extends DfsRefDatabase { - private final ReentrantLock lock = new ReentrantLock(true); + final ReftableDatabase reftableDatabase; private DfsReader ctx; - - private ReftableStack tableStack; - - private MergedReftable mergedTables; + private DfsReftableStack stack; /** * Initialize the reference database for a repository. @@ -97,6 +92,18 @@ public class DfsReftableDatabase extends DfsRefDatabase { */ protected DfsReftableDatabase(DfsRepository repo) { super(repo); + reftableDatabase = new ReftableDatabase() { + @Override + public MergedReftable openMergedReftable() throws IOException { + DfsReftableDatabase.this.getLock().lock(); + try { + return new MergedReftable(stack().readers()); + } finally { + DfsReftableDatabase.this.getLock().unlock(); + } + } + }; + stack = null; } /** {@inheritDoc} */ @@ -115,7 +122,7 @@ public class DfsReftableDatabase extends DfsRefDatabase { @Override public BatchRefUpdate newBatchUpdate() { DfsObjDatabase odb = getRepository().getObjectDatabase(); - return new ReftableBatchRefUpdate(this, odb); + return new DfsReftableBatchRefUpdate(this, odb); } /** @@ -124,7 +131,7 @@ public class DfsReftableDatabase extends DfsRefDatabase { * @return configuration to write new reftables with. */ public ReftableConfig getReftableConfig() { - return new ReftableConfig(getRepository().getConfig()); + return new ReftableConfig(getRepository()); } /** @@ -133,7 +140,7 @@ public class DfsReftableDatabase extends DfsRefDatabase { * @return the lock protecting this instance's state. */ protected ReentrantLock getLock() { - return lock; + return reftableDatabase.getLock(); } /** @@ -147,134 +154,57 @@ public class DfsReftableDatabase extends DfsRefDatabase { return true; } - /** - * Obtain a handle to the merged reader. - * - * @return (possibly cached) handle to the merged reader. - * @throws java.io.IOException - * if tables cannot be opened. - */ - protected Reftable reader() throws IOException { - lock.lock(); - try { - if (mergedTables == null) { - mergedTables = new MergedReftable(stack().readers()); - } - return mergedTables; - } finally { - lock.unlock(); - } - } /** - * Obtain a handle to the stack of reftables. + * Obtain a handle to the stack of reftables. Must hold lock. * * @return (possibly cached) handle to the stack. * @throws java.io.IOException * if tables cannot be opened. */ - protected ReftableStack stack() throws IOException { - lock.lock(); - try { - if (tableStack == null) { - DfsObjDatabase odb = getRepository().getObjectDatabase(); - if (ctx == null) { - ctx = odb.newReader(); - } - tableStack = ReftableStack.open(ctx, - Arrays.asList(odb.getReftables())); - } - return tableStack; - } finally { - lock.unlock(); + protected DfsReftableStack stack() throws IOException { + if (!getLock().isLocked()) { + throw new IllegalStateException("most hold lock to access stack"); //$NON-NLS-1$ } + DfsObjDatabase odb = getRepository().getObjectDatabase(); + + if (ctx == null) { + ctx = odb.newReader(); + } + if (stack == null) { + stack = DfsReftableStack.open(ctx, Arrays.asList(odb.getReftables())); + } + return stack; } - /** {@inheritDoc} */ @Override public boolean isNameConflicting(String refName) throws IOException { - lock.lock(); - try { - Reftable table = reader(); - - // Cannot be nested within an existing reference. - int lastSlash = refName.lastIndexOf('/'); - while (0 < lastSlash) { - if (table.hasRef(refName.substring(0, lastSlash))) { - return true; - } - lastSlash = refName.lastIndexOf('/', lastSlash - 1); - } - - // Cannot be the container of an existing reference. - return table.hasRefsWithPrefix(refName + '/'); - } finally { - lock.unlock(); - } + return reftableDatabase.isNameConflicting(refName, new TreeSet<>(), new HashSet<>()); } /** {@inheritDoc} */ @Override public Ref exactRef(String name) throws IOException { - lock.lock(); - try { - Reftable table = reader(); - Ref ref = table.exactRef(name); - if (ref != null && ref.isSymbolic()) { - return table.resolve(ref); - } - return ref; - } finally { - lock.unlock(); - } + return reftableDatabase.exactRef(name); } /** {@inheritDoc} */ @Override public Map<String, Ref> getRefs(String prefix) throws IOException { - RefList.Builder<Ref> all = new RefList.Builder<>(); - lock.lock(); - try { - Reftable table = reader(); - try (RefCursor rc = ALL.equals(prefix) ? table.allRefs() - : (prefix.endsWith("/") ? table.seekRefsWithPrefix(prefix) //$NON-NLS-1$ - : table.seekRef(prefix))) { - while (rc.next()) { - Ref ref = table.resolve(rc.getRef()); - if (ref != null && ref.getObjectId() != null) { - all.add(ref); - } - } - } - } finally { - lock.unlock(); + List<Ref> refs = reftableDatabase.getRefsByPrefix(prefix); + RefList.Builder<Ref> builder = new RefList.Builder<>(refs.size()); + for (Ref r : refs) { + builder.add(r); } - - RefList<Ref> none = RefList.emptyList(); - return new RefMap(prefix, all.toRefList(), none, none); + return new RefMap(prefix, builder.toRefList(), RefList.emptyList(), + RefList.emptyList()); } /** {@inheritDoc} */ @Override public List<Ref> getRefsByPrefix(String prefix) throws IOException { - List<Ref> all = new ArrayList<>(); - lock.lock(); - try { - Reftable table = reader(); - try (RefCursor rc = ALL.equals(prefix) ? table.allRefs() - : table.seekRefsWithPrefix(prefix)) { - while (rc.next()) { - Ref ref = table.resolve(rc.getRef()); - if (ref != null && ref.getObjectId() != null) { - all.add(ref); - } - } - } - } finally { - lock.unlock(); - } - return Collections.unmodifiableList(all); + return reftableDatabase.getRefsByPrefix(prefix); } /** {@inheritDoc} */ @@ -283,17 +213,13 @@ public class DfsReftableDatabase extends DfsRefDatabase { if (!getReftableConfig().isIndexObjects()) { return super.getTipsWithSha1(id); } - lock.lock(); - try { - RefCursor cursor = reader().byObjectId(id); - Set<Ref> refs = new HashSet<>(); - while (cursor.next()) { - refs.add(cursor.getRef()); - } - return refs; - } finally { - lock.unlock(); - } + return reftableDatabase.getTipsWithSha1(id); + } + + /** {@inheritDoc} */ + @Override + public boolean hasFastTipsWithSha1() throws IOException { + return reftableDatabase.hasFastTipsWithSha1(); } /** {@inheritDoc} */ @@ -314,19 +240,19 @@ public class DfsReftableDatabase extends DfsRefDatabase { @Override void clearCache() { - lock.lock(); + getLock().lock(); try { - if (tableStack != null) { - tableStack.close(); - tableStack = null; - } if (ctx != null) { ctx.close(); ctx = null; } - mergedTables = null; + reftableDatabase.clearCache(); + if (stack != null) { + stack.close(); + stack = null; + } } finally { - lock.unlock(); + getLock().unlock(); } } @@ -334,7 +260,7 @@ public class DfsReftableDatabase extends DfsRefDatabase { @Override protected boolean compareAndPut(Ref oldRef, @Nullable Ref newRef) throws IOException { - ReceiveCommand cmd = toCommand(oldRef, newRef); + ReceiveCommand cmd = ReftableDatabase.toCommand(oldRef, newRef); try (RevWalk rw = new RevWalk(getRepository())) { rw.setRetainBody(false); newBatchUpdate().setAllowNonFastForwards(true).addCommand(cmd) @@ -351,58 +277,6 @@ public class DfsReftableDatabase extends DfsRefDatabase { } } - private static ReceiveCommand toCommand(Ref oldRef, Ref newRef) { - ObjectId oldId = toId(oldRef); - ObjectId newId = toId(newRef); - String name = toName(oldRef, newRef); - - if (oldRef != null && oldRef.isSymbolic()) { - if (newRef != null) { - if (newRef.isSymbolic()) { - return ReceiveCommand.link(oldRef.getTarget().getName(), - newRef.getTarget().getName(), name); - } else { - return ReceiveCommand.unlink(oldRef.getTarget().getName(), - newId, name); - } - } else { - return ReceiveCommand.unlink(oldRef.getTarget().getName(), - ObjectId.zeroId(), name); - } - } - - if (newRef != null && newRef.isSymbolic()) { - if (oldRef != null) { - if (oldRef.isSymbolic()) { - return ReceiveCommand.link(oldRef.getTarget().getName(), - newRef.getTarget().getName(), name); - } else { - return ReceiveCommand.link(oldId, - newRef.getTarget().getName(), name); - } - } else { - return ReceiveCommand.link(ObjectId.zeroId(), - newRef.getTarget().getName(), name); - } - } - - return new ReceiveCommand(oldId, newId, name); - } - - private static ObjectId toId(Ref ref) { - if (ref != null) { - ObjectId id = ref.getObjectId(); - if (id != null) { - return id; - } - } - return ObjectId.zeroId(); - } - - private static String toName(Ref oldRef, Ref newRef) { - return oldRef != null ? oldRef.getName() : newRef.getName(); - } - /** {@inheritDoc} */ @Override protected boolean compareAndRemove(Ref oldRef) throws IOException { @@ -417,12 +291,12 @@ public class DfsReftableDatabase extends DfsRefDatabase { @Override void stored(Ref ref) { - // Unnecessary; ReftableBatchRefUpdate calls clearCache(). + // Unnecessary; DfsReftableBatchRefUpdate calls clearCache(). } @Override void removed(String refName) { - // Unnecessary; ReftableBatchRefUpdate calls clearCache(). + // Unnecessary; DfsReftableBatchRefUpdate calls clearCache(). } /** {@inheritDoc} */ @@ -430,4 +304,5 @@ public class DfsReftableDatabase extends DfsRefDatabase { protected void cachePeeledState(Ref oldLeaf, Ref newLeaf) { // Do not cache peeled state in reftable. } + } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReftableStack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableStack.java index 50ba0e0f38..59621a4e67 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReftableStack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReftableStack.java @@ -48,13 +48,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.eclipse.jgit.internal.storage.reftable.Reftable; +import org.eclipse.jgit.internal.storage.reftable.ReftableReader; /** * Tracks multiple open - * {@link org.eclipse.jgit.internal.storage.reftable.Reftable} instances. + * {@link org.eclipse.jgit.internal.storage.reftable.ReftableReader} instances. */ -public class ReftableStack implements AutoCloseable { +public class DfsReftableStack implements AutoCloseable { /** * Opens a stack of tables for reading. * @@ -67,9 +67,9 @@ public class ReftableStack implements AutoCloseable { * @throws java.io.IOException * a table could not be opened */ - public static ReftableStack open(DfsReader ctx, List<DfsReftable> files) + public static DfsReftableStack open(DfsReader ctx, List<DfsReftable> files) throws IOException { - ReftableStack stack = new ReftableStack(files.size()); + DfsReftableStack stack = new DfsReftableStack(files.size()); boolean close = true; try { for (DfsReftable t : files) { @@ -86,9 +86,9 @@ public class ReftableStack implements AutoCloseable { } private final List<DfsReftable> files; - private final List<Reftable> tables; + private final List<ReftableReader> tables; - private ReftableStack(int tableCnt) { + private DfsReftableStack(int tableCnt) { this.files = new ArrayList<>(tableCnt); this.tables = new ArrayList<>(tableCnt); } @@ -109,14 +109,14 @@ public class ReftableStack implements AutoCloseable { * @return unmodifiable list of tables, in the same order the files were * passed to {@link #open(DfsReader, List)}. */ - public List<Reftable> readers() { + public List<ReftableReader> readers() { return Collections.unmodifiableList(tables); } /** {@inheritDoc} */ @Override public void close() { - for (Reftable t : tables) { + for (ReftableReader t : tables) { try { t.close(); } catch (IOException e) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java new file mode 100644 index 0000000000..fd80ad9ec0 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2019 Google LLC + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.internal.storage.file; + +import static org.eclipse.jgit.lib.Ref.UNDEFINED_UPDATE_INDEX; +import static org.eclipse.jgit.lib.Ref.Storage.NEW; +import static org.eclipse.jgit.lib.Ref.Storage.PACKED; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; + +import org.eclipse.jgit.annotations.NonNull; +import org.eclipse.jgit.events.RefsChangedEvent; +import org.eclipse.jgit.internal.storage.reftable.MergedReftable; +import org.eclipse.jgit.internal.storage.reftable.ReftableBatchRefUpdate; +import org.eclipse.jgit.internal.storage.reftable.ReftableDatabase; +import org.eclipse.jgit.internal.storage.reftable.ReftableWriter; +import org.eclipse.jgit.lib.BatchRefUpdate; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdRef; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefDatabase; +import org.eclipse.jgit.lib.RefRename; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.ReflogEntry; +import org.eclipse.jgit.lib.ReflogReader; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.SymbolicRef; +import org.eclipse.jgit.revwalk.RevObject; +import org.eclipse.jgit.revwalk.RevTag; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.ReceiveCommand; +import org.eclipse.jgit.util.FileUtils; +import org.eclipse.jgit.util.RefList; +import org.eclipse.jgit.util.RefMap; + +/** + * Implements RefDatabase using reftable for storage. + * + * This class is threadsafe. + */ +public class FileReftableDatabase extends RefDatabase { + private final ReftableDatabase reftableDatabase; + + private final FileRepository fileRepository; + + private final FileReftableStack reftableStack; + + FileReftableDatabase(FileRepository repo, File refstackName) throws IOException { + this.fileRepository = repo; + this.reftableStack = new FileReftableStack(refstackName, + new File(fileRepository.getDirectory(), Constants.REFTABLE), + () -> fileRepository.fireEvent(new RefsChangedEvent()), + () -> fileRepository.getConfig()); + this.reftableDatabase = new ReftableDatabase() { + + @Override + public MergedReftable openMergedReftable() throws IOException { + return reftableStack.getMergedReftable(); + } + }; + } + + ReflogReader getReflogReader(String refname) throws IOException { + return reftableDatabase.getReflogReader(refname); + } + + /** + * @param repoDir + * @return whether the given repo uses reftable for refdb storage. + */ + public static boolean isReftable(File repoDir) { + return new File(repoDir, "refs").isFile() //$NON-NLS-1$ + && new File(repoDir, Constants.REFTABLE).isDirectory(); + } + + /** {@inheritDoc} */ + @Override + public boolean hasFastTipsWithSha1() throws IOException { + return reftableDatabase.hasFastTipsWithSha1(); + } + + /** + * Runs a full compaction for GC purposes. + * @throws IOException on I/O errors + */ + public void compactFully() throws IOException { + reftableDatabase.getLock().lock(); + try { + reftableStack.compactFully(); + } finally { + reftableDatabase.getLock().unlock(); + } + } + + private ReentrantLock getLock() { + return reftableDatabase.getLock(); + } + + /** {@inheritDoc} */ + @Override + public boolean performsAtomicTransactions() { + return true; + } + + /** {@inheritDoc} */ + @NonNull + @Override + public BatchRefUpdate newBatchUpdate() { + return new FileReftableBatchRefUpdate(this, fileRepository); + } + + /** {@inheritDoc} */ + @Override + public RefUpdate newUpdate(String refName, boolean detach) + throws IOException { + boolean detachingSymbolicRef = false; + Ref ref = exactRef(refName); + + if (ref == null) { + ref = new ObjectIdRef.Unpeeled(NEW, refName, null); + } else { + detachingSymbolicRef = detach && ref.isSymbolic(); + } + + RefUpdate update = new FileReftableRefUpdate(ref); + if (detachingSymbolicRef) { + update.setDetachingSymbolicRef(); + } + return update; + } + + /** {@inheritDoc} */ + @Override + public Ref exactRef(String name) throws IOException { + return reftableDatabase.exactRef(name); + } + + /** {@inheritDoc} */ + @Override + public List<Ref> getRefs() throws IOException { + return super.getRefs(); + } + + /** {@inheritDoc} */ + @Override + public Map<String, Ref> getRefs(String prefix) throws IOException { + List<Ref> refs = reftableDatabase.getRefsByPrefix(prefix); + RefList.Builder<Ref> builder = new RefList.Builder<>(refs.size()); + for (Ref r : refs) { + builder.add(r); + } + return new RefMap(prefix, builder.toRefList(), RefList.emptyList(), + RefList.emptyList()); + } + + /** {@inheritDoc} */ + @Override + public List<Ref> getAdditionalRefs() throws IOException { + return Collections.emptyList(); + } + + /** {@inheritDoc} */ + @Override + public Ref peel(Ref ref) throws IOException { + Ref oldLeaf = ref.getLeaf(); + if (oldLeaf.isPeeled() || oldLeaf.getObjectId() == null) { + return ref; + } + return recreate(ref, doPeel(oldLeaf), hasVersioning()); + + } + + private Ref doPeel(Ref leaf) throws IOException { + try (RevWalk rw = new RevWalk(fileRepository)) { + RevObject obj = rw.parseAny(leaf.getObjectId()); + if (obj instanceof RevTag) { + return new ObjectIdRef.PeeledTag(leaf.getStorage(), + leaf.getName(), leaf.getObjectId(), rw.peel(obj).copy(), + hasVersioning() ? leaf.getUpdateIndex() + : UNDEFINED_UPDATE_INDEX); + } + return new ObjectIdRef.PeeledNonTag(leaf.getStorage(), + leaf.getName(), leaf.getObjectId(), + hasVersioning() ? leaf.getUpdateIndex() + : UNDEFINED_UPDATE_INDEX); + + } + } + + private static Ref recreate(Ref old, Ref leaf, boolean hasVersioning) { + if (old.isSymbolic()) { + Ref dst = recreate(old.getTarget(), leaf, hasVersioning); + return new SymbolicRef(old.getName(), dst, + hasVersioning ? old.getUpdateIndex() + : UNDEFINED_UPDATE_INDEX); + } + return leaf; + } + + private class FileRefRename extends RefRename { + FileRefRename(RefUpdate src, RefUpdate dst) { + super(src, dst); + } + + void writeRename(ReftableWriter w) throws IOException { + long idx = reftableDatabase.nextUpdateIndex(); + w.setMinUpdateIndex(idx).setMaxUpdateIndex(idx).begin(); + List<Ref> refs = new ArrayList<>(3); + + Ref dest = destination.getRef(); + Ref head = exactRef(Constants.HEAD); + if (head != null && head.isSymbolic() + && head.getLeaf().getName().equals(source.getName())) { + head = new SymbolicRef(Constants.HEAD, dest, idx); + refs.add(head); + } + + ObjectId objId = source.getRef().getObjectId(); + + // XXX should we check if the source is a Tag vs. NonTag? + refs.add(new ObjectIdRef.PeeledNonTag(Ref.Storage.NEW, + destination.getName(), objId)); + refs.add(new ObjectIdRef.Unpeeled(Ref.Storage.NEW, source.getName(), + null)); + + w.sortAndWriteRefs(refs); + PersonIdent who = destination.getRefLogIdent(); + if (who == null) { + who = new PersonIdent(fileRepository); + } + + if (!destination.getRefLogMessage().isEmpty()) { + List<String> refnames = refs.stream().map(r -> r.getName()) + .collect(Collectors.toList()); + Collections.sort(refnames); + for (String s : refnames) { + ObjectId old = (Constants.HEAD.equals(s) + || s.equals(source.getName())) ? objId + : ObjectId.zeroId(); + ObjectId newId = (Constants.HEAD.equals(s) + || s.equals(destination.getName())) ? objId + : ObjectId.zeroId(); + + w.writeLog(s, idx, who, old, newId, + destination.getRefLogMessage()); + } + } + } + + @Override + protected RefUpdate.Result doRename() throws IOException { + Ref src = exactRef(source.getName()); + if (exactRef(destination.getName()) != null || src == null + || !source.getOldObjectId().equals(src.getObjectId())) { + return RefUpdate.Result.LOCK_FAILURE; + } + + if (src.isSymbolic()) { + // We could support this, but this is easier and compatible. + return RefUpdate.Result.IO_FAILURE; + } + + if (!addReftable(this::writeRename)) { + return RefUpdate.Result.LOCK_FAILURE; + } + + return RefUpdate.Result.RENAMED; + } + } + + /** {@inheritDoc} */ + @Override + public RefRename newRename(String fromName, String toName) + throws IOException { + RefUpdate src = newUpdate(fromName, true); + RefUpdate dst = newUpdate(toName, true); + return new FileRefRename(src, dst); + } + + /** {@inheritDoc} */ + @Override + public boolean isNameConflicting(String name) throws IOException { + return reftableDatabase.isNameConflicting(name, new TreeSet<>(), + new HashSet<>()); + } + + /** {@inheritDoc} */ + @Override + public void close() { + reftableStack.close(); + } + + /** {@inheritDoc} */ + @Override + public void create() throws IOException { + FileUtils.mkdir( + new File(fileRepository.getDirectory(), Constants.REFTABLE), + true); + } + + private boolean addReftable(FileReftableStack.Writer w) throws IOException { + if (!reftableStack.addReftable(w)) { + reftableStack.reload(); + reftableDatabase.clearCache(); + return false; + } + reftableDatabase.clearCache(); + + return true; + } + + private class FileReftableBatchRefUpdate extends ReftableBatchRefUpdate { + FileReftableBatchRefUpdate(FileReftableDatabase db, + Repository repository) { + super(db, db.reftableDatabase, db.getLock(), repository); + } + + @Override + protected void applyUpdates(List<Ref> newRefs, + List<ReceiveCommand> pending) throws IOException { + if (!addReftable(rw -> write(rw, newRefs, pending))) { + for (ReceiveCommand c : pending) { + if (c.getResult() == ReceiveCommand.Result.NOT_ATTEMPTED) { + c.setResult(RefUpdate.Result.LOCK_FAILURE); + } + } + } + } + } + + private class FileReftableRefUpdate extends RefUpdate { + FileReftableRefUpdate(Ref ref) { + super(ref); + } + + @Override + protected RefDatabase getRefDatabase() { + return FileReftableDatabase.this; + } + + @Override + protected Repository getRepository() { + return FileReftableDatabase.this.fileRepository; + } + + @Override + protected void unlock() { + // nop. + } + + private RevWalk rw; + + private Ref dstRef; + + @Override + public Result update(RevWalk walk) throws IOException { + try { + rw = walk; + return super.update(walk); + } finally { + rw = null; + } + } + + @Override + protected boolean tryLock(boolean deref) throws IOException { + dstRef = getRef(); + if (deref) { + dstRef = dstRef.getLeaf(); + } + + Ref derefed = exactRef(dstRef.getName()); + if (derefed != null) { + setOldObjectId(derefed.getObjectId()); + } + + return true; + } + + void writeUpdate(ReftableWriter w) throws IOException { + Ref newRef = null; + if (rw != null && !ObjectId.zeroId().equals(getNewObjectId())) { + RevObject obj = rw.parseAny(getNewObjectId()); + if (obj instanceof RevTag) { + newRef = new ObjectIdRef.PeeledTag(Ref.Storage.PACKED, + dstRef.getName(), getNewObjectId(), + rw.peel(obj).copy()); + } + } + if (newRef == null) { + newRef = new ObjectIdRef.PeeledNonTag(Ref.Storage.PACKED, + dstRef.getName(), getNewObjectId()); + } + + long idx = reftableDatabase.nextUpdateIndex(); + w.setMinUpdateIndex(idx).setMaxUpdateIndex(idx).begin() + .writeRef(newRef); + + ObjectId oldId = getOldObjectId(); + if (oldId == null) { + oldId = ObjectId.zeroId(); + } + w.writeLog(dstRef.getName(), idx, getRefLogIdent(), oldId, + getNewObjectId(), getRefLogMessage()); + } + + @Override + public PersonIdent getRefLogIdent() { + PersonIdent who = super.getRefLogIdent(); + if (who == null) { + who = new PersonIdent(getRepository()); + } + return who; + } + + void writeDelete(ReftableWriter w) throws IOException { + Ref newRef = new ObjectIdRef.Unpeeled(Ref.Storage.NEW, + dstRef.getName(), null); + long idx = reftableDatabase.nextUpdateIndex(); + w.setMinUpdateIndex(idx).setMaxUpdateIndex(idx).begin() + .writeRef(newRef); + + ObjectId oldId = ObjectId.zeroId(); + Ref old = exactRef(dstRef.getName()); + if (old != null) { + old = old.getLeaf(); + if (old.getObjectId() != null) { + oldId = old.getObjectId(); + } + } + + w.writeLog(dstRef.getName(), idx, getRefLogIdent(), oldId, + ObjectId.zeroId(), getRefLogMessage()); + } + + @Override + protected Result doUpdate(Result desiredResult) throws IOException { + if (isRefLogIncludingResult()) { + setRefLogMessage( + getRefLogMessage() + ": " + desiredResult.toString(), //$NON-NLS-1$ + false); + } + + if (!addReftable(this::writeUpdate)) { + return Result.LOCK_FAILURE; + } + + return desiredResult; + } + + @Override + protected Result doDelete(Result desiredResult) throws IOException { + + if (isRefLogIncludingResult()) { + setRefLogMessage( + getRefLogMessage() + ": " + desiredResult.toString(), //$NON-NLS-1$ + false); + } + + if (!addReftable(this::writeDelete)) { + return Result.LOCK_FAILURE; + } + + return desiredResult; + } + + void writeLink(ReftableWriter w) throws IOException { + long idx = reftableDatabase.nextUpdateIndex(); + w.setMinUpdateIndex(idx).setMaxUpdateIndex(idx).begin() + .writeRef(dstRef); + + ObjectId beforeId = ObjectId.zeroId(); + Ref before = exactRef(dstRef.getName()); + if (before != null) { + before = before.getLeaf(); + if (before.getObjectId() != null) { + beforeId = before.getObjectId(); + } + } + + Ref after = dstRef.getLeaf(); + ObjectId afterId = ObjectId.zeroId(); + if (after.getObjectId() != null) { + afterId = after.getObjectId(); + } + + w.writeLog(dstRef.getName(), idx, getRefLogIdent(), beforeId, + afterId, getRefLogMessage()); + } + + @Override + protected Result doLink(String target) throws IOException { + if (isRefLogIncludingResult()) { + setRefLogMessage( + getRefLogMessage() + ": " + Result.FORCED.toString(), //$NON-NLS-1$ + false); + } + + boolean exists = exactRef(getName()) != null; + dstRef = new SymbolicRef(getName(), + new ObjectIdRef.Unpeeled(Ref.Storage.NEW, target, null), + reftableDatabase.nextUpdateIndex()); + + if (!addReftable(this::writeLink)) { + return Result.LOCK_FAILURE; + } + // XXX unclear if we should support FORCED here. Baseclass says + // NEW is OK ? + return exists ? Result.FORCED : Result.NEW; + } + } + + private static void writeConvertTable(Repository repo, ReftableWriter w, + boolean writeLogs) throws IOException { + int size = 0; + List<Ref> refs = repo.getRefDatabase().getRefs(); + if (writeLogs) { + for (Ref r : refs) { + ReflogReader rlr = repo.getReflogReader(r.getName()); + if (rlr != null) { + size = Math.max(rlr.getReverseEntries().size(), size); + } + } + } + // We must use 1 here, nextUpdateIndex() on the empty stack is 1. + w.setMinUpdateIndex(1).setMaxUpdateIndex(size + 1).begin(); + + // The spec says to write the logs in the first table, and put refs in a + // separate table, but this complicates the compaction (when we can we drop + // deletions? Can we compact the .log table and the .ref table together?) + try (RevWalk rw = new RevWalk(repo)) { + List<Ref> toWrite = new ArrayList<>(refs.size()); + for (Ref r : refs) { + toWrite.add(refForWrite(rw, r)); + } + w.sortAndWriteRefs(toWrite); + } + + if (writeLogs) { + for (Ref r : refs) { + long idx = size; + ReflogReader reader = repo.getReflogReader(r.getName()); + if (reader == null) { + continue; + } + for (ReflogEntry e : reader.getReverseEntries()) { + w.writeLog(r.getName(), idx, e.getWho(), e.getOldId(), + e.getNewId(), e.getComment()); + idx--; + } + } + } + } + + private static Ref refForWrite(RevWalk rw, Ref r) throws IOException { + if (r.isSymbolic()) { + return new SymbolicRef(r.getName(), new ObjectIdRef.Unpeeled(NEW, + r.getTarget().getName(), null)); + } + ObjectId newId = r.getObjectId(); + RevObject obj = rw.parseAny(newId); + RevObject peel = null; + if (obj instanceof RevTag) { + peel = rw.peel(obj); + } + if (peel != null) { + return new ObjectIdRef.PeeledTag(PACKED, r.getName(), newId, + peel.copy()); + } + return new ObjectIdRef.PeeledNonTag(PACKED, r.getName(), newId); + } + + /** + * @param repo + * the repository + * @param refstackName + * the filename for the stack + * @param writeLogs + * whether to write reflogs + * @return a reftable based RefDB from an existing repository. + * @throws IOException + * on IO error + */ + public static FileReftableDatabase convertFrom(FileRepository repo, + File refstackName, boolean writeLogs) throws IOException { + FileReftableDatabase newDb = null; + try { + File reftableDir = new File(repo.getDirectory(), Constants.REFTABLE); + if (!reftableDir.isDirectory()) { + reftableDir.mkdir(); + } + + try (FileReftableStack stack = new FileReftableStack(refstackName, + reftableDir, null, () -> repo.getConfig())) { + stack.addReftable(rw -> writeConvertTable(repo, rw, writeLogs)); + } + refstackName = null; + } finally { + if (refstackName != null) { + refstackName.delete(); + } + } + return newDb; + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java new file mode 100644 index 0000000000..2c416c3802 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableStack.java @@ -0,0 +1,768 @@ +/* + * Copyright (C) 2019 Google LLC + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.internal.storage.file; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.errors.LockFailedException; +import org.eclipse.jgit.internal.storage.io.BlockSource; +import org.eclipse.jgit.internal.storage.reftable.MergedReftable; +import org.eclipse.jgit.internal.storage.reftable.ReftableCompactor; +import org.eclipse.jgit.internal.storage.reftable.ReftableConfig; +import org.eclipse.jgit.internal.storage.reftable.ReftableReader; +import org.eclipse.jgit.internal.storage.reftable.ReftableWriter; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.util.FileUtils; + +/** + * A mutable stack of reftables on local filesystem storage. Not thread-safe. + * This is an AutoCloseable because this object owns the file handles to the + * open reftables. + */ +public class FileReftableStack implements AutoCloseable { + private static class StackEntry { + + String name; + + ReftableReader reftableReader; + } + + private MergedReftable mergedReftable; + + private List<StackEntry> stack; + + private long lastNextUpdateIndex; + + private final File stackPath; + + private final File reftableDir; + + private final Runnable onChange; + + private final Supplier<Config> configSupplier; + + // Used for stats & testing. + static class CompactionStats { + + long tables; + + long bytes; + + int attempted; + + int failed; + + long refCount; + + long logCount; + + CompactionStats() { + tables = 0; + bytes = 0; + attempted = 0; + failed = 0; + logCount = 0; + refCount = 0; + } + } + + private final CompactionStats stats; + + /** + * Creates a stack corresponding to the list of reftables in the argument + * + * @param stackPath + * the filename for the stack. + * @param reftableDir + * the dir holding the tables. + * @param onChange + * hook to call if we notice a new write + * @param configSupplier + * Config supplier + * @throws IOException + * on I/O problems + */ + public FileReftableStack(File stackPath, File reftableDir, + @Nullable Runnable onChange, Supplier<Config> configSupplier) + throws IOException { + this.stackPath = stackPath; + this.reftableDir = reftableDir; + this.stack = new ArrayList<>(); + this.configSupplier = configSupplier; + this.onChange = onChange; + + // skip event notification + lastNextUpdateIndex = 0; + reload(); + + stats = new CompactionStats(); + } + + CompactionStats getStats() { + return stats; + } + + /** Thrown if the update indices in the stack are not monotonic */ + public static class ReftableNumbersNotIncreasingException + extends RuntimeException { + private static final long serialVersionUID = 1L; + + String name; + + long lastMax; + + long min; + + ReftableNumbersNotIncreasingException(String name, long lastMax, + long min) { + this.name = name; + this.lastMax = lastMax; + this.min = min; + } + } + + /** + * Reloads the stack, potentially reusing opened reftableReaders. + * + * @param names + * holds the names of the tables to load. + * @throws FileNotFoundException + * load must be retried. + * @throws IOException + * on other IO errors. + */ + private void reloadOnce(List<String> names) + throws IOException, FileNotFoundException { + Map<String, ReftableReader> current = stack.stream() + .collect(Collectors.toMap(e -> e.name, e -> e.reftableReader)); + + List<ReftableReader> newTables = new ArrayList<>(); + List<StackEntry> newStack = new ArrayList<>(stack.size() + 1); + try { + ReftableReader last = null; + for (String name : names) { + StackEntry entry = new StackEntry(); + entry.name = name; + + ReftableReader t = null; + if (current.containsKey(name)) { + t = current.remove(name); + } else { + File subtable = new File(reftableDir, name); + FileInputStream is; + + is = new FileInputStream(subtable); + + t = new ReftableReader(BlockSource.from(is)); + newTables.add(t); + } + + if (last != null) { + // TODO: move this to MergedReftable + if (last.maxUpdateIndex() >= t.minUpdateIndex()) { + throw new ReftableNumbersNotIncreasingException(name, + last.maxUpdateIndex(), t.minUpdateIndex()); + } + } + last = t; + + entry.reftableReader = t; + newStack.add(entry); + } + // survived without exceptions: swap in new stack, and close + // dangling tables. + stack = newStack; + newTables.clear(); + + current.values().forEach(r -> { + try { + r.close(); + } catch (IOException e) { + throw new AssertionError(e); + } + }); + } finally { + newTables.forEach(t -> { + try { + t.close(); + } catch (IOException ioe) { + // reader close should not generate errors. + throw new AssertionError(ioe); + } + }); + } + } + + void reload() throws IOException { + // Try for 2.5 seconds. + long deadline = System.currentTimeMillis() + 2500; + // A successful reftable transaction is 2 atomic file writes + // (open, write, close, rename), which a fast Linux system should be + // able to do in about ~200us. So 1 ms should be ample time. + long min = 1; + long max = 1000; + long delay = 0; + boolean success = false; + while (System.currentTimeMillis() < deadline) { + List<String> names = readTableNames(); + try { + reloadOnce(names); + success = true; + break; + } catch (FileNotFoundException e) { + List<String> changed = readTableNames(); + if (changed.equals(names)) { + throw e; + } + } + + delay = FileUtils.delay(delay, min, max); + try { + Thread.sleep(delay); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + } + + if (!success) { + // TODO: should reexamine the 'refs' file to see if it was the same + // if it didn't change, then we must have corruption. If it did, + // retry. + throw new LockFailedException(stackPath); + } + + mergedReftable = new MergedReftable(stack.stream() + .map(x -> x.reftableReader).collect(Collectors.toList())); + long curr = nextUpdateIndex(); + if (lastNextUpdateIndex > 0 && lastNextUpdateIndex != curr + && onChange != null) { + onChange.run(); + } + lastNextUpdateIndex = curr; + } + + /** + * @return the merged reftable + */ + public MergedReftable getMergedReftable() { + return mergedReftable; + } + + /** + * Writer is a callable that writes data to a reftable under construction. + * It should set the min/max update index, and then write refs and/or logs. + * It should not call finish() on the writer. + */ + public interface Writer { + /** + * Write data to reftable + * + * @param w + * writer to use + * @throws IOException + */ + void call(ReftableWriter w) throws IOException; + } + + private List<String> readTableNames() throws IOException { + List<String> names = new ArrayList<>(stack.size() + 1); + + try (BufferedReader br = new BufferedReader( + new InputStreamReader(new FileInputStream(stackPath), UTF_8))) { + String line; + while ((line = br.readLine()) != null) { + if (!line.isEmpty()) { + names.add(line); + } + } + } catch (FileNotFoundException e) { + // file isn't there: empty repository. + } + return names; + } + + /** + * @return true if the on-disk file corresponds to the in-memory data. + * @throws IOException + * on IO problem + */ + boolean isUpToDate() throws IOException { + // We could use FileSnapshot to avoid reading the file, but the file is + // small so it's probably a minor optimization. + try { + List<String> names = readTableNames(); + if (names.size() != stack.size()) { + return false; + } + for (int i = 0; i < names.size(); i++) { + if (!names.get(i).equals(stack.get(i).name)) { + return false; + } + } + } catch (FileNotFoundException e) { + return stack.isEmpty(); + } + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public void close() { + for (StackEntry entry : stack) { + try { + entry.reftableReader.close(); + } catch (Exception e) { + // we are reading; this should never fail. + throw new AssertionError(e); + } + } + } + + private long nextUpdateIndex() throws IOException { + return stack.size() > 0 + ? stack.get(stack.size() - 1).reftableReader.maxUpdateIndex() + + 1 + : 1; + } + + private String filename(long low, long high) { + return String.format("%012x-%012x", //$NON-NLS-1$ + Long.valueOf(low), Long.valueOf(high)); + } + + /** + * Tries to add a new reftable to the stack. Returns true if it succeeded, + * or false if there was a lock failure, due to races with other processes. + * This is package private so FileReftableDatabase can call into here. + * + * @param w + * writer to write data to a reftable under construction + * @return true if the transaction. + * @throws IOException + * on I/O problems + */ + @SuppressWarnings("nls") + public boolean addReftable(Writer w) throws IOException { + LockFile lock = new LockFile(stackPath); + try { + if (!lock.lockForAppend()) { + return false; + } + if (!isUpToDate()) { + return false; + } + + String fn = filename(nextUpdateIndex(), nextUpdateIndex()); + + File tmpTable = File.createTempFile(fn + "_", ".ref", + stackPath.getParentFile()); + + ReftableWriter.Stats s; + try (FileOutputStream fos = new FileOutputStream(tmpTable)) { + ReftableWriter rw = new ReftableWriter(reftableConfig(), fos); + w.call(rw); + rw.finish(); + s = rw.getStats(); + } + + if (s.minUpdateIndex() < nextUpdateIndex()) { + return false; + } + + // The spec says to name log-only files with .log, which is somewhat + // pointless given compaction, but we do so anyway. + fn += s.refCount() > 0 ? ".ref" : ".log"; + File dest = new File(reftableDir, fn); + + FileUtils.rename(tmpTable, dest, StandardCopyOption.ATOMIC_MOVE); + lock.write((fn + "\n").getBytes(UTF_8)); + if (!lock.commit()) { + FileUtils.delete(dest); + return false; + } + + reload(); + + autoCompact(); + } finally { + lock.unlock(); + } + return true; + } + + private ReftableConfig reftableConfig() { + return new ReftableConfig(configSupplier.get()); + } + + /** + * Write the reftable for the given range into a temp file. + * + * @param first + * index of first stack entry to be written + * @param last + * index of last stack entry to be written + * @return the file holding the replacement table. + * @throws IOException + * on I/O problem + */ + private File compactLocked(int first, int last) throws IOException { + String fn = filename(first, last); + + File tmpTable = File.createTempFile(fn + "_", ".ref", //$NON-NLS-1$//$NON-NLS-2$ + stackPath.getParentFile()); + try (FileOutputStream fos = new FileOutputStream(tmpTable)) { + ReftableCompactor c = new ReftableCompactor(fos) + .setConfig(reftableConfig()) + .setMinUpdateIndex( + stack.get(first).reftableReader.minUpdateIndex()) + .setMaxUpdateIndex( + stack.get(last).reftableReader.maxUpdateIndex()) + .setIncludeDeletes(first > 0); + + List<ReftableReader> compactMe = new ArrayList<>(); + long totalBytes = 0; + for (int i = first; i <= last; i++) { + compactMe.add(stack.get(i).reftableReader); + totalBytes += stack.get(i).reftableReader.size(); + } + c.addAll(compactMe); + + c.compact(); + + // Even though the compaction did not definitely succeed, we keep + // tally here as we've expended the effort. + stats.bytes += totalBytes; + stats.tables += first - last + 1; + stats.attempted++; + stats.refCount += c.getStats().refCount(); + stats.logCount += c.getStats().logCount(); + } + + return tmpTable; + } + + /** + * Compacts a range of the stack, following the file locking protocol + * documented in the spec. + * + * @param first + * index of first stack entry to be considered in compaction + * @param last + * index of last stack entry to be considered in compaction + * @return true if a compaction was successfully applied. + * @throws IOException + * on I/O problem + */ + boolean compactRange(int first, int last) throws IOException { + if (first >= last) { + return true; + } + LockFile lock = new LockFile(stackPath); + + File tmpTable = null; + List<LockFile> subtableLocks = new ArrayList<>(); + + try { + if (!lock.lock()) { + return false; + } + if (!isUpToDate()) { + return false; + } + + List<File> deleteOnSuccess = new ArrayList<>(); + for (int i = first; i <= last; i++) { + File f = new File(reftableDir, stack.get(i).name); + LockFile lf = new LockFile(f); + if (!lf.lock()) { + return false; + } + subtableLocks.add(lf); + deleteOnSuccess.add(f); + } + + lock.unlock(); + lock = null; + + tmpTable = compactLocked(first, last); + + lock = new LockFile(stackPath); + if (!lock.lock()) { + return false; + } + if (!isUpToDate()) { + return false; + } + + String fn = filename( + stack.get(first).reftableReader.minUpdateIndex(), + stack.get(last).reftableReader.maxUpdateIndex()); + + // The spec suggests to use .log for log-only tables, and collect + // all log entries in a single file at the bottom of the stack. That would + // require supporting overlapping ranges for the different tables. For the + // sake of simplicity, we simply ignore this and always produce a log + + // ref combined table. + fn += ".ref"; //$NON-NLS-1$ + File dest = new File(reftableDir, fn); + + FileUtils.rename(tmpTable, dest, StandardCopyOption.ATOMIC_MOVE); + tmpTable = null; + + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < first; i++) { + sb.append(stack.get(i).name + "\n"); //$NON-NLS-1$ + } + sb.append(fn + "\n"); //$NON-NLS-1$ + for (int i = last + 1; i < stack.size(); i++) { + sb.append(stack.get(i).name + "\n"); //$NON-NLS-1$ + } + + lock.write(sb.toString().getBytes(UTF_8)); + if (!lock.commit()) { + dest.delete(); + return false; + } + + for (File f : deleteOnSuccess) { + Files.delete(f.toPath()); + } + + reload(); + return true; + } finally { + if (tmpTable != null) { + tmpTable.delete(); + } + for (LockFile lf : subtableLocks) { + lf.unlock(); + } + if (lock != null) { + lock.unlock(); + } + } + } + + /** + * Calculate an approximate log2. + * + * @param sz + * @return log2 + */ + static int log(long sz) { + long base = 2; + if (sz <= 0) { + throw new IllegalArgumentException("log2 negative"); //$NON-NLS-1$ + } + int l = 0; + while (sz > 0) { + l++; + sz /= base; + } + + return l - 1; + } + + /** + * A segment is a consecutive list of reftables of the same approximate + * size. + */ + static class Segment { + // the approximate log_2 of the size. + int log; + + // The total bytes in this segment + long bytes; + + int start; + + int end; // exclusive. + + int size() { + return end - start; + } + + Segment(int start, int end, int log, long bytes) { + this.log = log; + this.start = start; + this.end = end; + this.bytes = bytes; + } + + Segment() { + this(0, 0, 0, 0); + } + + @Override + public int hashCode() { + return 0; // appease error-prone + } + + @Override + public boolean equals(Object other) { + Segment o = (Segment) other; + return o.bytes == bytes && o.log == log && o.start == start + && o.end == end; + } + + @SuppressWarnings("boxing") + @Override + public String toString() { + return String.format("{ [%d,%d) l=%d sz=%d }", start, end, log, //$NON-NLS-1$ + bytes); + } + } + + static List<Segment> segmentSizes(long sizes[]) { + List<Segment> segments = new ArrayList<>(); + Segment cur = new Segment(); + for (int i = 0; i < sizes.length; i++) { + int l = log(sizes[i]); + if (l != cur.log && cur.bytes > 0) { + segments.add(cur); + cur = new Segment(); + cur.start = i; + cur.log = l; + } + + cur.log = l; + cur.end = i + 1; + cur.bytes += sizes[i]; + } + segments.add(cur); + return segments; + } + + private static Optional<Segment> autoCompactCandidate(long sizes[]) { + if (sizes.length == 0) { + return Optional.empty(); + } + + // The cost of compaction is proportional to the size, and we want to + // avoid frequent large compactions. We do this by playing the game 2048 + // here: first compact together the smallest tables if there are more + // than one. Then try to see if the result will be big enough to match + // up with next up. + + List<Segment> segments = segmentSizes(sizes); + segments = segments.stream().filter(s -> s.size() > 1) + .collect(Collectors.toList()); + if (segments.isEmpty()) { + return Optional.empty(); + } + + Optional<Segment> optMinSeg = segments.stream() + .min(Comparator.comparing(s -> Integer.valueOf(s.log))); + // Input is non-empty, so always present. + Segment smallCollected = optMinSeg.get(); + while (smallCollected.start > 0) { + int prev = smallCollected.start - 1; + long prevSize = sizes[prev]; + if (log(smallCollected.bytes) < log(prevSize)) { + break; + } + smallCollected.start = prev; + smallCollected.bytes += prevSize; + } + + return Optional.of(smallCollected); + } + + /** + * Heuristically tries to compact the stack if the stack has a suitable + * shape. + * + * @throws IOException + */ + private void autoCompact() throws IOException { + Optional<Segment> cand = autoCompactCandidate(tableSizes()); + if (cand.isPresent()) { + if (!compactRange(cand.get().start, cand.get().end - 1)) { + stats.failed++; + } + } + } + + // 68b footer, 24b header = 92. + private static long OVERHEAD = 91; + + private long[] tableSizes() throws IOException { + long[] sizes = new long[stack.size()]; + for (int i = 0; i < stack.size(); i++) { + // If we don't subtract the overhead, the file size isn't + // proportional to the number of entries. This will cause us to + // compact too often, which is expensive. + sizes[i] = stack.get(i).reftableReader.size() - OVERHEAD; + } + return sizes; + } + + void compactFully() throws IOException { + if (!compactRange(0, stack.size() - 1)) { + stats.failed++; + } + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java index 4f5f8a613e..2f6ef51133 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java @@ -46,13 +46,17 @@ package org.eclipse.jgit.internal.storage.file; +import static java.util.stream.Collectors.toList; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.text.MessageFormat; import java.text.ParseException; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Set; @@ -68,10 +72,12 @@ import org.eclipse.jgit.internal.storage.file.ObjectDirectory.AlternateHandle; import org.eclipse.jgit.internal.storage.file.ObjectDirectory.AlternateRepository; import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase; import org.eclipse.jgit.lib.BaseRepositoryBuilder; +import org.eclipse.jgit.lib.BatchRefUpdate; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.CoreConfig.HideDotFiles; import org.eclipse.jgit.lib.CoreConfig.SymLinks; +import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; @@ -80,9 +86,11 @@ import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.ReflogReader; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.storage.pack.PackConfig; +import org.eclipse.jgit.transport.ReceiveCommand; import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.RawParseUtils; @@ -121,7 +129,7 @@ public class FileRepository extends Repository { private static final String UNNAMED = "Unnamed repository; edit this file to name it for gitweb."; //$NON-NLS-1$ private final FileBasedConfig repoConfig; - private final RefDatabase refs; + private RefDatabase refs; private final ObjectDirectory objectDatabase; private final Object snapshotLock = new Object(); @@ -199,11 +207,16 @@ public class FileRepository extends Repository { String reftype = repoConfig.getString( "extensions", null, "refStorage"); //$NON-NLS-1$ //$NON-NLS-2$ if (repositoryFormatVersion >= 1 && reftype != null) { - if (StringUtils.equalsIgnoreCase(reftype, "reftree")) { //$NON-NLS-1$ + if (StringUtils.equalsIgnoreCase(reftype, "reftable")) { //$NON-NLS-1$ + refs = new FileReftableDatabase(this, + new File(getDirectory(), "refs")); //$NON-NLS-1$ + } else if (StringUtils.equalsIgnoreCase(reftype, "reftree")) { //$NON-NLS-1$ refs = new RefTreeDatabase(this, new RefDirectory(this)); } else { throw new IOException(JGitText.get().unknownRepositoryFormat); } + } else if (FileReftableDatabase.isReftable(getDirectory())) { + refs = new FileReftableDatabase(this, new File(getDirectory(), "refs")); //$NON-NLS-1$ } else { refs = new RefDirectory(this); } @@ -358,9 +371,8 @@ public class FileRepository extends Repository { File directory = getDirectory(); if (directory != null) { return directory.getPath(); - } else { - throw new IllegalStateException(); } + throw new IllegalStateException(); } /** {@inheritDoc} */ @@ -531,10 +543,19 @@ public class FileRepository extends Repository { /** {@inheritDoc} */ @Override public ReflogReader getReflogReader(String refName) throws IOException { + if (refs instanceof FileReftableDatabase) { + // Cannot use findRef: reftable stores log data for deleted or renamed + // branches. + return ((FileReftableDatabase)refs).getReflogReader(refName); + } + + // TODO: use exactRef here, which offers more predictable and therefore preferable + // behavior. Ref ref = findRef(refName); - if (ref != null) - return new ReflogReaderImpl(this, ref.getName()); - return null; + if (ref == null) { + return null; + } + return new ReflogReaderImpl(this, ref.getName()); } /** {@inheritDoc} */ @@ -614,4 +635,173 @@ public class FileRepository extends Repository { throw new JGitInternalException(JGitText.get().gcFailed, e); } } + + /** + * Converts the RefDatabase from reftable to RefDirectory. This operation is + * not atomic. + * + * @param backup + * whether to rename or delete the old storage files. If set to + * true, the reftable list is left in "refs.old", and the + * reftable/ dir is left alone. If set to false, the reftable/ + * dir is removed, and "refs" file is removed. + * @throws IOException + * on IO problem + */ + void convertToPackedRefs(boolean backup) throws IOException { + List<Ref> all = refs.getRefs(); + File packedRefs = new File(getDirectory(), Constants.PACKED_REFS); + if (packedRefs.exists()) { + throw new IOException(MessageFormat.format(JGitText.get().fileAlreadyExists, + packedRefs.getName())); + } + + File refsFile = new File(getDirectory(), "refs"); //$NON-NLS-1$ + + refs.close(); + + if (backup) { + File refsOld = new File(getDirectory(), "refs.old"); //$NON-NLS-1$ + if (refsOld.exists()) { + throw new IOException(MessageFormat.format( + JGitText.get().fileAlreadyExists, + "refs.old")); //$NON-NLS-1$ + } + FileUtils.rename(refsFile, refsOld); + } else { + refsFile.delete(); + } + + // This is not atomic, but there is no way to instantiate a RefDirectory + // that is disconnected from the current repo. + refs = new RefDirectory(this); + refs.create(); + + List<Ref> symrefs = new ArrayList<>(); + BatchRefUpdate bru = refs.newBatchUpdate(); + for (Ref r : all) { + if (r.isSymbolic()) { + symrefs.add(r); + } else { + bru.addCommand(new ReceiveCommand(ObjectId.zeroId(), + r.getObjectId(), r.getName())); + } + } + + try (RevWalk rw = new RevWalk(this)) { + bru.execute(rw, NullProgressMonitor.INSTANCE); + } + + List<String> failed = new ArrayList<>(); + for (ReceiveCommand cmd : bru.getCommands()) { + if (cmd.getResult() != ReceiveCommand.Result.OK) { + failed.add(cmd.getRefName() + ": " + cmd.getResult()); //$NON-NLS-1$ + } + } + + if (!failed.isEmpty()) { + throw new IOException(String.format("%s: %s", //$NON-NLS-1$ + JGitText.get().failedToConvert, + StringUtils.join(failed, ", "))); //$NON-NLS-1$ + } + + for (Ref s : symrefs) { + RefUpdate up = refs.newUpdate(s.getName(), false); + up.setForceUpdate(true); + RefUpdate.Result res = up.link(s.getTarget().getName()); + if (res != RefUpdate.Result.NEW + && res != RefUpdate.Result.NO_CHANGE) { + throw new IOException( + String.format("ref %s: %s", s.getName(), res)); //$NON-NLS-1$ + } + } + + if (!backup) { + File reftableDir = new File(getDirectory(), Constants.REFTABLE); + FileUtils.delete(reftableDir, + FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS); + } + } + + @SuppressWarnings("nls") + void convertToReftable(boolean writeLogs, boolean backup) + throws IOException { + File newRefs = new File(getDirectory(), "refs.new"); + File reftableDir = new File(getDirectory(), Constants.REFTABLE); + + if (reftableDir.exists() && reftableDir.listFiles().length > 0) { + throw new IOException(JGitText.get().reftableDirExists); + } + + // Ignore return value, as it is tied to temporary newRefs file. + FileReftableDatabase.convertFrom(this, newRefs, writeLogs); + + File refsFile = new File(getDirectory(), "refs"); + + // non-atomic: remove old data. + File packedRefs = new File(getDirectory(), Constants.PACKED_REFS); + File logsDir = new File(getDirectory(), Constants.LOGS); + + + List<String> additional = getRefDatabase().getAdditionalRefs().stream() + .map(Ref::getName).collect(toList()); + additional.add(Constants.HEAD); + if (backup) { + FileUtils.rename(refsFile, new File(getDirectory(), "refs.old")); + if (packedRefs.exists()) { + FileUtils.rename(packedRefs, new File(getDirectory(), + Constants.PACKED_REFS + ".old")); + } + if (logsDir.exists()) { + FileUtils.rename(logsDir, + new File(getDirectory(), Constants.LOGS + ".old")); + } + for (String r : additional) { + FileUtils.rename(new File(getDirectory(), r), + new File(getDirectory(), r + ".old")); + } + } else { + packedRefs.delete(); // ignore return value. + FileUtils.delete(logsDir, FileUtils.RECURSIVE); + FileUtils.delete(refsFile, FileUtils.RECURSIVE); + for (String r : additional) { + new File(getDirectory(), r).delete(); + } + } + + // Put new data. + FileUtils.rename(newRefs, refsFile); + + refs.close(); + refs = new FileReftableDatabase(this, refsFile); + } + + /** + * Converts between ref storage formats. + * + * @param format + * the format to convert to, either "reftable" or "refdir" + * @param writeLogs + * whether to write reflogs + * @param backup + * whether to make a backup of the old data + * @throws IOException + * on I/O problems. + */ + @SuppressWarnings("nls") + public void convertRefStorage(String format, boolean writeLogs, + boolean backup) throws IOException { + if (format.equals("reftable")) { //$NON-NLS-1$ + if (refs instanceof RefDirectory) { + convertToReftable(writeLogs, backup); + } + } else if (format.equals("refdir")) {//$NON-NLS-1$ + if (refs instanceof FileReftableDatabase) { + convertToPackedRefs(backup); + } + } else { + throw new IOException(String.format( + "unknown supported ref storage format '%s'", format)); + } + } } 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 08bb6cb7fa..79ba4a1b02 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 @@ -771,13 +771,26 @@ public class GC { } /** - * Packs all non-symbolic, loose refs into packed-refs. + * Pack ref storage. For a RefDirectory database, this packs all + * non-symbolic, loose refs into packed-refs. For Reftable, all of the data + * is compacted into a single table. * * @throws java.io.IOException */ public void packRefs() throws IOException { - Collection<Ref> refs = repo.getRefDatabase() - .getRefsByPrefix(Constants.R_REFS); + RefDatabase refDb = repo.getRefDatabase(); + if (refDb instanceof FileReftableDatabase) { + // TODO: abstract this more cleanly. + pm.beginTask(JGitText.get().packRefs, 1); + try { + ((FileReftableDatabase) refDb).compactFully(); + } finally { + pm.endTask(); + } + return; + } + + Collection<Ref> refs = refDb.getRefsByPrefix(Constants.R_REFS); List<String> refsToBePacked = new ArrayList<>(refs.size()); pm.beginTask(JGitText.get().packRefs, refs.size()); try { @@ -895,7 +908,10 @@ public class GC { throw new IOException(e); } prunePacked(); - deleteEmptyRefsFolders(); + if (repo.getRefDatabase() instanceof RefDirectory) { + // TODO: abstract this more cleanly. + deleteEmptyRefsFolders(); + } deleteOrphans(); deleteTempPacksIdx(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java index 82458c1acf..13b9e79be8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java @@ -152,11 +152,10 @@ class GcLog { boolean commit() { if (nonEmpty) { return lock.commit(); - } else { - logFile.delete(); - lock.unlock(); - return true; } + logFile.delete(); + lock.unlock(); + return true; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java index e5a54e372c..09f2021686 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java @@ -109,10 +109,9 @@ class ObjectDirectoryInserter extends ObjectInserter { ObjectId id = idFor(type, data, off, len); if (!createDuplicate && db.has(id)) { return id; - } else { - File tmp = toTemp(type, data, off, len); - return insertOneObject(tmp, id, createDuplicate); } + File tmp = toTemp(type, data, off, len); + return insertOneObject(tmp, id, createDuplicate); } /** {@inheritDoc} */ @@ -141,12 +140,11 @@ class ObjectDirectoryInserter extends ObjectInserter { int actLen = IO.readFully(is, buf, 0); return insert(type, buf, 0, actLen, createDuplicate); - } else { - SHA1 md = digest(); - File tmp = toTemp(md, type, len, is); - ObjectId id = md.toObjectId(); - return insertOneObject(tmp, id, createDuplicate); } + SHA1 md = digest(); + File tmp = toTemp(md, type, len, is); + ObjectId id = md.toObjectId(); + return insertOneObject(tmp, id, createDuplicate); } private ObjectId insertOneObject( 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 88e05af414..9b9c3a7dec 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 @@ -844,19 +844,20 @@ public class PackFile implements Iterable<PackIndex.MutableEntry> { case Constants.OBJ_TREE: case Constants.OBJ_BLOB: case Constants.OBJ_TAG: { - if (delta != null || sz < curs.getStreamFileThreshold()) + if (delta != null || sz < curs.getStreamFileThreshold()) { data = decompress(pos + p, (int) sz, curs); + } if (delta != null) { type = typeCode; break SEARCH; } - if (data != null) + if (data != null) { return new ObjectLoader.SmallObject(typeCode, data); - else - return new LargePackedWholeObject(typeCode, sz, pos, p, - this, curs.db); + } + return new LargePackedWholeObject(typeCode, sz, pos, p, + this, curs.db); } case Constants.OBJ_OFS_DELTA: { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java index e45b53ea68..9023570607 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java @@ -366,12 +366,8 @@ class PackedBatchRefUpdate extends BatchRefUpdate { List<ReceiveCommand> commands) throws IOException { // Construct a new RefList by merging the old list with the updates. // This assumes that each ref occurs at most once as a ReceiveCommand. - Collections.sort(commands, new Comparator<ReceiveCommand>() { - @Override - public int compare(ReceiveCommand a, ReceiveCommand b) { - return a.getRefName().compareTo(b.getRefName()); - } - }); + Collections.sort(commands, + Comparator.comparing(ReceiveCommand::getRefName)); int delta = 0; for (ReceiveCommand c : commands) { 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 e5cea6c010..7733df15f9 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 @@ -594,10 +594,9 @@ public class RefDirectory extends RefDatabase { if (obj instanceof RevTag) { return new ObjectIdRef.PeeledTag(leaf.getStorage(), leaf .getName(), leaf.getObjectId(), rw.peel(obj).copy()); - } else { - return new ObjectIdRef.PeeledNonTag(leaf.getStorage(), leaf - .getName(), leaf.getObjectId()); } + return new ObjectIdRef.PeeledNonTag(leaf.getStorage(), + leaf.getName(), leaf.getObjectId()); } } @@ -894,10 +893,9 @@ public class RefDirectory extends RefDatabase { if (peeledObjectId != null) { return new ObjectIdRef.PeeledTag(PACKED, f.getName(), f.getObjectId(), peeledObjectId); - } else { - return new ObjectIdRef.PeeledNonTag(PACKED, f.getName(), - f.getObjectId()); } + return new ObjectIdRef.PeeledNonTag(PACKED, f.getName(), + f.getObjectId()); } void log(boolean force, RefUpdate update, String msg, boolean deref) @@ -1480,10 +1478,8 @@ public class RefDirectory extends RefDatabase { if (peeledObjectId != null) { return new LoosePeeledTag(snapShot, getName(), objectId, peeledObjectId); - } else { - return new LooseNonTag(snapShot, getName(), - objectId); } + return new LooseNonTag(snapShot, getName(), objectId); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java index 1a0d6953ab..dc4967fe4e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java @@ -90,9 +90,8 @@ class RefDirectoryUpdate extends RefUpdate { dst = database.findRef(name); setOldObjectId(dst != null ? dst.getObjectId() : null); return true; - } else { - return false; } + return false; } /** {@inheritDoc} */ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java index 08a14b28d2..3cdd90408e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java @@ -140,9 +140,9 @@ public class ReflogEntryImpl implements Serializable, ReflogEntry { /** {@inheritDoc} */ @Override public CheckoutEntry parseCheckout() { - if (getComment().startsWith(CheckoutEntryImpl.CHECKOUT_MOVING_FROM)) + if (getComment().startsWith(CheckoutEntryImpl.CHECKOUT_MOVING_FROM)) { return new CheckoutEntryImpl(this); - else - return null; + } + return null; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java index 131f716cf0..98d6ea00e7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogWriter.java @@ -61,6 +61,7 @@ import java.nio.channels.FileChannel; import java.text.MessageFormat; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.CoreConfig; import org.eclipse.jgit.lib.ObjectId; @@ -68,6 +69,7 @@ import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.ReflogEntry; +import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.util.FileUtils; /** @@ -239,7 +241,7 @@ public class ReflogWriter { private ReflogWriter log(String refName, byte[] rec) throws IOException { File log = refdb.logFor(refName); boolean write = forceWrite - || (isLogAllRefUpdates() && shouldAutoCreateLog(refName)) + || shouldAutoCreateLog(refName) || log.isFile(); if (!write) return this; @@ -260,15 +262,27 @@ public class ReflogWriter { return this; } - private boolean isLogAllRefUpdates() { - return refdb.getRepository().getConfig().get(CoreConfig.KEY) - .isLogAllRefUpdates(); - } - private boolean shouldAutoCreateLog(String refName) { - return refName.equals(HEAD) - || refName.startsWith(R_HEADS) - || refName.startsWith(R_REMOTES) - || refName.startsWith(R_NOTES); + Repository repo = refdb.getRepository(); + CoreConfig.LogRefUpdates value = repo.isBare() + ? CoreConfig.LogRefUpdates.FALSE + : CoreConfig.LogRefUpdates.TRUE; + value = repo.getConfig().getEnum(ConfigConstants.CONFIG_CORE_SECTION, + null, ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, value); + if (value != null) { + switch (value) { + case FALSE: + break; + case TRUE: + return refName.equals(HEAD) || refName.startsWith(R_HEADS) + || refName.startsWith(R_REMOTES) + || refName.startsWith(R_NOTES); + case ALWAYS: + return refName.equals(HEAD) || refName.startsWith(R_REFS); + default: + break; + } + } + return false; } }
\ No newline at end of file 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 79f1307578..fb06623d7e 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 @@ -139,49 +139,48 @@ public class UnpackedObject { } return new LargeObject(type, size, path, id, wc.db); - } else { - readSome(in, hdr, 2, 18); - int c = hdr[0] & 0xff; - int type = (c >> 4) & 7; - long size = c & 15; - int shift = 4; - int p = 1; - while ((c & 0x80) != 0) { - c = hdr[p++] & 0xff; - size += ((long) (c & 0x7f)) << shift; - shift += 7; - } + } + readSome(in, hdr, 2, 18); + int c = hdr[0] & 0xff; + int type = (c >> 4) & 7; + long size = c & 15; + int shift = 4; + int p = 1; + while ((c & 0x80) != 0) { + c = hdr[p++] & 0xff; + size += ((long) (c & 0x7f)) << shift; + shift += 7; + } - switch (type) { - case Constants.OBJ_COMMIT: - case Constants.OBJ_TREE: - case Constants.OBJ_BLOB: - case Constants.OBJ_TAG: - // Acceptable types for a loose object. - break; - default: - throw new CorruptObjectException(id, - JGitText.get().corruptObjectInvalidType); - } + switch (type) { + case Constants.OBJ_COMMIT: + case Constants.OBJ_TREE: + case Constants.OBJ_BLOB: + case Constants.OBJ_TAG: + // Acceptable types for a loose object. + break; + default: + throw new CorruptObjectException(id, + JGitText.get().corruptObjectInvalidType); + } - if (path == null && Integer.MAX_VALUE < size) { - LargeObjectException.ExceedsByteArrayLimit e; - e = new LargeObjectException.ExceedsByteArrayLimit(); - e.setObjectId(id); - throw e; - } - if (size < wc.getStreamFileThreshold() || path == null) { - in.reset(); - IO.skipFully(in, p); - Inflater inf = wc.inflater(); - InputStream zIn = inflate(in, inf); - byte[] data = new byte[(int) size]; - IO.readFully(zIn, data, 0, data.length); - checkValidEndOfStream(in, inf, id, hdr); - return new ObjectLoader.SmallObject(type, data); - } - return new LargeObject(type, size, path, id, wc.db); + if (path == null && Integer.MAX_VALUE < size) { + LargeObjectException.ExceedsByteArrayLimit e; + e = new LargeObjectException.ExceedsByteArrayLimit(); + e.setObjectId(id); + throw e; } + if (size < wc.getStreamFileThreshold() || path == null) { + in.reset(); + IO.skipFully(in, p); + Inflater inf = wc.inflater(); + InputStream zIn = inflate(in, inf); + byte[] data = new byte[(int) size]; + IO.readFully(zIn, data, 0, data.length); + checkValidEndOfStream(in, inf, id, hdr); + return new ObjectLoader.SmallObject(type, data); + } + return new LargeObject(type, size, path, id, wc.db); } catch (ZipException badStream) { throw new CorruptObjectException(id, JGitText.get().corruptObjectBadStream); @@ -213,19 +212,18 @@ public class UnpackedObject { JGitText.get().corruptObjectNegativeSize); return size; - } else { - readSome(in, hdr, 2, 18); - int c = hdr[0] & 0xff; - long size = c & 15; - int shift = 4; - int p = 1; - while ((c & 0x80) != 0) { - c = hdr[p++] & 0xff; - size += ((long) (c & 0x7f)) << shift; - shift += 7; - } - return size; } + readSome(in, hdr, 2, 18); + int c = hdr[0] & 0xff; + long size = c & 15; + int shift = 4; + int p = 1; + while ((c & 0x80) != 0) { + c = hdr[p++] & 0xff; + size += ((long) (c & 0x7f)) << shift; + shift += 7; + } + return size; } catch (ZipException badStream) { throw new CorruptObjectException(id, JGitText.get().corruptObjectBadStream); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObjectCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObjectCache.java index ea0d269053..616447a651 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObjectCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/UnpackedObjectCache.java @@ -126,17 +126,19 @@ class UnpackedObjectCache { for (int n = 0; n < MAX_CHAIN;) { ObjectId obj = ids.get(i); if (obj == null) { - if (ids.compareAndSet(i, null, toAdd.copy())) + if (ids.compareAndSet(i, null, toAdd.copy())) { return true; - else - continue; + } + continue; } - if (AnyObjectId.isEqual(obj, toAdd)) + if (AnyObjectId.isEqual(obj, toAdd)) { return true; + } - if (++i == ids.length()) + if (++i == ids.length()) { i = 0; + } n++; } return false; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/CachedPackUriProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/CachedPackUriProvider.java index 5cbc2baeb2..9496d78c2f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/CachedPackUriProvider.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/CachedPackUriProvider.java @@ -76,14 +76,22 @@ public interface CachedPackUriProvider { private final String hash; private final String uri; + private final long size; + /** * Constructs an object containing information about a packfile. - * @param hash the hash of the packfile as a hexadecimal string - * @param uri the URI corresponding to the packfile + * + * @param hash + * the hash of the packfile as a hexadecimal string + * @param uri + * the URI corresponding to the packfile + * @param size + * the size of the packfile in bytes */ - public PackInfo(String hash, String uri) { + public PackInfo(String hash, String uri, long size) { this.hash = hash; this.uri = uri; + this.size = size; } /** @@ -99,5 +107,12 @@ public interface CachedPackUriProvider { public String getUri() { return uri; } + + /** + * @return the size of the packfile in bytes (-1 if unknown) + */ + public long getSize() { + return size; + } } } 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 43067d364d..e4536643a7 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 @@ -1230,6 +1230,8 @@ public class PackWriter implements AutoCloseable { if (packInfo != null) { o.writeString(packInfo.getHash() + ' ' + packInfo.getUri() + '\n'); + stats.offloadedPackfiles += 1; + stats.offloadedPackfileSize += packInfo.getSize(); } else { unwrittenCachedPacks.add(pack); } @@ -1749,23 +1751,23 @@ public class PackWriter implements AutoCloseable { NullProgressMonitor.INSTANCE, Collections.singleton(otp)); continue; - } else { - // Object writing already started, we cannot recover. - // - CorruptObjectException coe; - coe = new CorruptObjectException(otp, ""); //$NON-NLS-1$ - coe.initCause(gone); - throw coe; } + // Object writing already started, we cannot recover. + // + CorruptObjectException coe; + coe = new CorruptObjectException(otp, ""); //$NON-NLS-1$ + coe.initCause(gone); + throw coe; } } // If we reached here, reuse wasn't possible. // - if (otp.isDeltaRepresentation()) + if (otp.isDeltaRepresentation()) { writeDeltaObjectDeflate(out, otp); - else + } else { writeWholeObjectDeflate(out, otp); + } out.endObject(); otp.setCRC((int) crc32.getValue()); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java index c740bf2c37..0144453cd7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/MergedReftable.java @@ -67,13 +67,11 @@ import org.eclipse.jgit.lib.ReflogEntry; * A {@code MergedReftable} is not thread-safe. */ public class MergedReftable extends Reftable { - private final Reftable[] tables; + private final ReftableReader[] tables; /** * Initialize a merged table reader. * <p> - * The tables in {@code tableStack} will be closed when this - * {@code MergedReftable} is closed. * * @param tableStack * stack of tables to read from. The base of the stack is at @@ -81,16 +79,35 @@ public class MergedReftable extends Reftable { * {@code tableStack.size() - 1}. The top of the stack (higher * index) shadows the base of the stack (lower index). */ - public MergedReftable(List<Reftable> tableStack) { - tables = tableStack.toArray(new Reftable[0]); + public MergedReftable(List<ReftableReader> tableStack) { + tables = tableStack.toArray(new ReftableReader[0]); // Tables must expose deletes to this instance to correctly // shadow references from lower tables. - for (Reftable t : tables) { + for (ReftableReader t : tables) { t.setIncludeDeletes(true); } } + /** + * {@inheritDoc} + */ + @Override + public long maxUpdateIndex() throws IOException { + return tables.length > 0 ? tables[tables.length - 1].maxUpdateIndex() + : 0; + } + + /** {@inheritDoc} */ + @Override + public boolean hasObjectMap() throws IOException { + boolean has = true; + for (int i = 0; has && i < tables.length; i++) { + has = has && tables[i].hasObjectMap(); + } + return has; + } + /** {@inheritDoc} */ @Override public RefCursor allRefs() throws IOException { @@ -124,7 +141,7 @@ public class MergedReftable extends Reftable { /** {@inheritDoc} */ @Override public RefCursor byObjectId(AnyObjectId name) throws IOException { - MergedRefCursor m = new MergedRefCursor(); + MergedRefCursor m = new FilteringMergedRefCursor(name); for (int i = 0; i < tables.length; i++) { m.add(new RefQueueEntry(tables[i].byObjectId(name), i)); } @@ -152,14 +169,6 @@ public class MergedReftable extends Reftable { return m; } - /** {@inheritDoc} */ - @Override - public void close() throws IOException { - for (Reftable t : tables) { - t.close(); - } - } - int queueSize() { return Math.max(1, tables.length); } @@ -251,6 +260,42 @@ public class MergedReftable extends Reftable { } } + private class FilteringMergedRefCursor extends MergedRefCursor { + final AnyObjectId filterId; + Ref filteredRef; + + FilteringMergedRefCursor(AnyObjectId id) { + filterId = id; + filteredRef = null; + } + + @Override + public Ref getRef() { + return filteredRef; + } + + @Override + public boolean next() throws IOException { + for (;;) { + boolean ok = super.next(); + if (!ok) { + return false; + } + + String name = super.getRef().getName(); + + try (RefCursor c = seekRef(name)) { + if (c.next()) { + if (filterId.equals(c.getRef().getObjectId())) { + filteredRef = c.getRef(); + return true; + } + } + } + } + } + } + private static class RefQueueEntry { static int compare(RefQueueEntry a, RefQueueEntry b) { int cmp = a.name().compareTo(b.name()); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java index cb02628e8d..8a8a14375a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/Reftable.java @@ -58,7 +58,7 @@ import org.eclipse.jgit.lib.SymbolicRef; /** * Abstract table of references. */ -public abstract class Reftable implements AutoCloseable { +public abstract class Reftable { /** * References to convert into a reftable * @@ -72,9 +72,9 @@ public abstract class Reftable implements AutoCloseable { cfg.setIndexObjects(false); cfg.setAlignBlocks(false); ByteArrayOutputStream buf = new ByteArrayOutputStream(); - new ReftableWriter() + new ReftableWriter(buf) .setConfig(cfg) - .begin(buf) + .begin() .sortAndWriteRefs(refs) .finish(); return new ReftableReader(BlockSource.from(buf.toByteArray())); @@ -98,6 +98,19 @@ public abstract class Reftable implements AutoCloseable { includeDeletes = deletes; } + + /** + * Get the maximum update index for log entries that appear in this + * reftable. + * + * @return the maximum update index for log entries that appear in this + * reftable. This should be 1 higher than the prior reftable's + * {@code maxUpdateIndex} if this table is used in a stack. + * @throws java.io.IOException + * file cannot be read. + */ + public abstract long maxUpdateIndex() throws IOException; + /** * Seek to the first reference, to iterate in order. * @@ -149,6 +162,12 @@ public abstract class Reftable implements AutoCloseable { public abstract RefCursor byObjectId(AnyObjectId id) throws IOException; /** + * @return whether this reftable can do a fast SHA1 => ref lookup. + * @throws IOException on I/O problems. + */ + public abstract boolean hasObjectMap() throws IOException; + + /** * Seek reader to read log records. * * @return cursor to iterate; empty cursor if no logs are present. @@ -282,8 +301,4 @@ public abstract class Reftable implements AutoCloseable { } return new SymbolicRef(ref.getName(), dst, ref.getUpdateIndex()); } - - /** {@inheritDoc} */ - @Override - public abstract void close() throws IOException; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReftableBatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableBatchRefUpdate.java index 07fd00f149..592120d89b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ReftableBatchRefUpdate.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableBatchRefUpdate.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017, Google Inc. + * Copyright (C) 2019, Google Inc. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -41,40 +41,11 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.eclipse.jgit.internal.storage.dfs; - -import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; -import static org.eclipse.jgit.lib.Ref.Storage.NEW; -import static org.eclipse.jgit.lib.Ref.Storage.PACKED; -import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE; -import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED; -import static org.eclipse.jgit.transport.ReceiveCommand.Result.OK; -import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_MISSING_OBJECT; -import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_NONFASTFORWARD; -import static org.eclipse.jgit.transport.ReceiveCommand.Type.UPDATE_NONFASTFORWARD; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.locks.ReentrantLock; +package org.eclipse.jgit.internal.storage.reftable; import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.errors.MissingObjectException; -import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource; -import org.eclipse.jgit.internal.storage.io.BlockSource; -import org.eclipse.jgit.internal.storage.pack.PackExt; -import org.eclipse.jgit.internal.storage.reftable.Reftable; -import org.eclipse.jgit.internal.storage.reftable.ReftableCompactor; -import org.eclipse.jgit.internal.storage.reftable.ReftableConfig; -import org.eclipse.jgit.internal.storage.reftable.ReftableReader; -import org.eclipse.jgit.internal.storage.reftable.ReftableWriter; +import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.BatchRefUpdate; import org.eclipse.jgit.lib.ObjectId; @@ -82,43 +53,65 @@ import org.eclipse.jgit.lib.ObjectIdRef; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.ReflogEntry; +import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.SymbolicRef; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevTag; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.transport.ReceiveCommand; -/** - * {@link org.eclipse.jgit.lib.BatchRefUpdate} for - * {@link org.eclipse.jgit.internal.storage.dfs.DfsReftableDatabase}. - */ -public class ReftableBatchRefUpdate extends BatchRefUpdate { - private static final int AVG_BYTES = 36; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.locks.Lock; +import java.util.stream.Collectors; + +import static org.eclipse.jgit.lib.Ref.Storage.NEW; +import static org.eclipse.jgit.lib.Ref.Storage.PACKED; - private final DfsReftableDatabase refdb; +import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE; +import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED; +import static org.eclipse.jgit.transport.ReceiveCommand.Result.OK; +import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_MISSING_OBJECT; +import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_NONFASTFORWARD; +import static org.eclipse.jgit.transport.ReceiveCommand.Type.DELETE; +import static org.eclipse.jgit.transport.ReceiveCommand.Type.UPDATE_NONFASTFORWARD; - private final DfsObjDatabase odb; +/** + * {@link org.eclipse.jgit.lib.BatchRefUpdate} for Reftable based RefDatabase. + */ +public abstract class ReftableBatchRefUpdate extends BatchRefUpdate { + private final Lock lock; - private final ReentrantLock lock; + private final ReftableDatabase refDb; - private final ReftableConfig reftableConfig; + private final Repository repository; /** - * Initialize batch update. + * Initialize. * * @param refdb - * database the update will modify. - * @param odb - * object database to store the reftable. + * The RefDatabase + * @param reftableDb + * The ReftableDatabase + * @param lock + * A lock protecting the refdatabase's state + * @param repository + * The repository on which this update will run */ - protected ReftableBatchRefUpdate(DfsReftableDatabase refdb, - DfsObjDatabase odb) { + protected ReftableBatchRefUpdate(RefDatabase refdb, ReftableDatabase reftableDb, Lock lock, + Repository repository) { super(refdb); - this.refdb = refdb; - this.odb = odb; - lock = refdb.getLock(); - reftableConfig = refdb.getReftableConfig(); + this.refDb = reftableDb; + this.lock = lock; + this.repository = repository; } /** {@inheritDoc} */ @@ -135,25 +128,36 @@ public class ReftableBatchRefUpdate extends BatchRefUpdate { if (!checkObjectExistence(rw, pending)) { return; } + // if we are here, checkObjectExistence might have flagged some problems + // but the transaction is not atomic, so we should proceed with the other + // pending commands. + pending = getPending(); if (!checkNonFastForwards(rw, pending)) { return; } + pending = getPending(); lock.lock(); try { - Reftable table = refdb.reader(); - if (!checkExpected(table, pending)) { + if (!checkExpected(pending)) { return; } + pending = getPending(); if (!checkConflicting(pending)) { return; } + pending = getPending(); if (!blockUntilTimestamps(MAX_WAIT)) { return; } - applyUpdates(rw, pending); + + List<Ref> newRefs = toNewRefs(rw, pending); + applyUpdates(newRefs, pending); for (ReceiveCommand cmd : pending) { - cmd.setResult(OK); + if (cmd.getResult() == NOT_ATTEMPTED) { + // XXX this is a bug in DFS ? + cmd.setResult(OK); + } } } finally { lock.unlock(); @@ -164,6 +168,19 @@ public class ReftableBatchRefUpdate extends BatchRefUpdate { } } + /** + * Implements the storage-specific part of the update. + * + * @param newRefs + * the new refs to create + * @param pending + * the pending receive commands to be executed + * @throws IOException + * if any of the writes fail. + */ + protected abstract void applyUpdates(List<Ref> newRefs, + List<ReceiveCommand> pending) throws IOException; + private List<ReceiveCommand> getPending() { return ReceiveCommand.filter(getCommands(), NOT_ATTEMPTED); } @@ -181,8 +198,10 @@ public class ReftableBatchRefUpdate extends BatchRefUpdate { // used for a missing object. Eagerly handle this case so we // can set the right result. cmd.setResult(REJECTED_MISSING_OBJECT); - ReceiveCommand.abort(pending); - return false; + if (isAtomic()) { + ReceiveCommand.abort(pending); + return false; + } } } return true; @@ -197,8 +216,10 @@ public class ReftableBatchRefUpdate extends BatchRefUpdate { cmd.updateType(rw); if (cmd.getType() == UPDATE_NONFASTFORWARD) { cmd.setResult(REJECTED_NONFASTFORWARD); - ReceiveCommand.abort(pending); - return false; + if (isAtomic()) { + ReceiveCommand.abort(pending); + return false; + } } } return true; @@ -206,40 +227,55 @@ public class ReftableBatchRefUpdate extends BatchRefUpdate { private boolean checkConflicting(List<ReceiveCommand> pending) throws IOException { - Set<String> names = new HashSet<>(); - for (ReceiveCommand cmd : pending) { - names.add(cmd.getRefName()); - } + TreeSet<String> added = new TreeSet<>(); + Set<String> deleted = + pending.stream() + .filter(cmd -> cmd.getType() == DELETE) + .map(c -> c.getRefName()) + .collect(Collectors.toSet()); boolean ok = true; for (ReceiveCommand cmd : pending) { + if (cmd.getType() == DELETE) { + continue; + } + String name = cmd.getRefName(); - if (refdb.isNameConflicting(name)) { - cmd.setResult(LOCK_FAILURE); - ok = false; - } else { - int s = name.lastIndexOf('/'); - while (0 < s) { - if (names.contains(name.substring(0, s))) { - cmd.setResult(LOCK_FAILURE); - ok = false; - break; - } - s = name.lastIndexOf('/', s - 1); + if (refDb.isNameConflicting(name, added, deleted)) { + if (isAtomic()) { + cmd.setResult( + ReceiveCommand.Result.REJECTED_OTHER_REASON, JGitText.get().transactionAborted); + } else { + cmd.setResult(LOCK_FAILURE); } + + ok = false; } + added.add(name); } - if (!ok && isAtomic()) { - ReceiveCommand.abort(pending); - return false; + + if (isAtomic()) { + if (!ok) { + pending.stream() + .filter(cmd -> cmd.getResult() == NOT_ATTEMPTED) + .forEach(cmd -> cmd.setResult(LOCK_FAILURE)); + } + return ok; } - return ok; + + for (ReceiveCommand cmd : pending) { + if (cmd.getResult() == NOT_ATTEMPTED) { + return true; + } + } + + return false; } - private boolean checkExpected(Reftable table, List<ReceiveCommand> pending) + private boolean checkExpected(List<ReceiveCommand> pending) throws IOException { for (ReceiveCommand cmd : pending) { - if (!matchOld(cmd, table.exactRef(cmd.getRefName()))) { + if (!matchOld(cmd, refDb.exactRef(cmd.getRefName()))) { cmd.setResult(LOCK_FAILURE); if (isAtomic()) { ReceiveCommand.abort(pending); @@ -253,7 +289,7 @@ public class ReftableBatchRefUpdate extends BatchRefUpdate { private static boolean matchOld(ReceiveCommand cmd, @Nullable Ref ref) { if (ref == null) { return AnyObjectId.isEqual(ObjectId.zeroId(), cmd.getOldId()) - && cmd.getOldSymref() == null; + && cmd.getOldSymref() == null; } else if (ref.isSymbolic()) { return ref.getTarget().getName().equals(cmd.getOldSymref()); } @@ -264,47 +300,26 @@ public class ReftableBatchRefUpdate extends BatchRefUpdate { return cmd.getOldId().equals(id); } - private void applyUpdates(RevWalk rw, List<ReceiveCommand> pending) - throws IOException { - List<Ref> newRefs = toNewRefs(rw, pending); - long updateIndex = nextUpdateIndex(); - Set<DfsPackDescription> prune = Collections.emptySet(); - DfsPackDescription pack = odb.newPack(PackSource.INSERT); - try (DfsOutputStream out = odb.writeFile(pack, REFTABLE)) { - ReftableConfig cfg = DfsPackCompactor - .configureReftable(reftableConfig, out); - - ReftableWriter.Stats stats; - if (refdb.compactDuringCommit() - && newRefs.size() * AVG_BYTES <= cfg.getRefBlockSize() - && canCompactTopOfStack(cfg)) { - ByteArrayOutputStream tmp = new ByteArrayOutputStream(); - write(tmp, cfg, updateIndex, newRefs, pending); - stats = compactTopOfStack(out, cfg, tmp.toByteArray()); - prune = toPruneTopOfStack(); - } else { - stats = write(out, cfg, updateIndex, newRefs, pending); - } - pack.addFileExt(REFTABLE); - pack.setReftableStats(stats); - } - - odb.commitPack(Collections.singleton(pack), prune); - odb.addReftable(pack, prune); - refdb.clearCache(); - } - - private ReftableWriter.Stats write(OutputStream os, ReftableConfig cfg, - long updateIndex, List<Ref> newRefs, List<ReceiveCommand> pending) - throws IOException { - ReftableWriter writer = new ReftableWriter(cfg) - .setMinUpdateIndex(updateIndex).setMaxUpdateIndex(updateIndex) - .begin(os).sortAndWriteRefs(newRefs); + /** + * Writes the refs to the writer, and calls finish. + * + * @param writer + * the writer on which we should write. + * @param newRefs + * the ref data to write.. + * @param pending + * the log data to write. + * @throws IOException + * in case of problems. + */ + protected void write(ReftableWriter writer, List<Ref> newRefs, + List<ReceiveCommand> pending) throws IOException { + long updateIndex = refDb.nextUpdateIndex(); + writer.setMinUpdateIndex(updateIndex).setMaxUpdateIndex(updateIndex) + .begin().sortAndWriteRefs(newRefs); if (!isRefLogDisabled()) { writeLog(writer, updateIndex, pending); } - writer.finish(); - return writer.getStats(); } private void writeLog(ReftableWriter writer, long updateIndex, @@ -319,7 +334,7 @@ public class ReftableBatchRefUpdate extends BatchRefUpdate { PersonIdent ident = getRefLogIdent(); if (ident == null) { - ident = new PersonIdent(refdb.getRepository()); + ident = new PersonIdent(repository); } for (String name : byName) { ReceiveCommand cmd = cmds.get(name); @@ -361,20 +376,25 @@ public class ReftableBatchRefUpdate extends BatchRefUpdate { } } + // Extracts and peels the refs out of the ReceiveCommands private static List<Ref> toNewRefs(RevWalk rw, List<ReceiveCommand> pending) - throws IOException { + throws IOException { List<Ref> refs = new ArrayList<>(pending.size()); for (ReceiveCommand cmd : pending) { + if (cmd.getResult() != NOT_ATTEMPTED) { + continue; + } + String name = cmd.getRefName(); ObjectId newId = cmd.getNewId(); String newSymref = cmd.getNewSymref(); if (AnyObjectId.isEqual(ObjectId.zeroId(), newId) - && newSymref == null) { + && newSymref == null) { refs.add(new ObjectIdRef.Unpeeled(NEW, name, null)); continue; } else if (newSymref != null) { refs.add(new SymbolicRef(name, - new ObjectIdRef.Unpeeled(NEW, newSymref, null))); + new ObjectIdRef.Unpeeled(NEW, newSymref, null))); continue; } @@ -385,76 +405,11 @@ public class ReftableBatchRefUpdate extends BatchRefUpdate { } if (peel != null) { refs.add(new ObjectIdRef.PeeledTag(PACKED, name, newId, - peel.copy())); + peel.copy())); } else { refs.add(new ObjectIdRef.PeeledNonTag(PACKED, name, newId)); } } return refs; } - - private long nextUpdateIndex() throws IOException { - long updateIndex = 0; - for (Reftable r : refdb.stack().readers()) { - if (r instanceof ReftableReader) { - updateIndex = Math.max(updateIndex, - ((ReftableReader) r).maxUpdateIndex()); - } - } - return updateIndex + 1; - } - - private boolean canCompactTopOfStack(ReftableConfig cfg) - throws IOException { - ReftableStack stack = refdb.stack(); - List<Reftable> readers = stack.readers(); - if (readers.isEmpty()) { - return false; - } - - int lastIdx = readers.size() - 1; - DfsReftable last = stack.files().get(lastIdx); - DfsPackDescription desc = last.getPackDescription(); - if (desc.getPackSource() != PackSource.INSERT - || !packOnlyContainsReftable(desc)) { - return false; - } - - Reftable table = readers.get(lastIdx); - int bs = cfg.getRefBlockSize(); - return table instanceof ReftableReader - && ((ReftableReader) table).size() <= 3 * bs; - } - - private ReftableWriter.Stats compactTopOfStack(OutputStream out, - ReftableConfig cfg, byte[] newTable) throws IOException { - List<Reftable> stack = refdb.stack().readers(); - Reftable last = stack.get(stack.size() - 1); - - List<Reftable> tables = new ArrayList<>(2); - tables.add(last); - tables.add(new ReftableReader(BlockSource.from(newTable))); - - ReftableCompactor compactor = new ReftableCompactor(); - compactor.setConfig(cfg); - compactor.setIncludeDeletes(true); - compactor.addAll(tables); - compactor.compact(out); - return compactor.getStats(); - } - - private Set<DfsPackDescription> toPruneTopOfStack() throws IOException { - List<DfsReftable> stack = refdb.stack().files(); - DfsReftable last = stack.get(stack.size() - 1); - return Collections.singleton(last.getPackDescription()); - } - - private boolean packOnlyContainsReftable(DfsPackDescription desc) { - for (PackExt ext : PackExt.values()) { - if (ext != REFTABLE && desc.hasFileExt(ext)) { - return false; - } - } - return true; - } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java index c4e8f69fa4..c73c245be5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableCompactor.java @@ -68,8 +68,8 @@ import org.eclipse.jgit.lib.ReflogEntry; * {@code setOldestReflogTimeMillis(Long.MAX_VALUE)}. */ public class ReftableCompactor { - private final ReftableWriter writer = new ReftableWriter(); - private final ArrayDeque<Reftable> tables = new ArrayDeque<>(); + private final ReftableWriter writer; + private final ArrayDeque<ReftableReader> tables = new ArrayDeque<>(); private long compactBytesLimit; private long bytesToCompact; @@ -80,6 +80,17 @@ public class ReftableCompactor { private Stats stats; /** + * Creates a new compactor. + * + * @param out + * stream to write the compacted tables to. Caller is responsible + * for closing {@code out}. + */ + public ReftableCompactor(OutputStream out) { + writer = new ReftableWriter(out); + } + + /** * Set configuration for the reftable. * * @param cfg @@ -177,12 +188,10 @@ public class ReftableCompactor { * @throws java.io.IOException * update indexes of a reader cannot be accessed. */ - public void addAll(List<? extends Reftable> readers) throws IOException { - tables.addAll(readers); - for (Reftable r : readers) { - if (r instanceof ReftableReader) { - adjustUpdateIndexes((ReftableReader) r); - } + public void addAll(List<ReftableReader> readers) throws IOException { + for (ReftableReader r : readers) { + tables.add(r); + adjustUpdateIndexes(r); } } @@ -225,19 +234,16 @@ public class ReftableCompactor { /** * Write a compaction to {@code out}. * - * @param out - * stream to write the compacted tables to. Caller is responsible - * for closing {@code out}. * @throws java.io.IOException * if tables cannot be read, or cannot be written. */ - public void compact(OutputStream out) throws IOException { + public void compact() throws IOException { MergedReftable mr = new MergedReftable(new ArrayList<>(tables)); mr.setIncludeDeletes(includeDeletes); writer.setMinUpdateIndex(Math.max(minUpdateIndex, 0)); writer.setMaxUpdateIndex(maxUpdateIndex); - writer.begin(out); + writer.begin(); mergeRefs(mr); mergeLogs(mr); writer.finish(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableDatabase.java new file mode 100644 index 0000000000..c08f1814dc --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableDatabase.java @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2017, Google LLC + * 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.reftable; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.locks.ReentrantLock; + +import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefDatabase; +import org.eclipse.jgit.lib.ReflogReader; +import org.eclipse.jgit.transport.ReceiveCommand; + +/** + * Operations on {@link MergedReftable} that is common to various reftable-using + * subclasses of {@link RefDatabase}. See + * {@link org.eclipse.jgit.internal.storage.dfs.DfsReftableDatabase} for an + * example. + */ +public abstract class ReftableDatabase { + // Protects mergedTables. + private final ReentrantLock lock = new ReentrantLock(true); + + private Reftable mergedTables; + + /** + * ReftableDatabase lazily initializes its merged reftable on the first read after + * construction or clearCache() call. This function should always instantiate a new + * MergedReftable based on the list of reftables specified by the underlying storage. + * + * @return the ReftableStack for this instance + * @throws IOException + * on I/O problems. + */ + abstract protected MergedReftable openMergedReftable() throws IOException; + + /** + * @return the next available logical timestamp for an additional reftable + * in the stack. + * @throws java.io.IOException + * on I/O problems. + */ + public long nextUpdateIndex() throws IOException { + lock.lock(); + try { + return reader().maxUpdateIndex() + 1; + } finally { + lock.unlock(); + } + } + + /** + * @return a ReflogReader for the given ref + * @param refname + * the name of the ref. + * @throws IOException + * on I/O problems + */ + public ReflogReader getReflogReader(String refname) throws IOException { + lock.lock(); + try { + return new ReftableReflogReader(lock, reader(), refname); + } finally { + lock.unlock(); + } + } + + /** + * @return a ReceiveCommand for the change from oldRef to newRef + * @param oldRef + * a ref + * @param newRef + * a ref + */ + public static ReceiveCommand toCommand(Ref oldRef, Ref newRef) { + ObjectId oldId = toId(oldRef); + ObjectId newId = toId(newRef); + String name = oldRef != null ? oldRef.getName() : newRef.getName(); + + if (oldRef != null && oldRef.isSymbolic()) { + if (newRef != null) { + if (newRef.isSymbolic()) { + return ReceiveCommand.link(oldRef.getTarget().getName(), + newRef.getTarget().getName(), name); + } + // This should pass in oldId for compat with + // RefDirectoryUpdate + return ReceiveCommand.unlink(oldRef.getTarget().getName(), + newId, name); + } + return ReceiveCommand.unlink(oldRef.getTarget().getName(), + ObjectId.zeroId(), name); + } + + if (newRef != null && newRef.isSymbolic()) { + if (oldRef != null) { + if (oldRef.isSymbolic()) { + return ReceiveCommand.link(oldRef.getTarget().getName(), + newRef.getTarget().getName(), name); + } + return ReceiveCommand.link(oldId, + newRef.getTarget().getName(), name); + } + return ReceiveCommand.link(ObjectId.zeroId(), + newRef.getTarget().getName(), name); + } + + return new ReceiveCommand(oldId, newId, name); + } + + private static ObjectId toId(Ref ref) { + if (ref != null) { + ObjectId id = ref.getObjectId(); + if (id != null) { + return id; + } + } + return ObjectId.zeroId(); + } + + /** + * @return the lock protecting underlying ReftableReaders against concurrent + * reads. + */ + public ReentrantLock getLock() { + return lock; + } + + /** + * @return the merged reftable that is implemented by the stack of + * reftables. Return value must be accessed under lock. + * @throws IOException + * on I/O problems + */ + private Reftable reader() throws IOException { + if (!lock.isLocked()) { + throw new IllegalStateException( + "must hold lock to access merged table"); //$NON-NLS-1$ + } + if (mergedTables == null) { + mergedTables = openMergedReftable(); + } + return mergedTables; + } + + /** + * @return whether the given refName would be illegal in a repository that + * uses loose refs. + * @param refName + * the name to check + * @param added + * a sorted set of refs we pretend have been added to the + * database. + * @param deleted + * a set of refs we pretend have been removed from the database. + * @throws IOException + * on I/O problems + */ + public boolean isNameConflicting(String refName, TreeSet<String> added, + Set<String> deleted) throws IOException { + lock.lock(); + try { + Reftable table = reader(); + + // Cannot be nested within an existing reference. + int lastSlash = refName.lastIndexOf('/'); + while (0 < lastSlash) { + String prefix = refName.substring(0, lastSlash); + if (!deleted.contains(prefix) + && (table.hasRef(prefix) || added.contains(prefix))) { + return true; + } + lastSlash = refName.lastIndexOf('/', lastSlash - 1); + } + + // Cannot be the container of an existing reference. + String prefix = refName + '/'; + RefCursor c = table.seekRefsWithPrefix(prefix); + while (c.next()) { + if (!deleted.contains(c.getRef().getName())) { + return true; + } + } + + String it = added.ceiling(refName + '/'); + if (it != null && it.startsWith(prefix)) { + return true; + } + return false; + } finally { + lock.unlock(); + } + } + + /** + * Read a single reference. + * <p> + * This method expects an unshortened reference name and does not search + * using the standard search path. + * + * @param name + * the unabbreviated name of the reference. + * @return the reference (if it exists); else {@code null}. + * @throws java.io.IOException + * the reference space cannot be accessed. + */ + @Nullable + public Ref exactRef(String name) throws IOException { + lock.lock(); + try { + Reftable table = reader(); + Ref ref = table.exactRef(name); + if (ref != null && ref.isSymbolic()) { + return table.resolve(ref); + } + return ref; + } finally { + lock.unlock(); + } + } + + /** + * Returns refs whose names start with a given prefix. + * + * @param prefix + * string that names of refs should start with; may be empty (to + * return all refs). + * @return immutable list of refs whose names start with {@code prefix}. + * @throws java.io.IOException + * the reference space cannot be accessed. + */ + public List<Ref> getRefsByPrefix(String prefix) throws IOException { + List<Ref> all = new ArrayList<>(); + lock.lock(); + try { + Reftable table = reader(); + try (RefCursor rc = RefDatabase.ALL.equals(prefix) ? table.allRefs() + : table.seekRefsWithPrefix(prefix)) { + while (rc.next()) { + Ref ref = table.resolve(rc.getRef()); + if (ref != null && ref.getObjectId() != null) { + all.add(ref); + } + } + } + } finally { + lock.unlock(); + } + + return Collections.unmodifiableList(all); + } + + /** + * @return whether there is a fast SHA1 to ref map. + * @throws IOException in case of I/O problems. + */ + public boolean hasFastTipsWithSha1() throws IOException { + lock.lock(); + try { + return reader().hasObjectMap(); + } finally { + lock.unlock(); + } + } + + /** + * Returns all refs that resolve directly to the given {@link ObjectId}. + * Includes peeled {@linkObjectId}s. + * + * @param id + * {@link ObjectId} to resolve + * @return a {@link Set} of {@link Ref}s whose tips point to the provided + * id. + * @throws java.io.IOException + * on I/O errors. + */ + public Set<Ref> getTipsWithSha1(ObjectId id) throws IOException { + lock.lock(); + try { + RefCursor cursor = reader().byObjectId(id); + Set<Ref> refs = new HashSet<>(); + while (cursor.next()) { + refs.add(cursor.getRef()); + } + return refs; + } finally { + lock.unlock(); + } + } + + /** + * Drops all data that might be cached in memory. + */ + public void clearCache() { + lock.lock(); + try { + mergedTables = null; + } finally { + lock.unlock(); + } + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java index 4f0ff2d1d1..14b821a1ed 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReader.java @@ -78,7 +78,7 @@ import org.eclipse.jgit.util.NB; * {@code ReftableReader} is not thread-safe. Concurrent readers need their own * instance to read from the same file. */ -public class ReftableReader extends Reftable { +public class ReftableReader extends Reftable implements AutoCloseable { private final BlockSource src; private int blockSize = -1; @@ -128,6 +128,16 @@ public class ReftableReader extends Reftable { return blockSize; } + @Override + public boolean hasObjectMap() throws IOException { + if (objIndexPosition == -1) { + readFileFooter(); + } + + // We have the map, we have no refs, or the table is small. + return (objPosition > 0 || refEnd == 24 || refIndexPosition == 0); + } + /** * Get the minimum update index for log entries that appear in this * reftable. @@ -146,15 +156,9 @@ public class ReftableReader extends Reftable { } /** - * Get the maximum update index for log entries that appear in this - * reftable. - * - * @return the maximum update index for log entries that appear in this - * reftable. This should be 1 higher than the prior reftable's - * {@code maxUpdateIndex} if this table is used in a stack. - * @throws java.io.IOException - * file cannot be read. + * {@inheritDoc} */ + @Override public long maxUpdateIndex() throws IOException { if (blockSize == -1) { readFileHeader(); @@ -169,11 +173,13 @@ public class ReftableReader extends Reftable { readFileHeader(); } - long end = refEnd > 0 ? refEnd : (src.size() - FILE_FOOTER_LEN); - src.adviseSequentialRead(0, end); + if (refEnd == 0) { + readFileFooter(); + } + src.adviseSequentialRead(0, refEnd); - RefCursorImpl i = new RefCursorImpl(end, null, false); - i.block = readBlock(0, end); + RefCursorImpl i = new RefCursorImpl(refEnd, null, false); + i.block = readBlock(0, refEnd); return i; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReflogReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReflogReader.java new file mode 100644 index 0000000000..c75d3cfa55 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableReflogReader.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2019, Google LLC + * 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.reftable; + +import org.eclipse.jgit.lib.ReflogEntry; +import org.eclipse.jgit.lib.ReflogReader; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.Lock; + +/** + * Implement the ReflogReader interface for a reflog stored in reftable. + */ +public class ReftableReflogReader implements ReflogReader { + private final Lock lock; + + private final Reftable reftable; + + private final String refname; + + ReftableReflogReader(Lock lock, Reftable merged, String refname) { + this.lock = lock; + this.reftable = merged; + this.refname = refname; + } + + /** {@inheritDoc} */ + @Override + public ReflogEntry getLastEntry() throws IOException { + lock.lock(); + try { + LogCursor cursor = reftable.seekLog(refname); + return cursor.next() ? cursor.getReflogEntry() : null; + } finally { + lock.unlock(); + } + } + + /** {@inheritDoc} */ + @Override + public List<ReflogEntry> getReverseEntries() throws IOException { + return getReverseEntries(Integer.MAX_VALUE); + } + + /** {@inheritDoc} */ + @Override + public ReflogEntry getReverseEntry(int number) throws IOException { + lock.lock(); + try { + LogCursor cursor = reftable.seekLog(refname); + while (true) { + if (!cursor.next() || number < 0) { + return null; + } + if (number == 0) { + return cursor.getReflogEntry(); + } + number--; + } + } finally { + lock.unlock(); + } + } + + /** {@inheritDoc} */ + @Override + public List<ReflogEntry> getReverseEntries(int max) throws IOException { + lock.lock(); + try { + LogCursor cursor = reftable.seekLog(refname); + + List<ReflogEntry> result = new ArrayList<>(); + while (cursor.next() && result.size() < max) { + result.add(cursor.getReflogEntry()); + } + + return result; + } finally { + lock.unlock(); + } + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java index 6459c2763d..96f8cb163a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftable/ReftableWriter.java @@ -108,6 +108,7 @@ public class ReftableWriter { private long minUpdateIndex; private long maxUpdateIndex; + private OutputStream outputStream; private ReftableOutputStream out; private ObjectIdSubclassMap<RefList> obj2ref; @@ -122,21 +123,27 @@ public class ReftableWriter { /** * Initialize a writer with a default configuration. + * + * @param os + * output stream. */ - public ReftableWriter() { - this(new ReftableConfig()); + public ReftableWriter(OutputStream os) { + this(new ReftableConfig(), os); lastRef = null; lastLog = null; } /** - * Initialize a writer with a specific configuration. + * Initialize a writer with a configuration. * * @param cfg - * configuration for the writer. + * configuration for the writer + * @param os + * output stream. */ - public ReftableWriter(ReftableConfig cfg) { + public ReftableWriter(ReftableConfig cfg, OutputStream os) { config = cfg; + outputStream = os; } /** @@ -183,16 +190,16 @@ public class ReftableWriter { } /** - * Begin writing the reftable. + * Begin writing the reftable. Should be called only once. Call this + * if a stream was passed to the constructor. * - * @param os - * stream to write the table to. Caller is responsible for - * closing the stream after invoking {@link #finish()}. * @return {@code this} - * @throws java.io.IOException - * if reftable header cannot be written. */ - public ReftableWriter begin(OutputStream os) throws IOException { + public ReftableWriter begin() { + if (out != null) { + throw new IllegalStateException("begin() called twice.");//$NON-NLS-1$ + } + refBlockSize = config.getRefBlockSize(); logBlockSize = config.getLogBlockSize(); restartInterval = config.getRestartInterval(); @@ -212,7 +219,7 @@ public class ReftableWriter { restartInterval = refBlockSize < (60 << 10) ? 16 : 64; } - out = new ReftableOutputStream(os, refBlockSize, alignBlocks); + out = new ReftableOutputStream(outputStream, refBlockSize, alignBlocks); refs = new Section(REF_BLOCK_TYPE); if (indexObjects) { obj2ref = new ObjectIdSubclassMap<>(); @@ -223,6 +230,7 @@ public class ReftableWriter { /** * Sort a collection of references and write them to the reftable. + * The input refs may not have duplicate names. * * @param refsToPack * references to sort and write. @@ -236,10 +244,16 @@ public class ReftableWriter { .map(r -> new RefEntry(r, maxUpdateIndex - minUpdateIndex)) .sorted(Entry::compare) .iterator(); + RefEntry last = null; while (itr.hasNext()) { RefEntry entry = itr.next(); + if (last != null && Entry.compare(last, entry) == 0) { + throwIllegalEntry(last, entry); + } + long blockPos = refs.write(entry); indexRef(entry.ref, blockPos); + last = entry; } return this; } @@ -288,7 +302,7 @@ public class ReftableWriter { private void throwIllegalEntry(Entry last, Entry now) { throw new IllegalArgumentException(MessageFormat.format( - JGitText.get().refTableRecordsMustIncrease, + JGitText.get().reftableRecordsMustIncrease, new String(last.key, UTF_8), new String(now.key, UTF_8))); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java index da98e3fadd..9c5423fb0e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/reftree/RefTreeBatch.java @@ -102,9 +102,8 @@ class RefTreeBatch extends BatchRefUpdate { if (isAtomic()) { ReceiveCommand.abort(getCommands()); return; - } else { - continue; } + continue; } } todo.add(new Command(rw, c)); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileCache.java index 882b2d055b..39a67afae3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/http/NetscapeCookieFileCache.java @@ -82,9 +82,8 @@ public class NetscapeCookieFileCache { public static NetscapeCookieFileCache getInstance(HttpConfig config) { if (instance == null) { return new NetscapeCookieFileCache(config); - } else { - return instance; } + return instance; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFile.java index c1e94a0a3e..ee6adeee98 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/ssh/OpenSshConfigFile.java @@ -384,9 +384,8 @@ public class OpenSshConfigFile { private static boolean isHostMatch(String pattern, String name) { if (pattern.startsWith("!")) { //$NON-NLS-1$ return !patternMatchesHost(pattern.substring(1), name); - } else { - return patternMatchesHost(pattern, name); } + return patternMatchesHost(pattern, name); } private static boolean patternMatchesHost(String pattern, String name) { @@ -399,10 +398,9 @@ public class OpenSshConfigFile { } fn.append(name); return fn.isMatch(); - } else { - // Not a pattern but a full host name - return pattern.equals(name); } + // Not a pattern but a full host name + return pattern.equals(name); } private static String dequote(String value) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java index 4f90e69008..24850ee44c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java @@ -302,10 +302,10 @@ public abstract class AnyObjectId implements Comparable<AnyObjectId> { /** {@inheritDoc} */ @Override public final boolean equals(Object o) { - if (o instanceof AnyObjectId) + if (o instanceof AnyObjectId) { return equals((AnyObjectId) o); - else - return false; + } + return false; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java index 96e50667b3..98a46f3e54 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java @@ -103,25 +103,29 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re private static File getSymRef(File workTree, File dotGit, FS fs) throws IOException { byte[] content = IO.readFully(dotGit); - if (!isSymRef(content)) + if (!isSymRef(content)) { throw new IOException(MessageFormat.format( JGitText.get().invalidGitdirRef, dotGit.getAbsolutePath())); + } int pathStart = 8; int lineEnd = RawParseUtils.nextLF(content, pathStart); while (content[lineEnd - 1] == '\n' || - (content[lineEnd - 1] == '\r' && SystemReader.getInstance().isWindows())) + (content[lineEnd - 1] == '\r' + && SystemReader.getInstance().isWindows())) { lineEnd--; - if (lineEnd == pathStart) + } + if (lineEnd == pathStart) { throw new IOException(MessageFormat.format( JGitText.get().invalidGitdirRef, dotGit.getAbsolutePath())); + } String gitdirPath = RawParseUtils.decode(content, pathStart, lineEnd); File gitdirFile = fs.resolve(workTree, gitdirPath); - if (gitdirFile.isAbsolute()) + if (gitdirFile.isAbsolute()) { return gitdirFile; - else - return new File(workTree, gitdirPath).getCanonicalFile(); + } + return new File(workTree, gitdirPath).getCanonicalFile(); } private FS fs; @@ -723,9 +727,8 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re .getAbsolutePath(), err.getMessage())); } return cfg; - } else { - return new Config(); } + return new Config(); } private File guessWorkTreeOrFail() throws IOException { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java index be53c4b4f6..cad747bcff 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java @@ -232,9 +232,9 @@ public class BranchConfig { private String getRemoteOrDefault() { String remote = getRemote(); - if (remote == null) + if (remote == null) { return Constants.DEFAULT_REMOTE_NAME; - else - return remote; + } + return remote; } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java index d26b7fd17d..2ef365399f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java @@ -1407,12 +1407,11 @@ public class Config { } trailingSpaces.append(cc); continue; - } else { - inLeadingSpace = false; - if (trailingSpaces != null) { - value.append(trailingSpaces); - trailingSpaces.setLength(0); - } + } + inLeadingSpace = false; + if (trailingSpaces != null) { + value.append(trailingSpaces); + trailingSpaces.setLength(0); } if ('\\' == c) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java index 068a8d82e6..b9af817213 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java @@ -149,6 +149,18 @@ public final class ConfigConstants { */ public static final String CONFIG_KEY_GPGSIGN = "gpgSign"; + /** + * The "hooksPath" key. + * @since 5.6 + */ + public static final String CONFIG_KEY_HOOKS_PATH = "hooksPath"; + + /** + * The "quotePath" key. + * @since 5.6 + */ + public static final String CONFIG_KEY_QUOTE_PATH = "quotePath"; + /** The "algorithm" key */ public static final String CONFIG_KEY_ALGORITHM = "algorithm"; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java index 9274fc6777..abd9dd6d38 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java @@ -281,6 +281,12 @@ public final class Constants { */ public static final String OBJECTS = "objects"; + /** + * Reftable folder name + * @since 5.6 + */ + public static final String REFTABLE = "reftable"; + /** Info refs folder */ public static final String INFO_REFS = "info/refs"; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java index 98de3a91cc..cdfa949cad 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CoreConfig.java @@ -79,40 +79,40 @@ public class CoreConfig { * @since 4.3 */ public static enum EOL { - /** checkin with LF, checkout with CRLF. */ + /** Check in with LF, check out with CRLF. */ CRLF, - /** checkin with LF, checkout without conversion. */ + /** Check in with LF, check out without conversion. */ LF, - /** use the platform's native line ending. */ + /** Use the platform's native line ending. */ NATIVE; } /** - * EOL stream conversion protocol + * EOL stream conversion protocol. * * @since 4.3 */ public static enum EolStreamType { - /** convert to CRLF without binary detection */ + /** Convert to CRLF without binary detection. */ TEXT_CRLF, - /** convert to LF without binary detection */ + /** Convert to LF without binary detection. */ TEXT_LF, - /** convert to CRLF with binary detection */ + /** Convert to CRLF with binary detection. */ AUTO_CRLF, - /** convert to LF with binary detection */ + /** Convert to LF with binary detection. */ AUTO_LF, - /** do not convert */ + /** Do not convert. */ DIRECT; } /** - * Permissible values for {@code core.checkstat} + * Permissible values for {@code core.checkstat}. * * @since 3.0 */ @@ -130,11 +130,30 @@ public class CoreConfig { DEFAULT } + /** + * Permissible values for {@code core.logAllRefUpdates}. + * + * @since 5.6 + */ + public static enum LogRefUpdates { + /** Don't create ref logs; default for bare repositories. */ + FALSE, + + /** + * Create ref logs for refs/heads/**, refs/remotes/**, refs/notes/**, + * and for HEAD. Default for non-bare repositories. + */ + TRUE, + + /** Create ref logs for all refs/** and for HEAD. */ + ALWAYS + } + private final int compression; private final int packIndexVersion; - private final boolean logAllRefUpdates; + private final LogRefUpdates logAllRefUpdates; private final String excludesfile; @@ -146,23 +165,26 @@ public class CoreConfig { * @since 3.3 */ public static enum SymLinks { - /** Checkout symbolic links as plain files */ + /** Check out symbolic links as plain files . */ FALSE, - /** Checkout symbolic links as links */ + + /** Check out symbolic links as links. */ TRUE } /** - * Options for hiding files whose names start with a period + * Options for hiding files whose names start with a period. * * @since 3.5 */ public static enum HideDotFiles { - /** Do not hide .files */ + /** Do not hide .files. */ FALSE, - /** Hide add .files */ + + /** Hide add .files. */ TRUE, - /** Hide only .git */ + + /** Hide only .git. */ DOTGITONLY } @@ -171,8 +193,9 @@ public class CoreConfig { ConfigConstants.CONFIG_KEY_COMPRESSION, DEFAULT_COMPRESSION); packIndexVersion = rc.getInt(ConfigConstants.CONFIG_PACK_SECTION, ConfigConstants.CONFIG_KEY_INDEXVERSION, 2); - logAllRefUpdates = rc.getBoolean(ConfigConstants.CONFIG_CORE_SECTION, - ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true); + logAllRefUpdates = rc.getEnum(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, + LogRefUpdates.TRUE); excludesfile = rc.getString(ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_EXCLUDESFILE); attributesfile = rc.getString(ConfigConstants.CONFIG_CORE_SECTION, @@ -201,9 +224,14 @@ public class CoreConfig { * Whether to log all refUpdates * * @return whether to log all refUpdates + * @deprecated since 5.6; default value depends on whether the repository is + * bare. Use + * {@link Config#getEnum(String, String, String, Enum)} + * directly. */ + @Deprecated public boolean isLogAllRefUpdates() { - return logAllRefUpdates; + return !LogRefUpdates.FALSE.equals(logAllRefUpdates); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java index e865da83b1..23e8de0e35 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/DefaultTypedConfigGetter.java @@ -134,11 +134,9 @@ public class DefaultTypedConfigGetter implements TypedConfigGetter { throw new IllegalArgumentException( MessageFormat.format(JGitText.get().enumValueNotSupported3, section, subsection, name, value)); - } else { - throw new IllegalArgumentException( - MessageFormat.format(JGitText.get().enumValueNotSupported2, - section, name, value)); } + throw new IllegalArgumentException(MessageFormat.format( + JGitText.get().enumValueNotSupported2, section, name, value)); } /** {@inheritDoc} */ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java index ce1eb597fc..167d0e08a8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java @@ -384,7 +384,32 @@ public class IndexDiff { * @throws java.io.IOException */ public boolean diff() throws IOException { - return diff(null, 0, 0, ""); //$NON-NLS-1$ + return diff(null); + } + + /** + * Run the diff operation. Until this is called, all lists will be empty. + * Use + * {@link #diff(ProgressMonitor, int, int, String, RepositoryBuilderFactory)} + * if a progress monitor is required. + * <p> + * The operation may create repositories for submodules using builders + * provided by the given {@code factory}, if any, and will also close these + * submodule repositories again. + * </p> + * + * @param factory + * the {@link RepositoryBuilderFactory} to use to create builders + * to create submodule repositories, if needed; if {@code null}, + * submodule repositories will be built using a plain + * {@link RepositoryBuilder}. + * @return if anything is different between index, tree, and workdir + * @throws java.io.IOException + * @since 5.6 + */ + public boolean diff(RepositoryBuilderFactory factory) + throws IOException { + return diff(null, 0, 0, "", factory); //$NON-NLS-1$ } /** @@ -410,6 +435,45 @@ public class IndexDiff { public boolean diff(final ProgressMonitor monitor, int estWorkTreeSize, int estIndexSize, final String title) throws IOException { + return diff(monitor, estWorkTreeSize, estIndexSize, title, null); + } + + /** + * Run the diff operation. Until this is called, all lists will be empty. + * <p> + * The operation may be aborted by the progress monitor. In that event it + * will report what was found before the cancel operation was detected. + * Callers should ignore the result if monitor.isCancelled() is true. If a + * progress monitor is not needed, callers should use {@link #diff()} + * instead. Progress reporting is crude and approximate and only intended + * for informing the user. + * </p> + * <p> + * The operation may create repositories for submodules using builders + * provided by the given {@code factory}, if any, and will also close these + * submodule repositories again. + * </p> + * + * @param monitor + * for reporting progress, may be null + * @param estWorkTreeSize + * number or estimated files in the working tree + * @param estIndexSize + * number of estimated entries in the cache + * @param title + * a {@link java.lang.String} object. + * @param factory + * the {@link RepositoryBuilderFactory} to use to create builders + * to create submodule repositories, if needed; if {@code null}, + * submodule repositories will be built using a plain + * {@link RepositoryBuilder}. + * @return if anything is different between index, tree, and workdir + * @throws java.io.IOException + * @since 5.6 + */ + public boolean diff(ProgressMonitor monitor, int estWorkTreeSize, + int estIndexSize, String title, RepositoryBuilderFactory factory) + throws IOException { dirCache = repository.readDirCache(); try (TreeWalk treeWalk = new TreeWalk(repository)) { @@ -535,64 +599,69 @@ public class IndexDiff { } if (ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL) { - IgnoreSubmoduleMode localIgnoreSubmoduleMode = ignoreSubmoduleMode; - SubmoduleWalk smw = SubmoduleWalk.forIndex(repository); - while (smw.next()) { - try { - if (localIgnoreSubmoduleMode == null) - localIgnoreSubmoduleMode = smw.getModulesIgnore(); - if (IgnoreSubmoduleMode.ALL - .equals(localIgnoreSubmoduleMode)) - continue; - } catch (ConfigInvalidException e) { - throw new IOException(MessageFormat.format( - JGitText.get().invalidIgnoreParamSubmodule, - smw.getPath()), e); - } - try (Repository subRepo = smw.getRepository()) { - String subRepoPath = smw.getPath(); - if (subRepo != null) { - ObjectId subHead = subRepo.resolve("HEAD"); //$NON-NLS-1$ - if (subHead != null - && !subHead.equals(smw.getObjectId())) { - modified.add(subRepoPath); - recordFileMode(subRepoPath, FileMode.GITLINK); - } else if (ignoreSubmoduleMode != IgnoreSubmoduleMode.DIRTY) { - IndexDiff smid = submoduleIndexDiffs.get(smw - .getPath()); - if (smid == null) { - smid = new IndexDiff(subRepo, - smw.getObjectId(), - wTreeIt.getWorkingTreeIterator(subRepo)); - submoduleIndexDiffs.put(subRepoPath, smid); - } - if (smid.diff()) { - if (ignoreSubmoduleMode == IgnoreSubmoduleMode.UNTRACKED - && smid.getAdded().isEmpty() - && smid.getChanged().isEmpty() - && smid.getConflicting().isEmpty() - && smid.getMissing().isEmpty() - && smid.getModified().isEmpty() - && smid.getRemoved().isEmpty()) { - continue; - } + try (SubmoduleWalk smw = new SubmoduleWalk(repository)) { + smw.setTree(new DirCacheIterator(dirCache)); + smw.setBuilderFactory(factory); + while (smw.next()) { + IgnoreSubmoduleMode localIgnoreSubmoduleMode = ignoreSubmoduleMode; + try { + if (localIgnoreSubmoduleMode == null) + localIgnoreSubmoduleMode = smw.getModulesIgnore(); + if (IgnoreSubmoduleMode.ALL + .equals(localIgnoreSubmoduleMode)) + continue; + } catch (ConfigInvalidException e) { + throw new IOException(MessageFormat.format( + JGitText.get().invalidIgnoreParamSubmodule, + smw.getPath()), e); + } + try (Repository subRepo = smw.getRepository()) { + String subRepoPath = smw.getPath(); + if (subRepo != null) { + ObjectId subHead = subRepo.resolve("HEAD"); //$NON-NLS-1$ + if (subHead != null + && !subHead.equals(smw.getObjectId())) { modified.add(subRepoPath); recordFileMode(subRepoPath, FileMode.GITLINK); + } else if (localIgnoreSubmoduleMode != IgnoreSubmoduleMode.DIRTY) { + IndexDiff smid = submoduleIndexDiffs + .get(smw.getPath()); + if (smid == null) { + smid = new IndexDiff(subRepo, + smw.getObjectId(), + wTreeIt.getWorkingTreeIterator( + subRepo)); + submoduleIndexDiffs.put(subRepoPath, smid); + } + if (smid.diff(factory)) { + if (localIgnoreSubmoduleMode == IgnoreSubmoduleMode.UNTRACKED + && smid.getAdded().isEmpty() + && smid.getChanged().isEmpty() + && smid.getConflicting().isEmpty() + && smid.getMissing().isEmpty() + && smid.getModified().isEmpty() + && smid.getRemoved().isEmpty()) { + continue; + } + modified.add(subRepoPath); + recordFileMode(subRepoPath, + FileMode.GITLINK); + } } - } - } else if (missingSubmodules.remove(subRepoPath)) { - // If the directory is there and empty but the submodule - // repository in .git/modules doesn't exist yet it isn't - // "missing". - File gitDir = new File( - new File(repository.getDirectory(), - Constants.MODULES), - subRepoPath); - if (!gitDir.isDirectory()) { - File dir = SubmoduleWalk.getSubmoduleDirectory( - repository, subRepoPath); - if (dir.isDirectory() && !hasFiles(dir)) { - missing.remove(subRepoPath); + } else if (missingSubmodules.remove(subRepoPath)) { + // If the directory is there and empty but the + // submodule repository in .git/modules doesn't + // exist yet it isn't "missing". + File gitDir = new File( + new File(repository.getDirectory(), + Constants.MODULES), + subRepoPath); + if (!gitDir.isDirectory()) { + File dir = SubmoduleWalk.getSubmoduleDirectory( + repository, subRepoPath); + if (dir.isDirectory() && !hasFiles(dir)) { + missing.remove(subRepoPath); + } } } } @@ -602,16 +671,17 @@ public class IndexDiff { } // consume the remaining work - if (monitor != null) + if (monitor != null) { monitor.endTask(); + } ignored = indexDiffFilter.getIgnoredPaths(); if (added.isEmpty() && changed.isEmpty() && removed.isEmpty() && missing.isEmpty() && modified.isEmpty() - && untracked.isEmpty()) + && untracked.isEmpty()) { return false; - else - return true; + } + return true; } private boolean hasFiles(File directory) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java index 700b9dbe85..e14fb102b7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java @@ -293,9 +293,8 @@ public abstract class ObjectReader implements AutoCloseable { if (idItr.hasNext()) { cur = idItr.next(); return true; - } else { - return false; } + return false; } @Override @@ -383,9 +382,8 @@ public abstract class ObjectReader implements AutoCloseable { cur = idItr.next(); sz = getObjectSize(cur, OBJ_ANY); return true; - } else { - return false; } + return false; } @Override diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java index 4d9450e758..9b5a1fdc22 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java @@ -497,6 +497,20 @@ public abstract class RefDatabase { } /** + * If the ref database does not support fast inverse queries, it may + * be advantageous to build a complete SHA1 to ref map in advance for + * multiple uses. To let applications decide on this decision, + * this function indicates whether the inverse map is available. + * + * @return whether this RefDatabase supports fast inverse ref queries. + * @throws IOException on I/O problems. + * @since 5.6 + */ + public boolean hasFastTipsWithSha1() throws IOException { + return false; + } + + /** * Check if any refs exist in the ref database. * <p> * This uses the same definition of refs as {@link #getRefs()}. In diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java index 68866ea279..0e9cf58cf2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java @@ -503,9 +503,8 @@ public abstract class Repository implements AutoCloseable { if (resolved instanceof String) { final Ref ref = findRef((String) resolved); return ref != null ? ref.getLeaf().getObjectId() : null; - } else { - return (ObjectId) resolved; } + return (ObjectId) resolved; } } @@ -527,11 +526,12 @@ public abstract class Repository implements AutoCloseable { try (RevWalk rw = new RevWalk(this)) { rw.setRetainBody(true); Object resolved = resolve(rw, revstr); - if (resolved != null) - if (resolved instanceof String) + if (resolved != null) { + if (resolved instanceof String) { return (String) resolved; - else - return ((AnyObjectId) resolved).getName(); + } + return ((AnyObjectId) resolved).getName(); + } return null; } } @@ -760,15 +760,15 @@ public abstract class Repository implements AutoCloseable { if (name == null) throw new RevisionSyntaxException(revstr); } else if (time.matches("^-\\d+$")) { //$NON-NLS-1$ - if (name != null) + if (name != null) { throw new RevisionSyntaxException(revstr); - else { - String previousCheckout = resolveReflogCheckout(-Integer - .parseInt(time)); - if (ObjectId.isId(previousCheckout)) - rev = parseSimple(rw, previousCheckout); - else - name = previousCheckout; + } + String previousCheckout = resolveReflogCheckout( + -Integer.parseInt(time)); + if (ObjectId.isId(previousCheckout)) { + rev = parseSimple(rw, previousCheckout); + } else { + name = previousCheckout; } } else { if (name == null) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryBuilderFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryBuilderFactory.java new file mode 100644 index 0000000000..fc12516837 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryBuilderFactory.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2019, Thomas Wolf <thomas.wolf@paranor.ch> and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.lib; + +import java.util.function.Supplier; + +/** + * A factory for {@link BaseRepositoryBuilder}s. + * <p> + * Note that a {@link BaseRepositoryBuilder} should be used only once to build a + * repository. Otherwise subsequently built repositories may be built using + * settings made for earlier built repositories. + * </p> + * + * @since 5.6 + */ +public interface RepositoryBuilderFactory extends + Supplier<BaseRepositoryBuilder<? extends BaseRepositoryBuilder, ? extends Repository>> { + // Empty +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java index fa113bfc6b..fc74f5324f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java @@ -476,7 +476,8 @@ public class RepositoryCache { public static boolean isGitRepository(File dir, FS fs) { return fs.resolve(dir, Constants.OBJECTS).exists() && fs.resolve(dir, "refs").exists() //$NON-NLS-1$ - && isValidHead(new File(dir, Constants.HEAD)); + && (fs.resolve(dir, Constants.REFTABLE).exists() + || isValidHead(new File(dir, Constants.HEAD))); } private static boolean isValidHead(File head) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocator.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocator.java index 11db7c5998..f28334cb80 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgKeyLocator.java @@ -72,12 +72,14 @@ import org.bouncycastle.gpg.keybox.PublicKeyRingBlob; import org.bouncycastle.gpg.keybox.UserID; import org.bouncycastle.gpg.keybox.jcajce.JcaKeyBoxBuilder; import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPKeyFlags; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; +import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPUtil; import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory; import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; @@ -90,6 +92,7 @@ import org.eclipse.jgit.api.errors.CanceledException; import org.eclipse.jgit.errors.UnsupportedCredentialItem; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.StringUtils; import org.eclipse.jgit.util.SystemReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -190,19 +193,92 @@ class BouncyCastleGpgKeyLocator { } } - private boolean containsSigningKey(String userId) { - return userId.toLowerCase(Locale.ROOT) - .contains(signingKey.toLowerCase(Locale.ROOT)); + /** + * Checks whether a given OpenPGP {@code userId} matches a given + * {@code signingKeySpec}, which is supposed to have one of the formats + * defined by GPG. + * <p> + * Not all formats are supported; only formats starting with '=', '<', + * '@', and '*' are handled. Any other format results in a case-insensitive + * substring match. + * </p> + * + * @param userId + * of a key + * @param signingKeySpec + * GPG key identification + * @return whether the {@code userId} matches + * @see <a href= + * "https://www.gnupg.org/documentation/manuals/gnupg/Specify-a-User-ID.html">GPG + * Documentation: How to Specify a User ID</a> + */ + static boolean containsSigningKey(String userId, String signingKeySpec) { + if (StringUtils.isEmptyOrNull(userId) + || StringUtils.isEmptyOrNull(signingKeySpec)) { + return false; + } + String toMatch = signingKeySpec; + if (toMatch.startsWith("0x") && toMatch.trim().length() > 2) { //$NON-NLS-1$ + return false; // Explicit fingerprint + } + int command = toMatch.charAt(0); + switch (command) { + case '=': + case '<': + case '@': + case '*': + toMatch = toMatch.substring(1); + if (toMatch.isEmpty()) { + return false; + } + break; + default: + break; + } + switch (command) { + case '=': + return userId.equals(toMatch); + case '<': { + int begin = userId.indexOf('<'); + int end = userId.indexOf('>', begin + 1); + int stop = toMatch.indexOf('>'); + return begin >= 0 && end > begin + 1 && stop > 0 + && userId.substring(begin + 1, end) + .equals(toMatch.substring(0, stop)); + } + case '@': { + int begin = userId.indexOf('<'); + int end = userId.indexOf('>', begin + 1); + return begin >= 0 && end > begin + 1 + && userId.substring(begin + 1, end).contains(toMatch); + } + default: + if (toMatch.trim().isEmpty()) { + return false; + } + return userId.toLowerCase(Locale.ROOT) + .contains(toMatch.toLowerCase(Locale.ROOT)); + } + } + + private String toFingerprint(String keyId) { + if (keyId.startsWith("0x")) { //$NON-NLS-1$ + return keyId.substring(2); + } + return keyId; } private PGPPublicKey findPublicKeyByKeyId(KeyBlob keyBlob) throws IOException { - String keyId = signingKey.toLowerCase(Locale.ROOT); + String keyId = toFingerprint(signingKey).toLowerCase(Locale.ROOT); + if (keyId.isEmpty()) { + return null; + } for (KeyInformation keyInfo : keyBlob.getKeyInformation()) { String fingerprint = Hex.toHexString(keyInfo.getFingerprint()) .toLowerCase(Locale.ROOT); if (fingerprint.endsWith(keyId)) { - return getFirstPublicKey(keyBlob); + return getPublicKey(keyBlob, keyInfo.getFingerprint()); } } return null; @@ -211,8 +287,8 @@ class BouncyCastleGpgKeyLocator { private PGPPublicKey findPublicKeyByUserId(KeyBlob keyBlob) throws IOException { for (UserID userID : keyBlob.getUserIds()) { - if (containsSigningKey(userID.getUserIDAsString())) { - return getFirstPublicKey(keyBlob); + if (containsSigningKey(userID.getUserIDAsString(), signingKey)) { + return getSigningPublicKey(keyBlob); } } return null; @@ -444,7 +520,7 @@ class BouncyCastleGpgKeyLocator { PGPUtil.getDecoderStream(new BufferedInputStream(in)), new JcaKeyFingerprintCalculator()); - String keyId = signingkey.toLowerCase(Locale.ROOT); + String keyId = toFingerprint(signingkey).toLowerCase(Locale.ROOT); Iterator<PGPSecretKeyRing> keyrings = pgpSec.getKeyRings(); while (keyrings.hasNext()) { PGPSecretKeyRing keyRing = keyrings.next(); @@ -462,7 +538,7 @@ class BouncyCastleGpgKeyLocator { Iterator<String> userIDs = key.getUserIDs(); while (userIDs.hasNext()) { String userId = userIDs.next(); - if (containsSigningKey(userId)) { + if (containsSigningKey(userId, signingKey)) { return key; } } @@ -490,7 +566,7 @@ class BouncyCastleGpgKeyLocator { new BufferedInputStream(in), new JcaKeyFingerprintCalculator()); - String keyId = signingKey.toLowerCase(Locale.ROOT); + String keyId = toFingerprint(signingKey).toLowerCase(Locale.ROOT); Iterator<PGPPublicKeyRing> keyrings = pgpPub.getKeyRings(); while (keyrings.hasNext()) { PGPPublicKeyRing keyRing = keyrings.next(); @@ -507,7 +583,7 @@ class BouncyCastleGpgKeyLocator { Iterator<String> userIDs = key.getUserIDs(); while (userIDs.hasNext()) { String userId = userIDs.next(); - if (containsSigningKey(userId)) { + if (containsSigningKey(userId, signingKey)) { return key; } } @@ -517,9 +593,42 @@ class BouncyCastleGpgKeyLocator { return null; } - private PGPPublicKey getFirstPublicKey(KeyBlob keyBlob) throws IOException { - return ((PublicKeyRingBlob) keyBlob).getPGPPublicKeyRing() - .getPublicKey(); + private PGPPublicKey getPublicKey(KeyBlob blob, byte[] fingerprint) + throws IOException { + return ((PublicKeyRingBlob) blob).getPGPPublicKeyRing() + .getPublicKey(fingerprint); + } + + private PGPPublicKey getSigningPublicKey(KeyBlob blob) throws IOException { + PGPPublicKey masterKey = null; + Iterator<PGPPublicKey> keys = ((PublicKeyRingBlob) blob) + .getPGPPublicKeyRing().getPublicKeys(); + while (keys.hasNext()) { + PGPPublicKey key = keys.next(); + // only consider keys that have the [S] usage flag set + if (isSigningKey(key)) { + if (key.isMasterKey()) { + masterKey = key; + } else { + return key; + } + } + } + // return the master key if no other signing key was found or null if + // the master key did not have the signing flag set + return masterKey; + } + + private boolean isSigningKey(PGPPublicKey key) { + Iterator signatures = key.getSignatures(); + while (signatures.hasNext()) { + PGPSignature sig = (PGPSignature) signatures.next(); + if ((sig.getHashedSubPackets().getKeyFlags() + & PGPKeyFlags.CAN_SIGN) > 0) { + return true; + } + } + return false; } private KeyBox readKeyBoxFile(Path keyboxFile) throws IOException, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java index cfe0931b47..cfa67eefdc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java @@ -115,7 +115,7 @@ public class BouncyCastleGpgSigner extends GpgSigner { NoSuchAlgorithmException, NoSuchProviderException, PGPException, URISyntaxException { if (gpgSigningKey == null || gpgSigningKey.isEmpty()) { - gpgSigningKey = committer.getEmailAddress(); + gpgSigningKey = '<' + committer.getEmailAddress() + '>'; } BouncyCastleGpgKeyLocator keyHelper = new BouncyCastleGpgKeyLocator( diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java index cdbe3cd26c..12f353e0da 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeConfig.java @@ -166,10 +166,10 @@ public class MergeConfig { String mergeOptions = config.getString( ConfigConstants.CONFIG_BRANCH_SECTION, branch, ConfigConstants.CONFIG_KEY_MERGEOPTIONS); - if (mergeOptions != null) + if (mergeOptions != null) { return mergeOptions.split("\\s"); //$NON-NLS-1$ - else - return new String[0]; + } + return new String[0]; } private static class MergeConfigSectionParser implements @@ -188,10 +188,10 @@ public class MergeConfig { @Override public boolean equals(Object obj) { - if (obj instanceof MergeConfigSectionParser) + if (obj instanceof MergeConfigSectionParser) { return branch.equals(((MergeConfigSectionParser) obj).branch); - else - return false; + } + return false; } @Override diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java index ca0e18a0ef..ca2f37abee 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java @@ -153,15 +153,16 @@ public class MergeMessageFormatter { private static void addConflictsMessage(List<String> conflictingPaths, StringBuilder sb) { sb.append("Conflicts:\n"); //$NON-NLS-1$ - for (String conflictingPath : conflictingPaths) + for (String conflictingPath : conflictingPaths) { sb.append('\t').append(conflictingPath).append('\n'); + } } private static String joinNames(List<String> names, String singular, String plural) { - if (names.size() == 1) + if (names.size() == 1) { return singular + " " + names.get(0); //$NON-NLS-1$ - else - return plural + " " + StringUtils.join(names, ", ", " and "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + return plural + " " + StringUtils.join(names, ", ", " and "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java index 0b423fb5d4..e0b00c0bd7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -652,42 +652,40 @@ public class ResolveMerger extends ThreeWayMerger { keep(ourDce); // no checkout needed! return true; - } else { - // same content but different mode on OURS and THEIRS. - // Try to merge the mode and report an error if this is - // not possible. - int newMode = mergeFileModes(modeB, modeO, modeT); - if (newMode != FileMode.MISSING.getBits()) { - if (newMode == modeO) - // ours version is preferred - keep(ourDce); - else { - // the preferred version THEIRS has a different mode - // than ours. Check it out! - if (isWorktreeDirty(work, ourDce)) - return false; - // we know about length and lastMod only after we have written the new content. - // This will happen later. Set these values to 0 for know. - DirCacheEntry e = add(tw.getRawPath(), theirs, - DirCacheEntry.STAGE_0, EPOCH, 0); - addToCheckout(tw.getPathString(), e, attributes); - } - return true; + } + // same content but different mode on OURS and THEIRS. + // Try to merge the mode and report an error if this is + // not possible. + int newMode = mergeFileModes(modeB, modeO, modeT); + if (newMode != FileMode.MISSING.getBits()) { + if (newMode == modeO) { + // ours version is preferred + keep(ourDce); } else { - // FileModes are not mergeable. We found a conflict on modes. - // For conflicting entries we don't know lastModified and length. - add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0); - add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0); - add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, - 0); - unmergedPaths.add(tw.getPathString()); - mergeResults.put( - tw.getPathString(), - new MergeResult<>(Collections - .<RawText> emptyList())); + // the preferred version THEIRS has a different mode + // than ours. Check it out! + if (isWorktreeDirty(work, ourDce)) { + return false; + } + // we know about length and lastMod only after we have + // written the new content. + // This will happen later. Set these values to 0 for know. + DirCacheEntry e = add(tw.getRawPath(), theirs, + DirCacheEntry.STAGE_0, EPOCH, 0); + addToCheckout(tw.getPathString(), e, attributes); } return true; } + // FileModes are not mergeable. We found a conflict on modes. + // For conflicting entries we don't know lastModified and + // length. + add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0); + add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0); + add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0); + unmergedPaths.add(tw.getPathString()); + mergeResults.put(tw.getPathString(), + new MergeResult<>(Collections.<RawText> emptyList())); + return true; } if (modeB == modeT && tw.idEqual(T_BASE, T_THEIRS)) { @@ -716,21 +714,20 @@ public class ResolveMerger extends ThreeWayMerger { addToCheckout(tw.getPathString(), e, attributes); } return true; - } else { - // we want THEIRS ... but THEIRS contains a folder or the - // deletion of the path. Delete what's in the working tree, - // which we know to be clean. - if (tw.getTreeCount() > T_FILE && tw.getRawMode(T_FILE) == 0) { - // Not present in working tree, so nothing to delete - return true; - } - if (modeT != 0 && modeT == modeB) { - // Base, ours, and theirs all contain a folder: don't delete - return true; - } - addDeletion(tw.getPathString(), nonTree(modeO), attributes); + } + // we want THEIRS ... but THEIRS contains a folder or the + // deletion of the path. Delete what's in the working tree, + // which we know to be clean. + if (tw.getTreeCount() > T_FILE && tw.getRawMode(T_FILE) == 0) { + // Not present in working tree, so nothing to delete return true; } + if (modeT != 0 && modeT == modeB) { + // Base, ours, and theirs all contain a folder: don't delete + return true; + } + addDeletion(tw.getPathString(), nonTree(modeO), attributes); + return true; } if (tw.isSubtree()) { @@ -1310,10 +1307,9 @@ public class ResolveMerger extends ThreeWayMerger { if (getUnmergedPaths().isEmpty() && !failed()) { resultTree = dircache.writeTree(getObjectInserter()); return true; - } else { - resultTree = null; - return false; } + resultTree = null; + return false; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java index 2fc0f4f073..d56e5c0c1e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ThreeWayMerger.java @@ -143,17 +143,17 @@ public abstract class ThreeWayMerger extends Merger { * @throws java.io.IOException */ protected AbstractTreeIterator mergeBase() throws IOException { - if (baseTree != null) + if (baseTree != null) { return openTree(baseTree); + } RevCommit baseCommit = (baseCommitId != null) ? walk .parseCommit(baseCommitId) : getBaseCommit(sourceCommits[0], sourceCommits[1]); if (baseCommit == null) { baseCommitId = null; return new EmptyTreeIterator(); - } else { - baseCommitId = baseCommit.toObjectId(); - return openTree(baseCommit.getTree()); } + baseCommitId = baseCommit.toObjectId(); + return openTree(baseCommit.getTree()); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/FanoutBucket.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/FanoutBucket.java index 7827a9aa05..c1616b3ed8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/FanoutBucket.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/FanoutBucket.java @@ -167,10 +167,10 @@ class FanoutBucket extends InMemoryNoteBucket { @Override public Note next() { - if (hasNext()) + if (hasNext()) { return itr.next(); - else - throw new NoSuchElementException(); + } + throw new NoSuchElementException(); } @Override @@ -214,30 +214,31 @@ class FanoutBucket extends InMemoryNoteBucket { NoteBucket b = table[cell]; if (b == null) { - if (noteData == null) + if (noteData == null) { return this; + } LeafBucket n = new LeafBucket(prefixLen + 2); table[cell] = n.set(noteOn, noteData, or); cnt++; return this; - } else { - NoteBucket n = b.set(noteOn, noteData, or); - if (n == null) { - table[cell] = null; - cnt--; + } + NoteBucket n = b.set(noteOn, noteData, or); + if (n == null) { + table[cell] = null; + cnt--; - if (cnt == 0) - return null; + if (cnt == 0) { + return null; + } - return contractIfTooSmall(noteOn, or); + return contractIfTooSmall(noteOn, or); - } else if (n != b) { - table[cell] = n; - } - return this; + } else if (n != b) { + table[cell] = n; } + return this; } InMemoryNoteBucket contractIfTooSmall(AnyObjectId noteOn, ObjectReader or) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java index 6723b6309c..0fa2a6306c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java @@ -129,10 +129,10 @@ class LeafBucket extends InMemoryNoteBucket { @Override public Note next() { - if (hasNext()) + if (hasNext()) { return notes[idx++]; - else - throw new NoSuchElementException(); + } + throw new NoSuchElementException(); } @Override @@ -156,25 +156,23 @@ class LeafBucket extends InMemoryNoteBucket { notes[p].setData(noteData.copy()); return this; - } else { - System.arraycopy(notes, p + 1, notes, p, cnt - p - 1); - cnt--; - return 0 < cnt ? this : null; } + System.arraycopy(notes, p + 1, notes, p, cnt - p - 1); + cnt--; + return 0 < cnt ? this : null; } else if (noteData != null) { if (shouldSplit()) { return split().set(noteOn, noteData, or); - - } else { - growIfFull(); - p = -(p + 1); - if (p < cnt) - System.arraycopy(notes, p, notes, p + 1, cnt - p); - notes[p] = new Note(noteOn, noteData.copy()); - cnt++; - return this; } + growIfFull(); + p = -(p + 1); + if (p < cnt) { + System.arraycopy(notes, p, notes, p + 1, cnt - p); + } + notes[p] = new Note(noteOn, noteData.copy()); + cnt++; + return this; } else { return this; @@ -234,12 +232,10 @@ class LeafBucket extends InMemoryNoteBucket { InMemoryNoteBucket append(Note note) { if (shouldSplit()) { return split().append(note); - - } else { - growIfFull(); - notes[cnt++] = note; - return this; } + growIfFull(); + notes[cnt++] = note; + return this; } private void growIfFull() { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java index cbef61338f..e4eef433d8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java @@ -278,10 +278,10 @@ public class NoteMap implements Iterable<Note> { public byte[] getCachedBytes(AnyObjectId id, int sizeLimit) throws LargeObjectException, MissingObjectException, IOException { ObjectId dataId = get(id); - if (dataId != null) + if (dataId != null) { return reader.open(dataId).getCachedBytes(sizeLimit); - else - return null; + } + return null; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java index ba7223b8f0..6ff1402900 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMapMerger.java @@ -307,10 +307,10 @@ public class NoteMapMerger { private static InMemoryNoteBucket addIfNotNull(InMemoryNoteBucket result, Note note) { - if (note != null) + if (note != null) { return result.append(note); - else - return result; + } + return result; } private NonNoteEntry mergeNonNotes(NonNoteEntry baseList, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteParser.java index 8ef3af10ad..7dfc47deb0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteParser.java @@ -181,9 +181,8 @@ final class NoteParser extends CanonicalTreeParser { } catch (ArrayIndexOutOfBoundsException notHex) { return -1; } - } else { - return -1; } + return -1; } private void storeNonNote() { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java index 45508ce027..2bb45c55dc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java @@ -391,11 +391,10 @@ public class PlotCommitList<L extends PlotLane> extends return pos.intValue(); } return positionsAllocated++; - } else { - final Integer min = freePositions.first(); - freePositions.remove(min); - return min.intValue(); } + final Integer min = freePositions.first(); + freePositions.remove(min); + return min.intValue(); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java index ee18fe7c2f..19e40b562b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java @@ -176,11 +176,10 @@ public class PlotWalk extends RevWalk { Collection<Ref> list = reverseRefMap.get(commitId); if (list == null) { return PlotCommit.NO_REFS; - } else { - Ref[] tags = list.toArray(new Ref[0]); - Arrays.sort(tags, new PlotRefComparator()); - return tags; } + Ref[] tags = list.toArray(new Ref[0]); + Arrays.sort(tags, new PlotRefComparator()); + return tags; } class PlotRefComparator implements Comparator<Ref> { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapCalculator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapCalculator.java deleted file mode 100644 index 14e95670aa..0000000000 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmapCalculator.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2019, Google LLC. - * 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.revwalk; - -import static java.util.Objects.requireNonNull; - -import java.io.IOException; - -import org.eclipse.jgit.errors.IncorrectObjectTypeException; -import org.eclipse.jgit.errors.MissingObjectException; -import org.eclipse.jgit.internal.revwalk.AddToBitmapFilter; -import org.eclipse.jgit.lib.BitmapIndex; -import org.eclipse.jgit.lib.BitmapIndex.Bitmap; -import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder; -import org.eclipse.jgit.lib.ProgressMonitor; - -/** - * Calculate the bitmap indicating what other commits are reachable from certain - * commit. - * <p> - * This bitmap refers only to commits. For a bitmap with ALL objects reachable - * from certain object, see {@code BitmapWalker}. - */ -class BitmapCalculator { - - private final RevWalk walk; - private final BitmapIndex bitmapIndex; - - BitmapCalculator(RevWalk walk) throws IOException { - this.walk = walk; - this.bitmapIndex = requireNonNull( - walk.getObjectReader().getBitmapIndex()); - } - - /** - * Get the reachability bitmap from certain commit to other commits. - * <p> - * This will return a precalculated bitmap if available or walk building one - * until finding a precalculated bitmap (and returning the union). - * <p> - * Beware that the returned bitmap it is guaranteed to include ONLY the - * commits reachable from the initial commit. It COULD include other objects - * (because precalculated bitmaps have them) but caller shouldn't count on - * that. See {@link BitmapWalker} for a full reachability bitmap. - * - * @param start - * the commit. Use {@code walk.parseCommit(objectId)} to get this - * object from the id. - * @param pm - * progress monitor. Updated by one per commit browsed in the - * graph - * @return the bitmap of reachable commits (and maybe some extra objects) - * for the commit - * @throws MissingObjectException - * the supplied id doesn't exist - * @throws IncorrectObjectTypeException - * the supplied id doesn't refer to a commit or a tag - * @throws IOException - * if the walk cannot open a packfile or loose object - */ - BitmapBuilder getBitmap(RevCommit start, ProgressMonitor pm) - throws MissingObjectException, - IncorrectObjectTypeException, IOException { - Bitmap precalculatedBitmap = bitmapIndex.getBitmap(start); - if (precalculatedBitmap != null) { - return asBitmapBuilder(precalculatedBitmap); - } - - walk.reset(); - walk.sort(RevSort.TOPO); - walk.markStart(start); - // Unbounded walk. If the repo has bitmaps, it should bump into one at - // some point. - - BitmapBuilder bitmapResult = bitmapIndex.newBitmapBuilder(); - walk.setRevFilter(new AddToBitmapFilter(bitmapResult)); - while (walk.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); - } - - return bitmapResult; - } - - private BitmapBuilder asBitmapBuilder(Bitmap bitmap) { - return bitmapIndex.newBitmapBuilder().or(bitmap); - } -} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmappedReachabilityChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmappedReachabilityChecker.java index 6e510f677b..bf831e3313 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmappedReachabilityChecker.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BitmappedReachabilityChecker.java @@ -45,13 +45,18 @@ package org.eclipse.jgit.revwalk; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.lib.BitmapIndex; +import org.eclipse.jgit.lib.BitmapIndex.Bitmap; import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder; -import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.revwalk.filter.RevFilter; /** * Checks the reachability using bitmaps. @@ -84,37 +89,108 @@ class BitmappedReachabilityChecker implements ReachabilityChecker { * Check all targets are reachable from the starters. * <p> * In this implementation, it is recommended to put the most popular - * starters (e.g. refs/heads tips) at the beginning of the collection + * starters (e.g. refs/heads tips) at the beginning. */ @Override public Optional<RevCommit> areAllReachable(Collection<RevCommit> targets, - Collection<RevCommit> starters) throws MissingObjectException, + Stream<RevCommit> starters) throws MissingObjectException, IncorrectObjectTypeException, IOException { - BitmapCalculator calculator = new BitmapCalculator(walk); - /** - * Iterate over starters bitmaps and remove targets as they become - * reachable. - * - * Building the total starters bitmap has the same cost (iterating over - * all starters adding the bitmaps) and this gives us the chance to - * shorcut the loop. - * - * This is based on the assuption that most of the starters will have - * the reachability bitmap precalculated. If many require a walk, the - * walk.reset() could start to take too much time. - */ List<RevCommit> remainingTargets = new ArrayList<>(targets); - for (RevCommit starter : starters) { - BitmapBuilder starterBitmap = calculator.getBitmap(starter, - NullProgressMonitor.INSTANCE); - remainingTargets.removeIf(starterBitmap::contains); - if (remainingTargets.isEmpty()) { - return Optional.empty(); + + walk.reset(); + walk.sort(RevSort.TOPO); + + // Filter emits only commits that are unreachable from previously + // visited commits. Internally it keeps a bitmap of everything + // reachable so far, which we use to discard reachable targets. + BitmapIndex repoBitmaps = walk.getObjectReader().getBitmapIndex(); + ReachedFilter reachedFilter = new ReachedFilter(repoBitmaps); + walk.setRevFilter(reachedFilter); + + Iterator<RevCommit> startersIter = starters.iterator(); + while (startersIter.hasNext()) { + walk.markStart(startersIter.next()); + while (walk.next() != null) { + remainingTargets.removeIf(reachedFilter::isReachable); + + if (remainingTargets.isEmpty()) { + return Optional.empty(); + } } + walk.reset(); } return Optional.of(remainingTargets.get(0)); } + /** + * This filter emits commits that were not bitmap-reachable from anything + * visited before. Or in other words, commits that add something (themselves + * or their bitmap) to the "reached" bitmap. + * + * Current progress can be queried via {@link #isReachable(RevCommit)}. + */ + private static class ReachedFilter extends RevFilter { + + private final BitmapIndex repoBitmaps; + private final BitmapBuilder reached; + + /** + * Create a filter that emits only previously unreachable commits. + * + * @param repoBitmaps + * bitmap index of the repo + */ + public ReachedFilter(BitmapIndex repoBitmaps) { + this.repoBitmaps = repoBitmaps; + this.reached = repoBitmaps.newBitmapBuilder(); + } + + /** {@inheritDoc} */ + @Override + public final boolean include(RevWalk walker, RevCommit cmit) { + Bitmap commitBitmap; + + if (reached.contains(cmit)) { + // already seen or included + dontFollow(cmit); + return false; + } + + if ((commitBitmap = repoBitmaps.getBitmap(cmit)) != null) { + reached.or(commitBitmap); + // Emit the commit because there are new contents in the bitmap + // but don't follow parents (they are already in the bitmap) + dontFollow(cmit); + return true; + } + + // No bitmaps, keep going + reached.addObject(cmit, Constants.OBJ_COMMIT); + return true; + } + + private static final void dontFollow(RevCommit cmit) { + for (RevCommit p : cmit.getParents()) { + p.add(RevFlag.SEEN); + } + } + + /** {@inheritDoc} */ + @Override + public final RevFilter clone() { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @Override + public final boolean requiresCommitBody() { + return false; + } + + boolean isReachable(RevCommit commit) { + return reached.contains(commit); + } + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PedestrianReachabilityChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PedestrianReachabilityChecker.java index bba3c5cff3..da9e75992f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PedestrianReachabilityChecker.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PedestrianReachabilityChecker.java @@ -44,7 +44,9 @@ package org.eclipse.jgit.revwalk; import java.io.IOException; import java.util.Collection; +import java.util.Iterator; import java.util.Optional; +import java.util.stream.Stream; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; @@ -75,7 +77,7 @@ class PedestrianReachabilityChecker implements ReachabilityChecker { @Override public Optional<RevCommit> areAllReachable(Collection<RevCommit> targets, - Collection<RevCommit> starters) + Stream<RevCommit> starters) throws MissingObjectException, IncorrectObjectTypeException, IOException { walk.reset(); @@ -87,8 +89,9 @@ class PedestrianReachabilityChecker implements ReachabilityChecker { walk.markStart(target); } - for (RevCommit starter : starters) { - walk.markUninteresting(starter); + Iterator<RevCommit> iterator = starters.iterator(); + while (iterator.hasNext()) { + walk.markUninteresting(iterator.next()); } return Optional.ofNullable(walk.next()); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ReachabilityChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ReachabilityChecker.java index 2ed06d1769..6a9c641318 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ReachabilityChecker.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ReachabilityChecker.java @@ -45,6 +45,7 @@ package org.eclipse.jgit.revwalk; import java.io.IOException; import java.util.Collection; import java.util.Optional; +import java.util.stream.Stream; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; @@ -82,9 +83,43 @@ public interface ReachabilityChecker { * @throws IOException * if any of the underlying indexes or readers can not be * opened. + * + * @deprecated see {{@link #areAllReachable(Collection, Stream)} + */ + @Deprecated + default Optional<RevCommit> areAllReachable(Collection<RevCommit> targets, + Collection<RevCommit> starters) throws MissingObjectException, + IncorrectObjectTypeException, IOException { + return areAllReachable(targets, starters.stream()); + } + + /** + * Check if all targets are reachable from the {@code starter} commits. + * <p> + * Caller should parse the objectIds (preferably with + * {@code walk.parseCommit()} and handle missing/incorrect type objects + * before calling this method. + * + * @param targets + * commits to reach. + * @param starters + * known starting points. + * @return An unreachable target if at least one of the targets is + * unreachable. An empty optional if all targets are reachable from + * the starters. + * + * @throws MissingObjectException + * if any of the incoming objects doesn't exist in the + * repository. + * @throws IncorrectObjectTypeException + * if any of the incoming objects is not a commit or a tag. + * @throws IOException + * if any of the underlying indexes or readers can not be + * opened. + * @since 5.6 */ Optional<RevCommit> areAllReachable(Collection<RevCommit> targets, - Collection<RevCommit> starters) + Stream<RevCommit> starters) throws MissingObjectException, IncorrectObjectTypeException, IOException; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java index 2e26641ebc..b77407bb38 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java @@ -103,11 +103,15 @@ class RewriteGenerator extends Generator { final int nParents = pList.length; for (int i = 0; i < nParents; i++) { final RevCommit oldp = pList[i]; - if (firstParent && i > 0) { - c.parents = new RevCommit[] { rewrite(oldp) }; + final RevCommit newp = rewrite(oldp); + if (firstParent) { + if (newp == null) { + c.parents = RevCommit.NO_PARENTS; + } else { + c.parents = new RevCommit[] { newp }; + } return c; } - final RevCommit newp = rewrite(oldp); if (oldp != newp) { pList[i] = newp; rewrote = true; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java index a2c9ef6da4..e0325c29f9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java @@ -80,11 +80,11 @@ class TopoSortGenerator extends Generator { if (c == null) { break; } - for (int i = 0; i < c.parents.length; i++) { - if (firstParent && i > 0) { + for (RevCommit p : c.parents) { + p.inDegree++; + if (firstParent) { break; } - c.parents[i].inDegree++; } pending.add(c); } @@ -119,11 +119,7 @@ class TopoSortGenerator extends Generator { // All of our children have already produced, // so it is OK for us to produce now as well. // - for (int i = 0; i < c.parents.length; i++) { - if (firstParent && i > 0) { - break; - } - RevCommit p = c.parents[i]; + for (RevCommit p : c.parents) { if (--p.inDegree == 0 && (p.flags & TOPO_DELAY) != 0) { // This parent tried to come before us, but we are // his last child. unpop the parent so it goes right @@ -132,6 +128,9 @@ class TopoSortGenerator extends Generator { p.flags &= ~TOPO_DELAY; pending.unpop(p); } + if (firstParent) { + break; + } } return c; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java index f7c3218850..090d1e110c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TreeRevFilter.java @@ -169,19 +169,19 @@ public class TreeRevFilter extends RevFilter { // c.flags |= rewriteFlag; return false; - } else { - // We have interesting items, but neither of the special - // cases denoted above. + } + + // We have interesting items, but neither of the special + // cases denoted above. + // + if (adds > 0 && tw.getFilter() instanceof FollowFilter) { + // One of the paths we care about was added in this + // commit. We need to update our filter to its older + // name, if we can discover it. Find out what that is. // - if (adds > 0 && tw.getFilter() instanceof FollowFilter) { - // One of the paths we care about was added in this - // commit. We need to update our filter to its older - // name, if we can discover it. Find out what that is. - // - updateFollowFilter(trees, ((FollowFilter) tw.getFilter()).cfg); - } - return true; + updateFollowFilter(trees, ((FollowFilter) tw.getFilter()).cfg); } + return true; } else if (nParents == 0) { // We have no parents to compare against. Consider us to be // REWRITE only if we have no paths matching our filter. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java index e6e3d4fb12..645da0a068 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java @@ -271,6 +271,20 @@ public class PackStatistics { public long treesTraversed; /** + * Amount of packfile uris sent to the client to download via HTTP. + * + * @since 5.6 + */ + public long offloadedPackfiles; + + /** + * Total size (in bytes) offloaded to HTTP downloads. + * + * @since 5.6 + */ + public long offloadedPackfileSize; + + /** * Statistics about each object type in the pack (commits, tags, trees * and blobs.) */ @@ -598,6 +612,22 @@ public class PackStatistics { } /** + * @return amount of packfiles offloaded (sent as "packfile-uri")/ + * @since 5.6 + */ + public long getOffloadedPackfiles() { + return statistics.offloadedPackfiles; + } + + /** + * @return total size (in bytes) offloaded to HTTP downloads. + * @since 5.6 + */ + public long getOffloadedPackfilesSize() { + return statistics.offloadedPackfileSize; + } + + /** * Get total time spent processing this pack. * * @return total time spent processing this pack. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java index e5559dea09..2e5776d646 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java @@ -57,6 +57,7 @@ import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.BaseRepositoryBuilder; import org.eclipse.jgit.lib.BlobBasedConfig; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ConfigConstants; @@ -66,6 +67,7 @@ import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryBuilder; +import org.eclipse.jgit.lib.RepositoryBuilderFactory; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.treewalk.AbstractTreeIterator; @@ -260,15 +262,41 @@ public class SubmoduleWalk implements AutoCloseable { */ public static Repository getSubmoduleRepository(final File parent, final String path, FS fs) throws IOException { + return getSubmoduleRepository(parent, path, fs, + new RepositoryBuilder()); + } + + /** + * Get submodule repository at path, using the specified file system + * abstraction and the specified builder + * + * @param parent + * {@link Repository} that contains the submodule + * @param path + * of the working tree of the submodule + * @param fs + * {@link FS} to use + * @param builder + * {@link BaseRepositoryBuilder} to use to build the submodule + * repository + * @return the {@link Repository} of the submodule, or {@code null} if it + * doesn't exist + * @throws IOException + * on errors + * @since 5.6 + */ + public static Repository getSubmoduleRepository(File parent, String path, + FS fs, BaseRepositoryBuilder<?, ? extends Repository> builder) + throws IOException { File subWorkTree = new File(parent, path); - if (!subWorkTree.isDirectory()) + if (!subWorkTree.isDirectory()) { return null; - File workTree = new File(parent, path); + } try { - return new RepositoryBuilder() // + return builder // .setMustExist(true) // .setFS(fs) // - .setWorkTree(workTree) // + .setWorkTree(subWorkTree) // .build(); } catch (RepositoryNotFoundException e) { return null; @@ -366,6 +394,8 @@ public class SubmoduleWalk implements AutoCloseable { private Map<String, String> pathToName; + private RepositoryBuilderFactory factory; + /** * Create submodule generator * @@ -639,7 +669,25 @@ public class SubmoduleWalk implements AutoCloseable { } /** - * The module name for the current submodule entry (used for the section name of .git/config) + * Sets the {@link RepositoryBuilderFactory} to use for creating submodule + * repositories. If none is set, a plain {@link RepositoryBuilder} is used. + * + * @param factory + * to set + * @since 5.6 + */ + public void setBuilderFactory(RepositoryBuilderFactory factory) { + this.factory = factory; + } + + private BaseRepositoryBuilder<?, ? extends Repository> getBuilder() { + return factory != null ? factory.get() : new RepositoryBuilder(); + } + + /** + * The module name for the current submodule entry (used for the section + * name of .git/config) + * * @since 4.10 * @return name */ @@ -735,6 +783,13 @@ public class SubmoduleWalk implements AutoCloseable { */ public IgnoreSubmoduleMode getModulesIgnore() throws IOException, ConfigInvalidException { + IgnoreSubmoduleMode mode = repoConfig.getEnum( + IgnoreSubmoduleMode.values(), + ConfigConstants.CONFIG_SUBMODULE_SECTION, getModuleName(), + ConfigConstants.CONFIG_KEY_IGNORE, null); + if (mode != null) { + return mode; + } lazyLoadModulesConfig(); return modulesConfig.getEnum(IgnoreSubmoduleMode.values(), ConfigConstants.CONFIG_SUBMODULE_SECTION, getModuleName(), @@ -748,7 +803,8 @@ public class SubmoduleWalk implements AutoCloseable { * @throws java.io.IOException */ public Repository getRepository() throws IOException { - return getSubmoduleRepository(repository, path); + return getSubmoduleRepository(repository.getWorkTree(), path, + repository.getFS(), getBuilder()); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AbstractAdvertiseRefsHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AbstractAdvertiseRefsHook.java index 4bf0d2692a..ed900121be 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AbstractAdvertiseRefsHook.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AbstractAdvertiseRefsHook.java @@ -67,7 +67,7 @@ public abstract class AbstractAdvertiseRefsHook implements AdvertiseRefsHook { /** {@inheritDoc} */ @Override - public void advertiseRefs(BaseReceivePack receivePack) + public void advertiseRefs(ReceivePack receivePack) throws ServiceMayNotContinueException { Map<String, Ref> refs = getAdvertisedRefs(receivePack.getRepository(), receivePack.getRevWalk()); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java index 8512f2d9fe..eb1aef9ad7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHook.java @@ -51,8 +51,8 @@ public interface AdvertiseRefsHook { /** * A simple hook that advertises the default refs. * <p> - * The method implementations do nothing to preserve the default behavior; see - * {@link UploadPack#setAdvertisedRefs(java.util.Map)} and + * The method implementations do nothing to preserve the default behavior; + * see {@link UploadPack#setAdvertisedRefs(java.util.Map)} and * {@link ReceivePack#setAdvertisedRefs(java.util.Map,java.util.Set)}. */ AdvertiseRefsHook DEFAULT = new AdvertiseRefsHook() { @@ -62,7 +62,7 @@ public interface AdvertiseRefsHook { } @Override - public void advertiseRefs(BaseReceivePack receivePack) { + public void advertiseRefs(ReceivePack receivePack) { // Do nothing. } }; @@ -89,7 +89,8 @@ public interface AdvertiseRefsHook { * if necessary. * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException * abort; the message will be sent to the user. + * @since 5.6 */ - void advertiseRefs(BaseReceivePack receivePack) + void advertiseRefs(ReceivePack receivePack) throws ServiceMayNotContinueException; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java index 12238a1f77..54c19783e3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AdvertiseRefsHookChain.java @@ -53,7 +53,7 @@ import java.util.List; * modify the results of the previous hooks in the chain by calling * {@link org.eclipse.jgit.transport.UploadPack#getAdvertisedRefs()}, or * {@link org.eclipse.jgit.transport.ReceivePack#getAdvertisedRefs()} or - * {@link org.eclipse.jgit.transport.BaseReceivePack#getAdvertisedObjects()}. + * {@link org.eclipse.jgit.transport.ReceivePack#getAdvertisedObjects()}. */ public class AdvertiseRefsHookChain implements AdvertiseRefsHook { private final AdvertiseRefsHook[] hooks; @@ -82,7 +82,7 @@ public class AdvertiseRefsHookChain implements AdvertiseRefsHook { /** {@inheritDoc} */ @Override - public void advertiseRefs(BaseReceivePack rp) + public void advertiseRefs(ReceivePack rp) throws ServiceMayNotContinueException { for (int i = 0; i < count; i++) hooks[i].advertiseRefs(rp); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java deleted file mode 100644 index 36a10cc6b9..0000000000 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java +++ /dev/null @@ -1,1971 +0,0 @@ -/* - * Copyright (C) 2008-2010, Google Inc. - * and other copyright owners as documented in the project's IP log. - * - * This program and the accompanying materials are made available - * under the terms of the Eclipse Distribution License v1.0 which - * accompanies this distribution, is reproduced below, and is - * available at http://www.eclipse.org/org/documents/edl-v10.php - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * - Neither the name of the Eclipse Foundation, Inc. nor the - * names of its contributors may be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.eclipse.jgit.transport; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC; -import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_DELETE_REFS; -import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_OFS_DELTA; -import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_OPTIONS; -import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_QUIET; -import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS; -import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SIDE_BAND_64K; -import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT; -import static org.eclipse.jgit.transport.SideBandOutputStream.CH_DATA; -import static org.eclipse.jgit.transport.SideBandOutputStream.CH_ERROR; -import static org.eclipse.jgit.transport.SideBandOutputStream.CH_PROGRESS; -import static org.eclipse.jgit.transport.SideBandOutputStream.MAX_BUF; - -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jgit.annotations.Nullable; -import org.eclipse.jgit.errors.InvalidObjectIdException; -import org.eclipse.jgit.errors.LargeObjectException; -import org.eclipse.jgit.errors.MissingObjectException; -import org.eclipse.jgit.errors.PackProtocolException; -import org.eclipse.jgit.errors.TooLargePackException; -import org.eclipse.jgit.internal.JGitText; -import org.eclipse.jgit.internal.storage.file.PackLock; -import org.eclipse.jgit.internal.submodule.SubmoduleValidator; -import org.eclipse.jgit.internal.submodule.SubmoduleValidator.SubmoduleValidationException; -import org.eclipse.jgit.internal.transport.parser.FirstCommand; -import org.eclipse.jgit.lib.AnyObjectId; -import org.eclipse.jgit.lib.BatchRefUpdate; -import org.eclipse.jgit.lib.Config; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.GitmoduleEntry; -import org.eclipse.jgit.lib.NullProgressMonitor; -import org.eclipse.jgit.lib.ObjectChecker; -import org.eclipse.jgit.lib.ObjectDatabase; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectIdSubclassMap; -import org.eclipse.jgit.lib.ObjectInserter; -import org.eclipse.jgit.lib.ObjectLoader; -import org.eclipse.jgit.lib.PersonIdent; -import org.eclipse.jgit.lib.ProgressMonitor; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.revwalk.ObjectWalk; -import org.eclipse.jgit.revwalk.RevBlob; -import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.revwalk.RevFlag; -import org.eclipse.jgit.revwalk.RevObject; -import org.eclipse.jgit.revwalk.RevSort; -import org.eclipse.jgit.revwalk.RevTree; -import org.eclipse.jgit.revwalk.RevWalk; -import org.eclipse.jgit.transport.PacketLineIn.InputOverLimitIOException; -import org.eclipse.jgit.transport.ReceiveCommand.Result; -import org.eclipse.jgit.util.io.InterruptTimer; -import org.eclipse.jgit.util.io.LimitedInputStream; -import org.eclipse.jgit.util.io.TimeoutInputStream; -import org.eclipse.jgit.util.io.TimeoutOutputStream; - -/** - * Base implementation of the side of a push connection that receives objects. - * <p> - * Contains high-level operations for initializing and closing streams, - * advertising refs, reading commands, and receiving and applying a pack. - * Subclasses compose these operations into full service implementations. - */ -public abstract class BaseReceivePack { - /** - * Data in the first line of a request, the line itself plus capabilities. - * - * @deprecated Use {@link FirstCommand} instead. - */ - @Deprecated - public static class FirstLine { - private final FirstCommand command; - - /** - * Parse the first line of a receive-pack request. - * - * @param line - * line from the client. - */ - public FirstLine(String line) { - command = FirstCommand.fromLine(line); - } - - /** @return non-capabilities part of the line. */ - public String getLine() { - return command.getLine(); - } - - /** @return capabilities parsed from the line. */ - public Set<String> getCapabilities() { - return command.getCapabilities(); - } - } - - /** Database we write the stored objects into. */ - final Repository db; - - /** Revision traversal support over {@link #db}. */ - final RevWalk walk; - - /** - * Is the client connection a bi-directional socket or pipe? - * <p> - * If true, this class assumes it can perform multiple read and write cycles - * with the client over the input and output streams. This matches the - * functionality available with a standard TCP/IP connection, or a local - * operating system or in-memory pipe. - * <p> - * If false, this class runs in a read everything then output results mode, - * making it suitable for single round-trip systems RPCs such as HTTP. - */ - private boolean biDirectionalPipe = true; - - /** Expecting data after the pack footer */ - private boolean expectDataAfterPackFooter; - - /** Should an incoming transfer validate objects? */ - private ObjectChecker objectChecker; - - /** Should an incoming transfer permit create requests? */ - private boolean allowCreates; - - /** Should an incoming transfer permit delete requests? */ - private boolean allowAnyDeletes; - private boolean allowBranchDeletes; - - /** Should an incoming transfer permit non-fast-forward requests? */ - private boolean allowNonFastForwards; - - /** Should an incoming transfer permit push options? **/ - private boolean allowPushOptions; - - /** - * Should the requested ref updates be performed as a single atomic - * transaction? - */ - private boolean atomic; - - private boolean allowOfsDelta; - private boolean allowQuiet = true; - - /** Identity to record action as within the reflog. */ - private PersonIdent refLogIdent; - - /** Hook used while advertising the refs to the client. */ - private AdvertiseRefsHook advertiseRefsHook; - - /** Filter used while advertising the refs to the client. */ - RefFilter refFilter; - - /** Timeout in seconds to wait for client interaction. */ - private int timeout; - - /** Timer to manage {@link #timeout}. */ - private InterruptTimer timer; - - private TimeoutInputStream timeoutIn; - - // Original stream passed to init(), since rawOut may be wrapped in a - // sideband. - private OutputStream origOut; - - /** Raw input stream. */ - protected InputStream rawIn; - - /** Raw output stream. */ - protected OutputStream rawOut; - - /** Optional message output stream. */ - protected OutputStream msgOut; - private SideBandOutputStream errOut; - - /** Packet line input stream around {@link #rawIn}. */ - protected PacketLineIn pckIn; - - /** Packet line output stream around {@link #rawOut}. */ - protected PacketLineOut pckOut; - - private final MessageOutputWrapper msgOutWrapper = new MessageOutputWrapper(); - - private PackParser parser; - - /** The refs we advertised as existing at the start of the connection. */ - Map<String, Ref> refs; - - /** All SHA-1s shown to the client, which can be possible edges. */ - Set<ObjectId> advertisedHaves; - - /** Capabilities requested by the client. */ - private Set<String> enabledCapabilities; - String userAgent; - private Set<ObjectId> clientShallowCommits; - private List<ReceiveCommand> commands; - private long maxCommandBytes; - private long maxDiscardBytes; - - private StringBuilder advertiseError; - - /** If {@link BasePackPushConnection#CAPABILITY_SIDE_BAND_64K} is enabled. */ - private boolean sideBand; - - private boolean quiet; - - /** Lock around the received pack file, while updating refs. */ - private PackLock packLock; - - private boolean checkReferencedIsReachable; - - /** Git object size limit */ - private long maxObjectSizeLimit; - - /** Total pack size limit */ - private long maxPackSizeLimit = -1; - - /** The size of the received pack, including index size */ - private Long packSize; - - private PushCertificateParser pushCertificateParser; - private SignedPushConfig signedPushConfig; - PushCertificate pushCert; - private ReceivedPackStatistics stats; - - /** - * Get the push certificate used to verify the pusher's identity. - * <p> - * Only valid after commands are read from the wire. - * - * @return the parsed certificate, or null if push certificates are disabled - * or no cert was presented by the client. - * @since 4.1 - * @deprecated use {@link ReceivePack#getPushCertificate}. - */ - @Deprecated - public abstract PushCertificate getPushCertificate(); - - /** - * Set the push certificate used to verify the pusher's identity. - * <p> - * Should only be called if reconstructing an instance without going through - * the normal {@link #recvCommands()} flow. - * - * @param cert - * the push certificate to set. - * @since 4.1 - * @deprecated use {@link ReceivePack#setPushCertificate(PushCertificate)}. - */ - @Deprecated - public abstract void setPushCertificate(PushCertificate cert); - - /** - * Create a new pack receive for an open repository. - * - * @param into - * the destination repository. - */ - protected BaseReceivePack(Repository into) { - db = into; - walk = new RevWalk(db); - walk.setRetainBody(false); - - TransferConfig tc = db.getConfig().get(TransferConfig.KEY); - objectChecker = tc.newReceiveObjectChecker(); - - ReceiveConfig rc = db.getConfig().get(ReceiveConfig::new); - allowCreates = rc.allowCreates; - allowAnyDeletes = true; - allowBranchDeletes = rc.allowDeletes; - allowNonFastForwards = rc.allowNonFastForwards; - allowOfsDelta = rc.allowOfsDelta; - allowPushOptions = rc.allowPushOptions; - maxCommandBytes = rc.maxCommandBytes; - maxDiscardBytes = rc.maxDiscardBytes; - advertiseRefsHook = AdvertiseRefsHook.DEFAULT; - refFilter = RefFilter.DEFAULT; - advertisedHaves = new HashSet<>(); - clientShallowCommits = new HashSet<>(); - signedPushConfig = rc.signedPush; - } - - /** Configuration for receive operations. */ - protected static class ReceiveConfig { - final boolean allowCreates; - final boolean allowDeletes; - final boolean allowNonFastForwards; - final boolean allowOfsDelta; - final boolean allowPushOptions; - final long maxCommandBytes; - final long maxDiscardBytes; - final SignedPushConfig signedPush; - - ReceiveConfig(Config config) { - allowCreates = true; - allowDeletes = !config.getBoolean("receive", "denydeletes", false); //$NON-NLS-1$ //$NON-NLS-2$ - allowNonFastForwards = !config.getBoolean("receive", //$NON-NLS-1$ - "denynonfastforwards", false); //$NON-NLS-1$ - allowOfsDelta = config.getBoolean("repack", "usedeltabaseoffset", //$NON-NLS-1$ //$NON-NLS-2$ - true); - allowPushOptions = config.getBoolean("receive", "pushoptions", //$NON-NLS-1$ //$NON-NLS-2$ - false); - maxCommandBytes = config.getLong("receive", //$NON-NLS-1$ - "maxCommandBytes", //$NON-NLS-1$ - 3 << 20); - maxDiscardBytes = config.getLong("receive", //$NON-NLS-1$ - "maxCommandDiscardBytes", //$NON-NLS-1$ - -1); - signedPush = SignedPushConfig.KEY.parse(config); - } - } - - /** - * Output stream that wraps the current {@link #msgOut}. - * <p> - * We don't want to expose {@link #msgOut} directly because it can change - * several times over the course of a session. - */ - class MessageOutputWrapper extends OutputStream { - @Override - public void write(int ch) { - if (msgOut != null) { - try { - msgOut.write(ch); - } catch (IOException e) { - // Ignore write failures. - } - } - } - - @Override - public void write(byte[] b, int off, int len) { - if (msgOut != null) { - try { - msgOut.write(b, off, len); - } catch (IOException e) { - // Ignore write failures. - } - } - } - - @Override - public void write(byte[] b) { - write(b, 0, b.length); - } - - @Override - public void flush() { - if (msgOut != null) { - try { - msgOut.flush(); - } catch (IOException e) { - // Ignore write failures. - } - } - } - } - - /** - * Get the process name used for pack lock messages. - * - * @return the process name used for pack lock messages. - */ - protected abstract String getLockMessageProcessName(); - - /** - * Get the repository this receive completes into. - * - * @return the repository this receive completes into. - * @deprecated use {@link ReceivePack#getRepository} - */ - @Deprecated - public abstract Repository getRepository(); - - /** - * Get the RevWalk instance used by this connection. - * - * @return the RevWalk instance used by this connection. - * @deprecated use {@link ReceivePack#getRevWalk} - */ - @Deprecated - public abstract RevWalk getRevWalk(); - - /** - * Get refs which were advertised to the client. - * - * @return all refs which were advertised to the client, or null if - * {@link #setAdvertisedRefs(Map, Set)} has not been called yet. - * @deprecated use {@link ReceivePack#getAdvertisedRefs} - */ - @Deprecated - public abstract Map<String, Ref> getAdvertisedRefs(); - - /** - * Set the refs advertised by this ReceivePack. - * <p> - * Intended to be called from a - * {@link org.eclipse.jgit.transport.PreReceiveHook}. - * - * @param allRefs - * explicit set of references to claim as advertised by this - * ReceivePack instance. This overrides any references that may - * exist in the source repository. The map is passed to the - * configured {@link #getRefFilter()}. If null, assumes all refs - * were advertised. - * @param additionalHaves - * explicit set of additional haves to claim as advertised. If - * null, assumes the default set of additional haves from the - * repository. - * @deprecated use {@link ReceivePack#setAdvertisedRefs} - */ - @Deprecated - public abstract void setAdvertisedRefs(Map<String, Ref> allRefs, Set<ObjectId> additionalHaves); - - /** - * Get objects advertised to the client. - * - * @return the set of objects advertised to the as present in this repository, - * or null if {@link #setAdvertisedRefs(Map, Set)} has not been called - * yet. - */ - public final Set<ObjectId> getAdvertisedObjects() { - return advertisedHaves; - } - - /** - * Whether this instance will validate all referenced, but not supplied by - * the client, objects are reachable from another reference. - * - * @return true if this instance will validate all referenced, but not - * supplied by the client, objects are reachable from another - * reference. - */ - public boolean isCheckReferencedObjectsAreReachable() { - return checkReferencedIsReachable; - } - - /** - * Validate all referenced but not supplied objects are reachable. - * <p> - * If enabled, this instance will verify that references to objects not - * contained within the received pack are already reachable through at least - * one other reference displayed as part of {@link #getAdvertisedRefs()}. - * <p> - * This feature is useful when the application doesn't trust the client to - * not provide a forged SHA-1 reference to an object, in an attempt to - * access parts of the DAG that they aren't allowed to see and which have - * been hidden from them via the configured - * {@link org.eclipse.jgit.transport.AdvertiseRefsHook} or - * {@link org.eclipse.jgit.transport.RefFilter}. - * <p> - * Enabling this feature may imply at least some, if not all, of the same - * functionality performed by {@link #setCheckReceivedObjects(boolean)}. - * Applications are encouraged to enable both features, if desired. - * - * @param b - * {@code true} to enable the additional check. - */ - public void setCheckReferencedObjectsAreReachable(boolean b) { - this.checkReferencedIsReachable = b; - } - - /** - * Whether this class expects a bi-directional pipe opened between the - * client and itself. - * - * @return true if this class expects a bi-directional pipe opened between - * the client and itself. The default is true. - */ - public boolean isBiDirectionalPipe() { - return biDirectionalPipe; - } - - /** - * Whether this class will assume the socket is a fully bidirectional pipe - * between the two peers and takes advantage of that by first transmitting - * the known refs, then waiting to read commands. - * - * @param twoWay - * if true, this class will assume the socket is a fully - * bidirectional pipe between the two peers and takes advantage - * of that by first transmitting the known refs, then waiting to - * read commands. If false, this class assumes it must read the - * commands before writing output and does not perform the - * initial advertising. - */ - public void setBiDirectionalPipe(boolean twoWay) { - biDirectionalPipe = twoWay; - } - - /** - * Whether there is data expected after the pack footer. - * - * @return {@code true} if there is data expected after the pack footer. - */ - public boolean isExpectDataAfterPackFooter() { - return expectDataAfterPackFooter; - } - - /** - * Whether there is additional data in InputStream after pack. - * - * @param e - * {@code true} if there is additional data in InputStream after - * pack. - */ - public void setExpectDataAfterPackFooter(boolean e) { - expectDataAfterPackFooter = e; - } - - /** - * Whether this instance will verify received objects are formatted - * correctly. - * - * @return {@code true} if this instance will verify received objects are - * formatted correctly. Validating objects requires more CPU time on - * this side of the connection. - */ - public boolean isCheckReceivedObjects() { - return objectChecker != null; - } - - /** - * Whether to enable checking received objects - * - * @param check - * {@code true} to enable checking received objects; false to - * assume all received objects are valid. - * @see #setObjectChecker(ObjectChecker) - */ - public void setCheckReceivedObjects(boolean check) { - if (check && objectChecker == null) - setObjectChecker(new ObjectChecker()); - else if (!check && objectChecker != null) - setObjectChecker(null); - } - - /** - * Set the object checking instance to verify each received object with - * - * @param impl - * if non-null the object checking instance to verify each - * received object with; null to disable object checking. - * @since 3.4 - */ - public void setObjectChecker(ObjectChecker impl) { - objectChecker = impl; - } - - /** - * Whether the client can request refs to be created. - * - * @return {@code true} if the client can request refs to be created. - */ - public boolean isAllowCreates() { - return allowCreates; - } - - /** - * Whether to permit create ref commands to be processed. - * - * @param canCreate - * {@code true} to permit create ref commands to be processed. - */ - public void setAllowCreates(boolean canCreate) { - allowCreates = canCreate; - } - - /** - * Whether the client can request refs to be deleted. - * - * @return {@code true} if the client can request refs to be deleted. - */ - public boolean isAllowDeletes() { - return allowAnyDeletes; - } - - /** - * Whether to permit delete ref commands to be processed. - * - * @param canDelete - * {@code true} to permit delete ref commands to be processed. - */ - public void setAllowDeletes(boolean canDelete) { - allowAnyDeletes = canDelete; - } - - /** - * Whether the client can delete from {@code refs/heads/}. - * - * @return {@code true} if the client can delete from {@code refs/heads/}. - * @since 3.6 - */ - public boolean isAllowBranchDeletes() { - return allowBranchDeletes; - } - - /** - * Configure whether to permit deletion of branches from the - * {@code refs/heads/} namespace. - * - * @param canDelete - * {@code true} to permit deletion of branches from the - * {@code refs/heads/} namespace. - * @since 3.6 - */ - public void setAllowBranchDeletes(boolean canDelete) { - allowBranchDeletes = canDelete; - } - - /** - * Whether the client can request non-fast-forward updates of a ref, - * possibly making objects unreachable. - * - * @return {@code true} if the client can request non-fast-forward updates - * of a ref, possibly making objects unreachable. - */ - public boolean isAllowNonFastForwards() { - return allowNonFastForwards; - } - - /** - * Configure whether to permit the client to ask for non-fast-forward - * updates of an existing ref. - * - * @param canRewind - * {@code true} to permit the client to ask for non-fast-forward - * updates of an existing ref. - */ - public void setAllowNonFastForwards(boolean canRewind) { - allowNonFastForwards = canRewind; - } - - /** - * Whether the client's commands should be performed as a single atomic - * transaction. - * - * @return {@code true} if the client's commands should be performed as a - * single atomic transaction. - * @since 4.4 - */ - public boolean isAtomic() { - return atomic; - } - - /** - * Configure whether to perform the client's commands as a single atomic - * transaction. - * - * @param atomic - * {@code true} to perform the client's commands as a single - * atomic transaction. - * @since 4.4 - */ - public void setAtomic(boolean atomic) { - this.atomic = atomic; - } - - /** - * Get identity of the user making the changes in the reflog. - * - * @return identity of the user making the changes in the reflog. - */ - public PersonIdent getRefLogIdent() { - return refLogIdent; - } - - /** - * Set the identity of the user appearing in the affected reflogs. - * <p> - * The timestamp portion of the identity is ignored. A new identity with the - * current timestamp will be created automatically when the updates occur - * and the log records are written. - * - * @param pi - * identity of the user. If null the identity will be - * automatically determined based on the repository - * configuration. - */ - public void setRefLogIdent(PersonIdent pi) { - refLogIdent = pi; - } - - /** - * Get the hook used while advertising the refs to the client - * - * @return the hook used while advertising the refs to the client - */ - public AdvertiseRefsHook getAdvertiseRefsHook() { - return advertiseRefsHook; - } - - /** - * Get the filter used while advertising the refs to the client - * - * @return the filter used while advertising the refs to the client - */ - public RefFilter getRefFilter() { - return refFilter; - } - - /** - * Set the hook used while advertising the refs to the client. - * <p> - * If the {@link org.eclipse.jgit.transport.AdvertiseRefsHook} chooses to - * call {@link #setAdvertisedRefs(Map,Set)}, only refs set by this hook - * <em>and</em> selected by the {@link org.eclipse.jgit.transport.RefFilter} - * will be shown to the client. Clients may still attempt to create or - * update a reference not advertised by the configured - * {@link org.eclipse.jgit.transport.AdvertiseRefsHook}. These attempts - * should be rejected by a matching - * {@link org.eclipse.jgit.transport.PreReceiveHook}. - * - * @param advertiseRefsHook - * the hook; may be null to show all refs. - */ - public void setAdvertiseRefsHook(AdvertiseRefsHook advertiseRefsHook) { - if (advertiseRefsHook != null) - this.advertiseRefsHook = advertiseRefsHook; - else - this.advertiseRefsHook = AdvertiseRefsHook.DEFAULT; - } - - /** - * Set the filter used while advertising the refs to the client. - * <p> - * Only refs allowed by this filter will be shown to the client. The filter - * is run against the refs specified by the - * {@link org.eclipse.jgit.transport.AdvertiseRefsHook} (if applicable). - * - * @param refFilter - * the filter; may be null to show all refs. - */ - public void setRefFilter(RefFilter refFilter) { - this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT; - } - - /** - * Get timeout (in seconds) before aborting an IO operation. - * - * @return timeout (in seconds) before aborting an IO operation. - */ - public int getTimeout() { - return timeout; - } - - /** - * Set the timeout before willing to abort an IO call. - * - * @param seconds - * number of seconds to wait (with no data transfer occurring) - * before aborting an IO read or write operation with the - * connected client. - */ - public void setTimeout(int seconds) { - timeout = seconds; - } - - /** - * Set the maximum number of command bytes to read from the client. - * - * @param limit - * command limit in bytes; if 0 there is no limit. - * @since 4.7 - */ - public void setMaxCommandBytes(long limit) { - maxCommandBytes = limit; - } - - /** - * Set the maximum number of command bytes to discard from the client. - * <p> - * Discarding remaining bytes allows this instance to consume the rest of - * the command block and send a human readable over-limit error via the - * side-band channel. If the client sends an excessive number of bytes this - * limit kicks in and the instance disconnects, resulting in a non-specific - * 'pipe closed', 'end of stream', or similar generic error at the client. - * <p> - * When the limit is set to {@code -1} the implementation will default to - * the larger of {@code 3 * maxCommandBytes} or {@code 3 MiB}. - * - * @param limit - * discard limit in bytes; if 0 there is no limit; if -1 the - * implementation tries to set a reasonable default. - * @since 4.7 - */ - public void setMaxCommandDiscardBytes(long limit) { - maxDiscardBytes = limit; - } - - /** - * Set the maximum allowed Git object size. - * <p> - * If an object is larger than the given size the pack-parsing will throw an - * exception aborting the receive-pack operation. - * - * @param limit - * the Git object size limit. If zero then there is not limit. - */ - public void setMaxObjectSizeLimit(long limit) { - maxObjectSizeLimit = limit; - } - - /** - * Set the maximum allowed pack size. - * <p> - * A pack exceeding this size will be rejected. - * - * @param limit - * the pack size limit, in bytes - * @since 3.3 - */ - public void setMaxPackSizeLimit(long limit) { - if (limit < 0) - throw new IllegalArgumentException(MessageFormat.format( - JGitText.get().receivePackInvalidLimit, Long.valueOf(limit))); - maxPackSizeLimit = limit; - } - - /** - * Check whether the client expects a side-band stream. - * - * @return true if the client has advertised a side-band capability, false - * otherwise. - * @throws org.eclipse.jgit.transport.RequestNotYetReadException - * if the client's request has not yet been read from the wire, so - * we do not know if they expect side-band. Note that the client - * may have already written the request, it just has not been - * read. - */ - public boolean isSideBand() throws RequestNotYetReadException { - checkRequestWasRead(); - return enabledCapabilities.contains(CAPABILITY_SIDE_BAND_64K); - } - - /** - * Whether clients may request avoiding noisy progress messages. - * - * @return true if clients may request avoiding noisy progress messages. - * @since 4.0 - */ - public boolean isAllowQuiet() { - return allowQuiet; - } - - /** - * Configure if clients may request the server skip noisy messages. - * - * @param allow - * true to allow clients to request quiet behavior; false to - * refuse quiet behavior and send messages anyway. This may be - * necessary if processing is slow and the client-server network - * connection can timeout. - * @since 4.0 - */ - public void setAllowQuiet(boolean allow) { - allowQuiet = allow; - } - - /** - * Whether the server supports receiving push options. - * - * @return true if the server supports receiving push options. - * @since 4.5 - */ - public boolean isAllowPushOptions() { - return allowPushOptions; - } - - /** - * Configure if the server supports receiving push options. - * - * @param allow - * true to optionally accept option strings from the client. - * @since 4.5 - */ - public void setAllowPushOptions(boolean allow) { - allowPushOptions = allow; - } - - /** - * True if the client wants less verbose output. - * - * @return true if the client has requested the server to be less verbose. - * @throws org.eclipse.jgit.transport.RequestNotYetReadException - * if the client's request has not yet been read from the wire, - * so we do not know if they expect side-band. Note that the - * client may have already written the request, it just has not - * been read. - * @since 4.0 - */ - public boolean isQuiet() throws RequestNotYetReadException { - checkRequestWasRead(); - return quiet; - } - - /** - * Set the configuration for push certificate verification. - * - * @param cfg - * new configuration; if this object is null or its {@link - * SignedPushConfig#getCertNonceSeed()} is null, push certificate - * verification will be disabled. - * @since 4.1 - */ - public void setSignedPushConfig(SignedPushConfig cfg) { - signedPushConfig = cfg; - } - - private PushCertificateParser getPushCertificateParser() { - if (pushCertificateParser == null) { - pushCertificateParser = new PushCertificateParser(db, signedPushConfig); - } - return pushCertificateParser; - } - - /** - * Get the user agent of the client. - * <p> - * If the client is new enough to use {@code agent=} capability that value - * will be returned. Older HTTP clients may also supply their version using - * the HTTP {@code User-Agent} header. The capability overrides the HTTP - * header if both are available. - * <p> - * When an HTTP request has been received this method returns the HTTP - * {@code User-Agent} header value until capabilities have been parsed. - * - * @return user agent supplied by the client. Available only if the client - * is new enough to advertise its user agent. - * @since 4.0 - */ - public String getPeerUserAgent() { - return UserAgent.getAgent(enabledCapabilities, userAgent); - } - - /** - * Get all of the command received by the current request. - * - * @return all of the command received by the current request. - */ - public List<ReceiveCommand> getAllCommands() { - return Collections.unmodifiableList(commands); - } - - /** - * Send an error message to the client. - * <p> - * If any error messages are sent before the references are advertised to - * the client, the errors will be sent instead of the advertisement and the - * receive operation will be aborted. All clients should receive and display - * such early stage errors. - * <p> - * If the reference advertisements have already been sent, messages are sent - * in a side channel. If the client doesn't support receiving messages, the - * message will be discarded, with no other indication to the caller or to - * the client. - * <p> - * {@link org.eclipse.jgit.transport.PreReceiveHook}s should always try to - * use - * {@link org.eclipse.jgit.transport.ReceiveCommand#setResult(Result, String)} - * with a result status of - * {@link org.eclipse.jgit.transport.ReceiveCommand.Result#REJECTED_OTHER_REASON} - * to indicate any reasons for rejecting an update. Messages attached to a - * command are much more likely to be returned to the client. - * - * @param what - * string describing the problem identified by the hook. The - * string must not end with an LF, and must not contain an LF. - */ - public void sendError(String what) { - if (refs == null) { - if (advertiseError == null) - advertiseError = new StringBuilder(); - advertiseError.append(what).append('\n'); - } else { - msgOutWrapper.write(Constants.encode("error: " + what + "\n")); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - private void fatalError(String msg) { - if (errOut != null) { - try { - errOut.write(Constants.encode(msg)); - errOut.flush(); - } catch (IOException e) { - // Ignore write failures - } - } else { - sendError(msg); - } - } - - /** - * Send a message to the client, if it supports receiving them. - * <p> - * If the client doesn't support receiving messages, the message will be - * discarded, with no other indication to the caller or to the client. - * - * @param what - * string describing the problem identified by the hook. The - * string must not end with an LF, and must not contain an LF. - */ - public void sendMessage(String what) { - msgOutWrapper.write(Constants.encode(what + "\n")); //$NON-NLS-1$ - } - - /** - * Get an underlying stream for sending messages to the client. - * - * @return an underlying stream for sending messages to the client. - */ - public OutputStream getMessageOutputStream() { - return msgOutWrapper; - } - - /** - * Get the size of the received pack file including the index size. - * - * This can only be called if the pack is already received. - * - * @return the size of the received pack including index size - * @throws java.lang.IllegalStateException - * if called before the pack has been received - * @since 3.3 - */ - public long getPackSize() { - if (packSize != null) - return packSize.longValue(); - throw new IllegalStateException(JGitText.get().packSizeNotSetYet); - } - - /** - * Get the commits from the client's shallow file. - * - * @return if the client is a shallow repository, the list of edge commits - * that define the client's shallow boundary. Empty set if the client - * is earlier than Git 1.9, or is a full clone. - * @since 3.5 - */ - protected Set<ObjectId> getClientShallowCommits() { - return clientShallowCommits; - } - - /** - * Whether any commands to be executed have been read. - * - * @return {@code true} if any commands to be executed have been read. - */ - protected boolean hasCommands() { - return !commands.isEmpty(); - } - - /** - * Whether an error occurred that should be advertised. - * - * @return true if an error occurred that should be advertised. - */ - protected boolean hasError() { - return advertiseError != null; - } - - /** - * Initialize the instance with the given streams. - * - * @param input - * raw input to read client commands and pack data from. Caller - * must ensure the input is buffered, otherwise read performance - * may suffer. - * @param output - * response back to the Git network client. Caller must ensure - * the output is buffered, otherwise write performance may - * suffer. - * @param messages - * secondary "notice" channel to send additional messages out - * through. When run over SSH this should be tied back to the - * standard error channel of the command execution. For most - * other network connections this should be null. - */ - protected void init(final InputStream input, final OutputStream output, - final OutputStream messages) { - origOut = output; - rawIn = input; - rawOut = output; - msgOut = messages; - - if (timeout > 0) { - final Thread caller = Thread.currentThread(); - timer = new InterruptTimer(caller.getName() + "-Timer"); //$NON-NLS-1$ - timeoutIn = new TimeoutInputStream(rawIn, timer); - TimeoutOutputStream o = new TimeoutOutputStream(rawOut, timer); - timeoutIn.setTimeout(timeout * 1000); - o.setTimeout(timeout * 1000); - rawIn = timeoutIn; - rawOut = o; - } - - pckIn = new PacketLineIn(rawIn); - pckOut = new PacketLineOut(rawOut); - pckOut.setFlushOnEnd(false); - - enabledCapabilities = new HashSet<>(); - commands = new ArrayList<>(); - } - - /** - * Get advertised refs, or the default if not explicitly advertised. - * - * @return advertised refs, or the default if not explicitly advertised. - */ - protected Map<String, Ref> getAdvertisedOrDefaultRefs() { - if (refs == null) - setAdvertisedRefs(null, null); - return refs; - } - - /** - * Receive a pack from the stream and check connectivity if necessary. - * - * @throws java.io.IOException - * an error occurred during unpacking or connectivity checking. - */ - protected void receivePackAndCheckConnectivity() throws IOException { - receivePack(); - if (needCheckConnectivity()) { - checkSubmodules(); - checkConnectivity(); - } - parser = null; - } - - /** - * Unlock the pack written by this object. - * - * @throws java.io.IOException - * the pack could not be unlocked. - */ - protected void unlockPack() throws IOException { - if (packLock != null) { - packLock.unlock(); - packLock = null; - } - } - - /** - * Generate an advertisement of available refs and capabilities. - * - * @param adv - * the advertisement formatter. - * @throws java.io.IOException - * the formatter failed to write an advertisement. - * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException - * the hook denied advertisement. - */ - public void sendAdvertisedRefs(RefAdvertiser adv) - throws IOException, ServiceMayNotContinueException { - if (advertiseError != null) { - adv.writeOne("ERR " + advertiseError); //$NON-NLS-1$ - return; - } - - try { - advertiseRefsHook.advertiseRefs(this); - } catch (ServiceMayNotContinueException fail) { - if (fail.getMessage() != null) { - adv.writeOne("ERR " + fail.getMessage()); //$NON-NLS-1$ - fail.setOutput(); - } - throw fail; - } - - adv.init(db); - adv.advertiseCapability(CAPABILITY_SIDE_BAND_64K); - adv.advertiseCapability(CAPABILITY_DELETE_REFS); - adv.advertiseCapability(CAPABILITY_REPORT_STATUS); - if (allowQuiet) - adv.advertiseCapability(CAPABILITY_QUIET); - String nonce = getPushCertificateParser().getAdvertiseNonce(); - if (nonce != null) { - adv.advertiseCapability(nonce); - } - if (db.getRefDatabase().performsAtomicTransactions()) - adv.advertiseCapability(CAPABILITY_ATOMIC); - if (allowOfsDelta) - adv.advertiseCapability(CAPABILITY_OFS_DELTA); - if (allowPushOptions) { - adv.advertiseCapability(CAPABILITY_PUSH_OPTIONS); - } - adv.advertiseCapability(OPTION_AGENT, UserAgent.get()); - adv.send(getAdvertisedOrDefaultRefs().values()); - for (ObjectId obj : advertisedHaves) - adv.advertiseHave(obj); - if (adv.isEmpty()) - adv.advertiseId(ObjectId.zeroId(), "capabilities^{}"); //$NON-NLS-1$ - adv.end(); - } - - /** - * Returns the statistics on the received pack if available. This should be - * called after {@link #receivePack} is called. - * - * @return ReceivedPackStatistics - * @since 4.6 - */ - @Nullable - public ReceivedPackStatistics getReceivedPackStatistics() { - return stats; - } - - /** - * Receive a list of commands from the input. - * - * @throws java.io.IOException - */ - protected void recvCommands() throws IOException { - PacketLineIn pck = maxCommandBytes > 0 - ? new PacketLineIn(rawIn, maxCommandBytes) - : pckIn; - PushCertificateParser certParser = getPushCertificateParser(); - boolean firstPkt = true; - try { - for (;;) { - String line; - try { - line = pck.readString(); - } catch (EOFException eof) { - if (commands.isEmpty()) - return; - throw eof; - } - if (PacketLineIn.isEnd(line)) { - break; - } - - if (line.length() >= 48 && line.startsWith("shallow ")) { //$NON-NLS-1$ - parseShallow(line.substring(8, 48)); - continue; - } - - if (firstPkt) { - firstPkt = false; - FirstCommand firstLine = FirstCommand.fromLine(line); - enabledCapabilities = firstLine.getCapabilities(); - line = firstLine.getLine(); - enableCapabilities(); - - if (line.equals(GitProtocolConstants.OPTION_PUSH_CERT)) { - certParser.receiveHeader(pck, !isBiDirectionalPipe()); - continue; - } - } - - if (line.equals(PushCertificateParser.BEGIN_SIGNATURE)) { - certParser.receiveSignature(pck); - continue; - } - - ReceiveCommand cmd = parseCommand(line); - if (cmd.getRefName().equals(Constants.HEAD)) { - cmd.setResult(Result.REJECTED_CURRENT_BRANCH); - } else { - cmd.setRef(refs.get(cmd.getRefName())); - } - commands.add(cmd); - if (certParser.enabled()) { - certParser.addCommand(cmd); - } - } - pushCert = certParser.build(); - if (hasCommands()) { - readPostCommands(pck); - } - } catch (PackProtocolException e) { - discardCommands(); - fatalError(e.getMessage()); - throw e; - } catch (InputOverLimitIOException e) { - String msg = JGitText.get().tooManyCommands; - discardCommands(); - fatalError(msg); - throw new PackProtocolException(msg); - } - } - - private void discardCommands() { - if (sideBand) { - long max = maxDiscardBytes; - if (max < 0) { - max = Math.max(3 * maxCommandBytes, 3L << 20); - } - try { - new PacketLineIn(rawIn, max).discardUntilEnd(); - } catch (IOException e) { - // Ignore read failures attempting to discard. - } - } - } - - private void parseShallow(String idStr) throws PackProtocolException { - ObjectId id; - try { - id = ObjectId.fromString(idStr); - } catch (InvalidObjectIdException e) { - throw new PackProtocolException(e.getMessage(), e); - } - clientShallowCommits.add(id); - } - - static ReceiveCommand parseCommand(String line) throws PackProtocolException { - if (line == null || line.length() < 83) { - throw new PackProtocolException( - JGitText.get().errorInvalidProtocolWantedOldNewRef); - } - String oldStr = line.substring(0, 40); - String newStr = line.substring(41, 81); - ObjectId oldId, newId; - try { - oldId = ObjectId.fromString(oldStr); - newId = ObjectId.fromString(newStr); - } catch (InvalidObjectIdException e) { - throw new PackProtocolException( - JGitText.get().errorInvalidProtocolWantedOldNewRef, e); - } - String name = line.substring(82); - if (!Repository.isValidRefName(name)) { - throw new PackProtocolException( - JGitText.get().errorInvalidProtocolWantedOldNewRef); - } - return new ReceiveCommand(oldId, newId, name); - } - - /** - * @param in - * request stream. - * @throws IOException - * request line cannot be read. - */ - void readPostCommands(PacketLineIn in) throws IOException { - // Do nothing by default. - } - - /** - * Enable capabilities based on a previously read capabilities line. - */ - protected void enableCapabilities() { - sideBand = isCapabilityEnabled(CAPABILITY_SIDE_BAND_64K); - quiet = allowQuiet && isCapabilityEnabled(CAPABILITY_QUIET); - if (sideBand) { - OutputStream out = rawOut; - - rawOut = new SideBandOutputStream(CH_DATA, MAX_BUF, out); - msgOut = new SideBandOutputStream(CH_PROGRESS, MAX_BUF, out); - errOut = new SideBandOutputStream(CH_ERROR, MAX_BUF, out); - - pckOut = new PacketLineOut(rawOut); - pckOut.setFlushOnEnd(false); - } - } - - /** - * Check if the peer requested a capability. - * - * @param name - * protocol name identifying the capability. - * @return true if the peer requested the capability to be enabled. - */ - protected boolean isCapabilityEnabled(String name) { - return enabledCapabilities.contains(name); - } - - void checkRequestWasRead() { - if (enabledCapabilities == null) - throw new RequestNotYetReadException(); - } - - /** - * Whether a pack is expected based on the list of commands. - * - * @return {@code true} if a pack is expected based on the list of commands. - */ - protected boolean needPack() { - for (ReceiveCommand cmd : commands) { - if (cmd.getType() != ReceiveCommand.Type.DELETE) - return true; - } - return false; - } - - /** - * Receive a pack from the input and store it in the repository. - * - * @throws IOException - * an error occurred reading or indexing the pack. - */ - private void receivePack() throws IOException { - // It might take the client a while to pack the objects it needs - // to send to us. We should increase our timeout so we don't - // abort while the client is computing. - // - if (timeoutIn != null) - timeoutIn.setTimeout(10 * timeout * 1000); - - ProgressMonitor receiving = NullProgressMonitor.INSTANCE; - ProgressMonitor resolving = NullProgressMonitor.INSTANCE; - if (sideBand && !quiet) - resolving = new SideBandProgressMonitor(msgOut); - - try (ObjectInserter ins = db.newObjectInserter()) { - String lockMsg = "jgit receive-pack"; //$NON-NLS-1$ - if (getRefLogIdent() != null) - lockMsg += " from " + getRefLogIdent().toExternalString(); //$NON-NLS-1$ - - parser = ins.newPackParser(packInputStream()); - parser.setAllowThin(true); - parser.setNeedNewObjectIds(checkReferencedIsReachable); - parser.setNeedBaseObjectIds(checkReferencedIsReachable); - parser.setCheckEofAfterPackFooter(!biDirectionalPipe - && !isExpectDataAfterPackFooter()); - parser.setExpectDataAfterPackFooter(isExpectDataAfterPackFooter()); - parser.setObjectChecker(objectChecker); - parser.setLockMessage(lockMsg); - parser.setMaxObjectSizeLimit(maxObjectSizeLimit); - packLock = parser.parse(receiving, resolving); - packSize = Long.valueOf(parser.getPackSize()); - stats = parser.getReceivedPackStatistics(); - ins.flush(); - } - - if (timeoutIn != null) - timeoutIn.setTimeout(timeout * 1000); - } - - private InputStream packInputStream() { - InputStream packIn = rawIn; - if (maxPackSizeLimit >= 0) { - packIn = new LimitedInputStream(packIn, maxPackSizeLimit) { - @Override - protected void limitExceeded() throws TooLargePackException { - throw new TooLargePackException(limit); - } - }; - } - return packIn; - } - - private boolean needCheckConnectivity() { - return isCheckReceivedObjects() - || isCheckReferencedObjectsAreReachable() - || !getClientShallowCommits().isEmpty(); - } - - private void checkSubmodules() - throws IOException { - ObjectDatabase odb = db.getObjectDatabase(); - if (objectChecker == null) { - return; - } - for (GitmoduleEntry entry : objectChecker.getGitsubmodules()) { - AnyObjectId blobId = entry.getBlobId(); - ObjectLoader blob = odb.open(blobId, Constants.OBJ_BLOB); - - try { - SubmoduleValidator.assertValidGitModulesFile( - new String(blob.getBytes(), UTF_8)); - } catch (LargeObjectException | SubmoduleValidationException e) { - throw new IOException(e); - } - } - } - - private void checkConnectivity() throws IOException { - ObjectIdSubclassMap<ObjectId> baseObjects = null; - ObjectIdSubclassMap<ObjectId> providedObjects = null; - ProgressMonitor checking = NullProgressMonitor.INSTANCE; - if (sideBand && !quiet) { - SideBandProgressMonitor m = new SideBandProgressMonitor(msgOut); - m.setDelayStart(750, TimeUnit.MILLISECONDS); - checking = m; - } - - if (checkReferencedIsReachable) { - baseObjects = parser.getBaseObjectIds(); - providedObjects = parser.getNewObjectIds(); - } - parser = null; - - try (ObjectWalk ow = new ObjectWalk(db)) { - if (baseObjects != null) { - ow.sort(RevSort.TOPO); - if (!baseObjects.isEmpty()) - ow.sort(RevSort.BOUNDARY, true); - } - - for (ReceiveCommand cmd : commands) { - if (cmd.getResult() != Result.NOT_ATTEMPTED) - continue; - if (cmd.getType() == ReceiveCommand.Type.DELETE) - continue; - ow.markStart(ow.parseAny(cmd.getNewId())); - } - for (ObjectId have : advertisedHaves) { - RevObject o = ow.parseAny(have); - ow.markUninteresting(o); - - if (baseObjects != null && !baseObjects.isEmpty()) { - o = ow.peel(o); - if (o instanceof RevCommit) - o = ((RevCommit) o).getTree(); - if (o instanceof RevTree) - ow.markUninteresting(o); - } - } - - checking.beginTask(JGitText.get().countingObjects, - ProgressMonitor.UNKNOWN); - RevCommit c; - while ((c = ow.next()) != null) { - checking.update(1); - if (providedObjects != null // - && !c.has(RevFlag.UNINTERESTING) // - && !providedObjects.contains(c)) - throw new MissingObjectException(c, Constants.TYPE_COMMIT); - } - - RevObject o; - while ((o = ow.nextObject()) != null) { - checking.update(1); - if (o.has(RevFlag.UNINTERESTING)) - continue; - - if (providedObjects != null) { - if (providedObjects.contains(o)) - continue; - else - throw new MissingObjectException(o, o.getType()); - } - - if (o instanceof RevBlob && !db.getObjectDatabase().has(o)) - throw new MissingObjectException(o, Constants.TYPE_BLOB); - } - checking.endTask(); - - if (baseObjects != null) { - for (ObjectId id : baseObjects) { - o = ow.parseAny(id); - if (!o.has(RevFlag.UNINTERESTING)) - throw new MissingObjectException(o, o.getType()); - } - } - } - } - - /** - * Validate the command list. - */ - protected void validateCommands() { - for (ReceiveCommand cmd : commands) { - final Ref ref = cmd.getRef(); - if (cmd.getResult() != Result.NOT_ATTEMPTED) - continue; - - if (cmd.getType() == ReceiveCommand.Type.DELETE) { - if (!isAllowDeletes()) { - // Deletes are not supported on this repository. - cmd.setResult(Result.REJECTED_NODELETE); - continue; - } - if (!isAllowBranchDeletes() - && ref.getName().startsWith(Constants.R_HEADS)) { - // Branches cannot be deleted, but other refs can. - cmd.setResult(Result.REJECTED_NODELETE); - continue; - } - } - - if (cmd.getType() == ReceiveCommand.Type.CREATE) { - if (!isAllowCreates()) { - cmd.setResult(Result.REJECTED_NOCREATE); - continue; - } - - if (ref != null && !isAllowNonFastForwards()) { - // Creation over an existing ref is certainly not going - // to be a fast-forward update. We can reject it early. - // - cmd.setResult(Result.REJECTED_NONFASTFORWARD); - continue; - } - - if (ref != null) { - // A well behaved client shouldn't have sent us a - // create command for a ref we advertised to it. - // - cmd.setResult(Result.REJECTED_OTHER_REASON, - JGitText.get().refAlreadyExists); - continue; - } - } - - if (cmd.getType() == ReceiveCommand.Type.DELETE && ref != null) { - ObjectId id = ref.getObjectId(); - if (id == null) { - id = ObjectId.zeroId(); - } - if (!ObjectId.zeroId().equals(cmd.getOldId()) - && !id.equals(cmd.getOldId())) { - // Delete commands can be sent with the old id matching our - // advertised value, *OR* with the old id being 0{40}. Any - // other requested old id is invalid. - // - cmd.setResult(Result.REJECTED_OTHER_REASON, - JGitText.get().invalidOldIdSent); - continue; - } - } - - if (cmd.getType() == ReceiveCommand.Type.UPDATE) { - if (ref == null) { - // The ref must have been advertised in order to be updated. - // - cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().noSuchRef); - continue; - } - ObjectId id = ref.getObjectId(); - if (id == null) { - // We cannot update unborn branch - cmd.setResult(Result.REJECTED_OTHER_REASON, - JGitText.get().cannotUpdateUnbornBranch); - continue; - } - - if (!id.equals(cmd.getOldId())) { - // A properly functioning client will send the same - // object id we advertised. - // - cmd.setResult(Result.REJECTED_OTHER_REASON, - JGitText.get().invalidOldIdSent); - continue; - } - - // Is this possibly a non-fast-forward style update? - // - RevObject oldObj, newObj; - try { - oldObj = walk.parseAny(cmd.getOldId()); - } catch (IOException e) { - cmd.setResult(Result.REJECTED_MISSING_OBJECT, cmd - .getOldId().name()); - continue; - } - - try { - newObj = walk.parseAny(cmd.getNewId()); - } catch (IOException e) { - cmd.setResult(Result.REJECTED_MISSING_OBJECT, cmd - .getNewId().name()); - continue; - } - - if (oldObj instanceof RevCommit && newObj instanceof RevCommit) { - try { - if (walk.isMergedInto((RevCommit) oldObj, - (RevCommit) newObj)) - cmd.setTypeFastForwardUpdate(); - else - cmd.setType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD); - } catch (MissingObjectException e) { - cmd.setResult(Result.REJECTED_MISSING_OBJECT, e - .getMessage()); - } catch (IOException e) { - cmd.setResult(Result.REJECTED_OTHER_REASON); - } - } else { - cmd.setType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD); - } - - if (cmd.getType() == ReceiveCommand.Type.UPDATE_NONFASTFORWARD - && !isAllowNonFastForwards()) { - cmd.setResult(Result.REJECTED_NONFASTFORWARD); - continue; - } - } - - if (!cmd.getRefName().startsWith(Constants.R_REFS) - || !Repository.isValidRefName(cmd.getRefName())) { - cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().funnyRefname); - } - } - } - - /** - * Whether any commands have been rejected so far. - * - * @return if any commands have been rejected so far. - * @since 3.6 - */ - protected boolean anyRejects() { - for (ReceiveCommand cmd : commands) { - if (cmd.getResult() != Result.NOT_ATTEMPTED && cmd.getResult() != Result.OK) - return true; - } - return false; - } - - /** - * Set the result to fail for any command that was not processed yet. - * - * @since 3.6 - */ - protected void failPendingCommands() { - ReceiveCommand.abort(commands); - } - - /** - * Filter the list of commands according to result. - * - * @param want - * desired status to filter by. - * @return a copy of the command list containing only those commands with the - * desired status. - */ - protected List<ReceiveCommand> filterCommands(Result want) { - return ReceiveCommand.filter(commands, want); - } - - /** - * Execute commands to update references. - */ - protected void executeCommands() { - List<ReceiveCommand> toApply = filterCommands(Result.NOT_ATTEMPTED); - if (toApply.isEmpty()) - return; - - ProgressMonitor updating = NullProgressMonitor.INSTANCE; - if (sideBand) { - SideBandProgressMonitor pm = new SideBandProgressMonitor(msgOut); - pm.setDelayStart(250, TimeUnit.MILLISECONDS); - updating = pm; - } - - BatchRefUpdate batch = db.getRefDatabase().newBatchUpdate(); - batch.setAllowNonFastForwards(isAllowNonFastForwards()); - batch.setAtomic(isAtomic()); - batch.setRefLogIdent(getRefLogIdent()); - batch.setRefLogMessage("push", true); //$NON-NLS-1$ - batch.addCommand(toApply); - try { - batch.setPushCertificate(getPushCertificate()); - batch.execute(walk, updating); - } catch (IOException err) { - for (ReceiveCommand cmd : toApply) { - if (cmd.getResult() == Result.NOT_ATTEMPTED) - cmd.reject(err); - } - } - } - - /** - * Send a status report. - * - * @param forClient - * true if this report is for a Git client, false if it is for an - * end-user. - * @param unpackError - * an error that occurred during unpacking, or {@code null} - * @param out - * the reporter for sending the status strings. - * @throws java.io.IOException - * an error occurred writing the status report. - */ - protected void sendStatusReport(final boolean forClient, - final Throwable unpackError, final Reporter out) throws IOException { - if (unpackError != null) { - out.sendString("unpack error " + unpackError.getMessage()); //$NON-NLS-1$ - if (forClient) { - for (ReceiveCommand cmd : commands) { - out.sendString("ng " + cmd.getRefName() //$NON-NLS-1$ - + " n/a (unpacker error)"); //$NON-NLS-1$ - } - } - return; - } - - if (forClient) - out.sendString("unpack ok"); //$NON-NLS-1$ - for (ReceiveCommand cmd : commands) { - if (cmd.getResult() == Result.OK) { - if (forClient) - out.sendString("ok " + cmd.getRefName()); //$NON-NLS-1$ - continue; - } - - final StringBuilder r = new StringBuilder(); - if (forClient) - r.append("ng ").append(cmd.getRefName()).append(" "); //$NON-NLS-1$ //$NON-NLS-2$ - else - r.append(" ! [rejected] ").append(cmd.getRefName()).append(" ("); //$NON-NLS-1$ //$NON-NLS-2$ - - switch (cmd.getResult()) { - case NOT_ATTEMPTED: - r.append("server bug; ref not processed"); //$NON-NLS-1$ - break; - - case REJECTED_NOCREATE: - r.append("creation prohibited"); //$NON-NLS-1$ - break; - - case REJECTED_NODELETE: - r.append("deletion prohibited"); //$NON-NLS-1$ - break; - - case REJECTED_NONFASTFORWARD: - r.append("non-fast forward"); //$NON-NLS-1$ - break; - - case REJECTED_CURRENT_BRANCH: - r.append("branch is currently checked out"); //$NON-NLS-1$ - break; - - case REJECTED_MISSING_OBJECT: - if (cmd.getMessage() == null) - r.append("missing object(s)"); //$NON-NLS-1$ - else if (cmd.getMessage().length() == Constants.OBJECT_ID_STRING_LENGTH) { - r.append("object "); //$NON-NLS-1$ - r.append(cmd.getMessage()); - r.append(" missing"); //$NON-NLS-1$ - } else - r.append(cmd.getMessage()); - break; - - case REJECTED_OTHER_REASON: - if (cmd.getMessage() == null) - r.append("unspecified reason"); //$NON-NLS-1$ - else - r.append(cmd.getMessage()); - break; - - case LOCK_FAILURE: - r.append("failed to lock"); //$NON-NLS-1$ - break; - - case OK: - // We shouldn't have reached this case (see 'ok' case above). - continue; - } - if (!forClient) - r.append(")"); //$NON-NLS-1$ - out.sendString(r.toString()); - } - } - - /** - * Close and flush (if necessary) the underlying streams. - * - * @throws java.io.IOException - */ - protected void close() throws IOException { - if (sideBand) { - // If we are using side band, we need to send a final - // flush-pkt to tell the remote peer the side band is - // complete and it should stop decoding. We need to - // use the original output stream as rawOut is now the - // side band data channel. - // - ((SideBandOutputStream) msgOut).flushBuffer(); - ((SideBandOutputStream) rawOut).flushBuffer(); - - PacketLineOut plo = new PacketLineOut(origOut); - plo.setFlushOnEnd(false); - plo.end(); - } - - if (biDirectionalPipe) { - // If this was a native git connection, flush the pipe for - // the caller. For smart HTTP we don't do this flush and - // instead let the higher level HTTP servlet code do it. - // - if (!sideBand && msgOut != null) - msgOut.flush(); - rawOut.flush(); - } - } - - /** - * Release any resources used by this object. - * - * @throws java.io.IOException - * the pack could not be unlocked. - */ - protected void release() throws IOException { - walk.close(); - unlockPack(); - timeoutIn = null; - rawIn = null; - rawOut = null; - msgOut = null; - pckIn = null; - pckOut = null; - refs = null; - // Keep the capabilities. If responses are sent after this release - // we need to remember at least whether sideband communication has to be - // used - commands = null; - if (timer != null) { - try { - timer.terminate(); - } finally { - timer = null; - } - } - } - - /** Interface for reporting status messages. */ - static abstract class Reporter { - abstract void sendString(String s) throws IOException; - } -} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProviderUserInfo.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProviderUserInfo.java index d901021788..6325a23530 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProviderUserInfo.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProviderUserInfo.java @@ -107,10 +107,9 @@ public class CredentialsProviderUserInfo implements UserInfo, if (provider.get(uri, v)) { passphrase = v.getValue(); return true; - } else { - passphrase = null; - return false; } + passphrase = null; + return false; } /** {@inheritDoc} */ @@ -120,10 +119,9 @@ public class CredentialsProviderUserInfo implements UserInfo, if (provider.get(uri, p)) { password = new String(p.getValue()); return true; - } else { - password = null; - return false; } + password = null; + return false; } private CredentialItem.StringType newPrompt(String msg) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java index 01f6fec7e4..72e95e6ba3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HMACSHA1NonceGenerator.java @@ -135,9 +135,8 @@ public class HMACSHA1NonceGenerator implements NonceGenerator { if (nonceStampSlop <= slop) { return NonceStatus.OK; - } else { - return NonceStatus.SLOP; } + return NonceStatus.SLOP; } private static final String HEX = "0123456789ABCDEF"; //$NON-NLS-1$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java index 14ccddfb61..c2f69e20be 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java @@ -215,7 +215,7 @@ final class ProtocolV2Parser { && line2.equals(OPTION_SIDEBAND_ALL)) { reqBuilder.setSidebandAll(true); } else if (line2.startsWith("packfile-uris ")) { //$NON-NLS-1$ - for (String s : line2.substring(14).split(",")) { + for (String s : line2.substring(14).split(",")) { //$NON-NLS-1$ reqBuilder.addPackfileUriProtocol(s); } } else { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java index 89c1a93788..3653879c7d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java @@ -43,7 +43,7 @@ package org.eclipse.jgit.transport; -import static org.eclipse.jgit.transport.BaseReceivePack.parseCommand; +import static org.eclipse.jgit.transport.ReceivePack.parseCommand; import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_CERT; import java.io.EOFException; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java index a9a995cd3f..0616b64d27 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java @@ -65,7 +65,7 @@ import org.eclipse.jgit.revwalk.RevWalk; /** * A command being processed by - * {@link org.eclipse.jgit.transport.BaseReceivePack}. + * {@link org.eclipse.jgit.transport.ReceivePack}. * <p> * This command instance roughly translates to the server side representation of * the {@link org.eclipse.jgit.transport.RemoteRefUpdate} created by the client. @@ -290,7 +290,7 @@ public class ReceiveCommand { /** * Create a new command for - * {@link org.eclipse.jgit.transport.BaseReceivePack}. + * {@link org.eclipse.jgit.transport.ReceivePack}. * * @param oldId * the expected old object id; must not be null. Use @@ -334,7 +334,7 @@ public class ReceiveCommand { /** * Create a new command for - * {@link org.eclipse.jgit.transport.BaseReceivePack}. + * {@link org.eclipse.jgit.transport.ReceivePack}. * * @param oldId * the old object id; must not be null. Use @@ -768,9 +768,9 @@ public class ReceiveCommand { * * @param rp * receive-pack session. - * @since 2.0 + * @since 5.6 */ - public void execute(BaseReceivePack rp) { + public void execute(ReceivePack rp) { try { String expTarget = getOldSymref(); boolean detach = getNewSymref() != null diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java index d6adf1e0d8..16fbbd42f3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java @@ -43,36 +43,255 @@ package org.eclipse.jgit.transport; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.eclipse.jgit.lib.Constants.HEAD; import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC; +import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_DELETE_REFS; +import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_OFS_DELTA; import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_OPTIONS; +import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_QUIET; import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS; +import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SIDE_BAND_64K; +import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT; +import static org.eclipse.jgit.transport.SideBandOutputStream.CH_DATA; +import static org.eclipse.jgit.transport.SideBandOutputStream.CH_ERROR; +import static org.eclipse.jgit.transport.SideBandOutputStream.CH_PROGRESS; +import static org.eclipse.jgit.transport.SideBandOutputStream.MAX_BUF; +import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.errors.InvalidObjectIdException; +import org.eclipse.jgit.errors.LargeObjectException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.errors.PackProtocolException; +import org.eclipse.jgit.errors.TooLargePackException; import org.eclipse.jgit.errors.UnpackException; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.internal.storage.file.PackLock; +import org.eclipse.jgit.internal.submodule.SubmoduleValidator; +import org.eclipse.jgit.internal.submodule.SubmoduleValidator.SubmoduleValidationException; +import org.eclipse.jgit.internal.transport.parser.FirstCommand; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.BatchRefUpdate; +import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.GitmoduleEntry; import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectChecker; +import org.eclipse.jgit.lib.ObjectDatabase; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdSubclassMap; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.ObjectLoader; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.ObjectWalk; +import org.eclipse.jgit.revwalk.RevBlob; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevFlag; +import org.eclipse.jgit.revwalk.RevObject; +import org.eclipse.jgit.revwalk.RevSort; +import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.PacketLineIn.InputOverLimitIOException; import org.eclipse.jgit.transport.ReceiveCommand.Result; import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser; +import org.eclipse.jgit.util.io.InterruptTimer; +import org.eclipse.jgit.util.io.LimitedInputStream; +import org.eclipse.jgit.util.io.TimeoutInputStream; +import org.eclipse.jgit.util.io.TimeoutOutputStream; /** * Implements the server side of a push connection, receiving objects. */ -public class ReceivePack extends BaseReceivePack { +public class ReceivePack { + /** + * Data in the first line of a request, the line itself plus capabilities. + * + * @deprecated Use {@link FirstCommand} instead. + * @since 5.6 + */ + @Deprecated + public static class FirstLine { + private final FirstCommand command; + + /** + * Parse the first line of a receive-pack request. + * + * @param line + * line from the client. + */ + public FirstLine(String line) { + command = FirstCommand.fromLine(line); + } + + /** @return non-capabilities part of the line. */ + public String getLine() { + return command.getLine(); + } + + /** @return capabilities parsed from the line. */ + public Set<String> getCapabilities() { + return command.getCapabilities(); + } + } + + /** Database we write the stored objects into. */ + private final Repository db; + + /** Revision traversal support over {@link #db}. */ + private final RevWalk walk; + + /** + * Is the client connection a bi-directional socket or pipe? + * <p> + * If true, this class assumes it can perform multiple read and write cycles + * with the client over the input and output streams. This matches the + * functionality available with a standard TCP/IP connection, or a local + * operating system or in-memory pipe. + * <p> + * If false, this class runs in a read everything then output results mode, + * making it suitable for single round-trip systems RPCs such as HTTP. + */ + private boolean biDirectionalPipe = true; + + /** Expecting data after the pack footer */ + private boolean expectDataAfterPackFooter; + + /** Should an incoming transfer validate objects? */ + private ObjectChecker objectChecker; + + /** Should an incoming transfer permit create requests? */ + private boolean allowCreates; + + /** Should an incoming transfer permit delete requests? */ + private boolean allowAnyDeletes; + + private boolean allowBranchDeletes; + + /** Should an incoming transfer permit non-fast-forward requests? */ + private boolean allowNonFastForwards; + + /** Should an incoming transfer permit push options? **/ + private boolean allowPushOptions; + + /** + * Should the requested ref updates be performed as a single atomic + * transaction? + */ + private boolean atomic; + + private boolean allowOfsDelta; + + private boolean allowQuiet = true; + + /** Identity to record action as within the reflog. */ + private PersonIdent refLogIdent; + + /** Hook used while advertising the refs to the client. */ + private AdvertiseRefsHook advertiseRefsHook; + + /** Filter used while advertising the refs to the client. */ + private RefFilter refFilter; + + /** Timeout in seconds to wait for client interaction. */ + private int timeout; + + /** Timer to manage {@link #timeout}. */ + private InterruptTimer timer; + + private TimeoutInputStream timeoutIn; + + // Original stream passed to init(), since rawOut may be wrapped in a + // sideband. + private OutputStream origOut; + + /** Raw input stream. */ + private InputStream rawIn; + + /** Raw output stream. */ + private OutputStream rawOut; + + /** Optional message output stream. */ + private OutputStream msgOut; + + private SideBandOutputStream errOut; + + /** Packet line input stream around {@link #rawIn}. */ + private PacketLineIn pckIn; + + /** Packet line output stream around {@link #rawOut}. */ + private PacketLineOut pckOut; + + private final MessageOutputWrapper msgOutWrapper = new MessageOutputWrapper(); + + private PackParser parser; + + /** The refs we advertised as existing at the start of the connection. */ + private Map<String, Ref> refs; + + /** All SHA-1s shown to the client, which can be possible edges. */ + private Set<ObjectId> advertisedHaves; + + /** Capabilities requested by the client. */ + private Set<String> enabledCapabilities; + + String userAgent; + + private Set<ObjectId> clientShallowCommits; + + private List<ReceiveCommand> commands; + + private long maxCommandBytes; + + private long maxDiscardBytes; + + private StringBuilder advertiseError; + + /** + * If {@link BasePackPushConnection#CAPABILITY_SIDE_BAND_64K} is enabled. + */ + private boolean sideBand; + + private boolean quiet; + + /** Lock around the received pack file, while updating refs. */ + private PackLock packLock; + + private boolean checkReferencedIsReachable; + + /** Git object size limit */ + private long maxObjectSizeLimit; + + /** Total pack size limit */ + private long maxPackSizeLimit = -1; + + /** The size of the received pack, including index size */ + private Long packSize; + + private PushCertificateParser pushCertificateParser; + + private SignedPushConfig signedPushConfig; + + private PushCertificate pushCert; + + private ReceivedPackStatistics stats; + /** Hook to validate the update commands before execution. */ private PreReceiveHook preReceive; @@ -93,18 +312,120 @@ public class ReceivePack extends BaseReceivePack { * the destination repository. */ public ReceivePack(Repository into) { - super(into); + db = into; + walk = new RevWalk(db); + walk.setRetainBody(false); + + TransferConfig tc = db.getConfig().get(TransferConfig.KEY); + objectChecker = tc.newReceiveObjectChecker(); + + ReceiveConfig rc = db.getConfig().get(ReceiveConfig::new); + allowCreates = rc.allowCreates; + allowAnyDeletes = true; + allowBranchDeletes = rc.allowDeletes; + allowNonFastForwards = rc.allowNonFastForwards; + allowOfsDelta = rc.allowOfsDelta; + allowPushOptions = rc.allowPushOptions; + maxCommandBytes = rc.maxCommandBytes; + maxDiscardBytes = rc.maxDiscardBytes; + advertiseRefsHook = AdvertiseRefsHook.DEFAULT; + refFilter = RefFilter.DEFAULT; + advertisedHaves = new HashSet<>(); + clientShallowCommits = new HashSet<>(); + signedPushConfig = rc.signedPush; preReceive = PreReceiveHook.NULL; postReceive = PostReceiveHook.NULL; } + /** Configuration for receive operations. */ + private static class ReceiveConfig { + final boolean allowCreates; + + final boolean allowDeletes; + + final boolean allowNonFastForwards; + + final boolean allowOfsDelta; + + final boolean allowPushOptions; + + final long maxCommandBytes; + + final long maxDiscardBytes; + + final SignedPushConfig signedPush; + + ReceiveConfig(Config config) { + allowCreates = true; + allowDeletes = !config.getBoolean("receive", "denydeletes", false); //$NON-NLS-1$ //$NON-NLS-2$ + allowNonFastForwards = !config.getBoolean("receive", //$NON-NLS-1$ + "denynonfastforwards", false); //$NON-NLS-1$ + allowOfsDelta = config.getBoolean("repack", "usedeltabaseoffset", //$NON-NLS-1$ //$NON-NLS-2$ + true); + allowPushOptions = config.getBoolean("receive", "pushoptions", //$NON-NLS-1$ //$NON-NLS-2$ + false); + maxCommandBytes = config.getLong("receive", //$NON-NLS-1$ + "maxCommandBytes", //$NON-NLS-1$ + 3 << 20); + maxDiscardBytes = config.getLong("receive", //$NON-NLS-1$ + "maxCommandDiscardBytes", //$NON-NLS-1$ + -1); + signedPush = SignedPushConfig.KEY.parse(config); + } + } + + /** + * Output stream that wraps the current {@link #msgOut}. + * <p> + * We don't want to expose {@link #msgOut} directly because it can change + * several times over the course of a session. + */ + class MessageOutputWrapper extends OutputStream { + @Override + public void write(int ch) { + if (msgOut != null) { + try { + msgOut.write(ch); + } catch (IOException e) { + // Ignore write failures. + } + } + } + + @Override + public void write(byte[] b, int off, int len) { + if (msgOut != null) { + try { + msgOut.write(b, off, len); + } catch (IOException e) { + // Ignore write failures. + } + } + } + + @Override + public void write(byte[] b) { + write(b, 0, b.length); + } + + @Override + public void flush() { + if (msgOut != null) { + try { + msgOut.flush(); + } catch (IOException e) { + // Ignore write failures. + } + } + } + } + /** * Get the repository this receive completes into. * * @return the repository this receive completes into. */ - @Override - public final Repository getRepository() { + public Repository getRepository() { return db; } @@ -113,8 +434,7 @@ public class ReceivePack extends BaseReceivePack { * * @return the RevWalk instance used by this connection. */ - @Override - public final RevWalk getRevWalk() { + public RevWalk getRevWalk() { return walk; } @@ -124,8 +444,7 @@ public class ReceivePack extends BaseReceivePack { * @return all refs which were advertised to the client, or null if * {@link #setAdvertisedRefs(Map, Set)} has not been called yet. */ - @Override - public final Map<String, Ref> getAdvertisedRefs() { + public Map<String, Ref> getAdvertisedRefs() { return refs; } @@ -146,8 +465,8 @@ public class ReceivePack extends BaseReceivePack { * null, assumes the default set of additional haves from the * repository. */ - @Override - public void setAdvertisedRefs(Map<String, Ref> allRefs, Set<ObjectId> additionalHaves) { + public void setAdvertisedRefs(Map<String, Ref> allRefs, + Set<ObjectId> additionalHaves) { refs = allRefs != null ? allRefs : db.getAllRefs(); refs = refFilter.filter(refs); advertisedHaves.clear(); @@ -170,6 +489,1525 @@ public class ReceivePack extends BaseReceivePack { } /** + * Get objects advertised to the client. + * + * @return the set of objects advertised to the as present in this + * repository, or null if {@link #setAdvertisedRefs(Map, Set)} has + * not been called yet. + */ + public final Set<ObjectId> getAdvertisedObjects() { + return advertisedHaves; + } + + /** + * Whether this instance will validate all referenced, but not supplied by + * the client, objects are reachable from another reference. + * + * @return true if this instance will validate all referenced, but not + * supplied by the client, objects are reachable from another + * reference. + */ + public boolean isCheckReferencedObjectsAreReachable() { + return checkReferencedIsReachable; + } + + /** + * Validate all referenced but not supplied objects are reachable. + * <p> + * If enabled, this instance will verify that references to objects not + * contained within the received pack are already reachable through at least + * one other reference displayed as part of {@link #getAdvertisedRefs()}. + * <p> + * This feature is useful when the application doesn't trust the client to + * not provide a forged SHA-1 reference to an object, in an attempt to + * access parts of the DAG that they aren't allowed to see and which have + * been hidden from them via the configured + * {@link org.eclipse.jgit.transport.AdvertiseRefsHook} or + * {@link org.eclipse.jgit.transport.RefFilter}. + * <p> + * Enabling this feature may imply at least some, if not all, of the same + * functionality performed by {@link #setCheckReceivedObjects(boolean)}. + * Applications are encouraged to enable both features, if desired. + * + * @param b + * {@code true} to enable the additional check. + */ + public void setCheckReferencedObjectsAreReachable(boolean b) { + this.checkReferencedIsReachable = b; + } + + /** + * Whether this class expects a bi-directional pipe opened between the + * client and itself. + * + * @return true if this class expects a bi-directional pipe opened between + * the client and itself. The default is true. + */ + public boolean isBiDirectionalPipe() { + return biDirectionalPipe; + } + + /** + * Whether this class will assume the socket is a fully bidirectional pipe + * between the two peers and takes advantage of that by first transmitting + * the known refs, then waiting to read commands. + * + * @param twoWay + * if true, this class will assume the socket is a fully + * bidirectional pipe between the two peers and takes advantage + * of that by first transmitting the known refs, then waiting to + * read commands. If false, this class assumes it must read the + * commands before writing output and does not perform the + * initial advertising. + */ + public void setBiDirectionalPipe(boolean twoWay) { + biDirectionalPipe = twoWay; + } + + /** + * Whether there is data expected after the pack footer. + * + * @return {@code true} if there is data expected after the pack footer. + */ + public boolean isExpectDataAfterPackFooter() { + return expectDataAfterPackFooter; + } + + /** + * Whether there is additional data in InputStream after pack. + * + * @param e + * {@code true} if there is additional data in InputStream after + * pack. + */ + public void setExpectDataAfterPackFooter(boolean e) { + expectDataAfterPackFooter = e; + } + + /** + * Whether this instance will verify received objects are formatted + * correctly. + * + * @return {@code true} if this instance will verify received objects are + * formatted correctly. Validating objects requires more CPU time on + * this side of the connection. + */ + public boolean isCheckReceivedObjects() { + return objectChecker != null; + } + + /** + * Whether to enable checking received objects + * + * @param check + * {@code true} to enable checking received objects; false to + * assume all received objects are valid. + * @see #setObjectChecker(ObjectChecker) + */ + public void setCheckReceivedObjects(boolean check) { + if (check && objectChecker == null) + setObjectChecker(new ObjectChecker()); + else if (!check && objectChecker != null) + setObjectChecker(null); + } + + /** + * Set the object checking instance to verify each received object with + * + * @param impl + * if non-null the object checking instance to verify each + * received object with; null to disable object checking. + * @since 3.4 + */ + public void setObjectChecker(ObjectChecker impl) { + objectChecker = impl; + } + + /** + * Whether the client can request refs to be created. + * + * @return {@code true} if the client can request refs to be created. + */ + public boolean isAllowCreates() { + return allowCreates; + } + + /** + * Whether to permit create ref commands to be processed. + * + * @param canCreate + * {@code true} to permit create ref commands to be processed. + */ + public void setAllowCreates(boolean canCreate) { + allowCreates = canCreate; + } + + /** + * Whether the client can request refs to be deleted. + * + * @return {@code true} if the client can request refs to be deleted. + */ + public boolean isAllowDeletes() { + return allowAnyDeletes; + } + + /** + * Whether to permit delete ref commands to be processed. + * + * @param canDelete + * {@code true} to permit delete ref commands to be processed. + */ + public void setAllowDeletes(boolean canDelete) { + allowAnyDeletes = canDelete; + } + + /** + * Whether the client can delete from {@code refs/heads/}. + * + * @return {@code true} if the client can delete from {@code refs/heads/}. + * @since 3.6 + */ + public boolean isAllowBranchDeletes() { + return allowBranchDeletes; + } + + /** + * Configure whether to permit deletion of branches from the + * {@code refs/heads/} namespace. + * + * @param canDelete + * {@code true} to permit deletion of branches from the + * {@code refs/heads/} namespace. + * @since 3.6 + */ + public void setAllowBranchDeletes(boolean canDelete) { + allowBranchDeletes = canDelete; + } + + /** + * Whether the client can request non-fast-forward updates of a ref, + * possibly making objects unreachable. + * + * @return {@code true} if the client can request non-fast-forward updates + * of a ref, possibly making objects unreachable. + */ + public boolean isAllowNonFastForwards() { + return allowNonFastForwards; + } + + /** + * Configure whether to permit the client to ask for non-fast-forward + * updates of an existing ref. + * + * @param canRewind + * {@code true} to permit the client to ask for non-fast-forward + * updates of an existing ref. + */ + public void setAllowNonFastForwards(boolean canRewind) { + allowNonFastForwards = canRewind; + } + + /** + * Whether the client's commands should be performed as a single atomic + * transaction. + * + * @return {@code true} if the client's commands should be performed as a + * single atomic transaction. + * @since 4.4 + */ + public boolean isAtomic() { + return atomic; + } + + /** + * Configure whether to perform the client's commands as a single atomic + * transaction. + * + * @param atomic + * {@code true} to perform the client's commands as a single + * atomic transaction. + * @since 4.4 + */ + public void setAtomic(boolean atomic) { + this.atomic = atomic; + } + + /** + * Get identity of the user making the changes in the reflog. + * + * @return identity of the user making the changes in the reflog. + */ + public PersonIdent getRefLogIdent() { + return refLogIdent; + } + + /** + * Set the identity of the user appearing in the affected reflogs. + * <p> + * The timestamp portion of the identity is ignored. A new identity with the + * current timestamp will be created automatically when the updates occur + * and the log records are written. + * + * @param pi + * identity of the user. If null the identity will be + * automatically determined based on the repository + * configuration. + */ + public void setRefLogIdent(PersonIdent pi) { + refLogIdent = pi; + } + + /** + * Get the hook used while advertising the refs to the client + * + * @return the hook used while advertising the refs to the client + */ + public AdvertiseRefsHook getAdvertiseRefsHook() { + return advertiseRefsHook; + } + + /** + * Get the filter used while advertising the refs to the client + * + * @return the filter used while advertising the refs to the client + */ + public RefFilter getRefFilter() { + return refFilter; + } + + /** + * Set the hook used while advertising the refs to the client. + * <p> + * If the {@link org.eclipse.jgit.transport.AdvertiseRefsHook} chooses to + * call {@link #setAdvertisedRefs(Map,Set)}, only refs set by this hook + * <em>and</em> selected by the {@link org.eclipse.jgit.transport.RefFilter} + * will be shown to the client. Clients may still attempt to create or + * update a reference not advertised by the configured + * {@link org.eclipse.jgit.transport.AdvertiseRefsHook}. These attempts + * should be rejected by a matching + * {@link org.eclipse.jgit.transport.PreReceiveHook}. + * + * @param advertiseRefsHook + * the hook; may be null to show all refs. + */ + public void setAdvertiseRefsHook(AdvertiseRefsHook advertiseRefsHook) { + if (advertiseRefsHook != null) + this.advertiseRefsHook = advertiseRefsHook; + else + this.advertiseRefsHook = AdvertiseRefsHook.DEFAULT; + } + + /** + * Set the filter used while advertising the refs to the client. + * <p> + * Only refs allowed by this filter will be shown to the client. The filter + * is run against the refs specified by the + * {@link org.eclipse.jgit.transport.AdvertiseRefsHook} (if applicable). + * + * @param refFilter + * the filter; may be null to show all refs. + */ + public void setRefFilter(RefFilter refFilter) { + this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT; + } + + /** + * Get timeout (in seconds) before aborting an IO operation. + * + * @return timeout (in seconds) before aborting an IO operation. + */ + public int getTimeout() { + return timeout; + } + + /** + * Set the timeout before willing to abort an IO call. + * + * @param seconds + * number of seconds to wait (with no data transfer occurring) + * before aborting an IO read or write operation with the + * connected client. + */ + public void setTimeout(int seconds) { + timeout = seconds; + } + + /** + * Set the maximum number of command bytes to read from the client. + * + * @param limit + * command limit in bytes; if 0 there is no limit. + * @since 4.7 + */ + public void setMaxCommandBytes(long limit) { + maxCommandBytes = limit; + } + + /** + * Set the maximum number of command bytes to discard from the client. + * <p> + * Discarding remaining bytes allows this instance to consume the rest of + * the command block and send a human readable over-limit error via the + * side-band channel. If the client sends an excessive number of bytes this + * limit kicks in and the instance disconnects, resulting in a non-specific + * 'pipe closed', 'end of stream', or similar generic error at the client. + * <p> + * When the limit is set to {@code -1} the implementation will default to + * the larger of {@code 3 * maxCommandBytes} or {@code 3 MiB}. + * + * @param limit + * discard limit in bytes; if 0 there is no limit; if -1 the + * implementation tries to set a reasonable default. + * @since 4.7 + */ + public void setMaxCommandDiscardBytes(long limit) { + maxDiscardBytes = limit; + } + + /** + * Set the maximum allowed Git object size. + * <p> + * If an object is larger than the given size the pack-parsing will throw an + * exception aborting the receive-pack operation. + * + * @param limit + * the Git object size limit. If zero then there is not limit. + */ + public void setMaxObjectSizeLimit(long limit) { + maxObjectSizeLimit = limit; + } + + /** + * Set the maximum allowed pack size. + * <p> + * A pack exceeding this size will be rejected. + * + * @param limit + * the pack size limit, in bytes + * @since 3.3 + */ + public void setMaxPackSizeLimit(long limit) { + if (limit < 0) + throw new IllegalArgumentException( + MessageFormat.format(JGitText.get().receivePackInvalidLimit, + Long.valueOf(limit))); + maxPackSizeLimit = limit; + } + + /** + * Check whether the client expects a side-band stream. + * + * @return true if the client has advertised a side-band capability, false + * otherwise. + * @throws org.eclipse.jgit.transport.RequestNotYetReadException + * if the client's request has not yet been read from the wire, + * so we do not know if they expect side-band. Note that the + * client may have already written the request, it just has not + * been read. + */ + public boolean isSideBand() throws RequestNotYetReadException { + checkRequestWasRead(); + return enabledCapabilities.contains(CAPABILITY_SIDE_BAND_64K); + } + + /** + * Whether clients may request avoiding noisy progress messages. + * + * @return true if clients may request avoiding noisy progress messages. + * @since 4.0 + */ + public boolean isAllowQuiet() { + return allowQuiet; + } + + /** + * Configure if clients may request the server skip noisy messages. + * + * @param allow + * true to allow clients to request quiet behavior; false to + * refuse quiet behavior and send messages anyway. This may be + * necessary if processing is slow and the client-server network + * connection can timeout. + * @since 4.0 + */ + public void setAllowQuiet(boolean allow) { + allowQuiet = allow; + } + + /** + * Whether the server supports receiving push options. + * + * @return true if the server supports receiving push options. + * @since 4.5 + */ + public boolean isAllowPushOptions() { + return allowPushOptions; + } + + /** + * Configure if the server supports receiving push options. + * + * @param allow + * true to optionally accept option strings from the client. + * @since 4.5 + */ + public void setAllowPushOptions(boolean allow) { + allowPushOptions = allow; + } + + /** + * True if the client wants less verbose output. + * + * @return true if the client has requested the server to be less verbose. + * @throws org.eclipse.jgit.transport.RequestNotYetReadException + * if the client's request has not yet been read from the wire, + * so we do not know if they expect side-band. Note that the + * client may have already written the request, it just has not + * been read. + * @since 4.0 + */ + public boolean isQuiet() throws RequestNotYetReadException { + checkRequestWasRead(); + return quiet; + } + + /** + * Set the configuration for push certificate verification. + * + * @param cfg + * new configuration; if this object is null or its + * {@link SignedPushConfig#getCertNonceSeed()} is null, push + * certificate verification will be disabled. + * @since 4.1 + */ + public void setSignedPushConfig(SignedPushConfig cfg) { + signedPushConfig = cfg; + } + + private PushCertificateParser getPushCertificateParser() { + if (pushCertificateParser == null) { + pushCertificateParser = new PushCertificateParser(db, + signedPushConfig); + } + return pushCertificateParser; + } + + /** + * Get the user agent of the client. + * <p> + * If the client is new enough to use {@code agent=} capability that value + * will be returned. Older HTTP clients may also supply their version using + * the HTTP {@code User-Agent} header. The capability overrides the HTTP + * header if both are available. + * <p> + * When an HTTP request has been received this method returns the HTTP + * {@code User-Agent} header value until capabilities have been parsed. + * + * @return user agent supplied by the client. Available only if the client + * is new enough to advertise its user agent. + * @since 4.0 + */ + public String getPeerUserAgent() { + return UserAgent.getAgent(enabledCapabilities, userAgent); + } + + /** + * Get all of the command received by the current request. + * + * @return all of the command received by the current request. + */ + public List<ReceiveCommand> getAllCommands() { + return Collections.unmodifiableList(commands); + } + + /** + * Send an error message to the client. + * <p> + * If any error messages are sent before the references are advertised to + * the client, the errors will be sent instead of the advertisement and the + * receive operation will be aborted. All clients should receive and display + * such early stage errors. + * <p> + * If the reference advertisements have already been sent, messages are sent + * in a side channel. If the client doesn't support receiving messages, the + * message will be discarded, with no other indication to the caller or to + * the client. + * <p> + * {@link org.eclipse.jgit.transport.PreReceiveHook}s should always try to + * use + * {@link org.eclipse.jgit.transport.ReceiveCommand#setResult(Result, String)} + * with a result status of + * {@link org.eclipse.jgit.transport.ReceiveCommand.Result#REJECTED_OTHER_REASON} + * to indicate any reasons for rejecting an update. Messages attached to a + * command are much more likely to be returned to the client. + * + * @param what + * string describing the problem identified by the hook. The + * string must not end with an LF, and must not contain an LF. + */ + public void sendError(String what) { + if (refs == null) { + if (advertiseError == null) + advertiseError = new StringBuilder(); + advertiseError.append(what).append('\n'); + } else { + msgOutWrapper.write(Constants.encode("error: " + what + "\n")); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + private void fatalError(String msg) { + if (errOut != null) { + try { + errOut.write(Constants.encode(msg)); + errOut.flush(); + } catch (IOException e) { + // Ignore write failures + } + } else { + sendError(msg); + } + } + + /** + * Send a message to the client, if it supports receiving them. + * <p> + * If the client doesn't support receiving messages, the message will be + * discarded, with no other indication to the caller or to the client. + * + * @param what + * string describing the problem identified by the hook. The + * string must not end with an LF, and must not contain an LF. + */ + public void sendMessage(String what) { + msgOutWrapper.write(Constants.encode(what + "\n")); //$NON-NLS-1$ + } + + /** + * Get an underlying stream for sending messages to the client. + * + * @return an underlying stream for sending messages to the client. + */ + public OutputStream getMessageOutputStream() { + return msgOutWrapper; + } + + /** + * Get whether or not a pack has been received. + * + * This can be called before calling {@link #getPackSize()} to avoid causing + * {@code IllegalStateException} when the pack size was not set because no + * pack was received. + * + * @return true if a pack has been received. + * @since 5.6 + */ + public boolean hasReceivedPack() { + return packSize != null; + } + + /** + * Get the size of the received pack file including the index size. + * + * This can only be called if the pack is already received. + * + * @return the size of the received pack including index size + * @throws java.lang.IllegalStateException + * if called before the pack has been received + * @since 3.3 + */ + public long getPackSize() { + if (packSize != null) + return packSize.longValue(); + throw new IllegalStateException(JGitText.get().packSizeNotSetYet); + } + + /** + * Get the commits from the client's shallow file. + * + * @return if the client is a shallow repository, the list of edge commits + * that define the client's shallow boundary. Empty set if the + * client is earlier than Git 1.9, or is a full clone. + */ + private Set<ObjectId> getClientShallowCommits() { + return clientShallowCommits; + } + + /** + * Whether any commands to be executed have been read. + * + * @return {@code true} if any commands to be executed have been read. + */ + private boolean hasCommands() { + return !commands.isEmpty(); + } + + /** + * Whether an error occurred that should be advertised. + * + * @return true if an error occurred that should be advertised. + */ + private boolean hasError() { + return advertiseError != null; + } + + /** + * Initialize the instance with the given streams. + * + * Visible for out-of-tree subclasses (e.g. tests that need to set the + * streams without going through the {@link #service()} method). + * + * @param input + * raw input to read client commands and pack data from. Caller + * must ensure the input is buffered, otherwise read performance + * may suffer. + * @param output + * response back to the Git network client. Caller must ensure + * the output is buffered, otherwise write performance may + * suffer. + * @param messages + * secondary "notice" channel to send additional messages out + * through. When run over SSH this should be tied back to the + * standard error channel of the command execution. For most + * other network connections this should be null. + */ + protected void init(final InputStream input, final OutputStream output, + final OutputStream messages) { + origOut = output; + rawIn = input; + rawOut = output; + msgOut = messages; + + if (timeout > 0) { + final Thread caller = Thread.currentThread(); + timer = new InterruptTimer(caller.getName() + "-Timer"); //$NON-NLS-1$ + timeoutIn = new TimeoutInputStream(rawIn, timer); + TimeoutOutputStream o = new TimeoutOutputStream(rawOut, timer); + timeoutIn.setTimeout(timeout * 1000); + o.setTimeout(timeout * 1000); + rawIn = timeoutIn; + rawOut = o; + } + + pckIn = new PacketLineIn(rawIn); + pckOut = new PacketLineOut(rawOut); + pckOut.setFlushOnEnd(false); + + enabledCapabilities = new HashSet<>(); + commands = new ArrayList<>(); + } + + /** + * Get advertised refs, or the default if not explicitly advertised. + * + * @return advertised refs, or the default if not explicitly advertised. + */ + private Map<String, Ref> getAdvertisedOrDefaultRefs() { + if (refs == null) + setAdvertisedRefs(null, null); + return refs; + } + + /** + * Receive a pack from the stream and check connectivity if necessary. + * + * Visible for out-of-tree subclasses. Subclasses overriding this method + * should invoke this implementation, as it alters the instance state (e.g. + * it reads the pack from the input and parses it before running the + * connectivity checks). + * + * @throws java.io.IOException + * an error occurred during unpacking or connectivity checking. + */ + protected void receivePackAndCheckConnectivity() throws IOException { + receivePack(); + if (needCheckConnectivity()) { + checkSubmodules(); + checkConnectivity(); + } + parser = null; + } + + /** + * Unlock the pack written by this object. + * + * @throws java.io.IOException + * the pack could not be unlocked. + */ + private void unlockPack() throws IOException { + if (packLock != null) { + packLock.unlock(); + packLock = null; + } + } + + /** + * Generate an advertisement of available refs and capabilities. + * + * @param adv + * the advertisement formatter. + * @throws java.io.IOException + * the formatter failed to write an advertisement. + * @throws org.eclipse.jgit.transport.ServiceMayNotContinueException + * the hook denied advertisement. + */ + public void sendAdvertisedRefs(RefAdvertiser adv) + throws IOException, ServiceMayNotContinueException { + if (advertiseError != null) { + adv.writeOne("ERR " + advertiseError); //$NON-NLS-1$ + return; + } + + try { + advertiseRefsHook.advertiseRefs(this); + } catch (ServiceMayNotContinueException fail) { + if (fail.getMessage() != null) { + adv.writeOne("ERR " + fail.getMessage()); //$NON-NLS-1$ + fail.setOutput(); + } + throw fail; + } + + adv.init(db); + adv.advertiseCapability(CAPABILITY_SIDE_BAND_64K); + adv.advertiseCapability(CAPABILITY_DELETE_REFS); + adv.advertiseCapability(CAPABILITY_REPORT_STATUS); + if (allowQuiet) + adv.advertiseCapability(CAPABILITY_QUIET); + String nonce = getPushCertificateParser().getAdvertiseNonce(); + if (nonce != null) { + adv.advertiseCapability(nonce); + } + if (db.getRefDatabase().performsAtomicTransactions()) + adv.advertiseCapability(CAPABILITY_ATOMIC); + if (allowOfsDelta) + adv.advertiseCapability(CAPABILITY_OFS_DELTA); + if (allowPushOptions) { + adv.advertiseCapability(CAPABILITY_PUSH_OPTIONS); + } + adv.advertiseCapability(OPTION_AGENT, UserAgent.get()); + adv.send(getAdvertisedOrDefaultRefs().values()); + for (ObjectId obj : advertisedHaves) + adv.advertiseHave(obj); + if (adv.isEmpty()) + adv.advertiseId(ObjectId.zeroId(), "capabilities^{}"); //$NON-NLS-1$ + adv.end(); + } + + /** + * Returns the statistics on the received pack if available. This should be + * called after {@link #receivePack} is called. + * + * @return ReceivedPackStatistics + * @since 4.6 + */ + @Nullable + public ReceivedPackStatistics getReceivedPackStatistics() { + return stats; + } + + /** + * Receive a list of commands from the input. + * + * @throws java.io.IOException + */ + private void recvCommands() throws IOException { + PacketLineIn pck = maxCommandBytes > 0 + ? new PacketLineIn(rawIn, maxCommandBytes) + : pckIn; + PushCertificateParser certParser = getPushCertificateParser(); + boolean firstPkt = true; + try { + for (;;) { + String line; + try { + line = pck.readString(); + } catch (EOFException eof) { + if (commands.isEmpty()) + return; + throw eof; + } + if (PacketLineIn.isEnd(line)) { + break; + } + + if (line.length() >= 48 && line.startsWith("shallow ")) { //$NON-NLS-1$ + parseShallow(line.substring(8, 48)); + continue; + } + + if (firstPkt) { + firstPkt = false; + FirstCommand firstLine = FirstCommand.fromLine(line); + enabledCapabilities = firstLine.getCapabilities(); + line = firstLine.getLine(); + enableCapabilities(); + + if (line.equals(GitProtocolConstants.OPTION_PUSH_CERT)) { + certParser.receiveHeader(pck, !isBiDirectionalPipe()); + continue; + } + } + + if (line.equals(PushCertificateParser.BEGIN_SIGNATURE)) { + certParser.receiveSignature(pck); + continue; + } + + ReceiveCommand cmd = parseCommand(line); + if (cmd.getRefName().equals(Constants.HEAD)) { + cmd.setResult(Result.REJECTED_CURRENT_BRANCH); + } else { + cmd.setRef(refs.get(cmd.getRefName())); + } + commands.add(cmd); + if (certParser.enabled()) { + certParser.addCommand(cmd); + } + } + pushCert = certParser.build(); + if (hasCommands()) { + readPostCommands(pck); + } + } catch (PackProtocolException e) { + discardCommands(); + fatalError(e.getMessage()); + throw e; + } catch (InputOverLimitIOException e) { + String msg = JGitText.get().tooManyCommands; + discardCommands(); + fatalError(msg); + throw new PackProtocolException(msg); + } + } + + private void discardCommands() { + if (sideBand) { + long max = maxDiscardBytes; + if (max < 0) { + max = Math.max(3 * maxCommandBytes, 3L << 20); + } + try { + new PacketLineIn(rawIn, max).discardUntilEnd(); + } catch (IOException e) { + // Ignore read failures attempting to discard. + } + } + } + + private void parseShallow(String idStr) throws PackProtocolException { + ObjectId id; + try { + id = ObjectId.fromString(idStr); + } catch (InvalidObjectIdException e) { + throw new PackProtocolException(e.getMessage(), e); + } + clientShallowCommits.add(id); + } + + /** + * @param in + * request stream. + * @throws IOException + * request line cannot be read. + */ + void readPostCommands(PacketLineIn in) throws IOException { + if (usePushOptions) { + pushOptions = new ArrayList<>(4); + for (;;) { + String option = in.readString(); + if (PacketLineIn.isEnd(option)) { + break; + } + pushOptions.add(option); + } + } + } + + /** + * Enable capabilities based on a previously read capabilities line. + */ + private void enableCapabilities() { + reportStatus = isCapabilityEnabled(CAPABILITY_REPORT_STATUS); + usePushOptions = isCapabilityEnabled(CAPABILITY_PUSH_OPTIONS); + sideBand = isCapabilityEnabled(CAPABILITY_SIDE_BAND_64K); + quiet = allowQuiet && isCapabilityEnabled(CAPABILITY_QUIET); + if (sideBand) { + OutputStream out = rawOut; + + rawOut = new SideBandOutputStream(CH_DATA, MAX_BUF, out); + msgOut = new SideBandOutputStream(CH_PROGRESS, MAX_BUF, out); + errOut = new SideBandOutputStream(CH_ERROR, MAX_BUF, out); + + pckOut = new PacketLineOut(rawOut); + pckOut.setFlushOnEnd(false); + } + } + + /** + * Check if the peer requested a capability. + * + * @param name + * protocol name identifying the capability. + * @return true if the peer requested the capability to be enabled. + */ + private boolean isCapabilityEnabled(String name) { + return enabledCapabilities.contains(name); + } + + private void checkRequestWasRead() { + if (enabledCapabilities == null) + throw new RequestNotYetReadException(); + } + + /** + * Whether a pack is expected based on the list of commands. + * + * @return {@code true} if a pack is expected based on the list of commands. + */ + private boolean needPack() { + for (ReceiveCommand cmd : commands) { + if (cmd.getType() != ReceiveCommand.Type.DELETE) + return true; + } + return false; + } + + /** + * Receive a pack from the input and store it in the repository. + * + * @throws IOException + * an error occurred reading or indexing the pack. + */ + private void receivePack() throws IOException { + // It might take the client a while to pack the objects it needs + // to send to us. We should increase our timeout so we don't + // abort while the client is computing. + // + if (timeoutIn != null) + timeoutIn.setTimeout(10 * timeout * 1000); + + ProgressMonitor receiving = NullProgressMonitor.INSTANCE; + ProgressMonitor resolving = NullProgressMonitor.INSTANCE; + if (sideBand && !quiet) + resolving = new SideBandProgressMonitor(msgOut); + + try (ObjectInserter ins = db.newObjectInserter()) { + String lockMsg = "jgit receive-pack"; //$NON-NLS-1$ + if (getRefLogIdent() != null) + lockMsg += " from " + getRefLogIdent().toExternalString(); //$NON-NLS-1$ + + parser = ins.newPackParser(packInputStream()); + parser.setAllowThin(true); + parser.setNeedNewObjectIds(checkReferencedIsReachable); + parser.setNeedBaseObjectIds(checkReferencedIsReachable); + parser.setCheckEofAfterPackFooter( + !biDirectionalPipe && !isExpectDataAfterPackFooter()); + parser.setExpectDataAfterPackFooter(isExpectDataAfterPackFooter()); + parser.setObjectChecker(objectChecker); + parser.setLockMessage(lockMsg); + parser.setMaxObjectSizeLimit(maxObjectSizeLimit); + packLock = parser.parse(receiving, resolving); + packSize = Long.valueOf(parser.getPackSize()); + stats = parser.getReceivedPackStatistics(); + ins.flush(); + } + + if (timeoutIn != null) + timeoutIn.setTimeout(timeout * 1000); + } + + private InputStream packInputStream() { + InputStream packIn = rawIn; + if (maxPackSizeLimit >= 0) { + packIn = new LimitedInputStream(packIn, maxPackSizeLimit) { + @Override + protected void limitExceeded() throws TooLargePackException { + throw new TooLargePackException(limit); + } + }; + } + return packIn; + } + + private boolean needCheckConnectivity() { + return isCheckReceivedObjects() + || isCheckReferencedObjectsAreReachable() + || !getClientShallowCommits().isEmpty(); + } + + private void checkSubmodules() throws IOException { + ObjectDatabase odb = db.getObjectDatabase(); + if (objectChecker == null) { + return; + } + for (GitmoduleEntry entry : objectChecker.getGitsubmodules()) { + AnyObjectId blobId = entry.getBlobId(); + ObjectLoader blob = odb.open(blobId, Constants.OBJ_BLOB); + + try { + SubmoduleValidator.assertValidGitModulesFile( + new String(blob.getBytes(), UTF_8)); + } catch (LargeObjectException | SubmoduleValidationException e) { + throw new IOException(e); + } + } + } + + private void checkConnectivity() throws IOException { + ObjectIdSubclassMap<ObjectId> baseObjects = null; + ObjectIdSubclassMap<ObjectId> providedObjects = null; + ProgressMonitor checking = NullProgressMonitor.INSTANCE; + if (sideBand && !quiet) { + SideBandProgressMonitor m = new SideBandProgressMonitor(msgOut); + m.setDelayStart(750, TimeUnit.MILLISECONDS); + checking = m; + } + + if (checkReferencedIsReachable) { + baseObjects = parser.getBaseObjectIds(); + providedObjects = parser.getNewObjectIds(); + } + parser = null; + + try (ObjectWalk ow = new ObjectWalk(db)) { + if (baseObjects != null) { + ow.sort(RevSort.TOPO); + if (!baseObjects.isEmpty()) + ow.sort(RevSort.BOUNDARY, true); + } + + for (ReceiveCommand cmd : commands) { + if (cmd.getResult() != Result.NOT_ATTEMPTED) + continue; + if (cmd.getType() == ReceiveCommand.Type.DELETE) + continue; + ow.markStart(ow.parseAny(cmd.getNewId())); + } + for (ObjectId have : advertisedHaves) { + RevObject o = ow.parseAny(have); + ow.markUninteresting(o); + + if (baseObjects != null && !baseObjects.isEmpty()) { + o = ow.peel(o); + if (o instanceof RevCommit) + o = ((RevCommit) o).getTree(); + if (o instanceof RevTree) + ow.markUninteresting(o); + } + } + + checking.beginTask(JGitText.get().countingObjects, + ProgressMonitor.UNKNOWN); + RevCommit c; + while ((c = ow.next()) != null) { + checking.update(1); + if (providedObjects != null // + && !c.has(RevFlag.UNINTERESTING) // + && !providedObjects.contains(c)) + throw new MissingObjectException(c, Constants.TYPE_COMMIT); + } + + RevObject o; + while ((o = ow.nextObject()) != null) { + checking.update(1); + if (o.has(RevFlag.UNINTERESTING)) + continue; + + if (providedObjects != null) { + if (providedObjects.contains(o)) { + continue; + } + throw new MissingObjectException(o, o.getType()); + } + + if (o instanceof RevBlob && !db.getObjectDatabase().has(o)) + throw new MissingObjectException(o, Constants.TYPE_BLOB); + } + checking.endTask(); + + if (baseObjects != null) { + for (ObjectId id : baseObjects) { + o = ow.parseAny(id); + if (!o.has(RevFlag.UNINTERESTING)) + throw new MissingObjectException(o, o.getType()); + } + } + } + } + + /** + * Validate the command list. + */ + private void validateCommands() { + for (ReceiveCommand cmd : commands) { + final Ref ref = cmd.getRef(); + if (cmd.getResult() != Result.NOT_ATTEMPTED) + continue; + + if (cmd.getType() == ReceiveCommand.Type.DELETE) { + if (!isAllowDeletes()) { + // Deletes are not supported on this repository. + cmd.setResult(Result.REJECTED_NODELETE); + continue; + } + if (!isAllowBranchDeletes() + && ref.getName().startsWith(Constants.R_HEADS)) { + // Branches cannot be deleted, but other refs can. + cmd.setResult(Result.REJECTED_NODELETE); + continue; + } + } + + if (cmd.getType() == ReceiveCommand.Type.CREATE) { + if (!isAllowCreates()) { + cmd.setResult(Result.REJECTED_NOCREATE); + continue; + } + + if (ref != null && !isAllowNonFastForwards()) { + // Creation over an existing ref is certainly not going + // to be a fast-forward update. We can reject it early. + // + cmd.setResult(Result.REJECTED_NONFASTFORWARD); + continue; + } + + if (ref != null) { + // A well behaved client shouldn't have sent us a + // create command for a ref we advertised to it. + // + cmd.setResult(Result.REJECTED_OTHER_REASON, + JGitText.get().refAlreadyExists); + continue; + } + } + + if (cmd.getType() == ReceiveCommand.Type.DELETE && ref != null) { + ObjectId id = ref.getObjectId(); + if (id == null) { + id = ObjectId.zeroId(); + } + if (!ObjectId.zeroId().equals(cmd.getOldId()) + && !id.equals(cmd.getOldId())) { + // Delete commands can be sent with the old id matching our + // advertised value, *OR* with the old id being 0{40}. Any + // other requested old id is invalid. + // + cmd.setResult(Result.REJECTED_OTHER_REASON, + JGitText.get().invalidOldIdSent); + continue; + } + } + + if (cmd.getType() == ReceiveCommand.Type.UPDATE) { + if (ref == null) { + // The ref must have been advertised in order to be updated. + // + cmd.setResult(Result.REJECTED_OTHER_REASON, + JGitText.get().noSuchRef); + continue; + } + ObjectId id = ref.getObjectId(); + if (id == null) { + // We cannot update unborn branch + cmd.setResult(Result.REJECTED_OTHER_REASON, + JGitText.get().cannotUpdateUnbornBranch); + continue; + } + + if (!id.equals(cmd.getOldId())) { + // A properly functioning client will send the same + // object id we advertised. + // + cmd.setResult(Result.REJECTED_OTHER_REASON, + JGitText.get().invalidOldIdSent); + continue; + } + + // Is this possibly a non-fast-forward style update? + // + RevObject oldObj, newObj; + try { + oldObj = walk.parseAny(cmd.getOldId()); + } catch (IOException e) { + cmd.setResult(Result.REJECTED_MISSING_OBJECT, + cmd.getOldId().name()); + continue; + } + + try { + newObj = walk.parseAny(cmd.getNewId()); + } catch (IOException e) { + cmd.setResult(Result.REJECTED_MISSING_OBJECT, + cmd.getNewId().name()); + continue; + } + + if (oldObj instanceof RevCommit + && newObj instanceof RevCommit) { + try { + if (walk.isMergedInto((RevCommit) oldObj, + (RevCommit) newObj)) + cmd.setTypeFastForwardUpdate(); + else + cmd.setType( + ReceiveCommand.Type.UPDATE_NONFASTFORWARD); + } catch (MissingObjectException e) { + cmd.setResult(Result.REJECTED_MISSING_OBJECT, + e.getMessage()); + } catch (IOException e) { + cmd.setResult(Result.REJECTED_OTHER_REASON); + } + } else { + cmd.setType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD); + } + + if (cmd.getType() == ReceiveCommand.Type.UPDATE_NONFASTFORWARD + && !isAllowNonFastForwards()) { + cmd.setResult(Result.REJECTED_NONFASTFORWARD); + continue; + } + } + + if (!cmd.getRefName().startsWith(Constants.R_REFS) + || !Repository.isValidRefName(cmd.getRefName())) { + cmd.setResult(Result.REJECTED_OTHER_REASON, + JGitText.get().funnyRefname); + } + } + } + + /** + * Whether any commands have been rejected so far. + * + * @return if any commands have been rejected so far. + */ + private boolean anyRejects() { + for (ReceiveCommand cmd : commands) { + if (cmd.getResult() != Result.NOT_ATTEMPTED + && cmd.getResult() != Result.OK) + return true; + } + return false; + } + + /** + * Set the result to fail for any command that was not processed yet. + * + */ + private void failPendingCommands() { + ReceiveCommand.abort(commands); + } + + /** + * Filter the list of commands according to result. + * + * @param want + * desired status to filter by. + * @return a copy of the command list containing only those commands with + * the desired status. + */ + private List<ReceiveCommand> filterCommands(Result want) { + return ReceiveCommand.filter(commands, want); + } + + /** + * Execute commands to update references. + */ + private void executeCommands() { + List<ReceiveCommand> toApply = filterCommands(Result.NOT_ATTEMPTED); + if (toApply.isEmpty()) + return; + + ProgressMonitor updating = NullProgressMonitor.INSTANCE; + if (sideBand) { + SideBandProgressMonitor pm = new SideBandProgressMonitor(msgOut); + pm.setDelayStart(250, TimeUnit.MILLISECONDS); + updating = pm; + } + + BatchRefUpdate batch = db.getRefDatabase().newBatchUpdate(); + batch.setAllowNonFastForwards(isAllowNonFastForwards()); + batch.setAtomic(isAtomic()); + batch.setRefLogIdent(getRefLogIdent()); + batch.setRefLogMessage("push", true); //$NON-NLS-1$ + batch.addCommand(toApply); + try { + batch.setPushCertificate(getPushCertificate()); + batch.execute(walk, updating); + } catch (IOException err) { + for (ReceiveCommand cmd : toApply) { + if (cmd.getResult() == Result.NOT_ATTEMPTED) + cmd.reject(err); + } + } + } + + /** + * Send a status report. + * + * @param forClient + * true if this report is for a Git client, false if it is for an + * end-user. + * @param unpackError + * an error that occurred during unpacking, or {@code null} + * @param out + * the reporter for sending the status strings. + * @throws java.io.IOException + * an error occurred writing the status report. + * @since 5.6 + */ + private void sendStatusReport(final boolean forClient, + final Throwable unpackError, final Reporter out) + throws IOException { + if (unpackError != null) { + out.sendString("unpack error " + unpackError.getMessage()); //$NON-NLS-1$ + if (forClient) { + for (ReceiveCommand cmd : commands) { + out.sendString("ng " + cmd.getRefName() //$NON-NLS-1$ + + " n/a (unpacker error)"); //$NON-NLS-1$ + } + } + return; + } + + if (forClient) + out.sendString("unpack ok"); //$NON-NLS-1$ + for (ReceiveCommand cmd : commands) { + if (cmd.getResult() == Result.OK) { + if (forClient) + out.sendString("ok " + cmd.getRefName()); //$NON-NLS-1$ + continue; + } + + final StringBuilder r = new StringBuilder(); + if (forClient) + r.append("ng ").append(cmd.getRefName()).append(" "); //$NON-NLS-1$ //$NON-NLS-2$ + else + r.append(" ! [rejected] ").append(cmd.getRefName()) //$NON-NLS-1$ + .append(" ("); //$NON-NLS-1$ + + switch (cmd.getResult()) { + case NOT_ATTEMPTED: + r.append("server bug; ref not processed"); //$NON-NLS-1$ + break; + + case REJECTED_NOCREATE: + r.append("creation prohibited"); //$NON-NLS-1$ + break; + + case REJECTED_NODELETE: + r.append("deletion prohibited"); //$NON-NLS-1$ + break; + + case REJECTED_NONFASTFORWARD: + r.append("non-fast forward"); //$NON-NLS-1$ + break; + + case REJECTED_CURRENT_BRANCH: + r.append("branch is currently checked out"); //$NON-NLS-1$ + break; + + case REJECTED_MISSING_OBJECT: + if (cmd.getMessage() == null) + r.append("missing object(s)"); //$NON-NLS-1$ + else if (cmd.getMessage() + .length() == Constants.OBJECT_ID_STRING_LENGTH) { + r.append("object "); //$NON-NLS-1$ + r.append(cmd.getMessage()); + r.append(" missing"); //$NON-NLS-1$ + } else + r.append(cmd.getMessage()); + break; + + case REJECTED_OTHER_REASON: + if (cmd.getMessage() == null) + r.append("unspecified reason"); //$NON-NLS-1$ + else + r.append(cmd.getMessage()); + break; + + case LOCK_FAILURE: + r.append("failed to lock"); //$NON-NLS-1$ + break; + + case OK: + // We shouldn't have reached this case (see 'ok' case above). + continue; + } + if (!forClient) + r.append(")"); //$NON-NLS-1$ + out.sendString(r.toString()); + } + } + + /** + * Close and flush (if necessary) the underlying streams. + * + * @throws java.io.IOException + */ + private void close() throws IOException { + if (sideBand) { + // If we are using side band, we need to send a final + // flush-pkt to tell the remote peer the side band is + // complete and it should stop decoding. We need to + // use the original output stream as rawOut is now the + // side band data channel. + // + ((SideBandOutputStream) msgOut).flushBuffer(); + ((SideBandOutputStream) rawOut).flushBuffer(); + + PacketLineOut plo = new PacketLineOut(origOut); + plo.setFlushOnEnd(false); + plo.end(); + } + + if (biDirectionalPipe) { + // If this was a native git connection, flush the pipe for + // the caller. For smart HTTP we don't do this flush and + // instead let the higher level HTTP servlet code do it. + // + if (!sideBand && msgOut != null) + msgOut.flush(); + rawOut.flush(); + } + } + + /** + * Release any resources used by this object. + * + * @throws java.io.IOException + * the pack could not be unlocked. + */ + private void release() throws IOException { + walk.close(); + unlockPack(); + timeoutIn = null; + rawIn = null; + rawOut = null; + msgOut = null; + pckIn = null; + pckOut = null; + refs = null; + // Keep the capabilities. If responses are sent after this release + // we need to remember at least whether sideband communication has to be + // used + commands = null; + if (timer != null) { + try { + timer.terminate(); + } finally { + timer = null; + } + } + } + + /** Interface for reporting status messages. */ + static abstract class Reporter { + abstract void sendString(String s) throws IOException; + } + + /** * Get the push certificate used to verify the pusher's identity. * <p> * Only valid after commands are read from the wire. @@ -178,7 +2016,6 @@ public class ReceivePack extends BaseReceivePack { * or no cert was presented by the client. * @since 4.1 */ - @Override public PushCertificate getPushCertificate() { return pushCert; } @@ -193,7 +2030,6 @@ public class ReceivePack extends BaseReceivePack { * the push certificate to set. * @since 4.1 */ - @Override public void setPushCertificate(PushCertificate cert) { pushCert = cert; } @@ -334,28 +2170,6 @@ public class ReceivePack extends BaseReceivePack { } } - /** {@inheritDoc} */ - @Override - protected void enableCapabilities() { - reportStatus = isCapabilityEnabled(CAPABILITY_REPORT_STATUS); - usePushOptions = isCapabilityEnabled(CAPABILITY_PUSH_OPTIONS); - super.enableCapabilities(); - } - - @Override - void readPostCommands(PacketLineIn in) throws IOException { - if (usePushOptions) { - pushOptions = new ArrayList<>(4); - for (;;) { - String option = in.readString(); - if (PacketLineIn.isEnd(option)) { - break; - } - pushOptions.add(option); - } - } - } - private void service() throws IOException { if (isBiDirectionalPipe()) { sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut)); @@ -377,8 +2191,7 @@ public class ReceivePack extends BaseReceivePack { try { if (unpackError == null) { - boolean atomic = isCapabilityEnabled(CAPABILITY_ATOMIC); - setAtomic(atomic); + setAtomic(isCapabilityEnabled(CAPABILITY_ATOMIC)); validateCommands(); if (atomic && anyRejects()) { @@ -437,9 +2250,27 @@ public class ReceivePack extends BaseReceivePack { repo.autoGC(NullProgressMonitor.INSTANCE); } - /** {@inheritDoc} */ - @Override - protected String getLockMessageProcessName() { - return "jgit receive-pack"; //$NON-NLS-1$ + static ReceiveCommand parseCommand(String line) + throws PackProtocolException { + if (line == null || line.length() < 83) { + throw new PackProtocolException( + JGitText.get().errorInvalidProtocolWantedOldNewRef); + } + String oldStr = line.substring(0, 40); + String newStr = line.substring(41, 81); + ObjectId oldId, newId; + try { + oldId = ObjectId.fromString(oldStr); + newId = ObjectId.fromString(newStr); + } catch (InvalidObjectIdException e) { + throw new PackProtocolException( + JGitText.get().errorInvalidProtocolWantedOldNewRef, e); + } + String name = line.substring(82); + if (!Repository.isValidRefName(name)) { + throw new PackProtocolException( + JGitText.get().errorInvalidProtocolWantedOldNewRef); + } + return new ReceiveCommand(oldId, newId, name); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java index 0a621f19e1..4474d1a858 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RemoteConfig.java @@ -292,22 +292,26 @@ public class RemoteConfig implements Serializable { private String replaceUri(final String uri, final Map<String, String> replacements) { - if (replacements.isEmpty()) + if (replacements.isEmpty()) { return uri; + } Entry<String, String> match = null; for (Entry<String, String> replacement : replacements.entrySet()) { // Ignore current entry if not longer than previous match if (match != null - && match.getKey().length() > replacement.getKey().length()) + && match.getKey().length() > replacement.getKey() + .length()) { continue; - if (!uri.startsWith(replacement.getKey())) + } + if (!uri.startsWith(replacement.getKey())) { continue; + } match = replacement; } - if (match != null) + if (match != null) { return match.getValue() + uri.substring(match.getKey().length()); - else - return uri; + } + return uri; } /** 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 758d74c3fa..100b433e00 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java @@ -132,6 +132,7 @@ public class TransferConfig { private final boolean allowReachableSha1InWant; private final boolean allowFilter; private final boolean allowSidebandAll; + private final boolean advertiseSidebandAll; final @Nullable ProtocolVersion protocolVersion; final String[] hideRefs; @@ -213,6 +214,8 @@ public class TransferConfig { hideRefs = rc.getStringList("uploadpack", null, "hiderefs"); allowSidebandAll = rc.getBoolean( "uploadpack", "allowsidebandall", false); + advertiseSidebandAll = rc.getBoolean("uploadpack", + "advertisesidebandall", false); } /** @@ -295,7 +298,8 @@ public class TransferConfig { } /** - * @return true if clients are allowed to specify a "sideband-all" line + * @return true if the server accepts sideband-all requests (see + * {{@link #isAdvertiseSidebandAll()} for the advertisement) * @since 5.5 */ public boolean isAllowSidebandAll() { @@ -303,6 +307,14 @@ public class TransferConfig { } /** + * @return true to advertise sideband all to the clients + * @since 5.6 + */ + public boolean isAdvertiseSidebandAll() { + return advertiseSidebandAll && allowSidebandAll; + } + + /** * Get {@link org.eclipse.jgit.transport.RefFilter} respecting configured * hidden refs. * 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 0b7907035e..2382f4c3af 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java @@ -302,11 +302,12 @@ public abstract class Transport implements AutoCloseable { URISyntaxException, TransportException { if (local != null) { final RemoteConfig cfg = new RemoteConfig(local.getConfig(), remote); - if (doesNotExist(cfg)) + if (doesNotExist(cfg)) { return open(local, new URIish(remote), null); + } return open(local, cfg, op); - } else - return open(new URIish(remote)); + } + return open(new URIish(remote)); } @@ -708,11 +709,11 @@ public abstract class Transport implements AutoCloseable { // try to find matching tracking refs for (RefSpec fetchSpec : fetchSpecs) { if (fetchSpec.matchSource(remoteName)) { - if (fetchSpec.isWildcard()) + if (fetchSpec.isWildcard()) { return fetchSpec.expandFromSource(remoteName) .getDestination(); - else - return fetchSpec.getDestination(); + } + return fetchSpec.getDestination(); } } return null; 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 3029327c52..2637a0273a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java @@ -698,9 +698,8 @@ public class TransportHttp extends HttpTransport implements WalkTransport, public CredentialItem[] items() { if (forRepo == null) { return new CredentialItem[] { message, now, always }; - } else { - return new CredentialItem[] { message, now, forRepo, always }; } + return new CredentialItem[] { message, now, forRepo, always }; } } @@ -1076,13 +1075,11 @@ public class TransportHttp extends HttpTransport implements WalkTransport, host = host.toLowerCase(Locale.ROOT); if (host.equals(cookieDomain)) { return true; - } else { - if (!host.endsWith(cookieDomain)) { - return false; - } - return host - .charAt(host.length() - cookieDomain.length() - 1) == '.'; } + if (!host.endsWith(cookieDomain)) { + return false; + } + return host.charAt(host.length() - cookieDomain.length() - 1) == '.'; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java index 7ca9cc134c..d5e03ebd57 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java @@ -351,10 +351,7 @@ public class URIish implements Serializable { } private String n2e(String s) { - if (s == null) - return ""; //$NON-NLS-1$ - else - return s; + return s == null ? "" : s; //$NON-NLS-1$ } // takes care to cut of a leading slash if a windows drive letter or a diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java index 20b45882df..6ee280b81e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java @@ -44,6 +44,7 @@ package org.eclipse.jgit.transport; import static java.util.Collections.unmodifiableMap; +import static java.util.Objects.requireNonNull; import static org.eclipse.jgit.lib.Constants.R_TAGS; import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REF_IN_WANT; import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SERVER_OPTION; @@ -84,7 +85,9 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.TreeMap; +import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.annotations.Nullable; @@ -282,6 +285,8 @@ public class UploadPack { private OutputStream msgOut = NullOutputStream.INSTANCE; + private ErrorWriter errOut = new PackProtocolErrorWriter(); + /** * Refs eligible for advertising to the client, set using * {@link #setAdvertisedRefs}. @@ -756,9 +761,59 @@ public class UploadPack { /** * Execute the upload task on the socket. * - * <p>If the client passed extra parameters (e.g., "version=2") through a - * side channel, the caller must call setExtraParameters first to supply - * them. + * <p> + * Same as {@link #uploadWithExceptionPropagation} except that the thrown + * exceptions are handled in the method, and the error messages are sent to + * the clients. + * + * <p> + * Call this method if the caller does not have an error handling mechanism. + * Call {@link #uploadWithExceptionPropagation} if the caller wants to have + * its own error handling mechanism. + * + * @param input + * @param output + * @param messages + * @throws java.io.IOException + */ + public void upload(InputStream input, OutputStream output, + @Nullable OutputStream messages) throws IOException { + try { + uploadWithExceptionPropagation(input, output, messages); + } catch (ServiceMayNotContinueException err) { + if (!err.isOutput() && err.getMessage() != null) { + try { + errOut.writeError(err.getMessage()); + } catch (IOException e) { + err.addSuppressed(e); + throw err; + } + err.setOutput(); + } + throw err; + } catch (IOException | RuntimeException | Error err) { + if (rawOut != null) { + String msg = err instanceof PackProtocolException + ? err.getMessage() + : JGitText.get().internalServerError; + try { + errOut.writeError(msg); + } catch (IOException e) { + err.addSuppressed(e); + throw err; + } + throw new UploadPackInternalServerErrorException(err); + } + throw err; + } + } + + /** + * Execute the upload task on the socket. + * + * <p> + * If the client passed extra parameters (e.g., "version=2") through a side + * channel, the caller must call setExtraParameters first to supply them. * * @param input * raw input to read client commands from. Caller must ensure the @@ -772,15 +827,21 @@ public class UploadPack { * through. When run over SSH this should be tied back to the * standard error channel of the command execution. For most * other network connections this should be null. - * @throws java.io.IOException + * @throws ServiceMayNotContinueException + * thrown if one of the hooks throws this. + * @throws IOException + * thrown if the server or the client I/O fails, or there's an + * internal server error. + * @since 5.6 */ - public void upload(InputStream input, OutputStream output, - @Nullable OutputStream messages) throws IOException { - PacketLineOut pckOut = null; + public void uploadWithExceptionPropagation(InputStream input, + OutputStream output, @Nullable OutputStream messages) + throws ServiceMayNotContinueException, IOException { try { rawIn = input; - if (messages != null) + if (messages != null) { msgOut = messages; + } if (timeout > 0) { final Thread caller = Thread.currentThread(); @@ -800,42 +861,12 @@ public class UploadPack { } pckIn = new PacketLineIn(rawIn); - pckOut = new PacketLineOut(rawOut); + PacketLineOut pckOut = new PacketLineOut(rawOut); if (useProtocolV2()) { serviceV2(pckOut); } else { service(pckOut); } - } catch (UploadPackInternalServerErrorException err) { - // UploadPackInternalServerErrorException is a special exception - // that indicates an error is already written to the client. Do - // nothing. - throw err; - } catch (ServiceMayNotContinueException err) { - if (!err.isOutput() && err.getMessage() != null && pckOut != null) { - try { - pckOut.writeString("ERR " + err.getMessage() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ - } catch (IOException e) { - err.addSuppressed(e); - throw err; - } - err.setOutput(); - } - throw err; - } catch (IOException | RuntimeException | Error err) { - if (pckOut != null) { - String msg = err instanceof PackProtocolException - ? err.getMessage() - : JGitText.get().internalServerError; - try { - pckOut.writeString("ERR " + msg + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ - } catch (IOException e) { - err.addSuppressed(e); - throw err; - } - throw new UploadPackInternalServerErrorException(err); - } - throw err; } finally { msgOut = NullOutputStream.INSTANCE; walk.close(); @@ -1296,7 +1327,7 @@ public class UploadPack { caps.add(COMMAND_FETCH + '=' + (transferConfig.isAllowFilter() ? OPTION_FILTER + ' ' : "") + (advertiseRefInWant ? CAPABILITY_REF_IN_WANT + ' ' : "") - + (transferConfig.isAllowSidebandAll() + + (transferConfig.isAdvertiseSidebandAll() ? OPTION_SIDEBAND_ALL + ' ' : "") + (cachedPackUriProvider != null ? "packfile-uris " : "") @@ -1844,8 +1875,7 @@ public class UploadPack { @Override public void checkWants(UploadPack up, List<ObjectId> wants) throws PackProtocolException, IOException { - checkNotAdvertisedWants(up, wants, - refIdSet(up.getAdvertisedRefs().values())); + checkNotAdvertisedWants(up, wants, up.getAdvertisedRefs().values()); } } @@ -1882,7 +1912,7 @@ public class UploadPack { public void checkWants(UploadPack up, List<ObjectId> wants) throws PackProtocolException, IOException { checkNotAdvertisedWants(up, wants, - refIdSet(up.getRepository().getRefDatabase().getRefs())); + up.getRepository().getRefDatabase().getRefs()); } } @@ -1942,12 +1972,14 @@ public class UploadPack { } private static void checkNotAdvertisedWants(UploadPack up, - List<ObjectId> notAdvertisedWants, Set<ObjectId> reachableFrom) + List<ObjectId> notAdvertisedWants, Collection<Ref> visibleRefs) throws IOException { ObjectReader reader = up.getRevWalk().getObjectReader(); + try (RevWalk walk = new RevWalk(reader)) { walk.setRetainBody(false); + Set<ObjectId> reachableFrom = refIdSet(visibleRefs); // Missing "wants" throw exception here List<RevObject> wantsAsObjs = objectIdsToRevObjects(walk, notAdvertisedWants); @@ -1994,10 +2026,13 @@ public class UploadPack { ReachabilityChecker reachabilityChecker = walk .createReachabilityChecker(); - List<RevCommit> starters = objectIdsToRevCommits(walk, - reachableFrom); + Stream<RevCommit> reachableCommits = importantRefsFirst(visibleRefs) + .map(UploadPack::refToObjectId) + .map(objId -> objectIdToRevCommit(walk, objId)) + .filter(Objects::nonNull); // Ignore missing tips + Optional<RevCommit> unreachable = reachabilityChecker - .areAllReachable(wantsAsCommits, starters); + .areAllReachable(wantsAsCommits, reachableCommits); if (unreachable.isPresent()) { throw new WantNotValidException(unreachable.get()); } @@ -2007,6 +2042,50 @@ public class UploadPack { } } + static Stream<Ref> importantRefsFirst( + Collection<Ref> visibleRefs) { + Predicate<Ref> startsWithRefsHeads = ref -> ref.getName() + .startsWith(Constants.R_HEADS); + Predicate<Ref> startsWithRefsTags = ref -> ref.getName() + .startsWith(Constants.R_TAGS); + Predicate<Ref> allOther = ref -> !startsWithRefsHeads.test(ref) + && !startsWithRefsTags.test(ref); + + return Stream.concat( + visibleRefs.stream().filter(startsWithRefsHeads), + Stream.concat( + visibleRefs.stream().filter(startsWithRefsTags), + visibleRefs.stream().filter(allOther))); + } + + private static ObjectId refToObjectId(Ref ref) { + return ref.getObjectId() != null ? ref.getObjectId() + : ref.getPeeledObjectId(); + } + + /** + * Translate an object id to a RevCommit. + * + * @param walk + * walk on the relevant object storae + * @param objectId + * Object Id + * @return RevCommit instance or null if the object is missing + */ + @Nullable + private static RevCommit objectIdToRevCommit(RevWalk walk, + ObjectId objectId) { + if (objectId == null) { + return null; + } + + try { + return walk.parseCommit(objectId); + } catch (IOException e) { + return null; + } + } + // Resolve the ObjectIds into RevObjects. Any missing object raises an // exception private static List<RevObject> objectIdsToRevObjects(RevWalk walk, @@ -2019,23 +2098,6 @@ public class UploadPack { return result; } - // Get commits from object ids. If the id is not a commit, ignore it. If the - // id doesn't exist, report the missing object in a exception. - private static List<RevCommit> objectIdsToRevCommits(RevWalk walk, - Iterable<ObjectId> objectIds) - throws MissingObjectException, IOException { - List<RevCommit> result = new ArrayList<>(); - for (ObjectId objectId : objectIds) { - try { - result.add(walk.parseCommit(objectId)); - } catch (IncorrectObjectTypeException e) { - continue; - } - } - return result; - } - - private void addCommonBase(RevObject o) { if (!o.has(COMMON)) { o.add(COMMON); @@ -2114,54 +2176,42 @@ public class UploadPack { Set<String> caps = req.getClientCapabilities(); boolean sideband = caps.contains(OPTION_SIDE_BAND) || caps.contains(OPTION_SIDE_BAND_64K); + if (sideband) { - try { - sendPack(true, req, accumulator, allTags, unshallowCommits, - deepenNots, pckOut); - } catch (ServiceMayNotContinueException err) { - String message = err.getMessage(); - if (message == null) { - message = JGitText.get().internalServerError; - } - try { - reportInternalServerErrorOverSideband(message); - } catch (IOException e) { - err.addSuppressed(e); - throw err; - } - throw new UploadPackInternalServerErrorException(err); - } catch (IOException | RuntimeException | Error err) { - try { - reportInternalServerErrorOverSideband( - JGitText.get().internalServerError); - } catch (IOException e) { - err.addSuppressed(e); - throw err; - } - throw new UploadPackInternalServerErrorException(err); + errOut = new SideBandErrorWriter(); + + int bufsz = SideBandOutputStream.SMALL_BUF; + if (req.getClientCapabilities().contains(OPTION_SIDE_BAND_64K)) { + bufsz = SideBandOutputStream.MAX_BUF; } + OutputStream packOut = new SideBandOutputStream( + SideBandOutputStream.CH_DATA, bufsz, rawOut); + + ProgressMonitor pm = NullProgressMonitor.INSTANCE; + if (!req.getClientCapabilities().contains(OPTION_NO_PROGRESS)) { + msgOut = new SideBandOutputStream( + SideBandOutputStream.CH_PROGRESS, bufsz, rawOut); + pm = new SideBandProgressMonitor(msgOut); + } + + sendPack(pm, pckOut, packOut, req, accumulator, allTags, + unshallowCommits, deepenNots); + pckOut.end(); } else { - sendPack(false, req, accumulator, allTags, unshallowCommits, deepenNots, - pckOut); + sendPack(NullProgressMonitor.INSTANCE, pckOut, rawOut, req, + accumulator, allTags, unshallowCommits, deepenNots); } } - private void reportInternalServerErrorOverSideband(String message) - throws IOException { - @SuppressWarnings("resource" /* java 7 */) - SideBandOutputStream err = new SideBandOutputStream( - SideBandOutputStream.CH_ERROR, SideBandOutputStream.SMALL_BUF, - rawOut); - err.write(Constants.encode(message)); - err.flush(); - } - /** * Send the requested objects to the client. * - * @param sideband - * whether to wrap the pack in side-band pkt-lines, interleaved - * with progress messages and errors. + * @param pm + * progress monitor + * @param pckOut + * PacketLineOut that shares the output with packOut + * @param packOut + * packfile output * @param req * request being processed * @param accumulator @@ -2173,35 +2223,14 @@ public class UploadPack { * shallow commits on the client that are now becoming unshallow * @param deepenNots * objects that the client specified using --shallow-exclude - * @param pckOut - * output writer * @throws IOException * if an error occurred while generating or writing the pack. */ - private void sendPack(final boolean sideband, - FetchRequest req, + private void sendPack(ProgressMonitor pm, PacketLineOut pckOut, + OutputStream packOut, FetchRequest req, PackStatistics.Accumulator accumulator, - @Nullable Collection<Ref> allTags, - List<ObjectId> unshallowCommits, - List<ObjectId> deepenNots, - PacketLineOut pckOut) throws IOException { - ProgressMonitor pm = NullProgressMonitor.INSTANCE; - OutputStream packOut = rawOut; - - if (sideband) { - int bufsz = SideBandOutputStream.SMALL_BUF; - if (req.getClientCapabilities().contains(OPTION_SIDE_BAND_64K)) - bufsz = SideBandOutputStream.MAX_BUF; - - packOut = new SideBandOutputStream(SideBandOutputStream.CH_DATA, - bufsz, rawOut); - if (!req.getClientCapabilities().contains(OPTION_NO_PROGRESS)) { - msgOut = new SideBandOutputStream( - SideBandOutputStream.CH_PROGRESS, bufsz, rawOut); - pm = new SideBandProgressMonitor(msgOut); - } - } - + @Nullable Collection<Ref> allTags, List<ObjectId> unshallowCommits, + List<ObjectId> deepenNots) throws IOException { if (wantAll.isEmpty()) { preUploadHook.onSendPack(this, wantIds, commonBase); } else { @@ -2344,9 +2373,6 @@ public class UploadPack { } pw.close(); } - - if (sideband) - pckOut.end(); } private static void findSymrefs( @@ -2411,4 +2437,28 @@ public class UploadPack { } } } + + private interface ErrorWriter { + void writeError(String message) throws IOException; + } + + private class SideBandErrorWriter implements ErrorWriter { + @Override + public void writeError(String message) throws IOException { + @SuppressWarnings("resource" /* java 7 */) + SideBandOutputStream err = new SideBandOutputStream( + SideBandOutputStream.CH_ERROR, + SideBandOutputStream.SMALL_BUF, requireNonNull(rawOut)); + err.write(Constants.encode(message)); + err.flush(); + } + } + + private class PackProtocolErrorWriter implements ErrorWriter { + @Override + public void writeError(String message) throws IOException { + new PacketLineOut(requireNonNull(rawOut)) + .writeString("ERR " + message + '\n'); //$NON-NLS-1$ + } + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java index b4a7af094d..9a08c080c3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/resolver/FileResolver.java @@ -124,8 +124,8 @@ public class FileResolver<C> implements RepositoryResolver<C> { // are responsible for closing the repository if we // complete successfully. return db; - } else - throw new ServiceNotEnabledException(); + } + throw new ServiceNotEnabledException(); } catch (RuntimeException | IOException e) { db.close(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java index 4f3eb05b11..6969ae45af 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java @@ -285,9 +285,8 @@ public class FileTreeIterator extends WorkingTreeIterator { } else if (attributes.isDirectory()) { if (new File(f, Constants.DOT_GIT).exists()) { return FileMode.GITLINK; - } else { - return FileMode.TREE; } + return FileMode.TREE; } else if (attributes.isExecutable()) { return FileMode.EXECUTABLE_FILE; } else { @@ -425,9 +424,8 @@ public class FileTreeIterator extends WorkingTreeIterator { if (attributes.isSymbolicLink()) { return new ByteArrayInputStream(fs.readSymLink(getFile()) .getBytes(UTF_8)); - } else { - return new FileInputStream(getFile()); } + return new FileInputStream(getFile()); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java index 8bb68dca17..88b76f7121 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java @@ -101,7 +101,6 @@ import org.eclipse.jgit.util.Paths; import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.TemporaryBuffer; import org.eclipse.jgit.util.TemporaryBuffer.LocalFile; -import org.eclipse.jgit.util.io.AutoLFInputStream; import org.eclipse.jgit.util.io.EolStreamTypeUtil; import org.eclipse.jgit.util.sha1.SHA1; @@ -686,10 +685,10 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { public InputStream openEntryStream() throws IOException { InputStream rawis = current().openInputStream(); if (getCleanFilterCommand() == null - && getEolStreamType() == EolStreamType.DIRECT) + && getEolStreamType() == EolStreamType.DIRECT) { return rawis; - else - return filterClean(rawis); + } + return filterClean(rawis); } /** @@ -980,13 +979,13 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { MetadataDiff diff = compareMetadata(entry); switch (diff) { case DIFFER_BY_TIMESTAMP: - if (forceContentCheck) + if (forceContentCheck) { // But we are told to look at content even though timestamps // tell us about modification return contentCheck(entry, reader); - else - // We are told to assume a modification if timestamps differs - return true; + } + // We are told to assume a modification if timestamps differs + return true; case SMUDGED: // The file is clean by timestamps but the entry was smudged. // Lets do a content check @@ -1087,47 +1086,13 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { entry.setLength((int) getEntryLength()); return false; - } else { - if (mode == FileMode.SYMLINK.getBits()) { - return !new File(readSymlinkTarget(current())).equals( - new File(readContentAsNormalizedString(entry, reader))); - } - // Content differs: that's a real change, perhaps - if (reader == null) // deprecated use, do no further checks - return true; - - switch (getEolStreamType()) { - case DIRECT: - return true; - default: - try { - ObjectLoader loader = reader.open(entry.getObjectId()); - if (loader == null) - return true; - - // We need to compute the length, but only if it is not - // a binary stream. - long dcInLen; - try (InputStream dcIn = new AutoLFInputStream( - loader.openStream(), true, - true /* abort if binary */)) { - dcInLen = computeLength(dcIn); - } catch (AutoLFInputStream.IsBinaryException e) { - return true; - } - - try (InputStream dcIn = new AutoLFInputStream( - loader.openStream(), true)) { - byte[] autoCrLfHash = computeHash(dcIn, dcInLen); - boolean changed = getEntryObjectId() - .compareTo(autoCrLfHash, 0) != 0; - return changed; - } - } catch (IOException e) { - return true; - } - } } + if (mode == FileMode.SYMLINK.getBits()) { + return !new File(readSymlinkTarget(current())).equals( + new File(readContentAsNormalizedString(entry, reader))); + } + // Content differs: that's a real change + return true; } private static String readContentAsNormalizedString(DirCacheEntry entry, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java index 6cca582b3b..52fb888291 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/IndexDiffFilter.java @@ -212,10 +212,9 @@ public class IndexDiffFilter extends TreeFilter { // If i is cnt then the path does not appear in any other tree, // and this working tree entry can be safely ignored. return i != cnt; - } else { - // In working tree and not ignored, and not in DirCache. - return true; } + // In working tree and not ignored, and not in DirCache. + return true; } // Always include subtrees as WorkingTreeIterator cannot provide diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathSuffixFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathSuffixFilter.java index 3d9f875e99..11896e4242 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathSuffixFilter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/PathSuffixFilter.java @@ -99,10 +99,10 @@ public class PathSuffixFilter extends TreeFilter { @Override public boolean include(TreeWalk walker) throws MissingObjectException, IncorrectObjectTypeException, IOException { - if (walker.isSubtree()) + if (walker.isSubtree()) { return true; - else - return walker.isPathSuffix(pathRaw, pathRaw.length); + } + return walker.isPathSuffix(pathRaw, pathRaw.length); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java index c8e6645f57..66f996554f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java @@ -173,20 +173,19 @@ public class ChangeIdUtil { boolean replaceExisting) { int indexOfChangeId = indexOfChangeId(message, "\n"); //$NON-NLS-1$ if (indexOfChangeId > 0) { - if (!replaceExisting) + if (!replaceExisting) { return message; - else { - StringBuilder ret = new StringBuilder(message.substring(0, - indexOfChangeId)); - ret.append(CHANGE_ID); - ret.append(" I"); //$NON-NLS-1$ - ret.append(ObjectId.toString(changeId)); - int indexOfNextLineBreak = message.indexOf("\n", //$NON-NLS-1$ - indexOfChangeId); - if (indexOfNextLineBreak > 0) - ret.append(message.substring(indexOfNextLineBreak)); - return ret.toString(); } + StringBuilder ret = new StringBuilder( + message.substring(0, indexOfChangeId)); + ret.append(CHANGE_ID); + ret.append(" I"); //$NON-NLS-1$ + ret.append(ObjectId.toString(changeId)); + int indexOfNextLineBreak = message.indexOf("\n", //$NON-NLS-1$ + indexOfChangeId); + if (indexOfNextLineBreak > 0) + ret.append(message.substring(indexOfNextLineBreak)); + return ret.toString(); } String[] lines = message.split("\n"); //$NON-NLS-1$ 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 0aa0e3668d..b6c88503b1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java @@ -61,6 +61,7 @@ import java.nio.charset.Charset; import java.nio.file.AccessDeniedException; import java.nio.file.FileStore; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; @@ -98,6 +99,7 @@ import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.LockFailedException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.file.FileSnapshot; +import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; @@ -147,15 +149,15 @@ public abstract class FS { */ public FS detect(Boolean cygwinUsed) { if (SystemReader.getInstance().isWindows()) { - if (cygwinUsed == null) + if (cygwinUsed == null) { cygwinUsed = Boolean.valueOf(FS_Win32_Cygwin.isCygwin()); - if (cygwinUsed.booleanValue()) + } + if (cygwinUsed.booleanValue()) { return new FS_Win32_Cygwin(); - else - return new FS_Win32(); - } else { - return new FS_POSIX(); + } + return new FS_Win32(); } + return new FS_POSIX(); } } @@ -837,7 +839,7 @@ public abstract class FS { try { FileUtils.delete(tempFile); } catch (IOException e) { - throw new RuntimeException(e); // panic + LOG.error(JGitText.get().cannotDeleteFile, tempFile); } } } @@ -1192,14 +1194,13 @@ public abstract class FS { gobbler.join(); if (rc == 0 && !gobbler.fail.get()) { return r; - } else { - if (debug) { - LOG.debug("readpipe rc=" + rc); //$NON-NLS-1$ - } - throw new CommandFailedException(rc, - gobbler.errorMessage.get(), - gobbler.exception.get()); } + if (debug) { + LOG.debug("readpipe rc=" + rc); //$NON-NLS-1$ + } + throw new CommandFailedException(rc, + gobbler.errorMessage.get(), + gobbler.exception.get()); } catch (InterruptedException ie) { // Stop bothering me, I have a zombie to reap. } @@ -1726,20 +1727,18 @@ public abstract class FS { final String hookName, String[] args, PrintStream outRedirect, PrintStream errRedirect, String stdinArgs) throws JGitInternalException { - final File hookFile = findHook(repository, hookName); - if (hookFile == null) + File hookFile = findHook(repository, hookName); + if (hookFile == null || hookName == null) { return new ProcessResult(Status.NOT_PRESENT); + } - final String hookPath = hookFile.getAbsolutePath(); - final File runDirectory; - if (repository.isBare()) - runDirectory = repository.getDirectory(); - else - runDirectory = repository.getWorkTree(); - final String cmd = relativize(runDirectory.getAbsolutePath(), - hookPath); + File runDirectory = getRunDirectory(repository, hookName); + if (runDirectory == null) { + return new ProcessResult(Status.NOT_PRESENT); + } + String cmd = hookFile.getAbsolutePath(); ProcessBuilder hookProcess = runInShell(cmd, args); - hookProcess.directory(runDirectory); + hookProcess.directory(runDirectory.getAbsoluteFile()); Map<String, String> environment = hookProcess.environment(); environment.put(Constants.GIT_DIR_KEY, repository.getDirectory().getAbsolutePath()); @@ -1774,12 +1773,71 @@ public abstract class FS { * @since 4.0 */ public File findHook(Repository repository, String hookName) { - File gitDir = repository.getDirectory(); - if (gitDir == null) + if (hookName == null) { + return null; + } + File hookDir = getHooksDirectory(repository); + if (hookDir == null) { return null; - final File hookFile = new File(new File(gitDir, - Constants.HOOKS), hookName); - return hookFile.isFile() ? hookFile : null; + } + File hookFile = new File(hookDir, hookName); + if (hookFile.isAbsolute()) { + if (!hookFile.exists() || (FS.DETECTED.supportsExecute() + && !FS.DETECTED.canExecute(hookFile))) { + return null; + } + } else { + try { + File runDirectory = getRunDirectory(repository, hookName); + if (runDirectory == null) { + return null; + } + Path hookPath = runDirectory.getAbsoluteFile().toPath() + .resolve(hookFile.toPath()); + FS fs = repository.getFS(); + if (fs == null) { + fs = FS.DETECTED; + } + if (!Files.exists(hookPath) || (fs.supportsExecute() + && !fs.canExecute(hookPath.toFile()))) { + return null; + } + hookFile = hookPath.toFile(); + } catch (InvalidPathException e) { + LOG.warn(MessageFormat.format(JGitText.get().invalidHooksPath, + hookFile)); + return null; + } + } + return hookFile; + } + + private File getRunDirectory(Repository repository, + @NonNull String hookName) { + if (repository.isBare()) { + return repository.getDirectory(); + } + switch (hookName) { + case "pre-receive": //$NON-NLS-1$ + case "update": //$NON-NLS-1$ + case "post-receive": //$NON-NLS-1$ + case "post-update": //$NON-NLS-1$ + case "push-to-checkout": //$NON-NLS-1$ + return repository.getDirectory(); + default: + return repository.getWorkTree(); + } + } + + private File getHooksDirectory(Repository repository) { + Config config = repository.getConfig(); + String hooksDir = config.getString(ConfigConstants.CONFIG_CORE_SECTION, + null, ConfigConstants.CONFIG_KEY_HOOKS_PATH); + if (hooksDir != null) { + return new File(hooksDir); + } + File dir = repository.getDirectory(); + return dir == null ? null : new File(dir, Constants.HOOKS); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java index 6a1eef2d66..5c2d8277cd 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java @@ -74,7 +74,6 @@ import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.errors.CommandFailedException; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.internal.JGitText; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.slf4j.Logger; @@ -262,7 +261,7 @@ public class FS_POSIX extends FS { List<String> argv = new ArrayList<>(4 + args.length); argv.add("sh"); //$NON-NLS-1$ argv.add("-c"); //$NON-NLS-1$ - argv.add(cmd + " \"$@\""); //$NON-NLS-1$ + argv.add("$0 \"$@\""); //$NON-NLS-1$ argv.add(cmd); argv.addAll(Arrays.asList(args)); ProcessBuilder proc = new ProcessBuilder(); @@ -311,20 +310,6 @@ public class FS_POSIX extends FS { /** {@inheritDoc} */ @Override - public File findHook(Repository repository, String hookName) { - final File gitdir = repository.getDirectory(); - if (gitdir == null) { - return null; - } - final Path hookPath = gitdir.toPath().resolve(Constants.HOOKS) - .resolve(hookName); - if (Files.isExecutable(hookPath)) - return hookPath.toFile(); - return null; - } - - /** {@inheritDoc} */ - @Override public boolean supportsAtomicCreateNewFile() { if (supportsAtomicFileCreation == AtomicFileCreation.UNDEFINED) { try { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java index 9a163e8e38..ac3248cb63 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java @@ -47,8 +47,6 @@ import static java.nio.charset.StandardCharsets.UTF_8; import java.io.File; import java.io.PrintStream; -import java.nio.file.Files; -import java.nio.file.Path; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; @@ -57,7 +55,6 @@ import java.util.List; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.errors.CommandFailedException; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -152,7 +149,7 @@ public class FS_Win32_Cygwin extends FS_Win32 { List<String> argv = new ArrayList<>(4 + args.length); argv.add("sh.exe"); //$NON-NLS-1$ argv.add("-c"); //$NON-NLS-1$ - argv.add(cmd + " \"$@\""); //$NON-NLS-1$ + argv.add("$0 \"$@\""); //$NON-NLS-1$ argv.add(cmd); argv.addAll(Arrays.asList(args)); ProcessBuilder proc = new ProcessBuilder(); @@ -175,18 +172,4 @@ public class FS_Win32_Cygwin extends FS_Win32 { return internalRunHookIfPresent(repository, hookName, args, outRedirect, errRedirect, stdinArgs); } - - /** {@inheritDoc} */ - @Override - public File findHook(Repository repository, String hookName) { - final File gitdir = repository.getDirectory(); - if (gitdir == null) { - return null; - } - final Path hookPath = gitdir.toPath().resolve(Constants.HOOKS) - .resolve(hookName); - if (Files.isExecutable(hookPath)) - return hookPath.toFile(); - return null; - } } 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 4d791e470a..e026e9274f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java @@ -73,6 +73,7 @@ import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.Random; import java.util.regex.Pattern; import org.eclipse.jgit.internal.JGitText; @@ -87,6 +88,8 @@ import org.slf4j.LoggerFactory; public class FileUtils { private static final Logger LOG = LoggerFactory.getLogger(FileUtils.class); + private static final Random RNG = new Random(); + /** * Option to delete given {@code File} */ @@ -986,4 +989,28 @@ public class FileUtils { } Files.setLastModifiedTime(f, FileTime.from(Instant.now())); } + + /** + * Compute a delay in a {@code min..max} interval with random jitter. + * + * @param last + * amount of delay waited before the last attempt. This is used + * to seed the next delay interval. Should be 0 if there was no + * prior delay. + * @param min + * shortest amount of allowable delay between attempts. + * @param max + * longest amount of allowable delay between attempts. + * @return new amount of delay to wait before the next attempt. + * + * @since 5.6 + */ + public static long delay(long last, long min, long max) { + long r = Math.max(0, last * 3 - min); + if (r > 0) { + int c = (int) Math.min(r + 1, Integer.MAX_VALUE); + r = RNG.nextInt(c); + } + return Math.max(Math.min(min + r, max), min); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java index 56a173163d..c6a6899948 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java @@ -144,7 +144,7 @@ public class GitDateParser { * <li>"yesterday"</li> * <li>"(x) years|months|weeks|days|hours|minutes|seconds ago"<br> * Multiple specs can be combined like in "2 weeks 3 days ago". Instead of ' - * ' one can use '.' to seperate the words</li> + * ' one can use '.' to separate the words</li> * <li>"yyyy-MM-dd HH:mm:ss Z" (ISO)</li> * <li>"EEE, dd MMM yyyy HH:mm:ss Z" (RFC)</li> * <li>"yyyy-MM-dd"</li> @@ -186,7 +186,7 @@ public class GitDateParser { * <li>"yesterday"</li> * <li>"(x) years|months|weeks|days|hours|minutes|seconds ago"<br> * Multiple specs can be combined like in "2 weeks 3 days ago". Instead of ' - * ' one can use '.' to seperate the words</li> + * ' one can use '.' to separate the words</li> * <li>"yyyy-MM-dd HH:mm:ss Z" (ISO)</li> * <li>"EEE, dd MMM yyyy HH:mm:ss Z" (RFC)</li> * <li>"yyyy-MM-dd"</li> diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java index 640670debc..d897255062 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/HttpSupport.java @@ -51,6 +51,7 @@ import java.io.UnsupportedEncodingException; import java.net.ConnectException; import java.net.Proxy; import java.net.ProxySelector; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLEncoder; @@ -299,7 +300,9 @@ public class HttpSupport { public static Proxy proxyFor(ProxySelector proxySelector, URL u) throws ConnectException { try { - return proxySelector.select(u.toURI()).get(0); + URI uri = new URI(u.getProtocol(), null, u.getHost(), u.getPort(), + null, null, null); + return proxySelector.select(uri).get(0); } catch (URISyntaxException e) { final ConnectException err; err = new ConnectException(MessageFormat.format(JGitText.get().cannotDetermineProxyFor, u)); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java index a07a4fd1a5..391598d8ae 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java @@ -345,13 +345,14 @@ public class IO { c = s.charAt(++i); l.add(sb.toString()); sb.setLength(0); - if (c != '\n') + if (c != '\n') { sb.append(c); + } continue; - } else { // EOF - l.add(sb.toString()); - break; } + // EOF + l.add(sb.toString()); + break; } sb.append(c); } @@ -401,20 +402,18 @@ public class IO { } resetAndSkipFully(in, n); } - } else { - StringBuilder buf = sizeHint > 0 - ? new StringBuilder(sizeHint) - : new StringBuilder(); - int i; - while ((i = in.read()) != -1) { - char c = (char) i; - buf.append(c); - if (c == '\n') { - break; - } + } + StringBuilder buf = sizeHint > 0 ? new StringBuilder(sizeHint) + : new StringBuilder(); + int i; + while ((i = in.read()) != -1) { + char c = (char) i; + buf.append(c); + if (c == '\n') { + break; } - return buf.toString(); } + return buf.toString(); } private static void resetAndSkipFully(Reader fd, long toSkip) throws IOException { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/LfsFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/LfsFactory.java index 96636b7994..85ee095013 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/LfsFactory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/LfsFactory.java @@ -145,7 +145,7 @@ public class LfsFactory { } /** - * Retrieve a pre-push hook to be applied. + * Retrieve a pre-push hook to be applied using the default error stream. * * @param repo * the {@link Repository} the hook is applied to. @@ -159,6 +159,22 @@ public class LfsFactory { } /** + * Retrieve a pre-push hook to be applied. + * + * @param repo + * the {@link Repository} the hook is applied to. + * @param outputStream + * @param errorStream + * @return a {@link PrePushHook} implementation or <code>null</code> + * @since 5.6 + */ + @Nullable + public PrePushHook getPrePushHook(Repository repo, PrintStream outputStream, + PrintStream errorStream) { + return getPrePushHook(repo, outputStream); + } + + /** * Retrieve an {@link LfsInstallCommand} which can be used to enable LFS * support (if available) either per repository or for the user. * diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/QuotedString.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/QuotedString.java index a55cad3705..2b2358abe9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/QuotedString.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/QuotedString.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, Google Inc. + * Copyright (C) 2008, 2019 Google Inc. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -54,7 +54,15 @@ import org.eclipse.jgit.lib.Constants; */ public abstract class QuotedString { /** Quoting style that obeys the rules Git applies to file names */ - public static final GitPathStyle GIT_PATH = new GitPathStyle(); + public static final GitPathStyle GIT_PATH = new GitPathStyle(true); + + /** + * Quoting style that obeys the rules Git applies to file names when + * {@code core.quotePath = false}. + * + * @since 5.6 + */ + public static final QuotedString GIT_PATH_MINIMAL = new GitPathStyle(false); /** * Quoting style used by the Bourne shell. @@ -256,40 +264,48 @@ public abstract class QuotedString { quote['"'] = '"'; } + private final boolean quoteHigh; + @Override public String quote(String instr) { - if (instr.length() == 0) + if (instr.isEmpty()) { return "\"\""; //$NON-NLS-1$ + } boolean reuse = true; final byte[] in = Constants.encode(instr); - final StringBuilder r = new StringBuilder(2 + in.length); - r.append('"'); + final byte[] out = new byte[4 * in.length + 2]; + int o = 0; + out[o++] = '"'; for (int i = 0; i < in.length; i++) { final int c = in[i] & 0xff; if (c < quote.length) { final byte style = quote[c]; if (style == 0) { - r.append((char) c); + out[o++] = (byte) c; continue; } if (style > 0) { reuse = false; - r.append('\\'); - r.append((char) style); + out[o++] = '\\'; + out[o++] = style; continue; } + } else if (!quoteHigh) { + out[o++] = (byte) c; + continue; } reuse = false; - r.append('\\'); - r.append((char) (((c >> 6) & 03) + '0')); - r.append((char) (((c >> 3) & 07) + '0')); - r.append((char) (((c >> 0) & 07) + '0')); + out[o++] = '\\'; + out[o++] = (byte) (((c >> 6) & 03) + '0'); + out[o++] = (byte) (((c >> 3) & 07) + '0'); + out[o++] = (byte) (((c >> 0) & 07) + '0'); } - if (reuse) + if (reuse) { return instr; - r.append('"'); - return r.toString(); + } + out[o++] = '"'; + return new String(out, 0, o, UTF_8); } @Override @@ -375,8 +391,8 @@ public abstract class QuotedString { return RawParseUtils.decode(UTF_8, r, 0, rPtr); } - private GitPathStyle() { - // Singleton + private GitPathStyle(boolean doQuote) { + quoteHigh = doQuote; } } } 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 9663e3cef5..ce1308f334 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RefMap.java @@ -191,12 +191,11 @@ public class RefMap extends AbstractMap<String, Ref> { Ref prior = loose.get(name); loose = loose.set(idx, value); return prior; - } else { - Ref prior = get(keyName); - loose = loose.add(idx, value); - sizeIsValid = false; - return prior; } + Ref prior = get(keyName); + loose = loose.add(idx, value); + sizeIsValid = false; + return prior; } /** {@inheritDoc} */ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java index 9ab2caa1ac..e437c1114b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java @@ -98,15 +98,16 @@ public abstract class LimitedInputStream extends FilterInputStream { @Override public int read() throws IOException { if (left == 0) { - if (in.available() == 0) + if (in.available() == 0) { return -1; - else - limitExceeded(); + } + limitExceeded(); } int result = in.read(); - if (result != -1) + if (result != -1) { --left; + } return result; } @@ -114,16 +115,17 @@ public abstract class LimitedInputStream extends FilterInputStream { @Override public int read(byte[] b, int off, int len) throws IOException { if (left == 0) { - if (in.available() == 0) + if (in.available() == 0) { return -1; - else - limitExceeded(); + } + limitExceeded(); } len = (int) Math.min(len, left); int result = in.read(b, off, len); - if (result != -1) + if (result != -1) { left -= result; + } return result; } @@ -51,7 +51,7 @@ <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit-parent</artifactId> <packaging>pom</packaging> - <version>5.5.2-SNAPSHOT</version> + <version>5.6.1-SNAPSHOT</version> <name>JGit - Parent</name> <url>${jgit-url}</url> @@ -180,6 +180,8 @@ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> <bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest> <jgit-last-release-version>5.4.0.201906121030-r</jgit-last-release-version> @@ -193,16 +195,16 @@ <commons-compress-version>1.18</commons-compress-version> <osgi-core-version>4.3.1</osgi-core-version> <servlet-api-version>3.1.0</servlet-api-version> - <jetty-version>9.4.20.v20190813</jetty-version> + <jetty-version>9.4.22.v20191022</jetty-version> <japicmp-version>0.14.1</japicmp-version> <httpclient-version>4.5.6</httpclient-version> <httpcore-version>4.4.10</httpcore-version> <slf4j-version>1.7.2</slf4j-version> <log4j-version>1.2.15</log4j-version> <maven-javadoc-plugin-version>3.1.1</maven-javadoc-plugin-version> - <tycho-extras-version>1.4.0</tycho-extras-version> + <tycho-extras-version>1.5.1</tycho-extras-version> <gson-version>2.8.2</gson-version> - <bouncycastle-version>1.61</bouncycastle-version> + <bouncycastle-version>1.64</bouncycastle-version> <spotbugs-maven-plugin-version>3.1.12.2</spotbugs-maven-plugin-version> <maven-project-info-reports-plugin-version>3.0.0</maven-project-info-reports-plugin-version> <maven-jxr-plugin-version>3.0.0</maven-jxr-plugin-version> @@ -240,7 +242,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> - <version>3.1.2</version> + <version>3.2.0</version> <configuration> <archive> <manifestEntries> @@ -283,7 +285,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> - <version>3.1.0</version> + <version>3.2.0</version> </plugin> <plugin> @@ -352,7 +354,7 @@ <plugin> <groupId>org.eclipse.cbi.maven.plugins</groupId> <artifactId>eclipse-jarsigner-plugin</artifactId> - <version>1.1.6</version> + <version>1.1.7</version> </plugin> <plugin> <groupId>org.eclipse.tycho.extras</groupId> @@ -367,7 +369,7 @@ <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> - <version>0.8.4</version> + <version>0.8.5</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -377,7 +379,7 @@ <dependency><!-- add support for ssh/scp --> <groupId>org.apache.maven.wagon</groupId> <artifactId>wagon-ssh</artifactId> - <version>3.3.3</version> + <version>3.3.4</version> </dependency> </dependencies> </plugin> @@ -428,7 +430,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> - <version>3.0.0-M2</version> + <version>3.0.0-M3</version> <executions> <execution> <id>enforce-maven</id> @@ -438,7 +440,7 @@ <configuration> <rules> <requireMavenVersion> - <version>3.5.2</version> + <version>3.6.2</version> </requireMavenVersion> </rules> </configuration> @@ -924,7 +926,7 @@ <dependency> <groupId>org.eclipse.jdt</groupId> <artifactId>ecj</artifactId> - <version>3.18.0</version> + <version>3.19.0</version> </dependency> </dependencies> </plugin> diff --git a/tools/bazelisk_version.bzl b/tools/bazelisk_version.bzl new file mode 100644 index 0000000000..d8b3d10982 --- /dev/null +++ b/tools/bazelisk_version.bzl @@ -0,0 +1,16 @@ +_template = """ +load("@bazel_skylib//lib:versions.bzl", "versions") + +def check_bazel_version(): + versions.check(minimum_bazel_version = "{version}") +""".strip() + +def _impl(repository_ctx): + repository_ctx.symlink(Label("@//:.bazelversion"), ".bazelversion") + bazelversion = repository_ctx.read(".bazelversion").strip() + + repository_ctx.file("BUILD", executable = False) + + repository_ctx.file("check.bzl", executable = False, content = _template.format(version = bazelversion)) + +bazelisk_version = repository_rule(implementation = _impl) |