diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java index a83a99333..658b971ac 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java @@ -45,7 +45,10 @@ package org.eclipse.jgit.transport; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -59,10 +62,16 @@ import java.util.Collections; import java.util.Set; import org.eclipse.jgit.errors.MissingBundlePrerequisiteException; +import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.NotSupportedException; import org.eclipse.jgit.errors.TransportException; +import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; +import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; @@ -161,6 +170,39 @@ public class BundleWriterTest extends SampleDataRepositoryTestCase { assertTrue(caught); } + @Test + public void testCustomObjectReader() throws Exception { + String refName = "refs/heads/blob"; + String data = "unflushed data"; + ObjectId id; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try (Repository repo = new InMemoryRepository( + new DfsRepositoryDescription("repo")); + ObjectInserter ins = repo.newObjectInserter(); + ObjectReader or = ins.newReader()) { + id = ins.insert(OBJ_BLOB, Constants.encode(data)); + BundleWriter bw = new BundleWriter(or); + bw.include(refName, id); + bw.writeBundle(NullProgressMonitor.INSTANCE, out); + assertNull(repo.exactRef(refName)); + try { + repo.open(id, OBJ_BLOB); + fail("We should not be able to open the unflushed blob"); + } catch (MissingObjectException e) { + // Expected. + } + } + + try (Repository repo = new InMemoryRepository( + new DfsRepositoryDescription("copy"))) { + fetchFromBundle(repo, out.toByteArray()); + Ref ref = repo.exactRef(refName); + assertNotNull(ref); + assertEquals(id, ref.getObjectId()); + assertEquals(data, new String(repo.open(id, OBJ_BLOB).getBytes(), UTF_8)); + } + } + private static FetchResult fetchFromBundle(final Repository newRepo, final byte[] bundle) throws URISyntaxException, NotSupportedException, TransportException { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java index 37d70e3a1..0920f2156 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java @@ -58,6 +58,7 @@ import org.eclipse.jgit.internal.storage.pack.PackWriter; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; @@ -84,6 +85,8 @@ import org.eclipse.jgit.storage.pack.PackConfig; public class BundleWriter { private final Repository db; + private final ObjectReader reader; + private final Map include; private final Set assume; @@ -100,8 +103,26 @@ public class BundleWriter { * @param repo * repository where objects are stored. */ - public BundleWriter(final Repository repo) { + public BundleWriter(Repository repo) { db = repo; + reader = null; + include = new TreeMap<>(); + assume = new HashSet<>(); + tagTargets = new HashSet<>(); + } + + /** + * Create a writer for a bundle. + * + * @param or + * reader for reading objects. Will be closed at the end of {@link + * #writeBundle(ProgressMonitor, OutputStream)}, but readers may be + * reused after closing. + * @since 4.8 + */ + public BundleWriter(ObjectReader or) { + db = null; + reader = or; include = new TreeMap<>(); assume = new HashSet<>(); tagTargets = new HashSet<>(); @@ -112,7 +133,8 @@ public class BundleWriter { * * @param pc * configuration controlling packing parameters. If null the - * source repository's settings will be used. + * source repository's settings will be used, or the default + * settings if constructed without a repo. */ public void setPackConfig(PackConfig pc) { this.packConfig = pc; @@ -196,10 +218,7 @@ public class BundleWriter { */ public void writeBundle(ProgressMonitor monitor, OutputStream os) throws IOException { - PackConfig pc = packConfig; - if (pc == null) - pc = new PackConfig(db); - try (PackWriter packWriter = new PackWriter(pc, db.newObjectReader())) { + try (PackWriter packWriter = newPackWriter()) { packWriter.setObjectCountCallback(callback); final HashSet inc = new HashSet<>(); @@ -242,6 +261,14 @@ public class BundleWriter { } } + private PackWriter newPackWriter() { + PackConfig pc = packConfig; + if (pc == null) { + pc = db != null ? new PackConfig(db) : new PackConfig(); + } + return new PackWriter(pc, reader != null ? reader : db.newObjectReader()); + } + /** * Set the {@link ObjectCountCallback}. *