{"thread":{"id":"14194","subject":"[EGIT PATCH 01/23] Fix: let FetchProcess use fetch() instead of doFetch()","startedAt":"2008-06-27T22:06:24Z","lastAt":"2008-06-28T12:36:21Z","messageCount":26,"participants":["Marek Zawirski","Robin Rosenberg"],"isPatch":true,"patchVersion":1,"patchTotal":23},"messages":[{"id":"81479","messageId":"1214604407-30572-1-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":null,"subject":"[EGIT PATCH 00/23] Push implementation","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:24Z","receivedAt":"2008-06-27T22:06:24Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"Finally, series with push implementation. It has taken a \"while\" to\nsquash all bugs this time and polish the series, uhh.\n\nPart of this series is signifficant refactor of .transport package to\nsupport code reuse between fetch and push implementations + minor\nfixes/improvements.\n\nNeeded push operation elements were created. Implementation provides\nbasis for different push protocols by common push process and its\ndendendencies. Push over git-receive-pack based transports is\nimplemented. \nShawn is now working on support for push over less git-inteligent\nprotocols. I'm moving into GUI stuff.\n\nBeside of JUnit test cases for (IMO) 2 most complex classes that\nrevealed few bugs, I've tested manually pgm.Push extensively. \nEach protocol (SSH, local, git-daemon) was tested at least 1 time.\n\n\nSo now I can say, that this branch is available on \nhttp://repo.or.cz/w/egit/zawir.git?a=shortlog;h=refs/heads/push\nand it was pushed with jgit push! :) Yeah!\nIt is based (together with packwriter stuff, not old packwrite branch)\non egit's master: 4cf736fdf3.\n\nBTW, in case of any comments, requests, please consider that I'm\nsemi-off-line next ~2,5weeks, I can sync my laptop each few days,\nbut certainly not everyday.\n\nPS I saw that Shawn's sftp-push branch also contains new \nTransportException constructors conversion, so we may have to \nresolve this duplication, I added it as last commit.\n\nMarek Zawirski (23):\n  Fix: let FetchProcess use fetch() instead of doFetch()\n  RefUpdate: new possible result Result.IO_FAILURE\n  Refactor TrackingRefUpdate to not hold RefSpec\n  New constructor without RefSpec for TrackingRefUpdate\n  Add RemoteRefUpdate class\n  Refactor: extract superclass OperationResult from FetchResult\n  Add PushResult class\n  Support for fetchThin and pushThin options in Transport\n  Big refactor: *Connection hierarchy\n  Add ignoreMissingUninteresting option to PackWriter\n  Add BasePackPushConnection implementing git-send-pack protocol\n  Fix: let RevWalk reset correctly before isMergedInto()\n  Add PushProcess class implementing git-send-pack logic\n  Clarify Repository#resolve() documentation\n  Add String versions of methods in RefSpec\n  Transport* - general support for push() and implementations\n  Test cases for PushProcess\n  Test cases for RefSpec to RemoteRefUpdate conversions\n  Repository search for command line tools\n  Push command line utility\n  Don't accept RefSpec with null source for fetch\n  Add new handy constructors to TransportException,\n    PackProtocolException\n  Use new TransportException constructors\n\n .../tst/org/spearce/jgit/lib/PackWriterTest.java   |   45 ++-\n .../spearce/jgit/transport/PushProcessTest.java    |  407 ++++++++++++++++++++\n .../org/spearce/jgit/transport/TransportTest.java  |  181 +++++++++\n .../spearce/jgit/errors/PackProtocolException.java |   30 ++\n .../spearce/jgit/errors/TransportException.java    |   31 ++\n .../src/org/spearce/jgit/lib/PackWriter.java       |   37 ++-\n .../src/org/spearce/jgit/lib/RefUpdate.java        |   27 ++-\n .../src/org/spearce/jgit/lib/Repository.java       |    2 +-\n .../src/org/spearce/jgit/pgm/Fetch.java            |   41 +--\n .../src/org/spearce/jgit/pgm/Main.java             |   24 +-\n .../src/org/spearce/jgit/pgm/Push.java             |  235 +++++++++++\n .../src/org/spearce/jgit/pgm/TextBuiltin.java      |   21 +\n .../src/org/spearce/jgit/revwalk/RevWalk.java      |    2 +-\n .../org/spearce/jgit/transport/BaseConnection.java |  103 +++++\n .../jgit/transport/BaseFetchConnection.java        |   86 ++++\n .../spearce/jgit/transport/BasePackConnection.java |  217 +++++++++++\n ...onnection.java => BasePackFetchConnection.java} |  169 +--------\n .../jgit/transport/BasePackPushConnection.java     |  226 +++++++++++\n .../src/org/spearce/jgit/transport/Connection.java |  104 +++++\n .../spearce/jgit/transport/FetchConnection.java    |  127 +-----\n .../org/spearce/jgit/transport/FetchProcess.java   |    8 +-\n .../org/spearce/jgit/transport/FetchResult.java    |   74 +----\n .../spearce/jgit/transport/OperationResult.java    |  119 ++++++\n .../org/spearce/jgit/transport/PackTransport.java  |    3 +-\n .../org/spearce/jgit/transport/PushConnection.java |   56 +++-\n .../org/spearce/jgit/transport/PushProcess.java    |  224 +++++++++++\n .../src/org/spearce/jgit/transport/PushResult.java |   84 ++++\n .../src/org/spearce/jgit/transport/RefSpec.java    |   46 ++-\n .../spearce/jgit/transport/RemoteRefUpdate.java    |  315 +++++++++++++++\n .../spearce/jgit/transport/TrackingRefUpdate.java  |   19 +-\n .../src/org/spearce/jgit/transport/Transport.java  |  252 ++++++++++++-\n .../spearce/jgit/transport/TransportBundle.java    |    8 +-\n .../spearce/jgit/transport/TransportGitAnon.java   |   52 +++-\n .../spearce/jgit/transport/TransportGitSsh.java    |   67 +++-\n .../org/spearce/jgit/transport/TransportLocal.java |  114 ++++--\n .../org/spearce/jgit/transport/TransportSftp.java  |   12 +-\n .../jgit/transport/WalkFetchConnection.java        |    2 +-\n .../org/spearce/jgit/transport/WalkTransport.java  |    7 +\n 38 files changed, 3103 insertions(+), 474 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/transport/PushProcessTest.java\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BaseConnection.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java\n rename org.spearce.jgit/src/org/spearce/jgit/transport/{PackFetchConnection.java => BasePackFetchConnection.java} (75%)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/Connection.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/OperationResult.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/PushResult.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/RemoteRefUpdate.java\n"},{"id":"81478","messageId":"1214604407-30572-2-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-1-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 01/23] Fix: let FetchProcess use fetch() instead of doFetch()","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:25Z","receivedAt":"2008-06-27T22:06:25Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"doFetch() call didn't check whether fetch() was already performed\n(it is intended for internal use), while fetch() does.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../org/spearce/jgit/transport/FetchProcess.java   |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\nindex afaf9e2..e33b35b 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\n@@ -139,7 +139,7 @@ class FetchProcess {\n \t\t\t\tif (!askFor.isEmpty() && (!includedTags || !askForIsComplete())) {\n \t\t\t\t\treopenConnection();\n \t\t\t\t\tif (!askFor.isEmpty())\n-\t\t\t\t\t\tconn.doFetch(monitor, askFor.values());\n+\t\t\t\t\t\tconn.fetch(monitor, askFor.values());\n \t\t\t\t}\n \t\t\t}\n \t\t} finally {\n-- \n1.5.5.3\n"},{"id":"81480","messageId":"1214604407-30572-3-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-2-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 02/23] RefUpdate: new possible result Result.IO_FAILURE","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:26Z","receivedAt":"2008-06-27T22:06:26Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"This result indicates that I/O error (beyond of IOException) occurred\nduring RefUpdate#update().\n\nHitherto behaviour was to just throw IOException and leave result with\nvalue Result.NOT_ATTEMPTED. It was just less informative.\n\nFetch class from pgm package needed new conditions for printing. Other\nclasses were reviewed and should still work just fine.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../src/org/spearce/jgit/lib/RefUpdate.java        |   27 +++++++++++++++++--\n .../src/org/spearce/jgit/pgm/Fetch.java            |    5 +++\n 2 files changed, 29 insertions(+), 3 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java\nindex 48044fb..369cb37 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java\n@@ -105,7 +105,18 @@ public class RefUpdate {\n \t\t * update to take place, so ref still contains the old value. No\n \t\t * previous history was lost.\n \t\t */\n-\t\tREJECTED\n+\t\tREJECTED,\n+\n+\t\t/**\n+\t\t * The ref was probably not updated because of I/O error.\n+\t\t * <p>\n+\t\t * Unexpected I/O error occurred when writing new ref. Such error may\n+\t\t * result in uncertain state, but most probably ref was not updated.\n+\t\t * <p>\n+\t\t * This kind of error doesn't include {@link #LOCK_FAILURE}, which is a\n+\t\t * different case.\n+\t\t */\n+\t\tIO_FAILURE\n \t}\n \n \t/** Repository the ref is stored in. */\n@@ -256,7 +267,12 @@ public class RefUpdate {\n \t */\n \tpublic Result forceUpdate() throws IOException {\n \t\trequireCanDoUpdate();\n-\t\treturn result = forceUpdateImpl();\n+\t\ttry {\n+\t\t\treturn result = forceUpdateImpl();\n+\t\t} catch (IOException x) {\n+\t\t\tresult = Result.IO_FAILURE;\n+\t\t\tthrow x;\n+\t\t}\n \t}\n \n \tprivate Result forceUpdateImpl() throws IOException {\n@@ -310,7 +326,12 @@ public class RefUpdate {\n \t */\n \tpublic Result update(final RevWalk walk) throws IOException {\n \t\trequireCanDoUpdate();\n-\t\treturn result = updateImpl(walk);\n+\t\ttry {\n+\t\t\treturn result = updateImpl(walk);\n+\t\t} catch (IOException x) {\n+\t\t\tresult = Result.IO_FAILURE;\n+\t\t\tthrow x;\n+\t\t}\n \t}\n \n \tprivate Result updateImpl(final RevWalk walk) throws IOException {\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java\nindex 6277970..3a81575 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java\n@@ -109,6 +109,9 @@ class Fetch extends TextBuiltin {\n \t\tif (r == RefUpdate.Result.LOCK_FAILURE)\n \t\t\treturn \"[lock fail]\";\n \n+\t\tif (r == RefUpdate.Result.IO_FAILURE)\n+\t\t\treturn \"[i/o error]\";\n+\n \t\tif (r == RefUpdate.Result.NEW) {\n \t\t\tif (u.getRemoteName().startsWith(REFS_HEADS))\n \t\t\t\treturn \"[new branch]\";\n@@ -143,6 +146,8 @@ class Fetch extends TextBuiltin {\n \tprivate static char shortTypeOf(final RefUpdate.Result r) {\n \t\tif (r == RefUpdate.Result.LOCK_FAILURE)\n \t\t\treturn '!';\n+\t\tif (r == RefUpdate.Result.IO_FAILURE)\n+\t\t\treturn '!';\n \t\tif (r == RefUpdate.Result.NEW)\n \t\t\treturn '*';\n \t\tif (r == RefUpdate.Result.FORCED)\n-- \n1.5.5.3\n"},{"id":"81482","messageId":"1214604407-30572-4-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-3-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 03/23] Refactor TrackingRefUpdate to not hold RefSpec","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:27Z","receivedAt":"2008-06-27T22:06:27Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"Just remoteName is needed, not a whole RefSpec.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../spearce/jgit/transport/TrackingRefUpdate.java  |   10 +++++-----\n 1 files changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java\nindex 56234a1..771e77a 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java\n@@ -49,14 +49,14 @@ import org.spearce.jgit.revwalk.RevWalk;\n \n /** Update of a locally stored tracking branch. */\n public class TrackingRefUpdate {\n-\tprivate final RefSpec spec;\n+\tprivate final String remoteName;\n \n \tprivate final RefUpdate update;\n \n-\tTrackingRefUpdate(final Repository db, final RefSpec s,\n+\tTrackingRefUpdate(final Repository db, final RefSpec spec,\n \t\t\tfinal AnyObjectId nv, final String msg) throws IOException {\n-\t\tspec = s;\n-\t\tupdate = db.updateRef(s.getDestination());\n+\t\tremoteName = spec.getSource();\n+\t\tupdate = db.updateRef(spec.getDestination());\n \t\tupdate.setForceUpdate(spec.isForceUpdate());\n \t\tupdate.setNewObjectId(nv);\n \t\tupdate.setRefLogMessage(msg, true);\n@@ -70,7 +70,7 @@ public class TrackingRefUpdate {\n \t * @return the name used within the remote repository.\n \t */\n \tpublic String getRemoteName() {\n-\t\treturn spec.getSource();\n+\t\treturn remoteName;\n \t}\n \n \t/**\n-- \n1.5.5.3\n"},{"id":"81481","messageId":"1214604407-30572-5-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-4-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 04/23] New constructor without RefSpec for TrackingRefUpdate","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:28Z","receivedAt":"2008-06-27T22:06:28Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"New constructor operates directly on RefSpec components: remote name,\nlocal name, force flag.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../spearce/jgit/transport/TrackingRefUpdate.java  |   13 ++++++++++---\n 1 files changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java\nindex 771e77a..a84b38a 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java\n@@ -55,9 +55,16 @@ public class TrackingRefUpdate {\n \n \tTrackingRefUpdate(final Repository db, final RefSpec spec,\n \t\t\tfinal AnyObjectId nv, final String msg) throws IOException {\n-\t\tremoteName = spec.getSource();\n-\t\tupdate = db.updateRef(spec.getDestination());\n-\t\tupdate.setForceUpdate(spec.isForceUpdate());\n+\t\tthis(db, spec.getDestination(), spec.getSource(), spec.isForceUpdate(),\n+\t\t\t\tnv, msg);\n+\t}\n+\n+\tTrackingRefUpdate(final Repository db, final String localName,\n+\t\t\tfinal String remoteName, final boolean forceUpdate,\n+\t\t\tfinal AnyObjectId nv, final String msg) throws IOException {\n+\t\tthis.remoteName = remoteName;\n+\t\tupdate = db.updateRef(localName);\n+\t\tupdate.setForceUpdate(forceUpdate);\n \t\tupdate.setNewObjectId(nv);\n \t\tupdate.setRefLogMessage(msg, true);\n \t}\n-- \n1.5.5.3\n"},{"id":"81483","messageId":"1214604407-30572-6-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-5-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 05/23] Add RemoteRefUpdate class","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:29Z","receivedAt":"2008-06-27T22:06:29Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"This class holds specification and status of remote ref update during\npush operation.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../spearce/jgit/transport/RemoteRefUpdate.java    |  315 ++++++++++++++++++++\n 1 files changed, 315 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/RemoteRefUpdate.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/RemoteRefUpdate.java b/org.spearce.jgit/src/org/spearce/jgit/transport/RemoteRefUpdate.java\nnew file mode 100644\nindex 0000000..3737c7a\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/RemoteRefUpdate.java\n@@ -0,0 +1,315 @@\n+/*\n+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>\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 remoteName 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+\n+import org.spearce.jgit.lib.ObjectId;\n+import org.spearce.jgit.lib.Repository;\n+import org.spearce.jgit.revwalk.RevWalk;\n+\n+/**\n+ * Represent request and status of a remote ref update. Specification is\n+ * provided by client, while status is handled by {@link PushProcess} class,\n+ * being read-only for client.\n+ * <p>\n+ * Client can create instances of this class directly, basing on user\n+ * specification and advertised refs ({@link Connection} or through\n+ * {@link Transport} helper methods. Apply this specification on remote\n+ * repository using\n+ * {@link Transport#push(org.spearce.jgit.lib.ProgressMonitor, java.util.Collection)}\n+ * method.\n+ * </p>\n+ * \n+ */\n+public class RemoteRefUpdate {\n+\t/**\n+\t * Represent current status of a remote ref update.\n+\t */\n+\tpublic static enum Status {\n+\t\t/**\n+\t\t * Push process hasn't yet attempted to update this ref. This is the\n+\t\t * default status, prior to push process execution.\n+\t\t */\n+\t\tNOT_ATTEMPTED,\n+\n+\t\t/**\n+\t\t * Remote ref was up to date, there was no need to update anything.\n+\t\t */\n+\t\tUP_TO_DATE,\n+\n+\t\t/**\n+\t\t * Remote ref update was rejected, as it would cause non fast-forward\n+\t\t * update.\n+\t\t */\n+\t\tREJECTED_NONFASTFORWARD,\n+\n+\t\t/**\n+\t\t * Remote ref update was rejected, because remote side doesn't\n+\t\t * support/allow deleting refs.\n+\t\t */\n+\t\tREJECTED_NODELETE,\n+\n+\t\t/**\n+\t\t * Remote ref update was rejected, because old object id on remote\n+\t\t * repository wasn't the same as defined expected old object.\n+\t\t */\n+\t\tREJECTED_REMOTE_CHANGED,\n+\n+\t\t/**\n+\t\t * Remote ref update was rejected for other reason, possibly described\n+\t\t * in {@link RemoteRefUpdate#getMessage()}.\n+\t\t */\n+\t\tREJECTED_OTHER_REASON,\n+\n+\t\t/**\n+\t\t * Remote ref didn't exist. Can occur on delete request of a non\n+\t\t * existing ref.\n+\t\t */\n+\t\tNON_EXISTING,\n+\n+\t\t/**\n+\t\t * Push process is awaiting update report from remote repository. This\n+\t\t * is a temporary state or state after critical error in push process.\n+\t\t */\n+\t\tAWAITING_REPORT,\n+\n+\t\t/**\n+\t\t * Remote ref was successfully updated.\n+\t\t */\n+\t\tOK;\n+\t}\n+\n+\tprivate final ObjectId expectedOldObjectId;\n+\n+\tprivate final ObjectId newObjectId;\n+\n+\tprivate final String remoteName;\n+\n+\tprivate final TrackingRefUpdate trackingRefUpdate;\n+\n+\tprivate String srcRef;\n+\n+\tprivate final boolean forceUpdate;\n+\n+\tprivate Status status;\n+\n+\tprivate boolean fastForward;\n+\n+\tprivate String message;\n+\n+\t/**\n+\t * Construct remote ref update request by providing an update specification.\n+\t * Object is created with default {@link Status#NOT_ATTEMPTED} status and no\n+\t * message.\n+\t * \n+\t * @param db\n+\t *            repository to push from.\n+\t * @param srcRef\n+\t *            source revision - any string resolvable by\n+\t *            {@link Repository#resolve(String)}. This resolves to the new\n+\t *            object that the caller want remote ref to be after update. Use\n+\t *            null or {@link ObjectId#zeroId()} string for delete request.\n+\t * @param remoteName\n+\t *            full name of a remote ref to update, e.g. \"refs/heads/master\"\n+\t *            (no wildcard, no short name).\n+\t * @param forceUpdate\n+\t *            true when caller want remote ref to be updated regardless\n+\t *            whether it is fast-forward update (old object is ancestor of\n+\t *            new object).\n+\t * @param localName\n+\t *            optional full name of a local stored tracking branch, to\n+\t *            update after push, e.g. \"refs/remotes/zawir/dirty\" (no\n+\t *            wildcard, no short name); null if no local tracking branch\n+\t *            should be updated.\n+\t * @param expectedOldObjectId\n+\t *            optional object id that caller is expecting, requiring to be\n+\t *            advertised by remote side before update; update will take\n+\t *            place ONLY if remote side advertise exactly this expected id;\n+\t *            null if caller doesn't care what object id remote side\n+\t *            advertise. Use {@link ObjectId#zeroId()} when expecting no\n+\t *            remote ref with this name.\n+\t * @throws IOException\n+\t *             when I/O error occurred during creating\n+\t *             {@link TrackingRefUpdate} for local tracking branch.\n+\t * @throws IllegalArgumentException\n+\t *             if some required parameter was null or srcRef can't be\n+\t *             resolved to any object.\n+\t */\n+\tpublic RemoteRefUpdate(final Repository db, final String srcRef,\n+\t\t\tfinal String remoteName, final boolean forceUpdate,\n+\t\t\tfinal String localName, final ObjectId expectedOldObjectId)\n+\t\t\tthrows IOException {\n+\t\tif (remoteName == null)\n+\t\t\tthrow new IllegalArgumentException(\"remote name can't be null\");\n+\t\tthis.srcRef = srcRef;\n+\t\tthis.newObjectId = (srcRef == null ? ObjectId.zeroId() : db\n+\t\t\t\t.resolve(srcRef));\n+\t\tif (newObjectId == null)\n+\t\t\tthrow new IllegalArgumentException(\n+\t\t\t\t\t\"source ref doesn't resolve to any object\");\n+\t\tthis.remoteName = remoteName;\n+\t\tthis.forceUpdate = forceUpdate;\n+\t\tif (localName != null && db != null)\n+\t\t\ttrackingRefUpdate = new TrackingRefUpdate(db, localName,\n+\t\t\t\t\tremoteName, forceUpdate, newObjectId, \"push\");\n+\t\telse\n+\t\t\ttrackingRefUpdate = null;\n+\t\tthis.expectedOldObjectId = expectedOldObjectId;\n+\t\tthis.status = Status.NOT_ATTEMPTED;\n+\t}\n+\n+\t/**\n+\t * @return expectedOldObjectId required to be advertised by remote side, as\n+\t *         set in constructor; may be null.\n+\t */\n+\tpublic ObjectId getExpectedOldObjectId() {\n+\t\treturn expectedOldObjectId;\n+\t}\n+\n+\t/**\n+\t * @return true if some object is required to be advertised by remote side,\n+\t *         as set in constructor; false otherwise.\n+\t */\n+\tpublic boolean isExpectingOldObjectId() {\n+\t\treturn expectedOldObjectId != null;\n+\t}\n+\n+\t/**\n+\t * @return newObjectId for remote ref, as set in constructor.\n+\t */\n+\tpublic ObjectId getNewObjectId() {\n+\t\treturn newObjectId;\n+\t}\n+\n+\t/**\n+\t * @return true if this update is deleting update; false otherwise.\n+\t */\n+\tpublic boolean isDelete() {\n+\t\treturn ObjectId.zeroId().equals(newObjectId);\n+\t}\n+\n+\t/**\n+\t * @return name of remote ref to update, as set in constructor.\n+\t */\n+\tpublic String getRemoteName() {\n+\t\treturn remoteName;\n+\t}\n+\n+\t/**\n+\t * @return local tracking branch update if localName was set in constructor.\n+\t */\n+\tpublic TrackingRefUpdate getTrackingRefUpdate() {\n+\t\treturn trackingRefUpdate;\n+\t}\n+\n+\t/**\n+\t * @return source revision as specified by user (in constructor), could be\n+\t *         any string parseable by {@link Repository#resolve(String)}; can\n+\t *         be null if specified that way in constructor - this stands for\n+\t *         delete request.\n+\t */\n+\tpublic String getSrcRef() {\n+\t\treturn srcRef;\n+\t}\n+\n+\t/**\n+\t * @return true if user specified a local tracking branch for remote update;\n+\t *         false otherwise.\n+\t */\n+\tpublic boolean hasTrackingRefUpdate() {\n+\t\treturn trackingRefUpdate != null;\n+\t}\n+\n+\t/**\n+\t * @return true if this update is forced regardless of old remote ref\n+\t *         object; false otherwise.\n+\t */\n+\tpublic boolean isForceUpdate() {\n+\t\treturn forceUpdate;\n+\t}\n+\n+\t/**\n+\t * @return status of remote ref update operation.\n+\t */\n+\tpublic Status getStatus() {\n+\t\treturn status;\n+\t}\n+\n+\t/**\n+\t * Check whether update was fast-forward. Note that this result is\n+\t * meaningful only after successful update (when status is {@link Status#OK}).\n+\t * \n+\t * @return true if update was fast-forward; false otherwise.\n+\t */\n+\tpublic boolean isFastForward() {\n+\t\treturn fastForward;\n+\t}\n+\n+\t/**\n+\t * @return message describing reasons of status when needed/possible; may be\n+\t *         null.\n+\t */\n+\tpublic String getMessage() {\n+\t\treturn message;\n+\t}\n+\n+\tprotected void setStatus(final Status status) {\n+\t\tthis.status = status;\n+\t}\n+\n+\tprotected void setFastForward(boolean fastForward) {\n+\t\tthis.fastForward = fastForward;\n+\t}\n+\n+\tprotected void setMessage(final String message) {\n+\t\tthis.message = message;\n+\t}\n+\n+\t/**\n+\t * Update locally stored tracking branch with the new object.\n+\t * \n+\t * @param walk\n+\t *            walker used for checking update properties.\n+\t * @throws IOException\n+\t *             when I/O error occurred during update\n+\t */\n+\tprotected void updateTrackingRef(final RevWalk walk) throws IOException {\n+\t\ttrackingRefUpdate.update(walk);\n+\t}\n+}\n-- \n1.5.5.3\n"},{"id":"81487","messageId":"1214604407-30572-7-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-6-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 06/23] Refactor: extract superclass OperationResult from FetchResult","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:30Z","receivedAt":"2008-06-27T22:06:30Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"New superclass holds information about advertised refs and updated\ntracking refs, which is all common to fetch and push operations.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../org/spearce/jgit/transport/FetchResult.java    |   74 +------------\n .../spearce/jgit/transport/OperationResult.java    |  119 ++++++++++++++++++++\n 2 files changed, 120 insertions(+), 73 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/OperationResult.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchResult.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchResult.java\nindex bd94b5f..cc8557f 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchResult.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchResult.java\n@@ -40,94 +40,22 @@ package org.spearce.jgit.transport;\n \n import java.util.ArrayList;\n import java.util.Collection;\n-import java.util.Collections;\n import java.util.List;\n-import java.util.Map;\n-import java.util.SortedMap;\n-import java.util.TreeMap;\n-\n-import org.spearce.jgit.lib.Ref;\n \n /**\n  * Final status after a successful fetch from a remote repository.\n  * \n  * @see Transport#fetch(org.spearce.jgit.lib.ProgressMonitor, Collection)\n  */\n-public class FetchResult {\n-\tprivate final SortedMap<String, TrackingRefUpdate> updates;\n-\n+public class FetchResult extends OperationResult {\n \tprivate final List<FetchHeadRecord> forMerge;\n \n-\tprivate Map<String, Ref> advertisedRefs;\n-\n \tFetchResult() {\n-\t\tupdates = new TreeMap<String, TrackingRefUpdate>();\n \t\tforMerge = new ArrayList<FetchHeadRecord>();\n-\t\tadvertisedRefs = Collections.<String, Ref> emptyMap();\n-\t}\n-\n-\tvoid add(final TrackingRefUpdate u) {\n-\t\tupdates.put(u.getLocalName(), u);\n \t}\n \n \tvoid add(final FetchHeadRecord r) {\n \t\tif (!r.notForMerge)\n \t\t\tforMerge.add(r);\n \t}\n-\n-\tvoid setAdvertisedRefs(final Map<String, Ref> ar) {\n-\t\tadvertisedRefs = ar;\n-\t}\n-\n-\t/**\n-\t * Get the complete list of refs advertised by the remote.\n-\t * <p>\n-\t * The returned refs may appear in any order. If the caller needs these to\n-\t * be sorted, they should be copied into a new array or List and then sorted\n-\t * by the caller as necessary.\n-\t * \n-\t * @return available/advertised refs. Never null. Not modifiable. The\n-\t *         collection can be empty if the remote side has no refs (it is an\n-\t *         empty/newly created repository).\n-\t */\n-\tpublic Collection<Ref> getAdvertisedRefs() {\n-\t\treturn advertisedRefs.values();\n-\t}\n-\n-\t/**\n-\t * Get a single advertised ref by name.\n-\t * <p>\n-\t * The name supplied should be valid ref name. To get a peeled value for a\n-\t * ref (aka <code>refs/tags/v1.0^{}</code>) use the base name (without\n-\t * the <code>^{}</code> suffix) and look at the peeled object id.\n-\t * \n-\t * @param name\n-\t *            name of the ref to obtain.\n-\t * @return the requested ref; null if the remote did not advertise this ref.\n-\t */\n-\tpublic final Ref getAdvertisedRef(final String name) {\n-\t\treturn advertisedRefs.get(name);\n-\t}\n-\n-\t/**\n-\t * Get the status of all local tracking refs that were updated.\n-\t * \n-\t * @return unmodifiable collection of local updates. Never null. Empty if\n-\t *         there were no local tracking refs updated.\n-\t */\n-\tpublic Collection<TrackingRefUpdate> getTrackingRefUpdates() {\n-\t\treturn Collections.unmodifiableCollection(updates.values());\n-\t}\n-\n-\t/**\n-\t * Get the status for a specific local tracking ref update.\n-\t * \n-\t * @param localName\n-\t *            name of the local ref (e.g. \"refs/remotes/origin/master\").\n-\t * @return status of the local ref; null if this local ref was not touched\n-\t *         during this fetch.\n-\t */\n-\tpublic TrackingRefUpdate getTrackingRefUpdate(final String localName) {\n-\t\treturn updates.get(localName);\n-\t}\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/OperationResult.java b/org.spearce.jgit/src/org/spearce/jgit/transport/OperationResult.java\nnew file mode 100644\nindex 0000000..9b411e1\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/OperationResult.java\n@@ -0,0 +1,119 @@\n+/*\n+ * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>\n+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>\n+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>\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.util.Collection;\n+import java.util.Collections;\n+import java.util.Map;\n+import java.util.SortedMap;\n+import java.util.TreeMap;\n+\n+import org.spearce.jgit.lib.Ref;\n+\n+/**\n+ * Class holding result of operation on remote repository. This includes refs\n+ * advertised by remote repo and local tracking refs updates.\n+ */\n+public abstract class OperationResult {\n+\n+\tprotected Map<String, Ref> advertisedRefs = Collections.emptyMap();\n+\n+\tprotected final SortedMap<String, TrackingRefUpdate> updates = new TreeMap<String, TrackingRefUpdate>();\n+\n+\t/**\n+\t * Get the complete list of refs advertised by the remote.\n+\t * <p>\n+\t * The returned refs may appear in any order. If the caller needs these to\n+\t * be sorted, they should be copied into a new array or List and then sorted\n+\t * by the caller as necessary.\n+\t * \n+\t * @return available/advertised refs. Never null. Not modifiable. The\n+\t *         collection can be empty if the remote side has no refs (it is an\n+\t *         empty/newly created repository).\n+\t */\n+\tpublic Collection<Ref> getAdvertisedRefs() {\n+\t\treturn Collections.unmodifiableCollection(advertisedRefs.values());\n+\t}\n+\n+\t/**\n+\t * Get a single advertised ref by name.\n+\t * <p>\n+\t * The name supplied should be valid ref name. To get a peeled value for a\n+\t * ref (aka <code>refs/tags/v1.0^{}</code>) use the base name (without\n+\t * the <code>^{}</code> suffix) and look at the peeled object id.\n+\t * \n+\t * @param name\n+\t *            name of the ref to obtain.\n+\t * @return the requested ref; null if the remote did not advertise this ref.\n+\t */\n+\tpublic final Ref getAdvertisedRef(final String name) {\n+\t\treturn advertisedRefs.get(name);\n+\t}\n+\n+\t/**\n+\t * Get the status of all local tracking refs that were updated.\n+\t * \n+\t * @return unmodifiable collection of local updates. Never null. Empty if\n+\t *         there were no local tracking refs updated.\n+\t */\n+\tpublic Collection<TrackingRefUpdate> getTrackingRefUpdates() {\n+\t\treturn Collections.unmodifiableCollection(updates.values());\n+\t}\n+\n+\t/**\n+\t * Get the status for a specific local tracking ref update.\n+\t * \n+\t * @param localName\n+\t *            name of the local ref (e.g. \"refs/remotes/origin/master\").\n+\t * @return status of the local ref; null if this local ref was not touched\n+\t *         during this operation.\n+\t */\n+\tpublic TrackingRefUpdate getTrackingRefUpdate(final String localName) {\n+\t\treturn updates.get(localName);\n+\t}\n+\n+\tprotected void setAdvertisedRefs(final Map<String, Ref> ar) {\n+\t\tadvertisedRefs = ar;\n+\t}\n+\n+\tprotected void add(final TrackingRefUpdate u) {\n+\t\tupdates.put(u.getLocalName(), u);\n+\t}\n+}\n\\ No newline at end of file\n-- \n1.5.5.3\n"},{"id":"81485","messageId":"1214604407-30572-8-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-7-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 07/23] Add PushResult class","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:31Z","receivedAt":"2008-06-27T22:06:31Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"Class represents result of push operation. In addition to the data\nprovided by OperationResult it also holds information about remote\nrefs updates.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../src/org/spearce/jgit/transport/PushResult.java |   84 ++++++++++++++++++++\n 1 files changed, 84 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/PushResult.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PushResult.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PushResult.java\nnew file mode 100644\nindex 0000000..11e5928\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PushResult.java\n@@ -0,0 +1,84 @@\n+/*\n+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>\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.util.Collection;\n+import java.util.Collections;\n+import java.util.Map;\n+\n+/**\n+ * Result of push operation to the remote repository. Holding information of\n+ * {@link OperationResult} and remote refs updates status.\n+ * \n+ * @see Transport#push(org.spearce.jgit.lib.ProgressMonitor, Collection)\n+ */\n+public class PushResult extends OperationResult {\n+\tprivate Map<String, RemoteRefUpdate> remoteUpdates = Collections.emptyMap();\n+\n+\t/**\n+\t * Get status of remote refs updates. Together with\n+\t * {@link #getAdvertisedRefs()} it provides full description/status of each\n+\t * ref update.\n+\t * <p>\n+\t * Returned collection is not sorted in any order.\n+\t * </p>\n+\t * \n+\t * @return collection of remote refs updates\n+\t */\n+\tpublic Collection<RemoteRefUpdate> getRemoteUpdates() {\n+\t\treturn Collections.unmodifiableCollection(remoteUpdates.values());\n+\t}\n+\n+\t/**\n+\t * Get status of specific remote ref update by remote ref name. Together\n+\t * with {@link #getAdvertisedRef(String)} it provide full description/status\n+\t * of this ref update.\n+\t * \n+\t * @param refName\n+\t *            remote ref name\n+\t * @return status of remote ref update\n+\t */\n+\tpublic RemoteRefUpdate getRemoteUpdate(final String refName) {\n+\t\treturn remoteUpdates.get(refName);\n+\t}\n+\n+\tprotected void setRemoteUpdates(\n+\t\t\tfinal Map<String, RemoteRefUpdate> remoteUpdates) {\n+\t\tthis.remoteUpdates = remoteUpdates;\n+\t}\n+}\n-- \n1.5.5.3\n"},{"id":"81484","messageId":"1214604407-30572-9-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-8-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 08/23] Support for fetchThin and pushThin options in Transport","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:32Z","receivedAt":"2008-06-27T22:06:32Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"This option determines whether we should use thin pack when possible\nduring fetching from or pushing to a remote repo.\n\nFor fetching the default is to produce a thin pack when remote side\nsupports it, while for pushing the default setting is to not produce a\nthin pack.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../jgit/transport/PackFetchConnection.java        |    4 +-\n .../src/org/spearce/jgit/transport/Transport.java  |   63 ++++++++++++++++++++\n 2 files changed, 66 insertions(+), 1 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java\nindex 5f15a8d..6209030 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java\n@@ -150,6 +150,7 @@ abstract class PackFetchConnection extends FetchConnection {\n \t\tlocal = packTransport.local;\n \t\turi = packTransport.uri;\n \t\tincludeTags = packTransport.getTagOpt() != TagOpt.NO_TAGS;\n+\t\tthinPack = packTransport.isFetchThin();\n \n \t\twalk = new RevWalk(local);\n \t\treachableCommits = new RevCommitList<RevCommit>();\n@@ -363,7 +364,8 @@ abstract class PackFetchConnection extends FetchConnection {\n \t\t\tincludeTags = wantCapability(line, OPTION_INCLUDE_TAG);\n \t\twantCapability(line, OPTION_OFS_DELTA);\n \t\tmultiAck = wantCapability(line, OPTION_MULTI_ACK);\n-\t\tthinPack = wantCapability(line, OPTION_THIN_PACK);\n+\t\tif (thinPack)\n+\t\t\tthinPack = wantCapability(line, OPTION_THIN_PACK);\n \t\tif (wantCapability(line, OPTION_SIDE_BAND_64K))\n \t\t\tsideband = true;\n \t\telse if (wantCapability(line, OPTION_SIDE_BAND))\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 6cc38ec..c4b71eb 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@@ -142,6 +142,16 @@ public abstract class Transport {\n \t\tthrow new NotSupportedException(\"URI not supported: \" + remote);\n \t}\n \n+\t/**\n+\t * Default setting for {@link #fetchThin} option.\n+\t */\n+\tpublic static final boolean DEFAULT_FETCH_THIN = true;\n+\n+\t/**\n+\t * Default setting for {@link #pushThin} option.\n+\t */\n+\tpublic static final boolean DEFAULT_PUSH_THIN = false;\n+\n \t/** The repository this transport fetches into, or pushes out of. */\n \tprotected final Repository local;\n \n@@ -165,6 +175,12 @@ public abstract class Transport {\n \t */\n \tprivate TagOpt tagopt = TagOpt.NO_TAGS;\n \n+\t/** Should fetch request thin-pack if remote repository can produce it. */\n+\tprivate boolean fetchThin = DEFAULT_FETCH_THIN;\n+\n+\t/** Should push produce thin-pack when sending objects to remote repository. */\n+\tprivate boolean pushThin = DEFAULT_PUSH_THIN;\n+\n \t/**\n \t * Create a new transport instance.\n \t * \n@@ -234,6 +250,53 @@ public abstract class Transport {\n \t}\n \n \t/**\n+\t * Default setting is: {@link #DEFAULT_FETCH_THIN}\n+\t * \n+\t * @return true if fetch should request thin-pack when possible; false\n+\t *         otherwise\n+\t * @see PackTransport\n+\t */\n+\tpublic boolean isFetchThin() {\n+\t\treturn fetchThin;\n+\t}\n+\n+\t/**\n+\t * Set the thin-pack preference for fetch operation. Default setting is:\n+\t * {@link #DEFAULT_FETCH_THIN}\n+\t * \n+\t * @param fetchThin\n+\t *            true when fetch should request thin-pack when possible; false\n+\t *            when it shouldn't\n+\t * @see PackTransport\n+\t */\n+\tpublic void setFetchThin(final boolean fetchThin) {\n+\t\tthis.fetchThin = fetchThin;\n+\t}\n+\n+\t/**\n+\t * Default setting is: {@value #DEFAULT_PUSH_THIN}\n+\t * \n+\t * @return true if push should produce thin-pack in pack transports\n+\t * @see PackTransport\n+\t */\n+\tpublic boolean isPushThin() {\n+\t\treturn pushThin;\n+\t}\n+\n+\t/**\n+\t * Set thin-pack preference for push operation. Default setting is:\n+\t * {@value #DEFAULT_PUSH_THIN}\n+\t * \n+\t * @param pushThin\n+\t *            true when push should produce thin-pack in pack transports;\n+\t *            false when it shouldn't\n+\t * @see PackTransport\n+\t */\n+\tpublic void setPushThin(final boolean pushThin) {\n+\t\tthis.pushThin = pushThin;\n+\t}\n+\n+\t/**\n \t * Fetch objects and refs from the remote repository to the local one.\n \t * <p>\n \t * This is a utility function providing standard fetch behavior. Local\n-- \n1.5.5.3\n"},{"id":"81491","messageId":"1214604407-30572-10-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-9-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 09/23] Big refactor: *Connection hierarchy","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:33Z","receivedAt":"2008-06-27T22:06:33Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"New interfaces and base classes are introduced to cope with lack of\nmultiple inheritance and allow code reuse between fetch and push\noperations implementations. Some renames (adding Base prefix) are also\nperformed to distinct between interfaces and base implementations.\n\nSome generalizations/cleanings in interfaces and implementations\n(particularly in Base* classes) were introduced. readAdvertisedRefs() in\nBasePackConnection now support both push and fetch advertisements.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../org/spearce/jgit/transport/BaseConnection.java |  103 +++++++++\n .../jgit/transport/BaseFetchConnection.java        |   86 ++++++++\n .../spearce/jgit/transport/BasePackConnection.java |  217 ++++++++++++++++++++\n ...onnection.java => BasePackFetchConnection.java} |  165 ++--------------\n .../src/org/spearce/jgit/transport/Connection.java |  104 ++++++++++\n .../spearce/jgit/transport/FetchConnection.java    |  127 ++----------\n .../org/spearce/jgit/transport/FetchProcess.java   |    2 +-\n .../org/spearce/jgit/transport/PackTransport.java  |    3 +-\n .../org/spearce/jgit/transport/PushConnection.java |   56 +++++-\n .../spearce/jgit/transport/TransportBundle.java    |    2 +-\n .../spearce/jgit/transport/TransportGitAnon.java   |    2 +-\n .../spearce/jgit/transport/TransportGitSsh.java    |    2 +-\n .../org/spearce/jgit/transport/TransportLocal.java |    2 +-\n .../jgit/transport/WalkFetchConnection.java        |    2 +-\n 14 files changed, 602 insertions(+), 271 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BaseConnection.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java\n rename org.spearce.jgit/src/org/spearce/jgit/transport/{PackFetchConnection.java => BasePackFetchConnection.java} (76%)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/Connection.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BaseConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BaseConnection.java\nnew file mode 100644\nindex 0000000..9a6b7df\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BaseConnection.java\n@@ -0,0 +1,103 @@\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, Marek Zawirski <marek.zawirski@gmail.com>\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.util.Collection;\n+import java.util.Collections;\n+import java.util.Map;\n+\n+import org.spearce.jgit.errors.TransportException;\n+import org.spearce.jgit.lib.Ref;\n+\n+/**\n+ * Base helper class for implementing operations connections.\n+ * \n+ * @see BasePackConnection\n+ * @see BaseFetchConnection\n+ */\n+abstract class BaseConnection implements Connection {\n+\n+\tprivate Map<String, Ref> advertisedRefs = Collections.emptyMap();\n+\n+\tprivate boolean startedOperation;\n+\n+\tpublic Map<String, Ref> getRefsMap() {\n+\t\treturn advertisedRefs;\n+\t}\n+\n+\tpublic final Collection<Ref> getRefs() {\n+\t\treturn advertisedRefs.values();\n+\t}\n+\n+\tpublic final Ref getRef(final String name) {\n+\t\treturn advertisedRefs.get(name);\n+\t}\n+\n+\tpublic abstract void close();\n+\n+\t/**\n+\t * Denote the list of refs available on the remote repository.\n+\t * <p>\n+\t * Implementors should invoke this method once they have obtained the refs\n+\t * that are available from the remote repository.\n+\t * \n+\t * @param all\n+\t *            the complete list of refs the remote has to offer. This map\n+\t *            will be wrapped in an unmodifiable way to protect it, but it\n+\t *            does not get copied.\n+\t */\n+\tprotected void available(final Map<String, Ref> all) {\n+\t\tadvertisedRefs = Collections.unmodifiableMap(all);\n+\t}\n+\n+\t/**\n+\t * Helper method for ensuring one-operation per connection. Check whether\n+\t * operation was already marked as started, and mark it as started.\n+\t * \n+\t * @throws TransportException\n+\t *             if operation was already marked as started.\n+\t */\n+\tprotected void markStartedOperation() throws TransportException {\n+\t\tif (startedOperation)\n+\t\t\tthrow new TransportException(\n+\t\t\t\t\t\"Only one operation call per connection is supported.\");\n+\t\tstartedOperation = true;\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java\nnew file mode 100644\nindex 0000000..7fb13bc\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java\n@@ -0,0 +1,86 @@\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.util.Collection;\n+\n+import org.spearce.jgit.errors.TransportException;\n+import org.spearce.jgit.lib.ProgressMonitor;\n+import org.spearce.jgit.lib.Ref;\n+\n+/**\n+ * Base helper class for fetch connection implementations. Provides some common\n+ * typical structures and methods used during fetch connection.\n+ * <p>\n+ * Implementors of fetch over pack-based protocols should consider using\n+ * {@link BasePackFetchConnection} instead.\n+ * </p>\n+ */\n+abstract class BaseFetchConnection extends BaseConnection implements\n+\t\tFetchConnection {\n+\tpublic final void fetch(final ProgressMonitor monitor,\n+\t\t\tfinal Collection<Ref> want) throws TransportException {\n+\t\tmarkStartedOperation();\n+\t\tdoFetch(monitor, want);\n+\t}\n+\n+\t/**\n+\t * Default implementation of {@link FetchConnection#didFetchIncludeTags()} -\n+\t * returning false.\n+\t */\n+\tpublic boolean didFetchIncludeTags() {\n+\t\treturn false;\n+\t}\n+\n+\t/**\n+\t * Implementation of {@link #fetch(ProgressMonitor, Collection)} without\n+\t * checking for multiple fetch.\n+\t * \n+\t * @param monitor\n+\t *            as in {@link #fetch(ProgressMonitor, Collection)}\n+\t * @param want\n+\t *            as in {@link #fetch(ProgressMonitor, Collection)}\n+\t * @throws TransportException\n+\t *             as in {@link #fetch(ProgressMonitor, Collection)}, but\n+\t *             implementation doesn't have to care about multiple\n+\t *             {@link #fetch(ProgressMonitor, Collection)} calls, as it is\n+\t *             checked in this class.\n+\t */\n+\tprotected abstract void doFetch(final ProgressMonitor monitor,\n+\t\t\tfinal Collection<Ref> want) throws TransportException;\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\nnew file mode 100644\nindex 0000000..d119672\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java\n@@ -0,0 +1,217 @@\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, Marek Zawirski <marek.zawirski@gmail.com>\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.BufferedInputStream;\n+import java.io.BufferedOutputStream;\n+import java.io.EOFException;\n+import java.io.IOException;\n+import java.io.InputStream;\n+import java.io.OutputStream;\n+import java.util.HashSet;\n+import java.util.LinkedHashMap;\n+import java.util.Set;\n+\n+import org.spearce.jgit.errors.PackProtocolException;\n+import org.spearce.jgit.errors.TransportException;\n+import org.spearce.jgit.lib.ObjectId;\n+import org.spearce.jgit.lib.Ref;\n+import org.spearce.jgit.lib.Repository;\n+\n+/**\n+ * Base helper class for pack-based operations implementations. Provides partial\n+ * implementation of pack-protocol - refs advertising and capabilities support,\n+ * and some other helper methods.\n+ * \n+ * @see BasePackFetchConnection\n+ * @see BasePackPushConnection\n+ */\n+abstract class BasePackConnection extends BaseConnection {\n+\n+\t/** The repository this transport fetches into, or pushes out of. */\n+\tprotected final Repository local;\n+\n+\t/** Remote repository location. */\n+\tprotected final URIish uri;\n+\n+\t/** Buffered input stream reading from the remote. */\n+\tprotected InputStream in;\n+\n+\t/** Buffered output stream sending to the remote. */\n+\tprotected OutputStream out;\n+\n+\t/** Packet line decoder around {@link #in}. */\n+\tprotected PacketLineIn pckIn;\n+\n+\t/** Packet line encoder around {@link #out}. */\n+\tprotected PacketLineOut pckOut;\n+\n+\t/** Capability tokens advertised by the remote side. */\n+\tprivate final Set<String> remoteCapablities = new HashSet<String>();\n+\n+\tBasePackConnection(final PackTransport packTransport) {\n+\t\tlocal = packTransport.local;\n+\t\turi = packTransport.uri;\n+\t}\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\tout = myOut instanceof BufferedOutputStream ? myOut\n+\t\t\t\t: new BufferedOutputStream(myOut);\n+\n+\t\tpckIn = new PacketLineIn(in);\n+\t\tpckOut = new PacketLineOut(out);\n+\t}\n+\n+\tprotected void readAdvertisedRefs() throws TransportException {\n+\t\ttry {\n+\t\t\treadAdvertisedRefsImpl();\n+\t\t} catch (TransportException err) {\n+\t\t\tclose();\n+\t\t\tthrow err;\n+\t\t} catch (IOException err) {\n+\t\t\tclose();\n+\t\t\tthrow new TransportException(err.getMessage(), err);\n+\t\t} catch (RuntimeException err) {\n+\t\t\tclose();\n+\t\t\tthrow new TransportException(err.getMessage(), err);\n+\t\t}\n+\t}\n+\n+\tprivate void readAdvertisedRefsImpl() throws IOException {\n+\t\tfinal LinkedHashMap<String, Ref> avail = new LinkedHashMap<String, Ref>();\n+\t\tfor (;;) {\n+\t\t\tString line;\n+\n+\t\t\ttry {\n+\t\t\t\tline = pckIn.readString();\n+\t\t\t} catch (EOFException eof) {\n+\t\t\t\tif (avail.isEmpty())\n+\t\t\t\t\tthrow new TransportException(uri + \" not found.\");\n+\t\t\t\tthrow eof;\n+\t\t\t}\n+\n+\t\t\tif (avail.isEmpty()) {\n+\t\t\t\tfinal int nul = line.indexOf('\\0');\n+\t\t\t\tif (nul >= 0) {\n+\t\t\t\t\t// The first line (if any) may contain \"hidden\"\n+\t\t\t\t\t// capability values after a NUL byte.\n+\t\t\t\t\tfor (String c : line.substring(nul + 1).split(\" \"))\n+\t\t\t\t\t\tremoteCapablities.add(c);\n+\t\t\t\t\tline = line.substring(0, nul);\n+\t\t\t\t}\n+\n+\t\t\t\tif (line.equals(\"capabilties^{}\")) {\n+\t\t\t\t\t// special line from git-receive-pack to show\n+\t\t\t\t\t// capabilities when there are no refs to advertise\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t\tif (line.length() == 0)\n+\t\t\t\tbreak;\n+\n+\t\t\tString name = line.substring(41, line.length());\n+\t\t\tfinal ObjectId id = ObjectId.fromString(line.substring(0, 40));\n+\t\t\tif (name.endsWith(\"^{}\")) {\n+\t\t\t\tname = name.substring(0, name.length() - 3);\n+\t\t\t\tfinal Ref prior = avail.get(name);\n+\t\t\t\tif (prior == null)\n+\t\t\t\t\tthrow new PackProtocolException(uri + \": advertisement of \"\n+\t\t\t\t\t\t\t+ name + \"^{} came before \" + name);\n+\n+\t\t\t\tif (prior.getPeeledObjectId() != null)\n+\t\t\t\t\tthrow duplicateAdvertisement(name + \"^{}\");\n+\n+\t\t\t\tavail.put(name, new Ref(name, prior.getObjectId(), id));\n+\t\t\t} else {\n+\t\t\t\tfinal Ref prior = avail.put(name, new Ref(name, id));\n+\t\t\t\tif (prior != null)\n+\t\t\t\t\tthrow duplicateAdvertisement(name);\n+\t\t\t}\n+\t\t}\n+\t\tavailable(avail);\n+\t}\n+\n+\tprotected boolean isCapableOf(final String option) {\n+\t\treturn remoteCapablities.contains(option);\n+\t}\n+\n+\tprotected boolean wantCapability(final StringBuilder b, final String option) {\n+\t\tif (!isCapableOf(option))\n+\t\t\treturn false;\n+\t\tif (b.length() > 0)\n+\t\t\tb.append(' ');\n+\t\tb.append(option);\n+\t\treturn true;\n+\t}\n+\n+\tprivate PackProtocolException duplicateAdvertisement(final String name) {\n+\t\treturn new PackProtocolException(uri + \": duplicate advertisements of \"\n+\t\t\t\t+ name);\n+\t}\n+\n+\t@Override\n+\tpublic void close() {\n+\t\tif (out != null) {\n+\t\t\ttry {\n+\t\t\t\tpckOut.end();\n+\t\t\t\tout.close();\n+\t\t\t} catch (IOException err) {\n+\t\t\t\t// Ignore any close errors.\n+\t\t\t} finally {\n+\t\t\t\tout = null;\n+\t\t\t\tpckOut = null;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (in != null) {\n+\t\t\ttry {\n+\t\t\t\tin.close();\n+\t\t\t} catch (IOException err) {\n+\t\t\t\t// Ignore any close errors.\n+\t\t\t} finally {\n+\t\t\t\tin = null;\n+\t\t\t\tpckIn = null;\n+\t\t\t}\n+\t\t}\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\nsimilarity index 76%\nrename from org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java\nrename to org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\nindex 6209030..04a91bf 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java\n@@ -38,26 +38,15 @@\n \n package org.spearce.jgit.transport;\n \n-import java.io.BufferedInputStream;\n-import java.io.BufferedOutputStream;\n-import java.io.EOFException;\n import java.io.IOException;\n-import java.io.InputStream;\n-import java.io.OutputStream;\n import java.util.Collection;\n import java.util.Date;\n-import java.util.HashSet;\n-import java.util.LinkedHashMap;\n-import java.util.Set;\n \n-import org.spearce.jgit.errors.PackProtocolException;\n import org.spearce.jgit.errors.TransportException;\n import org.spearce.jgit.lib.AnyObjectId;\n import org.spearce.jgit.lib.MutableObjectId;\n-import org.spearce.jgit.lib.ObjectId;\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.RevCommitList;\n import org.spearce.jgit.revwalk.RevFlag;\n@@ -78,8 +67,14 @@ import org.spearce.jgit.revwalk.filter.RevFilter;\n  * This connection requires only a bi-directional pipe or socket, and thus is\n  * easily wrapped up into a local process pipe, anonymous TCP socket, or a\n  * command executed through an SSH tunnel.\n+ * <p>\n+ * Concrete implementations should just call\n+ * {@link #init(java.io.InputStream, java.io.OutputStream)} and\n+ * {@link #readAdvertisedRefs()} methods in constructor or before any use. They\n+ * should also handle resources releasing in {@link #close()} method if needed.\n  */\n-abstract class PackFetchConnection extends FetchConnection {\n+abstract class BasePackFetchConnection extends BasePackConnection implements\n+\t\tFetchConnection {\n \t/**\n \t * Maximum number of 'have' lines to send before giving up.\n \t * <p>\n@@ -103,27 +98,6 @@ abstract class PackFetchConnection extends FetchConnection {\n \n \tstatic final String OPTION_SHALLOW = \"shallow\";\n \n-\t/** The repository this transport fetches into, or pushes out of. */\n-\tprotected final Repository local;\n-\n-\t/** Remote repository location. */\n-\tprotected final URIish uri;\n-\n-\t/** Capability tokens advertised by the remote side. */\n-\tprotected final Set<String> remoteCapablities = new HashSet<String>();\n-\n-\t/** Buffered input stream reading from the remote. */\n-\tprotected InputStream in;\n-\n-\t/** Buffered output stream sending to the remote. */\n-\tprotected OutputStream out;\n-\n-\t/** Packet line decoder around {@link #in}. */\n-\tprotected PacketLineIn pckIn;\n-\n-\t/** Packet line encoder around {@link #out}. */\n-\tprotected PacketLineOut pckOut;\n-\n \tprivate final RevWalk walk;\n \n \t/** All commits that are immediately reachable by a local ref. */\n@@ -146,9 +120,8 @@ abstract class PackFetchConnection extends FetchConnection {\n \n \tprivate boolean includeTags;\n \n-\tPackFetchConnection(final PackTransport packTransport) {\n-\t\tlocal = packTransport.local;\n-\t\turi = packTransport.uri;\n+\tBasePackFetchConnection(final PackTransport packTransport) {\n+\t\tsuper(packTransport);\n \t\tincludeTags = packTransport.getTagOpt() != TagOpt.NO_TAGS;\n \t\tthinPack = packTransport.isFetchThin();\n \n@@ -163,91 +136,16 @@ abstract class PackFetchConnection extends FetchConnection {\n \t\twalk.carry(ADVERTISED);\n \t}\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\tout = myOut instanceof BufferedOutputStream ? myOut\n-\t\t\t\t: new BufferedOutputStream(myOut);\n-\n-\t\tpckIn = new PacketLineIn(in);\n-\t\tpckOut = new PacketLineOut(out);\n+\tpublic final void fetch(final ProgressMonitor monitor,\n+\t\t\tfinal Collection<Ref> want) throws TransportException {\n+\t\tmarkStartedOperation();\n+\t\tdoFetch(monitor, want);\n \t}\n \n-\t@Override\n \tpublic boolean didFetchIncludeTags() {\n-\t\treturn includeTags;\n-\t}\n-\n-\tprotected void readAdvertisedRefs() throws TransportException {\n-\t\ttry {\n-\t\t\treadAdvertisedRefsImpl();\n-\t\t} catch (TransportException err) {\n-\t\t\tclose();\n-\t\t\tthrow err;\n-\t\t} catch (IOException err) {\n-\t\t\tclose();\n-\t\t\tthrow new TransportException(err.getMessage(), err);\n-\t\t} catch (RuntimeException err) {\n-\t\t\tclose();\n-\t\t\tthrow new TransportException(err.getMessage(), err);\n-\t\t}\n-\t}\n-\n-\tprivate void readAdvertisedRefsImpl() throws IOException {\n-\t\tfinal LinkedHashMap<String, Ref> avail = new LinkedHashMap<String, Ref>();\n-\t\tfor (;;) {\n-\t\t\tString line;\n-\n-\t\t\ttry {\n-\t\t\t\tline = pckIn.readString();\n-\t\t\t} catch (EOFException eof) {\n-\t\t\t\tif (avail.isEmpty())\n-\t\t\t\t\tthrow new TransportException(uri + \" not found.\");\n-\t\t\t\tthrow eof;\n-\t\t\t}\n-\n-\t\t\tif (avail.isEmpty()) {\n-\t\t\t\t// The first line (if any) may contain \"hidden\"\n-\t\t\t\t// capability values after a NUL byte.\n-\t\t\t\t//\n-\t\t\t\tfinal int nul = line.indexOf('\\0');\n-\t\t\t\tif (nul >= 0) {\n-\t\t\t\t\tfor (String c : line.substring(nul + 1).split(\" \"))\n-\t\t\t\t\t\tremoteCapablities.add(c);\n-\t\t\t\t\tline = line.substring(0, nul);\n-\t\t\t\t}\n-\t\t\t}\n-\n-\t\t\tif (line.length() == 0)\n-\t\t\t\tbreak;\n-\n-\t\t\tString name = line.substring(41, line.length());\n-\t\t\tfinal ObjectId id = ObjectId.fromString(line.substring(0, 40));\n-\t\t\tif (name.endsWith(\"^{}\")) {\n-\t\t\t\tname = name.substring(0, name.length() - 3);\n-\t\t\t\tfinal Ref prior = avail.get(name);\n-\t\t\t\tif (prior == null)\n-\t\t\t\t\tthrow new PackProtocolException(\"advertisement of \" + name\n-\t\t\t\t\t\t\t+ \"^{} came before \" + name);\n-\n-\t\t\t\tif (prior.getPeeledObjectId() != null)\n-\t\t\t\t\tthrow duplicateAdvertisement(name + \"^{}\");\n-\n-\t\t\t\tavail.put(name, new Ref(name, prior.getObjectId(), id));\n-\t\t\t} else {\n-\t\t\t\tfinal Ref prior = avail.put(name, new Ref(name, id));\n-\t\t\t\tif (prior != null)\n-\t\t\t\t\tthrow duplicateAdvertisement(name);\n-\t\t\t}\n-\t\t}\n-\t\tavailable(avail);\n+\t\treturn false;\n \t}\n \n-\tprivate PackProtocolException duplicateAdvertisement(final String name) {\n-\t\treturn new PackProtocolException(\"duplicate advertisements of \" + name);\n-\t}\n-\n-\t@Override\n \tprotected void doFetch(final ProgressMonitor monitor,\n \t\t\tfinal Collection<Ref> want) throws TransportException {\n \t\ttry {\n@@ -373,15 +271,6 @@ abstract class PackFetchConnection extends FetchConnection {\n \t\treturn line.toString();\n \t}\n \n-\tprivate boolean wantCapability(final StringBuilder b, final String option) {\n-\t\tif (!remoteCapablities.contains(option))\n-\t\t\treturn false;\n-\t\tif (b.length() > 0)\n-\t\t\tb.append(' ');\n-\t\tb.append(option);\n-\t\treturn true;\n-\t}\n-\n \tprivate void negotiate(final ProgressMonitor monitor) throws IOException,\n \t\t\tCancelledException {\n \t\tfinal MutableObjectId ackId = new MutableObjectId();\n@@ -568,32 +457,6 @@ abstract class PackFetchConnection extends FetchConnection {\n \t\tip.renameAndOpenPack();\n \t}\n \n-\t@Override\n-\tpublic void close() {\n-\t\tif (out != null) {\n-\t\t\ttry {\n-\t\t\t\tpckOut.end();\n-\t\t\t\tout.close();\n-\t\t\t} catch (IOException err) {\n-\t\t\t\t// Ignore any close errors.\n-\t\t\t} finally {\n-\t\t\t\tout = null;\n-\t\t\t\tpckOut = null;\n-\t\t\t}\n-\t\t}\n-\n-\t\tif (in != null) {\n-\t\t\ttry {\n-\t\t\t\tin.close();\n-\t\t\t} catch (IOException err) {\n-\t\t\t\t// Ignore any close errors.\n-\t\t\t} finally {\n-\t\t\t\tin = null;\n-\t\t\t\tpckIn = null;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n \tprivate static class CancelledException extends Exception {\n \t\tprivate static final long serialVersionUID = 1L;\n \t}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/Connection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/Connection.java\nnew file mode 100644\nindex 0000000..5a91e9b\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/Connection.java\n@@ -0,0 +1,104 @@\n+/*\n+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>\n+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>\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.util.Collection;\n+import java.util.Map;\n+\n+import org.spearce.jgit.lib.Ref;\n+\n+/**\n+ * Represent connection for operation on a remote repository.\n+ * <p>\n+ * Currently all operations on remote repository (fetch and push) provide\n+ * information about remote refs. Every connection is able to be closed and\n+ * should be closed - this is a connection client responsibility.\n+ * \n+ * @see Transport\n+ */\n+public interface Connection {\n+\n+\t/**\n+\t * Get the complete map of refs advertised as available for fetching or\n+\t * pushing.\n+\t * \n+\t * @return available/advertised refs: map of refname to ref. Never null. Not\n+\t *         modifiable. The collection can be empty if the remote side has no\n+\t *         refs (it is an empty/newly created repository).\n+\t */\n+\tpublic Map<String, Ref> getRefsMap();\n+\n+\t/**\n+\t * Get the complete list of refs advertised as available for fetching or\n+\t * pushing.\n+\t * <p>\n+\t * The returned refs may appear in any order. If the caller needs these to\n+\t * be sorted, they should be copied into a new array or List and then sorted\n+\t * by the caller as necessary.\n+\t * \n+\t * @return available/advertised refs. Never null. Not modifiable. The\n+\t *         collection can be empty if the remote side has no refs (it is an\n+\t *         empty/newly created repository).\n+\t */\n+\tpublic Collection<Ref> getRefs();\n+\n+\t/**\n+\t * Get a single advertised ref by name.\n+\t * <p>\n+\t * The name supplied should be valid ref name. To get a peeled value for a\n+\t * ref (aka <code>refs/tags/v1.0^{}</code>) use the base name (without\n+\t * the <code>^{}</code> suffix) and look at the peeled object id.\n+\t * \n+\t * @param name\n+\t *            name of the ref to obtain.\n+\t * @return the requested ref; null if the remote did not advertise this ref.\n+\t */\n+\tpublic Ref getRef(final String name);\n+\n+\t/**\n+\t * Close any resources used by this connection.\n+\t * <p>\n+\t * If the remote repository is contacted by a network socket this method\n+\t * must close that network socket, disconnecting the two peers. If the\n+\t * remote repository is actually local (same system) this method must close\n+\t * any open file handles used to read the \"remote\" repository.\n+\t */\n+\tpublic void close();\n+\n+}\n\\ No newline at end of file\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java\nindex 8e7641c..9d25b0d 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java\n@@ -38,8 +38,6 @@\n package org.spearce.jgit.transport;\n \n import java.util.Collection;\n-import java.util.Collections;\n-import java.util.Map;\n \n import org.spearce.jgit.errors.TransportException;\n import org.spearce.jgit.lib.ProgressMonitor;\n@@ -62,84 +60,13 @@ import org.spearce.jgit.lib.Ref;\n  * \n  * @see Transport\n  */\n-public abstract class FetchConnection {\n-\tprivate Map<String, Ref> cachedRefs = Collections.<String, Ref> emptyMap();\n-\n-\t/** Have we started {@link #fetch(ProgressMonitor, Collection)} yet? */\n-\tprivate boolean startedFetch;\n-\n-\tMap<String, Ref> getCachedRefs() {\n-\t\treturn cachedRefs;\n-\t}\n-\n-\t/**\n-\t * Denote the list of refs available on the remote repository.\n-\t * <p>\n-\t * Implementors should invoke this method once they have obtained the refs\n-\t * that are available from the remote repository.s\n-\t * \n-\t * @param all\n-\t *            the complete list of refs the remote has to offer. This map\n-\t *            will be wrapped in an unmodifiable way to protect it, but it\n-\t *            does not get copied.\n-\t */\n-\tprotected void available(final Map<String, Ref> all) {\n-\t\tcachedRefs = Collections.unmodifiableMap(all);\n-\t}\n-\n-\t/**\n-\t * Get the complete list of refs advertised as available for fetching.\n-\t * <p>\n-\t * The returned refs may appear in any order. If the caller needs these to\n-\t * be sorted, they should be copied into a new array or List and then sorted\n-\t * by the caller as necessary.\n-\t * \n-\t * @return available/advertised refs. Never null. Not modifiable. The\n-\t *         collection can be empty if the remote side has no refs (it is an\n-\t *         empty/newly created repository).\n-\t */\n-\tpublic final Collection<Ref> getRefs() {\n-\t\treturn cachedRefs.values();\n-\t}\n-\n-\t/**\n-\t * Get a single advertised ref by name.\n-\t * <p>\n-\t * The name supplied should be valid ref name. To get a peeled value for a\n-\t * ref (aka <code>refs/tags/v1.0^{}</code>) use the base name (without\n-\t * the <code>^{}</code> suffix) and look at the peeled object id.\n-\t * \n-\t * @param name\n-\t *            name of the ref to obtain.\n-\t * @return the requested ref; null if the remote did not advertise this ref.\n-\t */\n-\tpublic final Ref getRef(final String name) {\n-\t\treturn cachedRefs.get(name);\n-\t}\n-\n+public interface FetchConnection extends Connection {\n \t/**\n \t * Fetch objects we don't have but that are reachable from advertised refs.\n-\t * \n-\t * @param monitor\n-\t *            progress monitor to update the end-user about the amount of\n-\t *            work completed, or to indicate cancellation.\n-\t * @param want\n-\t *            one or more refs advertised by this connection that the caller\n-\t *            wants to store locally.\n-\t * @throws TransportException\n-\t *             objects could not be copied due to a network failure,\n-\t *             protocol error, or error on remote side.\n-\t */\n-\tpublic final void fetch(final ProgressMonitor monitor,\n-\t\t\tfinal Collection<Ref> want) throws TransportException {\n-\t\tif (startedFetch)\n-\t\t\tthrow new TransportException(\"Only one fetch call supported.\");\n-\t\tstartedFetch = true;\n-\t\tdoFetch(monitor, want);\n-\t}\n-\n-\t/**\n-\t * Fetch objects this repository does not yet contain.\n+\t * <p>\n+\t * Only one call per connection is allowed. Subsequent calls will result in\n+\t * {@link TransportException}.\n+\t * </p>\n \t * <p>\n \t * Implementations are free to use network connections as necessary to\n \t * efficiently (for both client and server) transfer objects from the remote\n@@ -147,22 +74,24 @@ public abstract class FetchConnection {\n \t * avoid replacing/overwriting/duplicating an object already available in\n \t * the local destination repository. Locally available objects and packs\n \t * should always be preferred over remotely available objects and packs.\n+\t * {@link Transport#isFetchThin()} should be honored if applicable.\n+\t * </p>\n \t * \n \t * @param monitor\n-\t *            progress feedback to inform the end-user about the status of\n-\t *            the object transfer. Implementors should poll the monitor at\n-\t *            regular intervals to look for cancellation requests from the\n-\t *            user.\n+\t *            progress monitor to inform the end-user about the amount of\n+\t *            work completed, or to indicate cancellation. Implementations\n+\t *            should poll the monitor at regular intervals to look for\n+\t *            cancellation requests from the user.\n \t * @param want\n-\t *            one or more refs that were previously passed to\n-\t *            {@link #available(Map)} by the implementation. These refs\n-\t *            indicate the objects the caller wants copied.\n+\t *            one or more refs advertised by this connection that the caller\n+\t *            wants to store locally.\n \t * @throws TransportException\n \t *             objects could not be copied due to a network failure,\n-\t *             protocol error, or error on remote side.\n+\t *             protocol error, or error on remote side, or connection was\n+\t *             already used for fetch.\n \t */\n-\tprotected abstract void doFetch(ProgressMonitor monitor,\n-\t\t\tCollection<Ref> want) throws TransportException;\n+\tpublic void fetch(final ProgressMonitor monitor, final Collection<Ref> want)\n+\t\t\tthrows TransportException;\n \n \t/**\n \t * Did the last {@link #fetch(ProgressMonitor, Collection)} get tags?\n@@ -170,9 +99,9 @@ public abstract class FetchConnection {\n \t * Some Git aware transports are able to implicitly grab an annotated tag if\n \t * {@link TagOpt#AUTO_FOLLOW} or {@link TagOpt#FETCH_TAGS} was selected and\n \t * the object the tag peels to (references) was transferred as part of the\n-\t * last {@link #doFetch(ProgressMonitor, Collection)} call. If it is\n-\t * possible for such tags to have been included in the transfer this method\n-\t * returns true, allowing the caller to attempt tag discovery.\n+\t * last {@link #fetch(ProgressMonitor, Collection)} call. If it is possible\n+\t * for such tags to have been included in the transfer this method returns\n+\t * true, allowing the caller to attempt tag discovery.\n \t * <p>\n \t * By returning only true/false (and not the actual list of tags obtained)\n \t * the transport itself does not need to be aware of whether or not tags\n@@ -181,17 +110,5 @@ public abstract class FetchConnection {\n \t * @return true if the last fetch call implicitly included tag objects;\n \t *         false if tags were not implicitly obtained.\n \t */\n-\tpublic boolean didFetchIncludeTags() {\n-\t\treturn false;\n-\t}\n-\n-\t/**\n-\t * Close any resources used by this connection.\n-\t * <p>\n-\t * If the remote repository is contacted by a network socket this method\n-\t * must close that network socket, disconnecting the two peers. If the\n-\t * remote repository is actually local (same system) this method must close\n-\t * any open file handles used to read the \"remote\" repository.\n-\t */\n-\tpublic abstract void close();\n-}\n+\tpublic boolean didFetchIncludeTags();\n+}\n\\ No newline at end of file\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\nindex e33b35b..c765c12 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\n@@ -97,7 +97,7 @@ class FetchProcess {\n \n \t\tconn = transport.openFetch();\n \t\ttry {\n-\t\t\tresult.setAdvertisedRefs(conn.getCachedRefs());\n+\t\t\tresult.setAdvertisedRefs(conn.getRefsMap());\n \t\t\tfinal Set<Ref> matched = new HashSet<Ref>();\n \t\t\tfor (final RefSpec spec : toFetch) {\n \t\t\t\tif (spec.isWildcard())\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PackTransport.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PackTransport.java\nindex 177e065..50708d3 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/PackTransport.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PackTransport.java\n@@ -46,7 +46,8 @@ import org.spearce.jgit.lib.Repository;\n  * forth by creating pack files on the source side and indexing them on the\n  * receiving side.\n  * \n- * @see PackFetchConnection\n+ * @see BasePackFetchConnection\n+ * @see BasePackPushConnection\n  */\n abstract class PackTransport extends Transport {\n \tPackTransport(final Repository local, final URIish u) {\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PushConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PushConnection.java\nindex 316bb95..835b15c 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/PushConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PushConnection.java\n@@ -1,6 +1,7 @@\n /*\n  * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>\n- *\n+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>\n+ * \n  * All rights reserved.\n  *\n  * Redistribution and use in source and binary forms, with or\n@@ -37,6 +38,12 @@\n \n package org.spearce.jgit.transport;\n \n+import java.util.Map;\n+\n+import org.spearce.jgit.errors.TransportException;\n+import org.spearce.jgit.lib.ProgressMonitor;\n+import org.spearce.jgit.transport.RemoteRefUpdate.Status;\n+\n /**\n  * Lists known refs from the remote and sends objects to the remote.\n  * <p>\n@@ -55,14 +62,47 @@ package org.spearce.jgit.transport;\n  * \n  * @see Transport\n  */\n-public abstract class PushConnection {\n+public interface PushConnection extends Connection {\n+\n \t/**\n-\t * Close any resources used by this connection.\n+\t * Pushes to the remote repository basing on provided specification. This\n+\t * possibly result in update/creation/deletion of refs on remote repository\n+\t * and sending objects that remote repository need to have a consistent\n+\t * objects graph from new refs.\n+\t * <p>\n+\t * <p>\n+\t * Only one call per connection is allowed. Subsequent calls will result in\n+\t * {@link TransportException}.\n+\t * </p>\n \t * <p>\n-\t * If the remote repository is contacted by a network socket this method\n-\t * must close that network socket, disconnecting the two peers. If the\n-\t * remote repository is actually local (same system) this method must close\n-\t * any open file handles used to read the \"remote\" repository.\n+\t * Implementation may use local repository to send a minimum set of objects\n+\t * needed by remote repository in efficient way.\n+\t * {@link Transport#isPushThin()} should be honored if applicable.\n+\t * refUpdates should be filled with information about status of each update.\n+\t * </p>\n+\t * \n+\t * @param monitor\n+\t *            progress monitor to update the end-user about the amount of\n+\t *            work completed, or to indicate cancellation. Implementors\n+\t *            should poll the monitor at regular intervals to look for\n+\t *            cancellation requests from the user.\n+\t * @param refUpdates\n+\t *            map of remote refnames to remote refs update\n+\t *            specifications/statuses. Can't be empty. This indicate what\n+\t *            refs caller want to update on remote side. Only refs updates\n+\t *            with {@link Status#NOT_ATTEMPTED} should passed.\n+\t *            Implementation must ensure that and appropriate status with\n+\t *            optional message should be set during call. No refUpdate with\n+\t *            {@link Status#AWAITING_REPORT} or {@link Status#NOT_ATTEMPTED}\n+\t *            can be leaved by implementation after return from this call.\n+\t * @throws TransportException\n+\t *             objects could not be copied due to a network failure,\n+\t *             critical protocol error, or error on remote side, or\n+\t *             connection was already used for push - new connection must be\n+\t *             created. Non-critical errors concerning only isolated refs\n+\t *             should be placed in refUpdates.\n \t */\n-\tpublic abstract void close();\n+\tpublic void push(final ProgressMonitor monitor,\n+\t\t\tfinal Map<String, RemoteRefUpdate> refUpdates)\n+\t\t\tthrows TransportException;\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 2c173fd..48120a8 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@@ -95,7 +95,7 @@ class TransportBundle extends PackTransport {\n \t\treturn new BundleFetchConnection();\n \t}\n \n-\tclass BundleFetchConnection extends FetchConnection {\n+\tclass BundleFetchConnection extends BaseFetchConnection {\n \t\tFileInputStream in;\n \n \t\tRewindBufferedInputStream bin;\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java\nindex e37757a..a7a419e 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java\n@@ -99,7 +99,7 @@ class TransportGitAnon extends PackTransport {\n \t\tpckOut.flush();\n \t}\n \n-\tclass TcpFetchConnection extends PackFetchConnection {\n+\tclass TcpFetchConnection extends BasePackFetchConnection {\n \t\tprivate Socket sock;\n \n \t\tTcpFetchConnection() throws TransportException {\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java\nindex 8944df7..f6e456a 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java\n@@ -188,7 +188,7 @@ class TransportGitSsh extends PackTransport {\n \t\t}\n \t}\n \n-\tclass SshFetchConnection extends PackFetchConnection {\n+\tclass SshFetchConnection extends BasePackFetchConnection {\n \t\tprivate Session session;\n \n \t\tprivate ChannelExec channel;\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\nindex cde648d..e109cf4 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\n@@ -83,7 +83,7 @@ class TransportLocal extends PackTransport {\n \t\treturn new LocalFetchConnection();\n \t}\n \n-\tclass LocalFetchConnection extends PackFetchConnection {\n+\tclass LocalFetchConnection extends BasePackFetchConnection {\n \t\tprivate Process uploadPack;\n \n \t\tLocalFetchConnection() throws TransportException {\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java\nindex 45c2ded..78116b2 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java\n@@ -95,7 +95,7 @@ import org.spearce.jgit.treewalk.TreeWalk;\n  * \n  * @see WalkRemoteObjectDatabase\n  */\n-class WalkFetchConnection extends FetchConnection {\n+class WalkFetchConnection extends BaseFetchConnection {\n \t/** The repository this transport fetches into, or pushes out of. */\n \tprivate final Repository local;\n \n-- \n1.5.5.3\n"},{"id":"81486","messageId":"1214604407-30572-11-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-10-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 10/23] Add ignoreMissingUninteresting option to PackWriter","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:34Z","receivedAt":"2008-06-27T22:06:34Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"This option is useful when caller cares only about locally existing\nuninteresting objects.\n\nTest cases created.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../tst/org/spearce/jgit/lib/PackWriterTest.java   |   45 +++++++++++++++++---\n .../src/org/spearce/jgit/lib/PackWriter.java       |   37 +++++++++++-----\n 2 files changed, 65 insertions(+), 17 deletions(-)\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/PackWriterTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/PackWriterTest.java\nindex 9572342..f94eb72 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/PackWriterTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/PackWriterTest.java\n@@ -120,7 +120,7 @@ public class PackWriterTest extends RepositoryTestCase {\n \t * @throws IOException\n \t */\n \tpublic void testWriteEmptyPack1() throws IOException {\n-\t\tcreateVerifyOpenPack(EMPTY_LIST_OBJECT, EMPTY_LIST_OBJECT, false);\n+\t\tcreateVerifyOpenPack(EMPTY_LIST_OBJECT, EMPTY_LIST_OBJECT, false, false);\n \n \t\tassertEquals(0, writer.getObjectsNumber());\n \t\tassertEquals(0, pack.getObjectCount());\n@@ -142,6 +142,37 @@ public class PackWriterTest extends RepositoryTestCase {\n \t}\n \n \t/**\n+\t * Try to pass non-existing object as uninteresting, with non-ignoring\n+\t * setting.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testNotIgnoreNonExistingObjects() throws IOException {\n+\t\tfinal ObjectId nonExisting = ObjectId\n+\t\t\t\t.fromString(\"0000000000000000000000000000000000000001\");\n+\t\ttry {\n+\t\t\tcreateVerifyOpenPack(EMPTY_LIST_OBJECT, Collections.nCopies(1,\n+\t\t\t\t\tnonExisting), false, false);\n+\t\t\tfail(\"Should have thrown MissingObjectException\");\n+\t\t} catch (MissingObjectException x) {\n+\t\t\t// expected\n+\t\t}\n+\t}\n+\n+\t/**\n+\t * Try to pass non-existing object as uninteresting, with ignoring setting.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testIgnoreNonExistingObjects() throws IOException {\n+\t\tfinal ObjectId nonExisting = ObjectId\n+\t\t\t\t.fromString(\"0000000000000000000000000000000000000001\");\n+\t\tcreateVerifyOpenPack(EMPTY_LIST_OBJECT, Collections.nCopies(1,\n+\t\t\t\tnonExisting), false, true);\n+\t\t// shouldn't throw anything\n+\t}\n+\n+\t/**\n \t * Create pack basing on only interesting objects, then precisely verify\n \t * content. No delta reuse here.\n \t * \n@@ -326,7 +357,7 @@ public class PackWriterTest extends RepositoryTestCase {\n \t\tfinal LinkedList<ObjectId> interestings = new LinkedList<ObjectId>();\n \t\tinterestings.add(ObjectId\n \t\t\t\t.fromString(\"82c6b885ff600be425b4ea96dee75dca255b69e7\"));\n-\t\tcreateVerifyOpenPack(interestings, EMPTY_LIST_OBJECT, false);\n+\t\tcreateVerifyOpenPack(interestings, EMPTY_LIST_OBJECT, false, false);\n \n \t\tfinal ObjectId expectedOrder[] = new ObjectId[] {\n \t\t\t\tObjectId.fromString(\"82c6b885ff600be425b4ea96dee75dca255b69e7\"),\n@@ -352,7 +383,7 @@ public class PackWriterTest extends RepositoryTestCase {\n \t\tfinal LinkedList<ObjectId> uninterestings = new LinkedList<ObjectId>();\n \t\tuninterestings.add(ObjectId\n \t\t\t\t.fromString(\"540a36d136cf413e4b064c2b0e0a4db60f77feab\"));\n-\t\tcreateVerifyOpenPack(interestings, uninterestings, false);\n+\t\tcreateVerifyOpenPack(interestings, uninterestings, false, false);\n \n \t\tfinal ObjectId expectedOrder[] = new ObjectId[] {\n \t\t\t\tObjectId.fromString(\"82c6b885ff600be425b4ea96dee75dca255b69e7\"),\n@@ -380,7 +411,7 @@ public class PackWriterTest extends RepositoryTestCase {\n \t\tfinal LinkedList<ObjectId> uninterestings = new LinkedList<ObjectId>();\n \t\tuninterestings.add(ObjectId\n \t\t\t\t.fromString(\"c59759f143fb1fe21c197981df75a7ee00290799\"));\n-\t\tcreateVerifyOpenPack(interestings, uninterestings, thin);\n+\t\tcreateVerifyOpenPack(interestings, uninterestings, thin, false);\n \n \t\tfinal ObjectId writtenObjects[] = new ObjectId[] {\n \t\t\t\tObjectId.fromString(\"82c6b885ff600be425b4ea96dee75dca255b69e7\"),\n@@ -404,9 +435,11 @@ public class PackWriterTest extends RepositoryTestCase {\n \t}\n \n \tprivate void createVerifyOpenPack(final Collection<ObjectId> interestings,\n-\t\t\tfinal Collection<ObjectId> uninterestings, final boolean thin)\n+\t\t\tfinal Collection<ObjectId> uninterestings, final boolean thin,\n+\t\t\tfinal boolean ignoreMissingUninteresting)\n \t\t\tthrows MissingObjectException, IOException {\n-\t\twriter.writePack(interestings, uninterestings, thin);\n+\t\twriter.writePack(interestings, uninterestings, thin,\n+\t\t\t\tignoreMissingUninteresting);\n \t\tverifyOpenPack(thin);\n \t}\n \ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java b/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java\nindex ba43da5..a331237 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java\n@@ -77,7 +77,7 @@ import org.spearce.jgit.util.NB;\n  * Typical usage consists of creating instance intended for some pack,\n  * configuring options through accessors methods and finally call\n  * {@link #writePack(Iterator)} or\n- * {@link #writePack(Collection, Collection, boolean)} with objects\n+ * {@link #writePack(Collection, Collection, boolean, boolean)} with objects\n  * specification, to generate a pack stream.\n  * </p>\n  * <p>\n@@ -98,7 +98,7 @@ public class PackWriter {\n \t * Title of {@link ProgressMonitor} task used during counting objects to\n \t * pack.\n \t * \n-\t * @see #writePack(Collection, Collection, boolean)\n+\t * @see #writePack(Collection, Collection, boolean, boolean)\n \t */\n \tpublic static final String COUNTING_OBJECTS_PROGRESS = \"Counting objects to pack\";\n \n@@ -107,7 +107,7 @@ public class PackWriter {\n \t * reuse or delta reuse.\n \t * \n \t * @see #writePack(Iterator)\n-\t * @see #writePack(Collection, Collection, boolean)\n+\t * @see #writePack(Collection, Collection, boolean, boolean)\n \t */\n \tpublic static final String SEARCHING_REUSE_PROGRESS = \"Searching for delta and object reuse\";\n \n@@ -116,7 +116,7 @@ public class PackWriter {\n \t * (objects)\n \t * \n \t * @see #writePack(Iterator)\n-\t * @see #writePack(Collection, Collection, boolean)\n+\t * @see #writePack(Collection, Collection, boolean, boolean)\n \t */\n \tpublic static final String WRITING_OBJECTS_PROGRESS = \"Writing objects\";\n \n@@ -193,7 +193,7 @@ public class PackWriter {\n \t * Create writer for specified repository, that will write a pack to\n \t * provided output stream. Objects for packing are specified in\n \t * {@link #writePack(Iterator)} or\n-\t * {@link #writePack(Collection, Collection, boolean)}.\n+\t * {@link #writePack(Collection, Collection, boolean, boolean)}.\n \t * \n \t * @param repo\n \t *            repository where objects are stored.\n@@ -203,7 +203,7 @@ public class PackWriter {\n \t * @param monitor\n \t *            operations progress monitor, used within\n \t *            {@link #writePack(Iterator)} or\n-\t *            {@link #writePack(Collection, Collection, boolean)}.\n+\t *            {@link #writePack(Collection, Collection, boolean, boolean)}.\n \t */\n \tpublic PackWriter(final Repository repo, final OutputStream out,\n \t\t\tfinal ProgressMonitor monitor) {\n@@ -233,7 +233,8 @@ public class PackWriter {\n \t * writer will search for delta representation of object in repository and\n \t * use it if possible. Normally, only deltas with base to another object\n \t * existing in set of objects to pack will be used. Exception is however\n-\t * thin-pack (see {@link #writePack(Collection, Collection, boolean)} and\n+\t * thin-pack (see\n+\t * {@link #writePack(Collection, Collection, boolean, boolean)} and\n \t * {@link #writePack(Iterator)}) where base object must exist on other side\n \t * machine.\n \t * <p>\n@@ -442,15 +443,21 @@ public class PackWriter {\n \t *            belonging to party repository (uninteresting/boundary) as\n \t *            determined by set; this kind of pack is used only for\n \t *            transport; true - to produce thin pack, false - otherwise.\n+\t * @param ignoreMissingUninteresting\n+\t *            true if writer should ignore non existing uninteresting\n+\t *            objects during construction set of objects to pack; false\n+\t *            otherwise - non existing uninteresting objects may cause\n+\t *            {@link MissingObjectException}\n \t * @throws IOException\n \t *             when some I/O problem occur during reading objects for pack\n \t *             or writing pack stream.\n \t */\n \tpublic void writePack(final Collection<ObjectId> interestingObjects,\n-\t\t\tfinal Collection<ObjectId> uninterestingObjects, boolean thin)\n+\t\t\tfinal Collection<ObjectId> uninterestingObjects,\n+\t\t\tfinal boolean thin, final boolean ignoreMissingUninteresting)\n \t\t\tthrows IOException {\n \t\tObjectWalk walker = setUpWalker(interestingObjects,\n-\t\t\t\tuninterestingObjects, thin);\n+\t\t\t\tuninterestingObjects, thin, ignoreMissingUninteresting);\n \t\tfindObjectsToPack(walker);\n \t\twritePackInternal();\n \t}\n@@ -682,7 +689,8 @@ public class PackWriter {\n \n \tprivate ObjectWalk setUpWalker(\n \t\t\tfinal Collection<ObjectId> interestingObjects,\n-\t\t\tfinal Collection<ObjectId> uninterestingObjects, boolean thin)\n+\t\t\tfinal Collection<ObjectId> uninterestingObjects,\n+\t\t\tfinal boolean thin, final boolean ignoreMissingUninteresting)\n \t\t\tthrows MissingObjectException, IOException,\n \t\t\tIncorrectObjectTypeException {\n \t\tfinal ObjectWalk walker = new ObjectWalk(db);\n@@ -696,7 +704,14 @@ public class PackWriter {\n \t\t\twalker.markStart(o);\n \t\t}\n \t\tfor (ObjectId id : uninterestingObjects) {\n-\t\t\tRevObject o = walker.parseAny(id);\n+\t\t\tfinal RevObject o;\n+\t\t\ttry {\n+\t\t\t\to = walker.parseAny(id);\n+\t\t\t} catch (MissingObjectException x) {\n+\t\t\t\tif (ignoreMissingUninteresting)\n+\t\t\t\t\tcontinue;\n+\t\t\t\tthrow x;\n+\t\t\t}\n \t\t\twalker.markUninteresting(o);\n \t\t}\n \t\treturn walker;\n-- \n1.5.5.3\n"},{"id":"81488","messageId":"1214604407-30572-12-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-11-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 11/23] Add BasePackPushConnection implementing git-send-pack protocol","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:35Z","receivedAt":"2008-06-27T22:06:35Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"Implementation realies extensively on RemoteRefUpdate as input.\n\nIt supports report-status capability, and honors delete-refs one.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../jgit/transport/BasePackPushConnection.java     |  226 ++++++++++++++++++++\n 1 files changed, 226 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java\nnew file mode 100644\nindex 0000000..159e331\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java\n@@ -0,0 +1,226 @@\n+/*\n+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>\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.IOException;\n+import java.util.ArrayList;\n+import java.util.Collection;\n+import java.util.Map;\n+\n+import org.spearce.jgit.errors.PackProtocolException;\n+import org.spearce.jgit.errors.TransportException;\n+import org.spearce.jgit.lib.ObjectId;\n+import org.spearce.jgit.lib.PackWriter;\n+import org.spearce.jgit.lib.ProgressMonitor;\n+import org.spearce.jgit.lib.Ref;\n+import org.spearce.jgit.transport.RemoteRefUpdate.Status;\n+\n+/**\n+ * Push implementation using the native Git pack transfer service.\n+ * <p>\n+ * This is the canonical implementation for transferring objects to the remote\n+ * repository from the local repository by talking to the 'git-receive-pack'\n+ * service. Objects are packed on the local side into a pack file and then sent\n+ * to the remote repository.\n+ * <p>\n+ * This connection requires only a bi-directional pipe or socket, and thus is\n+ * easily wrapped up into a local process pipe, anonymous TCP socket, or a\n+ * command executed through an SSH tunnel.\n+ * <p>\n+ * This implementation honors {@link Transport#isPushThin()} option.\n+ * <p>\n+ * Concrete implementations should just call\n+ * {@link #init(java.io.InputStream, java.io.OutputStream)} and\n+ * {@link #readAdvertisedRefs()} methods in constructor or before any use. They\n+ * should also handle resources releasing in {@link #close()} method if needed.\n+ */\n+class BasePackPushConnection extends BasePackConnection implements\n+\t\tPushConnection {\n+\tstatic final String CAPABILITY_REPORT_STATUS = \"report-status\";\n+\n+\tstatic final String CAPABILITY_DELETE_REFS = \"delete-refs\";\n+\n+\tprivate final boolean thinPack;\n+\n+\tprivate boolean capableDeleteRefs;\n+\n+\tprivate boolean capableReport;\n+\n+\tprivate boolean sentCommand;\n+\n+\tprivate boolean writePack;\n+\n+\tBasePackPushConnection(final PackTransport transport) {\n+\t\tsuper(transport);\n+\t\tthinPack = transport.isPushThin();\n+\t}\n+\n+\tpublic void push(final ProgressMonitor monitor,\n+\t\t\tfinal Map<String, RemoteRefUpdate> refUpdates)\n+\t\t\tthrows TransportException {\n+\t\tmarkStartedOperation();\n+\t\tdoPush(monitor, refUpdates);\n+\t}\n+\n+\tprotected void doPush(final ProgressMonitor monitor,\n+\t\t\tfinal Map<String, RemoteRefUpdate> refUpdates)\n+\t\t\tthrows TransportException {\n+\t\ttry {\n+\t\t\twriteCommands(refUpdates.values(), monitor);\n+\t\t\tif (writePack)\n+\t\t\t\twritePack(refUpdates, monitor);\n+\t\t\tif (sentCommand && capableReport)\n+\t\t\t\treadStatusReport(refUpdates);\n+\t\t} catch (TransportException e) {\n+\t\t\tthrow e;\n+\t\t} catch (Exception e) {\n+\t\t\tthrow new TransportException(uri + \": \" + e.getMessage(), e);\n+\t\t} finally {\n+\t\t\tclose();\n+\t\t}\n+\t}\n+\n+\tprivate void writeCommands(final Collection<RemoteRefUpdate> refUpdates,\n+\t\t\tfinal ProgressMonitor monitor) throws IOException {\n+\t\tfinal String capabilties = enableCapabilties();\n+\t\tfor (final RemoteRefUpdate rru : refUpdates) {\n+\t\t\tif (!capableDeleteRefs && rru.isDelete()) {\n+\t\t\t\trru.setStatus(Status.REJECTED_NODELETE);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\tfinal StringBuilder sb = new StringBuilder();\n+\t\t\tfinal Ref advertisedRef = getRef(rru.getRemoteName());\n+\t\t\tfinal ObjectId oldId = (advertisedRef == null ? ObjectId.zeroId()\n+\t\t\t\t\t: advertisedRef.getObjectId());\n+\t\t\tsb.append(oldId);\n+\t\t\tsb.append(' ');\n+\t\t\tsb.append(rru.getNewObjectId());\n+\t\t\tsb.append(' ');\n+\t\t\tsb.append(rru.getRemoteName());\n+\t\t\tif (!sentCommand) {\n+\t\t\t\tsentCommand = true;\n+\t\t\t\tsb.append(capabilties);\n+\t\t\t}\n+\n+\t\t\tpckOut.writeString(sb.toString());\n+\t\t\trru.setStatus(sentCommand ? Status.AWAITING_REPORT : Status.OK);\n+\t\t\tif (!rru.isDelete())\n+\t\t\t\twritePack = true;\n+\t\t}\n+\n+\t\tif (monitor.isCancelled())\n+\t\t\tthrow new TransportException(uri + \": push cancelled\");\n+\t\tpckOut.end();\n+\t}\n+\n+\tprivate String enableCapabilties() {\n+\t\tfinal StringBuilder line = new StringBuilder();\n+\t\tcapableReport = wantCapability(line, CAPABILITY_REPORT_STATUS);\n+\t\tcapableDeleteRefs = wantCapability(line, CAPABILITY_DELETE_REFS);\n+\t\tif (line.length() > 0)\n+\t\t\tline.insert(0, '\\0');\n+\t\treturn line.toString();\n+\t}\n+\n+\tprivate void writePack(final Map<String, RemoteRefUpdate> refUpdates,\n+\t\t\tfinal ProgressMonitor monitor) throws IOException {\n+\t\tfinal PackWriter writer = new PackWriter(local, out, monitor);\n+\t\tfinal ArrayList<ObjectId> remoteObjects = new ArrayList<ObjectId>(\n+\t\t\t\tgetRefs().size());\n+\t\tfinal ArrayList<ObjectId> newObjects = new ArrayList<ObjectId>(\n+\t\t\t\trefUpdates.size());\n+\n+\t\tfor (final Ref r : getRefs())\n+\t\t\tremoteObjects.add(r.getObjectId());\n+\t\tfor (final RemoteRefUpdate r : refUpdates.values())\n+\t\t\tnewObjects.add(r.getNewObjectId());\n+\n+\t\twriter.writePack(newObjects, remoteObjects, thinPack, true);\n+\t}\n+\n+\tprivate void readStatusReport(final Map<String, RemoteRefUpdate> refUpdates)\n+\t\t\tthrows IOException {\n+\t\tfinal String unpackLine = pckIn.readString();\n+\t\tif (!unpackLine.startsWith(\"unpack \"))\n+\t\t\tthrow new PackProtocolException(uri + \": unexpected report line: \"\n+\t\t\t\t\t+ unpackLine);\n+\t\tfinal String unpackStatus = unpackLine.substring(\"unpack \".length());\n+\t\tif (!unpackStatus.equals(\"ok\"))\n+\t\t\tthrow new TransportException(uri\n+\t\t\t\t\t+ \": error occurred during unpacking on the remote end: \"\n+\t\t\t\t\t+ unpackStatus);\n+\n+\t\tString refLine;\n+\t\twhile ((refLine = pckIn.readString()).length() > 0) {\n+\t\t\tboolean ok = false;\n+\t\t\tint refNameEnd = -1;\n+\t\t\tif (refLine.startsWith(\"ok \")) {\n+\t\t\t\tok = true;\n+\t\t\t\trefNameEnd = refLine.length();\n+\t\t\t} else if (refLine.startsWith(\"ng \")) {\n+\t\t\t\tok = false;\n+\t\t\t\trefNameEnd = refLine.indexOf(\" \", 3);\n+\t\t\t}\n+\t\t\tif (refNameEnd == -1)\n+\t\t\t\tthrow new PackProtocolException(uri\n+\t\t\t\t\t\t+ \": unexpected report line: \" + refLine);\n+\t\t\tfinal String refName = refLine.substring(3, refNameEnd);\n+\t\t\tfinal String message = (ok ? null : refLine\n+\t\t\t\t\t.substring(refNameEnd + 1));\n+\n+\t\t\tfinal RemoteRefUpdate rru = refUpdates.get(refName);\n+\t\t\tif (rru == null)\n+\t\t\t\tthrow new PackProtocolException(uri\n+\t\t\t\t\t\t+ \": unexpected ref report: \" + refName);\n+\t\t\tif (ok) {\n+\t\t\t\trru.setStatus(Status.OK);\n+\t\t\t} else {\n+\t\t\t\trru.setStatus(Status.REJECTED_OTHER_REASON);\n+\t\t\t\trru.setMessage(message);\n+\t\t\t}\n+\t\t}\n+\t\tfor (final RemoteRefUpdate rru : refUpdates.values()) {\n+\t\t\tif (rru.getStatus() == Status.AWAITING_REPORT)\n+\t\t\t\tthrow new PackProtocolException(uri\n+\t\t\t\t\t\t+ \": expected report for ref \" + rru.getRemoteName()\n+\t\t\t\t\t\t+ \" not received\");\n+\t\t}\n+\t}\n+}\n-- \n1.5.5.3\n"},{"id":"81490","messageId":"1214604407-30572-13-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-12-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 12/23] Fix: let RevWalk reset correctly before isMergedInto()","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:36Z","receivedAt":"2008-06-27T22:06:36Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"Retained flags was wrongly computed for reset() call inside\nisMergedInto().\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../src/org/spearce/jgit/revwalk/RevWalk.java      |    2 +-\n 1 files changed, 1 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 fc757a5..7976d75 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@@ -347,7 +347,7 @@ public class RevWalk implements Iterable<RevCommit> {\n \t\tfinal TreeFilter oldTF = treeFilter;\n \t\ttry {\n \t\t\tfinishDelayedFreeFlags();\n-\t\t\treset(~freeFlags & ~RESERVED_FLAGS);\n+\t\t\treset(~freeFlags & APP_FLAGS);\n \t\t\tfilter = RevFilter.MERGE_BASE;\n \t\t\ttreeFilter = TreeFilter.ALL;\n \t\t\tmarkStart(tip);\n-- \n1.5.5.3\n"},{"id":"81489","messageId":"1214604407-30572-14-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-13-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 13/23] Add PushProcess class implementing git-send-pack logic","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:37Z","receivedAt":"2008-06-27T22:06:37Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"This class perform analogous operations as FetchProcess. It processes\nrefs advertised by connection, updates RemoteRefUpdates and\nlocal tracking branches - TrackingRefUpdates.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../org/spearce/jgit/transport/PushProcess.java    |  224 ++++++++++++++++++++\n 1 files changed, 224 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java\nnew file mode 100644\nindex 0000000..f742949\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java\n@@ -0,0 +1,224 @@\n+/*\n+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>\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.util.Collection;\n+import java.util.HashMap;\n+import java.util.Map;\n+\n+import org.spearce.jgit.errors.MissingObjectException;\n+import org.spearce.jgit.errors.NotSupportedException;\n+import org.spearce.jgit.errors.TransportException;\n+import org.spearce.jgit.lib.ObjectId;\n+import org.spearce.jgit.lib.ProgressMonitor;\n+import org.spearce.jgit.lib.Ref;\n+import org.spearce.jgit.revwalk.RevCommit;\n+import org.spearce.jgit.revwalk.RevObject;\n+import org.spearce.jgit.revwalk.RevWalk;\n+import org.spearce.jgit.transport.RemoteRefUpdate.Status;\n+\n+/**\n+ * Class performing push operation on remote repository.\n+ * \n+ * @see Transport#push(ProgressMonitor, Collection)\n+ */\n+class PushProcess {\n+\t/** Task name for {@link ProgressMonitor} used during opening connection. */\n+\tstatic final String PROGRESS_OPENING_CONNECTION = \"Opening connection\";\n+\n+\t/** Transport used to perform this operation. */\n+\tprivate final Transport transport;\n+\n+\t/** Push operation connection created to perform this operation */\n+\tprivate PushConnection connection;\n+\n+\t/** Refs to update on remote side. */\n+\tprivate final Map<String, RemoteRefUpdate> toPush;\n+\n+\t/** Revision walker for checking some updates properties. */\n+\tprivate final RevWalk walker;\n+\n+\t/**\n+\t * Create process for specified transport and refs updates specification.\n+\t * \n+\t * @param transport\n+\t *            transport between remote and local repository, used to create\n+\t *            connection.\n+\t * @param toPush\n+\t *            specification of refs updates (and local tracking branches).\n+\t * @throws TransportException\n+\t */\n+\tPushProcess(final Transport transport,\n+\t\t\tfinal Collection<RemoteRefUpdate> toPush) throws TransportException {\n+\t\tthis.walker = new RevWalk(transport.local);\n+\t\tthis.transport = transport;\n+\t\tthis.toPush = new HashMap<String, RemoteRefUpdate>();\n+\t\tfor (final RemoteRefUpdate rru : toPush) {\n+\t\t\tif (this.toPush.put(rru.getRemoteName(), rru) != null)\n+\t\t\t\tthrow new TransportException(\n+\t\t\t\t\t\t\"Duplicate remote ref update is illegal. Affected remote name: \"\n+\t\t\t\t\t\t\t\t+ rru.getRemoteName());\n+\t\t}\n+\t}\n+\n+\t/**\n+\t * Perform push operation between local and remote repository - set remote\n+\t * refs appropriately, send needed objects and update local tracking refs.\n+\t * \n+\t * @param monitor\n+\t *            progress monitor used for feedback about operation.\n+\t * @return result of push operation with complete status description.\n+\t * @throws NotSupportedException\n+\t *             when push operation is not supported by provided transport.\n+\t * @throws TransportException\n+\t *             when some error occurred during operation, like I/O, protocol\n+\t *             error, or local database consistency error.\n+\t */\n+\tPushResult execute(final ProgressMonitor monitor)\n+\t\t\tthrows NotSupportedException, TransportException {\n+\t\tmonitor.beginTask(PROGRESS_OPENING_CONNECTION, ProgressMonitor.UNKNOWN);\n+\t\tconnection = transport.openPush();\n+\t\ttry {\n+\t\t\tmonitor.endTask();\n+\n+\t\t\tfinal Map<String, RemoteRefUpdate> preprocessed = prepareRemoteUpdates();\n+\t\t\tif (!preprocessed.isEmpty())\n+\t\t\t\tconnection.push(monitor, preprocessed);\n+\t\t} finally {\n+\t\t\tconnection.close();\n+\t\t}\n+\t\tupdateTrackingRefs();\n+\t\treturn prepareOperationResult();\n+\t}\n+\n+\tprivate Map<String, RemoteRefUpdate> prepareRemoteUpdates()\n+\t\t\tthrows TransportException {\n+\t\tfinal Map<String, RemoteRefUpdate> result = new HashMap<String, RemoteRefUpdate>();\n+\t\tfor (final RemoteRefUpdate rru : toPush.values()) {\n+\t\t\tfinal Ref advertisedRef = connection.getRef(rru.getRemoteName());\n+\t\t\tfinal ObjectId advertisedOld = (advertisedRef == null ? ObjectId\n+\t\t\t\t\t.zeroId() : advertisedRef.getObjectId());\n+\n+\t\t\tif (rru.getNewObjectId().equals(advertisedOld)) {\n+\t\t\t\tif (rru.isDelete()) {\n+\t\t\t\t\t// ref does exist neither locally nor remotely\n+\t\t\t\t\trru.setStatus(Status.NON_EXISTING);\n+\t\t\t\t} else {\n+\t\t\t\t\t// same object - nothing to do\n+\t\t\t\t\trru.setStatus(Status.UP_TO_DATE);\n+\t\t\t\t}\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t// caller has explicitly specified expected old object id, while it\n+\t\t\t// has been changed in the mean time - reject\n+\t\t\tif (rru.isExpectingOldObjectId()\n+\t\t\t\t\t&& !rru.getExpectedOldObjectId().equals(advertisedOld)) {\n+\t\t\t\trru.setStatus(Status.REJECTED_REMOTE_CHANGED);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t// create ref (hasn't existed on remote side) and delete ref\n+\t\t\t// are always fast-forward commands, feasible at this level\n+\t\t\tif (advertisedOld.equals(ObjectId.zeroId()) || rru.isDelete()) {\n+\t\t\t\trru.setFastForward(true);\n+\t\t\t\tresult.put(rru.getRemoteName(), rru);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t// check for fast-forward:\n+\t\t\t// - both old and new ref must point to commits, AND\n+\t\t\t// - both of them must be known for us, exist in repository, AND\n+\t\t\t// - old commit must be ancestor of new commit\n+\t\t\tboolean fastForward = true;\n+\t\t\ttry {\n+\t\t\t\tRevObject oldRev = walker.parseAny(advertisedOld);\n+\t\t\t\tfinal RevObject newRev = walker.parseAny(rru.getNewObjectId());\n+\t\t\t\tif (!(oldRev instanceof RevCommit)\n+\t\t\t\t\t\t|| !(newRev instanceof RevCommit)\n+\t\t\t\t\t\t|| !walker.isMergedInto((RevCommit) oldRev,\n+\t\t\t\t\t\t\t\t(RevCommit) newRev))\n+\t\t\t\t\tfastForward = false;\n+\t\t\t} catch (MissingObjectException x) {\n+\t\t\t\tfastForward = false;\n+\t\t\t} catch (Exception x) {\n+\t\t\t\tthrow new TransportException(transport.getURI()\n+\t\t\t\t\t\t+ \": reading objects from local repository failed: \"\n+\t\t\t\t\t\t+ x.getMessage(), x);\n+\t\t\t}\n+\t\t\trru.setFastForward(fastForward);\n+\t\t\tif (!fastForward && !rru.isForceUpdate())\n+\t\t\t\trru.setStatus(Status.REJECTED_NONFASTFORWARD);\n+\t\t\telse\n+\t\t\t\tresult.put(rru.getRemoteName(), rru);\n+\t\t}\n+\t\treturn result;\n+\t}\n+\n+\tprivate void updateTrackingRefs() {\n+\t\tfor (final RemoteRefUpdate rru : toPush.values()) {\n+\t\t\tfinal Status status = rru.getStatus();\n+\t\t\tif (rru.hasTrackingRefUpdate()\n+\t\t\t\t\t&& (status == Status.UP_TO_DATE || status == Status.OK)) {\n+\t\t\t\t// update local tracking branch only when there is a chance that\n+\t\t\t\t// it has changed; this is possible for:\n+\t\t\t\t// -updated (OK) status,\n+\t\t\t\t// -up to date (UP_TO_DATE) status\n+\t\t\t\ttry {\n+\t\t\t\t\trru.updateTrackingRef(walker);\n+\t\t\t\t} catch (IOException e) {\n+\t\t\t\t\t// ignore as RefUpdate has stored I/O error status\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tprivate PushResult prepareOperationResult() {\n+\t\tfinal PushResult result = new PushResult();\n+\t\tresult.setAdvertisedRefs(connection.getRefsMap());\n+\t\tresult.setRemoteUpdates(toPush);\n+\n+\t\tfor (final RemoteRefUpdate rru : toPush.values()) {\n+\t\t\tfinal TrackingRefUpdate tru = rru.getTrackingRefUpdate();\n+\t\t\tif (tru != null)\n+\t\t\t\tresult.add(tru);\n+\t\t}\n+\t\treturn result;\n+\t}\n+}\n-- \n1.5.5.3\n"},{"id":"81492","messageId":"1214604407-30572-15-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-14-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 14/23] Clarify Repository#resolve() documentation","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:38Z","receivedAt":"2008-06-27T22:06:38Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"Say explicitly that this method returns null when revstr can't be\nresolved.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../src/org/spearce/jgit/lib/Repository.java       |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java\nindex 64f93ff..2b43b2c 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java\n@@ -524,7 +524,7 @@ public class Repository {\n \t * </ul>\n \t *\n \t * @param revstr A git object references expression\n-\t * @return an ObjectId\n+\t * @return an ObjectId or null if revstr can't be resolved to any ObjectId\n \t * @throws IOException on serious errors\n \t */\n \tpublic ObjectId resolve(final String revstr) throws IOException {\n-- \n1.5.5.3\n"},{"id":"81493","messageId":"1214604407-30572-16-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-15-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 15/23] Add String versions of methods in RefSpec","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:39Z","receivedAt":"2008-06-27T22:06:39Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"matchDestination(), matchSource(), expandFromSourec() can take String\nas parameter now, not only Ref (we just need a ref name).\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../src/org/spearce/jgit/transport/RefSpec.java    |   46 +++++++++++++++++--\n 1 files changed, 41 insertions(+), 5 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/RefSpec.java b/org.spearce.jgit/src/org/spearce/jgit/transport/RefSpec.java\nindex 38489be..1589e19 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/RefSpec.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/RefSpec.java\n@@ -281,6 +281,17 @@ public class RefSpec {\n \t}\n \n \t/**\n+\t * Does this specification's source description match the ref name?\n+\t * \n+\t * @param r\n+\t *            ref name that should be tested.\n+\t * @return true if the names match; false otherwise.\n+\t */\n+\tpublic boolean matchSource(final String r) {\n+\t\treturn match(r, getSource());\n+\t}\n+\n+\t/**\n \t * Does this specification's source description match the ref?\n \t * \n \t * @param r\n@@ -288,7 +299,18 @@ public class RefSpec {\n \t * @return true if the names match; false otherwise.\n \t */\n \tpublic boolean matchSource(final Ref r) {\n-\t\treturn match(r, getSource());\n+\t\treturn match(r.getName(), getSource());\n+\t}\n+\n+\t/**\n+\t * Does this specification's destination description match the ref name?\n+\t * \n+\t * @param r\n+\t *            ref name that should be tested.\n+\t * @return true if the names match; false otherwise.\n+\t */\n+\tpublic boolean matchDestination(final String r) {\n+\t\treturn match(r, getDestination());\n \t}\n \n \t/**\n@@ -299,7 +321,21 @@ public class RefSpec {\n \t * @return true if the names match; false otherwise.\n \t */\n \tpublic boolean matchDestination(final Ref r) {\n-\t\treturn match(r, getDestination());\n+\t\treturn match(r.getName(), getDestination());\n+\t}\n+\n+\t/**\n+\t * Expand this specification to exactly match a ref name.\n+\t * <p>\n+\t * Callers must first verify the passed ref name matches this specification,\n+\t * otherwise expansion results may be unpredictable.\n+\t * \n+\t * @param r\n+\t *            a ref name that matched our source specification.\n+\t * @return a new specification that is not a wildcard.\n+\t */\n+\tpublic RefSpec expandFromSource(final String r) {\n+\t\treturn isWildcard() ? new RefSpec(this, r) : this;\n \t}\n \n \t/**\n@@ -316,12 +352,12 @@ public class RefSpec {\n \t\treturn isWildcard() ? new RefSpec(this, r.getName()) : this;\n \t}\n \n-\tprivate boolean match(final Ref r, final String s) {\n+\tprivate boolean match(final String refName, final String s) {\n \t\tif (s == null)\n \t\t\treturn false;\n \t\tif (isWildcard())\n-\t\t\treturn r.getName().startsWith(s.substring(0, s.length() - 1));\n-\t\treturn r.getName().equals(s);\n+\t\t\treturn refName.startsWith(s.substring(0, s.length() - 1));\n+\t\treturn refName.equals(s);\n \t}\n \n \tpublic int hashCode() {\n-- \n1.5.5.3\n"},{"id":"81496","messageId":"1214604407-30572-17-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-16-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 16/23] Transport* - general support for push() and implementations","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:40Z","receivedAt":"2008-06-27T22:06:40Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"Implementation of push() at abstract Transport class level and\nimplementations of concrete protocols: SSH, local, git-daemon.\n\nSome Transport* implementations required refactoring to share code\nbetween pack and fetch connections.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../src/org/spearce/jgit/transport/Transport.java  |  184 +++++++++++++++++++-\n .../spearce/jgit/transport/TransportBundle.java    |    6 +\n .../spearce/jgit/transport/TransportGitAnon.java   |   39 ++++\n .../spearce/jgit/transport/TransportGitSsh.java    |   51 ++++++\n .../org/spearce/jgit/transport/TransportLocal.java |  113 ++++++++----\n .../org/spearce/jgit/transport/WalkTransport.java  |    7 +\n 6 files changed, 361 insertions(+), 39 deletions(-)\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 c4b71eb..da5b41e 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@@ -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, Marek Zawirski <marek.zawirski@gmail.com>\n  *\n  * All rights reserved.\n  *\n@@ -42,12 +43,16 @@ import java.net.URISyntaxException;\n import java.util.ArrayList;\n import java.util.Collection;\n import java.util.Collections;\n+import java.util.HashSet;\n+import java.util.LinkedList;\n import java.util.List;\n+import java.util.Map;\n \n import org.spearce.jgit.errors.NotSupportedException;\n import org.spearce.jgit.errors.TransportException;\n import org.spearce.jgit.lib.NullProgressMonitor;\n import org.spearce.jgit.lib.ProgressMonitor;\n+import org.spearce.jgit.lib.Ref;\n import org.spearce.jgit.lib.Repository;\n \n /**\n@@ -105,6 +110,8 @@ public abstract class Transport {\n \t\ttn.setOptionUploadPack(cfg.getUploadPack());\n \t\ttn.fetch = cfg.getFetchRefSpecs();\n \t\ttn.tagopt = cfg.getTagOpt();\n+\t\ttn.setOptionReceivePack(cfg.getReceivePack());\n+\t\ttn.push = cfg.getPushRefSpecs();\n \t\treturn tn;\n \t}\n \n@@ -152,6 +159,20 @@ public abstract class Transport {\n \t */\n \tpublic static final boolean DEFAULT_PUSH_THIN = false;\n \n+\t/**\n+\t * Specification for fetch or push operations, to fetch or push all tags.\n+\t * Acts as --tags.\n+\t */\n+\tpublic static final RefSpec REFSPEC_TAGS = new RefSpec(\n+\t\t\t\"refs/tags/*:refs/tags/*\");\n+\n+\t/**\n+\t * Specification for push operation, to push all refs under refs/heads. Acts\n+\t * as --all.\n+\t */\n+\tpublic static final RefSpec REFSPEC_PUSH_ALL = new RefSpec(\n+\t\t\t\"refs/heads/*:refs/heads/*\");\n+\n \t/** The repository this transport fetches into, or pushes out of. */\n \tprotected final Repository local;\n \n@@ -162,7 +183,7 @@ public abstract class Transport {\n \tprivate String optionUploadPack = RemoteConfig.DEFAULT_UPLOAD_PACK;\n \n \t/** Specifications to apply during fetch. */\n-\tprivate List<RefSpec> fetch = Collections.<RefSpec> emptyList();\n+\tprivate List<RefSpec> fetch = Collections.emptyList();\n \n \t/**\n \t * How {@link #fetch(ProgressMonitor, Collection)} should handle tags.\n@@ -178,6 +199,12 @@ public abstract class Transport {\n \t/** Should fetch request thin-pack if remote repository can produce it. */\n \tprivate boolean fetchThin = DEFAULT_FETCH_THIN;\n \n+\t/** Name of the receive pack program, if it must be executed. */\n+\tprivate String optionReceivePack = RemoteConfig.DEFAULT_RECEIVE_PACK;\n+\n+\t/** Specifications to apply during push. */\n+\tprivate List<RefSpec> push = Collections.emptyList();\n+\n \t/** Should push produce thin-pack when sending objects to remote repository. */\n \tprivate boolean pushThin = DEFAULT_PUSH_THIN;\n \n@@ -274,6 +301,31 @@ public abstract class Transport {\n \t}\n \n \t/**\n+\t * Default setting is: {@value RemoteConfig#DEFAULT_RECEIVE_PACK}\n+\t * \n+\t * @return remote executable providing receive-pack service for pack\n+\t *         transports.\n+\t * @see PackTransport\n+\t */\n+\tpublic String getOptionReceivePack() {\n+\t\treturn optionReceivePack;\n+\t}\n+\n+\t/**\n+\t * Set remote executable providing receive-pack service for pack transports.\n+\t * Default setting is: {@value RemoteConfig#DEFAULT_RECEIVE_PACK}\n+\t * \n+\t * @param optionReceivePack\n+\t *            remote executable, if null or empty default one is set;\n+\t */\n+\tpublic void setOptionReceivePack(String optionReceivePack) {\n+\t\tif (optionReceivePack != null && optionReceivePack.length() > 0)\n+\t\t\tthis.optionReceivePack = optionReceivePack;\n+\t\telse\n+\t\t\tthis.optionReceivePack = RemoteConfig.DEFAULT_RECEIVE_PACK;\n+\t}\n+\n+\t/**\n \t * Default setting is: {@value #DEFAULT_PUSH_THIN}\n \t * \n \t * @return true if push should produce thin-pack in pack transports\n@@ -356,6 +408,98 @@ public abstract class Transport {\n \t}\n \n \t/**\n+\t * Push objects and refs from the local repository to the remote one.\n+\t * <p>\n+\t * This is a utility function providing standard push behavior. It updates\n+\t * remote refs and send there necessary objects according to remote ref\n+\t * update specification. After successful remote ref update, associated\n+\t * locally stored tracking branch is updated if set up accordingly. Detailed\n+\t * operation result is provided after execution.\n+\t * <p>\n+\t * For setting up remote ref update specification from ref spec, see helper\n+\t * method {@link #findRemoteRefUpdatesFor(Collection)}, predefined refspecs ({@link #REFSPEC_TAGS},\n+\t * {@link #REFSPEC_PUSH_ALL}) or consider using directly\n+\t * {@link RemoteRefUpdate} for more possibilities.\n+\t * \n+\t * @see RemoteRefUpdate\n+\t * \n+\t * @param monitor\n+\t *            progress monitor to inform the user about our processing\n+\t *            activity. Must not be null. Use {@link NullProgressMonitor} if\n+\t *            progress updates are not interesting or necessary.\n+\t * @param toPush\n+\t *            specification of refs to push. May be null or the empty\n+\t *            collection to use the specifications from the RemoteConfig\n+\t *            converted by {@link #findRemoteRefUpdatesFor(Collection)}. No\n+\t *            more than 1 RemoteRefUpdate with the same remoteName is\n+\t *            allowed.\n+\t * @return information about results of remote refs updates, tracking refs\n+\t *         updates and refs advertised by remote repository.\n+\t * @throws NotSupportedException\n+\t *             this transport implementation does not support pusing\n+\t *             objects.\n+\t * @throws TransportException\n+\t *             the remote connection could not be established or object\n+\t *             copying (if necessary) failed at I/O or protocol level or\n+\t *             update specification was incorrect.\n+\t */\n+\tpublic PushResult push(final ProgressMonitor monitor,\n+\t\t\tCollection<RemoteRefUpdate> toPush) throws NotSupportedException,\n+\t\t\tTransportException {\n+\t\tif (toPush == null || toPush.isEmpty()) {\n+\t\t\t// If the caller did not ask for anything use the defaults.\n+\t\t\ttoPush = findRemoteRefUpdatesFor(push);\n+\t\t\tif (toPush.isEmpty())\n+\t\t\t\tthrow new TransportException(\"Nothing to push.\");\n+\t\t}\n+\t\tfinal PushProcess pushProcess = new PushProcess(this, toPush);\n+\t\treturn pushProcess.execute(monitor);\n+\t}\n+\n+\t/**\n+\t * Convert push remote refs update specification from {@link RefSpec} form\n+\t * to {@link RemoteRefUpdate}. Conversion expands wildcards by matching\n+\t * source part to local refs. expectedOldObjectId in RemoteRefUpdate is\n+\t * always set as null. Tracking branch is configured if RefSpec destination\n+\t * matches source of any fetch ref spec for this transport remote\n+\t * configuration.\n+\t * \n+\t * @param specs\n+\t *            collection of RefSpec to convert.\n+\t * @return collection of set up {@link RemoteRefUpdate}.\n+\t * @throws TransportException\n+\t *             when problem occurred during conversion or specification set\n+\t *             up: most probably, missing objects or refs.\n+\t */\n+\tpublic Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(\n+\t\t\tfinal Collection<RefSpec> specs) throws TransportException {\n+\t\tfinal List<RemoteRefUpdate> result = new LinkedList<RemoteRefUpdate>();\n+\t\tfinal Collection<RefSpec> procRefs = expandPushWildcardsFor(specs);\n+\n+\t\tfor (final RefSpec spec : procRefs) {\n+\t\t\ttry {\n+\t\t\t\tfinal String srcRef = spec.getSource();\n+\t\t\t\t// null destination (no-colon in ref-spec) is a special case\n+\t\t\t\tfinal String remoteName = (spec.getDestination() == null ? spec\n+\t\t\t\t\t\t.getSource() : spec.getDestination());\n+\t\t\t\tfinal boolean forceUpdate = spec.isForceUpdate();\n+\t\t\t\tfinal String localName = findTrackingRefName(remoteName);\n+\n+\t\t\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(local, srcRef,\n+\t\t\t\t\t\tremoteName, forceUpdate, localName, null);\n+\t\t\t\tresult.add(rru);\n+\t\t\t} catch (TransportException x) {\n+\t\t\t\tthrow x;\n+\t\t\t} catch (Exception x) {\n+\t\t\t\tthrow new TransportException(\n+\t\t\t\t\t\t\"Problem with resolving push ref spec \\\"\" + spec\n+\t\t\t\t\t\t\t\t+ \"\\\" locally: \" + x.getMessage(), x);\n+\t\t\t}\n+\t\t}\n+\t\treturn result;\n+\t}\n+\n+\t/**\n \t * Begins a new connection for fetching from the remote repository.\n \t * \n \t * @return a fresh connection to fetch from the remote repository.\n@@ -373,9 +517,41 @@ public abstract class Transport {\n \t * @return a fresh connection to push into the remote repository.\n \t * @throws NotSupportedException\n \t *             the implementation does not support pushing.\n+\t * @throws TransportException\n+\t *             the remote connection could not be established\n \t */\n-\tpublic final PushConnection openPush() throws NotSupportedException\n-\t/* TransportException */{\n-\t\tthrow new NotSupportedException(\"No push support.\");\n+\tpublic abstract PushConnection openPush() throws NotSupportedException,\n+\t\t\tTransportException;\n+\n+\tprivate Collection<RefSpec> expandPushWildcardsFor(\n+\t\t\tfinal Collection<RefSpec> specs) {\n+\t\tfinal Map<String, Ref> localRefs = local.getAllRefs();\n+\t\tfinal Collection<RefSpec> procRefs = new HashSet<RefSpec>();\n+\n+\t\tfor (final RefSpec spec : specs) {\n+\t\t\tif (spec.isWildcard()) {\n+\t\t\t\tfor (final Ref localRef : localRefs.values()) {\n+\t\t\t\t\tif (spec.matchSource(localRef))\n+\t\t\t\t\t\tprocRefs.add(spec.expandFromSource(localRef));\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tprocRefs.add(spec);\n+\t\t\t}\n+\t\t}\n+\t\treturn procRefs;\n+\t}\n+\n+\tprivate String findTrackingRefName(final String remoteName) {\n+\t\t// try to find matching tracking refs\n+\t\tfor (final RefSpec fetchSpec : fetch) {\n+\t\t\tif (fetchSpec.matchSource(remoteName)) {\n+\t\t\t\tif (fetchSpec.isWildcard())\n+\t\t\t\t\treturn fetchSpec.expandFromSource(remoteName)\n+\t\t\t\t\t\t\t.getDestination();\n+\t\t\t\telse\n+\t\t\t\t\treturn fetchSpec.getDestination();\n+\t\t\t}\n+\t\t}\n+\t\treturn null;\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 48120a8..1bf081a 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@@ -95,6 +95,12 @@ class TransportBundle extends PackTransport {\n \t\treturn new BundleFetchConnection();\n \t}\n \n+\t@Override\n+\tpublic PushConnection openPush() throws NotSupportedException {\n+\t\tthrow new NotSupportedException(\n+\t\t\t\t\"Push is not supported for bundle transport\");\n+\t}\n+\n \tclass BundleFetchConnection extends BaseFetchConnection {\n \t\tFileInputStream in;\n \ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java\nindex a7a419e..6e49083 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.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, Marek Zawirski <marek.zawirski@gmail.com>\n  *\n  * All rights reserved.\n  *\n@@ -71,6 +72,11 @@ class TransportGitAnon extends PackTransport {\n \t\treturn new TcpFetchConnection();\n \t}\n \n+\t@Override\n+\tpublic PushConnection openPush() throws TransportException {\n+\t\treturn new TcpPushConnection();\n+\t}\n+\n \tSocket openConnection() throws TransportException {\n \t\tfinal int port = uri.getPort() > 0 ? uri.getPort() : GIT_PORT;\n \t\ttry {\n@@ -131,4 +137,37 @@ class TransportGitAnon extends PackTransport {\n \t\t\t}\n \t\t}\n \t}\n+\n+\tclass TcpPushConnection extends BasePackPushConnection {\n+\t\tprivate Socket sock;\n+\n+\t\tTcpPushConnection() throws TransportException {\n+\t\t\tsuper(TransportGitAnon.this);\n+\t\t\tsock = openConnection();\n+\t\t\ttry {\n+\t\t\t\tinit(sock.getInputStream(), sock.getOutputStream());\n+\t\t\t\tservice(\"git-receive-pack\", pckOut);\n+\t\t\t} catch (IOException err) {\n+\t\t\t\tclose();\n+\t\t\t\tthrow new TransportException(uri.toString()\n+\t\t\t\t\t\t+ \": remote hung up unexpectedly\", err);\n+\t\t\t}\n+\t\t\treadAdvertisedRefs();\n+\t\t}\n+\n+\t\t@Override\n+\t\tpublic void close() {\n+\t\t\tsuper.close();\n+\n+\t\t\tif (sock != null) {\n+\t\t\t\ttry {\n+\t\t\t\t\tsock.close();\n+\t\t\t\t} catch (IOException err) {\n+\t\t\t\t\t// Ignore errors during close.\n+\t\t\t\t} finally {\n+\t\t\t\t\tsock = null;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java\nindex f6e456a..55be4f6 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.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, Marek Zawirski <marek.zawirski@gmail.com>\n  *\n  * All rights reserved.\n  *\n@@ -88,6 +89,11 @@ class TransportGitSsh extends PackTransport {\n \t\treturn new SshFetchConnection();\n \t}\n \n+\t@Override\n+\tpublic PushConnection openPush() throws TransportException {\n+\t\treturn new SshPushConnection();\n+\t}\n+\n \tprivate static void sqMinimal(final StringBuilder cmd, final String val) {\n \t\tif (val.matches(\"^[a-zA-Z0-9._/-]*$\")) {\n \t\t\t// If the string matches only generally safe characters\n@@ -232,4 +238,49 @@ class TransportGitSsh extends PackTransport {\n \t\t\t}\n \t\t}\n \t}\n+\n+\tclass SshPushConnection extends BasePackPushConnection {\n+\t\tprivate Session session;\n+\n+\t\tprivate ChannelExec channel;\n+\n+\t\tSshPushConnection() throws TransportException {\n+\t\t\tsuper(TransportGitSsh.this);\n+\t\t\ttry {\n+\t\t\t\tsession = openSession();\n+\t\t\t\tchannel = exec(session, getOptionReceivePack());\n+\t\t\t\tinit(channel.getInputStream(), channel.getOutputStream());\n+\t\t\t} catch (TransportException err) {\n+\t\t\t\tclose();\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(uri.toString()\n+\t\t\t\t\t\t+ \": remote hung up unexpectedly\", err);\n+\t\t\t}\n+\t\t\treadAdvertisedRefs();\n+\t\t}\n+\n+\t\t@Override\n+\t\tpublic void close() {\n+\t\t\tsuper.close();\n+\n+\t\t\tif (channel != null) {\n+\t\t\t\ttry {\n+\t\t\t\t\tif (channel.isConnected())\n+\t\t\t\t\t\tchannel.disconnect();\n+\t\t\t\t} finally {\n+\t\t\t\t\tchannel = null;\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t\tif (session != null) {\n+\t\t\t\ttry {\n+\t\t\t\t\tsch.releaseSession(session);\n+\t\t\t\t} finally {\n+\t\t\t\t\tsession = null;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\nindex e109cf4..f48dc6d 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\n@@ -2,6 +2,7 @@\n  * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>\n  * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>\n  * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>\n+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>\n  *\n  * All rights reserved.\n  *\n@@ -43,6 +44,7 @@ import java.io.File;\n import java.io.IOException;\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@@ -83,50 +85,35 @@ class TransportLocal extends PackTransport {\n \t\treturn new LocalFetchConnection();\n \t}\n \n+\t@Override\n+\tpublic PushConnection openPush() throws NotSupportedException,\n+\t\t\tTransportException {\n+\t\treturn new LocalPushConnection();\n+\t}\n+\n+\tprotected Process startProcessWithErrStream(final String cmd)\n+\t\t\tthrows TransportException {\n+\t\ttry {\n+\t\t\tfinal Process proc = Runtime.getRuntime().exec(\n+\t\t\t\t\tnew String[] { cmd, \".\" }, null, remoteGitDir);\n+\t\t\tnew StreamRewritingThread(proc.getErrorStream()).start();\n+\t\t\treturn proc;\n+\t\t} catch (IOException err) {\n+\t\t\tthrow new TransportException(uri.toString() + \": \"\n+\t\t\t\t\t+ err.getMessage(), err);\n+\t\t}\n+\t}\n+\n \tclass LocalFetchConnection extends BasePackFetchConnection {\n \t\tprivate Process uploadPack;\n \n \t\tLocalFetchConnection() throws TransportException {\n \t\t\tsuper(TransportLocal.this);\n-\t\t\ttry {\n-\t\t\t\tuploadPack = Runtime.getRuntime().exec(\n-\t\t\t\t\t\tnew String[] { getOptionUploadPack(), \".\" }, null,\n-\t\t\t\t\t\tremoteGitDir);\n-\t\t\t} catch (IOException err) {\n-\t\t\t\tthrow new TransportException(uri.toString() + \": \"\n-\t\t\t\t\t\t+ err.getMessage(), err);\n-\t\t\t}\n-\t\t\tstartErrorThread();\n+\t\t\tuploadPack = startProcessWithErrStream(getOptionReceivePack());\n \t\t\tinit(uploadPack.getInputStream(), uploadPack.getOutputStream());\n \t\t\treadAdvertisedRefs();\n \t\t}\n \n-\t\tprivate void startErrorThread() {\n-\t\t\tfinal InputStream errorStream = uploadPack.getErrorStream();\n-\t\t\tnew Thread(\"JGit \" + getOptionUploadPack() + \" Errors\") {\n-\t\t\t\tpublic void run() {\n-\t\t\t\t\tfinal byte[] tmp = new byte[512];\n-\t\t\t\t\ttry {\n-\t\t\t\t\t\tfor (;;) {\n-\t\t\t\t\t\t\tfinal int n = errorStream.read(tmp);\n-\t\t\t\t\t\t\tif (n < 0)\n-\t\t\t\t\t\t\t\tbreak;\n-\t\t\t\t\t\t\tSystem.err.write(tmp, 0, n);\n-\t\t\t\t\t\t\tSystem.err.flush();\n-\t\t\t\t\t\t}\n-\t\t\t\t\t} catch (IOException err) {\n-\t\t\t\t\t\t// Ignore errors reading errors.\n-\t\t\t\t\t} finally {\n-\t\t\t\t\t\ttry {\n-\t\t\t\t\t\t\terrorStream.close();\n-\t\t\t\t\t\t} catch (IOException err2) {\n-\t\t\t\t\t\t\t// Ignore errors closing the pipe.\n-\t\t\t\t\t\t}\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t}.start();\n-\t\t}\n-\n \t\t@Override\n \t\tpublic void close() {\n \t\t\tsuper.close();\n@@ -142,4 +129,60 @@ class TransportLocal extends PackTransport {\n \t\t\t}\n \t\t}\n \t}\n+\n+\tclass LocalPushConnection extends BasePackPushConnection {\n+\t\tprivate Process receivePack;\n+\n+\t\tLocalPushConnection() throws TransportException {\n+\t\t\tsuper(TransportLocal.this);\n+\t\t\treceivePack = startProcessWithErrStream(getOptionReceivePack());\n+\t\t\tinit(receivePack.getInputStream(), receivePack.getOutputStream());\n+\t\t\treadAdvertisedRefs();\n+\t\t}\n+\n+\t\t@Override\n+\t\tpublic void close() {\n+\t\t\tsuper.close();\n+\n+\t\t\tif (receivePack != null) {\n+\t\t\t\ttry {\n+\t\t\t\t\treceivePack.waitFor();\n+\t\t\t\t} catch (InterruptedException ie) {\n+\t\t\t\t\t// Stop waiting and return anyway.\n+\t\t\t\t} finally {\n+\t\t\t\t\treceivePack = null;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tclass StreamRewritingThread extends Thread {\n+\t\tprivate final InputStream in;\n+\n+\t\tStreamRewritingThread(final InputStream in) {\n+\t\t\tsuper(\"JGit \" + getOptionUploadPack() + \" Errors\");\n+\t\t\tthis.in = in;\n+\t\t}\n+\n+\t\tpublic void run() {\n+\t\t\tfinal byte[] tmp = new byte[512];\n+\t\t\ttry {\n+\t\t\t\tfor (;;) {\n+\t\t\t\t\tfinal int n = in.read(tmp);\n+\t\t\t\t\tif (n < 0)\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\tSystem.err.write(tmp, 0, n);\n+\t\t\t\t\tSystem.err.flush();\n+\t\t\t\t}\n+\t\t\t} catch (IOException err) {\n+\t\t\t\t// Ignore errors reading errors.\n+\t\t\t} finally {\n+\t\t\t\ttry {\n+\t\t\t\t\tin.close();\n+\t\t\t\t} catch (IOException err2) {\n+\t\t\t\t\t// Ignore errors closing the pipe.\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkTransport.java b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkTransport.java\nindex ae51d6d..29dd661 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkTransport.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkTransport.java\n@@ -37,6 +37,7 @@\n \n package org.spearce.jgit.transport;\n \n+import org.spearce.jgit.errors.NotSupportedException;\n import org.spearce.jgit.lib.Repository;\n \n /**\n@@ -55,4 +56,10 @@ abstract class WalkTransport extends Transport {\n \tWalkTransport(final Repository local, final URIish u) {\n \t\tsuper(local, u);\n \t}\n+\n+\t@Override\n+\tpublic PushConnection openPush() throws NotSupportedException {\n+\t\tthrow new NotSupportedException(\n+\t\t\t\t\"Push is not supported by object walking transports\");\n+\t}\n }\n-- \n1.5.5.3\n"},{"id":"81494","messageId":"1214604407-30572-18-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-17-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 17/23] Test cases for PushProcess","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:41Z","receivedAt":"2008-06-27T22:06:41Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"Tests for push process with highly differentiated remote update cases,\nthat are possible in practice.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../spearce/jgit/transport/PushProcessTest.java    |  407 ++++++++++++++++++++\n 1 files changed, 407 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/transport/PushProcessTest.java\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/PushProcessTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/PushProcessTest.java\nnew file mode 100644\nindex 0000000..f0cfe98\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/PushProcessTest.java\n@@ -0,0 +1,407 @@\n+/*\n+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>\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.util.HashMap;\n+import java.util.HashSet;\n+import java.util.Map;\n+\n+import org.spearce.jgit.errors.NotSupportedException;\n+import org.spearce.jgit.errors.TransportException;\n+import org.spearce.jgit.lib.ObjectId;\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.lib.RepositoryTestCase;\n+import org.spearce.jgit.lib.TextProgressMonitor;\n+import org.spearce.jgit.lib.RefUpdate.Result;\n+import org.spearce.jgit.transport.RemoteRefUpdate.Status;\n+\n+public class PushProcessTest extends RepositoryTestCase {\n+\tprivate PushProcess process;\n+\n+\tprivate MockTransport transport;\n+\n+\tprivate HashSet<RemoteRefUpdate> refUpdates;\n+\n+\tprivate HashSet<Ref> advertisedRefs;\n+\n+\tprivate Status connectionUpdateStatus;\n+\n+\t@Override\n+\tpublic void setUp() throws Exception {\n+\t\tsuper.setUp();\n+\t\ttransport = new MockTransport(db, new URIish());\n+\t\trefUpdates = new HashSet<RemoteRefUpdate>();\n+\t\tadvertisedRefs = new HashSet<Ref>();\n+\t\tconnectionUpdateStatus = Status.OK;\n+\t}\n+\n+\t/**\n+\t * Test for fast-forward remote update.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateFastForward() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\",\n+\t\t\t\t\"refs/heads/master\", false, null, null);\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\"));\n+\t\ttestOneUpdateStatus(rru, ref, Status.OK, true);\n+\t}\n+\n+\t/**\n+\t * Test for non fast-forward remote update, when remote object is not known\n+\t * to local repository.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateNonFastForwardUnknownObject() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\",\n+\t\t\t\t\"refs/heads/master\", false, null, null);\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"0000000000000000000000000000000000000001\"));\n+\t\ttestOneUpdateStatus(rru, ref, Status.REJECTED_NONFASTFORWARD, null);\n+\t}\n+\n+\t/**\n+\t * Test for non fast-forward remote update, when remote object is known to\n+\t * local repository, but it is not an ancestor of new object.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateNonFastForward() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\",\n+\t\t\t\t\"refs/heads/master\", false, null, null);\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\"));\n+\t\ttestOneUpdateStatus(rru, ref, Status.REJECTED_NONFASTFORWARD, null);\n+\t}\n+\n+\t/**\n+\t * Test for non fast-forward remote update, when force update flag is set.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateNonFastForwardForced() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\",\n+\t\t\t\t\"refs/heads/master\", true, null, null);\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\"));\n+\t\ttestOneUpdateStatus(rru, ref, Status.OK, false);\n+\t}\n+\n+\t/**\n+\t * Test for remote ref creation.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateCreateRef() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\",\n+\t\t\t\t\"refs/heads/master\", false, null, null);\n+\t\ttestOneUpdateStatus(rru, null, Status.OK, true);\n+\t}\n+\n+\t/**\n+\t * Test for remote ref deletion.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateDelete() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db, null,\n+\t\t\t\t\"refs/heads/master\", false, null, null);\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\"));\n+\t\ttestOneUpdateStatus(rru, ref, Status.OK, true);\n+\t}\n+\n+\t/**\n+\t * Test for remote ref deletion (try), when that ref doesn't exist on remote\n+\t * repo.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateDeleteNonExisting() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db, null,\n+\t\t\t\t\"refs/heads/master\", false, null, null);\n+\t\ttestOneUpdateStatus(rru, null, Status.NON_EXISTING, null);\n+\t}\n+\n+\t/**\n+\t * Test for remote ref update, when it is already up to date.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateUpToDate() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\",\n+\t\t\t\t\"refs/heads/master\", false, null, null);\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\"));\n+\t\ttestOneUpdateStatus(rru, ref, Status.UP_TO_DATE, null);\n+\t}\n+\n+\t/**\n+\t * Test for remote ref update with expected remote object.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateExpectedRemote() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\",\n+\t\t\t\t\"refs/heads/master\", false, null, ObjectId\n+\t\t\t\t\t\t.fromString(\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\"));\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\"));\n+\t\ttestOneUpdateStatus(rru, ref, Status.OK, true);\n+\t}\n+\n+\t/**\n+\t * Test for remote ref update with expected old object set, when old object\n+\t * is not that expected one.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateUnexpectedRemote() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\",\n+\t\t\t\t\"refs/heads/master\", false, null, ObjectId\n+\t\t\t\t\t\t.fromString(\"0000000000000000000000000000000000000001\"));\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\"));\n+\t\ttestOneUpdateStatus(rru, ref, Status.REJECTED_REMOTE_CHANGED, null);\n+\t}\n+\n+\t/**\n+\t * Test for remote ref update with expected old object set, when old object\n+\t * is not that expected one and force update flag is set (which should have\n+\t * lower priority) - shouldn't change behavior.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateUnexpectedRemoteVsForce() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\",\n+\t\t\t\t\"refs/heads/master\", true, null, ObjectId\n+\t\t\t\t\t\t.fromString(\"0000000000000000000000000000000000000001\"));\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\"));\n+\t\ttestOneUpdateStatus(rru, ref, Status.REJECTED_REMOTE_CHANGED, null);\n+\t}\n+\n+\t/**\n+\t * Test for remote ref udpate, when connection rejects update.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateRejectedByConnection() throws IOException {\n+\t\tconnectionUpdateStatus = Status.REJECTED_OTHER_REASON;\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\",\n+\t\t\t\t\"refs/heads/master\", false, null, null);\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\"));\n+\t\ttestOneUpdateStatus(rru, ref, Status.REJECTED_OTHER_REASON, null);\n+\t}\n+\n+\t/**\n+\t * Test for remote refs updates with mixed cases that shouldn't depend on\n+\t * each other.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testUpdateMixedCases() throws IOException {\n+\t\tfinal RemoteRefUpdate rruOk = new RemoteRefUpdate(db, null,\n+\t\t\t\t\"refs/heads/master\", false, null, null);\n+\t\tfinal Ref refToChange = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\"));\n+\t\tfinal RemoteRefUpdate rruReject = new RemoteRefUpdate(db, null,\n+\t\t\t\t\"refs/heads/nonexisting\", false, null, null);\n+\t\trefUpdates.add(rruOk);\n+\t\trefUpdates.add(rruReject);\n+\t\tadvertisedRefs.add(refToChange);\n+\t\texecutePush();\n+\t\tassertEquals(Status.OK, rruOk.getStatus());\n+\t\tassertEquals(true, rruOk.isFastForward());\n+\t\tassertEquals(Status.NON_EXISTING, rruReject.getStatus());\n+\t}\n+\n+\t/**\n+\t * Test for local tracking ref update.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testTrackingRefUpdateEnabled() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\",\n+\t\t\t\t\"refs/heads/master\", false, \"refs/remotes/test/master\", null);\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\"));\n+\t\trefUpdates.add(rru);\n+\t\tadvertisedRefs.add(ref);\n+\t\tfinal PushResult result = executePush();\n+\t\tfinal TrackingRefUpdate tru = result\n+\t\t\t\t.getTrackingRefUpdate(\"refs/remotes/test/master\");\n+\t\tassertNotNull(tru);\n+\t\tassertEquals(\"refs/remotes/test/master\", tru.getLocalName());\n+\t\tassertEquals(Result.NEW, tru.getResult());\n+\t}\n+\n+\t/**\n+\t * Test for local tracking ref update disabled.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testTrackingRefUpdateDisabled() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\",\n+\t\t\t\t\"refs/heads/master\", false, null, null);\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\"));\n+\t\trefUpdates.add(rru);\n+\t\tadvertisedRefs.add(ref);\n+\t\tfinal PushResult result = executePush();\n+\t\tassertTrue(result.getTrackingRefUpdates().isEmpty());\n+\t}\n+\n+\t/**\n+\t * Test for local tracking ref update when remote update has failed.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testTrackingRefUpdateOnReject() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\",\n+\t\t\t\t\"refs/heads/master\", false, null, null);\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\"));\n+\t\tfinal PushResult result = testOneUpdateStatus(rru, ref,\n+\t\t\t\tStatus.REJECTED_NONFASTFORWARD, null);\n+\t\tassertTrue(result.getTrackingRefUpdates().isEmpty());\n+\t}\n+\n+\t/**\n+\t * Test for push operation result - that contains expected elements.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testPushResult() throws IOException {\n+\t\tfinal RemoteRefUpdate rru = new RemoteRefUpdate(db,\n+\t\t\t\t\"2c349335b7f797072cf729c4f3bb0914ecb6dec9\",\n+\t\t\t\t\"refs/heads/master\", false, \"refs/remotes/test/master\", null);\n+\t\tfinal Ref ref = new Ref(\"refs/heads/master\", ObjectId\n+\t\t\t\t.fromString(\"ac7e7e44c1885efb472ad54a78327d66bfc4ecef\"));\n+\t\trefUpdates.add(rru);\n+\t\tadvertisedRefs.add(ref);\n+\t\tfinal PushResult result = executePush();\n+\t\tassertEquals(1, result.getTrackingRefUpdates().size());\n+\t\tassertEquals(1, result.getAdvertisedRefs().size());\n+\t\tassertEquals(1, result.getRemoteUpdates().size());\n+\t\tassertNotNull(result.getTrackingRefUpdate(\"refs/remotes/test/master\"));\n+\t\tassertNotNull(result.getAdvertisedRef(\"refs/heads/master\"));\n+\t\tassertNotNull(result.getRemoteUpdate(\"refs/heads/master\"));\n+\t}\n+\n+\tprivate PushResult testOneUpdateStatus(final RemoteRefUpdate rru,\n+\t\t\tfinal Ref advertisedRef, final Status expectedStatus,\n+\t\t\tBoolean fastForward) throws NotSupportedException,\n+\t\t\tTransportException {\n+\t\trefUpdates.add(rru);\n+\t\tif (advertisedRef != null)\n+\t\t\tadvertisedRefs.add(advertisedRef);\n+\t\tfinal PushResult result = executePush();\n+\t\tassertEquals(expectedStatus, rru.getStatus());\n+\t\tif (fastForward != null)\n+\t\t\tassertEquals(fastForward.booleanValue(), rru.isFastForward());\n+\t\treturn result;\n+\t}\n+\n+\tprivate PushResult executePush() throws NotSupportedException,\n+\t\t\tTransportException {\n+\t\tprocess = new PushProcess(transport, refUpdates);\n+\t\treturn process.execute(new TextProgressMonitor());\n+\t}\n+\n+\tprivate class MockTransport extends Transport {\n+\t\tMockTransport(Repository local, URIish uri) {\n+\t\t\tsuper(local, uri);\n+\t\t}\n+\n+\t\t@Override\n+\t\tpublic FetchConnection openFetch() throws NotSupportedException,\n+\t\t\t\tTransportException {\n+\t\t\tthrow new NotSupportedException(\"mock\");\n+\t\t}\n+\n+\t\t@Override\n+\t\tpublic PushConnection openPush() throws NotSupportedException,\n+\t\t\t\tTransportException {\n+\t\t\treturn new MockPushConnection();\n+\t\t}\n+\t}\n+\n+\tprivate class MockPushConnection extends BaseConnection implements\n+\t\t\tPushConnection {\n+\t\tMockPushConnection() {\n+\t\t\tfinal Map<String, Ref> refsMap = new HashMap<String, Ref>();\n+\t\t\tfor (final Ref r : advertisedRefs)\n+\t\t\t\trefsMap.put(r.getName(), r);\n+\t\t\tavailable(refsMap);\n+\t\t}\n+\n+\t\t@Override\n+\t\tpublic void close() {\n+\t\t\t// nothing here\n+\t\t}\n+\n+\t\tpublic void push(ProgressMonitor monitor,\n+\t\t\t\tMap<String, RemoteRefUpdate> refUpdates)\n+\t\t\t\tthrows TransportException {\n+\t\t\tfor (final RemoteRefUpdate rru : refUpdates.values()) {\n+\t\t\t\tassertEquals(Status.NOT_ATTEMPTED, rru.getStatus());\n+\t\t\t\trru.setStatus(connectionUpdateStatus);\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n-- \n1.5.5.3\n"},{"id":"81495","messageId":"1214604407-30572-19-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-18-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 18/23] Test cases for RefSpec to RemoteRefUpdate conversions","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:42Z","receivedAt":"2008-06-27T22:06:42Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"Tests for method Transport#findRemoteRefUpdatesFor().\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../org/spearce/jgit/transport/TransportTest.java  |  181 ++++++++++++++++++++\n 1 files changed, 181 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java\nnew file mode 100644\nindex 0000000..47d738b\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java\n@@ -0,0 +1,181 @@\n+/*\n+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>\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.util.Arrays;\n+import java.util.Collection;\n+import java.util.Collections;\n+\n+import org.spearce.jgit.lib.RepositoryConfig;\n+import org.spearce.jgit.lib.RepositoryTestCase;\n+\n+public class TransportTest extends RepositoryTestCase {\n+\tprivate Transport transport;\n+\n+\tprivate RemoteConfig remoteConfig;\n+\n+\t@Override\n+\tpublic void setUp() throws Exception {\n+\t\tsuper.setUp();\n+\t\tfinal RepositoryConfig config = db.getConfig();\n+\t\tremoteConfig = new RemoteConfig(config, \"test\");\n+\t\tremoteConfig.addURI(new URIish(\"http://everyones.loves.git/u/2\"));\n+\t}\n+\n+\t/**\n+\t * Test RefSpec to RemoteRefUpdate conversion with simple RefSpec - no\n+\t * wildcard, no tracking ref in repo configuration.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testFindRemoteRefUpdatesNoWildcardNoTracking()\n+\t\t\tthrows IOException {\n+\t\ttransport = Transport.open(db, remoteConfig);\n+\t\tfinal Collection<RemoteRefUpdate> result = transport\n+\t\t\t\t.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(\n+\t\t\t\t\t\t\"refs/heads/master:refs/heads/x\")));\n+\n+\t\tassertEquals(1, result.size());\n+\t\tfinal RemoteRefUpdate rru = result.iterator().next();\n+\t\tassertNull(rru.getExpectedOldObjectId());\n+\t\tassertFalse(rru.isForceUpdate());\n+\t\tassertEquals(\"refs/heads/master\", rru.getSrcRef());\n+\t\tassertEquals(db.resolve(\"refs/heads/master\"), rru.getNewObjectId());\n+\t\tassertEquals(\"refs/heads/x\", rru.getRemoteName());\n+\t}\n+\n+\t/**\n+\t * Test RefSpec to RemoteRefUpdate conversion with no-destination RefSpec\n+\t * (destination should be set up for the same name as source).\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testFindRemoteRefUpdatesNoWildcardNoDestination()\n+\t\t\tthrows IOException {\n+\t\ttransport = Transport.open(db, remoteConfig);\n+\t\tfinal Collection<RemoteRefUpdate> result = transport\n+\t\t\t\t.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(\n+\t\t\t\t\t\t\"+refs/heads/master\")));\n+\n+\t\tassertEquals(1, result.size());\n+\t\tfinal RemoteRefUpdate rru = result.iterator().next();\n+\t\tassertNull(rru.getExpectedOldObjectId());\n+\t\tassertTrue(rru.isForceUpdate());\n+\t\tassertEquals(\"refs/heads/master\", rru.getSrcRef());\n+\t\tassertEquals(db.resolve(\"refs/heads/master\"), rru.getNewObjectId());\n+\t\tassertEquals(\"refs/heads/master\", rru.getRemoteName());\n+\t}\n+\n+\t/**\n+\t * Test RefSpec to RemoteRefUpdate conversion with wildcard RefSpec.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testFindRemoteRefUpdatesWildcardNoTracking() throws IOException {\n+\t\ttransport = Transport.open(db, remoteConfig);\n+\t\tfinal Collection<RemoteRefUpdate> result = transport\n+\t\t\t\t.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(\n+\t\t\t\t\t\t\"+refs/heads/*:refs/heads/test/*\")));\n+\n+\t\tassertEquals(7, result.size());\n+\t\tboolean foundA = false;\n+\t\tboolean foundB = false;\n+\t\tfor (final RemoteRefUpdate rru : result) {\n+\t\t\tif (\"refs/heads/a\".equals(rru.getSrcRef())\n+\t\t\t\t\t&& \"refs/heads/test/a\".equals(rru.getRemoteName()))\n+\t\t\t\tfoundA = true;\n+\t\t\tif (\"refs/heads/b\".equals(rru.getSrcRef())\n+\t\t\t\t\t&& \"refs/heads/test/b\".equals(rru.getRemoteName()))\n+\t\t\t\tfoundB = true;\n+\t\t}\n+\t\tassertTrue(foundA);\n+\t\tassertTrue(foundB);\n+\t}\n+\n+\t/**\n+\t * Test RefSpec to RemoteRefUpdate conversion for more than one RefSpecs\n+\t * handling.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testFindRemoteRefUpdatesTwoRefSpecs() throws IOException {\n+\t\ttransport = Transport.open(db, remoteConfig);\n+\t\tfinal RefSpec specA = new RefSpec(\"+refs/heads/a:refs/heads/b\");\n+\t\tfinal RefSpec specC = new RefSpec(\"+refs/heads/c:refs/heads/d\");\n+\t\tfinal Collection<RefSpec> specs = Arrays.asList(specA, specC);\n+\t\tfinal Collection<RemoteRefUpdate> result = transport\n+\t\t\t\t.findRemoteRefUpdatesFor(specs);\n+\n+\t\tassertEquals(2, result.size());\n+\t\tboolean foundA = false;\n+\t\tboolean foundC = false;\n+\t\tfor (final RemoteRefUpdate rru : result) {\n+\t\t\tif (\"refs/heads/a\".equals(rru.getSrcRef())\n+\t\t\t\t\t&& \"refs/heads/b\".equals(rru.getRemoteName()))\n+\t\t\t\tfoundA = true;\n+\t\t\tif (\"refs/heads/c\".equals(rru.getSrcRef())\n+\t\t\t\t\t&& \"refs/heads/d\".equals(rru.getRemoteName()))\n+\t\t\t\tfoundC = true;\n+\t\t}\n+\t\tassertTrue(foundA);\n+\t\tassertTrue(foundC);\n+\t}\n+\n+\t/**\n+\t * Test RefSpec to RemoteRefUpdate conversion for tracking ref search.\n+\t * \n+\t * @throws IOException\n+\t */\n+\tpublic void testFindRemoteRefUpdatesTrackingRef() throws IOException {\n+\t\tremoteConfig.addFetchRefSpec(new RefSpec(\n+\t\t\t\t\"refs/heads/*:refs/remotes/test/*\"));\n+\t\ttransport = Transport.open(db, remoteConfig);\n+\t\tfinal Collection<RemoteRefUpdate> result = transport\n+\t\t\t\t.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(\n+\t\t\t\t\t\t\"+refs/heads/a:refs/heads/a\")));\n+\n+\t\tassertEquals(1, result.size());\n+\t\tfinal TrackingRefUpdate tru = result.iterator().next()\n+\t\t\t\t.getTrackingRefUpdate();\n+\t\tassertEquals(\"refs/remotes/test/a\", tru.getLocalName());\n+\t\tassertEquals(\"refs/heads/a\", tru.getRemoteName());\n+\t\tassertEquals(db.resolve(\"refs/heads/a\"), tru.getNewObjectId());\n+\t\tassertNull(tru.getOldObjectId());\n+\t}\n+}\n-- \n1.5.5.3\n"},{"id":"81500","messageId":"1214604407-30572-20-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-19-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 19/23] Repository search for command line tools","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:43Z","receivedAt":"2008-06-27T22:06:43Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"Introducing some simple search for git repository in parent directories\nof current directory.\n\nPrevious version was annoying: we had to be in directory that contains\n.git/ or specify it explicitly by --git-dir.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../src/org/spearce/jgit/pgm/Main.java             |   24 +++++++++++++++++--\n 1 files changed, 21 insertions(+), 3 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/Main.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/Main.java\nindex 44f8a42..8afd0d7 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/Main.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/Main.java\n@@ -85,12 +85,12 @@ public class Main {\n \n \tprivate static void execute(final String[] argv) throws Exception {\n \t\tint argi = 0;\n-\t\tString gitdir = \".git\";\n \n+\t\tFile gitdir = null;\n \t\tfor (; argi < argv.length; argi++) {\n \t\t\tfinal String arg = argv[argi];\n \t\t\tif (arg.startsWith(\"--git-dir=\"))\n-\t\t\t\tgitdir = arg.substring(\"--git-dir=\".length());\n+\t\t\t\tgitdir = new File(arg.substring(\"--git-dir=\".length()));\n \t\t\telse if (arg.equals(\"--show-stack-trace\"))\n \t\t\t\tshowStackTrace = true;\n \t\t\telse if (arg.startsWith(\"--\"))\n@@ -101,8 +101,15 @@ public class Main {\n \n \t\tif (argi == argv.length)\n \t\t\tusage();\n+\t\tif (gitdir == null)\n+\t\t\tgitdir = findGitDir();\n+\t\tif (gitdir == null || !gitdir.isDirectory()) {\n+\t\t\tSystem.err.println(\"error: can't find git directory\");\n+\t\t\tSystem.exit(1);\n+\t\t}\n+\n \t\tfinal TextBuiltin cmd = createCommand(argv[argi++]);\n-\t\tcmd.db = new Repository(new File(gitdir));\n+\t\tcmd.db = new Repository(gitdir);\n \t\ttry {\n \t\t\tcmd.execute(subarray(argv, argi));\n \t\t} finally {\n@@ -111,6 +118,17 @@ public class Main {\n \t\t}\n \t}\n \n+\tprivate static File findGitDir() {\n+\t\tFile current = new File(\".\").getAbsoluteFile();\n+\t\twhile (current != null) {\n+\t\t\tfinal File gitDir = new File(current, \".git\");\n+\t\t\tif (gitDir.isDirectory())\n+\t\t\t\treturn gitDir;\n+\t\t\tcurrent = current.getParentFile();\n+\t\t}\n+\t\treturn null;\n+\t}\n+\n \tprivate static String[] subarray(final String[] argv, final int i) {\n \t\treturn Arrays.asList(argv).subList(i, argv.length).toArray(\n \t\t\t\tnew String[0]);\n-- \n1.5.5.3\n"},{"id":"81497","messageId":"1214604407-30572-21-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-20-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 20/23] Push command line utility","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:44Z","receivedAt":"2008-06-27T22:06:44Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"pgm.Push class providing command line push utility, similar to C Git\none.\n\nSome shared abbreviating methods for both Fetch and Push are moved to\nTextBuiltin.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../src/org/spearce/jgit/pgm/Fetch.java            |   36 +---\n .../src/org/spearce/jgit/pgm/Push.java             |  235 ++++++++++++++++++++\n .../src/org/spearce/jgit/pgm/TextBuiltin.java      |   21 ++\n 3 files changed, 262 insertions(+), 30 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java\nindex 3a81575..c9c997e 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java\n@@ -40,8 +40,6 @@ package org.spearce.jgit.pgm;\n import java.util.ArrayList;\n import java.util.List;\n \n-import org.spearce.jgit.lib.Constants;\n-import org.spearce.jgit.lib.ObjectId;\n import org.spearce.jgit.lib.RefUpdate;\n import org.spearce.jgit.lib.TextProgressMonitor;\n import org.spearce.jgit.transport.FetchResult;\n@@ -50,12 +48,6 @@ import org.spearce.jgit.transport.TrackingRefUpdate;\n import org.spearce.jgit.transport.Transport;\n \n class Fetch extends TextBuiltin {\n-\tprivate static final String REFS_HEADS = Constants.HEADS_PREFIX + \"/\";\n-\n-\tprivate static final String REFS_REMOTES = Constants.REMOTES_PREFIX + \"/\";\n-\n-\tprivate static final String REFS_TAGS = Constants.TAGS_PREFIX + \"/\";\n-\n \t@Override\n \tvoid execute(String[] args) throws Exception {\n \t\tint argi = 0;\n@@ -84,20 +76,8 @@ class Fetch extends TextBuiltin {\n \t\tfor (final TrackingRefUpdate u : r.getTrackingRefUpdates()) {\n \t\t\tfinal char type = shortTypeOf(u.getResult());\n \t\t\tfinal String longType = longTypeOf(u);\n-\n-\t\t\tString src = u.getRemoteName();\n-\t\t\tif (src.startsWith(REFS_HEADS))\n-\t\t\t\tsrc = src.substring(REFS_HEADS.length());\n-\t\t\telse if (src.startsWith(REFS_TAGS))\n-\t\t\t\tsrc = src.substring(REFS_TAGS.length());\n-\n-\t\t\tString dst = u.getLocalName();\n-\t\t\tif (dst.startsWith(REFS_HEADS))\n-\t\t\t\tdst = dst.substring(REFS_HEADS.length());\n-\t\t\telse if (dst.startsWith(REFS_TAGS))\n-\t\t\t\tdst = dst.substring(REFS_TAGS.length());\n-\t\t\telse if (dst.startsWith(REFS_REMOTES))\n-\t\t\t\tdst = dst.substring(REFS_REMOTES.length());\n+\t\t\tfinal String src = abbreviateRef(u.getRemoteName(), false);\n+\t\t\tfinal String dst = abbreviateRef(u.getLocalName(), true);\n \n \t\t\tout.format(\" %c %-17s %-10s -> %s\", type, longType, src, dst);\n \t\t\tout.println();\n@@ -121,14 +101,14 @@ class Fetch extends TextBuiltin {\n \t\t}\n \n \t\tif (r == RefUpdate.Result.FORCED) {\n-\t\t\tfinal String aOld = abbreviate(u.getOldObjectId());\n-\t\t\tfinal String aNew = abbreviate(u.getNewObjectId());\n+\t\t\tfinal String aOld = abbreviateObject(u.getOldObjectId());\n+\t\t\tfinal String aNew = abbreviateObject(u.getNewObjectId());\n \t\t\treturn aOld + \"...\" + aNew;\n \t\t}\n \n \t\tif (r == RefUpdate.Result.FAST_FORWARD) {\n-\t\t\tfinal String aOld = abbreviate(u.getOldObjectId());\n-\t\t\tfinal String aNew = abbreviate(u.getNewObjectId());\n+\t\t\tfinal String aOld = abbreviateObject(u.getOldObjectId());\n+\t\t\tfinal String aNew = abbreviateObject(u.getNewObjectId());\n \t\t\treturn aOld + \"..\" + aNew;\n \t\t}\n \n@@ -139,10 +119,6 @@ class Fetch extends TextBuiltin {\n \t\treturn \"[\" + r.name() + \"]\";\n \t}\n \n-\tprivate static String abbreviate(final ObjectId id) {\n-\t\treturn id.toString().substring(0, 7);\n-\t}\n-\n \tprivate static char shortTypeOf(final RefUpdate.Result r) {\n \t\tif (r == RefUpdate.Result.LOCK_FAILURE)\n \t\t\treturn '!';\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java\nnew file mode 100644\nindex 0000000..4130bc9\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java\n@@ -0,0 +1,235 @@\n+/*\n+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>\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.pgm;\n+\n+import java.util.Collection;\n+import java.util.LinkedList;\n+\n+import org.spearce.jgit.lib.Ref;\n+import org.spearce.jgit.lib.TextProgressMonitor;\n+import org.spearce.jgit.transport.PushResult;\n+import org.spearce.jgit.transport.RefSpec;\n+import org.spearce.jgit.transport.RemoteRefUpdate;\n+import org.spearce.jgit.transport.Transport;\n+import org.spearce.jgit.transport.RemoteRefUpdate.Status;\n+\n+class Push extends TextBuiltin {\n+\n+\tprivate boolean verbose = false;\n+\n+\tprivate Transport transport;\n+\n+\tprivate boolean first = true;\n+\n+\t@Override\n+\tvoid execute(String[] args) throws Exception {\n+\t\tfinal LinkedList<RefSpec> refSpecs = new LinkedList<RefSpec>();\n+\t\tBoolean thin = null;\n+\t\tString exec = null;\n+\t\tboolean forceAll = false;\n+\n+\t\tint argi = 0;\n+\t\tfor (; argi < args.length; argi++) {\n+\t\t\tfinal String a = args[argi];\n+\t\t\tif (\"--thin\".equals(a))\n+\t\t\t\tthin = true;\n+\t\t\telse if (\"--no-thin\".equals(a))\n+\t\t\t\tthin = false;\n+\t\t\telse if (\"-f\".equals(a) || \"--force\".equals(a))\n+\t\t\t\tforceAll = true;\n+\t\t\telse if (a.startsWith(\"--exec=\"))\n+\t\t\t\texec = a.substring(\"--exec=\".length());\n+\t\t\telse if (a.startsWith(\"--receive-pack=\"))\n+\t\t\t\texec = a.substring(\"--receive-pack=\".length());\n+\t\t\telse if (\"--tags\".equals(a))\n+\t\t\t\trefSpecs.add(Transport.REFSPEC_TAGS);\n+\t\t\telse if (\"--all\".equals(a))\n+\t\t\t\trefSpecs.add(Transport.REFSPEC_PUSH_ALL);\n+\t\t\telse if (\"-v\".equals(a))\n+\t\t\t\tverbose = true;\n+\t\t\telse if (\"--\".equals(a)) {\n+\t\t\t\targi++;\n+\t\t\t\tbreak;\n+\t\t\t} else if (a.startsWith(\"-\"))\n+\t\t\t\tdie(\"usage: push [--all] [--tags] [--force] [--thin]\\n\"\n+\t\t\t\t\t\t+ \"[--receive-pack=<git-receive-pack>] [<repository> [<refspec>]...]\");\n+\t\t\telse\n+\t\t\t\tbreak;\n+\t\t}\n+\n+\t\tfinal String repository;\n+\t\tif (argi == args.length)\n+\t\t\trepository = \"origin\";\n+\t\telse\n+\t\t\trepository = args[argi++];\n+\t\ttransport = Transport.open(db, repository);\n+\t\tif (thin != null)\n+\t\t\ttransport.setPushThin(thin);\n+\t\tif (exec != null)\n+\t\t\ttransport.setOptionReceivePack(exec);\n+\n+\t\tfor (; argi < args.length; argi++) {\n+\t\t\tfinal RefSpec spec = new RefSpec(args[argi]);\n+\t\t\tif (forceAll)\n+\t\t\t\tspec.setForceUpdate(true);\n+\t\t\trefSpecs.add(spec);\n+\t\t}\n+\t\tfinal Collection<RemoteRefUpdate> toPush = transport\n+\t\t\t\t.findRemoteRefUpdatesFor(refSpecs);\n+\n+\t\tfinal PushResult result = transport.push(new TextProgressMonitor(),\n+\t\t\t\ttoPush);\n+\t\tprintPushResult(result);\n+\t}\n+\n+\tprivate void printPushResult(final PushResult result) {\n+\t\tboolean everythingUpToDate = true;\n+\t\t// at first, print up-to-date ones...\n+\t\tfor (final RemoteRefUpdate rru : result.getRemoteUpdates()) {\n+\t\t\tif (rru.getStatus() == Status.UP_TO_DATE) {\n+\t\t\t\tif (verbose)\n+\t\t\t\t\tprintRefUpdateResult(result, rru);\n+\t\t\t} else\n+\t\t\t\teverythingUpToDate = false;\n+\t\t}\n+\n+\t\tfor (final RemoteRefUpdate rru : result.getRemoteUpdates()) {\n+\t\t\t// ...then successful updates...\n+\t\t\tif (rru.getStatus() == Status.OK)\n+\t\t\t\tprintRefUpdateResult(result, rru);\n+\t\t}\n+\n+\t\tfor (final RemoteRefUpdate rru : result.getRemoteUpdates()) {\n+\t\t\t// ...finally, others (problematic)\n+\t\t\tif (rru.getStatus() != Status.OK\n+\t\t\t\t\t&& rru.getStatus() != Status.UP_TO_DATE)\n+\t\t\t\tprintRefUpdateResult(result, rru);\n+\t\t}\n+\n+\t\tif (everythingUpToDate)\n+\t\t\tout.println(\"Everything up-to-date\");\n+\t}\n+\n+\tprivate void printRefUpdateResult(final PushResult result,\n+\t\t\tfinal RemoteRefUpdate rru) {\n+\t\tif (first) {\n+\t\t\tfirst = false;\n+\t\t\tout.format(\"To %s\\n\", transport.getURI());\n+\t\t}\n+\n+\t\tfinal String remoteName = rru.getRemoteName();\n+\t\tfinal String srcRef = rru.isDelete() ? null : rru.getSrcRef();\n+\n+\t\tswitch (rru.getStatus()) {\n+\t\tcase OK:\n+\t\t\tif (rru.isDelete())\n+\t\t\t\tprintUpdateLine('-', \"[deleted]\", null, remoteName, null);\n+\t\t\telse {\n+\t\t\t\tfinal Ref oldRef = result.getAdvertisedRef(remoteName);\n+\t\t\t\tif (oldRef == null) {\n+\t\t\t\t\tfinal String summary;\n+\t\t\t\t\tif (remoteName.startsWith(REFS_TAGS))\n+\t\t\t\t\t\tsummary = \"[new tag]\";\n+\t\t\t\t\telse\n+\t\t\t\t\t\tsummary = \"[new branch]\";\n+\t\t\t\t\tprintUpdateLine('*', summary, srcRef, remoteName, null);\n+\t\t\t\t} else {\n+\t\t\t\t\tboolean fastForward = rru.isFastForward();\n+\t\t\t\t\tfinal char flag = fastForward ? ' ' : '+';\n+\t\t\t\t\tfinal String summary = abbreviateObject(oldRef\n+\t\t\t\t\t\t\t.getObjectId())\n+\t\t\t\t\t\t\t+ (fastForward ? \"..\" : \"...\")\n+\t\t\t\t\t\t\t+ abbreviateObject(rru.getNewObjectId());\n+\t\t\t\t\tfinal String message = fastForward ? null : \"forced update\";\n+\t\t\t\t\tprintUpdateLine(flag, summary, srcRef, remoteName, message);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase NON_EXISTING:\n+\t\t\tprintUpdateLine('X', \"[no match]\", null, remoteName, null);\n+\t\t\tbreak;\n+\n+\t\tcase REJECTED_NODELETE:\n+\t\t\tprintUpdateLine('!', \"[rejected]\", null, remoteName,\n+\t\t\t\t\t\"remote side does not support deleting refs\");\n+\t\t\tbreak;\n+\n+\t\tcase REJECTED_NONFASTFORWARD:\n+\t\t\tprintUpdateLine('!', \"[rejected]\", srcRef, remoteName,\n+\t\t\t\t\t\"non-fast forward\");\n+\t\t\tbreak;\n+\n+\t\tcase REJECTED_REMOTE_CHANGED:\n+\t\t\tfinal String message = \"remote ref object changed - is not expected one \"\n+\t\t\t\t\t+ abbreviateObject(rru.getExpectedOldObjectId());\n+\t\t\tprintUpdateLine('!', \"[rejected]\", srcRef, remoteName, message);\n+\t\t\tbreak;\n+\n+\t\tcase REJECTED_OTHER_REASON:\n+\t\t\tprintUpdateLine('!', \"[remote rejected]\", srcRef, remoteName, rru\n+\t\t\t\t\t.getMessage());\n+\t\t\tbreak;\n+\n+\t\tcase UP_TO_DATE:\n+\t\t\tif (verbose)\n+\t\t\t\tprintUpdateLine('=', \"[up to date]\", srcRef, remoteName, null);\n+\t\t\tbreak;\n+\n+\t\tcase NOT_ATTEMPTED:\n+\t\tcase AWAITING_REPORT:\n+\t\t\tprintUpdateLine('?', \"[unexpected push-process behavior]\", srcRef,\n+\t\t\t\t\tremoteName, rru.getMessage());\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tprivate void printUpdateLine(final char flag, final String summary,\n+\t\t\tfinal String srcRef, final String destRef, final String message) {\n+\t\tout.format(\" %c %-17s\", flag, summary);\n+\n+\t\tif (srcRef != null)\n+\t\t\tout.format(\" %s ->\", abbreviateRef(srcRef, true));\n+\t\tout.format(\" %s\", abbreviateRef(destRef, true));\n+\n+\t\tif (message != null)\n+\t\t\tout.format(\" (%s)\", message);\n+\n+\t\tout.println();\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/TextBuiltin.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/TextBuiltin.java\nindex 163f795..b3d8f39 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/TextBuiltin.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/TextBuiltin.java\n@@ -43,10 +43,17 @@ import java.io.IOException;\n import java.io.OutputStreamWriter;\n import java.io.PrintWriter;\n \n+import org.spearce.jgit.lib.Constants;\n import org.spearce.jgit.lib.ObjectId;\n import org.spearce.jgit.lib.Repository;\n \n abstract class TextBuiltin {\n+\tprotected static final String REFS_HEADS = Constants.HEADS_PREFIX + \"/\";\n+\n+\tprotected static final String REFS_REMOTES = Constants.REMOTES_PREFIX + \"/\";\n+\n+\tprotected static final String REFS_TAGS = Constants.TAGS_PREFIX + \"/\";\n+\n \tprotected PrintWriter out;\n \n \tprotected Repository db;\n@@ -72,4 +79,18 @@ abstract class TextBuiltin {\n \tprotected static Die die(final String why) {\n \t\treturn new Die(why);\n \t}\n+\n+\tprotected static String abbreviateObject(final ObjectId id) {\n+\t\treturn id.toString().substring(0, 7);\n+\t}\n+\n+\tprotected String abbreviateRef(String dst, boolean abbreviateRemote) {\n+\t\tif (dst.startsWith(REFS_HEADS))\n+\t\t\tdst = dst.substring(REFS_HEADS.length());\n+\t\telse if (dst.startsWith(REFS_TAGS))\n+\t\t\tdst = dst.substring(REFS_TAGS.length());\n+\t\telse if (abbreviateRemote && dst.startsWith(REFS_REMOTES))\n+\t\t\tdst = dst.substring(REFS_REMOTES.length());\n+\t\treturn dst;\n+\t}\n }\n-- \n1.5.5.3\n"},{"id":"81501","messageId":"1214604407-30572-22-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-21-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 21/23] Don't accept RefSpec with null source for fetch","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:45Z","receivedAt":"2008-06-27T22:06:45Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"RefSpec with null source has no sense, so let's inform about it.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../org/spearce/jgit/transport/FetchProcess.java   |    4 ++++\n .../src/org/spearce/jgit/transport/Transport.java  |    5 +++--\n 2 files changed, 7 insertions(+), 2 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\nindex c765c12..f9c2266 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\n@@ -100,6 +100,10 @@ class FetchProcess {\n \t\t\tresult.setAdvertisedRefs(conn.getRefsMap());\n \t\t\tfinal Set<Ref> matched = new HashSet<Ref>();\n \t\t\tfor (final RefSpec spec : toFetch) {\n+\t\t\t\tif (spec.getSource() == null)\n+\t\t\t\t\tthrow new TransportException(\n+\t\t\t\t\t\t\t\"Source ref not specified for refspec: \" + spec);\n+\n \t\t\t\tif (spec.isWildcard())\n \t\t\t\t\texpandWildcard(spec, matched);\n \t\t\t\telse\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 da5b41e..8260da6 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@@ -363,14 +363,15 @@ public abstract class Transport {\n \t * @param toFetch\n \t *            specification of refs to fetch locally. May be null or the\n \t *            empty collection to use the specifications from the\n-\t *            RemoteConfig.\n+\t *            RemoteConfig. Source for each RefSpec can't be null.\n \t * @return information describing the tracking refs updated.\n \t * @throws NotSupportedException\n \t *             this transport implementation does not support fetching\n \t *             objects.\n \t * @throws TransportException\n \t *             the remote connection could not be established or object\n-\t *             copying (if necessary) failed.\n+\t *             copying (if necessary) failed or update specification was\n+\t *             incorrect.\n \t */\n \tpublic FetchResult fetch(final ProgressMonitor monitor,\n \t\t\tCollection<RefSpec> toFetch) throws NotSupportedException,\n-- \n1.5.5.3\n"},{"id":"81498","messageId":"1214604407-30572-23-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-22-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 22/23] Add new handy constructors to TransportException, PackProtocolException","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:46Z","receivedAt":"2008-06-27T22:06:46Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"Constructor takes additionally URI argument, to add prefix: uri + \": \"\nbefore real message. Now we don't have to remember about ugly (uri + \":\n\") prefix in each thrown message;\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../spearce/jgit/errors/PackProtocolException.java |   30 +++++++++++++++++++\n .../spearce/jgit/errors/TransportException.java    |   31 ++++++++++++++++++++\n 2 files changed, 61 insertions(+), 0 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/errors/PackProtocolException.java b/org.spearce.jgit/src/org/spearce/jgit/errors/PackProtocolException.java\nindex 525496a..7b5b4f6 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/errors/PackProtocolException.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/errors/PackProtocolException.java\n@@ -38,6 +38,7 @@\n \n package org.spearce.jgit.errors;\n \n+import org.spearce.jgit.transport.URIish;\n \n /**\n  * Indicates a protocol error has occurred while fetching/pushing objects.\n@@ -46,6 +47,35 @@ public class PackProtocolException extends TransportException {\n \tprivate static final long serialVersionUID = 1L;\n \n \t/**\n+\t * Constructs an PackProtocolException with the specified detail message\n+\t * prefixed with provided URI.\n+\t * \n+\t * @param uri\n+\t *            URI used for transport\n+\t * @param s\n+\t *            message\n+\t */\n+\tpublic PackProtocolException(final URIish uri, final String s) {\n+\t\tsuper(uri + \": \" + s);\n+\t}\n+\n+\t/**\n+\t * Constructs an PackProtocolException with the specified detail message\n+\t * prefixed with provided URI.\n+\t * \n+\t * @param uri\n+\t *            URI used for transport\n+\t * @param s\n+\t *            message\n+\t * @param cause\n+\t *            root cause exception\n+\t */\n+\tpublic PackProtocolException(final URIish uri, final String s,\n+\t\t\tfinal Throwable cause) {\n+\t\tthis(uri + \": \" + s, cause);\n+\t}\n+\n+\t/**\n \t * Constructs an PackProtocolException with the specified detail message.\n \t * \n \t * @param s\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/errors/TransportException.java b/org.spearce.jgit/src/org/spearce/jgit/errors/TransportException.java\nindex 7b378db..13c7a28 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/errors/TransportException.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/errors/TransportException.java\n@@ -40,6 +40,8 @@ package org.spearce.jgit.errors;\n \n import java.io.IOException;\n \n+import org.spearce.jgit.transport.URIish;\n+\n /**\n  * Indicates a protocol error has occurred while fetching/pushing objects.\n  */\n@@ -47,6 +49,35 @@ public class TransportException extends IOException {\n \tprivate static final long serialVersionUID = 1L;\n \n \t/**\n+\t * Constructs an TransportException with the specified detail message\n+\t * prefixed with provided URI.\n+\t * \n+\t * @param uri\n+\t *            URI used for transport\n+\t * @param s\n+\t *            message\n+\t */\n+\tpublic TransportException(final URIish uri, final String s) {\n+\t\tsuper(uri + \": \" + s);\n+\t}\n+\n+\t/**\n+\t * Constructs an TransportException with the specified detail message\n+\t * prefixed with provided URI.\n+\t * \n+\t * @param uri\n+\t *            URI used for transport\n+\t * @param s\n+\t *            message\n+\t * @param cause\n+\t *            root cause exception\n+\t */\n+\tpublic TransportException(final URIish uri, final String s,\n+\t\t\tfinal Throwable cause) {\n+\t\tthis(uri + \": \" + s, cause);\n+\t}\n+\n+\t/**\n \t * Constructs an TransportException with the specified detail message.\n \t * \n \t * @param s\n-- \n1.5.5.3\n"},{"id":"81499","messageId":"1214604407-30572-24-git-send-email-marek.zawirski@gmail.com","threadId":"14194","inReplyTo":"1214604407-30572-23-git-send-email-marek.zawirski@gmail.com","subject":"[EGIT PATCH 23/23] Use new TransportException constructors","fromName":"Marek Zawirski","fromEmail":"marek.zawirski@gmail.com","sentAt":"2008-06-27T22:06:47Z","receivedAt":"2008-06-27T22:06:47Z","isPatch":true,"sender":{"key":"marek.zawirski@gmail.com","avatar":null},"body":"Modify existing TransportException constructor calls to new ones with\nURI as argument.\n\nSigned-off-by: Marek Zawirski <marek.zawirski@gmail.com>\n---\n .../spearce/jgit/transport/BasePackConnection.java |    6 +++---\n .../jgit/transport/BasePackPushConnection.java     |   12 ++++++------\n .../org/spearce/jgit/transport/PushProcess.java    |    6 +++---\n .../spearce/jgit/transport/TransportGitAnon.java   |   15 +++++++--------\n .../spearce/jgit/transport/TransportGitSsh.java    |   18 ++++++++----------\n .../org/spearce/jgit/transport/TransportLocal.java |    3 +--\n .../org/spearce/jgit/transport/TransportSftp.java  |   12 +++++-------\n 7 files changed, 33 insertions(+), 39 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 d119672..9b39ebc 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@@ -125,7 +125,7 @@ abstract class BasePackConnection extends BaseConnection {\n \t\t\t\tline = pckIn.readString();\n \t\t\t} catch (EOFException eof) {\n \t\t\t\tif (avail.isEmpty())\n-\t\t\t\t\tthrow new TransportException(uri + \" not found.\");\n+\t\t\t\t\tthrow new TransportException(uri, \"not found.\");\n \t\t\t\tthrow eof;\n \t\t\t}\n \n@@ -155,7 +155,7 @@ abstract class BasePackConnection extends BaseConnection {\n \t\t\t\tname = name.substring(0, name.length() - 3);\n \t\t\t\tfinal Ref prior = avail.get(name);\n \t\t\t\tif (prior == null)\n-\t\t\t\t\tthrow new PackProtocolException(uri + \": advertisement of \"\n+\t\t\t\t\tthrow new PackProtocolException(uri, \"advertisement of \"\n \t\t\t\t\t\t\t+ name + \"^{} came before \" + name);\n \n \t\t\t\tif (prior.getPeeledObjectId() != null)\n@@ -185,7 +185,7 @@ abstract class BasePackConnection extends BaseConnection {\n \t}\n \n \tprivate PackProtocolException duplicateAdvertisement(final String name) {\n-\t\treturn new PackProtocolException(uri + \": duplicate advertisements of \"\n+\t\treturn new PackProtocolException(uri, \"duplicate advertisements of \"\n \t\t\t\t+ name);\n \t}\n \ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java\nindex 159e331..c56605a 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java\n@@ -110,7 +110,7 @@ class BasePackPushConnection extends BasePackConnection implements\n \t\t} catch (TransportException e) {\n \t\t\tthrow e;\n \t\t} catch (Exception e) {\n-\t\t\tthrow new TransportException(uri + \": \" + e.getMessage(), e);\n+\t\t\tthrow new TransportException(uri, e.getMessage(), e);\n \t\t} finally {\n \t\t\tclose();\n \t\t}\n@@ -146,7 +146,7 @@ class BasePackPushConnection extends BasePackConnection implements\n \t\t}\n \n \t\tif (monitor.isCancelled())\n-\t\t\tthrow new TransportException(uri + \": push cancelled\");\n+\t\t\tthrow new TransportException(uri, \"push cancelled\");\n \t\tpckOut.end();\n \t}\n \n@@ -179,13 +179,13 @@ class BasePackPushConnection extends BasePackConnection implements\n \t\t\tthrows IOException {\n \t\tfinal String unpackLine = pckIn.readString();\n \t\tif (!unpackLine.startsWith(\"unpack \"))\n-\t\t\tthrow new PackProtocolException(uri + \": unexpected report line: \"\n+\t\t\tthrow new PackProtocolException(uri, \"unexpected report line: \"\n \t\t\t\t\t+ unpackLine);\n \t\tfinal String unpackStatus = unpackLine.substring(\"unpack \".length());\n \t\tif (!unpackStatus.equals(\"ok\"))\n-\t\t\tthrow new TransportException(uri\n-\t\t\t\t\t+ \": error occurred during unpacking on the remote end: \"\n-\t\t\t\t\t+ unpackStatus);\n+\t\t\tthrow new TransportException(uri,\n+\t\t\t\t\t\"error occurred during unpacking on the remote end: \"\n+\t\t\t\t\t\t\t+ unpackStatus);\n \n \t\tString refLine;\n \t\twhile ((refLine = pckIn.readString()).length() > 0) {\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java\nindex f742949..1b5f9c6 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java\n@@ -178,9 +178,9 @@ class PushProcess {\n \t\t\t} catch (MissingObjectException x) {\n \t\t\t\tfastForward = false;\n \t\t\t} catch (Exception x) {\n-\t\t\t\tthrow new TransportException(transport.getURI()\n-\t\t\t\t\t\t+ \": reading objects from local repository failed: \"\n-\t\t\t\t\t\t+ x.getMessage(), x);\n+\t\t\t\tthrow new TransportException(transport.getURI(),\n+\t\t\t\t\t\t\"reading objects from local repository failed: \"\n+\t\t\t\t\t\t\t\t+ x.getMessage(), x);\n \t\t\t}\n \t\t\trru.setFastForward(fastForward);\n \t\t\tif (!fastForward && !rru.isForceUpdate())\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java\nindex 6e49083..8a78099 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java\n@@ -82,12 +82,11 @@ class TransportGitAnon extends PackTransport {\n \t\ttry {\n \t\t\treturn new Socket(InetAddress.getByName(uri.getHost()), port);\n \t\t} catch (IOException c) {\n-\t\t\tfinal String us = uri.toString();\n \t\t\tif (c instanceof UnknownHostException)\n-\t\t\t\tthrow new TransportException(us + \": Unknown host\");\n+\t\t\t\tthrow new TransportException(uri, \"unknown host\");\n \t\t\tif (c instanceof ConnectException)\n-\t\t\t\tthrow new TransportException(us + \": \" + c.getMessage());\n-\t\t\tthrow new TransportException(us + \": \" + c.getMessage(), c);\n+\t\t\t\tthrow new TransportException(uri, c.getMessage());\n+\t\t\tthrow new TransportException(uri, c.getMessage(), c);\n \t\t}\n \t}\n \n@@ -116,8 +115,8 @@ class TransportGitAnon extends PackTransport {\n \t\t\t\tservice(\"git-upload-pack\", pckOut);\n \t\t\t} catch (IOException err) {\n \t\t\t\tclose();\n-\t\t\t\tthrow new TransportException(uri.toString()\n-\t\t\t\t\t\t+ \": remote hung up unexpectedly\", err);\n+\t\t\t\tthrow new TransportException(uri,\n+\t\t\t\t\t\t\"remote hung up unexpectedly\", err);\n \t\t\t}\n \t\t\treadAdvertisedRefs();\n \t\t}\n@@ -149,8 +148,8 @@ class TransportGitAnon extends PackTransport {\n \t\t\t\tservice(\"git-receive-pack\", pckOut);\n \t\t\t} catch (IOException err) {\n \t\t\t\tclose();\n-\t\t\t\tthrow new TransportException(uri.toString()\n-\t\t\t\t\t\t+ \": remote hung up unexpectedly\", err);\n+\t\t\t\tthrow new TransportException(uri,\n+\t\t\t\t\t\t\"remote hung up unexpectedly\", err);\n \t\t\t}\n \t\t\treadAdvertisedRefs();\n \t\t}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java\nindex 55be4f6..46c60c3 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java\n@@ -162,13 +162,12 @@ class TransportGitSsh extends PackTransport {\n \t\t\t\tsession.connect();\n \t\t\treturn session;\n \t\t} catch (JSchException je) {\n-\t\t\tfinal String us = uri.toString();\n \t\t\tfinal Throwable c = je.getCause();\n \t\t\tif (c instanceof UnknownHostException)\n-\t\t\t\tthrow new TransportException(us + \": Unknown host\");\n+\t\t\t\tthrow new TransportException(uri, \"unknown host\");\n \t\t\tif (c instanceof ConnectException)\n-\t\t\t\tthrow new TransportException(us + \": \" + c.getMessage());\n-\t\t\tthrow new TransportException(us + \": \" + je.getMessage(), je);\n+\t\t\t\tthrow new TransportException(uri, c.getMessage());\n+\t\t\tthrow new TransportException(uri, je.getMessage(), je);\n \t\t}\n \t}\n \n@@ -189,8 +188,7 @@ class TransportGitSsh extends PackTransport {\n \t\t\tchannel.connect();\n \t\t\treturn channel;\n \t\t} catch (JSchException je) {\n-\t\t\tthrow new TransportException(uri.toString() + \": \"\n-\t\t\t\t\t+ je.getMessage(), je);\n+\t\t\tthrow new TransportException(uri, je.getMessage(), je);\n \t\t}\n \t}\n \n@@ -210,8 +208,8 @@ class TransportGitSsh extends PackTransport {\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(uri.toString()\n-\t\t\t\t\t\t+ \": remote hung up unexpectedly\", err);\n+\t\t\t\tthrow new TransportException(uri,\n+\t\t\t\t\t\t\"remote hung up unexpectedly\", err);\n \t\t\t}\n \t\t\treadAdvertisedRefs();\n \t\t}\n@@ -255,8 +253,8 @@ class TransportGitSsh extends PackTransport {\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(uri.toString()\n-\t\t\t\t\t\t+ \": remote hung up unexpectedly\", err);\n+\t\t\t\tthrow new TransportException(uri,\n+\t\t\t\t\t\t\"remote hung up unexpectedly\", err);\n \t\t\t}\n \t\t\treadAdvertisedRefs();\n \t\t}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\nindex f48dc6d..761d1b8 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\n@@ -99,8 +99,7 @@ class TransportLocal extends PackTransport {\n \t\t\tnew StreamRewritingThread(proc.getErrorStream()).start();\n \t\t\treturn proc;\n \t\t} catch (IOException err) {\n-\t\t\tthrow new TransportException(uri.toString() + \": \"\n-\t\t\t\t\t+ err.getMessage(), err);\n+\t\t\tthrow new TransportException(uri, err.getMessage(), err);\n \t\t}\n \t}\n \ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportSftp.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportSftp.java\nindex cfe22c1..21657ef 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportSftp.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportSftp.java\n@@ -111,13 +111,12 @@ class TransportSftp extends WalkTransport {\n \t\t\t\tsession.connect();\n \t\t\treturn session;\n \t\t} catch (JSchException je) {\n-\t\t\tfinal String us = uri.toString();\n \t\t\tfinal Throwable c = je.getCause();\n \t\t\tif (c instanceof UnknownHostException)\n-\t\t\t\tthrow new TransportException(us + \": Unknown host\");\n+\t\t\t\tthrow new TransportException(uri, \"unknown host\");\n \t\t\tif (c instanceof ConnectException)\n-\t\t\t\tthrow new TransportException(us + \": \" + c.getMessage());\n-\t\t\tthrow new TransportException(us + \": \" + je.getMessage(), je);\n+\t\t\t\tthrow new TransportException(uri, c.getMessage());\n+\t\t\tthrow new TransportException(uri, je.getMessage(), je);\n \t\t}\n \t}\n \n@@ -127,8 +126,7 @@ class TransportSftp extends WalkTransport {\n \t\t\tchannel.connect();\n \t\t\treturn (ChannelSftp) channel;\n \t\t} catch (JSchException je) {\n-\t\t\tthrow new TransportException(uri.toString() + \": \"\n-\t\t\t\t\t+ je.getMessage(), je);\n+\t\t\tthrow new TransportException(uri, je.getMessage(), je);\n \t\t}\n \t}\n \n@@ -259,7 +257,7 @@ class TransportSftp extends WalkTransport {\n \t\t\t} catch (FileNotFoundException notPacked) {\n \t\t\t\t// Perhaps it wasn't worthwhile, or is just an older repository.\n \t\t\t} catch (IOException e) {\n-\t\t\t\tthrow new TransportException(uri + \": error in packed-refs\", e);\n+\t\t\t\tthrow new TransportException(uri, \"error in packed-refs\", e);\n \t\t\t}\n \t\t\treadRef(avail, \"../HEAD\", \"HEAD\");\n \t\t\treadLooseRefs(avail, \"../refs\", \"refs/\");\n-- \n1.5.5.3\n"},{"id":"81515","messageId":"200806280125.13106.robin.rosenberg@dewire.com","threadId":"14194","inReplyTo":"1214604407-30572-1-git-send-email-marek.zawirski@gmail.com","subject":"Re: [EGIT PATCH 00/23] Push implementation","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2008-06-27T23:25:12Z","receivedAt":"2008-06-27T23:25:12Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"lördagen den 28 juni 2008 00.06.24 skrev Marek Zawirski:\n> Finally, series with push implementation. It has taken a \"while\" to\n> squash all bugs this time and polish the series, uhh.\n\nThis will make fine weekend reading :)\n\n-- robin\n"},{"id":"81554","messageId":"200806281436.21264.robin.rosenberg.lists@dewire.com","threadId":"14194","inReplyTo":"1214604407-30572-21-git-send-email-marek.zawirski@gmail.com","subject":"Re: [EGIT PATCH 20/23] Push command line utility","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg.lists@dewire.com","sentAt":"2008-06-28T12:36:21Z","receivedAt":"2008-06-28T12:36:21Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"Marek, \n\nRefSpecs are unmutable classes. I Can squeeze this into the patchset.  \n\nOther than that, impressive!\n\n-- robin\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java\nindex 4130bc9..cbdf465 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java\n@@ -104,9 +104,9 @@ class Push extends TextBuiltin {\n                        transport.setOptionReceivePack(exec);\n\n                for (; argi < args.length; argi++) {\n-                       final RefSpec spec = new RefSpec(args[argi]);\n+                       RefSpec spec = new RefSpec(args[argi]);\n                        if (forceAll)\n-                               spec.setForceUpdate(true);\n+                               spec = spec.setForceUpdate(true);\n                        refSpecs.add(spec);\n                }\n                final Collection<RemoteRefUpdate> toPush = transport\n"}]}