Merge branch 'master' into stable-7.5 * master: InterruptTimer: don't use Yoda-style condition InterruptTimer: avoid expensive notify when begin is soon after end InterruptTimer: avoid unneeded notify for end() Disable MergeToolTest#testEmptyToolName Fix hamcrest version to 3.0.0 in target platform Add InterruptTimer Tests Update slf4j to 2.0.17 Update org.hamcrest to 3.0.0 DfsPackFile: asObjectIdSet() when only inclusion is needed. DfsObjDatabase: read reftables from midx covered packs Update jetty to 12.1.3 Fix signed push failing when using push options DfsReader/PackFile: Move bitmap inclusion check to the packfile Use generic Map interface in signature of internal API methods Allow to discover bitmap on disk created after the packfile DfsPackCompactor: add toPrune method MidxPackList: Helper to get packs/midx and overlaps between them DfsPackFileMidx: make the class public [ssh] Fix order of keys in pubkey auth if an agent is used Update bytebuddy to 1.17.8 Update jetty to 12.1.2 DfsPackCompactor: Move #autoAdd to the tests (its only caller) DfsPackFileMidx: add #getAllCoveredPacks() method DfsGarbageCollector: handle pack lists with multipack indexes DfsPackFileMidx: Return bitmap from any underlying pack midx: caller chooses the order of packs in the midx DfsObjDatabase: make #setUseMultipackIndex public MidxPackFilterTest: Remove unused import DfsObjDatabase: move pack mangling to helper MidxPackFilter Document how to test a release staged in Maven Central Portal DfsMidxWriter: helper class to create a pack with an midx DfsObjDatabase: make useMultipackIndex getter/setter protected Update Maven plugins DfsObjDatabase: introduce multipack index Prepare 5.13.6-SNAPSHOT builds JGit v5.13.5.202508271544-r Remove resolver option from target-platform-configuration Add missing release property to maven build Suppress API errors for minor API changes in service releases Remove unnecessary casts Change-Id: I6fba55292e9948ae74808e4c0883742b4048c2ac
diff --git a/WORKSPACE b/WORKSPACE index b690564..644e283 100644 --- a/WORKSPACE +++ b/WORKSPACE
@@ -142,16 +142,18 @@ sha1 = "a3fcc5d3c29b2b03433aa2d2f2d2c1b1638924a1", ) +SLF4J_VERS = "2.0.17" + maven_jar( name = "log-api", - artifact = "org.slf4j:slf4j-api:1.7.36", - sha1 = "6c62681a2f655b49963a5983b8b0950a6120ae14", + artifact = "org.slf4j:slf4j-api:" + SLF4J_VERS, + sha1 = "d9e58ac9c7779ba3bf8142aff6c830617a7fe60f", ) maven_jar( name = "slf4j-simple", - artifact = "org.slf4j:slf4j-simple:1.7.36", - sha1 = "a41f9cfe6faafb2eb83a1c7dd2d0dfd844e2a936", + artifact = "org.slf4j:slf4j-simple:" + SLF4J_VERS, + sha1 = "9872a3fd794ffe7b18d17747926a64d61526ca96", ) maven_jar( @@ -198,8 +200,8 @@ maven_jar( name = "hamcrest", - artifact = "org.hamcrest:hamcrest:2.2", - sha1 = "1820c0968dba3a11a1b30669bb1f01978a91dedc", + artifact = "org.hamcrest:hamcrest:3.0", + sha1 = "8fd9b78a8e6a6510a078a9e30e9e86a6035cfaf7", ) maven_jar( @@ -214,18 +216,18 @@ sha1 = "8f34ccd6808899ad1d0aac6a770b73191f2f2a53", ) -BYTE_BUDDY_VERSION = "1.17.7" +BYTE_BUDDY_VERSION = "1.17.8" maven_jar( name = "bytebuddy", artifact = "net.bytebuddy:byte-buddy:" + BYTE_BUDDY_VERSION, - sha1 = "3856bfab61beb23e099a0d6629f2ba8de4b98ace", + sha1 = "af5735f63d00ca47a9375fae5c7471a36331c6ed", ) maven_jar( name = "bytebuddy-agent", artifact = "net.bytebuddy:byte-buddy-agent:" + BYTE_BUDDY_VERSION, - sha1 = "fbf3d6d649ed37fc9e9c59480a05be0a26e3c2da", + sha1 = "f09415827a71be7ed621c7bd02550678f28bc81c", ) maven_jar( @@ -240,54 +242,54 @@ sha1 = "48b8230771e573b54ce6e867a9001e75977fe78e", ) -JETTY_VER = "12.1.1" +JETTY_VER = "12.1.3" maven_jar( name = "jetty-servlet", artifact = "org.eclipse.jetty.ee10:jetty-ee10-servlet:" + JETTY_VER, - sha1 = "28e6e238d77f94d71714945a7d064fedcefa6918", + sha1 = "b2709dddac048fb03735c9ea85673dbfcec8bdfc", ) maven_jar( name = "jetty-security", artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VER, - sha1 = "089c47852a9ac216e66b2d3d2e12b8721b9b8ca2", + sha1 = "f40cb316ef0e9a168f59eaf0b2d0440b7adcb1f8", ) maven_jar( name = "jetty-server", artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VER, - sha1 = "4a34529a4737bcc4868186914a72a097edee1a52", + sha1 = "7741aafcd7d6dc718d04d4cfb883982e361d6577", ) maven_jar( name = "jetty-session", artifact = "org.eclipse.jetty:jetty-session:" + JETTY_VER, - sha1 = "7db390e7856c75e001b1ade978e27397dcbc97eb", + sha1 = "0837f081a357a2c835a96ceaa09445921a33b0e9", ) maven_jar( name = "jetty-http", artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VER, - sha1 = "4c087942e5cdaf4b716146312f9ff4c5a1e289d9", + sha1 = "3822fb03ec85e4157cf68c1ac661b5d06fd19b25", ) maven_jar( name = "jetty-io", artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VER, - sha1 = "f9efcb4d69ee757721c5f0f3bf4cd55b48a44b48", + sha1 = "2c46bf53f41e40df72ff457c40553da2ace7b956", ) maven_jar( name = "jetty-util", artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VER, - sha1 = "582a66cbad2b577ad11b7945e434bd5732c1e45d", + sha1 = "9606f6cc440419f62214ceaa2c8ab4b312baf6be", ) maven_jar( name = "jetty-util-ajax", artifact = "org.eclipse.jetty:jetty-util-ajax:" + JETTY_VER, - sha1 = "81d03427b838dfc994c072eadd69e8a8a3802c0d", + sha1 = "d0b0a631434ca2cf5a913d2852893779bfecebf8", ) BOUNCYCASTLE_VER = "1.82"
diff --git a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF index 1dde9aa..0157b21 100644 --- a/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ant.test/META-INF/MANIFEST.MF
@@ -14,5 +14,5 @@ org.eclipse.jgit.junit;version="[7.5.0,7.6.0)", org.eclipse.jgit.lib;version="[7.5.0,7.6.0)", org.eclipse.jgit.util;version="[7.5.0,7.6.0)", - org.hamcrest.core;version="[1.1.0,3.0.0)", + org.hamcrest;version="[3.0.0,4.0.0)", org.junit;version="[4.13,5.0.0)"
diff --git a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF index 44a76a1..10544b6 100644 --- a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
@@ -8,7 +8,6 @@ Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Require-Bundle: org.hamcrest.core;bundle-version="[1.3.0,2.0.0)" Import-Package: org.bouncycastle.asn1.cryptlib;version="[1.80.0,2.0.0)", org.bouncycastle.jce.provider;version="[1.80.0,2.0.0)", org.bouncycastle.openpgp;version="[1.80.0,2.0.0)", @@ -18,6 +17,7 @@ org.eclipse.jgit.gpg.bc.internal;version="[7.5.0,7.6.0)", org.eclipse.jgit.gpg.bc.internal.keys;version="[7.5.0,7.6.0)", org.eclipse.jgit.util.sha1;version="[7.5.0,7.6.0)", + org.hamcrest;version="[3.0.0,4.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.runner;version="[4.13,5.0.0)", org.junit.runners;version="[4.13,5.0.0)"
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF index d1d82a8..8c4b4cb 100644 --- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
@@ -8,8 +8,6 @@ Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Require-Bundle: org.hamcrest.core;bundle-version="[1.3.0,2.0.0)", - org.hamcrest.library;bundle-version="[1.3.0,2.0.0)" Import-Package: jakarta.servlet;version="[6.0.0,7.0.0)", jakarta.servlet.http;version="[6.0.0,7.0.0)", net.bytebuddy.agent;version="[1.9.0,2.0.0)", @@ -50,6 +48,7 @@ org.eclipse.jgit.transport.http.apache;version="[7.5.0,7.6.0)", org.eclipse.jgit.transport.resolver;version="[7.5.0,7.6.0)", org.eclipse.jgit.util;version="[7.5.0,7.6.0)", + org.hamcrest;version="[3.0.0,4.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.rules;version="[4.13,5.0.0)", org.junit.runner;version="[4.13,5.0.0)",
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 b7bd24d..cbe0465 100644 --- a/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.server.test/META-INF/MANIFEST.MF
@@ -45,7 +45,7 @@ org.eclipse.jgit.treewalk;version="[7.5.0,7.6.0)", org.eclipse.jgit.treewalk.filter;version="[7.5.0,7.6.0)", org.eclipse.jgit.util;version="[7.5.0,7.6.0)", - org.hamcrest.core;version="[1.1.0,3.0.0)", + org.hamcrest;version="[3.0.0,4.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.rules;version="[4.13,5.0.0)", org.junit.runner;version="[4.13,5.0.0)",
diff --git a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF index f460a8c..cc1b4cc 100644 --- a/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.lfs.test/META-INF/MANIFEST.MF
@@ -24,7 +24,7 @@ org.eclipse.jgit.treewalk;version="[7.5.0,7.6.0)", org.eclipse.jgit.treewalk.filter;version="[7.5.0,7.6.0)", org.eclipse.jgit.util;version="[7.5.0,7.6.0)", - org.hamcrest.core;version="[1.1.0,3.0.0)", + org.hamcrest;version="[3.0.0,4.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.runner;version="[4.13,5.0.0)", org.junit.runners;version="[4.13,5.0.0)"
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml index eef699c..08294c7 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.repository/category.xml
@@ -234,6 +234,24 @@ <bundle id="org.osgi.service.cm.source"> <category name="JGit-dependency-bundles"/> </bundle> + <bundle id="org.objectweb.asm"> + <category name="JGit-dependency-bundles"/> + </bundle> + <bundle id="org.objectweb.asm.commons"> + <category name="JGit-dependency-bundles"/> + </bundle> + <bundle id="org.objectweb.asm.util"> + <category name="JGit-dependency-bundles"/> + </bundle> + <bundle id="org.objectweb.asm.tree"> + <category name="JGit-dependency-bundles"/> + </bundle> + <bundle id="org.objectweb.asm.tree.analysis"> + <category name="JGit-dependency-bundles"/> + </bundle> + <bundle id="org.apache.aries.spifly.dynamic.bundle"> + <category name="JGit-dependency-bundles"/> + </bundle> <category-def name="JGit" label="Java implementation of Git"> <description> Java implementation of Git
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.target deleted file mode 100644 index a91976c..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.target +++ /dev/null
@@ -1,288 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.32" sequenceNumber="1759825554"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.4.0"/> - <unit id="org.objenesis.source" version="3.4.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024-06"/> - </location> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.osgi" version="0.0.0"/> - <repository location="https://download.eclipse.org/staging/2024-06/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.10</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.16.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.20.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.18.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.18.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.1.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.13.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.17.7</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.17.7</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.82</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.82</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.82</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.82</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.27.6</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.37</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.19.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.28.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-lang3</artifactId> - <version>3.19.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.20.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.3.5</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.tpd deleted file mode 100644 index b8574c7..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.32" with source configurePhase - -include "orbit/orbit-4.32.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/staging/2024-06/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.target deleted file mode 100644 index 220a42a..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.target +++ /dev/null
@@ -1,288 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde?> -<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.33" sequenceNumber="1759825555"> - <locations> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/> - <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/> - <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> - <unit id="org.apache.ant" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.ant.source" version="1.10.14.v20230922-1200"/> - <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> - <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> - <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> - <unit id="org.junit" version="4.13.2.v20230809-1000"/> - <unit id="org.junit.source" version="4.13.2.v20230809-1000"/> - <unit id="org.objenesis" version="3.4.0"/> - <unit id="org.objenesis.source" version="3.4.0"/> - <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> - <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/> - <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024-09"/> - </location> - <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> - <unit id="org.eclipse.osgi" version="0.0.0"/> - <repository location="https://download.eclipse.org/releases/2024-09/"/> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz"> - <dependencies> - <dependency> - <groupId>org.tukaani</groupId> - <artifactId>xz</artifactId> - <version>1.10</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j"> - <dependencies> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd"> - <dependencies> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-osgi</artifactId> - <version>2.16.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-sftp</artifactId> - <version>2.16.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito"> - <dependencies> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>5.20.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna"> - <dependencies> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna</artifactId> - <version>5.18.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.java.dev.jna</groupId> - <artifactId>jna-platform</artifactId> - <version>5.18.1</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty"> - <dependencies> - <dependency> - <groupId>org.eclipse.jetty.ee10</groupId> - <artifactId>jetty-ee10-servlet</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-session</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util-ajax</artifactId> - <version>12.1.1</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>jakarta.servlet</groupId> - <artifactId>jakarta.servlet-api</artifactId> - <version>6.1.0</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah"> - <dependencies> - <dependency> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - <version>1.2.3</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest"> - <dependencies> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest</artifactId> - <version>2.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson"> - <dependencies> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.13.2</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy"> - <dependencies> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy</artifactId> - <version>1.17.7</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>net.bytebuddy</groupId> - <artifactId>byte-buddy-agent</artifactId> - <version>1.17.7</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle"> - <dependencies> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpg-jdk18on</artifactId> - <version>1.82</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcprov-jdk18on</artifactId> - <version>1.82</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcpkix-jdk18on</artifactId> - <version>1.82</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.bouncycastle</groupId> - <artifactId>bcutil-jdk18on</artifactId> - <version>1.82</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj"> - <dependencies> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.27.6</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j"> - <dependencies> - <dependency> - <groupId>args4j</groupId> - <artifactId>args4j</artifactId> - <version>2.37</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache"> - <dependencies> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>1.19.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-compress</artifactId> - <version>1.28.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-lang3</artifactId> - <version>3.19.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.20.0</version> - <type>jar</type> - </dependency> - <dependency> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - <version>1.3.5</version> - <type>jar</type> - </dependency> - </dependencies> - </location> - </locations> -</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.tpd deleted file mode 100644 index 74c6878..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.tpd +++ /dev/null
@@ -1,8 +0,0 @@ -target "jgit-4.33" with source configurePhase - -include "orbit/orbit-4.33.tpd" -include "maven/dependencies.tpd" - -location "https://download.eclipse.org/releases/2024-09/" { - org.eclipse.osgi lazy -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target index 95494e8..c323c45 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.34" sequenceNumber="1759825554"> +<target name="jgit-4.34" sequenceNumber="1761604946"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -10,16 +10,20 @@ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> <unit id="org.apache.ant" version="1.10.15.v20240901-1000"/> <unit id="org.apache.ant.source" version="1.10.15.v20240901-1000"/> + <unit id="org.apache.aries.spifly.dynamic.bundle" version="1.3.7"/> <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest" version="3.0.0"/> + <unit id="org.hamcrest.source" version="3.0.0"/> <unit id="org.junit" version="4.13.2.v20240929-1000"/> <unit id="org.junit.source" version="4.13.2.v20240929-1000"/> + <unit id="org.objectweb.asm" version="9.7.1"/> + <unit id="org.objectweb.asm.commons" version="9.7.1"/> + <unit id="org.objectweb.asm.util" version="9.7.1"/> + <unit id="org.objectweb.asm.tree" version="9.7.1"/> + <unit id="org.objectweb.asm.tree.analysis" version="9.7.1"/> <unit id="org.objenesis" version="3.4.0"/> <unit id="org.objenesis.source" version="3.4.0"/> <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> @@ -45,13 +49,13 @@ <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> + <version>2.0.17</version> <type>jar</type> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> + <version>2.0.17</version> <type>jar</type> </dependency> </dependencies> @@ -103,49 +107,49 @@ <dependency> <groupId>org.eclipse.jetty.ee10</groupId> <artifactId>jetty-ee10-servlet</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-http</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-io</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-security</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-session</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util-ajax</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> @@ -171,7 +175,7 @@ <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest</artifactId> - <version>2.2</version> + <version>3.0</version> <type>jar</type> </dependency> </dependencies> @@ -191,13 +195,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.17.7</version> + <version>1.17.8</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.17.7</version> + <version>1.17.8</version> <type>jar</type> </dependency> </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target index dd06ccd..baf1e3b 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.35" sequenceNumber="1759825554"> +<target name="jgit-4.35" sequenceNumber="1761604946"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -10,16 +10,20 @@ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> <unit id="org.apache.ant" version="1.10.15.v20240901-1000"/> <unit id="org.apache.ant.source" version="1.10.15.v20240901-1000"/> + <unit id="org.apache.aries.spifly.dynamic.bundle" version="1.3.7"/> <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest" version="3.0.0"/> + <unit id="org.hamcrest.source" version="3.0.0"/> <unit id="org.junit" version="4.13.2.v20240929-1000"/> <unit id="org.junit.source" version="4.13.2.v20240929-1000"/> + <unit id="org.objectweb.asm" version="9.7.1"/> + <unit id="org.objectweb.asm.commons" version="9.7.1"/> + <unit id="org.objectweb.asm.util" version="9.7.1"/> + <unit id="org.objectweb.asm.tree" version="9.7.1"/> + <unit id="org.objectweb.asm.tree.analysis" version="9.7.1"/> <unit id="org.objenesis" version="3.4.0"/> <unit id="org.objenesis.source" version="3.4.0"/> <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> @@ -45,13 +49,13 @@ <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> + <version>2.0.17</version> <type>jar</type> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> + <version>2.0.17</version> <type>jar</type> </dependency> </dependencies> @@ -103,49 +107,49 @@ <dependency> <groupId>org.eclipse.jetty.ee10</groupId> <artifactId>jetty-ee10-servlet</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-http</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-io</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-security</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-session</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util-ajax</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> @@ -171,7 +175,7 @@ <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest</artifactId> - <version>2.2</version> + <version>3.0</version> <type>jar</type> </dependency> </dependencies> @@ -191,13 +195,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.17.7</version> + <version>1.17.8</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.17.7</version> + <version>1.17.8</version> <type>jar</type> </dependency> </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target index e6cf65a..298bc2a 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.36" sequenceNumber="1759825554"> +<target name="jgit-4.36" sequenceNumber="1761604946"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -10,16 +10,20 @@ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> <unit id="org.apache.ant" version="1.10.15.v20240901-1000"/> <unit id="org.apache.ant.source" version="1.10.15.v20240901-1000"/> + <unit id="org.apache.aries.spifly.dynamic.bundle" version="1.3.7"/> <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest" version="3.0.0"/> + <unit id="org.hamcrest.source" version="3.0.0"/> <unit id="org.junit" version="4.13.2.v20240929-1000"/> <unit id="org.junit.source" version="4.13.2.v20240929-1000"/> + <unit id="org.objectweb.asm" version="9.8.0"/> + <unit id="org.objectweb.asm.commons" version="9.8.0"/> + <unit id="org.objectweb.asm.util" version="9.8.0"/> + <unit id="org.objectweb.asm.tree" version="9.8.0"/> + <unit id="org.objectweb.asm.tree.analysis" version="9.8.0"/> <unit id="org.objenesis" version="3.4.0"/> <unit id="org.objenesis.source" version="3.4.0"/> <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> @@ -45,13 +49,13 @@ <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> + <version>2.0.17</version> <type>jar</type> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> + <version>2.0.17</version> <type>jar</type> </dependency> </dependencies> @@ -103,49 +107,49 @@ <dependency> <groupId>org.eclipse.jetty.ee10</groupId> <artifactId>jetty-ee10-servlet</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-http</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-io</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-security</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-session</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util-ajax</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> @@ -171,7 +175,7 @@ <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest</artifactId> - <version>2.2</version> + <version>3.0</version> <type>jar</type> </dependency> </dependencies> @@ -191,13 +195,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.17.7</version> + <version>1.17.8</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.17.7</version> + <version>1.17.8</version> <type>jar</type> </dependency> </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target index 3765962..ec93cd0 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.37" sequenceNumber="1759825554"> +<target name="jgit-4.37" sequenceNumber="1761604946"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -10,16 +10,20 @@ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> <unit id="org.apache.ant" version="1.10.15.v20240901-1000"/> <unit id="org.apache.ant.source" version="1.10.15.v20240901-1000"/> + <unit id="org.apache.aries.spifly.dynamic.bundle" version="1.3.7"/> <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest" version="3.0.0"/> + <unit id="org.hamcrest.source" version="3.0.0"/> <unit id="org.junit" version="4.13.2.v20240929-1000"/> <unit id="org.junit.source" version="4.13.2.v20240929-1000"/> + <unit id="org.objectweb.asm" version="9.8.0"/> + <unit id="org.objectweb.asm.commons" version="9.8.0"/> + <unit id="org.objectweb.asm.util" version="9.8.0"/> + <unit id="org.objectweb.asm.tree" version="9.8.0"/> + <unit id="org.objectweb.asm.tree.analysis" version="9.8.0"/> <unit id="org.objenesis" version="3.4.0"/> <unit id="org.objenesis.source" version="3.4.0"/> <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> @@ -45,13 +49,13 @@ <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> + <version>2.0.17</version> <type>jar</type> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> + <version>2.0.17</version> <type>jar</type> </dependency> </dependencies> @@ -103,49 +107,49 @@ <dependency> <groupId>org.eclipse.jetty.ee10</groupId> <artifactId>jetty-ee10-servlet</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-http</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-io</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-security</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-session</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util-ajax</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> @@ -171,7 +175,7 @@ <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest</artifactId> - <version>2.2</version> + <version>3.0</version> <type>jar</type> </dependency> </dependencies> @@ -191,13 +195,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.17.7</version> + <version>1.17.8</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.17.7</version> + <version>1.17.8</version> <type>jar</type> </dependency> </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target index 71ac500..c0f3dd9 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.38" sequenceNumber="1759825922"> +<target name="jgit-4.38" sequenceNumber="1761604947"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -10,16 +10,20 @@ <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/> <unit id="org.apache.ant" version="1.10.15.v20240901-1000"/> <unit id="org.apache.ant.source" version="1.10.15.v20240901-1000"/> + <unit id="org.apache.aries.spifly.dynamic.bundle" version="1.3.7"/> <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/> <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/> <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/> <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/> - <unit id="org.hamcrest.core" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.core.source" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library" version="1.3.0.v20230809-1000"/> - <unit id="org.hamcrest.library.source" version="1.3.0.v20230809-1000"/> + <unit id="org.hamcrest" version="3.0.0"/> + <unit id="org.hamcrest.source" version="3.0.0"/> <unit id="org.junit" version="4.13.2.v20240929-1000"/> <unit id="org.junit.source" version="4.13.2.v20240929-1000"/> + <unit id="org.objectweb.asm" version="9.9.0"/> + <unit id="org.objectweb.asm.commons" version="9.9.0"/> + <unit id="org.objectweb.asm.util" version="9.9.0"/> + <unit id="org.objectweb.asm.tree" version="9.9.0"/> + <unit id="org.objectweb.asm.tree.analysis" version="9.9.0"/> <unit id="org.objenesis" version="3.4.0"/> <unit id="org.objenesis.source" version="3.4.0"/> <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/> @@ -45,13 +49,13 @@ <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> - <version>1.7.36</version> + <version>2.0.17</version> <type>jar</type> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> - <version>1.7.36</version> + <version>2.0.17</version> <type>jar</type> </dependency> </dependencies> @@ -103,49 +107,49 @@ <dependency> <groupId>org.eclipse.jetty.ee10</groupId> <artifactId>jetty-ee10-servlet</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-http</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-io</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-security</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-session</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util-ajax</artifactId> - <version>12.1.1</version> + <version>12.1.3</version> <type>jar</type> </dependency> <dependency> @@ -171,7 +175,7 @@ <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest</artifactId> - <version>2.2</version> + <version>3.0</version> <type>jar</type> </dependency> </dependencies> @@ -191,13 +195,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.17.7</version> + <version>1.17.8</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.17.7</version> + <version>1.17.8</version> <type>jar</type> </dependency> </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd index 2f2f0b3..5e4f998 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd
@@ -97,12 +97,12 @@ dependency { groupId = "net.bytebuddy" artifactId = "byte-buddy" - version = "1.17.7" + version = "1.17.8" } dependency { groupId = "net.bytebuddy" artifactId = "byte-buddy-agent" - version = "1.17.7" + version = "1.17.8" } } @@ -128,7 +128,7 @@ dependency { groupId = "org.hamcrest" artifactId = "hamcrest" - version = "2.2" + version = "3.0" } } @@ -154,42 +154,42 @@ dependency { groupId = "org.eclipse.jetty.ee10" artifactId = "jetty-ee10-servlet" - version = "12.1.1" + version = "12.1.3" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-http" - version = "12.1.1" + version = "12.1.3" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-io" - version = "12.1.1" + version = "12.1.3" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-security" - version = "12.1.1" + version = "12.1.3" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-server" - version = "12.1.1" + version = "12.1.3" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-session" - version = "12.1.1" + version = "12.1.3" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-util" - version = "12.1.1" + version = "12.1.3" } dependency { groupId = "org.eclipse.jetty" artifactId = "jetty-util-ajax" - version = "12.1.1" + version = "12.1.3" } dependency { groupId = "jakarta.servlet" @@ -256,12 +256,12 @@ dependency { groupId = "org.slf4j" artifactId = "slf4j-api" - version = "1.7.36" + version = "2.0.17" } dependency { groupId = "org.slf4j" artifactId = "slf4j-simple" - version = "1.7.36" + version = "2.0.17" } }
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.32.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.32.tpd deleted file mode 100644 index 59fcd87..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.32.tpd +++ /dev/null
@@ -1,25 +0,0 @@ -target "orbit-4.32" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024-06" { - com.jcraft.jsch [0.1.55.v20230916-1400,0.1.55.v20230916-1400] - com.jcraft.jsch.source [0.1.55.v20230916-1400,0.1.55.v20230916-1400] - com.jcraft.jzlib [1.1.3.v20230916-1400,1.1.3.v20230916-1400] - com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] - org.apache.ant [1.10.14.v20230922-1200,1.10.14.v20230922-1200] - org.apache.ant.source [1.10.14.v20230922-1200,1.10.14.v20230922-1200] - org.apache.httpcomponents.httpclient [4.5.14,4.5.14] - org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14] - org.apache.httpcomponents.httpcore [4.4.16,4.4.16] - org.apache.httpcomponents.httpcore.source [4.4.16,4.4.16] - org.hamcrest.core [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.core.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.junit [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.junit.source [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.objenesis [3.4,3.4] - org.objenesis.source [3.4,3.4] - org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733] - org.osgi.service.cm.source [1.6.1.202109301733,1.6.1.202109301733] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.33.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.33.tpd deleted file mode 100644 index 2cfa0a8..0000000 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.33.tpd +++ /dev/null
@@ -1,25 +0,0 @@ -target "orbit-4.33" with source configurePhase -// see https://download.eclipse.org/tools/orbit/downloads/ - -location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2024-09" { - com.jcraft.jsch [0.1.55.v20230916-1400,0.1.55.v20230916-1400] - com.jcraft.jsch.source [0.1.55.v20230916-1400,0.1.55.v20230916-1400] - com.jcraft.jzlib [1.1.3.v20230916-1400,1.1.3.v20230916-1400] - com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] - org.apache.ant [1.10.14.v20230922-1200,1.10.14.v20230922-1200] - org.apache.ant.source [1.10.14.v20230922-1200,1.10.14.v20230922-1200] - org.apache.httpcomponents.httpclient [4.5.14,4.5.14] - org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14] - org.apache.httpcomponents.httpcore [4.4.16,4.4.16] - org.apache.httpcomponents.httpcore.source [4.4.16,4.4.16] - org.hamcrest.core [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.core.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.junit [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.junit.source [4.13.2.v20230809-1000,4.13.2.v20230809-1000] - org.objenesis [3.4,3.4] - org.objenesis.source [3.4,3.4] - org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733] - org.osgi.service.cm.source [1.6.1.202109301733,1.6.1.202109301733] -}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.34.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.34.tpd index d3e15bb..d3c2f2f 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.34.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.34.tpd
@@ -8,16 +8,20 @@ com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] org.apache.ant [1.10.15.v20240901-1000,1.10.15.v20240901-1000] org.apache.ant.source [1.10.15.v20240901-1000,1.10.15.v20240901-1000] + org.apache.aries.spifly.dynamic.bundle [1.3.7,1.3.7] org.apache.httpcomponents.httpclient [4.5.14,4.5.14] org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14] org.apache.httpcomponents.httpcore [4.4.16,4.4.16] org.apache.httpcomponents.httpcore.source [4.4.16,4.4.16] - org.hamcrest.core [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.core.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] + org.hamcrest [3.0.0,3.0.0] + org.hamcrest.source [3.0.0,3.0.0] org.junit [4.13.2.v20240929-1000,4.13.2.v20240929-1000] org.junit.source [4.13.2.v20240929-1000,4.13.2.v20240929-1000] + org.objectweb.asm [9.7.1,9.7.1] + org.objectweb.asm.commons [9.7.1,9.7.1] + org.objectweb.asm.util [9.7.1,9.7.1] + org.objectweb.asm.tree [9.7.1,9.7.1] + org.objectweb.asm.tree.analysis [9.7.1,9.7.1] org.objenesis [3.4,3.4] org.objenesis.source [3.4,3.4] org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733]
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.35.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.35.tpd index ec6996e..f5f9a08 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.35.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.35.tpd
@@ -8,16 +8,20 @@ com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] org.apache.ant [1.10.15.v20240901-1000,1.10.15.v20240901-1000] org.apache.ant.source [1.10.15.v20240901-1000,1.10.15.v20240901-1000] + org.apache.aries.spifly.dynamic.bundle [1.3.7,1.3.7] org.apache.httpcomponents.httpclient [4.5.14,4.5.14] org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14] org.apache.httpcomponents.httpcore [4.4.16,4.4.16] org.apache.httpcomponents.httpcore.source [4.4.16,4.4.16] - org.hamcrest.core [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.core.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] + org.hamcrest [3.0.0,3.0.0] + org.hamcrest.source [3.0.0,3.0.0] org.junit [4.13.2.v20240929-1000,4.13.2.v20240929-1000] org.junit.source [4.13.2.v20240929-1000,4.13.2.v20240929-1000] + org.objectweb.asm [9.7.1,9.7.1] + org.objectweb.asm.commons [9.7.1,9.7.1] + org.objectweb.asm.util [9.7.1,9.7.1] + org.objectweb.asm.tree [9.7.1,9.7.1] + org.objectweb.asm.tree.analysis [9.7.1,9.7.1] org.objenesis [3.4,3.4] org.objenesis.source [3.4,3.4] org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733]
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.36.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.36.tpd index 4f46583..b60e90d 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.36.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.36.tpd
@@ -8,16 +8,20 @@ com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] org.apache.ant [1.10.15.v20240901-1000,1.10.15.v20240901-1000] org.apache.ant.source [1.10.15.v20240901-1000,1.10.15.v20240901-1000] + org.apache.aries.spifly.dynamic.bundle [1.3.7,1.3.7] org.apache.httpcomponents.httpclient [4.5.14,4.5.14] org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14] org.apache.httpcomponents.httpcore [4.4.16,4.4.16] org.apache.httpcomponents.httpcore.source [4.4.16,4.4.16] - org.hamcrest.core [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.core.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] + org.hamcrest [3.0.0,3.0.0] + org.hamcrest.source [3.0.0,3.0.0] org.junit [4.13.2.v20240929-1000,4.13.2.v20240929-1000] org.junit.source [4.13.2.v20240929-1000,4.13.2.v20240929-1000] + org.objectweb.asm [9.8.0,9.8.0] + org.objectweb.asm.commons [9.8.0,9.8.0] + org.objectweb.asm.util [9.8.0,9.8.0] + org.objectweb.asm.tree [9.8.0,9.8.0] + org.objectweb.asm.tree.analysis [9.8.0,9.8.0] org.objenesis [3.4,3.4] org.objenesis.source [3.4,3.4] org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733]
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.37.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.37.tpd index 9c1ba4f..c142490 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.37.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.37.tpd
@@ -8,16 +8,20 @@ com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] org.apache.ant [1.10.15.v20240901-1000,1.10.15.v20240901-1000] org.apache.ant.source [1.10.15.v20240901-1000,1.10.15.v20240901-1000] + org.apache.aries.spifly.dynamic.bundle [1.3.7,1.3.7] org.apache.httpcomponents.httpclient [4.5.14,4.5.14] org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14] org.apache.httpcomponents.httpcore [4.4.16,4.4.16] org.apache.httpcomponents.httpcore.source [4.4.16,4.4.16] - org.hamcrest.core [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.core.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] + org.hamcrest [3.0.0,3.0.0] + org.hamcrest.source [3.0.0,3.0.0] org.junit [4.13.2.v20240929-1000,4.13.2.v20240929-1000] org.junit.source [4.13.2.v20240929-1000,4.13.2.v20240929-1000] + org.objectweb.asm [9.8.0,9.8.0] + org.objectweb.asm.commons [9.8.0,9.8.0] + org.objectweb.asm.util [9.8.0,9.8.0] + org.objectweb.asm.tree [9.8.0,9.8.0] + org.objectweb.asm.tree.analysis [9.8.0,9.8.0] org.objenesis [3.4,3.4] org.objenesis.source [3.4,3.4] org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733]
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.38.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.38.tpd index cfa3682..7601cc4 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.38.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.38.tpd
@@ -8,16 +8,20 @@ com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400] org.apache.ant [1.10.15.v20240901-1000,1.10.15.v20240901-1000] org.apache.ant.source [1.10.15.v20240901-1000,1.10.15.v20240901-1000] + org.apache.aries.spifly.dynamic.bundle [1.3.7,1.3.7] org.apache.httpcomponents.httpclient [4.5.14,4.5.14] org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14] org.apache.httpcomponents.httpcore [4.4.16,4.4.16] org.apache.httpcomponents.httpcore.source [4.4.16,4.4.16] - org.hamcrest.core [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.core.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library [1.3.0.v20230809-1000,1.3.0.v20230809-1000] - org.hamcrest.library.source [1.3.0.v20230809-1000,1.3.0.v20230809-1000] + org.hamcrest [3.0.0,3.0.0] + org.hamcrest.source [3.0.0,3.0.0] org.junit [4.13.2.v20240929-1000,4.13.2.v20240929-1000] org.junit.source [4.13.2.v20240929-1000,4.13.2.v20240929-1000] + org.objectweb.asm [9.9.0,9.9.0] + org.objectweb.asm.commons [9.9.0,9.9.0] + org.objectweb.asm.util [9.9.0,9.9.0] + org.objectweb.asm.tree [9.9.0,9.9.0] + org.objectweb.asm.tree.analysis [9.9.0,9.9.0] org.objenesis [3.4,3.4] org.objenesis.source [3.4,3.4] org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733]
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml index 8215c2c..301ed91 100644 --- a/org.eclipse.jgit.packaging/pom.xml +++ b/org.eclipse.jgit.packaging/pom.xml
@@ -31,7 +31,7 @@ <properties> <java.version>17</java.version> <tycho-version>4.0.13</tycho-version> - <target-platform>jgit-4.32</target-platform> + <target-platform>jgit-4.34</target-platform> <project.build.outputTimestamp>${git.commit.time}</project.build.outputTimestamp> </properties>
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java index 1844223..a7df4fa 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java
@@ -16,8 +16,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; -import java.util.HashMap; -import java.util.Map; +import java.util.LinkedHashMap; import org.eclipse.jgit.internal.storage.file.ObjectDirectory; import org.eclipse.jgit.internal.storage.file.Pack; @@ -87,7 +86,7 @@ private void writeMultiPackIndex() throws IOException { ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase(); - Map<String, PackIndex> indexes = new HashMap<>(); + LinkedHashMap<String, PackIndex> indexes = new LinkedHashMap<>(); for (Pack pack : odb.getPacks()) { PackFile packFile = pack.getPackFile().create(PackExt.INDEX); try {
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 c74fa22..c10f613 100644 --- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
@@ -8,8 +8,8 @@ Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Require-Bundle: org.hamcrest.core;bundle-version="[1.3.0,2.0.0)" -Import-Package: org.apache.sshd.certificate;version="[2.16.0,2.17.0)", +Import-Package: org.apache.sshd.agent;version="[2.16.0,2.17.0)", + org.apache.sshd.certificate;version="[2.16.0,2.17.0)", org.apache.sshd.client.config.hosts;version="[2.16.0,2.17.0)", org.apache.sshd.common;version="[2.16.0,2.17.0)", org.apache.sshd.common.auth;version="[2.16.0,2.17.0)", @@ -42,6 +42,7 @@ org.eclipse.jgit.transport.sshd;version="[7.5.0,7.6.0)", org.eclipse.jgit.transport.sshd.agent;version="[7.5.0,7.6.0)", org.eclipse.jgit.util;version="[7.5.0,7.6.0)", + org.hamcrest;version="[3.0.0,4.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.experimental.theories;version="[4.13,5.0.0)", org.junit.rules;version="[4.13.0,5.0.0)",
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java index 8739457..98478e5 100644 --- a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java +++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2018, 2022 Thomas Wolf <thomas.wolf@paranor.ch> and others + * Copyright (C) 2018, 2025 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 @@ -16,8 +16,10 @@ import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; +import java.io.BufferedInputStream; import java.io.BufferedWriter; import java.io.File; +import java.io.InputStream; import java.io.IOException; import java.io.UncheckedIOException; import java.net.URISyntaxException; @@ -26,12 +28,17 @@ import java.nio.file.StandardOpenOption; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.PrivateKey; import java.security.PublicKey; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; +import org.apache.sshd.agent.SshAgentConstants; import org.apache.sshd.client.config.hosts.KnownHostEntry; import org.apache.sshd.client.config.hosts.KnownHostHashValue; import org.apache.sshd.common.NamedFactory; @@ -43,7 +50,12 @@ import org.apache.sshd.common.kex.DHFactory; import org.apache.sshd.common.kex.KeyExchangeFactory; import org.apache.sshd.common.session.Session; +import org.apache.sshd.common.signature.BuiltinSignatures; +import org.apache.sshd.common.signature.Signature; +import org.apache.sshd.common.util.buffer.ByteArrayBuffer; import org.apache.sshd.common.util.net.SshdSocketAddress; +import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.core.CoreModuleProperties; import org.apache.sshd.server.ServerAuthenticationManager; import org.apache.sshd.server.ServerBuilder; import org.apache.sshd.server.SshServer; @@ -55,6 +67,8 @@ import org.eclipse.jgit.transport.RemoteSession; import org.eclipse.jgit.transport.SshSessionFactory; import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.transport.sshd.agent.Connector; +import org.eclipse.jgit.transport.sshd.agent.ConnectorFactory; import org.eclipse.jgit.util.FS; import org.junit.Test; import org.junit.experimental.theories.Theories; @@ -63,13 +77,13 @@ @RunWith(Theories.class) public class ApacheSshTest extends SshTestBase { - @Override - protected SshSessionFactory createSessionFactory() { + private SshSessionFactory createSessionFactory( + ConnectorFactory agentFactory) { return new SshdSessionFactoryBuilder() // No proxies in tests .setProxyDataFactory(null) // No ssh-agent in tests - .setConnectorFactory(null) + .setConnectorFactory(agentFactory) // The home directory is mocked at this point! .setHomeDirectory(FS.DETECTED.userHome()) .setSshDirectory(sshDir) @@ -77,6 +91,11 @@ protected SshSessionFactory createSessionFactory() { } @Override + protected SshSessionFactory createSessionFactory() { + return createSessionFactory(null); + } + + @Override protected void installConfig(String... config) { File configFile = new File(sshDir, Constants.CONFIG); if (config != null) { @@ -133,6 +152,35 @@ public void testWrongKeyFirst() throws Exception { "IdentityFile " + userKey.getAbsolutePath()); } + /** + * Test for ext-info-c being sent. Try authenticating first with a wrong RSA + * key. If ext-info-c is not set, the client will re-try three times with + * the wrong key (once for each RSA signature algorithm). Since we set the + * server to disconnect after three failed attempts, the test will fail. If + * ext-info-c _is_ sent, the client will try only once and then try the + * correct ed25519 key next and will succeed. + * + * @throws Exception + * on errors + */ + @Test + public void testKexExtension() throws Exception { + File userKey = new File(getTemporaryDirectory(), "userkey"); + copyTestResource("id_ed25519", userKey); + File publicKey = new File(getTemporaryDirectory(), "userkey.pub"); + copyTestResource("id_ed25519.pub", publicKey); + server.setTestUserPublicKey(publicKey.toPath()); + CoreModuleProperties.MAX_AUTH_REQUESTS.set(server.getPropertyResolver(), + Integer.valueOf(3)); + cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, // + "Host git", // + "HostName localhost", // + "Port " + testPort, // + "User " + TEST_USER, // + "IdentityFile " + privateKey1.getAbsolutePath(), // RSA + "IdentityFile " + userKey.getAbsolutePath()); + } + @Test public void testHashedKnownHosts() throws Exception { assertTrue("Failed to delete known_hosts", knownHosts.delete()); @@ -894,4 +942,182 @@ public void testCipherModificationUnknown() throws Exception { "Ciphers 3des-cbc")); assertTrue(e.getLocalizedMessage().contains("3des-cbc")); } + + /** + * Tests that the client does not try agent keys in an arbitrary order. It + * should try agent keys that correspond to a listed IdentityFile first. + * + * @throws Exception + * on errors + */ + @Test + public void testAgentWithIdentities() throws Exception { + try (FakeAgentConnector fakeAgent = new FakeAgentConnector()) { + // Fill the agent with a few fake RSA key pairs + KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); + generator.initialize(1024); + fakeAgent.add(generator.generateKeyPair()); + fakeAgent.add(generator.generateKeyPair()); + fakeAgent.add(generator.generateKeyPair()); + fakeAgent.add(generator.generateKeyPair()); + + File userKey = new File(getTemporaryDirectory(), "userkey"); + copyTestResource("id_ed25519", userKey); + File publicKey = new File(getTemporaryDirectory(), "userkey.pub"); + copyTestResource("id_ed25519.pub", publicKey); + server.setTestUserPublicKey(publicKey.toPath()); + try (InputStream in = new BufferedInputStream( + Files.newInputStream(userKey.toPath()))) { + Iterable<KeyPair> pairs = SecurityUtils + .loadKeyPairIdentities(null, null, in, null); + fakeAgent.add(pairs.iterator().next()); + } + + ConnectorFactory fakeFactory = new FakeConnectorFactory() { + + @Override + public Connector create(String identityAgent, File homeDir) + throws IOException { + return fakeAgent; + } + }; + SshSessionFactory.setInstance(createSessionFactory(fakeFactory)); + CoreModuleProperties.MAX_AUTH_REQUESTS + .set(server.getPropertyResolver(), Integer.valueOf(2)); + cloneWith("ssh://git/doesntmatter", defaultCloneDir, null, // + "Host git", // + "HostName localhost", // + "Port " + testPort, // + "User " + TEST_USER, // + "IdentityFile " + userKey.getAbsolutePath()); + assertTrue("Agent should have been called", fakeAgent.signCalled); + } + } + + /** + * A little dummy implementation of an SSH agent for testing. + */ + private static class FakeAgentConnector implements Connector { + + private Map<String, KeyPair> keys = new LinkedHashMap<>(); + + boolean signCalled; + + void add(KeyPair pair) { + keys.put(KeyUtils.getFingerPrint(pair.getPublic()), pair); + } + + @Override + public void close() throws IOException { + // Nothing to do + } + + @Override + public boolean connect() throws IOException { + return true; + } + + @Override + public byte[] rpc(byte command, byte[] message) throws IOException { + switch (command) { + case SshAgentConstants.SSH2_AGENTC_REQUEST_IDENTITIES: + return list(); + case SshAgentConstants.SSH2_AGENTC_SIGN_REQUEST: + signCalled = true; + return sign(message); + default: + return new byte[] { SshAgentConstants.SSH_AGENT_SUCCESS }; + } + } + + private byte[] list() { + ByteArrayBuffer result = new ByteArrayBuffer(); + result.putByte(SshAgentConstants.SSH2_AGENT_IDENTITIES_ANSWER); + result.putInt(keys.size()); + for (KeyPair pair : keys.values()) { + result.putPublicKey(pair.getPublic()); + result.putString(""); // Comment + } + return result.getCompactData(); + } + + private byte[] sign(byte[] message) { + ByteArrayBuffer buf = new ByteArrayBuffer(message, 5, + message.length - 5); + try { + PublicKey pk = buf.getPublicKey(); + byte[] dataToSign = buf.getBytes(); + int flags = buf.getInt(); + KeyPair pair = keys.get(KeyUtils.getFingerPrint(pk)); + if (pair == null) { + return new byte[] { SshAgentConstants.SSH_AGENT_FAILURE }; + } + // Figure out key type and signature + PrivateKey sk = pair.getPrivate(); + String keyType = KeyUtils.getKeyType(sk); + String signatureAlgorithm = keyType; + // We ignore complications for sk-keys or certificates here + if (keyType.equals("ssh-rsa")) { + switch (flags & 6) { + case 2: + signatureAlgorithm = KeyUtils.RSA_SHA256_KEY_TYPE_ALIAS; + break; + case 4: + signatureAlgorithm = KeyUtils.RSA_SHA512_KEY_TYPE_ALIAS; + break; + default: + break; + } + } + Signature signer = BuiltinSignatures + .fromFactoryName(signatureAlgorithm).create(); + signer.initSigner(null, sk); + signer.update(null, dataToSign); + ByteArrayBuffer sig = new ByteArrayBuffer(); + sig.putString(signatureAlgorithm); + sig.putBytes(signer.sign(null)); + ByteArrayBuffer result = new ByteArrayBuffer(); + result.putByte(SshAgentConstants.SSH2_AGENT_SIGN_RESPONSE); + result.putBytes(sig.getCompactData()); + return result.getCompactData(); + } catch (Exception e) { + return new byte[] { SshAgentConstants.SSH_AGENT_FAILURE }; + } + } + } + + abstract static class FakeConnectorFactory implements ConnectorFactory { + + @Override + public boolean isSupported() { + return true; + } + + @Override + public String getName() { + return "fake"; + } + + @Override + public Collection<ConnectorDescriptor> getSupportedConnectors() { + return Collections.singleton(getDefaultConnector()); + } + + @Override + public ConnectorDescriptor getDefaultConnector() { + return new ConnectorDescriptor() { + + @Override + public String getIdentityAgent() { + return "fake"; + } + + @Override + public String getDisplayName() { + return "fake"; + } + }; + } + + } }
diff --git a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties index 773c4b9..c91a64a 100644 --- a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties +++ b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
@@ -69,6 +69,7 @@ knownHostsUserAskCreationMsg=File {0} does not exist. knownHostsUserAskCreationPrompt=Create file {0} ? loginDenied=Cannot log in at {0}:{1} +noExplicitKeys=Host config for {0} has 'IdentitiesOnly yes' but no valid 'IdentityFile' configured. passwordPrompt=Password pkcs11Error=ERROR: {0} pkcs11FailedInstantiation=HostConfig for host {0} (hostname {1}): could not instantiate {2} {3}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java index 6aace47..7aaa5c2 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2018, 2023 Thomas Wolf <twolf@apache.org> and others + * Copyright (C) 2018, 2025 Thomas Wolf <twolf@apache.org> 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 @@ -32,6 +32,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; @@ -381,60 +382,39 @@ protected Iterable<KeyAgentIdentity> initializeAgentIdentities( if (allAgentKeys == null) { return null; } - Collection<PublicKey> identityFiles = identitiesOnly(); - if (GenericUtils.isEmpty(identityFiles)) { + if (hostConfig == null) { + return allAgentKeys; + } + Collection<PublicKey> explicitKeys = getExplicitKeys( + hostConfig.getIdentities()); + if (GenericUtils.isEmpty(explicitKeys)) { + if (hostConfig.isIdentitiesOnly()) { + log.warn(LOG_FORMAT, format(SshdText.get().noExplicitKeys, + hostConfig.getHost())); + return Collections.emptyList(); + } return allAgentKeys; } - // Only consider agent or PKCS11 keys that match a known public key - // file. - return () -> new Iterator<>() { - - private final Iterator<KeyAgentIdentity> identities = allAgentKeys - .iterator(); - - private KeyAgentIdentity next; - - @Override - public boolean hasNext() { - while (next == null && identities.hasNext()) { - KeyAgentIdentity val = identities.next(); - PublicKey pk = val.getKeyIdentity().getPublic(); - // This checks against all explicit keys for any agent - // key, but since identityFiles.size() is typically 1, - // it should be fine. - if (identityFiles.stream() - .anyMatch(k -> KeyUtils.compareKeys(k, pk))) { - next = val; - return true; - } - if (log.isTraceEnabled()) { - log.trace( - "Ignoring SSH agent or PKCS11 {} key not in explicit IdentityFile in SSH config: {}", //$NON-NLS-1$ - KeyUtils.getKeyType(pk), - KeyUtils.getFingerPrint(pk)); - } - } - return next != null; + // Sort the identities such that the ones for the explicitly listed + // keys come first, in the order listed. + Map<String, KeyAgentIdentity> fromAgent = new LinkedHashMap<>(); + allAgentKeys.forEach(k -> fromAgent.computeIfAbsent( + KeyUtils.getFingerPrint(k.getKeyIdentity().getPublic()), + x -> k)); + List<KeyAgentIdentity> result = new ArrayList<>(); + for (PublicKey pk : explicitKeys) { + KeyAgentIdentity id = fromAgent + .remove(KeyUtils.getFingerPrint(pk)); + if (id != null) { + result.add(id); } - - @Override - public KeyAgentIdentity next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - KeyAgentIdentity result = next; - next = null; - return result; - } - }; - } - - private Collection<PublicKey> identitiesOnly() { - if (hostConfig != null && hostConfig.isIdentitiesOnly()) { - return getExplicitKeys(hostConfig.getIdentities()); } - return Collections.emptyList(); + if (!hostConfig.isIdentitiesOnly()) { + result.addAll(fromAgent.values()); + } + + return result; } private Iterable<KeyAgentIdentity> getAgentIdentities()
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java index e401378..d40ec83 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
@@ -1,5 +1,5 @@ /* - * Copyright (C) 2018, 2024 Thomas Wolf <twolf@apache.org> and others + * Copyright (C) 2018, 2025 Thomas Wolf <twolf@apache.org> 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 @@ -91,6 +91,7 @@ public static SshdText get() { /***/ public String knownHostsUserAskCreationMsg; /***/ public String knownHostsUserAskCreationPrompt; /***/ public String loginDenied; + /***/ public String noExplicitKeys; /***/ public String passwordPrompt; /***/ public String pkcs11Error; /***/ public String pkcs11FailedInstantiation;
diff --git a/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF index 2443823..5823845 100644 --- a/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF
@@ -8,7 +8,6 @@ Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Require-Bundle: org.hamcrest.core;bundle-version="[1.3.0,2.0.0)" Import-Package: com.jcraft.jsch;version="[0.1.54,0.2.0)", org.eclipse.jgit.errors;version="[7.5.0,7.6.0)", org.eclipse.jgit.internal.storage.file;version="[7.5.0,7.6.0)", @@ -18,6 +17,7 @@ org.eclipse.jgit.transport;version="[7.5.0,7.6.0)", org.eclipse.jgit.transport.ssh.jsch;version="[7.5.0,7.6.0)", org.eclipse.jgit.util;version="[7.5.0,7.6.0)", + org.hamcrest;version="[3.0.0,4.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.experimental.theories;version="[4.13,5.0.0)", org.junit.runner;version="[4.13,5.0.0)"
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF index 9689f43..c724d35 100644 --- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -8,8 +8,6 @@ Bundle-Vendor: %Bundle-Vendor Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git -Require-Bundle: org.hamcrest.core;bundle-version="[1.3.0,2.0.0)", - org.hamcrest.library;bundle-version="[1.3.0,2.0.0)" Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)", net.bytebuddy.agent;version="[1.9.0,2.0.0)", net.bytebuddy.dynamic.loading;version="[1.9.0,2.0.0)", @@ -83,6 +81,8 @@ org.eclipse.jgit.util;version="[7.5.0,7.6.0)", org.eclipse.jgit.util.io;version="[7.5.0,7.6.0)", org.eclipse.jgit.util.sha1;version="[7.5.0,7.6.0)", + org.hamcrest;version="[3.0.0,4.0.0)", + org.hamcrest.collection;version="[3.0.0,4.0.0)", org.junit;version="[4.13,5.0.0)", org.junit.experimental.theories;version="[4.13,5.0.0)", org.junit.function;version="[4.13.0,5.0.0)",
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 80bd689..b340636 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
@@ -4,6 +4,7 @@ import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC_REST; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.INSERT; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE; +import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH; @@ -18,9 +19,12 @@ import java.io.IOException; import java.time.Instant; import java.time.ZoneOffset; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph; import org.eclipse.jgit.internal.storage.commitgraph.CommitGraphWriter; @@ -42,6 +46,7 @@ import org.eclipse.jgit.lib.ObjectId; 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.Repository; import org.eclipse.jgit.revwalk.RevBlob; @@ -62,12 +67,15 @@ public class DfsGarbageCollectorTest { private DfsObjDatabase odb; private MockSystemReader mockSystemReader; + private static final ProgressMonitor NULL_PM = NullProgressMonitor.INSTANCE; + @Before public void setUp() throws IOException { DfsRepositoryDescription desc = new DfsRepositoryDescription("test"); git = new TestRepository<>(new InMemoryRepository(desc)); repo = git.getRepository(); odb = repo.getObjectDatabase(); + odb.setUseMultipackIndex(true); mockSystemReader = new MockSystemReader(); SystemReader.setInstance(mockSystemReader); } @@ -1227,6 +1235,117 @@ public void objectSizeIndex_unreachableGarbage_noIdx() throws Exception { } @Test + public void midx_oneMidx_deleteMidxs_allObjectsOneGC() throws Exception { + String master = "refs/heads/master"; + RevCommit root = git.branch(master).commit().message("root").noParents() + .create(); + git.branch(master).commit().message("commit on head") + .add("file.txt", git.blob("a blob")).parent(root).create(); + assertEquals(3, countPacks(INSERT)); + + DfsPackDescription midx = DfsMidxWriter.writeMidx( + NullProgressMonitor.INSTANCE, odb, + Arrays.asList(odb.getPacks()), null); + odb.commitPack(List.of(midx), null); + + gcNoTtl(); + + // Only one pack, is GC but not multipack index + assertEquals(1, odb.getPacks().length); + DfsPackDescription actualDesc = odb.getPacks()[0].getPackDescription(); + assertEquals(GC, actualDesc.getPackSource()); + assertFalse(actualDesc.hasFileExt(MULTI_PACK_INDEX)); + DfsPackFile pack = odb.getPacks()[0]; + assertFalse(pack instanceof DfsPackFileMidx); + assertTrue(isObjectInPack(root, pack)); + } + + @Test + public void midx_chainedMidx_deleteMidxs_allObjsInOneGC() throws Exception { + String master = "refs/heads/master"; + List<RevCommit> knownCommits = new ArrayList<>(11); + RevCommit root = git.branch(master).commit().message("root").noParents() + .create(); + knownCommits.add(root); + RevCommit tip = root; + for (int i = 0; i < 10; i++) { + tip = git.branch(master).commit().message("commit on head") + .add("file.txt", git.blob("a blob " + i)).parent(tip) + .create(); + knownCommits.add(tip); + // Each of these creates two packs + } + assertEquals(21, countPacks(INSERT)); + + List<DfsPackFile> basicPacks = Arrays.stream(odb.getPacks()) + .collect(Collectors.toUnmodifiableList()); + DfsPackDescription midx = DfsMidxWriter.writeMidx(NULL_PM, odb, + basicPacks.subList(0, 9), null); + odb.commitPack(List.of(midx), null); + + DfsPackDescription midx2 = DfsMidxWriter.writeMidx(NULL_PM, odb, + basicPacks.subList(9, 21), midx); + odb.commitPack(List.of(midx2), null); + + // Verify we got one pack that is an midx + // This is testing the test code + assertEquals(1, odb.getPacks().length); + assertTrue(odb.getPacks()[0] instanceof DfsPackFileMidx); + DfsPackDescription theDesc = odb.getPacks()[0].getPackDescription(); + assertTrue(theDesc.hasFileExt(MULTI_PACK_INDEX)); + assertEquals(12, theDesc.getCoveredPacks().size()); + assertEquals(theDesc.getMultiPackIndexBase(), midx); + assertEquals(9, + theDesc.getMultiPackIndexBase().getCoveredPacks().size()); + gcNoTtl(); + + // One pack, GC WITHOUT multipack index, contains ALL objects + assertEquals(1, odb.getPacks().length); + DfsPackFile pack = odb.getPacks()[0]; + assertEquals(GC, pack.getPackDescription().getPackSource()); + assertFalse(pack instanceof DfsPackFileMidx); + assertFalse(pack.getPackDescription().hasFileExt(MULTI_PACK_INDEX)); + for (RevCommit c : knownCommits) { + assertTrue(isObjectInPack(c, pack)); + } + } + + @Test + public void midx_packAndMidx_deleteMidxs_allObjectsOneGC() + throws Exception { + String master = "refs/heads/master"; + RevCommit root = git.branch(master).commit().message("root").noParents() + .create(); + RevCommit tip = git.branch(master).commit().message("commit on head") + .add("file.txt", git.blob("a blob")).parent(root).create(); + assertEquals(3, countPacks(INSERT)); + + List<DfsPackFile> packs = Arrays.stream(odb.getPacks()).toList(); + DfsPackDescription midx = DfsMidxWriter.writeMidx(NULL_PM, odb, packs, + null); + odb.commitPack(List.of(midx), null); + + RevBlob blobOutOfMidx = git.blob("some content"); + RevCommit commitOutOfMidx = git.branch(master).commit() + .message("an extra commit").add("other.txt", blobOutOfMidx) + .parent(tip).create(); + assertEquals(3, odb.getPacks().length); // midx + 2 new packs + gcNoTtl(); + + // Only one pack, is GC but not multipack index + assertEquals(1, odb.getPacks().length); + DfsPackDescription actualDesc = odb.getPacks()[0].getPackDescription(); + assertEquals(GC, actualDesc.getPackSource()); + assertFalse(actualDesc.hasFileExt(MULTI_PACK_INDEX)); + + DfsPackFile pack = odb.getPacks()[0]; + assertTrue(isObjectInPack(root, pack)); + assertTrue(isObjectInPack(root, pack)); + assertTrue(isObjectInPack(blobOutOfMidx, pack)); + assertTrue(isObjectInPack(commitOutOfMidx, pack)); + } + + @Test public void bitmapIndexWrittenDuringGc() throws Exception { int numBranches = 2; int commitsPerBranch = 50;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabaseTest.java new file mode 100644 index 0000000..c30753e --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabaseTest.java
@@ -0,0 +1,279 @@ +/* + * Copyright (C) 2025, Google LLC + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.dfs; + +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.COMPACT; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.INSERT; +import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX; +import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; +import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.junit.Before; +import org.junit.Test; + +public class DfsObjDatabaseTest { + InMemoryRepository db; + + private static final DfsRepositoryDescription repoDesc = new DfsRepositoryDescription( + "test"); + + @Before + public void setUp() { + db = new InMemoryRepository(repoDesc); + } + + @Test + public void getPacks_allInMidx_midxEnabled_onlyMidx() throws IOException { + db.getObjectDatabase().setUseMultipackIndex(true); + + DfsPackDescription gcPack = pack("aaaa", GC, 100, PACK); + DfsPackDescription compactPack = pack("cccc", COMPACT, 101, PACK); + DfsPackDescription compactTwoPack = pack("bbbb", COMPACT, 102, PACK); + + DfsPackDescription multiPackIndex = pack("xxxx", GC, 104, + MULTI_PACK_INDEX); + multiPackIndex + .setCoveredPacks(List.of(gcPack, compactPack, compactTwoPack)); + + db.getObjectDatabase().commitPack( + List.of(gcPack, compactPack, compactTwoPack, multiPackIndex), + Collections.emptyList()); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertPackList(packs, multiPackIndex); + } + + @Test + public void getPacks_allInMidx_midxDisabled_packsNoMidx() + throws IOException { + db.getObjectDatabase().setUseMultipackIndex(false); + + DfsPackDescription gcPack = pack("aaaa", GC, 100, PACK); + DfsPackDescription compactPack = pack("cccc", COMPACT, 101, PACK); + DfsPackDescription compactTwoPack = pack("bbbb", COMPACT, 102, PACK); + + DfsPackDescription multiPackIndex = pack("xxxx", GC, 104, + MULTI_PACK_INDEX); + multiPackIndex + .setCoveredPacks(List.of(gcPack, compactPack, compactTwoPack)); + + db.getObjectDatabase().commitPack( + List.of(gcPack, compactPack, compactTwoPack, multiPackIndex), + Collections.emptyList()); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertPackList(packs, compactTwoPack, compactPack, gcPack); + } + + @Test + public void getPacks_someInMidx_midxEnabled_midxPlusUncovered() + throws IOException { + db.getObjectDatabase().setUseMultipackIndex(true); + + DfsPackDescription gcPack = pack("aaaa", GC, 100, PACK); + DfsPackDescription compactPack = pack("cccc", COMPACT, 101, PACK); + DfsPackDescription insertPack = pack("bbbb", COMPACT, 102, PACK); + + DfsPackDescription multiPackIndex = pack("xxxx", GC, 104, + MULTI_PACK_INDEX); + multiPackIndex.setCoveredPacks(List.of(gcPack, compactPack, insertPack)); + db.getObjectDatabase().commitPack( + List.of(gcPack, compactPack, insertPack, multiPackIndex), + null); + + DfsPackDescription uncoveredPack = pack("dddd", COMPACT, 103, PACK); + db.getObjectDatabase().commitPack(List.of(uncoveredPack), null); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertPackList(packs, uncoveredPack, multiPackIndex); + } + + @Test + public void getPacks_someInMidx_midxDisabled_packsNoMidx() + throws IOException { + db.getObjectDatabase().setUseMultipackIndex(false); + + DfsPackDescription gcPack = pack("aaaa", GC, 100, PACK); + DfsPackDescription compactPack = pack("cccc", COMPACT, 101, PACK); + DfsPackDescription insertPack = pack("bbbb", COMPACT, 102, PACK); + + DfsPackDescription multiPackIndex = pack("xxxx", GC, 104, + MULTI_PACK_INDEX); + multiPackIndex + .setCoveredPacks(List.of(gcPack, compactPack, insertPack)); + db.getObjectDatabase().commitPack( + List.of(gcPack, compactPack, insertPack, multiPackIndex), null); + + DfsPackDescription uncoveredPack = pack("dddd", COMPACT, 103, PACK); + db.getObjectDatabase().commitPack(List.of(uncoveredPack), null); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertPackList(packs, uncoveredPack, insertPack, compactPack, gcPack); + } + + @Test + public void getPacks_midxChain_midxEnabled_topMidx() throws IOException { + db.getObjectDatabase().setUseMultipackIndex(true); + + DfsPackDescription gcPack = pack("aaaa", GC, 100, PACK); + DfsPackDescription compactPack = pack("cccc", COMPACT, 101, PACK); + DfsPackDescription insertPack = pack("bbbb", COMPACT, 102, PACK); + + DfsPackDescription midxBase = pack("xxxx", GC, 104, + MULTI_PACK_INDEX); + midxBase.setCoveredPacks(List.of(gcPack, compactPack, insertPack)); + db.getObjectDatabase().commitPack( + List.of(gcPack, compactPack, insertPack, midxBase), + null); + + DfsPackDescription insert1 = pack("insert1", INSERT, 105, PACK); + DfsPackDescription insert2 = pack("insert2", INSERT, 106, PACK); + DfsPackDescription midxTip = pack("xxx2", GC, 107, MULTI_PACK_INDEX); + midxTip.setCoveredPacks(List.of(insert1, insert2)); + midxTip.setMultiPackIndexBase(midxBase); + db.getObjectDatabase().commitPack(List.of(insert1, insert2, midxTip), null); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertPackList(packs, midxTip); + } + + @Test + public void getPacks_midxChain_midxDisabled_packsNoMidx() + throws IOException { + db.getObjectDatabase().setUseMultipackIndex(false); + + DfsPackDescription gcPack = pack("aaaa", GC, 100, PACK); + DfsPackDescription compactPack = pack("cccc", COMPACT, 101, PACK); + DfsPackDescription insertPack = pack("bbbb", COMPACT, 102, PACK); + + DfsPackDescription midxBase = pack("xxxx", GC, 104, MULTI_PACK_INDEX); + midxBase.setCoveredPacks(List.of(gcPack, compactPack, insertPack)); + db.getObjectDatabase().commitPack( + List.of(gcPack, compactPack, insertPack, midxBase), null); + + DfsPackDescription insert1 = pack("insert1", INSERT, 105, PACK); + DfsPackDescription insert2 = pack("insert2", INSERT, 106, PACK); + DfsPackDescription midxTip = pack("xxx2", GC, 107, MULTI_PACK_INDEX); + midxTip.setCoveredPacks(List.of(insert1, insert2)); + midxTip.setMultiPackIndexBase(midxBase); + db.getObjectDatabase().commitPack(List.of(insert1, insert2, midxTip), + null); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertPackList(packs, insert2, insert1, insertPack, compactPack, + gcPack); + } + + @Test + public void getReftables_multipleInsideMidx() throws IOException { + db.getObjectDatabase().setUseMultipackIndex(true); + + DfsPackDescription gcPack = pack("aaaa", GC, 100, PACK, REFTABLE); + DfsPackDescription compactPack = pack("cccc", COMPACT, 101, PACK, + REFTABLE); + DfsPackDescription compactTwoPack = pack("bbbb", COMPACT, 102, PACK); + + DfsPackDescription multiPackIndex = pack("xxxx", GC, 104, + MULTI_PACK_INDEX); + multiPackIndex + .setCoveredPacks(List.of(gcPack, compactPack, compactTwoPack)); + + db.getObjectDatabase().commitPack( + List.of(gcPack, compactPack, compactTwoPack, multiPackIndex), + Collections.emptyList()); + + DfsReftable[] reftables = db.getObjectDatabase().getReftables(); + assertReftableList(reftables, gcPack, compactPack); + } + + @Test + public void getReftables_midxChain() throws IOException { + db.getObjectDatabase().setUseMultipackIndex(true); + + DfsPackDescription gcPack = pack("aaaa", GC, 100, PACK, REFTABLE); + DfsPackDescription compactPack = pack("cccc", COMPACT, 101, PACK, + REFTABLE); + DfsPackDescription insertPack = pack("bbbb", COMPACT, 102, PACK); + + DfsPackDescription midxBase = pack("xxxx", GC, 104, MULTI_PACK_INDEX); + midxBase.setCoveredPacks(List.of(gcPack, compactPack, insertPack)); + db.getObjectDatabase().commitPack( + List.of(gcPack, compactPack, insertPack, midxBase), null); + + DfsPackDescription insert1 = pack("insert1", INSERT, 105, PACK, + REFTABLE); + DfsPackDescription insert2 = pack("insert2", INSERT, 106, PACK); + DfsPackDescription midxTip = pack("xxx2", GC, 107, MULTI_PACK_INDEX); + midxTip.setCoveredPacks(List.of(insert1, insert2)); + midxTip.setMultiPackIndexBase(midxBase); + db.getObjectDatabase().commitPack(List.of(insert1, insert2, midxTip), + null); + + DfsReftable[] reftables = db.getObjectDatabase().getReftables(); + assertReftableList(reftables, gcPack, compactPack, insert1); + } + + @Test + public void getReftables_inAndOutOfMidx() throws IOException { + db.getObjectDatabase().setUseMultipackIndex(true); + + DfsPackDescription gcPack = pack("aaaa", GC, 100, PACK, REFTABLE); + DfsPackDescription compactPack = pack("cccc", COMPACT, 101, PACK); + DfsPackDescription insertPack = pack("bbbb", COMPACT, 102, PACK); + + DfsPackDescription multiPackIndex = pack("xxxx", GC, 104, + MULTI_PACK_INDEX); + multiPackIndex + .setCoveredPacks(List.of(gcPack, compactPack, insertPack)); + db.getObjectDatabase().commitPack( + List.of(gcPack, compactPack, insertPack, multiPackIndex), null); + + DfsPackDescription uncoveredPack = pack("dddd", COMPACT, 103, PACK, + REFTABLE); + db.getObjectDatabase().commitPack(List.of(uncoveredPack), null); + + DfsReftable[] reftables = db.getObjectDatabase().getReftables(); + assertReftableList(reftables, gcPack, uncoveredPack); + } + + private static DfsPackDescription pack(String name, + DfsObjDatabase.PackSource source, long timeMs, PackExt... ext) { + DfsPackDescription desc = new DfsPackDescription(repoDesc, name, + source); + desc.setLastModified(timeMs); + for (PackExt packExt : ext) { + desc.addFileExt(packExt); + } + return desc; + } + + private static void assertPackList(DfsPackFile[] actual, + DfsPackDescription... expected) { + assertEquals(expected.length, actual.length); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], actual[i].getPackDescription()); + } + } + + private static void assertReftableList(DfsReftable[] actual, + DfsPackDescription... expected) { + assertEquals(expected.length, actual.length); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], actual[i].getPackDescription()); + } + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java index c3b6aa8..84505a8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java
@@ -14,6 +14,7 @@ import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.INSERT; import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; +import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -21,14 +22,20 @@ import java.io.IOException; import java.util.Arrays; import java.util.Optional; +import java.util.zip.Deflater; +import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.junit.TestRng; import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.revwalk.RevCommit; import org.junit.Before; import org.junit.Test; public class DfsPackCompacterTest { + private static final int AUTO_ADD_SIZE = 5 * 1024 * 1024; // 5 MiB + private TestRepository<InMemoryRepository> git; private InMemoryRepository repo; private DfsObjDatabase odb; @@ -137,19 +144,62 @@ public void testObjectSizeIndexNotWritten() throws Exception { assertFalse(compactPack.get().getPackDescription().hasFileExt(OBJECT_SIZE_INDEX)); } + @Test + public void testPrunePack() throws Exception { + ObjectId o1 = writePackWithRandomBlob(200); + ObjectId o2 = writePackWithRandomBlob(100); + ObjectId o3 = writePackWithRandomBlob(210); + DfsPackFile[] packsToCompact = odb.getPacks(); + + DfsPackCompactor compactor = new DfsPackCompactor(repo); + compactor.add(packsToCompact[1]); + compactor.add(packsToCompact[2]); + compactor.prune(packsToCompact[0]); + + compactor.compact(null); + + assertEquals(1, odb.getPacks().length); + assertFalse(odb.has(o3)); // pack with o3 was pruned + assertTrue(odb.has(o1)); + assertTrue(odb.has(o2)); + } + private TestRepository<InMemoryRepository>.CommitBuilder commit() { return git.commit(); } private void compact() throws IOException { DfsPackCompactor compactor = new DfsPackCompactor(repo); - compactor.autoAdd(); + DfsObjDatabase objdb = repo.getObjectDatabase(); + for (DfsPackFile pack : objdb.getPacks()) { + DfsPackDescription d = pack.getPackDescription(); + if (d.getFileSize(PACK) < AUTO_ADD_SIZE) { + compactor.add(pack); + } else { + compactor.exclude(pack); + } + } compactor.compact(null); odb.clearCache(); } private static void writeObjectSizeIndex(DfsRepository repo, boolean should) { repo.getConfig().setInt(ConfigConstants.CONFIG_PACK_SECTION, null, - ConfigConstants.CONFIG_KEY_MIN_BYTES_OBJ_SIZE_INDEX, should ? 0 : -1); + ConfigConstants.CONFIG_KEY_MIN_BYTES_OBJ_SIZE_INDEX, + should ? 0 : -1); + } + + private ObjectId writePackWithBlob(byte[] data) throws IOException { + DfsInserter ins = (DfsInserter) repo.newObjectInserter(); + ins.setCompressionLevel(Deflater.NO_COMPRESSION); + ObjectId blobId = ins.insert(OBJ_BLOB, data); + ins.flush(); + return blobId; + } + + // Do not use the size twice into the same test (it gives the same blob!) + private ObjectId writePackWithRandomBlob(int size) throws IOException { + byte[] data = new TestRng(JGitTestUtil.getName()).nextBytes(size); + return writePackWithBlob(data); } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxTest.java index 998ea0d..3fd4e2c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidxTest.java
@@ -29,6 +29,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -36,6 +37,7 @@ import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.internal.storage.dfs.DfsPackFileMidx.VOffsetCalculator; +import org.eclipse.jgit.internal.storage.file.PackBitmapIndex; import org.eclipse.jgit.internal.storage.file.PackIndex; import org.eclipse.jgit.internal.storage.midx.MultiPackIndex.PackOffset; import org.eclipse.jgit.internal.storage.midx.MultiPackIndexWriter; @@ -302,36 +304,35 @@ public void midx_findOffset() throws IOException { ObjectId o1 = writePackWithRandomBlob(100); ObjectId o2 = writePackWithRandomBlob(200); ObjectId o3 = writePackWithRandomBlob(150); + // Packs are written in the midx in reverse insertion time DfsPackFileMidx midx = writeMultipackIndex(); DfsPackFile packOne = findPack(o1); - long packOneSize = packOne.getPackDescription().getFileSize(PACK); DfsPackFile packTwo = findPack(o2); long packTwoSize = packTwo.getPackDescription().getFileSize(PACK); DfsPackFile packThree = findPack(o3); + long packThreeSize = packThree.getPackDescription().getFileSize(PACK); - // Packs have sequential names (pack-NN-INSERT) and midx uses pack-name - // order. We rely on that to know the pack offsets try (DfsReader ctx = db.getObjectDatabase().newReader()) { long posOne = midx.findOffset(ctx, o1); DfsPackFileMidx.DfsPackOffset po = midx.getOffsetCalculator() .decode(posOne); assertEquals(12, po.getPackOffset()); - assertEquals(0, po.getPackStart()); + assertEquals(packThreeSize + packTwoSize, po.getPackStart()); assertEquals(packOne.getPackDescription(), po.getPack().getPackDescription()); long posTwo = midx.findOffset(ctx, o2); po = midx.getOffsetCalculator().decode(posTwo); assertEquals(12, po.getPackOffset()); - assertEquals(packOneSize, po.getPackStart()); + assertEquals(packThreeSize, po.getPackStart()); assertEquals(packTwo.getPackDescription(), po.getPack().getPackDescription()); long posThree = midx.findOffset(ctx, o3); po = midx.getOffsetCalculator().decode(posThree); assertEquals(12, po.getPackOffset()); - assertEquals(packOneSize + packTwoSize, po.getPackStart()); + assertEquals(0, po.getPackStart()); assertEquals(packThree.getPackDescription(), po.getPack().getPackDescription()); @@ -420,15 +421,15 @@ public void midx_findAllFromPack() throws Exception { true); assertEquals(3, allFromPack.size()); - // Objects are in (pack, offset) order (i.e. pack) + // Objects are in (pack, offset) order (i.e. reverse pack insert) DfsObjectToPack oneToPack = allFromPack.get(0); - assertEquals(midx.findOffset(ctx, o1), oneToPack.getOffset()); + assertEquals(midx.findOffset(ctx, o3), oneToPack.getOffset()); DfsObjectToPack twoToPack = allFromPack.get(1); assertEquals(midx.findOffset(ctx, o2), twoToPack.getOffset()); DfsObjectToPack threeToPack = allFromPack.get(2); - assertEquals(midx.findOffset(ctx, o3), threeToPack.getOffset()); + assertEquals(midx.findOffset(ctx, o1), threeToPack.getOffset()); } } @@ -442,7 +443,7 @@ public void midx_findAllFromPack_withBase() throws Exception { ObjectId o6 = writePackWithRandomBlob(600); DfsPackFile[] packs = db.getObjectDatabase().getPacks(); - // Packs are in reverse insertion order + // Packs are in reverse insertion order (o6 -> o1) DfsPackFileMidx midxBase = writeMultipackIndex( Arrays.copyOfRange(packs, 3, 6), null); DfsPackFileMidx midxTip = writeMultipackIndex( @@ -461,24 +462,25 @@ public void midx_findAllFromPack_withBase() throws Exception { otps, true); assertEquals(6, allFromPack.size()); - // Objects are in (pack, offset) order (i.e. pack) + // Objects are in midx-offset order which is: + // base(o3 < o2 < o1) -> tip (06 < 05 < o4) DfsObjectToPack oneToPack = allFromPack.get(0); - assertEquals(midxTip.findOffset(ctx, o1), oneToPack.getOffset()); + assertEquals(midxTip.findOffset(ctx, o3), oneToPack.getOffset()); DfsObjectToPack twoToPack = allFromPack.get(1); assertEquals(midxTip.findOffset(ctx, o2), twoToPack.getOffset()); DfsObjectToPack threeToPack = allFromPack.get(2); - assertEquals(midxTip.findOffset(ctx, o3), threeToPack.getOffset()); + assertEquals(midxTip.findOffset(ctx, o1), threeToPack.getOffset()); DfsObjectToPack fourToPack = allFromPack.get(3); - assertEquals(midxTip.findOffset(ctx, o4), fourToPack.getOffset()); + assertEquals(midxTip.findOffset(ctx, o6), fourToPack.getOffset()); DfsObjectToPack fiveToPack = allFromPack.get(4); assertEquals(midxTip.findOffset(ctx, o5), fiveToPack.getOffset()); DfsObjectToPack sixToPack = allFromPack.get(5); - assertEquals(midxTip.findOffset(ctx, o6), sixToPack.getOffset()); + assertEquals(midxTip.findOffset(ctx, o4), sixToPack.getOffset()); } } @@ -842,6 +844,92 @@ public void midx_fillRepresentation_withBase() throws Exception { } @Test + public void midx_getBitmapIndex() throws Exception { + RevCommit c1 = writePackWithCommit(); + RevCommit c2 = writePackWithCommit(); + gcWithBitmaps(); + + ObjectId blob = writePackWithRandomBlob(300); + DfsPackFileMidx dfsPackFileMidx = writeMultipackIndex(); + try (DfsReader ctx = db.getObjectDatabase().newReader()) { + PackBitmapIndex bitmapIndex = dfsPackFileMidx.getBitmapIndex(ctx); + assertNotNull(bitmapIndex); + // Both commits have same tree and blob + assertEquals(4, bitmapIndex.getObjectCount()); + assertEquals(1, bitmapIndex.findPosition(c1)); + assertEquals(0, bitmapIndex.findPosition(c2)); + assertEquals(-1, bitmapIndex.findPosition(blob)); + } + } + + @Test + public void midx_getAllCoveredPacks() throws Exception { + writePackWithCommit(); + writePackWithRandomBlob(300); + writePackWithRandomBlob(500); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertEquals(4, packs.length); + DfsPackFileMidx midx = writeMultipackIndex(packs, null); + + assertEquals(4, midx.getAllCoveredPacks().size()); + List<DfsPackDescription> expected = Arrays.stream(packs) + .map(p -> p.getPackDescription()).toList(); + List<DfsPackDescription> actual = midx.getAllCoveredPacks().stream() + .map(DfsPackFile::getPackDescription).toList(); + assertEquals(expected, actual); + } + + @Test + public void midx_getAllCoveredPacks_withBase() throws Exception { + writePackWithCommit(); + writePackWithRandomBlob(300); + writePackWithRandomBlob(500); + writePackWithRandomBlob(100); + writePackWithCommit(); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertEquals(6, packs.length); + DfsPackFileMidx midxBase = writeMultipackIndex( + Arrays.copyOfRange(packs, 4, 6), null); + DfsPackFileMidx midxMiddle = writeMultipackIndex( + Arrays.copyOfRange(packs, 2, 4), midxBase); + DfsPackFileMidx midxTip = writeMultipackIndex( + Arrays.copyOfRange(packs, 0, 2), midxMiddle); + + assertEquals(6, midxTip.getAllCoveredPacks().size()); + List<DfsPackDescription> expected = Arrays.stream(packs) + .map(DfsPackFile::getPackDescription).toList(); + List<DfsPackDescription> actual = midxTip.getAllCoveredPacks().stream() + .map(DfsPackFile::getPackDescription).toList(); + assertEquals(expected, actual); + } + + @Test + public void midx_getCoveredPacks_withBase_onlyTopMidx() throws Exception { + writePackWithCommit(); + writePackWithRandomBlob(300); + writePackWithRandomBlob(500); + writePackWithRandomBlob(100); + writePackWithCommit(); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertEquals(6, packs.length); + DfsPackFileMidx midxBase = writeMultipackIndex( + Arrays.copyOfRange(packs, 3, 6), null); + DfsPackFileMidx midxTip = writeMultipackIndex( + Arrays.copyOfRange(packs, 0, 3), midxBase); + + assertEquals(3, midxTip.getCoveredPacks().size()); + List<DfsPackDescription> expected = Arrays + .stream(Arrays.copyOfRange(packs, 0, 3)) + .map(DfsPackFile::getPackDescription).toList(); + List<DfsPackDescription> actual = midxTip.getCoveredPacks().stream() + .map(DfsPackFile::getPackDescription).toList(); + assertEquals(expected, actual); + } + + @Test public void midx_corrupt() throws Exception { RevCommit commit = writePackWithCommit(); writePackWithRandomBlob(200); @@ -1067,16 +1155,22 @@ private DfsPackFileMidx writeMultipackIndex() throws IOException { return writeMultipackIndex(db.getObjectDatabase().getPacks(), null); } + private void gcWithBitmaps() throws IOException { + DfsGarbageCollector garbageCollector = new DfsGarbageCollector(db); + garbageCollector.pack(NullProgressMonitor.INSTANCE); + } + private DfsPackFileMidx writeMultipackIndex(DfsPackFile[] packs, DfsPackFileMidx base) throws IOException { - Map<String, PackIndex> forMidx = new HashMap<>(packs.length); - Map<String, DfsPackDescription> requiredPacks = new HashMap<>( + LinkedHashMap<String, PackIndex> forMidx = new LinkedHashMap<>( + packs.length); + Map<String, DfsPackDescription> descByName = new HashMap<>( packs.length); try (DfsReader ctx = db.getObjectDatabase().newReader()) { for (DfsPackFile pack : packs) { forMidx.put(pack.getPackDescription().getPackName(), pack.getPackIndex(ctx)); - requiredPacks.put(pack.getPackDescription().getPackName(), + descByName.put(pack.getPackDescription().getPackName(), pack.getPackDescription()); } } @@ -1087,7 +1181,7 @@ private DfsPackFileMidx writeMultipackIndex(DfsPackFile[] packs, MultiPackIndexWriter.Result midxStats = w .write(NullProgressMonitor.INSTANCE, out, forMidx); desc.setCoveredPacks(midxStats.packNames().stream() - .map(requiredPacks::get).toList()); + .map(descByName::get).toList()); desc.addFileExt(PackExt.MULTI_PACK_INDEX); } db.getObjectDatabase().commitPack(List.of(desc), null);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackFilterTest.java new file mode 100644 index 0000000..584bab1 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackFilterTest.java
@@ -0,0 +1,237 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.dfs; + +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.COMPACT; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.INSERT; +import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX; +import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.junit.Test; + +public class MidxPackFilterTest { + private static final DfsRepositoryDescription repoDesc = new DfsRepositoryDescription( + "test"); + + private static int timeCounter = 0; + + @Test + public void useMidx_oneMidxCoversAll_onlyMidx() { + DfsPackDescription gc = pack("aaaa", GC, PACK); + DfsPackDescription compact = pack("cccc", COMPACT, PACK); + DfsPackDescription compactTwo = pack("bbbb", COMPACT, PACK); + DfsPackDescription midx = pack("midx", GC, MULTI_PACK_INDEX); + midx.setCoveredPacks(List.of(gc, compact, compactTwo)); + + List<DfsPackDescription> reorgPacks = MidxPackFilter + .useMidx(List.of(gc, compact, compactTwo, midx)); + assertEquals(1, reorgPacks.size()); + assertEquals(midx, reorgPacks.get(0)); + } + + @Test + public void useMidx_midxAndOneUncoveredPack_midxAndPack() { + DfsPackDescription gc = pack("aaaa", GC, PACK); + DfsPackDescription compact = pack("cccc", COMPACT, PACK); + DfsPackDescription compactTwo = pack("bbbb", COMPACT, PACK); + DfsPackDescription midx = pack("midx", GC, MULTI_PACK_INDEX); + midx.setCoveredPacks(List.of(gc, compact, compactTwo)); + + DfsPackDescription extra = pack("extra", COMPACT, PACK); + + List<DfsPackDescription> reorgPacks = MidxPackFilter + .useMidx(List.of(gc, compact, compactTwo, midx, extra)); + assertEquals(2, reorgPacks.size()); + assertTrue(reorgPacks.contains(midx)); + assertTrue(reorgPacks.contains(extra)); + } + + @Test + public void useMidx_noMidx_allPacks() { + DfsPackDescription gc = pack("aaaa", GC, PACK); + DfsPackDescription compact = pack("cccc", COMPACT, PACK); + DfsPackDescription compactTwo = pack("bbbb", COMPACT, PACK); + + List<DfsPackDescription> reorgPacks = MidxPackFilter + .useMidx(List.of(gc, compact, compactTwo)); + assertEquals(3, reorgPacks.size()); + assertTrue(reorgPacks.contains(gc)); + assertTrue(reorgPacks.contains(compact)); + assertTrue(reorgPacks.contains(compactTwo)); + } + + @Test + public void useMidx_midxMissesOnePack_onlyPacks() { + DfsPackDescription gc = pack("aaaa", GC, PACK); + DfsPackDescription compact = pack("cccc", COMPACT, PACK); + DfsPackDescription compactTwo = pack("bbbb", COMPACT, PACK); + DfsPackDescription midx = pack("midx", GC, MULTI_PACK_INDEX); + midx.setCoveredPacks(List.of(gc, compact, compactTwo)); + + List<DfsPackDescription> reorgPacks = MidxPackFilter + .useMidx(List.of(gc, compactTwo, midx)); // compact missing + assertEquals(2, reorgPacks.size()); + assertTrue(reorgPacks.contains(gc)); + assertTrue(reorgPacks.contains(compactTwo)); + } + + @Test + public void useMidx_nestedMidx_onlyTopMidx() { + DfsPackDescription gc = pack("aaaa", GC, PACK); + DfsPackDescription compact = pack("cccc", COMPACT, PACK); + DfsPackDescription firstMidx = pack("midx1", GC, MULTI_PACK_INDEX); + firstMidx.setCoveredPacks(List.of(gc, compact)); + + DfsPackDescription compact2 = pack("dddd", COMPACT, PACK); + DfsPackDescription compact3 = pack("eeee", COMPACT, PACK); + DfsPackDescription topMidx = pack("midx2", GC, MULTI_PACK_INDEX); + topMidx.setCoveredPacks(List.of(compact2, compact3)); + topMidx.setMultiPackIndexBase(firstMidx); + + List<DfsPackDescription> reorgPacks = MidxPackFilter.useMidx( + List.of(gc, compact, firstMidx, compact2, compact3, topMidx)); + assertEquals(1, reorgPacks.size()); + assertTrue(reorgPacks.contains(topMidx)); + } + + @Test + public void useMidx_nestedMidxAndOnePack_topMidxAndPack() { + DfsPackDescription gc = pack("aaaa", GC, PACK); + DfsPackDescription compact = pack("cccc", COMPACT, PACK); + DfsPackDescription firstMidx = pack("midx1", GC, MULTI_PACK_INDEX); + firstMidx.setCoveredPacks(List.of(gc, compact)); + + DfsPackDescription compact2 = pack("dddd", COMPACT, PACK); + DfsPackDescription compact3 = pack("eeee", COMPACT, PACK); + DfsPackDescription topMidx = pack("midx2", GC, MULTI_PACK_INDEX); + topMidx.setCoveredPacks(List.of(compact2, compact3)); + topMidx.setMultiPackIndexBase(firstMidx); + + DfsPackDescription uncovered = pack("uncovered", INSERT, PACK); + + List<DfsPackDescription> reorgPacks = MidxPackFilter.useMidx(List.of(gc, + compact, firstMidx, compact2, compact3, topMidx, uncovered)); + assertEquals(2, reorgPacks.size()); + assertTrue(reorgPacks.contains(topMidx)); + assertTrue(reorgPacks.contains(uncovered)); + } + + @Test + public void skipMidx_oneMidxCoversAll_allPacks() { + DfsPackDescription gc = pack("aaaa", GC, PACK); + DfsPackDescription compact = pack("cccc", COMPACT, PACK); + DfsPackDescription compactTwo = pack("bbbb", COMPACT, PACK); + DfsPackDescription midx = pack("midx", GC, MULTI_PACK_INDEX); + midx.setCoveredPacks(List.of(gc, compact, compactTwo)); + + List<DfsPackDescription> reorgPacks = MidxPackFilter + .skipMidxs(List.of(gc, compact, compactTwo, midx)); + assertEquals(3, reorgPacks.size()); + assertTrue(reorgPacks.contains(gc)); + assertTrue(reorgPacks.contains(compact)); + assertTrue(reorgPacks.contains(compactTwo)); + } + + @Test + public void skipMidx_midxAndOneUncoveredPack_allPacks() { + DfsPackDescription gc = pack("aaaa", GC, PACK); + DfsPackDescription compact = pack("cccc", COMPACT, PACK); + DfsPackDescription compactTwo = pack("bbbb", COMPACT, PACK); + DfsPackDescription midx = pack("midx", GC, MULTI_PACK_INDEX); + midx.setCoveredPacks(List.of(gc, compact, compactTwo)); + + DfsPackDescription extra = pack("extra", COMPACT, PACK); + + List<DfsPackDescription> reorgPacks = MidxPackFilter + .skipMidxs(List.of(gc, compact, compactTwo, midx, extra)); + assertEquals(4, reorgPacks.size()); + assertTrue(reorgPacks.contains(gc)); + assertTrue(reorgPacks.contains(compact)); + assertTrue(reorgPacks.contains(compactTwo)); + assertTrue(reorgPacks.contains(extra)); + } + + @Test + public void skipMidx_noMidx_allPacks() { + DfsPackDescription gc = pack("aaaa", GC, PACK); + DfsPackDescription compact = pack("cccc", COMPACT, PACK); + DfsPackDescription compactTwo = pack("bbbb", COMPACT, PACK); + + List<DfsPackDescription> reorgPacks = MidxPackFilter + .skipMidxs(List.of(gc, compact, compactTwo)); + assertEquals(3, reorgPacks.size()); + assertTrue(reorgPacks.contains(gc)); + assertTrue(reorgPacks.contains(compact)); + assertTrue(reorgPacks.contains(compactTwo)); + } + + @Test + public void skipMidx_nestedMidx_allPacks() { + DfsPackDescription gc = pack("aaaa", GC, PACK); + DfsPackDescription compact = pack("cccc", COMPACT, PACK); + DfsPackDescription firstMidx = pack("midx1", GC, MULTI_PACK_INDEX); + firstMidx.setCoveredPacks(List.of(gc, compact)); + + DfsPackDescription compact2 = pack("dddd", COMPACT, PACK); + DfsPackDescription compact3 = pack("eeee", COMPACT, PACK); + DfsPackDescription topMidx = pack("midx2", GC, MULTI_PACK_INDEX); + topMidx.setCoveredPacks(List.of(compact2, compact3)); + topMidx.setMultiPackIndexBase(firstMidx); + + List<DfsPackDescription> reorgPacks = MidxPackFilter.skipMidxs( + List.of(gc, compact, firstMidx, compact2, compact3, topMidx)); + assertEquals(4, reorgPacks.size()); + assertTrue(reorgPacks.contains(gc)); + assertTrue(reorgPacks.contains(compact)); + assertTrue(reorgPacks.contains(compact2)); + assertTrue(reorgPacks.contains(compact3)); + } + + @Test + public void skipMidx_nestedMidxAndOnePack_allPacks() { + DfsPackDescription gc = pack("aaaa", GC, PACK); + DfsPackDescription compact = pack("cccc", COMPACT, PACK); + DfsPackDescription firstMidx = pack("midx1", GC, MULTI_PACK_INDEX); + firstMidx.setCoveredPacks(List.of(gc, compact)); + + DfsPackDescription compact2 = pack("dddd", COMPACT, PACK); + DfsPackDescription compact3 = pack("eeee", COMPACT, PACK); + DfsPackDescription topMidx = pack("midx2", GC, MULTI_PACK_INDEX); + topMidx.setCoveredPacks(List.of(compact2, compact3)); + topMidx.setMultiPackIndexBase(firstMidx); + + DfsPackDescription uncovered = pack("uncovered", INSERT, PACK); + + List<DfsPackDescription> reorgPacks = MidxPackFilter + .skipMidxs(List.of(gc, compact, firstMidx, compact2, compact3, + topMidx, uncovered)); + assertEquals(5, reorgPacks.size()); + assertTrue(reorgPacks.contains(gc)); + assertTrue(reorgPacks.contains(compact)); + assertTrue(reorgPacks.contains(compact2)); + assertTrue(reorgPacks.contains(compact3)); + assertTrue(reorgPacks.contains(uncovered)); + } + + private static DfsPackDescription pack(String name, + DfsObjDatabase.PackSource source, PackExt ext) { + DfsPackDescription desc = new DfsPackDescription(repoDesc, name, + source); + desc.setLastModified(timeCounter++); + desc.addFileExt(ext); + return desc; + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackListTest.java new file mode 100644 index 0000000..6ab1156 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackListTest.java
@@ -0,0 +1,252 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.dfs; + +import static java.util.Arrays.asList; +import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.zip.Deflater; + +import org.eclipse.jgit.junit.JGitTestUtil; +import org.eclipse.jgit.junit.TestRng; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectId; +import org.junit.Before; +import org.junit.Test; + +public class MidxPackListTest { + + InMemoryRepository db; + + @Before + public void setUp() { + db = new InMemoryRepository(new DfsRepositoryDescription("test")); + db.getObjectDatabase().setUseMultipackIndex(true); + } + + @Test + public void getAllPlainPacks_onlyPlain() throws IOException { + setupThreePacks(); + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + MidxPackList packList = MidxPackList.create(packs); + assertEquals(3, packList.getAllPlainPacks().size()); + } + + @Test + public void getAllPlainPacks_onlyMidx() throws IOException { + setupThreePacksAndMidx(); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertEquals(1, packs.length); + MidxPackList packList = MidxPackList.create(packs); + assertEquals(3, packList.getAllPlainPacks().size()); + } + + @Test + public void getAllPlainPacks_midxPlusOne() throws IOException { + setupThreePacksAndMidx(); + writePackWithRandomBlob(60); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertEquals(2, packs.length); + MidxPackList packList = MidxPackList.create(packs); + assertEquals(4, packList.getAllPlainPacks().size()); + } + + @Test + public void getAllPlainPacks_nestedMidx() throws IOException { + setupSixPacksThreeMidx(); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertEquals(1, packs.length); + MidxPackList packList = MidxPackList.create(packs); + assertEquals(6, packList.getAllPlainPacks().size()); + } + + @Test + public void getAllMidxPacks_onlyPlain() throws IOException { + setupThreePacks(); + + MidxPackList packList = MidxPackList + .create(db.getObjectDatabase().getPacks()); + assertEquals(0, packList.getAllMidxPacks().size()); + } + + @Test + public void getAllMidxPacks_onlyMidx() throws IOException { + setupThreePacksAndMidx(); + + MidxPackList packList = MidxPackList + .create(db.getObjectDatabase().getPacks()); + assertEquals(1, packList.getAllMidxPacks().size()); + } + + @Test + public void getAllMidxPacks_midxPlusOne() throws IOException { + setupThreePacksAndMidx(); + writePackWithRandomBlob(60); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertEquals(2, packs.length); + MidxPackList packList = MidxPackList.create(packs); + assertEquals(1, packList.getAllMidxPacks().size()); + } + + @Test + public void getAllMidxPacks_nestedMidx() throws IOException { + setupSixPacksThreeMidx(); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertEquals(1, packs.length); + MidxPackList packList = MidxPackList.create(packs); + assertEquals(3, packList.getAllMidxPacks().size()); + } + + @Test + public void findAllImpactedMidx_onlyPacks() throws IOException { + setupThreePacks(); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + MidxPackList packList = MidxPackList + .create(db.getObjectDatabase().getPacks()); + assertEquals(0, packList.findAllCoveringMidxs(asList(packs)).size()); + } + + @Test + public void findAllImpactedMidx_onlyMidx() throws IOException { + setupThreePacksAndMidx(); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + MidxPackList packList = MidxPackList.create(packs); + List<DfsPackFile> covered = ((DfsPackFileMidx) packs[0]) + .getAllCoveredPacks(); + assertEquals(1, packList.findAllCoveringMidxs(covered.get(0)).size()); + assertEquals(1, packList.findAllCoveringMidxs(covered.get(1)).size()); + assertEquals(1, packList.findAllCoveringMidxs(covered.get(2)).size()); + + assertEquals("multiple packs covered", 1, + packList.findAllCoveringMidxs(covered.subList(0, 2)).size()); + } + + @Test + public void findAllImpactedMidx_midxPlusOne() throws IOException { + setupThreePacksAndMidx(); + writePackWithRandomBlob(60); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertEquals(2, packs.length); + + DfsPackFile uncoveredPack = packs[0]; + List<DfsPackFile> coveredPacks = ((DfsPackFileMidx) packs[1]) + .getAllCoveredPacks(); + assertEquals(3, coveredPacks.size()); + + MidxPackList packList = MidxPackList.create(packs); + assertEquals("one non covered", 0, + packList.findAllCoveringMidxs(uncoveredPack).size()); + assertEquals("one and covered", 1, + packList.findAllCoveringMidxs(coveredPacks.get(1)).size()); + assertEquals( + "two, only one covered", 1, packList + .findAllCoveringMidxs( + List.of(uncoveredPack, coveredPacks.get(2))) + .size()); + } + + @Test + public void findAllImpactedMidxs_nestedMidx() throws IOException { + setupSixPacksThreeMidx(); + + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertEquals(1, packs.length); + MidxPackList packList = MidxPackList.create(packs); + List<DfsPackFile> coveredPacks = ((DfsPackFileMidx) packs[0]) + .getAllCoveredPacks(); + assertEquals(6, coveredPacks.size()); + + assertEquals("one covered tip midx", 1, + packList.findAllCoveringMidxs(coveredPacks.get(0)).size()); + assertEquals("one covered middle midx", 2, + packList.findAllCoveringMidxs(coveredPacks.get(2)).size()); + assertEquals("one covered base midx", 3, + packList.findAllCoveringMidxs(coveredPacks.get(4)).size()); + assertEquals( + "multiple covered in chain", 3, packList + .findAllCoveringMidxs(List.of(coveredPacks.get(1), + coveredPacks.get(2), coveredPacks.get(5))) + .size()); + } + + + + private void setupThreePacks() throws IOException { + writePackWithRandomBlob(100); + writePackWithRandomBlob(300); + writePackWithRandomBlob(50); + } + + private void setupThreePacksAndMidx() throws IOException { + writePackWithRandomBlob(100); + writePackWithRandomBlob(300); + writePackWithRandomBlob(50); + writeMultipackIndex(); + } + + private void setupSixPacksThreeMidx() throws IOException { + writePackWithRandomBlob(100); + writePackWithRandomBlob(300); + writePackWithRandomBlob(50); + writePackWithRandomBlob(400); + writePackWithRandomBlob(130); + writePackWithRandomBlob(500); + DfsPackFile[] packs = db.getObjectDatabase().getPacks(); + assertEquals(6, packs.length); + DfsPackFileMidx midxBase = writeMultipackIndex( + Arrays.copyOfRange(packs, 4, 6), null); + DfsPackFileMidx midxMid = writeMultipackIndex( + Arrays.copyOfRange(packs, 2, 4), midxBase); + writeMultipackIndex(Arrays.copyOfRange(packs, 0, 2), midxMid); + assertEquals("only top midx", 1, + db.getObjectDatabase().getPacks().length); + } + + private void writeMultipackIndex() throws IOException { + writeMultipackIndex(db.getObjectDatabase().getPacks(), null); + } + + private DfsPackFileMidx writeMultipackIndex(DfsPackFile[] packs, + DfsPackFileMidx base) throws IOException { + List<DfsPackFile> packfiles = asList(packs); + DfsPackDescription desc = DfsMidxWriter.writeMidx( + NullProgressMonitor.INSTANCE, db.getObjectDatabase(), packfiles, + base != null ? base.getPackDescription() : null); + db.getObjectDatabase().commitPack(List.of(desc), null); + return DfsPackFileMidx.create(DfsBlockCache.getInstance(), desc, + packfiles, base); + } + + private ObjectId writePackWithBlob(byte[] data) throws IOException { + DfsInserter ins = (DfsInserter) db.newObjectInserter(); + ins.setCompressionLevel(Deflater.NO_COMPRESSION); + ObjectId blobId = ins.insert(OBJ_BLOB, data); + ins.flush(); + return blobId; + } + + // Do not use the size twice into the same test (it gives the same blob!) + private ObjectId writePackWithRandomBlob(int size) throws IOException { + byte[] data = new TestRng(JGitTestUtil.getName()).nextBytes(size); + return writePackWithBlob(data); + } +}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoaderTest.java index 494f1d1..3c7e27d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoaderTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexLoaderTest.java
@@ -17,8 +17,8 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import org.eclipse.jgit.internal.storage.file.PackIndex; import org.eclipse.jgit.junit.FakeIndexFactory; @@ -64,8 +64,10 @@ public void load_validFile_basic_jgit() throws Exception { new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000012", 1502))); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo, "p3", - idxThree); + LinkedHashMap<String, PackIndex> packs = new LinkedHashMap<>(3); + packs.put("p1", idxOne); + packs.put("p2", idxTwo); + packs.put("p3", idxThree); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexTest.java index 7af3f54..6436e31 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexTest.java
@@ -20,8 +20,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Set; import org.eclipse.jgit.internal.storage.file.PackIndex; @@ -103,8 +103,8 @@ public void basicMidx() throws IOException { new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000012", 1502))); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo, "p3", - idxThree); + LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne, + "p2", idxTwo, "p3", idxThree); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs); @@ -140,7 +140,8 @@ public void jgit_largeOffsetChunk() throws IOException { "0000000000000000000000000000000000000002", (1L << 35)), new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000003", 13))); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne, + "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs); @@ -170,7 +171,8 @@ public void jgit_largeOffset_noChunk() throws IOException { "0000000000000000000000000000000000000002", 501), new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000003", 13))); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne, + "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs); @@ -206,7 +208,8 @@ public void jgit_resolve() throws IOException { // Match "32fe829a1c000000000000000000000000000010"); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne, + "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs); @@ -249,7 +252,8 @@ public void jgit_resolve_matchLimit() throws IOException { // Match "32fe829a1c000000000000000000000000000010"); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne, + "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs); @@ -283,7 +287,8 @@ public void jgit_resolve_noMatches() throws IOException { "bbbbbb0000000000000000000000000000000003", "32fe829a1c000000000000000000000000000010"); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne, + "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs); @@ -313,7 +318,8 @@ public void jgit_resolve_noMatches_last() throws IOException { "bbbbbb0000000000000000000000000000000003", "32fe829a1c000000000000000000000000000010"); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne, + "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs); @@ -334,7 +340,8 @@ public void jgit_resolve_empty() throws IOException { PackIndex idxOne = FakeIndexFactory.indexOf(List.of()); PackIndex idxTwo = FakeIndexFactory.indexOf(List.of()); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne, + "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs); @@ -371,8 +378,8 @@ public void jgit_findPosition() throws IOException { new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000012", 1502))); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo, "p3", - idxThree); + LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne, + "p2", idxTwo, "p3", idxThree); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs); @@ -426,8 +433,8 @@ public void jgit_getObjectCount() throws IOException { new FakeIndexFactory.IndexObject( "0000000000000000000000000000000000000012", 1502))); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo, "p3", - idxThree); + LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne, + "p2", idxTwo, "p3", idxThree); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs); @@ -442,7 +449,8 @@ public void jgit_getObjectCount_emtpy() throws IOException { PackIndex idxOne = FakeIndexFactory.indexOf(List.of()); PackIndex idxTwo = FakeIndexFactory.indexOf(List.of()); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + LinkedHashMap<String, PackIndex> packs = orderedMapOf("p1", idxOne, + "p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs); @@ -472,4 +480,21 @@ private static void assertInIndex(MultiPackIndex midx, int expectedPackId, packOffset.getPackId()); assertEquals(expectedOffset, packOffset.getOffset()); } + + private static LinkedHashMap<String, PackIndex> orderedMapOf(String s1, + PackIndex pi1, String s2, PackIndex pi2) { + LinkedHashMap<String, PackIndex> map = new LinkedHashMap<>(2); + map.put(s1, pi1); + map.put(s2, pi2); + return map; + } + + private static LinkedHashMap<String, PackIndex> orderedMapOf(String s1, + PackIndex pi1, String s2, PackIndex pi2, String s3, PackIndex pi3) { + LinkedHashMap<String, PackIndex> map = new LinkedHashMap<>(2); + map.put(s1, pi1); + map.put(s2, pi2); + map.put(s3, pi3); + return map; + } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java index 26353d8..9b085a3 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java
@@ -22,8 +22,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import org.eclipse.jgit.internal.storage.file.PackIndex; import org.eclipse.jgit.junit.FakeIndexFactory; @@ -46,8 +46,9 @@ public void write_allSmallOffsets() throws IOException { object("0000000000000000000000000000000000000004", 1500), object("0000000000000000000000000000000000000006", 3000)); - Map<String, PackIndex> data = Map.of("packname1", index1, "packname2", - index2); + LinkedHashMap<String, PackIndex> data = new LinkedHashMap<>(); + data.put("packname1", index1); + data.put("packname2", index2); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -75,13 +76,15 @@ public void write_smallOffset_limit() throws IOException { PackIndex index1 = indexOf( object("0000000000000000000000000000000000000001", 500), object("0000000000000000000000000000000000000003", 1500), - object("0000000000000000000000000000000000000005", (1L << 32) -1)); + object("0000000000000000000000000000000000000005", + (1L << 32) - 1)); PackIndex index2 = indexOf( object("0000000000000000000000000000000000000002", 500), object("0000000000000000000000000000000000000004", 1500), object("0000000000000000000000000000000000000006", 3000)); - Map<String, PackIndex> data = - Map.of("packname1", index1, "packname2", index2); + LinkedHashMap<String, PackIndex> data = new LinkedHashMap<>(2); + data.put("packname1", index1); + data.put("packname2", index2); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -114,12 +117,14 @@ public void write_largeOffset() throws IOException { object("0000000000000000000000000000000000000002", 500), object("0000000000000000000000000000000000000004", 1500), object("0000000000000000000000000000000000000006", 3000)); - Map<String, PackIndex> data = - Map.of("packname1", index1, "packname2", index2); + LinkedHashMap<String, PackIndex> data = new LinkedHashMap<>(2); + data.put("bbbbbbbbb", index1); + data.put("aaaaaaaaa", index2); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); - writer.write(NullProgressMonitor.INSTANCE, out, data); + MultiPackIndexWriter.Result result = writer + .write(NullProgressMonitor.INSTANCE, out, data); // header (12 bytes) // + chunkHeader (7 * 12 bytes) // + fanout table (256 * 4 bytes) @@ -138,13 +143,18 @@ public void write_largeOffset() throws IOException { assertEquals(3, chunkIds.indexOf(MIDX_CHUNKID_LARGEOFFSETS)); assertEquals(4, chunkIds.indexOf(MIDX_CHUNKID_REVINDEX)); assertEquals(5, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES)); + + assertEquals("bbbbbbbbb", result.packNames().get(0)); + assertEquals("aaaaaaaaa", result.packNames().get(1)); } @Test public void jgit_emptyMidx() throws IOException { PackIndex idxOne = FakeIndexFactory.indexOf(List.of()); PackIndex idxTwo = FakeIndexFactory.indexOf(List.of()); - Map<String, PackIndex> packs = Map.of("p1", idxOne, "p2", idxTwo); + LinkedHashMap<String, PackIndex> packs = new LinkedHashMap<>(2); + packs.put("p1", idxOne); + packs.put("p2", idxTwo); MultiPackIndexWriter writer = new MultiPackIndexWriter(); ByteArrayOutputStream out = new ByteArrayOutputStream(); writer.write(NullProgressMonitor.INSTANCE, out, packs);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexMergerTest.java index 8218cbc..0eafdaf 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexMergerTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/PackIndexMergerTest.java
@@ -15,7 +15,7 @@ import java.util.Arrays; import java.util.Iterator; -import java.util.Map; +import java.util.LinkedHashMap; import org.eclipse.jgit.internal.storage.file.PackIndex; import org.eclipse.jgit.junit.FakeIndexFactory; @@ -39,7 +39,7 @@ public void rawIterator_noDuplicates() { oidOffset("0000000000000000000000000000000000000007", 14), oidOffset("0000000000000000000000000000000000000012", 1502)); PackIndexMerger merger = new PackIndexMerger( - Map.of("p1", idxOne, "p2", idxTwo, "p3", idxThree)); + orderedMapOf("p1", idxOne, "p2", idxTwo, "p3", idxThree)); assertEquals(9, merger.getUniqueObjectCount()); assertEquals(3, merger.getPackCount()); assertFalse(merger.needsLargeOffsetsChunk()); @@ -60,13 +60,48 @@ public void rawIterator_noDuplicates() { } @Test + public void rawIterator_noDuplicates_honorPackOrder() { + PackIndex idxOne = indexOf( + oidOffset("0000000000000000000000000000000000000001", 500), + oidOffset("0000000000000000000000000000000000000005", 12), + oidOffset("0000000000000000000000000000000000000010", 1500)); + PackIndex idxTwo = indexOf( + oidOffset("0000000000000000000000000000000000000002", 501), + oidOffset("0000000000000000000000000000000000000003", 13), + oidOffset("0000000000000000000000000000000000000015", 1501)); + PackIndex idxThree = indexOf( + oidOffset("0000000000000000000000000000000000000004", 502), + oidOffset("0000000000000000000000000000000000000007", 14), + oidOffset("0000000000000000000000000000000000000012", 1502)); + PackIndexMerger merger = new PackIndexMerger( + orderedMapOf("p3", idxThree, "p2", idxTwo, "p1", idxOne)); + assertEquals(9, merger.getUniqueObjectCount()); + assertEquals(3, merger.getPackCount()); + assertFalse(merger.needsLargeOffsetsChunk()); + Iterator<PackIndexMerger.MidxMutableEntry> it = merger.rawIterator(); + assertNextEntry(it, "0000000000000000000000000000000000000001", 2, 500); + assertNextEntry(it, "0000000000000000000000000000000000000002", 1, 501); + assertNextEntry(it, "0000000000000000000000000000000000000003", 1, 13); + assertNextEntry(it, "0000000000000000000000000000000000000004", 0, 502); + assertNextEntry(it, "0000000000000000000000000000000000000005", 2, 12); + assertNextEntry(it, "0000000000000000000000000000000000000007", 0, 14); + assertNextEntry(it, "0000000000000000000000000000000000000010", 2, + 1500); + assertNextEntry(it, "0000000000000000000000000000000000000012", 0, + 1502); + assertNextEntry(it, "0000000000000000000000000000000000000015", 1, + 1501); + assertFalse(it.hasNext()); + } + + @Test public void rawIterator_allDuplicates() { PackIndex idxOne = indexOf( oidOffset("0000000000000000000000000000000000000001", 500), oidOffset("0000000000000000000000000000000000000005", 12), oidOffset("0000000000000000000000000000000000000010", 1500)); PackIndexMerger merger = new PackIndexMerger( - Map.of("p1", idxOne, "p2", idxOne, "p3", idxOne)); + orderedMapOf("p1", idxOne, "p2", idxOne, "p3", idxOne)); assertEquals(3, merger.getUniqueObjectCount()); assertEquals(3, merger.getPackCount()); assertFalse(merger.needsLargeOffsetsChunk()); @@ -101,7 +136,7 @@ public void bySha1Iterator_noDuplicates() { oidOffset("0000000000000000000000000000000000000007", 14), oidOffset("0000000000000000000000000000000000000012", 1502)); PackIndexMerger merger = new PackIndexMerger( - Map.of("p1", idxOne, "p2", idxTwo, "p3", idxThree)); + orderedMapOf("p1", idxOne, "p2", idxTwo, "p3", idxThree)); assertEquals(9, merger.getUniqueObjectCount()); assertEquals(3, merger.getPackCount()); assertFalse(merger.needsLargeOffsetsChunk()); @@ -128,7 +163,7 @@ public void bySha1Iterator_allDuplicates() { oidOffset("0000000000000000000000000000000000000005", 12), oidOffset("0000000000000000000000000000000000000010", 1500)); PackIndexMerger merger = new PackIndexMerger( - Map.of("p1", idxOne, "p2", idxOne, "p3", idxOne)); + orderedMapOf("p1", idxOne, "p2", idxOne, "p3", idxOne)); assertEquals(3, merger.getUniqueObjectCount()); assertEquals(3, merger.getPackCount()); assertFalse(merger.needsLargeOffsetsChunk()); @@ -152,7 +187,7 @@ public void bySha1Iterator_differentIndexSizes() { oidOffset("0000000000000000000000000000000000000007", 12), oidOffset("0000000000000000000000000000000000000012", 1500)); PackIndexMerger merger = new PackIndexMerger( - Map.of("p1", idxOne, "p2", idxTwo, "p3", idxThree)); + orderedMapOf("p1", idxOne, "p2", idxTwo, "p3", idxThree)); assertEquals(6, merger.getUniqueObjectCount()); assertEquals(3, merger.getPackCount()); assertFalse(merger.needsLargeOffsetsChunk()); @@ -170,7 +205,7 @@ public void bySha1Iterator_differentIndexSizes() { @Test public void merger_noIndexes() { - PackIndexMerger merger = new PackIndexMerger(Map.of()); + PackIndexMerger merger = new PackIndexMerger(new LinkedHashMap<>()); assertEquals(0, merger.getUniqueObjectCount()); assertFalse(merger.needsLargeOffsetsChunk()); assertTrue(merger.getPackNames().isEmpty()); @@ -181,7 +216,7 @@ public void merger_noIndexes() { @Test public void merger_emptyIndexes() { PackIndexMerger merger = new PackIndexMerger( - Map.of("p1", indexOf(), "p2", indexOf())); + orderedMapOf("p1", indexOf(), "p2", indexOf())); assertEquals(0, merger.getUniqueObjectCount()); assertFalse(merger.needsLargeOffsetsChunk()); assertEquals(2, merger.getPackNames().size()); @@ -197,7 +232,7 @@ public void bySha1Iterator_largeOffsets_needsChunk() { PackIndex idx2 = indexOf(oidOffset( "0000000000000000000000000000000000000003", (1L << 31) + 10)); PackIndexMerger merger = new PackIndexMerger( - Map.of("p1", idx1, "p2", idx2)); + orderedMapOf("p1", idx1, "p2", idx2)); assertTrue(merger.needsLargeOffsetsChunk()); assertEquals(2, merger.getOffsetsOver31BitsCount()); assertEquals(3, merger.getUniqueObjectCount()); @@ -213,7 +248,7 @@ public void bySha1Iterator_largeOffsets_noChunk() { PackIndex idx2 = indexOf(oidOffset( "0000000000000000000000000000000000000003", (1L << 31) + 10)); PackIndexMerger merger = new PackIndexMerger( - Map.of("p1", idx1, "p2", idx2)); + orderedMapOf("p1", idx1, "p2", idx2)); assertFalse(merger.needsLargeOffsetsChunk()); assertEquals(2, merger.getOffsetsOver31BitsCount()); assertEquals(3, merger.getUniqueObjectCount()); @@ -236,4 +271,22 @@ private static IndexObject oidOffset(String oid, long offset) { private static PackIndex indexOf(IndexObject... objs) { return FakeIndexFactory.indexOf(Arrays.asList(objs)); } + + private static LinkedHashMap<String, PackIndex> orderedMapOf(String s1, + PackIndex pi1, String s2, PackIndex pi2) { + LinkedHashMap map = new LinkedHashMap(3); + map.put(s1, pi1); + map.put(s2, pi2); + return map; + } + + private static LinkedHashMap<String, PackIndex> orderedMapOf(String s1, + PackIndex pi1, String s2, PackIndex pi2, String s3, PackIndex pi3) { + LinkedHashMap map = new LinkedHashMap(3); + map.put(s1, pi1); + map.put(s2, pi2); + map.put(s3, pi3); + return map; + } + }
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 5db4563..118ce18 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
@@ -57,6 +57,7 @@ import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; +import java.util.List; import org.eclipse.jgit.errors.PackProtocolException; import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; @@ -364,6 +365,77 @@ public void testMissingPusheeField() throws Exception { assertFalse(cert.toText().contains(PushCertificateParser.PUSHEE)); } + @Test + public void testWithPushOptions() throws Exception { + // Same cert as INPUT, but with push-option lines added after nonce + String inputWithOptions = "001ccertificate version 0.1\n" + + "0041pusher Dave Borowitz <dborowitz@google.com> 1433954361 -0700\n" + + "0024pushee git://localhost/repo.git\n" + + "002anonce 1433954361-bde756572d665bba81d8\n" + + "0024push-option label=Code-Review+2\n" + + "0021push-option label=Verified+1\n" + + "0017push-option submit\n" + + "0020push-option hashtag=bug fix\n" + + "0005\n" + + "00680000000000000000000000000000000000000000" + + " 6c2b981a177396fb47345b7df3e4d3f854c6bea7" + + " refs/heads/master\n" + + "0022-----BEGIN PGP SIGNATURE-----\n" + + "0016Version: GnuPG v1\n" + + "0005\n" + + "0045iQEcBAABAgAGBQJVeGg5AAoJEPfTicJkUdPkUggH/RKAeI9/i/LduuiqrL/SSdIa\n" + + "00459tYaSqJKLbXz63M/AW4Sp+4u+dVCQvnAt/a35CVEnpZz6hN4Kn/tiswOWVJf4CO7\n" + + "0045htNubGs5ZMwvD6sLYqKAnrM3WxV/2TbbjzjZW6Jkidz3jz/WRT4SmjGYiEO7aA+V\n" + + "00454ZdIS9f7sW5VsHHYlNThCA7vH8Uu48bUovFXyQlPTX0pToSgrWV3JnTxDNxfn3iG\n" + + "0045IL0zTY/qwVCdXgFownLcs6J050xrrBWIKqfcWr3u4D2aCLyR0v+S/KArr7ulZygY\n" + + "0045+SOklImn8TAZiNxhWtA6ens66IiammUkZYFv7SSzoPLFZT4dC84SmGPWgf94NoQ=\n" + + "000a=XFeC\n" + + "0020-----END PGP SIGNATURE-----\n" + + "0012push-cert-end\n"; + + PacketLineIn pckIn = newPacketLineIn(inputWithOptions); + PushCertificateParser parser = + new PushCertificateParser(db, newEnabledConfig()); + parser.receiveHeader(pckIn, false); + + parser.addCommand(pckIn.readString()); + assertEquals(PushCertificateParser.BEGIN_SIGNATURE, pckIn.readString()); + parser.receiveSignature(pckIn); + + PushCertificate cert = parser.build(); + assertNotNull(cert); + assertEquals("0.1", cert.getVersion()); + assertEquals("Dave Borowitz", cert.getPusherIdent().getName()); + + // Verify push options were parsed and are available on the certificate + List<String> pushOptions = cert.getPushOptions(); + assertEquals(4, pushOptions.size()); + assertEquals("label=Code-Review+2", pushOptions.get(0)); + assertEquals("label=Verified+1", pushOptions.get(1)); + assertEquals("submit", pushOptions.get(2)); + assertEquals("hashtag=bug fix", pushOptions.get(3)); + + // Verify that toText() includes push options (critical for signature verification) + String text = cert.toText(); + assertTrue("toText() must include push-option lines", + text.contains("push-option label=Code-Review+2")); + assertTrue("toText() must include push-option lines", + text.contains("push-option label=Verified+1")); + assertTrue("toText() must include push-option lines", + text.contains("push-option submit")); + assertTrue("toText() must include push-option lines", + text.contains("push-option hashtag=bug fix")); + + // Verify push options appear after nonce and before empty line + int nonceIndex = text.indexOf("nonce"); + int pushOptionIndex = text.indexOf("push-option"); + int emptyLineIndex = text.indexOf("\n\n"); + assertTrue("push-option must appear after nonce", + pushOptionIndex > nonceIndex); + assertTrue("push-option must appear before empty line separator", + pushOptionIndex < emptyLineIndex); + } + private static String concatPacketLines(String input, int begin, int end) throws IOException { StringBuilder result = new StringBuilder();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackTest.java index 156746d..595b970 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackTest.java
@@ -45,8 +45,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + import org.eclipse.jgit.errors.PackProtocolException; +import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.transport.ReceiveCommand.Result; import org.junit.Test; /** Tests for receive-pack utilities. */ @@ -82,4 +89,62 @@ private void assertParseCommandFails(String input) { // Expected. } } + + @Test + public void testCertificatePushOptionsMismatch() throws Exception { + ReceiveCommand cmd1 = new ReceiveCommand( + ObjectId.fromString("0000000000000000000000000000000000000000"), + ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"), + "refs/heads/master"); + ReceiveCommand cmd2 = new ReceiveCommand( + ObjectId.fromString("0000000000000000000000000000000000000000"), + ObjectId.fromString("badc0ffebadc0ffebadc0ffebadc0ffebadc0ffe"), + "refs/heads/branch"); + + List<ReceiveCommand> commands = new ArrayList<>(); + commands.add(cmd1); + commands.add(cmd2); + + ReceivePack.validateCertificatePushOptions( + Arrays.asList("option1", "option2"), + Arrays.asList("option1", "different"), commands); + + assertEquals(Result.REJECTED_OTHER_REASON, cmd1.getResult()); + assertEquals(Result.REJECTED_OTHER_REASON, cmd2.getResult()); + assertEquals(JGitText.get().pushCertificateInconsistentPushOptions, + cmd1.getMessage()); + assertEquals(JGitText.get().pushCertificateInconsistentPushOptions, + cmd2.getMessage()); + } + + @Test + public void testCertificatePushOptionsMatch() throws Exception { + ReceiveCommand cmd = new ReceiveCommand( + ObjectId.fromString("0000000000000000000000000000000000000000"), + ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"), + "refs/heads/master"); + + List<ReceiveCommand> commands = Collections.singletonList(cmd); + + ReceivePack.validateCertificatePushOptions( + Arrays.asList("option1", "option2"), + Arrays.asList("option1", "option2"), commands); + + assertEquals(Result.NOT_ATTEMPTED, cmd.getResult()); + } + + @Test + public void testCertificatePushOptionsNullTreatedAsEmpty() throws Exception { + ReceiveCommand cmd = new ReceiveCommand( + ObjectId.fromString("0000000000000000000000000000000000000000"), + ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"), + "refs/heads/master"); + + List<ReceiveCommand> commands = Collections.singletonList(cmd); + + ReceivePack.validateCertificatePushOptions(Collections.emptyList(), + null, commands); + + assertEquals(Result.NOT_ATTEMPTED, cmd.getResult()); + } }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/InterruptTimerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/InterruptTimerTest.java new file mode 100644 index 0000000..68de7d6 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/InterruptTimerTest.java
@@ -0,0 +1,182 @@ +/* + * Copyright (C) 2025, NVIDIA CORPORATION + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.util.io; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import java.util.Arrays; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class InterruptTimerTest { + private static final int MULTIPLIER = 1; // Increase if tests get flaky + private static final int BUFFER = 5; // Increase if tests get flaky + private static final int REPEATS = 100; // Increase to stress test more + + private static final int TOO_LONG = 3 * MULTIPLIER + BUFFER; + private static final int SHORT_ENOUGH = 1 * MULTIPLIER; + private static final int TIMEOUT_LONG_ENOUGH = TOO_LONG; + private static final int TIMEOUT_TOO_SHORT = SHORT_ENOUGH; + + private InterruptTimer timer; + + @Before + public void setUp() { + timer = new InterruptTimer(); + } + + @After + public void tearDown() { + timer.terminate(); + for (Thread t : active()) + assertFalse(t instanceof InterruptTimer.AlarmThread); + } + + @Test + public void testShortEnough() { + int interrupted = 0; + try { + timer.begin(TIMEOUT_LONG_ENOUGH); + Thread.sleep(SHORT_ENOUGH); + timer.end(); + } catch (InterruptedException e) { + interrupted++; + } + assertEquals("Was Not Interrupted", interrupted, 0); + } + + @Test + public void testTooLong() { + int interrupted = 0; + try { + timer.begin(TIMEOUT_TOO_SHORT); + Thread.sleep(TOO_LONG); + timer.end(); + } catch (InterruptedException e) { + interrupted++; + } + assertEquals("Was Interrupted", interrupted, 1); + } + + @Test + public void testNotInterruptedAfterEnd() { + int interrupted = 0; + try { + timer.begin(TIMEOUT_LONG_ENOUGH); + Thread.sleep(SHORT_ENOUGH); + timer.end(); + Thread.sleep(TIMEOUT_LONG_ENOUGH * 3); + } catch (InterruptedException e) { + interrupted++; + } + assertEquals("Was Not Interrupted Even After End", interrupted, 0); + } + + @Test + public void testRestartBeforeTimeout() { + int interrupted = 0; + try { + timer.begin(TIMEOUT_LONG_ENOUGH * 2); + Thread.sleep(SHORT_ENOUGH); + timer.end(); + timer.begin(TIMEOUT_LONG_ENOUGH); + Thread.sleep(SHORT_ENOUGH); + timer.end(); + } catch (InterruptedException e) { + interrupted++; + } + assertEquals("Was Not Interrupted Even When Restarted Before Timeout", interrupted, 0); + } + + @Test + public void testSecondExpiresBeforeFirst() { + int interrupted = 0; + try { + timer.begin(TIMEOUT_LONG_ENOUGH * 3); + Thread.sleep(SHORT_ENOUGH); + timer.end(); + timer.begin(TIMEOUT_TOO_SHORT); + Thread.sleep(TOO_LONG); + timer.end(); + } catch (InterruptedException e) { + interrupted++; + } + assertEquals("Was Interrupted Even When Second Timeout Expired Before First", interrupted, 1); + } + + @Test + public void testRepeatedShortEnough() { + int interrupted = 0; + for (int i = 0; i < REPEATS; i++) { + try { + timer.begin(TIMEOUT_LONG_ENOUGH); + Thread.sleep(SHORT_ENOUGH); + timer.end(); + } catch (InterruptedException e) { + interrupted++; + } + } + assertEquals("Was Never Interrupted", interrupted, 0); + } + + @Test + public void testRepeatedTooLong() { + int interrupted = 0; + for (int i = 0; i < REPEATS; i++) { + try { + timer.begin(TIMEOUT_TOO_SHORT); + Thread.sleep(TOO_LONG); + timer.end(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + interrupted++; + } + } + assertEquals("Was always Interrupted", interrupted, REPEATS); + } + + @Test + public void testRepeatedShortThanTooLong() { + int interrupted = 0; + for (int i = 0; i < REPEATS; i++) { + try { + timer.begin(TIMEOUT_LONG_ENOUGH); + Thread.sleep(SHORT_ENOUGH); + timer.end(); + } catch (InterruptedException e) { + interrupted++; + } + } + assertEquals("Was Not Interrupted Early", interrupted, 0); + try { + timer.begin(TIMEOUT_TOO_SHORT); + Thread.sleep(TOO_LONG); + timer.end(); + } catch (InterruptedException e) { + interrupted++; + } + assertEquals("Was Interrupted On Long", interrupted, 1); + } + + private static List<Thread> active() { + Thread[] all = new Thread[16]; + int n = Thread.currentThread().getThreadGroup().enumerate(all); + while (n == all.length) { + all = new Thread[all.length * 2]; + n = Thread.currentThread().getThreadGroup().enumerate(all); + } + return Arrays.asList(all).subList(0, n); + } +}
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index f0cf71d..d760003 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -103,9 +103,12 @@ org.eclipse.jgit.junit.http, org.eclipse.jgit.http.server, org.eclipse.jgit.lfs, + org.eclipse.jgit.lfs.test, org.eclipse.jgit.pgm, org.eclipse.jgit.pgm.test, - org.eclipse.jgit.ssh.apache", + org.eclipse.jgit.ssh.apache, + org.eclipse.jgit.ssh.apache.test, + org.eclipse.jgit.ssh.jsch.test", org.eclipse.jgit.internal.storage.io;version="7.5.0"; x-friends:="org.eclipse.jgit.junit, org.eclipse.jgit.test,
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 e24cba6..6158032 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -638,6 +638,7 @@ pushCertificateInvalidFieldValue=Push certificate has missing or invalid value for {0}: {1} pushCertificateInvalidHeader=Push certificate has invalid header format pushCertificateInvalidSignature=Push certificate has invalid signature format +pushCertificateInconsistentPushOptions=Push certificate push options do not match command push options pushDefaultNothing=No refspec given and push.default=nothing; no upstream branch can be determined pushDefaultNoUpstream=No upstream branch found for local branch ''{0}'' pushDefaultSimple=push.default=simple requires local branch name ''{0}'' to be equal to upstream tracked branch name ''{1}''
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 8928f47..9bd99ed 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -669,6 +669,7 @@ public static JGitText get() { /***/ public String pushCertificateInvalidFieldValue; /***/ public String pushCertificateInvalidHeader; /***/ public String pushCertificateInvalidSignature; + /***/ public String pushCertificateInconsistentPushOptions; /***/ public String pushDefaultNothing; /***/ public String pushDefaultNoUpstream; /***/ public String pushDefaultSimple;
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 199481c..78d65b5 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
@@ -18,6 +18,7 @@ import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE; import static org.eclipse.jgit.internal.storage.dfs.DfsPackCompactor.configureReftable; import static org.eclipse.jgit.internal.storage.pack.PackExt.COMMIT_GRAPH; +import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; @@ -25,6 +26,7 @@ import java.io.IOException; import java.time.Instant; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -33,6 +35,7 @@ import java.util.GregorianCalendar; import java.util.HashSet; import java.util.List; +import java.util.Queue; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -95,6 +98,8 @@ public class DfsGarbageCollector { private List<DfsReftable> reftablesBefore; private List<DfsPackFile> expiredGarbagePacks; + private List<DfsPackFileMidx> existingMidxs; + private Collection<Ref> refsBefore; private Set<ObjectId> allHeadsAndTags; private Set<ObjectId> allTags; @@ -431,9 +436,11 @@ private Collection<Ref> getAllRefs() throws IOException { } private void readPacksBefore() throws IOException { - DfsPackFile[] packs = objdb.getPacks(); - packsBefore = new ArrayList<>(packs.length); - expiredGarbagePacks = new ArrayList<>(packs.length); + DfsPackFile[] rawPacks = objdb.getPacks(); + List<DfsPackFile> packs = getPlainPacks(rawPacks); + existingMidxs = getMidxPacks(rawPacks); + packsBefore = new ArrayList<>(packs.size()); + expiredGarbagePacks = new ArrayList<>(packs.size()); long now = SystemReader.getInstance().now().toEpochMilli(); for (DfsPackFile p : packs) { @@ -448,6 +455,41 @@ private void readPacksBefore() throws IOException { } } + private static List<DfsPackFile> getPlainPacks(DfsPackFile[] packs) { + List<DfsPackFile> plainPacks = new ArrayList<>(); + Queue<DfsPackFile> pending = new ArrayDeque<>( + Arrays.stream(packs).toList()); + while (!pending.isEmpty()) { + DfsPackFile pack = pending.poll(); + if (pack instanceof DfsPackFileMidx midxPack) { + plainPacks.addAll(midxPack.getCoveredPacks()); + if (midxPack.getMultipackIndexBase() != null) { + pending.add(midxPack.getMultipackIndexBase()); + } + } else { + plainPacks.add(pack); + } + } + return plainPacks; + } + + private static List<DfsPackFileMidx> getMidxPacks(DfsPackFile[] packs) { + List<DfsPackFileMidx> topLevelMidxs = Arrays.stream(packs).filter( + p -> p.getPackDescription().hasFileExt(MULTI_PACK_INDEX)) + .map(p -> (DfsPackFileMidx) p).toList(); + + List<DfsPackFileMidx> midxPacks = new ArrayList<>(); + Queue<DfsPackFileMidx> pending = new ArrayDeque<>(topLevelMidxs); + while (!pending.isEmpty()) { + DfsPackFileMidx midx = pending.poll(); + midxPacks.add(midx); + if (midx.getMultipackIndexBase() != null) { + pending.add(midx.getMultipackIndexBase()); + } + } + return midxPacks; + } + private void readReftablesBefore() throws IOException { DfsReftable[] tables = objdb.getReftables(); reftablesBefore = new ArrayList<>(Arrays.asList(tables)); @@ -568,6 +610,11 @@ private Set<DfsPackDescription> toPrune() { for (DfsPackFile pack : expiredGarbagePacks) { toPrune.add(pack.getPackDescription()); } + + for (DfsPackFileMidx pack : existingMidxs) { + toPrune.add(pack.getPackDescription()); + } + return toPrune; }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java new file mode 100644 index 0000000..28ef98d --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java
@@ -0,0 +1,87 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.dfs; + +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; +import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC; +import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.internal.storage.midx.MultiPackIndexWriter; +import org.eclipse.jgit.lib.ProgressMonitor; + +/** + * Create a pack with a multipack index, setting the required fields in the + * description. + */ +public class DfsMidxWriter { + + private DfsMidxWriter() { + } + + /** + * Create a pack with the multipack index + * + * @param pm + * a progress monitor + * @param objdb + * an object database + * @param packs + * the packs to cover + * @param base + * parent of this midx in the chain (if any). + * @return a pack (uncommitted) with the multipack index of the packs passed + * as parameter. + * @throws IOException + * an error opening the packs or writing the stream. + */ + public static DfsPackDescription writeMidx(ProgressMonitor pm, + DfsObjDatabase objdb, List<DfsPackFile> packs, + @Nullable DfsPackDescription base) throws IOException { + LinkedHashMap<String, PackIndex> inputs = new LinkedHashMap<>( + packs.size()); + try (DfsReader ctx = objdb.newReader()) { + for (DfsPackFile pack : packs) { + inputs.put(pack.getPackDescription().getPackName(), + pack.getPackIndex(ctx)); + } + } + + DfsPackDescription midxPackDesc = objdb.newPack(GC); + try (DfsOutputStream out = objdb.writeFile(midxPackDesc, + MULTI_PACK_INDEX)) { + MultiPackIndexWriter w = new MultiPackIndexWriter(); + MultiPackIndexWriter.Result result = w.write(pm, out, inputs); + midxPackDesc.addFileExt(MULTI_PACK_INDEX); + midxPackDesc.setObjectCount(result.objectCount()); + + Map<String, DfsPackDescription> byName = packs.stream() + .map(DfsPackFile::getPackDescription) + .collect(toMap(DfsPackDescription::getPackName, + Function.identity())); + List<DfsPackDescription> coveredPacks = result.packNames().stream() + .map(byName::get).collect(toList()); + midxPackDesc.setCoveredPacks(coveredPacks); + if (base != null) { + midxPackDesc.setMultiPackIndexBase(base); + } + } + + return midxPackDesc; + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java index 1a873d1..7b7a378 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
@@ -13,13 +13,14 @@ import static java.util.stream.Collectors.joining; import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; +import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX; +import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; @@ -27,13 +28,15 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; import org.eclipse.jgit.internal.storage.file.BasePackIndexWriter; import org.eclipse.jgit.internal.storage.file.PackBitmapIndexWriterV1; -import org.eclipse.jgit.internal.storage.pack.PackIndexWriter; import org.eclipse.jgit.internal.storage.pack.PackBitmapIndexWriter; import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.internal.storage.pack.PackIndexWriter; import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.ObjectDatabase; import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.ObjectReader; @@ -198,6 +201,8 @@ public String toString() { private Comparator<DfsPackDescription> packComparator; + private boolean useMultipackIndex; + /** * Initialize an object database for our repository. * @@ -212,6 +217,9 @@ protected DfsObjDatabase(DfsRepository repository, this.packList = new AtomicReference<>(NO_PACKS); this.readerOptions = options; this.packComparator = DfsPackDescription.objectLookupComparator(); + this.useMultipackIndex = repository.getConfig().getBoolean( + ConfigConstants.CONFIG_CORE_SECTION, + ConfigConstants.CONFIG_KEY_MULTIPACKINDEX, false); } /** @@ -249,6 +257,28 @@ public ObjectInserter newInserter() { } /** + * Whether to use multipack indexes in the list of packs + * <p> + * This overrides the value in the core.multiPackIndex config key read at + * construction time. + * + * @param value + * value to set in the flag + */ + public void setUseMultipackIndex(boolean value) { + this.useMultipackIndex = value; + } + + /** + * Should this object db return multipack indexes + * + * @return current value of the flag + */ + protected boolean useMultipackIndex() { + return this.useMultipackIndex; + } + + /** * Scan and list all available pack files in the repository. * * @return list of available packs. The returned array is shared with the @@ -455,6 +485,11 @@ protected abstract void commitPackImpl(Collection<DfsPackDescription> desc, * The returned list must support random access and must be mutable by the * caller. It is sorted in place using the natural sorting of the returned * DfsPackDescription objects. + * <p> + * With multipack index enabled, this method returns the descriptions of the + * multipack index(es) (which include descriptions of covered packs) and of + * packs not covered by the midxs. With multipack index disabled, it returns + * only regular packs (the midx is just ignored). * * @return available packs. May be empty if there are no packs. * @throws java.io.IOException @@ -579,10 +614,10 @@ private PackList scanPacksImpl(PackList old) throws IOException { Map<DfsPackDescription, DfsReftable> reftables = reftableMap(old); List<DfsPackDescription> scanned = listPacks(); - Collections.sort(scanned, packComparator); + scanned.sort(packComparator); List<DfsPackFile> newPacks = new ArrayList<>(scanned.size()); - List<DfsReftable> newReftables = new ArrayList<>(scanned.size()); + List<DfsPackDescription> packsWithReftables = new ArrayList<>(); boolean foundNew = false; for (DfsPackDescription dsc : scanned) { DfsPackFile oldPack = packs.remove(dsc); @@ -591,8 +626,20 @@ private PackList scanPacksImpl(PackList old) throws IOException { } else if (dsc.hasFileExt(PackExt.PACK)) { newPacks.add(createDfsPackFile(cache, dsc)); foundNew = true; + } else if (dsc.hasFileExt(MULTI_PACK_INDEX)) { + newPacks.add( + createDfsPackFileMidx(cache, dsc, packsWithReftables)); + foundNew = true; } + if (dsc.hasFileExt(REFTABLE)) { + packsWithReftables.add(dsc); + } + } + + List<DfsReftable> newReftables = new ArrayList<>( + packsWithReftables.size()); + for (DfsPackDescription dsc : packsWithReftables) { DfsReftable oldReftable = reftables.remove(dsc); if (oldReftable != null) { newReftables.add(oldReftable); @@ -607,7 +654,7 @@ private PackList scanPacksImpl(PackList old) throws IOException { if (!foundNew) { return old; } - Collections.sort(newReftables, reftableComparator()); + newReftables.sort(reftableComparator()); return new PackList( newPacks.toArray(new DfsPackFile[0]), newReftables.toArray(new DfsReftable[0])); @@ -615,7 +662,7 @@ private PackList scanPacksImpl(PackList old) throws IOException { /** * Create instances of DfsPackFile - * + * <p> * Implementors can decide to construct or wrap DfsPackFile in different * ways. * @@ -630,6 +677,38 @@ protected DfsPackFile createDfsPackFile(DfsBlockCache cache, return new DfsPackFile(cache, dsc); } + /** + * Create instances of DfsPackFileMidx + * + * @param cache + * block cache + * @param dsc + * pack description + * @param containsReftables + * used to return packs inside this midx that also have reftables + * + * @return the dfs packfile + */ + protected DfsPackFileMidx createDfsPackFileMidx(DfsBlockCache cache, + DfsPackDescription dsc, + List<DfsPackDescription> containsReftables) { + DfsPackFileMidx base = null; + if (dsc.getMultiPackIndexBase() != null) { + // The base is always a multipack index + base = createDfsPackFileMidx(cache, dsc.getMultiPackIndexBase(), + containsReftables); + } + // A pack shouldn't be in the pack list and inside a multipack index + // at the same time. In that case, we will have it under two + // different DfsPackFile instances. + List<DfsPackFile> coveredPacks = dsc.getCoveredPacks().stream() + .map(desc -> createDfsPackFile(cache, desc)) + .collect(Collectors.toUnmodifiableList()); + dsc.getCoveredPacks().stream().filter(d -> d.hasFileExt(REFTABLE)) + .forEach(containsReftables::add); + return DfsPackFileMidx.create(cache, dsc, coveredPacks, base); + } + private static Map<DfsPackDescription, DfsPackFile> packMap(PackList old) { Map<DfsPackDescription, DfsPackFile> forReuse = new HashMap<>(); for (DfsPackFile p : old.packs) {
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 6339b03..8860cce 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
@@ -11,7 +11,6 @@ package org.eclipse.jgit.internal.storage.dfs; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.COMPACT; -import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC; import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; @@ -68,10 +67,11 @@ public class DfsPackCompactor { private final List<DfsReftable> srcReftables; private final List<ObjectIdSet> exclude; + private final List<DfsPackDescription> prune; + private PackStatistics newStats; private DfsPackDescription outDesc; - private int autoAddSize; private ReftableConfig reftableConfig; private RevWalk rw; @@ -86,10 +86,10 @@ public class DfsPackCompactor { */ public DfsPackCompactor(DfsRepository repository) { repo = repository; - autoAddSize = 5 * 1024 * 1024; // 5 MiB srcPacks = new ArrayList<>(); srcReftables = new ArrayList<>(); exclude = new ArrayList<>(4); + prune = new ArrayList<>(); } /** @@ -135,38 +135,6 @@ public DfsPackCompactor add(DfsReftable table) { } /** - * Automatically select pack and reftables to be included, and add them. - * <p> - * Packs are selected based on size, smaller packs get included while bigger - * ones are omitted. - * - * @return {@code this} - * @throws java.io.IOException - * existing packs cannot be read. - */ - public DfsPackCompactor autoAdd() throws IOException { - DfsObjDatabase objdb = repo.getObjectDatabase(); - for (DfsPackFile pack : objdb.getPacks()) { - DfsPackDescription d = pack.getPackDescription(); - if (d.getFileSize(PACK) < autoAddSize) - add(pack); - else - exclude(pack); - } - - if (reftableConfig != null) { - for (DfsReftable table : objdb.getReftables()) { - DfsPackDescription d = table.getPackDescription(); - if (d.getPackSource() != GC - && d.getFileSize(REFTABLE) < autoAddSize) { - add(table); - } - } - } - return this; - } - - /** * Exclude objects from the compacted pack. * * @param set @@ -188,11 +156,23 @@ public DfsPackCompactor exclude(ObjectIdSet set) { * pack index cannot be loaded. */ public DfsPackCompactor exclude(DfsPackFile pack) throws IOException { - final PackIndex idx; + final ObjectIdSet objectIdSet; try (DfsReader ctx = (DfsReader) repo.newObjectReader()) { - idx = pack.getPackIndex(ctx); + objectIdSet = pack.asObjectIdSet(ctx); } - return exclude(idx); + return exclude(objectIdSet); + } + + /** + * Delete also this pack when writing to the db the compacted packs + * + * @param pack + * a pack to delete + * @return {@code this} + */ + public DfsPackCompactor prune(DfsPackFile pack) { + prune.add(pack.getPackDescription()); + return this; } /** @@ -367,6 +347,7 @@ private Collection<DfsPackDescription> toPrune() { Set<DfsPackDescription> toPrune = new HashSet<>(); toPrune.addAll(packs); toPrune.addAll(reftables); + toPrune.addAll(prune); return toPrune; }
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 3aacdc2..ecc97e9 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
@@ -37,6 +37,7 @@ import java.util.zip.DataFormatException; import java.util.zip.Inflater; +import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.errors.MissingObjectException; @@ -57,9 +58,11 @@ import org.eclipse.jgit.internal.storage.pack.StoredObjectRepresentation; import org.eclipse.jgit.lib.AbbreviatedObjectId; import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.BitmapIndex; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdSet; import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; @@ -251,6 +254,22 @@ public PackIndex getPackIndex(DfsReader ctx) throws IOException { return idx(ctx); } + /** + * Get a view of this packfile as a set of objects + * <p> + * To use when the caller only needs to check inclusion (without specific + * order or getting offsets). + * + * @param ctx + * reader context + * @return a view of this packfile as a set of objects + * @throws IOException + * cannot load the backing data from storage + */ + public ObjectIdSet asObjectIdSet(DfsReader ctx) throws IOException { + return idx(ctx); + } + private PackIndex idx(DfsReader ctx) throws IOException { if (index != null) { return index; @@ -1204,6 +1223,34 @@ long getIndexedObjectSize(DfsReader ctx, int idxPosition) } /** + * Return pack(s) with all its objects included in the bitmap. + * <p> + * The bitmap is modified removing the objects in the returned packs. + * <p> + * The list could contain more than one pack in the multipack-index case. + * + * @param ctx + * a reader + * @param need + * bitmap with the required objects. It can be modified in this + * call. The objects from the returned packs are removed from the + * bitmap. + * @return list of packs with ALL their objects in the bitmap. + * @throws IOException + * error reading the bitmap index. + */ + @NonNull + List<DfsPackFile> fullyIncludedIn(DfsReader ctx, + BitmapIndex.BitmapBuilder need) throws IOException { + PackBitmapIndex bi = this.getBitmapIndex(ctx); + if (bi != null && need.removeAllOrNone(bi)) { + return Collections.singletonList(this); + } + + return Collections.emptyList(); + } + + /** * Populates the representation object with the details of how the object at * "pos" is stored in this pack (e.g. whole or deltified, its packed * length).
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java index acdbd7e..742fe6c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java
@@ -14,6 +14,7 @@ import java.io.IOException; import java.nio.channels.Channels; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -35,7 +36,9 @@ import org.eclipse.jgit.internal.storage.pack.PackOutputStream; import org.eclipse.jgit.lib.AbbreviatedObjectId; import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.BitmapIndex; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectIdSet; import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.util.BlockList; @@ -45,7 +48,7 @@ * <p> * It uses the position in the multipack index of the objects as their "offset". */ -final class DfsPackFileMidx extends DfsPackFile { +public final class DfsPackFileMidx extends DfsPackFile { private static final int REF_POSITION = 0; @@ -146,18 +149,54 @@ public PackIndex getPackIndex(DfsReader ctx) { } @Override + public ObjectIdSet asObjectIdSet(DfsReader ctx) throws IOException { + MultiPackIndex multiPackIndex = midx(ctx); + return objectId -> multiPackIndex.hasObject(objectId); + } + + @Override public PackReverseIndex getReverseIdx(DfsReader ctx) { throw new IllegalStateException( "Shouldn't use multipack index if the reverse index is needed"); //$NON-NLS-1$ } @Override - public PackBitmapIndex getBitmapIndex(DfsReader ctx) { - // TODO(ifrade): Implement this + public PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException { + // TODO(ifrade): at some point we will have bitmaps over the multipack + // index + // At the moment bitmap is in GC, at the end of the chain + if (base != null) { + return base.getBitmapIndex(ctx); + } + + for (DfsPackFile pack : packsInIdOrder) { + PackBitmapIndex bitmapIndex = pack.getBitmapIndex(ctx); + if (bitmapIndex != null) { + return bitmapIndex; + } + } return null; } @Override + List<DfsPackFile> fullyIncludedIn(DfsReader ctx, + BitmapIndex.BitmapBuilder need) throws IOException { + List<DfsPackFile> fullyIncluded = new ArrayList<>(); + for (DfsPackFile pack : packs) { + List<DfsPackFile> includedPacks = pack.fullyIncludedIn(ctx, need); + if (!includedPacks.isEmpty()) { + fullyIncluded.addAll(includedPacks); + } + } + + if (base != null) { + fullyIncluded.addAll(base.fullyIncludedIn(ctx, need)); + } + + return fullyIncluded; + } + + @Override public CommitGraph getCommitGraph(DfsReader ctx) throws IOException { for (DfsPackFile pack : packs) { CommitGraph cg = pack.getCommitGraph(ctx); @@ -193,6 +232,25 @@ public List<DfsPackFile> getCoveredPacks() { } /** + * All packs indexed by this multipack index and its chain + * <p> + * This does not include the inner multipack indexes themselves, only their + * covered packs. + * + * @return packs indexed by this multipack index and its parents. + */ + public List<DfsPackFile> getAllCoveredPacks() { + List<DfsPackFile> coveredPacks = new ArrayList<>(packs); + DfsPackFileMidx base = getMultipackIndexBase(); + while (base != null) { + coveredPacks.addAll(base.getCoveredPacks()); + base = base.getMultipackIndexBase(); + } + + return coveredPacks; + } + + /** * Base of this multipack index * <p> * If this midx is part of a chain, this is its parent
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java index f50cd59..2272cc5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
@@ -24,6 +24,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import java.util.zip.DataFormatException; import java.util.zip.Inflater; @@ -149,10 +150,12 @@ public Optional<CommitGraph> getCommitGraph() throws IOException { public Collection<CachedPack> getCachedPacksAndUpdate( BitmapBuilder needBitmap) throws IOException { for (DfsPackFile pack : db.getPacks()) { - PackBitmapIndex bitmapIndex = pack.getBitmapIndex(this); - if (needBitmap.removeAllOrNone(bitmapIndex)) - return Collections.<CachedPack> singletonList( - new DfsCachedPack(pack)); + // p != pack in the multipack index case + List<DfsPackFile> p = pack.fullyIncludedIn(this, needBitmap); + if (!p.isEmpty()) { + return p.stream().map(DfsCachedPack::new) + .collect(Collectors.toUnmodifiableList()); + } } return Collections.emptyList(); }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java index fe8dc17..ddf6f39 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/InMemoryRepository.java
@@ -133,7 +133,8 @@ public void setReadableChannelBlockSizeForTest(int blockSize) { @Override protected synchronized List<DfsPackDescription> listPacks() { - return packs; + return useMultipackIndex() ? MidxPackFilter.useMidx(packs) + : MidxPackFilter.skipMidxs(packs); } @Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackFilter.java new file mode 100644 index 0000000..50de974 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackFilter.java
@@ -0,0 +1,98 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.dfs; + +import org.eclipse.jgit.internal.storage.pack.PackExt; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Format a flat list of packs and midxs into a valid list of packs. + * <p> + * A valid list of packs is either: + * <ul> + * <li>A list with midxs and uncovered packs</li> + * <li>A list of packs (without any midx)</li> + * </ul> + */ +public class MidxPackFilter { + + private MidxPackFilter() { + } + + /** + * Reorganize the flat list of packs removing the midxs + * + * @param packs + * flat list of all packs in the repo, may include midx. Packs + * covered by the midx appear also on their own. + * @return a list of packs without midxs + */ + public static List<DfsPackDescription> skipMidxs( + List<DfsPackDescription> packs) { + // Covered packs appear also on their own in the list, so we can just + // take the midx out. + return packs.stream() + .filter(desc -> !desc.hasFileExt(PackExt.MULTI_PACK_INDEX)) + .collect(Collectors.toList()); + } + + /** + * Remove from the list any packs covered by midxs. + * <p> + * This verifies that all referenced packs by the midxs exist. + * + * @param packs + * list of packs with maybe some midxs + * @return midxs and uncovered packs. All the input packs if no midx. Ignore + * midxs with missing covered packs. + */ + public static List<DfsPackDescription> useMidx( + List<DfsPackDescription> packs) { + // Take the packs covered by the midxs out of the list + List<DfsPackDescription> midxs = packs.stream() + .filter(desc -> desc.hasFileExt(PackExt.MULTI_PACK_INDEX)) + .toList(); + if (midxs.isEmpty()) { + return packs; + } + + Set<DfsPackDescription> inputPacks = new HashSet<>(packs); + Set<DfsPackDescription> allCoveredPacks = new HashSet<>(); + for (DfsPackDescription midx : midxs) { + Set<DfsPackDescription> coveredPacks = new HashSet<>(); + findCoveredPacks(midx, coveredPacks); + if (!inputPacks.containsAll(coveredPacks)) { + // This midx references packs not in the pack db. + // It could be part of a chain, so we just ignore all midxs + return skipMidxs(packs); + } + allCoveredPacks.addAll(coveredPacks); + } + + return packs.stream().filter(d -> !allCoveredPacks.contains(d)) + .collect(Collectors.toList()); + } + + private static void findCoveredPacks(DfsPackDescription midx, + Set<DfsPackDescription> covered) { + if (!midx.getCoveredPacks().isEmpty()) { + covered.addAll(midx.getCoveredPacks()); + } + + if (midx.getMultiPackIndexBase() != null) { + findCoveredPacks(midx.getMultiPackIndexBase(), covered); + covered.add(midx.getMultiPackIndexBase()); + } + } +}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackList.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackList.java new file mode 100644 index 0000000..d26b157 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackList.java
@@ -0,0 +1,167 @@ +/* + * Copyright (C) 2025, Google LLC. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.internal.storage.dfs; + +import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.TreeSet; + +/** + * Helper class to manipulate a list of packs with (maybe) midxs. + **/ +public final class MidxPackList { + + private static final Comparator<DfsPackFile> PACK_NAME_COMPARATOR = Comparator + .comparing(pack -> pack.getPackDescription().getPackName()); + + /** + * Wrap the packs list into a MidxPackList + * <p> + * The input list is well-formed, doesn't have duplicated packs/midxs. + * + * @param packs + * list of packs (regular or tip midxs) + * @return a MidxPackList instance + */ + public static MidxPackList create(DfsPackFile[] packs) { + return new MidxPackList(packs); + } + + private final List<DfsPackFile> packs; + + private MidxPackList(DfsPackFile[] packs) { + this.packs = Arrays.asList(packs); + } + + /** + * Get all plain packs in the list, either top-level or inside midxs + * + * @return a list of all "real" packs in this pack list, either top level or + * inside midxs. + **/ + public List<DfsPackFile> getAllPlainPacks() { + List<DfsPackFile> plainPacks = new ArrayList<>(); + Queue<DfsPackFile> pending = new ArrayDeque<>(packs); + while (!pending.isEmpty()) { + DfsPackFile pack = pending.poll(); + if (pack instanceof DfsPackFileMidx midxPack) { + plainPacks.addAll(midxPack.getCoveredPacks()); + if (midxPack.getMultipackIndexBase() != null) { + pending.add(midxPack.getMultipackIndexBase()); + } + } else { + plainPacks.add(pack); + } + } + return plainPacks; + } + + /** + * Get all midx in the list, either top-level or inside other midxs + * + * @return a list of all midxs in thist list, either top level or nested + * inside other midxs. + **/ + public List<DfsPackFileMidx> getAllMidxPacks() { + List<DfsPackFileMidx> topLevelMidxs = packs.stream().filter( + p -> p.getPackDescription().hasFileExt(MULTI_PACK_INDEX)) + .map(p -> (DfsPackFileMidx) p).toList(); + + List<DfsPackFileMidx> midxPacks = new ArrayList<>(); + Queue<DfsPackFileMidx> pending = new ArrayDeque<>(topLevelMidxs); + while (!pending.isEmpty()) { + DfsPackFileMidx midx = pending.poll(); + midxPacks.add(midx); + if (midx.getMultipackIndexBase() != null) { + pending.add(midx.getMultipackIndexBase()); + } + } + return midxPacks; + } + + /** + * Alias for {@link #findAllCoveringMidxs(List)}, as convenience for tests + * + * @param pack + * a single pack + * @return all the midxs that include (directly or indirectly) the pack + */ + Set<DfsPackFileMidx> findAllCoveringMidxs(DfsPackFile pack) { + return findAllCoveringMidxs(List.of(pack)); + } + + /** + * Return all the midxs that cover (directoy or indirectly) a set of packs + * <p> + * In a chain like midx3(p6, p5) -> midx2(p4, p3) -> midx1(p2, p1), if we + * check for p3, midx3 and midx2 are covering it and midx1 is not. + * + * @param queryPacks + * subset of packs we are checking for coverage + * @return set of midxs from the packlist that should also be removed + */ + public Set<DfsPackFileMidx> findAllCoveringMidxs( + List<DfsPackFile> queryPacks) { + if (queryPacks.isEmpty()) { + return Collections.emptySet(); + } + + List<DfsPackFileMidx> topLevelMidxs = packs.stream().filter( + p -> p.getPackDescription().hasFileExt(MULTI_PACK_INDEX)) + .map(p -> (DfsPackFileMidx) p).toList(); + + if (topLevelMidxs.isEmpty()) { + return Collections.emptySet(); + } + + // TODO(ifrade): Delete from queryPacks as we find them and stop if we + // are done + Set<DfsPackFileMidx> impactedMidxs = asSet(List.of()); + for (DfsPackFileMidx midx : topLevelMidxs) { + List<DfsPackFileMidx> visitedMidxs = new ArrayList<>(); + DfsPackFileMidx current = midx; + while (current != null) { + visitedMidxs.add(current); + if (containsAny(current.getCoveredPacks(), queryPacks)) { + // Anything above in the chain is also covering this pack + impactedMidxs.addAll(visitedMidxs); + // Reset the list and keep going, maybe something + // deeper in the chain is also affected + visitedMidxs.clear(); + } + current = current.getMultipackIndexBase(); + } + visitedMidxs.clear(); + } + + return impactedMidxs; + } + + private static boolean containsAny(List<DfsPackFile> inMidx, + List<DfsPackFile> queryPacks) { + Set<DfsPackFile> inMidxSet = asSet(inMidx); + return queryPacks.stream().anyMatch(inMidxSet::contains); + } + + private static <T extends DfsPackFile> TreeSet<T> asSet( + List<T> initialValues) { + TreeSet<T> theSet = new TreeSet<>(PACK_NAME_COMPARATOR); + theSet.addAll(initialValues); + return theSet; + } +} \ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java index 81577a8..fd040b9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java
@@ -14,7 +14,6 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; -import java.util.stream.Collectors; import org.eclipse.jgit.internal.storage.file.PackIndex; import org.eclipse.jgit.lib.AnyObjectId; @@ -93,12 +92,17 @@ private void fill(int packId, PackIndex.MutableEntry other) { private final int uniqueObjectCount; + /** + * Build a common view of these pack indexes + * <p> + * Order matters: in case of duplicates, the first pack with the object wins + * + * @param packs + * map of pack names to indexes, ordered. + */ PackIndexMerger(Map<String, PackIndex> packs) { - this.packNames = packs.keySet().stream().sorted() - .collect(Collectors.toUnmodifiableList()); - - this.indexes = packNames.stream().map(packs::get) - .collect(Collectors.toUnmodifiableList()); + this.packNames = packs.keySet().stream().toList(); + this.indexes = packs.values().stream().toList(); // Iterate for duplicates int objectCount = 0;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificate.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificate.java index 437abb0..b95d094 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificate.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificate.java
@@ -53,11 +53,12 @@ public enum NonceStatus { private final String nonce; private final NonceStatus nonceStatus; private final List<ReceiveCommand> commands; + private final List<String> pushOptions; private final String signature; PushCertificate(String version, PushCertificateIdent pusher, String pushee, String nonce, NonceStatus nonceStatus, List<ReceiveCommand> commands, - String signature) { + List<String> pushOptions, String signature) { if (version == null || version.isEmpty()) { throw new IllegalArgumentException(MessageFormat.format( JGitText.get().pushCertificateInvalidField, VERSION)); @@ -95,6 +96,7 @@ public enum NonceStatus { this.nonce = nonce; this.nonceStatus = nonceStatus; this.commands = commands; + this.pushOptions = pushOptions; this.signature = signature; } @@ -171,6 +173,16 @@ public List<ReceiveCommand> getCommands() { } /** + * Get the list of push options that were included in the push certificate. + * + * @return the push options, or an empty list if none. + * @since 7.5 + */ + public List<String> getPushOptions() { + return pushOptions; + } + + /** * Get the raw signature * * @return the raw signature, consisting of the lines received between the @@ -212,8 +224,12 @@ private StringBuilder toStringBuilder() { if (pushee != null) { sb.append(PUSHEE).append(' ').append(pushee).append('\n'); } - sb.append(NONCE).append(' ').append(nonce).append('\n') - .append('\n'); + sb.append(NONCE).append(' ').append(nonce).append('\n'); + for (String option : pushOptions) { + sb.append(PushCertificateParser.PUSH_OPTION).append(' ') + .append(option).append('\n'); + } + sb.append('\n'); for (ReceiveCommand cmd : commands) { sb.append(cmd.getOldId().name()) .append(' ').append(cmd.getNewId().name())
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 463d053..c9f0dec 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushCertificateParser.java
@@ -47,6 +47,8 @@ public class PushCertificateParser { static final String NONCE = "nonce"; //$NON-NLS-1$ + static final String PUSH_OPTION = "push-option"; //$NON-NLS-1$ + static final String END_CERT = "push-cert-end"; //$NON-NLS-1$ private static final String VERSION_0_1 = "0.1"; //$NON-NLS-1$ @@ -173,6 +175,7 @@ public static PushCertificate fromString(String str) private final boolean enabled; private final NonceGenerator nonceGenerator; private final List<ReceiveCommand> commands = new ArrayList<>(); + private final List<String> pushOptions = new ArrayList<>(); /** * <p>Constructor for PushCertificateParser.</p> @@ -251,7 +254,8 @@ public PushCertificate build() throws IOException { } try { return new PushCertificate(version, pusher, pushee, receivedNonce, - nonceStatus, Collections.unmodifiableList(commands), signature); + nonceStatus, Collections.unmodifiableList(commands), + Collections.unmodifiableList(pushOptions), signature); } catch (IllegalArgumentException e) { throw new IOException(e.getMessage(), e); } @@ -368,10 +372,16 @@ private void receiveHeader(StringReader reader, boolean stateless) ? nonceGenerator.verify( receivedNonce, sentNonce(), db, stateless, nonceSlopLimit) : NonceStatus.UNSOLICITED; - // An empty line. - if (!reader.read().isEmpty()) { - throw new PackProtocolException( - JGitText.get().pushCertificateInvalidHeader); + // Read push-option lines (if any) before the empty line separator + String line; + while (!(line = reader.read()).isEmpty()) { + if (line.startsWith(PUSH_OPTION + " ")) { + pushOptions.add(parseHeader(line, PUSH_OPTION)); + } else { + // Not a push-option, should be empty line + throw new PackProtocolException( + JGitText.get().pushCertificateInvalidHeader); + } } } catch (EOFException eof) { throw new PackProtocolException(
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 6f211e0..3d9c81c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -40,6 +40,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.Function; @@ -1375,6 +1376,11 @@ private void recvCommands() throws IOException { if (hasCommands()) { readPostCommands(pck); } + // Verify that push options in the certificate match the post-command ones. + if (pushCert != null) { + validateCertificatePushOptions(pushCert.getPushOptions(), + pushOptions, commands); + } } catch (Throwable t) { discardCommands(); throw t; @@ -1406,6 +1412,35 @@ private void parseShallow(String idStr) throws PackProtocolException { } /** + * Validates that push options in the certificate match the post-command + * push options. If they don't match, marks all commands as rejected. + * <p> + * This prevents tampering with signed push certificates by ensuring the + * options that were signed match exactly the options sent after the + * commands. + * + * @param certPushOptions + * the push options from the certificate + * @param postCommandPushOptions + * the push options sent after commands (may be null) + * @param commands + * the list of commands to reject if validation fails + */ + static void validateCertificatePushOptions(List<String> certPushOptions, + List<String> postCommandPushOptions, List<ReceiveCommand> commands) { + List<String> postOptions = postCommandPushOptions == null + ? Collections.emptyList() + : postCommandPushOptions; + if (!Objects.equals(certPushOptions, postOptions)) { + // Mark all commands as rejected like in C Git. + for (ReceiveCommand cmd : commands) { + cmd.setResult(Result.REJECTED_OTHER_REASON, + JGitText.get().pushCertificateInconsistentPushOptions); + } + } + } + + /** * @param in * request stream. * @throws IOException
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java index 888b8fb..e717412 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/InterruptTimer.java
@@ -151,6 +151,7 @@ protected void finalize() throws Throwable { static final class AlarmState implements Runnable { private Thread callingThread; + private int lastTimeout; private long deadline; private boolean terminated; @@ -163,7 +164,7 @@ static final class AlarmState implements Runnable { public synchronized void run() { while (!terminated && callingThread.isAlive()) { try { - if (0 < deadline) { + if (deadline > 0) { final long delay = deadline - now(); if (delay <= 0) { deadline = 0; @@ -172,7 +173,9 @@ public synchronized void run() { wait(delay); } } else { - wait(1000); + // When the timer is not running, avoid waking up more than once a second + wait(lastTimeout == 0 ? 1000 : lastTimeout); + lastTimeout = 0; } } catch (InterruptedException e) { // Treat an interrupt as notice to examine state. @@ -185,15 +188,21 @@ synchronized void begin(int timeout) { throw new IllegalStateException(JGitText.get().timerAlreadyTerminated); callingThread = Thread.currentThread(); deadline = now() + timeout; - notifyAll(); + if (lastTimeout != timeout) { + boolean isNotify = lastTimeout == 0 || lastTimeout > timeout; + lastTimeout = timeout; + if (isNotify) { + notifyAll(); + } // else avoid the expensive notify when the runloop will already timeout in time + } } synchronized void end() { - if (0 == deadline) + if (0 == deadline) { Thread.interrupted(); - else + } else { deadline = 0; - notifyAll(); + } } synchronized void terminate() {
diff --git a/pom.xml b/pom.xml index a75f6f4..038b067 100644 --- a/pom.xml +++ b/pom.xml
@@ -130,25 +130,25 @@ <commons-compress-version>1.28.0</commons-compress-version> <osgi-core-version>6.0.0</osgi-core-version> <servlet-api-version>6.1.0</servlet-api-version> - <jetty-version>12.1.1</jetty-version> - <japicmp-version>0.23.1</japicmp-version> + <jetty-version>12.1.3</jetty-version> + <japicmp-version>0.24.1</japicmp-version> <httpclient-version>4.5.14</httpclient-version> <httpcore-version>4.4.16</httpcore-version> - <slf4j-version>1.7.36</slf4j-version> - <maven-javadoc-plugin-version>3.11.2</maven-javadoc-plugin-version> + <slf4j-version>2.0.17</slf4j-version> + <maven-javadoc-plugin-version>3.12.0</maven-javadoc-plugin-version> <gson-version>2.13.2</gson-version> <bouncycastle-version>1.82</bouncycastle-version> - <spotbugs-maven-plugin-version>4.9.3.0</spotbugs-maven-plugin-version> + <spotbugs-maven-plugin-version>4.9.6.0</spotbugs-maven-plugin-version> <maven-project-info-reports-plugin-version>3.9.0</maven-project-info-reports-plugin-version> <maven-jxr-plugin-version>3.6.0</maven-jxr-plugin-version> - <maven-surefire-plugin-version>3.5.3</maven-surefire-plugin-version> + <maven-surefire-plugin-version>3.5.4</maven-surefire-plugin-version> <maven-surefire-report-plugin-version>${maven-surefire-plugin-version}</maven-surefire-report-plugin-version> - <maven-compiler-plugin-version>3.14.0</maven-compiler-plugin-version> + <maven-compiler-plugin-version>3.14.1</maven-compiler-plugin-version> <plexus-compiler-version>2.13.0</plexus-compiler-version> - <hamcrest-version>2.2</hamcrest-version> + <hamcrest-version>3.0</hamcrest-version> <assertj-version>3.27.6</assertj-version> <jna-version>5.18.1</jna-version> - <byte-buddy-version>1.17.7</byte-buddy-version> + <byte-buddy-version>1.17.8</byte-buddy-version> <!-- Properties to enable jacoco code coverage analysis --> <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin> @@ -208,13 +208,13 @@ <plugin> <artifactId>maven-clean-plugin</artifactId> - <version>3.4.1</version> + <version>3.5.0</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> - <version>3.6.0</version> + <version>3.6.1</version> </plugin> <plugin> @@ -226,7 +226,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> - <version>3.8.1</version> + <version>3.9.0</version> </plugin> <plugin> @@ -255,7 +255,7 @@ <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> - <version>3.6.0</version> + <version>3.6.1</version> </plugin> <plugin> @@ -277,7 +277,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-pmd-plugin</artifactId> - <version>3.26.0</version> + <version>3.27.0</version> <configuration> <inputEncoding>${project.build.sourceEncoding}</inputEncoding> <minimumTokens>100</minimumTokens> @@ -372,7 +372,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-artifact-plugin</artifactId> - <version>3.6.0</version> + <version>3.6.1</version> <configuration> <ignore>**/*cyclonedx.json</ignore> <reproducible>true</reproducible> @@ -381,7 +381,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> - <version>3.5.0</version> + <version>3.6.2</version> </plugin> </plugins> </pluginManagement> @@ -655,7 +655,7 @@ <plugin> <groupId>org.codehaus.gmavenplus</groupId> <artifactId>gmavenplus-plugin</artifactId> - <version>4.2.0</version> + <version>4.2.1</version> <dependencies> <dependency> <groupId>org.apache.groovy</groupId>
diff --git a/tools/maven-central/README.md b/tools/maven-central/README.md index 04f115e..40156a5 100644 --- a/tools/maven-central/README.md +++ b/tools/maven-central/README.md
@@ -75,6 +75,8 @@ ``` - check in the [Maven Central Portal](https://central.sonatype.com/publishing/deployments) if the release looks good. You can download uploaded artifacts from there. + How to manually test a staged release is explained + [here](https://central.sonatype.org/publish/publish-portal-api/#manually-testing-a-deployment-bundle) - publish the new release - by clicking "Publish" on the [portal deployment page](https://central.sonatype.com/publishing/deployments) - or by running