{"thread":{"id":"15377","subject":"[JGIT PATCH 0/7] Misc. RevWalk, bundle transport improvements","startedAt":"2008-09-04T23:42:12Z","lastAt":"2008-09-04T23:42:19Z","messageCount":8,"participants":["Shawn O. Pearce"],"isPatch":true,"patchVersion":1,"patchTotal":7},"messages":[{"id":"89805","messageId":"1220571739-4219-1-git-send-email-spearce@spearce.org","threadId":"15377","inReplyTo":null,"subject":"[JGIT PATCH 0/7] Misc. RevWalk, bundle transport improvements","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-04T23:42:12Z","receivedAt":"2008-09-04T23:42:12Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"The bundle transport improvements are needed for another open source\nproject I'm starting to find myself working on.  Details to be made\navailable at a later date, but its possibly something quite cool for\nthe Git community in general.\n\nAnyway...\n\nShawn O. Pearce (7):\n  Cleanup RevWalk.parseCommit, parseTree to not throw\n    ClassCastException\n  Cleanup RevWalk.parseTree semantics\n  Fix potential NullPointerException in RevWalk.parseTree\n  Add prerequisite verification to the bundle transport\n  Include URIish in bundle transport within any TransportExceptions\n  Refactor TransportBundle to not be dependent on FileInputStream\n  Refactor bundle transport to permit streaming from application\n\n .../jgit/pgm/opt/AbstractTreeIteratorHandler.java  |    2 -\n .../org/spearce/jgit/pgm/opt/RevCommitHandler.java |    2 -\n .../org/spearce/jgit/pgm/opt/RevTreeHandler.java   |    2 -\n .../errors/MissingBundlePrerequisiteException.java |   73 ++++++++++\n .../src/org/spearce/jgit/revwalk/RevWalk.java      |   28 +++-\n .../spearce/jgit/transport/BasePackConnection.java |    2 +-\n .../jgit/transport/BasePackFetchConnection.java    |    2 -\n .../src/org/spearce/jgit/transport/IndexPack.java  |   20 ++-\n .../src/org/spearce/jgit/transport/Transport.java  |    4 +-\n .../spearce/jgit/transport/TransportBundle.java    |  150 +++++++++++---------\n .../jgit/transport/TransportBundleFile.java        |   82 +++++++++++\n .../jgit/transport/TransportBundleStream.java      |  105 ++++++++++++++\n 12 files changed, 384 insertions(+), 88 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/errors/MissingBundlePrerequisiteException.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleFile.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleStream.java\n"},{"id":"89807","messageId":"1220571739-4219-2-git-send-email-spearce@spearce.org","threadId":"15377","inReplyTo":"1220571739-4219-1-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 1/7] Cleanup RevWalk.parseCommit, parseTree to not throw ClassCastException","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-04T23:42:13Z","receivedAt":"2008-09-04T23:42:13Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Throwing ClassCastException here for non-commits is really difficult\nto work with at the caller level because we may catch the wrong sort\nof ClassCastException and may mask a bug deep inside of RevWalk's\nparsing code.  It is cleaner to throw IncorrectObjectTypeException\nand catch that.  Besides, the method javadoc says that is what gets\nthrown if either method is given the wrong type.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../jgit/pgm/opt/AbstractTreeIteratorHandler.java  |    2 --\n .../org/spearce/jgit/pgm/opt/RevCommitHandler.java |    2 --\n .../org/spearce/jgit/pgm/opt/RevTreeHandler.java   |    2 --\n .../src/org/spearce/jgit/revwalk/RevWalk.java      |    7 ++++++-\n .../jgit/transport/BasePackFetchConnection.java    |    2 --\n 5 files changed, 6 insertions(+), 9 deletions(-)\n\ndiff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/AbstractTreeIteratorHandler.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/AbstractTreeIteratorHandler.java\nindex e439c87..9432d5f 100644\n--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/AbstractTreeIteratorHandler.java\n+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/AbstractTreeIteratorHandler.java\n@@ -112,8 +112,6 @@ public int parseArguments(final Parameters params) throws CmdLineException {\n \t\tfinal CanonicalTreeParser p = new CanonicalTreeParser();\n \t\ttry {\n \t\t\tp.reset(clp.getRepository(), clp.getRevWalk().parseTree(id));\n-\t\t} catch (ClassCastException e) {\n-\t\t\tthrow new CmdLineException(name + \" is not a tree\");\n \t\t} catch (MissingObjectException e) {\n \t\t\tthrow new CmdLineException(name + \" is not a tree\");\n \t\t} catch (IncorrectObjectTypeException e) {\ndiff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/RevCommitHandler.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/RevCommitHandler.java\nindex 772a8d7..5bfc61e 100644\n--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/RevCommitHandler.java\n+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/RevCommitHandler.java\n@@ -115,8 +115,6 @@ private void addOne(final String name, final boolean interesting)\n \t\tfinal RevCommit c;\n \t\ttry {\n \t\t\tc = clp.getRevWalk().parseCommit(id);\n-\t\t} catch (ClassCastException e) {\n-\t\t\tthrow new CmdLineException(name + \" is not a commit\");\n \t\t} catch (MissingObjectException e) {\n \t\t\tthrow new CmdLineException(name + \" is not a commit\");\n \t\t} catch (IncorrectObjectTypeException e) {\ndiff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/RevTreeHandler.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/RevTreeHandler.java\nindex de64336..0a0c5d2 100644\n--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/RevTreeHandler.java\n+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/RevTreeHandler.java\n@@ -88,8 +88,6 @@ public int parseArguments(final Parameters params) throws CmdLineException {\n \t\tfinal RevTree c;\n \t\ttry {\n \t\t\tc = clp.getRevWalk().parseTree(id);\n-\t\t} catch (ClassCastException e) {\n-\t\t\tthrow new CmdLineException(name + \" is not a tree\");\n \t\t} catch (MissingObjectException e) {\n \t\t\tthrow new CmdLineException(name + \" is not a tree\");\n \t\t} catch (IncorrectObjectTypeException e) {\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java\nindex c90f2a3..243d9b3 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java\n@@ -608,6 +608,9 @@ public RevCommit parseCommit(final AnyObjectId id)\n \t\t\tc = ((RevTag) c).getObject();\n \t\t\tparse(c);\n \t\t}\n+\t\tif (!(c instanceof RevCommit))\n+\t\t\tthrow new IncorrectObjectTypeException(id.toObjectId(),\n+\t\t\t\t\tConstants.TYPE_COMMIT);\n \t\treturn (RevCommit) c;\n \t}\n \n@@ -639,7 +642,9 @@ public RevTree parseTree(final AnyObjectId id)\n \t\tif (c instanceof RevCommit) {\n \t\t\tc = ((RevCommit) c).getTree();\n \t\t\tparse(c);\n-\t\t}\n+\t\t} else if (!(c instanceof RevTree))\n+\t\t\tthrow new IncorrectObjectTypeException(id.toObjectId(),\n+\t\t\t\t\tConstants.TYPE_TREE);\n \t\tfinal RevTree t = (RevTree) c;\n \t\tif (db.openObject(t).getType() != Constants.OBJ_TREE)\n \t\t\tthrow new IncorrectObjectTypeException(t, Constants.TYPE_TREE);\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\nindex 39fa761..a22b33d 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\n@@ -197,8 +197,6 @@ private void markReachable(final int maxTime) throws IOException {\n \t\t\t\treachableCommits.add(o);\n \t\t\t} catch (IOException readError) {\n \t\t\t\t// If we cannot read the value of the ref skip it.\n-\t\t\t} catch (ClassCastException cce) {\n-\t\t\t\t// Not a commit type.\n \t\t\t}\n \t\t}\n \n-- \n1.6.0.1.319.g9f32b\n"},{"id":"89809","messageId":"1220571739-4219-3-git-send-email-spearce@spearce.org","threadId":"15377","inReplyTo":"1220571739-4219-2-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 2/7] Cleanup RevWalk.parseTree semantics","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-04T23:42:14Z","receivedAt":"2008-09-04T23:42:14Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"When we call parseAny we may have opened the ObjectLoader for the\ntree we are going after.  If that worked we know the object exists\nin the repository and is certainly recorded as type \"tree\" so we\ndo not need to open the object a second time before returning to\nthe caller.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../src/org/spearce/jgit/revwalk/RevWalk.java      |   18 +++++++++++++-----\n 1 files changed, 13 insertions(+), 5 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java\nindex 243d9b3..5a29dcf 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java\n@@ -639,15 +639,21 @@ public RevTree parseTree(final AnyObjectId id)\n \t\t\tc = ((RevTag) c).getObject();\n \t\t\tparse(c);\n \t\t}\n-\t\tif (c instanceof RevCommit) {\n-\t\t\tc = ((RevCommit) c).getTree();\n-\t\t\tparse(c);\n-\t\t} else if (!(c instanceof RevTree))\n+\t\t\n+\t\tfinal RevTree t;\n+\t\tif (c instanceof RevCommit)\n+\t\t\tt = ((RevCommit) c).getTree();\n+\t\telse if (!(c instanceof RevTree))\n \t\t\tthrow new IncorrectObjectTypeException(id.toObjectId(),\n \t\t\t\t\tConstants.TYPE_TREE);\n-\t\tfinal RevTree t = (RevTree) c;\n+\t\telse\n+\t\t\tt = (RevTree) c;\n+\n+\t\tif ((t.flags & PARSED) != 0)\n+\t\t\treturn t;\n \t\tif (db.openObject(t).getType() != Constants.OBJ_TREE)\n \t\t\tthrow new IncorrectObjectTypeException(t, Constants.TYPE_TREE);\n+\t\tt.flags |= PARSED;\n \t\treturn t;\n \t}\n \n@@ -685,10 +691,12 @@ public RevObject parseAny(final AnyObjectId id)\n \t\t\t}\n \t\t\tcase Constants.OBJ_TREE: {\n \t\t\t\tr = new RevTree(ldr.getId());\n+\t\t\t\tr.flags |= PARSED;\n \t\t\t\tbreak;\n \t\t\t}\n \t\t\tcase Constants.OBJ_BLOB: {\n \t\t\t\tr = new RevBlob(ldr.getId());\n+\t\t\t\tr.flags |= PARSED;\n \t\t\t\tbreak;\n \t\t\t}\n \t\t\tcase Constants.OBJ_TAG: {\n-- \n1.6.0.1.319.g9f32b\n"},{"id":"89806","messageId":"1220571739-4219-4-git-send-email-spearce@spearce.org","threadId":"15377","inReplyTo":"1220571739-4219-3-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 3/7] Fix potential NullPointerException in RevWalk.parseTree","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-04T23:42:15Z","receivedAt":"2008-09-04T23:42:15Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"If we have previously obtained this RevTree by lookupTree (such as\nin a commit) but we are missing in the repository and call parseTree\nwe want a MissingObjectException to be thrown, not an NPE.  The NPE\ntells us nothing and could be the same as a bug internal to RevWalk.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../src/org/spearce/jgit/revwalk/RevWalk.java      |    5 ++++-\n 1 files changed, 4 insertions(+), 1 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java\nindex 5a29dcf..0dead10 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java\n@@ -651,7 +651,10 @@ else if (!(c instanceof RevTree))\n \n \t\tif ((t.flags & PARSED) != 0)\n \t\t\treturn t;\n-\t\tif (db.openObject(t).getType() != Constants.OBJ_TREE)\n+\t\tfinal ObjectLoader ldr = db.openObject(t);\n+\t\tif (ldr == null)\n+\t\t\tthrow new MissingObjectException(t, Constants.TYPE_TREE);\n+\t\tif (ldr.getType() != Constants.OBJ_TREE)\n \t\t\tthrow new IncorrectObjectTypeException(t, Constants.TYPE_TREE);\n \t\tt.flags |= PARSED;\n \t\treturn t;\n-- \n1.6.0.1.319.g9f32b\n"},{"id":"89810","messageId":"1220571739-4219-5-git-send-email-spearce@spearce.org","threadId":"15377","inReplyTo":"1220571739-4219-4-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 4/7] Add prerequisite verification to the bundle transport","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-04T23:42:16Z","receivedAt":"2008-09-04T23:42:16Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Before we can fetch the objects contained within the bundle into\nthe repository we need to know if we have the necessary bases in\nour reachable history, thus ensuring that we have what is needed\nto fill out the thin pack and access everything contained within\nit.  If we are missing any of the commits named as prerequisites\nin the bundle header we cannot import it.\n\nI forgot to implement this when I initially added bundle support\nto the transport implementation.  Better late then never.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../errors/MissingBundlePrerequisiteException.java |   73 ++++++++++++++++++++\n .../spearce/jgit/transport/TransportBundle.java    |   68 ++++++++++++++++++\n 2 files changed, 141 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/errors/MissingBundlePrerequisiteException.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/errors/MissingBundlePrerequisiteException.java b/org.spearce.jgit/src/org/spearce/jgit/errors/MissingBundlePrerequisiteException.java\nnew file mode 100644\nindex 0000000..ccd9281\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/errors/MissingBundlePrerequisiteException.java\n@@ -0,0 +1,73 @@\n+/*\n+ * Copyright (C) 2008, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.errors;\n+\n+import java.util.Collection;\n+\n+import org.spearce.jgit.lib.ObjectId;\n+import org.spearce.jgit.transport.URIish;\n+\n+/**\n+ * Indicates a base/common object was required, but is not found.\n+ */\n+public class MissingBundlePrerequisiteException extends TransportException {\n+\tprivate static final long serialVersionUID = 1L;\n+\n+\tprivate static String format(final Collection<ObjectId> ids) {\n+\t\tfinal StringBuilder r = new StringBuilder();\n+\t\tr.append(\"missing prerequisite commits:\");\n+\t\tfor (final ObjectId p : ids) {\n+\t\t\tr.append(\"\\n  \");\n+\t\t\tr.append(p.name());\n+\t\t}\n+\t\treturn r.toString();\n+\t}\n+\n+\t/**\n+\t * Constructs a MissingBundlePrerequisiteException for a set of objects.\n+\t * \n+\t * @param uri\n+\t *            URI used for transport\n+\t * @param ids\n+\t *            the ids of the base/common object(s) we don't have.\n+\t */\n+\tpublic MissingBundlePrerequisiteException(final URIish uri,\n+\t\t\tfinal Collection<ObjectId> ids) {\n+\t\tsuper(uri, format(ids));\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\nindex d8c2ba4..e502619 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\n@@ -1,6 +1,7 @@\n /*\n  * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>\n  * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>\n+ * Copyright (C) 2008, Google Inc.\n  *\n  * All rights reserved.\n  *\n@@ -44,11 +45,15 @@\n import java.io.FileNotFoundException;\n import java.io.IOException;\n import java.io.InputStream;\n+import java.util.ArrayList;\n import java.util.Collection;\n import java.util.HashSet;\n import java.util.LinkedHashMap;\n+import java.util.List;\n import java.util.Set;\n \n+import org.spearce.jgit.errors.MissingObjectException;\n+import org.spearce.jgit.errors.MissingBundlePrerequisiteException;\n import org.spearce.jgit.errors.NotSupportedException;\n import org.spearce.jgit.errors.PackProtocolException;\n import org.spearce.jgit.errors.TransportException;\n@@ -57,6 +62,10 @@\n import org.spearce.jgit.lib.ProgressMonitor;\n import org.spearce.jgit.lib.Ref;\n import org.spearce.jgit.lib.Repository;\n+import org.spearce.jgit.revwalk.RevCommit;\n+import org.spearce.jgit.revwalk.RevFlag;\n+import org.spearce.jgit.revwalk.RevObject;\n+import org.spearce.jgit.revwalk.RevWalk;\n import org.spearce.jgit.util.FS;\n import org.spearce.jgit.util.RawParseUtils;\n \n@@ -200,6 +209,7 @@ private String readLine(final byte[] hdrbuf) throws IOException {\n \t\t@Override\n \t\tprotected void doFetch(final ProgressMonitor monitor,\n \t\t\t\tfinal Collection<Ref> want) throws TransportException {\n+\t\t\tverifyPrerequisites();\n \t\t\ttry {\n \t\t\t\tfinal IndexPack ip = IndexPack.create(local, in);\n \t\t\t\tip.setFixThin(true);\n@@ -214,6 +224,64 @@ protected void doFetch(final ProgressMonitor monitor,\n \t\t\t}\n \t\t}\n \n+\t\tprivate void verifyPrerequisites() throws TransportException {\n+\t\t\tif (prereqs.isEmpty())\n+\t\t\t\treturn;\n+\n+\t\t\tfinal RevWalk rw = new RevWalk(local);\n+\t\t\tfinal RevFlag PREREQ = rw.newFlag(\"PREREQ\");\n+\t\t\tfinal RevFlag SEEN = rw.newFlag(\"SEEN\");\n+\t\t\t\n+\t\t\tfinal List<ObjectId> missing = new ArrayList<ObjectId>();\n+\t\t\tfinal List<RevObject> commits = new ArrayList<RevObject>();\n+\t\t\tfor (final ObjectId p : prereqs) {\n+\t\t\t\ttry {\n+\t\t\t\t\tfinal RevCommit c = rw.parseCommit(p);\n+\t\t\t\t\tif (!c.has(PREREQ)) {\n+\t\t\t\t\t\tc.add(PREREQ);\n+\t\t\t\t\t\tcommits.add(c);\n+\t\t\t\t\t}\n+\t\t\t\t} catch (MissingObjectException notFound) {\n+\t\t\t\t\tmissing.add(p);\n+\t\t\t\t} catch (IOException err) {\n+\t\t\t\t\tthrow new TransportException(uri, \"Cannot read commit \"\n+\t\t\t\t\t\t\t+ p.name(), err);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif (!missing.isEmpty())\n+\t\t\t\tthrow new MissingBundlePrerequisiteException(uri, missing);\n+\n+\t\t\tfor (final Ref r : local.getAllRefs().values()) {\n+\t\t\t\ttry {\n+\t\t\t\t\trw.markStart(rw.parseCommit(r.getObjectId()));\n+\t\t\t\t} catch (IOException readError) {\n+\t\t\t\t\t// If we cannot read the value of the ref skip it.\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t\tint remaining = commits.size();\n+\t\t\ttry {\n+\t\t\t\tRevCommit c;\n+\t\t\t\twhile ((c = rw.next()) != null) {\n+\t\t\t\t\tif (c.has(PREREQ)) {\n+\t\t\t\t\t\tc.add(SEEN);\n+\t\t\t\t\t\tif (--remaining == 0)\n+\t\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t} catch (IOException err) {\n+\t\t\t\tthrow new TransportException(uri, \"Cannot read object\", err);\n+\t\t\t}\n+\n+\t\t\tif (remaining > 0) {\n+\t\t\t\tfor (final RevObject o : commits) {\n+\t\t\t\t\tif (!o.has(SEEN))\n+\t\t\t\t\t\tmissing.add(o);\n+\t\t\t\t}\n+\t\t\t\tthrow new MissingBundlePrerequisiteException(uri, missing);\n+\t\t\t}\n+\t\t}\n+\n \t\t@Override\n \t\tpublic void close() {\n \t\t\tif (in != null) {\n-- \n1.6.0.1.319.g9f32b\n"},{"id":"89812","messageId":"1220571739-4219-6-git-send-email-spearce@spearce.org","threadId":"15377","inReplyTo":"1220571739-4219-5-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 5/7] Include URIish in bundle transport within any TransportExceptions","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-04T23:42:17Z","receivedAt":"2008-09-04T23:42:17Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"This way the bundle path (as entered by the user) is reported as\npart of the error.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../spearce/jgit/transport/TransportBundle.java    |   21 ++++++++-----------\n 1 files changed, 9 insertions(+), 12 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\nindex e502619..de62fb8 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\n@@ -128,7 +128,7 @@ BundleFetchConnection() throws TransportException {\n \t\t\t\tin = new FileInputStream(bundle);\n \t\t\t\tbin = new RewindBufferedInputStream(in);\n \t\t\t} catch (FileNotFoundException err) {\n-\t\t\t\tthrow new TransportException(bundle.getPath() + \": not found\");\n+\t\t\t\tthrow new TransportException(uri, \"not found\");\n \t\t\t}\n \n \t\t\ttry {\n@@ -137,8 +137,7 @@ BundleFetchConnection() throws TransportException {\n \t\t\t\t\treadBundleV2();\n \t\t\t\t\tbreak;\n \t\t\t\tdefault:\n-\t\t\t\t\tthrow new TransportException(bundle.getPath()\n-\t\t\t\t\t\t\t+ \": not a bundle\");\n+\t\t\t\t\tthrow new TransportException(uri, \"not a bundle\");\n \t\t\t\t}\n \n \t\t\t\tin.getChannel().position(\n@@ -149,12 +148,10 @@ BundleFetchConnection() throws TransportException {\n \t\t\t\tthrow err;\n \t\t\t} catch (IOException err) {\n \t\t\t\tclose();\n-\t\t\t\tthrow new TransportException(bundle.getPath() + \": \"\n-\t\t\t\t\t\t+ err.getMessage(), err);\n+\t\t\t\tthrow new TransportException(uri, err.getMessage(), err);\n \t\t\t} catch (RuntimeException err) {\n \t\t\t\tclose();\n-\t\t\t\tthrow new TransportException(bundle.getPath() + \": \"\n-\t\t\t\t\t\t+ err.getMessage(), err);\n+\t\t\t\tthrow new TransportException(uri, err.getMessage(), err);\n \t\t\t}\n \t\t}\n \n@@ -162,7 +159,7 @@ private int readSignature() throws IOException {\n \t\t\tfinal String rev = readLine(new byte[1024]);\n \t\t\tif (V2_BUNDLE_SIGNATURE.equals(rev))\n \t\t\t\treturn 2;\n-\t\t\tthrow new TransportException(bundle.getPath() + \": not a bundle\");\n+\t\t\tthrow new TransportException(uri, \"not a bundle\");\n \t\t}\n \n \t\tprivate void readBundleV2() throws IOException {\n@@ -189,8 +186,8 @@ private void readBundleV2() throws IOException {\n \t\t}\n \n \t\tprivate PackProtocolException duplicateAdvertisement(final String name) {\n-\t\t\treturn new PackProtocolException(\"duplicate advertisements of \"\n-\t\t\t\t\t+ name);\n+\t\t\treturn new PackProtocolException(uri,\n+\t\t\t\t\t\"duplicate advertisements of \" + name);\n \t\t}\n \n \t\tprivate String readLine(final byte[] hdrbuf) throws IOException {\n@@ -217,10 +214,10 @@ protected void doFetch(final ProgressMonitor monitor,\n \t\t\t\tip.renameAndOpenPack();\n \t\t\t} catch (IOException err) {\n \t\t\t\tclose();\n-\t\t\t\tthrow new TransportException(err.getMessage(), err);\n+\t\t\t\tthrow new TransportException(uri, err.getMessage(), err);\n \t\t\t} catch (RuntimeException err) {\n \t\t\t\tclose();\n-\t\t\t\tthrow new TransportException(err.getMessage(), err);\n+\t\t\t\tthrow new TransportException(uri, err.getMessage(), err);\n \t\t\t}\n \t\t}\n \n-- \n1.6.0.1.319.g9f32b\n"},{"id":"89808","messageId":"1220571739-4219-7-git-send-email-spearce@spearce.org","threadId":"15377","inReplyTo":"1220571739-4219-6-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 6/7] Refactor TransportBundle to not be dependent on FileInputStream","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-04T23:42:18Z","receivedAt":"2008-09-04T23:42:18Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"By using a straight up BufferedInputStream and making it play nicely\nwith IndexPack's internal buffering we can permit TransportBundle to\naccept input from any sort of InputStream, not just those that have\na positionable Channel underneath of them.  This makes it possible\nto stream a bundle over the network, or from a byte[] in memory.\n\nIndexPack now publishes its BUFFER_SIZE member so callers can create\ntheir own BufferedInputStream with the same size buffer.  This way we\ncan be sure that reads after the first bypass BufferedInputStream's\nbuffer and go directly into IndexPack's buffer.\n\nThe BUFFER_SIZE is increased to 8192 as that is the same size that\nis used by default in BufferedInputStream in Java 6.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../spearce/jgit/transport/BasePackConnection.java |    2 +-\n .../src/org/spearce/jgit/transport/IndexPack.java  |   20 +++++++--\n .../spearce/jgit/transport/TransportBundle.java    |   43 ++++++--------------\n 3 files changed, 30 insertions(+), 35 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java\nindex 6101802..184a5fd 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java\n@@ -101,7 +101,7 @@ BasePackConnection(final PackTransport packTransport) {\n \n \tprotected void init(final InputStream myIn, final OutputStream myOut) {\n \t\tin = myIn instanceof BufferedInputStream ? myIn\n-\t\t\t\t: new BufferedInputStream(myIn);\n+\t\t\t\t: new BufferedInputStream(myIn, IndexPack.BUFFER_SIZE);\n \t\tout = myOut instanceof BufferedOutputStream ? myOut\n \t\t\t\t: new BufferedOutputStream(myOut);\n \ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java b/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java\nindex 2c98823..bc52896 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/IndexPack.java\n@@ -76,20 +76,30 @@\n \t/** Progress message when computing names of delta compressed objects. */\n \tpublic static final String PROGRESS_RESOLVE_DELTA = \"Resolving deltas\";\n \n-\tprivate static final int BUFFER_SIZE = 4096;\n+\t/**\n+\t * Size of the internal stream buffer.\n+\t * <p>\n+\t * If callers are going to be supplying IndexPack a BufferedInputStream they\n+\t * should use this buffer size as the size of the buffer for that\n+\t * BufferedInputStream, and any other its may be wrapping. This way the\n+\t * buffers will cascade efficiently and only the IndexPack buffer will be\n+\t * receiving the bulk of the data stream.\n+\t */\n+\tpublic static final int BUFFER_SIZE = 8192;\n \n \t/**\n \t * Create an index pack instance to load a new pack into a repository.\n \t * <p>\n \t * The received pack data and generated index will be saved to temporary\n-\t * files within the repository's <code>objects</code> directory. To use\n-\t * the data contained within them call {@link #renameAndOpenPack()} once the\n+\t * files within the repository's <code>objects</code> directory. To use the\n+\t * data contained within them call {@link #renameAndOpenPack()} once the\n \t * indexing is complete.\n \t * \n \t * @param db\n \t *            the repository that will receive the new pack.\n \t * @param is\n-\t *            stream to read the pack data from.\n+\t *            stream to read the pack data from. If the stream is buffered\n+\t *            use {@link #BUFFER_SIZE} as the buffer size for the stream.\n \t * @return a new index pack instance.\n \t * @throws IOException\n \t *             a temporary file could not be created.\n@@ -164,6 +174,8 @@ public static IndexPack create(final Repository db, final InputStream is)\n \t * \n \t * @param db\n \t * @param src\n+\t *            stream to read the pack data from. If the stream is buffered\n+\t *            use {@link #BUFFER_SIZE} as the buffer size for the stream.\n \t * @param dstBase\n \t * @throws IOException\n \t *             the output packfile could not be created.\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\nindex de62fb8..765fc0f 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\n@@ -102,7 +102,13 @@ TransportBundle(final Repository local, final URIish uri) {\n \t@Override\n \tpublic FetchConnection openFetch() throws NotSupportedException,\n \t\t\tTransportException {\n-\t\treturn new BundleFetchConnection();\n+\t\tfinal InputStream src;\n+\t\ttry {\n+\t\t\tsrc = new FileInputStream(bundle);\n+\t\t} catch (FileNotFoundException err) {\n+\t\t\tthrow new TransportException(uri, \"not found\");\n+\t\t}\n+\t\treturn new BundleFetchConnection(src);\n \t}\n \n \t@Override\n@@ -117,20 +123,12 @@ public void close() {\n \t}\n \n \tclass BundleFetchConnection extends BaseFetchConnection {\n-\t\tFileInputStream in;\n-\n-\t\tRewindBufferedInputStream bin;\n+\t\tInputStream bin;\n \n \t\tfinal Set<ObjectId> prereqs = new HashSet<ObjectId>();\n \n-\t\tBundleFetchConnection() throws TransportException {\n-\t\t\ttry {\n-\t\t\t\tin = new FileInputStream(bundle);\n-\t\t\t\tbin = new RewindBufferedInputStream(in);\n-\t\t\t} catch (FileNotFoundException err) {\n-\t\t\t\tthrow new TransportException(uri, \"not found\");\n-\t\t\t}\n-\n+\t\tBundleFetchConnection(final InputStream src) throws TransportException {\n+\t\t\tbin = new BufferedInputStream(src, IndexPack.BUFFER_SIZE);\n \t\t\ttry {\n \t\t\t\tswitch (readSignature()) {\n \t\t\t\tcase 2:\n@@ -139,10 +137,6 @@ BundleFetchConnection() throws TransportException {\n \t\t\t\tdefault:\n \t\t\t\t\tthrow new TransportException(uri, \"not a bundle\");\n \t\t\t\t}\n-\n-\t\t\t\tin.getChannel().position(\n-\t\t\t\t\t\tin.getChannel().position() - bin.buffered());\n-\t\t\t\tbin = null;\n \t\t\t} catch (TransportException err) {\n \t\t\t\tclose();\n \t\t\t\tthrow err;\n@@ -208,7 +202,7 @@ protected void doFetch(final ProgressMonitor monitor,\n \t\t\t\tfinal Collection<Ref> want) throws TransportException {\n \t\t\tverifyPrerequisites();\n \t\t\ttry {\n-\t\t\t\tfinal IndexPack ip = IndexPack.create(local, in);\n+\t\t\t\tfinal IndexPack ip = IndexPack.create(local, bin);\n \t\t\t\tip.setFixThin(true);\n \t\t\t\tip.index(monitor);\n \t\t\t\tip.renameAndOpenPack();\n@@ -281,26 +275,15 @@ private void verifyPrerequisites() throws TransportException {\n \n \t\t@Override\n \t\tpublic void close() {\n-\t\t\tif (in != null) {\n+\t\t\tif (bin != null) {\n \t\t\t\ttry {\n-\t\t\t\t\tin.close();\n+\t\t\t\t\tbin.close();\n \t\t\t\t} catch (IOException ie) {\n \t\t\t\t\t// Ignore close failures.\n \t\t\t\t} finally {\n-\t\t\t\t\tin = null;\n \t\t\t\t\tbin = null;\n \t\t\t\t}\n \t\t\t}\n \t\t}\n-\n-\t\tclass RewindBufferedInputStream extends BufferedInputStream {\n-\t\t\tRewindBufferedInputStream(final InputStream src) {\n-\t\t\t\tsuper(src);\n-\t\t\t}\n-\n-\t\t\tint buffered() {\n-\t\t\t\treturn (count - pos);\n-\t\t\t}\n-\t\t}\n \t}\n }\n-- \n1.6.0.1.319.g9f32b\n"},{"id":"89811","messageId":"1220571739-4219-8-git-send-email-spearce@spearce.org","threadId":"15377","inReplyTo":"1220571739-4219-7-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 7/7] Refactor bundle transport to permit streaming from application","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-04T23:42:19Z","receivedAt":"2008-09-04T23:42:19Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"The new TransportBundleStream is public and can be created by an\napplication directly from any InputStream.  This permits the app\nto obtain the bundle data on its own via any means and feed it\ninto the bundle transport.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../src/org/spearce/jgit/transport/Transport.java  |    4 +-\n .../spearce/jgit/transport/TransportBundle.java    |   36 +-------\n .../jgit/transport/TransportBundleFile.java        |   82 +++++++++++++++\n .../jgit/transport/TransportBundleStream.java      |  105 ++++++++++++++++++++\n 4 files changed, 191 insertions(+), 36 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleFile.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleStream.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java\nindex 65f2c6b..7284b28 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java\n@@ -204,8 +204,8 @@ else if (TransportGitAnon.canHandle(remote))\n \t\telse if (TransportAmazonS3.canHandle(remote))\n \t\t\treturn new TransportAmazonS3(local, remote);\n \n-\t\telse if (TransportBundle.canHandle(remote))\n-\t\t\treturn new TransportBundle(local, remote);\n+\t\telse if (TransportBundleFile.canHandle(remote))\n+\t\t\treturn new TransportBundleFile(local, remote);\n \n \t\telse if (TransportLocal.canHandle(remote))\n \t\t\treturn new TransportLocal(local, remote);\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\nindex 765fc0f..fed34e8 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java\n@@ -40,9 +40,6 @@\n package org.spearce.jgit.transport;\n \n import java.io.BufferedInputStream;\n-import java.io.File;\n-import java.io.FileInputStream;\n-import java.io.FileNotFoundException;\n import java.io.IOException;\n import java.io.InputStream;\n import java.util.ArrayList;\n@@ -52,8 +49,8 @@\n import java.util.List;\n import java.util.Set;\n \n-import org.spearce.jgit.errors.MissingObjectException;\n import org.spearce.jgit.errors.MissingBundlePrerequisiteException;\n+import org.spearce.jgit.errors.MissingObjectException;\n import org.spearce.jgit.errors.NotSupportedException;\n import org.spearce.jgit.errors.PackProtocolException;\n import org.spearce.jgit.errors.TransportException;\n@@ -66,7 +63,6 @@\n import org.spearce.jgit.revwalk.RevFlag;\n import org.spearce.jgit.revwalk.RevObject;\n import org.spearce.jgit.revwalk.RevWalk;\n-import org.spearce.jgit.util.FS;\n import org.spearce.jgit.util.RawParseUtils;\n \n /**\n@@ -76,39 +72,11 @@\n  * communicate with to decide what the peer already knows. So push is not\n  * supported by the bundle transport.\n  */\n-class TransportBundle extends PackTransport {\n+abstract class TransportBundle extends PackTransport {\n \tstatic final String V2_BUNDLE_SIGNATURE = \"# v2 git bundle\";\n \n-\tstatic boolean canHandle(final URIish uri) {\n-\t\tif (uri.getHost() != null || uri.getPort() > 0 || uri.getUser() != null\n-\t\t\t\t|| uri.getPass() != null || uri.getPath() == null)\n-\t\t\treturn false;\n-\n-\t\tif (\"file\".equals(uri.getScheme()) || uri.getScheme() == null) {\n-\t\t\tfinal File f = FS.resolve(new File(\".\"), uri.getPath());\n-\t\t\treturn f.isFile() || f.getName().endsWith(\".bundle\");\n-\t\t}\n-\n-\t\treturn false;\n-\t}\n-\n-\tprivate final File bundle;\n-\n \tTransportBundle(final Repository local, final URIish uri) {\n \t\tsuper(local, uri);\n-\t\tbundle = FS.resolve(new File(\".\"), uri.getPath()).getAbsoluteFile();\n-\t}\n-\n-\t@Override\n-\tpublic FetchConnection openFetch() throws NotSupportedException,\n-\t\t\tTransportException {\n-\t\tfinal InputStream src;\n-\t\ttry {\n-\t\t\tsrc = new FileInputStream(bundle);\n-\t\t} catch (FileNotFoundException err) {\n-\t\t\tthrow new TransportException(uri, \"not found\");\n-\t\t}\n-\t\treturn new BundleFetchConnection(src);\n \t}\n \n \t@Override\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleFile.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleFile.java\nnew file mode 100644\nindex 0000000..c9ff1b2\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleFile.java\n@@ -0,0 +1,82 @@\n+/*\n+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.transport;\n+\n+import java.io.File;\n+import java.io.FileInputStream;\n+import java.io.FileNotFoundException;\n+import java.io.InputStream;\n+\n+import org.spearce.jgit.errors.NotSupportedException;\n+import org.spearce.jgit.errors.TransportException;\n+import org.spearce.jgit.lib.Repository;\n+import org.spearce.jgit.util.FS;\n+\n+class TransportBundleFile extends TransportBundle {\n+\tstatic boolean canHandle(final URIish uri) {\n+\t\tif (uri.getHost() != null || uri.getPort() > 0 || uri.getUser() != null\n+\t\t\t\t|| uri.getPass() != null || uri.getPath() == null)\n+\t\t\treturn false;\n+\n+\t\tif (\"file\".equals(uri.getScheme()) || uri.getScheme() == null) {\n+\t\t\tfinal File f = FS.resolve(new File(\".\"), uri.getPath());\n+\t\t\treturn f.isFile() || f.getName().endsWith(\".bundle\");\n+\t\t}\n+\n+\t\treturn false;\n+\t}\n+\n+\tprivate final File bundle;\n+\n+\tTransportBundleFile(final Repository local, final URIish uri) {\n+\t\tsuper(local, uri);\n+\t\tbundle = FS.resolve(new File(\".\"), uri.getPath()).getAbsoluteFile();\n+\t}\n+\n+\t@Override\n+\tpublic FetchConnection openFetch() throws NotSupportedException,\n+\t\t\tTransportException {\n+\t\tfinal InputStream src;\n+\t\ttry {\n+\t\t\tsrc = new FileInputStream(bundle);\n+\t\t} catch (FileNotFoundException err) {\n+\t\t\tthrow new TransportException(uri, \"not found\");\n+\t\t}\n+\t\treturn new BundleFetchConnection(src);\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleStream.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleStream.java\nnew file mode 100644\nindex 0000000..0272261\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundleStream.java\n@@ -0,0 +1,105 @@\n+/*\n+ * Copyright (C) 2008, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.transport;\n+\n+import java.io.IOException;\n+import java.io.InputStream;\n+\n+import org.spearce.jgit.errors.TransportException;\n+import org.spearce.jgit.lib.Repository;\n+\n+/**\n+ * Single shot fetch from a streamed Git bundle.\n+ * <p>\n+ * The bundle is read from an unbuffered input stream, which limits the\n+ * transport to opening at most one FetchConnection before needing to recreate\n+ * the transport instance.\n+ */\n+public class TransportBundleStream extends TransportBundle {\n+\tprivate InputStream src;\n+\n+\t/**\n+\t * Create a new transport to fetch objects from a streamed bundle.\n+\t * <p>\n+\t * The stream can be unbuffered (buffering is automatically provided\n+\t * internally to smooth out short reads) and unpositionable (the stream is\n+\t * read from only once, sequentially).\n+\t * <p>\n+\t * When the FetchConnection or the this instance is closed the supplied\n+\t * input stream is also automatically closed. This frees callers from\n+\t * needing to keep track of the supplied stream.\n+\t * \n+\t * @param db\n+\t *            repository the fetched objects will be loaded into.\n+\t * @param uri\n+\t *            symbolic name of the source of the stream. The URI can\n+\t *            reference a non-existent resource. It is used only for\n+\t *            exception reporting.\n+\t * @param in\n+\t *            the stream to read the bundle from.\n+\t */\n+\tpublic TransportBundleStream(final Repository db, final URIish uri,\n+\t\t\tfinal InputStream in) {\n+\t\tsuper(db, uri);\n+\t\tsrc = in;\n+\t}\n+\n+\t@Override\n+\tpublic FetchConnection openFetch() throws TransportException {\n+\t\tif (src == null)\n+\t\t\tthrow new TransportException(uri, \"Only one fetch supported\");\n+\t\ttry {\n+\t\t\treturn new BundleFetchConnection(src);\n+\t\t} finally {\n+\t\t\tsrc = null;\n+\t\t}\n+\t}\n+\n+\t@Override\n+\tpublic void close() {\n+\t\tif (src != null) {\n+\t\t\ttry {\n+\t\t\t\tsrc.close();\n+\t\t\t} catch (IOException err) {\n+\t\t\t\t// Ignore a close error.\n+\t\t\t} finally {\n+\t\t\t\tsrc = null;\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n-- \n1.6.0.1.319.g9f32b\n"}]}