By moving the logic that parses a pack stream from the network (or a bundle) into a type that can be constructed by an ObjectInserter, repository implementations have a chance to inject their own logic for storing object data received into the destination repository. The API isn't completely generic yet, there are still quite a few assumptions that the PackParser subclass is storing the data onto the local filesystem as a single file. But its about the simplest split of IndexPack I can come up with without completely ripping the code apart. Change-Id: I5b167c9cc6d7a7c56d0197c62c0fd0036a83ec6c Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>tags/v0.11.1
@@ -45,12 +45,12 @@ | |||
package org.eclipse.jgit.pgm; | |||
import java.io.BufferedInputStream; | |||
import java.io.File; | |||
import org.kohsuke.args4j.Argument; | |||
import org.kohsuke.args4j.Option; | |||
import org.eclipse.jgit.lib.CoreConfig; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.lib.TextProgressMonitor; | |||
import org.eclipse.jgit.storage.file.ObjectDirectoryPackParser; | |||
import org.eclipse.jgit.transport.PackParser; | |||
import org.kohsuke.args4j.Option; | |||
class IndexPack extends TextBuiltin { | |||
@Option(name = "--fix-thin", usage = "usage_fixAThinPackToBeComplete") | |||
@@ -59,20 +59,21 @@ class IndexPack extends TextBuiltin { | |||
@Option(name = "--index-version", usage = "usage_indexFileFormatToCreate") | |||
private int indexVersion = -1; | |||
@Argument(index = 0, required = true, metaVar = "metaVar_base") | |||
private File base; | |||
@Override | |||
protected void run() throws Exception { | |||
if (indexVersion == -1) | |||
indexVersion = db.getConfig().get(CoreConfig.KEY) | |||
.getPackIndexVersion(); | |||
final BufferedInputStream in; | |||
final org.eclipse.jgit.transport.IndexPack ip; | |||
in = new BufferedInputStream(System.in); | |||
ip = new org.eclipse.jgit.transport.IndexPack(db, in, base); | |||
ip.setFixThin(fixThin); | |||
ip.setIndexVersion(indexVersion); | |||
ip.index(new TextProgressMonitor()); | |||
BufferedInputStream in = new BufferedInputStream(System.in); | |||
ObjectInserter inserter = db.newObjectInserter(); | |||
try { | |||
PackParser p = inserter.newPackParser(in); | |||
p.setAllowThin(fixThin); | |||
if (indexVersion != -1 && p instanceof ObjectDirectoryPackParser) { | |||
ObjectDirectoryPackParser imp = (ObjectDirectoryPackParser) p; | |||
imp.setIndexVersion(indexVersion); | |||
} | |||
p.parse(new TextProgressMonitor()); | |||
inserter.flush(); | |||
} finally { | |||
inserter.release(); | |||
} | |||
} | |||
} |
@@ -71,7 +71,7 @@ import org.eclipse.jgit.lib.ObjectLoader; | |||
import org.eclipse.jgit.lib.ObjectStream; | |||
import org.eclipse.jgit.revwalk.RevBlob; | |||
import org.eclipse.jgit.storage.pack.DeltaEncoder; | |||
import org.eclipse.jgit.transport.IndexPack; | |||
import org.eclipse.jgit.transport.PackParser; | |||
import org.eclipse.jgit.util.IO; | |||
import org.eclipse.jgit.util.NB; | |||
import org.eclipse.jgit.util.TemporaryBuffer; | |||
@@ -212,11 +212,9 @@ public class PackFileTest extends LocalDiskRepositoryTestCase { | |||
deflate(pack, delta3); | |||
digest(pack); | |||
final byte[] raw = pack.toByteArray(); | |||
IndexPack ip = IndexPack.create(repo, new ByteArrayInputStream(raw)); | |||
ip.setFixThin(true); | |||
ip.index(NullProgressMonitor.INSTANCE); | |||
ip.renameAndOpenPack(); | |||
PackParser ip = index(pack.toByteArray()); | |||
ip.setAllowThin(true); | |||
ip.parse(NullProgressMonitor.INSTANCE); | |||
assertTrue("has blob", wc.has(id3)); | |||
@@ -273,11 +271,9 @@ public class PackFileTest extends LocalDiskRepositoryTestCase { | |||
deflate(pack, delta3); | |||
digest(pack); | |||
final byte[] raw = pack.toByteArray(); | |||
IndexPack ip = IndexPack.create(repo, new ByteArrayInputStream(raw)); | |||
ip.setFixThin(true); | |||
ip.index(NullProgressMonitor.INSTANCE); | |||
ip.renameAndOpenPack(); | |||
PackParser ip = index(pack.toByteArray()); | |||
ip.setAllowThin(true); | |||
ip.parse(NullProgressMonitor.INSTANCE); | |||
assertTrue("has blob", wc.has(id3)); | |||
@@ -364,4 +360,18 @@ public class PackFileTest extends LocalDiskRepositoryTestCase { | |||
md.update(buf.toByteArray()); | |||
buf.write(md.digest()); | |||
} | |||
private ObjectInserter inserter; | |||
@After | |||
public void release() { | |||
if (inserter != null) | |||
inserter.release(); | |||
} | |||
private PackParser index(byte[] raw) throws IOException { | |||
if (inserter == null) | |||
inserter = repo.newObjectInserter(); | |||
return inserter.newPackParser(new ByteArrayInputStream(raw)); | |||
} | |||
} |
@@ -44,6 +44,7 @@ | |||
package org.eclipse.jgit.storage.file; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
@@ -52,7 +53,6 @@ import java.io.ByteArrayOutputStream; | |||
import java.io.File; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
@@ -66,14 +66,14 @@ import org.eclipse.jgit.errors.MissingObjectException; | |||
import org.eclipse.jgit.junit.JGitTestUtil; | |||
import org.eclipse.jgit.lib.NullProgressMonitor; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.lib.SampleDataRepositoryTestCase; | |||
import org.eclipse.jgit.lib.TextProgressMonitor; | |||
import org.eclipse.jgit.revwalk.RevObject; | |||
import org.eclipse.jgit.revwalk.RevWalk; | |||
import org.eclipse.jgit.storage.file.PackIndex.MutableEntry; | |||
import org.eclipse.jgit.storage.pack.PackConfig; | |||
import org.eclipse.jgit.storage.pack.PackWriter; | |||
import org.eclipse.jgit.transport.IndexPack; | |||
import org.eclipse.jgit.transport.PackParser; | |||
import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
@@ -92,28 +92,34 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
private ByteArrayOutputStream os; | |||
private File packBase; | |||
private File packFile; | |||
private PackFile pack; | |||
private File indexFile; | |||
private ObjectInserter inserter; | |||
private PackFile pack; | |||
private FileRepository dst; | |||
@Before | |||
public void setUp() throws Exception { | |||
super.setUp(); | |||
os = new ByteArrayOutputStream(); | |||
packBase = new File(trash, "tmp_pack"); | |||
packFile = new File(trash, "tmp_pack.pack"); | |||
indexFile = new File(trash, "tmp_pack.idx"); | |||
config = new PackConfig(db); | |||
dst = createBareRepository(); | |||
File alt = new File(dst.getObjectDatabase().getDirectory(), "info/alternates"); | |||
alt.getParentFile().mkdirs(); | |||
write(alt, db.getObjectDatabase().getDirectory().getAbsolutePath() + "\n"); | |||
} | |||
@After | |||
public void tearDown() throws Exception { | |||
if (writer != null) | |||
if (writer != null) { | |||
writer.release(); | |||
writer = null; | |||
} | |||
if (inserter != null) { | |||
inserter.release(); | |||
inserter = null; | |||
} | |||
super.tearDown(); | |||
} | |||
@@ -408,6 +414,11 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
config.setIndexVersion(2); | |||
writeVerifyPack4(false); | |||
File packFile = pack.getPackFile(); | |||
String name = packFile.getName(); | |||
String base = name.substring(0, name.lastIndexOf('.')); | |||
File indexFile = new File(packFile.getParentFile(), base + ".idx"); | |||
// Validate that IndexPack came up with the right CRC32 value. | |||
final PackIndex idx1 = PackIndex.open(indexFile); | |||
assertTrue(idx1 instanceof PackIndexV2); | |||
@@ -544,23 +555,31 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
} | |||
private void verifyOpenPack(final boolean thin) throws IOException { | |||
final byte[] packData = os.toByteArray(); | |||
if (thin) { | |||
final InputStream is = new ByteArrayInputStream(os.toByteArray()); | |||
final IndexPack indexer = new IndexPack(db, is, packBase); | |||
PackParser p = index(packData); | |||
try { | |||
indexer.index(new TextProgressMonitor()); | |||
p.parse(NullProgressMonitor.INSTANCE); | |||
fail("indexer should grumble about missing object"); | |||
} catch (IOException x) { | |||
// expected | |||
} | |||
} | |||
final InputStream is = new ByteArrayInputStream(os.toByteArray()); | |||
final IndexPack indexer = new IndexPack(db, is, packBase); | |||
indexer.setKeepEmpty(true); | |||
indexer.setFixThin(thin); | |||
indexer.setIndexVersion(2); | |||
indexer.index(new TextProgressMonitor()); | |||
pack = new PackFile(indexFile, packFile); | |||
ObjectDirectoryPackParser p = (ObjectDirectoryPackParser) index(packData); | |||
p.setKeepEmpty(true); | |||
p.setAllowThin(thin); | |||
p.setIndexVersion(2); | |||
p.parse(NullProgressMonitor.INSTANCE); | |||
pack = p.getPackFile(); | |||
assertNotNull("have PackFile after parsing", pack); | |||
} | |||
private PackParser index(final byte[] packData) throws IOException { | |||
if (inserter == null) | |||
inserter = dst.newObjectInserter(); | |||
return inserter.newPackParser(new ByteArrayInputStream(packData)); | |||
} | |||
private void verifyObjectsOrder(final ObjectId objectsOrder[]) { |
@@ -61,13 +61,15 @@ import org.eclipse.jgit.junit.TestRepository; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.NullProgressMonitor; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.lib.RepositoryTestCase; | |||
import org.eclipse.jgit.lib.TextProgressMonitor; | |||
import org.eclipse.jgit.revwalk.RevBlob; | |||
import org.eclipse.jgit.storage.file.ObjectDirectoryPackParser; | |||
import org.eclipse.jgit.storage.file.PackFile; | |||
import org.eclipse.jgit.util.NB; | |||
import org.eclipse.jgit.util.TemporaryBuffer; | |||
import org.junit.After; | |||
import org.junit.Test; | |||
/** | |||
@@ -76,8 +78,7 @@ import org.junit.Test; | |||
* to make sure they contain the expected objects (well we don't test | |||
* for all of them unless the packs are very small). | |||
*/ | |||
public class IndexPackTest extends RepositoryTestCase { | |||
public class PackParserTest extends RepositoryTestCase { | |||
/** | |||
* Test indexing one of the test packs in the egit repo. It has deltas. | |||
* | |||
@@ -88,9 +89,10 @@ public class IndexPackTest extends RepositoryTestCase { | |||
File packFile = JGitTestUtil.getTestResourceFile("pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.pack"); | |||
final InputStream is = new FileInputStream(packFile); | |||
try { | |||
IndexPack pack = new IndexPack(db, is, new File(trash, "tmp_pack1")); | |||
pack.index(new TextProgressMonitor()); | |||
PackFile file = new PackFile(new File(trash, "tmp_pack1.idx"), new File(trash, "tmp_pack1.pack")); | |||
ObjectDirectoryPackParser p = (ObjectDirectoryPackParser) index(is); | |||
p.parse(NullProgressMonitor.INSTANCE); | |||
PackFile file = p.getPackFile(); | |||
assertTrue(file.hasObject(ObjectId.fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904"))); | |||
assertTrue(file.hasObject(ObjectId.fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab"))); | |||
assertTrue(file.hasObject(ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259"))); | |||
@@ -115,9 +117,10 @@ public class IndexPackTest extends RepositoryTestCase { | |||
File packFile = JGitTestUtil.getTestResourceFile("pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.pack"); | |||
final InputStream is = new FileInputStream(packFile); | |||
try { | |||
IndexPack pack = new IndexPack(db, is, new File(trash, "tmp_pack2")); | |||
pack.index(new TextProgressMonitor()); | |||
PackFile file = new PackFile(new File(trash, "tmp_pack2.idx"), new File(trash, "tmp_pack2.pack")); | |||
ObjectDirectoryPackParser p = (ObjectDirectoryPackParser) index(is); | |||
p.parse(NullProgressMonitor.INSTANCE); | |||
PackFile file = p.getPackFile(); | |||
assertTrue(file.hasObject(ObjectId.fromString("02ba32d3649e510002c21651936b7077aa75ffa9"))); | |||
assertTrue(file.hasObject(ObjectId.fromString("0966a434eb1a025db6b71485ab63a3bfbea520b6"))); | |||
assertTrue(file.hasObject(ObjectId.fromString("09efc7e59a839528ac7bda9fa020dc9101278680"))); | |||
@@ -151,11 +154,9 @@ public class IndexPackTest extends RepositoryTestCase { | |||
digest(pack); | |||
final byte[] raw = pack.toByteArray(); | |||
IndexPack ip = IndexPack.create(db, new ByteArrayInputStream(raw)); | |||
ip.setFixThin(true); | |||
ip.index(NullProgressMonitor.INSTANCE); | |||
ip.renameAndOpenPack(); | |||
PackParser p = index(new ByteArrayInputStream(pack.toByteArray())); | |||
p.setAllowThin(true); | |||
p.parse(NullProgressMonitor.INSTANCE); | |||
} | |||
@Test | |||
@@ -171,10 +172,9 @@ public class IndexPackTest extends RepositoryTestCase { | |||
deflate(pack, data); | |||
digest(pack); | |||
final byte[] raw = pack.toByteArray(); | |||
IndexPack ip = IndexPack.create(db, new ByteArrayInputStream(raw)); | |||
ip.index(NullProgressMonitor.INSTANCE); | |||
ip.renameAndOpenPack(); | |||
PackParser p = index(new ByteArrayInputStream(pack.toByteArray())); | |||
p.setAllowThin(false); | |||
p.parse(NullProgressMonitor.INSTANCE); | |||
} | |||
private void packHeader(TemporaryBuffer.Heap tinyPack, int cnt) | |||
@@ -205,4 +205,18 @@ public class IndexPackTest extends RepositoryTestCase { | |||
md.update(buf.toByteArray()); | |||
buf.write(md.digest()); | |||
} | |||
private ObjectInserter inserter; | |||
@After | |||
public void release() { | |||
if (inserter != null) | |||
inserter.release(); | |||
} | |||
private PackParser index(InputStream in) throws IOException { | |||
if (inserter == null) | |||
inserter = db.newObjectInserter(); | |||
return inserter.newPackParser(in); | |||
} | |||
} |
@@ -67,6 +67,7 @@ import org.eclipse.jgit.junit.TestRepository; | |||
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.ObjectLoader; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.lib.Repository; | |||
@@ -536,12 +537,22 @@ public class ReceivePackRefFilterTest extends LocalDiskRepositoryTestCase { | |||
buf.write(md.digest()); | |||
} | |||
private ObjectInserter inserter; | |||
@After | |||
public void release() { | |||
if (inserter != null) | |||
inserter.release(); | |||
} | |||
private void openPack(TemporaryBuffer.Heap buf) throws IOException { | |||
if (inserter == null) | |||
inserter = src.newObjectInserter(); | |||
final byte[] raw = buf.toByteArray(); | |||
IndexPack ip = IndexPack.create(src, new ByteArrayInputStream(raw)); | |||
ip.setFixThin(true); | |||
ip.index(PM); | |||
ip.renameAndOpenPack(); | |||
PackParser p = inserter.newPackParser(new ByteArrayInputStream(raw)); | |||
p.setAllowThin(true); | |||
p.parse(PM); | |||
} | |||
private static PacketLineIn asPacketLineIn(TemporaryBuffer.Heap buf) |
@@ -95,7 +95,6 @@ public class CoreConfig { | |||
/** | |||
* @return the preferred pack index file format; 0 for oldest possible. | |||
* @see org.eclipse.jgit.transport.IndexPack | |||
*/ | |||
public int getPackIndexVersion() { | |||
return packIndexVersion; |
@@ -52,6 +52,8 @@ import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.security.MessageDigest; | |||
import org.eclipse.jgit.transport.PackParser; | |||
/** | |||
* Inserts objects into an existing {@code ObjectDatabase}. | |||
* <p> | |||
@@ -73,6 +75,11 @@ public abstract class ObjectInserter { | |||
throw new UnsupportedOperationException(); | |||
} | |||
@Override | |||
public PackParser newPackParser(InputStream in) throws IOException { | |||
throw new UnsupportedOperationException(); | |||
} | |||
@Override | |||
public void flush() throws IOException { | |||
// Do nothing. | |||
@@ -282,6 +289,19 @@ public abstract class ObjectInserter { | |||
public abstract ObjectId insert(int objectType, long length, InputStream in) | |||
throws IOException; | |||
/** | |||
* Initialize a parser to read from a pack formatted stream. | |||
* | |||
* @param in | |||
* the input stream. The stream is not closed by the parser, and | |||
* must instead be closed by the caller once parsing is complete. | |||
* @return the pack parser. | |||
* @throws IOException | |||
* the parser instance, which can be configured and then used to | |||
* parse objects into the ObjectDatabase. | |||
*/ | |||
public abstract PackParser newPackParser(InputStream in) throws IOException; | |||
/** | |||
* Make all inserted objects visible. | |||
* <p> |
@@ -58,6 +58,7 @@ import org.eclipse.jgit.lib.ObjectIdSubclassMap; | |||
import org.eclipse.jgit.lib.ObjectLoader; | |||
import org.eclipse.jgit.storage.pack.ObjectToPack; | |||
import org.eclipse.jgit.storage.pack.PackWriter; | |||
import org.eclipse.jgit.util.FS; | |||
/** | |||
* The cached instance of an {@link ObjectDirectory}. | |||
@@ -132,6 +133,11 @@ class CachedObjectDirectory extends FileObjectDatabase { | |||
return wrapped.getConfig(); | |||
} | |||
@Override | |||
FS getFS() { | |||
return wrapped.getFS(); | |||
} | |||
@Override | |||
AlternateHandle[] myAlternates() { | |||
if (alts == null) { | |||
@@ -233,6 +239,11 @@ class CachedObjectDirectory extends FileObjectDatabase { | |||
return result; | |||
} | |||
@Override | |||
PackFile openPack(File pack, File idx) throws IOException { | |||
return wrapped.openPack(pack, idx); | |||
} | |||
@Override | |||
void selectObjectRepresentation(PackWriter packer, ObjectToPack otp, | |||
WindowCursor curs) throws IOException { |
@@ -56,6 +56,7 @@ import org.eclipse.jgit.lib.ObjectLoader; | |||
import org.eclipse.jgit.lib.ObjectReader; | |||
import org.eclipse.jgit.storage.pack.ObjectToPack; | |||
import org.eclipse.jgit.storage.pack.PackWriter; | |||
import org.eclipse.jgit.util.FS; | |||
abstract class FileObjectDatabase extends ObjectDatabase { | |||
static enum InsertLooseObjectResult { | |||
@@ -132,6 +133,8 @@ abstract class FileObjectDatabase extends ObjectDatabase { | |||
abstract Config getConfig(); | |||
abstract FS getFS(); | |||
/** | |||
* Open an object from this database. | |||
* <p> | |||
@@ -278,6 +281,8 @@ abstract class FileObjectDatabase extends ObjectDatabase { | |||
abstract InsertLooseObjectResult insertUnpackedObject(File tmp, | |||
ObjectId id, boolean createDuplicate) throws IOException; | |||
abstract PackFile openPack(File pack, File idx) throws IOException; | |||
abstract FileObjectDatabase newCachedFileObjectDatabase(); | |||
static class AlternateHandle { |
@@ -233,11 +233,13 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
* path of the pack file to open. | |||
* @param idx | |||
* path of the corresponding index file. | |||
* @return the pack that was opened and added to the database. | |||
* @throws IOException | |||
* index file could not be opened, read, or is not recognized as | |||
* a Git pack file index. | |||
*/ | |||
public void openPack(final File pack, final File idx) throws IOException { | |||
public PackFile openPack(final File pack, final File idx) | |||
throws IOException { | |||
final String p = pack.getName(); | |||
final String i = idx.getName(); | |||
@@ -250,7 +252,9 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
if (!p.substring(0, 45).equals(i.substring(0, 45))) | |||
throw new IOException(MessageFormat.format(JGitText.get().packDoesNotMatchIndex, pack)); | |||
insertPack(new PackFile(idx, pack)); | |||
PackFile res = new PackFile(idx, pack); | |||
insertPack(res); | |||
return res; | |||
} | |||
@Override | |||
@@ -519,6 +523,11 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
return config; | |||
} | |||
@Override | |||
FS getFS() { | |||
return fs; | |||
} | |||
private void insertPack(final PackFile pf) { | |||
PackList o, n; | |||
do { |
@@ -63,6 +63,7 @@ import org.eclipse.jgit.lib.Config; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.transport.PackParser; | |||
import org.eclipse.jgit.util.FileUtils; | |||
/** Creates loose objects in a {@link ObjectDirectory}. */ | |||
@@ -100,6 +101,11 @@ class ObjectDirectoryInserter extends ObjectInserter { | |||
throw new ObjectWritingException("Unable to create new object: " + dst); | |||
} | |||
@Override | |||
public PackParser newPackParser(InputStream in) throws IOException { | |||
return new ObjectDirectoryPackParser(db, in); | |||
} | |||
@Override | |||
public void flush() throws IOException { | |||
// Do nothing. Objects are immediately visible. |
@@ -0,0 +1,480 @@ | |||
/* | |||
* Copyright (C) 2008-2011, Google Inc. | |||
* Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com> | |||
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Eclipse Distribution License v1.0 which | |||
* accompanies this distribution, is reproduced below, and is | |||
* available at http://www.eclipse.org/org/documents/edl-v10.php | |||
* | |||
* All rights reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or | |||
* without modification, are permitted provided that the following | |||
* conditions are met: | |||
* | |||
* - Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* - Redistributions in binary form must reproduce the above | |||
* copyright notice, this list of conditions and the following | |||
* disclaimer in the documentation and/or other materials provided | |||
* with the distribution. | |||
* | |||
* - Neither the name of the Eclipse Foundation, Inc. nor the | |||
* names of its contributors may be used to endorse or promote | |||
* products derived from this software without specific prior | |||
* written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | |||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | |||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
package org.eclipse.jgit.storage.file; | |||
import java.io.File; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.RandomAccessFile; | |||
import java.security.MessageDigest; | |||
import java.text.MessageFormat; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.zip.CRC32; | |||
import java.util.zip.Deflater; | |||
import org.eclipse.jgit.JGitText; | |||
import org.eclipse.jgit.lib.AnyObjectId; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.CoreConfig; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.lib.ProgressMonitor; | |||
import org.eclipse.jgit.transport.PackParser; | |||
import org.eclipse.jgit.transport.PackedObjectInfo; | |||
import org.eclipse.jgit.util.FileUtils; | |||
import org.eclipse.jgit.util.NB; | |||
/** | |||
* Consumes a pack stream and stores as a pack file in {@link ObjectDirectory}. | |||
* <p> | |||
* To obtain an instance of a parser, applications should use | |||
* {@link ObjectInserter#newPackParser(InputStream)}. | |||
*/ | |||
public class ObjectDirectoryPackParser extends PackParser { | |||
private final FileObjectDatabase db; | |||
/** CRC-32 computation for objects that are appended onto the pack. */ | |||
private final CRC32 crc; | |||
/** Running SHA-1 of any base objects appended after {@link #origEnd}. */ | |||
private final MessageDigest tailDigest; | |||
/** Preferred format version of the pack-*.idx file to generate. */ | |||
private int indexVersion; | |||
/** If true, pack with 0 objects will be stored. Usually these are deleted. */ | |||
private boolean keepEmpty; | |||
/** Path of the temporary file holding the pack data. */ | |||
private File tmpPack; | |||
/** | |||
* Path of the index created for the pack, to find objects quickly at read | |||
* time. | |||
*/ | |||
private File tmpIdx; | |||
/** Read/write handle to {@link #tmpPack} while it is being parsed. */ | |||
private RandomAccessFile out; | |||
/** Length of the original pack stream, before missing bases were appended. */ | |||
private long origEnd; | |||
/** The original checksum of data up to {@link #origEnd}. */ | |||
private byte[] origHash; | |||
/** Current end of the pack file. */ | |||
private long packEnd; | |||
/** Checksum of the entire pack file. */ | |||
private byte[] packHash; | |||
/** Compresses delta bases when completing a thin pack. */ | |||
private Deflater def; | |||
/** The pack that was created, if parsing was successful. */ | |||
private PackFile newPack; | |||
ObjectDirectoryPackParser(FileObjectDatabase odb, InputStream src) { | |||
super(odb, src); | |||
this.db = odb; | |||
this.crc = new CRC32(); | |||
this.tailDigest = Constants.newMessageDigest(); | |||
indexVersion = db.getConfig().get(CoreConfig.KEY).getPackIndexVersion(); | |||
} | |||
/** | |||
* Set the pack index file format version this instance will create. | |||
* | |||
* @param version | |||
* the version to write. The special version 0 designates the | |||
* oldest (most compatible) format available for the objects. | |||
* @see PackIndexWriter | |||
*/ | |||
public void setIndexVersion(int version) { | |||
indexVersion = version; | |||
} | |||
/** | |||
* Configure this index pack instance to keep an empty pack. | |||
* <p> | |||
* By default an empty pack (a pack with no objects) is not kept, as doi so | |||
* is completely pointless. With no objects in the pack there is no d stored | |||
* by it, so the pack is unnecessary. | |||
* | |||
* @param empty | |||
* true to enable keeping an empty pack. | |||
*/ | |||
public void setKeepEmpty(final boolean empty) { | |||
keepEmpty = empty; | |||
} | |||
/** | |||
* Get the imported {@link PackFile}. | |||
* <p> | |||
* This method is supplied only to support testing; applications shouldn't | |||
* be using it directly to access the imported data. | |||
* | |||
* @return the imported PackFile, if parsing was successful. | |||
*/ | |||
public PackFile getPackFile() { | |||
return newPack; | |||
} | |||
@Override | |||
public PackLock parse(ProgressMonitor progress) throws IOException { | |||
tmpPack = File.createTempFile("incoming_", ".pack", db.getDirectory()); | |||
tmpIdx = new File(db.getDirectory(), baseName(tmpPack) + ".idx"); | |||
try { | |||
out = new RandomAccessFile(tmpPack, "rw"); | |||
super.parse(progress); | |||
out.seek(packEnd); | |||
out.write(packHash); | |||
out.getChannel().force(true); | |||
out.close(); | |||
writeIdx(); | |||
tmpPack.setReadOnly(); | |||
tmpIdx.setReadOnly(); | |||
return renameAndOpenPack(getLockMessage()); | |||
} finally { | |||
if (def != null) | |||
def.end(); | |||
try { | |||
if (out != null && out.getChannel().isOpen()) | |||
out.close(); | |||
} catch (IOException closeError) { | |||
// Ignored. We want to delete the file. | |||
} | |||
cleanupTemporaryFiles(); | |||
} | |||
} | |||
@Override | |||
protected void onBeginWholeObject(long streamPosition, int type, | |||
long inflatedSize) throws IOException { | |||
crc.reset(); | |||
} | |||
@Override | |||
protected void onEndWholeObject(PackedObjectInfo info) throws IOException { | |||
info.setCRC((int) crc.getValue()); | |||
} | |||
@Override | |||
protected void onBeginOfsDelta(long streamPosition, | |||
long baseStreamPosition, long inflatedSize) throws IOException { | |||
crc.reset(); | |||
} | |||
@Override | |||
protected void onBeginRefDelta(long streamPosition, AnyObjectId baseId, | |||
long inflatedSize) throws IOException { | |||
crc.reset(); | |||
} | |||
@Override | |||
protected UnresolvedDelta onEndDelta() throws IOException { | |||
UnresolvedDelta delta = new UnresolvedDelta(); | |||
delta.setCRC((int) crc.getValue()); | |||
return delta; | |||
} | |||
@Override | |||
protected void onObjectHeader(Source src, byte[] raw, int pos, int len) | |||
throws IOException { | |||
crc.update(raw, pos, len); | |||
} | |||
@Override | |||
protected void onObjectData(Source src, byte[] raw, int pos, int len) | |||
throws IOException { | |||
crc.update(raw, pos, len); | |||
} | |||
@Override | |||
protected void onStoreStream(byte[] raw, int pos, int len) | |||
throws IOException { | |||
out.write(raw, pos, len); | |||
} | |||
@Override | |||
protected void onPackFooter(byte[] hash) throws IOException { | |||
packEnd = out.getFilePointer(); | |||
origEnd = packEnd; | |||
origHash = hash; | |||
packHash = hash; | |||
} | |||
@Override | |||
protected ObjectTypeAndSize seekDatabase(UnresolvedDelta delta, | |||
ObjectTypeAndSize info) throws IOException { | |||
out.seek(delta.getOffset()); | |||
crc.reset(); | |||
return readObjectHeader(info); | |||
} | |||
@Override | |||
protected ObjectTypeAndSize seekDatabase(PackedObjectInfo obj, | |||
ObjectTypeAndSize info) throws IOException { | |||
out.seek(obj.getOffset()); | |||
crc.reset(); | |||
return readObjectHeader(info); | |||
} | |||
@Override | |||
protected int readDatabase(byte[] dst, int pos, int cnt) throws IOException { | |||
return out.read(dst, pos, cnt); | |||
} | |||
@Override | |||
protected boolean checkCRC(int oldCRC) { | |||
return oldCRC == (int) crc.getValue(); | |||
} | |||
private static String baseName(File tmpPack) { | |||
String name = tmpPack.getName(); | |||
return name.substring(0, name.lastIndexOf('.')); | |||
} | |||
private void cleanupTemporaryFiles() { | |||
if (tmpIdx != null && !tmpIdx.delete() && tmpIdx.exists()) | |||
tmpIdx.deleteOnExit(); | |||
if (tmpPack != null && !tmpPack.delete() && tmpPack.exists()) | |||
tmpPack.deleteOnExit(); | |||
} | |||
@Override | |||
protected boolean onAppendBase(final int typeCode, final byte[] data, | |||
final PackedObjectInfo info) throws IOException { | |||
info.setOffset(packEnd); | |||
final byte[] buf = buffer(); | |||
int sz = data.length; | |||
int len = 0; | |||
buf[len++] = (byte) ((typeCode << 4) | sz & 15); | |||
sz >>>= 4; | |||
while (sz > 0) { | |||
buf[len - 1] |= 0x80; | |||
buf[len++] = (byte) (sz & 0x7f); | |||
sz >>>= 7; | |||
} | |||
tailDigest.update(buf, 0, len); | |||
crc.reset(); | |||
crc.update(buf, 0, len); | |||
out.seek(packEnd); | |||
out.write(buf, 0, len); | |||
packEnd += len; | |||
if (def == null) | |||
def = new Deflater(Deflater.DEFAULT_COMPRESSION, false); | |||
else | |||
def.reset(); | |||
def.setInput(data); | |||
def.finish(); | |||
while (!def.finished()) { | |||
len = def.deflate(buf); | |||
tailDigest.update(buf, 0, len); | |||
crc.update(buf, 0, len); | |||
out.write(buf, 0, len); | |||
packEnd += len; | |||
} | |||
info.setCRC((int) crc.getValue()); | |||
return true; | |||
} | |||
@Override | |||
protected void onEndThinPack() throws IOException { | |||
final byte[] tailHash = this.tailDigest.digest(); | |||
final byte[] buf = buffer(); | |||
final MessageDigest origDigest = Constants.newMessageDigest(); | |||
final MessageDigest tailDigest = Constants.newMessageDigest(); | |||
final MessageDigest packDigest = Constants.newMessageDigest(); | |||
long origRemaining = origEnd; | |||
out.seek(0); | |||
out.readFully(buf, 0, 12); | |||
origDigest.update(buf, 0, 12); | |||
origRemaining -= 12; | |||
NB.encodeInt32(buf, 8, getObjectCount()); | |||
out.seek(0); | |||
out.write(buf, 0, 12); | |||
packDigest.update(buf, 0, 12); | |||
for (;;) { | |||
final int n = out.read(buf); | |||
if (n < 0) | |||
break; | |||
if (origRemaining != 0) { | |||
final int origCnt = (int) Math.min(n, origRemaining); | |||
origDigest.update(buf, 0, origCnt); | |||
origRemaining -= origCnt; | |||
if (origRemaining == 0) | |||
tailDigest.update(buf, origCnt, n - origCnt); | |||
} else | |||
tailDigest.update(buf, 0, n); | |||
packDigest.update(buf, 0, n); | |||
} | |||
if (!Arrays.equals(origDigest.digest(), origHash) | |||
|| !Arrays.equals(tailDigest.digest(), tailHash)) | |||
throw new IOException( | |||
JGitText.get().packCorruptedWhileWritingToFilesystem); | |||
packHash = packDigest.digest(); | |||
} | |||
private void writeIdx() throws IOException { | |||
List<PackedObjectInfo> list = getSortedObjectList(null /* by ObjectId */); | |||
final FileOutputStream os = new FileOutputStream(tmpIdx); | |||
try { | |||
final PackIndexWriter iw; | |||
if (indexVersion <= 0) | |||
iw = PackIndexWriter.createOldestPossible(os, list); | |||
else | |||
iw = PackIndexWriter.createVersion(os, indexVersion); | |||
iw.write(list, packHash); | |||
os.getChannel().force(true); | |||
} finally { | |||
os.close(); | |||
} | |||
} | |||
private PackLock renameAndOpenPack(final String lockMessage) | |||
throws IOException { | |||
if (!keepEmpty && getObjectCount() == 0) { | |||
cleanupTemporaryFiles(); | |||
return null; | |||
} | |||
final MessageDigest d = Constants.newMessageDigest(); | |||
final byte[] oeBytes = new byte[Constants.OBJECT_ID_LENGTH]; | |||
for (int i = 0; i < getObjectCount(); i++) { | |||
final PackedObjectInfo oe = getObject(i); | |||
oe.copyRawTo(oeBytes, 0); | |||
d.update(oeBytes); | |||
} | |||
final String name = ObjectId.fromRaw(d.digest()).name(); | |||
final File packDir = new File(db.getDirectory(), "pack"); | |||
final File finalPack = new File(packDir, "pack-" + name + ".pack"); | |||
final File finalIdx = new File(packDir, "pack-" + name + ".idx"); | |||
final PackLock keep = new PackLock(finalPack, db.getFS()); | |||
if (!packDir.exists() && !packDir.mkdir() && !packDir.exists()) { | |||
// The objects/pack directory isn't present, and we are unable | |||
// to create it. There is no way to move this pack in. | |||
// | |||
cleanupTemporaryFiles(); | |||
throw new IOException(MessageFormat.format( | |||
JGitText.get().cannotCreateDirectory, packDir | |||
.getAbsolutePath())); | |||
} | |||
if (finalPack.exists()) { | |||
// If the pack is already present we should never replace it. | |||
// | |||
cleanupTemporaryFiles(); | |||
return null; | |||
} | |||
if (lockMessage != null) { | |||
// If we have a reason to create a keep file for this pack, do | |||
// so, or fail fast and don't put the pack in place. | |||
// | |||
try { | |||
if (!keep.lock(lockMessage)) | |||
throw new IOException(MessageFormat.format( | |||
JGitText.get().cannotLockPackIn, finalPack)); | |||
} catch (IOException e) { | |||
cleanupTemporaryFiles(); | |||
throw e; | |||
} | |||
} | |||
if (!tmpPack.renameTo(finalPack)) { | |||
cleanupTemporaryFiles(); | |||
keep.unlock(); | |||
throw new IOException(MessageFormat.format( | |||
JGitText.get().cannotMovePackTo, finalPack)); | |||
} | |||
if (!tmpIdx.renameTo(finalIdx)) { | |||
cleanupTemporaryFiles(); | |||
keep.unlock(); | |||
if (!finalPack.delete()) | |||
finalPack.deleteOnExit(); | |||
throw new IOException(MessageFormat.format( | |||
JGitText.get().cannotMoveIndexTo, finalIdx)); | |||
} | |||
try { | |||
newPack = db.openPack(finalPack, finalIdx); | |||
} catch (IOException err) { | |||
keep.unlock(); | |||
if (finalPack.exists()) | |||
FileUtils.delete(finalPack); | |||
if (finalIdx.exists()) | |||
FileUtils.delete(finalIdx); | |||
throw err; | |||
} | |||
return lockMessage != null ? keep : null; | |||
} | |||
} |
@@ -61,6 +61,7 @@ import org.eclipse.jgit.lib.Config; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.MutableObjectId; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.lib.ProgressMonitor; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.lib.Config.SectionParser; | |||
@@ -635,17 +636,21 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
} | |||
private void receivePack(final ProgressMonitor monitor) throws IOException { | |||
final IndexPack ip; | |||
InputStream input = in; | |||
if (sideband) | |||
input = new SideBandInputStream(input, monitor, getMessageWriter()); | |||
ip = IndexPack.create(local, input); | |||
ip.setFixThin(thinPack); | |||
ip.setObjectChecking(transport.isCheckFetchedObjects()); | |||
ip.index(monitor); | |||
packLock = ip.renameAndOpenPack(lockMessage); | |||
ObjectInserter ins = local.newObjectInserter(); | |||
try { | |||
PackParser parser = ins.newPackParser(input); | |||
parser.setAllowThin(thinPack); | |||
parser.setObjectChecking(transport.isCheckFetchedObjects()); | |||
parser.setLockMessage(lockMessage); | |||
packLock = parser.parse(monitor); | |||
ins.flush(); | |||
} finally { | |||
ins.release(); | |||
} | |||
} | |||
private static class CancelledException extends Exception { |
@@ -66,8 +66,10 @@ import org.eclipse.jgit.errors.MissingObjectException; | |||
import org.eclipse.jgit.errors.PackProtocolException; | |||
import org.eclipse.jgit.errors.TransportException; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.NullProgressMonitor; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectIdRef; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.lib.ProgressMonitor; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
@@ -96,7 +98,7 @@ class BundleFetchConnection extends BaseFetchConnection { | |||
BundleFetchConnection(Transport transportBundle, final InputStream src) throws TransportException { | |||
transport = transportBundle; | |||
bin = new BufferedInputStream(src, IndexPack.BUFFER_SIZE); | |||
bin = new BufferedInputStream(src); | |||
try { | |||
switch (readSignature()) { | |||
case 2: | |||
@@ -179,9 +181,17 @@ class BundleFetchConnection extends BaseFetchConnection { | |||
throws TransportException { | |||
verifyPrerequisites(); | |||
try { | |||
final IndexPack ip = newIndexPack(); | |||
ip.index(monitor); | |||
packLock = ip.renameAndOpenPack(lockMessage); | |||
ObjectInserter ins = transport.local.newObjectInserter(); | |||
try { | |||
PackParser parser = ins.newPackParser(bin); | |||
parser.setAllowThin(true); | |||
parser.setObjectChecking(transport.isCheckFetchedObjects()); | |||
parser.setLockMessage(lockMessage); | |||
packLock = parser.parse(NullProgressMonitor.INSTANCE); | |||
ins.flush(); | |||
} finally { | |||
ins.release(); | |||
} | |||
} catch (IOException err) { | |||
close(); | |||
throw new TransportException(transport.uri, err.getMessage(), err); | |||
@@ -201,13 +211,6 @@ class BundleFetchConnection extends BaseFetchConnection { | |||
return Collections.<PackLock> emptyList(); | |||
} | |||
private IndexPack newIndexPack() throws IOException { | |||
final IndexPack ip = IndexPack.create(transport.local, bin); | |||
ip.setFixThin(true); | |||
ip.setObjectChecking(transport.isCheckFetchedObjects()); | |||
return ip; | |||
} | |||
private void verifyPrerequisites() throws TransportException { | |||
if (prereqs.isEmpty()) | |||
return; |
@@ -44,7 +44,7 @@ | |||
package org.eclipse.jgit.transport; | |||
/** | |||
* Simple Map<long,Object> helper for {@link IndexPack}. | |||
* Simple Map<long,Object> helper for {@link PackParser}. | |||
* | |||
* @param <V> | |||
* type of the value instance. |
@@ -70,15 +70,16 @@ import org.eclipse.jgit.errors.MissingObjectException; | |||
import org.eclipse.jgit.errors.PackProtocolException; | |||
import org.eclipse.jgit.errors.UnpackException; | |||
import org.eclipse.jgit.lib.Config; | |||
import org.eclipse.jgit.lib.Config.SectionParser; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.NullProgressMonitor; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectIdSubclassMap; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.lib.PersonIdent; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.lib.RefUpdate; | |||
import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.lib.Config.SectionParser; | |||
import org.eclipse.jgit.revwalk.ObjectWalk; | |||
import org.eclipse.jgit.revwalk.RevBlob; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
@@ -161,7 +162,7 @@ public class ReceivePack { | |||
private Writer msgs; | |||
private IndexPack ip; | |||
private PackParser parser; | |||
/** The refs we advertised as existing at the start of the connection. */ | |||
private Map<String, Ref> refs; | |||
@@ -630,7 +631,7 @@ public class ReceivePack { | |||
receivePack(); | |||
if (needCheckConnectivity()) | |||
checkConnectivity(); | |||
ip = null; | |||
parser = null; | |||
unpackError = null; | |||
} catch (IOException err) { | |||
unpackError = err; | |||
@@ -779,17 +780,23 @@ public class ReceivePack { | |||
if (timeoutIn != null) | |||
timeoutIn.setTimeout(10 * timeout * 1000); | |||
ip = IndexPack.create(db, rawIn); | |||
ip.setFixThin(true); | |||
ip.setNeedNewObjectIds(checkReferencedIsReachable); | |||
ip.setNeedBaseObjectIds(checkReferencedIsReachable); | |||
ip.setObjectChecking(isCheckReceivedObjects()); | |||
ip.index(NullProgressMonitor.INSTANCE); | |||
String lockMsg = "jgit receive-pack"; | |||
if (getRefLogIdent() != null) | |||
lockMsg += " from " + getRefLogIdent().toExternalString(); | |||
packLock = ip.renameAndOpenPack(lockMsg); | |||
ObjectInserter ins = db.newObjectInserter(); | |||
try { | |||
String lockMsg = "jgit receive-pack"; | |||
if (getRefLogIdent() != null) | |||
lockMsg += " from " + getRefLogIdent().toExternalString(); | |||
parser = ins.newPackParser(rawIn); | |||
parser.setAllowThin(true); | |||
parser.setNeedNewObjectIds(checkReferencedIsReachable); | |||
parser.setNeedBaseObjectIds(checkReferencedIsReachable); | |||
parser.setObjectChecking(isCheckReceivedObjects()); | |||
parser.setLockMessage(lockMsg); | |||
packLock = parser.parse(NullProgressMonitor.INSTANCE); | |||
ins.flush(); | |||
} finally { | |||
ins.release(); | |||
} | |||
if (timeoutIn != null) | |||
timeoutIn.setTimeout(timeout * 1000); | |||
@@ -805,10 +812,10 @@ public class ReceivePack { | |||
ObjectIdSubclassMap<ObjectId> providedObjects = null; | |||
if (checkReferencedIsReachable) { | |||
baseObjects = ip.getBaseObjectIds(); | |||
providedObjects = ip.getNewObjectIds(); | |||
baseObjects = parser.getBaseObjectIds(); | |||
providedObjects = parser.getNewObjectIds(); | |||
} | |||
ip = null; | |||
parser = null; | |||
final ObjectWalk ow = new ObjectWalk(db); | |||
ow.setRetainBody(false); |
@@ -856,17 +856,16 @@ class WalkFetchConnection extends BaseFetchConnection { | |||
} | |||
void downloadPack(final ProgressMonitor monitor) throws IOException { | |||
final WalkRemoteObjectDatabase.FileStream s; | |||
final IndexPack ip; | |||
s = connection.open("pack/" + packName); | |||
ip = IndexPack.create(local, s.in); | |||
ip.setFixThin(false); | |||
ip.setObjectChecker(objCheck); | |||
ip.index(monitor); | |||
final PackLock keep = ip.renameAndOpenPack(lockMessage); | |||
if (keep != null) | |||
packLocks.add(keep); | |||
String name = "pack/" + packName; | |||
WalkRemoteObjectDatabase.FileStream s = connection.open(name); | |||
PackParser parser = inserter.newPackParser(s.in); | |||
parser.setAllowThin(false); | |||
parser.setObjectChecker(objCheck); | |||
parser.setLockMessage(lockMessage); | |||
PackLock lock = parser.parse(monitor); | |||
if (lock != null) | |||
packLocks.add(lock); | |||
inserter.flush(); | |||
} | |||
} | |||
} |