* [EGIT PATCH 11/23] Add BasePackPushConnection implementing git-send-pack protocol
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-11-git-send-email-marek.zawirski@gmail.com>
Implementation realies extensively on RemoteRefUpdate as input.
It supports report-status capability, and honors delete-refs one.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../jgit/transport/BasePackPushConnection.java | 226 ++++++++++++++++++++
1 files changed, 226 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
new file mode 100644
index 0000000..159e331
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import org.spearce.jgit.errors.PackProtocolException;
+import org.spearce.jgit.errors.TransportException;
+import org.spearce.jgit.lib.ObjectId;
+import org.spearce.jgit.lib.PackWriter;
+import org.spearce.jgit.lib.ProgressMonitor;
+import org.spearce.jgit.lib.Ref;
+import org.spearce.jgit.transport.RemoteRefUpdate.Status;
+
+/**
+ * Push implementation using the native Git pack transfer service.
+ * <p>
+ * This is the canonical implementation for transferring objects to the remote
+ * repository from the local repository by talking to the 'git-receive-pack'
+ * service. Objects are packed on the local side into a pack file and then sent
+ * to the remote repository.
+ * <p>
+ * This connection requires only a bi-directional pipe or socket, and thus is
+ * easily wrapped up into a local process pipe, anonymous TCP socket, or a
+ * command executed through an SSH tunnel.
+ * <p>
+ * This implementation honors {@link Transport#isPushThin()} option.
+ * <p>
+ * Concrete implementations should just call
+ * {@link #init(java.io.InputStream, java.io.OutputStream)} and
+ * {@link #readAdvertisedRefs()} methods in constructor or before any use. They
+ * should also handle resources releasing in {@link #close()} method if needed.
+ */
+class BasePackPushConnection extends BasePackConnection implements
+ PushConnection {
+ static final String CAPABILITY_REPORT_STATUS = "report-status";
+
+ static final String CAPABILITY_DELETE_REFS = "delete-refs";
+
+ private final boolean thinPack;
+
+ private boolean capableDeleteRefs;
+
+ private boolean capableReport;
+
+ private boolean sentCommand;
+
+ private boolean writePack;
+
+ BasePackPushConnection(final PackTransport transport) {
+ super(transport);
+ thinPack = transport.isPushThin();
+ }
+
+ public void push(final ProgressMonitor monitor,
+ final Map<String, RemoteRefUpdate> refUpdates)
+ throws TransportException {
+ markStartedOperation();
+ doPush(monitor, refUpdates);
+ }
+
+ protected void doPush(final ProgressMonitor monitor,
+ final Map<String, RemoteRefUpdate> refUpdates)
+ throws TransportException {
+ try {
+ writeCommands(refUpdates.values(), monitor);
+ if (writePack)
+ writePack(refUpdates, monitor);
+ if (sentCommand && capableReport)
+ readStatusReport(refUpdates);
+ } catch (TransportException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new TransportException(uri + ": " + e.getMessage(), e);
+ } finally {
+ close();
+ }
+ }
+
+ private void writeCommands(final Collection<RemoteRefUpdate> refUpdates,
+ final ProgressMonitor monitor) throws IOException {
+ final String capabilties = enableCapabilties();
+ for (final RemoteRefUpdate rru : refUpdates) {
+ if (!capableDeleteRefs && rru.isDelete()) {
+ rru.setStatus(Status.REJECTED_NODELETE);
+ continue;
+ }
+
+ final StringBuilder sb = new StringBuilder();
+ final Ref advertisedRef = getRef(rru.getRemoteName());
+ final ObjectId oldId = (advertisedRef == null ? ObjectId.zeroId()
+ : advertisedRef.getObjectId());
+ sb.append(oldId);
+ sb.append(' ');
+ sb.append(rru.getNewObjectId());
+ sb.append(' ');
+ sb.append(rru.getRemoteName());
+ if (!sentCommand) {
+ sentCommand = true;
+ sb.append(capabilties);
+ }
+
+ pckOut.writeString(sb.toString());
+ rru.setStatus(sentCommand ? Status.AWAITING_REPORT : Status.OK);
+ if (!rru.isDelete())
+ writePack = true;
+ }
+
+ if (monitor.isCancelled())
+ throw new TransportException(uri + ": push cancelled");
+ pckOut.end();
+ }
+
+ private String enableCapabilties() {
+ final StringBuilder line = new StringBuilder();
+ capableReport = wantCapability(line, CAPABILITY_REPORT_STATUS);
+ capableDeleteRefs = wantCapability(line, CAPABILITY_DELETE_REFS);
+ if (line.length() > 0)
+ line.insert(0, '\0');
+ return line.toString();
+ }
+
+ private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
+ final ProgressMonitor monitor) throws IOException {
+ final PackWriter writer = new PackWriter(local, out, monitor);
+ final ArrayList<ObjectId> remoteObjects = new ArrayList<ObjectId>(
+ getRefs().size());
+ final ArrayList<ObjectId> newObjects = new ArrayList<ObjectId>(
+ refUpdates.size());
+
+ for (final Ref r : getRefs())
+ remoteObjects.add(r.getObjectId());
+ for (final RemoteRefUpdate r : refUpdates.values())
+ newObjects.add(r.getNewObjectId());
+
+ writer.writePack(newObjects, remoteObjects, thinPack, true);
+ }
+
+ private void readStatusReport(final Map<String, RemoteRefUpdate> refUpdates)
+ throws IOException {
+ final String unpackLine = pckIn.readString();
+ if (!unpackLine.startsWith("unpack "))
+ throw new PackProtocolException(uri + ": unexpected report line: "
+ + unpackLine);
+ final String unpackStatus = unpackLine.substring("unpack ".length());
+ if (!unpackStatus.equals("ok"))
+ throw new TransportException(uri
+ + ": error occurred during unpacking on the remote end: "
+ + unpackStatus);
+
+ String refLine;
+ while ((refLine = pckIn.readString()).length() > 0) {
+ boolean ok = false;
+ int refNameEnd = -1;
+ if (refLine.startsWith("ok ")) {
+ ok = true;
+ refNameEnd = refLine.length();
+ } else if (refLine.startsWith("ng ")) {
+ ok = false;
+ refNameEnd = refLine.indexOf(" ", 3);
+ }
+ if (refNameEnd == -1)
+ throw new PackProtocolException(uri
+ + ": unexpected report line: " + refLine);
+ final String refName = refLine.substring(3, refNameEnd);
+ final String message = (ok ? null : refLine
+ .substring(refNameEnd + 1));
+
+ final RemoteRefUpdate rru = refUpdates.get(refName);
+ if (rru == null)
+ throw new PackProtocolException(uri
+ + ": unexpected ref report: " + refName);
+ if (ok) {
+ rru.setStatus(Status.OK);
+ } else {
+ rru.setStatus(Status.REJECTED_OTHER_REASON);
+ rru.setMessage(message);
+ }
+ }
+ for (final RemoteRefUpdate rru : refUpdates.values()) {
+ if (rru.getStatus() == Status.AWAITING_REPORT)
+ throw new PackProtocolException(uri
+ + ": expected report for ref " + rru.getRemoteName()
+ + " not received");
+ }
+ }
+}
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 10/23] Add ignoreMissingUninteresting option to PackWriter
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-10-git-send-email-marek.zawirski@gmail.com>
This option is useful when caller cares only about locally existing
uninteresting objects.
Test cases created.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../tst/org/spearce/jgit/lib/PackWriterTest.java | 45 +++++++++++++++++---
.../src/org/spearce/jgit/lib/PackWriter.java | 37 +++++++++++-----
2 files changed, 65 insertions(+), 17 deletions(-)
diff --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
index 9572342..f94eb72 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/PackWriterTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/PackWriterTest.java
@@ -120,7 +120,7 @@ public class PackWriterTest extends RepositoryTestCase {
* @throws IOException
*/
public void testWriteEmptyPack1() throws IOException {
- createVerifyOpenPack(EMPTY_LIST_OBJECT, EMPTY_LIST_OBJECT, false);
+ createVerifyOpenPack(EMPTY_LIST_OBJECT, EMPTY_LIST_OBJECT, false, false);
assertEquals(0, writer.getObjectsNumber());
assertEquals(0, pack.getObjectCount());
@@ -142,6 +142,37 @@ public class PackWriterTest extends RepositoryTestCase {
}
/**
+ * Try to pass non-existing object as uninteresting, with non-ignoring
+ * setting.
+ *
+ * @throws IOException
+ */
+ public void testNotIgnoreNonExistingObjects() throws IOException {
+ final ObjectId nonExisting = ObjectId
+ .fromString("0000000000000000000000000000000000000001");
+ try {
+ createVerifyOpenPack(EMPTY_LIST_OBJECT, Collections.nCopies(1,
+ nonExisting), false, false);
+ fail("Should have thrown MissingObjectException");
+ } catch (MissingObjectException x) {
+ // expected
+ }
+ }
+
+ /**
+ * Try to pass non-existing object as uninteresting, with ignoring setting.
+ *
+ * @throws IOException
+ */
+ public void testIgnoreNonExistingObjects() throws IOException {
+ final ObjectId nonExisting = ObjectId
+ .fromString("0000000000000000000000000000000000000001");
+ createVerifyOpenPack(EMPTY_LIST_OBJECT, Collections.nCopies(1,
+ nonExisting), false, true);
+ // shouldn't throw anything
+ }
+
+ /**
* Create pack basing on only interesting objects, then precisely verify
* content. No delta reuse here.
*
@@ -326,7 +357,7 @@ public class PackWriterTest extends RepositoryTestCase {
final LinkedList<ObjectId> interestings = new LinkedList<ObjectId>();
interestings.add(ObjectId
.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"));
- createVerifyOpenPack(interestings, EMPTY_LIST_OBJECT, false);
+ createVerifyOpenPack(interestings, EMPTY_LIST_OBJECT, false, false);
final ObjectId expectedOrder[] = new ObjectId[] {
ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
@@ -352,7 +383,7 @@ public class PackWriterTest extends RepositoryTestCase {
final LinkedList<ObjectId> uninterestings = new LinkedList<ObjectId>();
uninterestings.add(ObjectId
.fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab"));
- createVerifyOpenPack(interestings, uninterestings, false);
+ createVerifyOpenPack(interestings, uninterestings, false, false);
final ObjectId expectedOrder[] = new ObjectId[] {
ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
@@ -380,7 +411,7 @@ public class PackWriterTest extends RepositoryTestCase {
final LinkedList<ObjectId> uninterestings = new LinkedList<ObjectId>();
uninterestings.add(ObjectId
.fromString("c59759f143fb1fe21c197981df75a7ee00290799"));
- createVerifyOpenPack(interestings, uninterestings, thin);
+ createVerifyOpenPack(interestings, uninterestings, thin, false);
final ObjectId writtenObjects[] = new ObjectId[] {
ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
@@ -404,9 +435,11 @@ public class PackWriterTest extends RepositoryTestCase {
}
private void createVerifyOpenPack(final Collection<ObjectId> interestings,
- final Collection<ObjectId> uninterestings, final boolean thin)
+ final Collection<ObjectId> uninterestings, final boolean thin,
+ final boolean ignoreMissingUninteresting)
throws MissingObjectException, IOException {
- writer.writePack(interestings, uninterestings, thin);
+ writer.writePack(interestings, uninterestings, thin,
+ ignoreMissingUninteresting);
verifyOpenPack(thin);
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java b/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java
index ba43da5..a331237 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java
@@ -77,7 +77,7 @@ import org.spearce.jgit.util.NB;
* Typical usage consists of creating instance intended for some pack,
* configuring options through accessors methods and finally call
* {@link #writePack(Iterator)} or
- * {@link #writePack(Collection, Collection, boolean)} with objects
+ * {@link #writePack(Collection, Collection, boolean, boolean)} with objects
* specification, to generate a pack stream.
* </p>
* <p>
@@ -98,7 +98,7 @@ public class PackWriter {
* Title of {@link ProgressMonitor} task used during counting objects to
* pack.
*
- * @see #writePack(Collection, Collection, boolean)
+ * @see #writePack(Collection, Collection, boolean, boolean)
*/
public static final String COUNTING_OBJECTS_PROGRESS = "Counting objects to pack";
@@ -107,7 +107,7 @@ public class PackWriter {
* reuse or delta reuse.
*
* @see #writePack(Iterator)
- * @see #writePack(Collection, Collection, boolean)
+ * @see #writePack(Collection, Collection, boolean, boolean)
*/
public static final String SEARCHING_REUSE_PROGRESS = "Searching for delta and object reuse";
@@ -116,7 +116,7 @@ public class PackWriter {
* (objects)
*
* @see #writePack(Iterator)
- * @see #writePack(Collection, Collection, boolean)
+ * @see #writePack(Collection, Collection, boolean, boolean)
*/
public static final String WRITING_OBJECTS_PROGRESS = "Writing objects";
@@ -193,7 +193,7 @@ public class PackWriter {
* Create writer for specified repository, that will write a pack to
* provided output stream. Objects for packing are specified in
* {@link #writePack(Iterator)} or
- * {@link #writePack(Collection, Collection, boolean)}.
+ * {@link #writePack(Collection, Collection, boolean, boolean)}.
*
* @param repo
* repository where objects are stored.
@@ -203,7 +203,7 @@ public class PackWriter {
* @param monitor
* operations progress monitor, used within
* {@link #writePack(Iterator)} or
- * {@link #writePack(Collection, Collection, boolean)}.
+ * {@link #writePack(Collection, Collection, boolean, boolean)}.
*/
public PackWriter(final Repository repo, final OutputStream out,
final ProgressMonitor monitor) {
@@ -233,7 +233,8 @@ public class PackWriter {
* writer will search for delta representation of object in repository and
* use it if possible. Normally, only deltas with base to another object
* existing in set of objects to pack will be used. Exception is however
- * thin-pack (see {@link #writePack(Collection, Collection, boolean)} and
+ * thin-pack (see
+ * {@link #writePack(Collection, Collection, boolean, boolean)} and
* {@link #writePack(Iterator)}) where base object must exist on other side
* machine.
* <p>
@@ -442,15 +443,21 @@ public class PackWriter {
* belonging to party repository (uninteresting/boundary) as
* determined by set; this kind of pack is used only for
* transport; true - to produce thin pack, false - otherwise.
+ * @param ignoreMissingUninteresting
+ * true if writer should ignore non existing uninteresting
+ * objects during construction set of objects to pack; false
+ * otherwise - non existing uninteresting objects may cause
+ * {@link MissingObjectException}
* @throws IOException
* when some I/O problem occur during reading objects for pack
* or writing pack stream.
*/
public void writePack(final Collection<ObjectId> interestingObjects,
- final Collection<ObjectId> uninterestingObjects, boolean thin)
+ final Collection<ObjectId> uninterestingObjects,
+ final boolean thin, final boolean ignoreMissingUninteresting)
throws IOException {
ObjectWalk walker = setUpWalker(interestingObjects,
- uninterestingObjects, thin);
+ uninterestingObjects, thin, ignoreMissingUninteresting);
findObjectsToPack(walker);
writePackInternal();
}
@@ -682,7 +689,8 @@ public class PackWriter {
private ObjectWalk setUpWalker(
final Collection<ObjectId> interestingObjects,
- final Collection<ObjectId> uninterestingObjects, boolean thin)
+ final Collection<ObjectId> uninterestingObjects,
+ final boolean thin, final boolean ignoreMissingUninteresting)
throws MissingObjectException, IOException,
IncorrectObjectTypeException {
final ObjectWalk walker = new ObjectWalk(db);
@@ -696,7 +704,14 @@ public class PackWriter {
walker.markStart(o);
}
for (ObjectId id : uninterestingObjects) {
- RevObject o = walker.parseAny(id);
+ final RevObject o;
+ try {
+ o = walker.parseAny(id);
+ } catch (MissingObjectException x) {
+ if (ignoreMissingUninteresting)
+ continue;
+ throw x;
+ }
walker.markUninteresting(o);
}
return walker;
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 09/23] Big refactor: *Connection hierarchy
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-9-git-send-email-marek.zawirski@gmail.com>
New interfaces and base classes are introduced to cope with lack of
multiple inheritance and allow code reuse between fetch and push
operations implementations. Some renames (adding Base prefix) are also
performed to distinct between interfaces and base implementations.
Some generalizations/cleanings in interfaces and implementations
(particularly in Base* classes) were introduced. readAdvertisedRefs() in
BasePackConnection now support both push and fetch advertisements.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../org/spearce/jgit/transport/BaseConnection.java | 103 +++++++++
.../jgit/transport/BaseFetchConnection.java | 86 ++++++++
.../spearce/jgit/transport/BasePackConnection.java | 217 ++++++++++++++++++++
...onnection.java => BasePackFetchConnection.java} | 165 ++--------------
.../src/org/spearce/jgit/transport/Connection.java | 104 ++++++++++
.../spearce/jgit/transport/FetchConnection.java | 127 ++----------
.../org/spearce/jgit/transport/FetchProcess.java | 2 +-
.../org/spearce/jgit/transport/PackTransport.java | 3 +-
.../org/spearce/jgit/transport/PushConnection.java | 56 +++++-
.../spearce/jgit/transport/TransportBundle.java | 2 +-
.../spearce/jgit/transport/TransportGitAnon.java | 2 +-
.../spearce/jgit/transport/TransportGitSsh.java | 2 +-
.../org/spearce/jgit/transport/TransportLocal.java | 2 +-
.../jgit/transport/WalkFetchConnection.java | 2 +-
14 files changed, 602 insertions(+), 271 deletions(-)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BaseConnection.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java
rename org.spearce.jgit/src/org/spearce/jgit/transport/{PackFetchConnection.java => BasePackFetchConnection.java} (76%)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/Connection.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BaseConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BaseConnection.java
new file mode 100644
index 0000000..9a6b7df
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BaseConnection.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.spearce.jgit.errors.TransportException;
+import org.spearce.jgit.lib.Ref;
+
+/**
+ * Base helper class for implementing operations connections.
+ *
+ * @see BasePackConnection
+ * @see BaseFetchConnection
+ */
+abstract class BaseConnection implements Connection {
+
+ private Map<String, Ref> advertisedRefs = Collections.emptyMap();
+
+ private boolean startedOperation;
+
+ public Map<String, Ref> getRefsMap() {
+ return advertisedRefs;
+ }
+
+ public final Collection<Ref> getRefs() {
+ return advertisedRefs.values();
+ }
+
+ public final Ref getRef(final String name) {
+ return advertisedRefs.get(name);
+ }
+
+ public abstract void close();
+
+ /**
+ * Denote the list of refs available on the remote repository.
+ * <p>
+ * Implementors should invoke this method once they have obtained the refs
+ * that are available from the remote repository.
+ *
+ * @param all
+ * the complete list of refs the remote has to offer. This map
+ * will be wrapped in an unmodifiable way to protect it, but it
+ * does not get copied.
+ */
+ protected void available(final Map<String, Ref> all) {
+ advertisedRefs = Collections.unmodifiableMap(all);
+ }
+
+ /**
+ * Helper method for ensuring one-operation per connection. Check whether
+ * operation was already marked as started, and mark it as started.
+ *
+ * @throws TransportException
+ * if operation was already marked as started.
+ */
+ protected void markStartedOperation() throws TransportException {
+ if (startedOperation)
+ throw new TransportException(
+ "Only one operation call per connection is supported.");
+ startedOperation = true;
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java
new file mode 100644
index 0000000..7fb13bc
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.util.Collection;
+
+import org.spearce.jgit.errors.TransportException;
+import org.spearce.jgit.lib.ProgressMonitor;
+import org.spearce.jgit.lib.Ref;
+
+/**
+ * Base helper class for fetch connection implementations. Provides some common
+ * typical structures and methods used during fetch connection.
+ * <p>
+ * Implementors of fetch over pack-based protocols should consider using
+ * {@link BasePackFetchConnection} instead.
+ * </p>
+ */
+abstract class BaseFetchConnection extends BaseConnection implements
+ FetchConnection {
+ public final void fetch(final ProgressMonitor monitor,
+ final Collection<Ref> want) throws TransportException {
+ markStartedOperation();
+ doFetch(monitor, want);
+ }
+
+ /**
+ * Default implementation of {@link FetchConnection#didFetchIncludeTags()} -
+ * returning false.
+ */
+ public boolean didFetchIncludeTags() {
+ return false;
+ }
+
+ /**
+ * Implementation of {@link #fetch(ProgressMonitor, Collection)} without
+ * checking for multiple fetch.
+ *
+ * @param monitor
+ * as in {@link #fetch(ProgressMonitor, Collection)}
+ * @param want
+ * as in {@link #fetch(ProgressMonitor, Collection)}
+ * @throws TransportException
+ * as in {@link #fetch(ProgressMonitor, Collection)}, but
+ * implementation doesn't have to care about multiple
+ * {@link #fetch(ProgressMonitor, Collection)} calls, as it is
+ * checked in this class.
+ */
+ protected abstract void doFetch(final ProgressMonitor monitor,
+ final Collection<Ref> want) throws TransportException;
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java
new file mode 100644
index 0000000..d119672
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Set;
+
+import org.spearce.jgit.errors.PackProtocolException;
+import org.spearce.jgit.errors.TransportException;
+import org.spearce.jgit.lib.ObjectId;
+import org.spearce.jgit.lib.Ref;
+import org.spearce.jgit.lib.Repository;
+
+/**
+ * Base helper class for pack-based operations implementations. Provides partial
+ * implementation of pack-protocol - refs advertising and capabilities support,
+ * and some other helper methods.
+ *
+ * @see BasePackFetchConnection
+ * @see BasePackPushConnection
+ */
+abstract class BasePackConnection extends BaseConnection {
+
+ /** The repository this transport fetches into, or pushes out of. */
+ protected final Repository local;
+
+ /** Remote repository location. */
+ protected final URIish uri;
+
+ /** Buffered input stream reading from the remote. */
+ protected InputStream in;
+
+ /** Buffered output stream sending to the remote. */
+ protected OutputStream out;
+
+ /** Packet line decoder around {@link #in}. */
+ protected PacketLineIn pckIn;
+
+ /** Packet line encoder around {@link #out}. */
+ protected PacketLineOut pckOut;
+
+ /** Capability tokens advertised by the remote side. */
+ private final Set<String> remoteCapablities = new HashSet<String>();
+
+ BasePackConnection(final PackTransport packTransport) {
+ local = packTransport.local;
+ uri = packTransport.uri;
+ }
+
+ protected void init(final InputStream myIn, final OutputStream myOut) {
+ in = myIn instanceof BufferedInputStream ? myIn
+ : new BufferedInputStream(myIn);
+ out = myOut instanceof BufferedOutputStream ? myOut
+ : new BufferedOutputStream(myOut);
+
+ pckIn = new PacketLineIn(in);
+ pckOut = new PacketLineOut(out);
+ }
+
+ protected void readAdvertisedRefs() throws TransportException {
+ try {
+ readAdvertisedRefsImpl();
+ } catch (TransportException err) {
+ close();
+ throw err;
+ } catch (IOException err) {
+ close();
+ throw new TransportException(err.getMessage(), err);
+ } catch (RuntimeException err) {
+ close();
+ throw new TransportException(err.getMessage(), err);
+ }
+ }
+
+ private void readAdvertisedRefsImpl() throws IOException {
+ final LinkedHashMap<String, Ref> avail = new LinkedHashMap<String, Ref>();
+ for (;;) {
+ String line;
+
+ try {
+ line = pckIn.readString();
+ } catch (EOFException eof) {
+ if (avail.isEmpty())
+ throw new TransportException(uri + " not found.");
+ throw eof;
+ }
+
+ if (avail.isEmpty()) {
+ final int nul = line.indexOf('\0');
+ if (nul >= 0) {
+ // The first line (if any) may contain "hidden"
+ // capability values after a NUL byte.
+ for (String c : line.substring(nul + 1).split(" "))
+ remoteCapablities.add(c);
+ line = line.substring(0, nul);
+ }
+
+ if (line.equals("capabilties^{}")) {
+ // special line from git-receive-pack to show
+ // capabilities when there are no refs to advertise
+ continue;
+ }
+ }
+
+ if (line.length() == 0)
+ break;
+
+ String name = line.substring(41, line.length());
+ final ObjectId id = ObjectId.fromString(line.substring(0, 40));
+ if (name.endsWith("^{}")) {
+ name = name.substring(0, name.length() - 3);
+ final Ref prior = avail.get(name);
+ if (prior == null)
+ throw new PackProtocolException(uri + ": advertisement of "
+ + name + "^{} came before " + name);
+
+ if (prior.getPeeledObjectId() != null)
+ throw duplicateAdvertisement(name + "^{}");
+
+ avail.put(name, new Ref(name, prior.getObjectId(), id));
+ } else {
+ final Ref prior = avail.put(name, new Ref(name, id));
+ if (prior != null)
+ throw duplicateAdvertisement(name);
+ }
+ }
+ available(avail);
+ }
+
+ protected boolean isCapableOf(final String option) {
+ return remoteCapablities.contains(option);
+ }
+
+ protected boolean wantCapability(final StringBuilder b, final String option) {
+ if (!isCapableOf(option))
+ return false;
+ if (b.length() > 0)
+ b.append(' ');
+ b.append(option);
+ return true;
+ }
+
+ private PackProtocolException duplicateAdvertisement(final String name) {
+ return new PackProtocolException(uri + ": duplicate advertisements of "
+ + name);
+ }
+
+ @Override
+ public void close() {
+ if (out != null) {
+ try {
+ pckOut.end();
+ out.close();
+ } catch (IOException err) {
+ // Ignore any close errors.
+ } finally {
+ out = null;
+ pckOut = null;
+ }
+ }
+
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException err) {
+ // Ignore any close errors.
+ } finally {
+ in = null;
+ pckIn = null;
+ }
+ }
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
similarity index 76%
rename from org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java
rename to org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
index 6209030..04a91bf 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
@@ -38,26 +38,15 @@
package org.spearce.jgit.transport;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.EOFException;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.util.Collection;
import java.util.Date;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.Set;
-import org.spearce.jgit.errors.PackProtocolException;
import org.spearce.jgit.errors.TransportException;
import org.spearce.jgit.lib.AnyObjectId;
import org.spearce.jgit.lib.MutableObjectId;
-import org.spearce.jgit.lib.ObjectId;
import org.spearce.jgit.lib.ProgressMonitor;
import org.spearce.jgit.lib.Ref;
-import org.spearce.jgit.lib.Repository;
import org.spearce.jgit.revwalk.RevCommit;
import org.spearce.jgit.revwalk.RevCommitList;
import org.spearce.jgit.revwalk.RevFlag;
@@ -78,8 +67,14 @@ import org.spearce.jgit.revwalk.filter.RevFilter;
* This connection requires only a bi-directional pipe or socket, and thus is
* easily wrapped up into a local process pipe, anonymous TCP socket, or a
* command executed through an SSH tunnel.
+ * <p>
+ * Concrete implementations should just call
+ * {@link #init(java.io.InputStream, java.io.OutputStream)} and
+ * {@link #readAdvertisedRefs()} methods in constructor or before any use. They
+ * should also handle resources releasing in {@link #close()} method if needed.
*/
-abstract class PackFetchConnection extends FetchConnection {
+abstract class BasePackFetchConnection extends BasePackConnection implements
+ FetchConnection {
/**
* Maximum number of 'have' lines to send before giving up.
* <p>
@@ -103,27 +98,6 @@ abstract class PackFetchConnection extends FetchConnection {
static final String OPTION_SHALLOW = "shallow";
- /** The repository this transport fetches into, or pushes out of. */
- protected final Repository local;
-
- /** Remote repository location. */
- protected final URIish uri;
-
- /** Capability tokens advertised by the remote side. */
- protected final Set<String> remoteCapablities = new HashSet<String>();
-
- /** Buffered input stream reading from the remote. */
- protected InputStream in;
-
- /** Buffered output stream sending to the remote. */
- protected OutputStream out;
-
- /** Packet line decoder around {@link #in}. */
- protected PacketLineIn pckIn;
-
- /** Packet line encoder around {@link #out}. */
- protected PacketLineOut pckOut;
-
private final RevWalk walk;
/** All commits that are immediately reachable by a local ref. */
@@ -146,9 +120,8 @@ abstract class PackFetchConnection extends FetchConnection {
private boolean includeTags;
- PackFetchConnection(final PackTransport packTransport) {
- local = packTransport.local;
- uri = packTransport.uri;
+ BasePackFetchConnection(final PackTransport packTransport) {
+ super(packTransport);
includeTags = packTransport.getTagOpt() != TagOpt.NO_TAGS;
thinPack = packTransport.isFetchThin();
@@ -163,91 +136,16 @@ abstract class PackFetchConnection extends FetchConnection {
walk.carry(ADVERTISED);
}
- protected void init(final InputStream myIn, final OutputStream myOut) {
- in = myIn instanceof BufferedInputStream ? myIn
- : new BufferedInputStream(myIn);
- out = myOut instanceof BufferedOutputStream ? myOut
- : new BufferedOutputStream(myOut);
-
- pckIn = new PacketLineIn(in);
- pckOut = new PacketLineOut(out);
+ public final void fetch(final ProgressMonitor monitor,
+ final Collection<Ref> want) throws TransportException {
+ markStartedOperation();
+ doFetch(monitor, want);
}
- @Override
public boolean didFetchIncludeTags() {
- return includeTags;
- }
-
- protected void readAdvertisedRefs() throws TransportException {
- try {
- readAdvertisedRefsImpl();
- } catch (TransportException err) {
- close();
- throw err;
- } catch (IOException err) {
- close();
- throw new TransportException(err.getMessage(), err);
- } catch (RuntimeException err) {
- close();
- throw new TransportException(err.getMessage(), err);
- }
- }
-
- private void readAdvertisedRefsImpl() throws IOException {
- final LinkedHashMap<String, Ref> avail = new LinkedHashMap<String, Ref>();
- for (;;) {
- String line;
-
- try {
- line = pckIn.readString();
- } catch (EOFException eof) {
- if (avail.isEmpty())
- throw new TransportException(uri + " not found.");
- throw eof;
- }
-
- if (avail.isEmpty()) {
- // The first line (if any) may contain "hidden"
- // capability values after a NUL byte.
- //
- final int nul = line.indexOf('\0');
- if (nul >= 0) {
- for (String c : line.substring(nul + 1).split(" "))
- remoteCapablities.add(c);
- line = line.substring(0, nul);
- }
- }
-
- if (line.length() == 0)
- break;
-
- String name = line.substring(41, line.length());
- final ObjectId id = ObjectId.fromString(line.substring(0, 40));
- if (name.endsWith("^{}")) {
- name = name.substring(0, name.length() - 3);
- final Ref prior = avail.get(name);
- if (prior == null)
- throw new PackProtocolException("advertisement of " + name
- + "^{} came before " + name);
-
- if (prior.getPeeledObjectId() != null)
- throw duplicateAdvertisement(name + "^{}");
-
- avail.put(name, new Ref(name, prior.getObjectId(), id));
- } else {
- final Ref prior = avail.put(name, new Ref(name, id));
- if (prior != null)
- throw duplicateAdvertisement(name);
- }
- }
- available(avail);
+ return false;
}
- private PackProtocolException duplicateAdvertisement(final String name) {
- return new PackProtocolException("duplicate advertisements of " + name);
- }
-
- @Override
protected void doFetch(final ProgressMonitor monitor,
final Collection<Ref> want) throws TransportException {
try {
@@ -373,15 +271,6 @@ abstract class PackFetchConnection extends FetchConnection {
return line.toString();
}
- private boolean wantCapability(final StringBuilder b, final String option) {
- if (!remoteCapablities.contains(option))
- return false;
- if (b.length() > 0)
- b.append(' ');
- b.append(option);
- return true;
- }
-
private void negotiate(final ProgressMonitor monitor) throws IOException,
CancelledException {
final MutableObjectId ackId = new MutableObjectId();
@@ -568,32 +457,6 @@ abstract class PackFetchConnection extends FetchConnection {
ip.renameAndOpenPack();
}
- @Override
- public void close() {
- if (out != null) {
- try {
- pckOut.end();
- out.close();
- } catch (IOException err) {
- // Ignore any close errors.
- } finally {
- out = null;
- pckOut = null;
- }
- }
-
- if (in != null) {
- try {
- in.close();
- } catch (IOException err) {
- // Ignore any close errors.
- } finally {
- in = null;
- pckIn = null;
- }
- }
- }
-
private static class CancelledException extends Exception {
private static final long serialVersionUID = 1L;
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/Connection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/Connection.java
new file mode 100644
index 0000000..5a91e9b
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/Connection.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.spearce.jgit.lib.Ref;
+
+/**
+ * Represent connection for operation on a remote repository.
+ * <p>
+ * Currently all operations on remote repository (fetch and push) provide
+ * information about remote refs. Every connection is able to be closed and
+ * should be closed - this is a connection client responsibility.
+ *
+ * @see Transport
+ */
+public interface Connection {
+
+ /**
+ * Get the complete map of refs advertised as available for fetching or
+ * pushing.
+ *
+ * @return available/advertised refs: map of refname to ref. Never null. Not
+ * modifiable. The collection can be empty if the remote side has no
+ * refs (it is an empty/newly created repository).
+ */
+ public Map<String, Ref> getRefsMap();
+
+ /**
+ * Get the complete list of refs advertised as available for fetching or
+ * pushing.
+ * <p>
+ * The returned refs may appear in any order. If the caller needs these to
+ * be sorted, they should be copied into a new array or List and then sorted
+ * by the caller as necessary.
+ *
+ * @return available/advertised refs. Never null. Not modifiable. The
+ * collection can be empty if the remote side has no refs (it is an
+ * empty/newly created repository).
+ */
+ public Collection<Ref> getRefs();
+
+ /**
+ * Get a single advertised ref by name.
+ * <p>
+ * The name supplied should be valid ref name. To get a peeled value for a
+ * ref (aka <code>refs/tags/v1.0^{}</code>) use the base name (without
+ * the <code>^{}</code> suffix) and look at the peeled object id.
+ *
+ * @param name
+ * name of the ref to obtain.
+ * @return the requested ref; null if the remote did not advertise this ref.
+ */
+ public Ref getRef(final String name);
+
+ /**
+ * Close any resources used by this connection.
+ * <p>
+ * If the remote repository is contacted by a network socket this method
+ * must close that network socket, disconnecting the two peers. If the
+ * remote repository is actually local (same system) this method must close
+ * any open file handles used to read the "remote" repository.
+ */
+ public void close();
+
+}
\ No newline at end of file
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java
index 8e7641c..9d25b0d 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java
@@ -38,8 +38,6 @@
package org.spearce.jgit.transport;
import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
import org.spearce.jgit.errors.TransportException;
import org.spearce.jgit.lib.ProgressMonitor;
@@ -62,84 +60,13 @@ import org.spearce.jgit.lib.Ref;
*
* @see Transport
*/
-public abstract class FetchConnection {
- private Map<String, Ref> cachedRefs = Collections.<String, Ref> emptyMap();
-
- /** Have we started {@link #fetch(ProgressMonitor, Collection)} yet? */
- private boolean startedFetch;
-
- Map<String, Ref> getCachedRefs() {
- return cachedRefs;
- }
-
- /**
- * Denote the list of refs available on the remote repository.
- * <p>
- * Implementors should invoke this method once they have obtained the refs
- * that are available from the remote repository.s
- *
- * @param all
- * the complete list of refs the remote has to offer. This map
- * will be wrapped in an unmodifiable way to protect it, but it
- * does not get copied.
- */
- protected void available(final Map<String, Ref> all) {
- cachedRefs = Collections.unmodifiableMap(all);
- }
-
- /**
- * Get the complete list of refs advertised as available for fetching.
- * <p>
- * The returned refs may appear in any order. If the caller needs these to
- * be sorted, they should be copied into a new array or List and then sorted
- * by the caller as necessary.
- *
- * @return available/advertised refs. Never null. Not modifiable. The
- * collection can be empty if the remote side has no refs (it is an
- * empty/newly created repository).
- */
- public final Collection<Ref> getRefs() {
- return cachedRefs.values();
- }
-
- /**
- * Get a single advertised ref by name.
- * <p>
- * The name supplied should be valid ref name. To get a peeled value for a
- * ref (aka <code>refs/tags/v1.0^{}</code>) use the base name (without
- * the <code>^{}</code> suffix) and look at the peeled object id.
- *
- * @param name
- * name of the ref to obtain.
- * @return the requested ref; null if the remote did not advertise this ref.
- */
- public final Ref getRef(final String name) {
- return cachedRefs.get(name);
- }
-
+public interface FetchConnection extends Connection {
/**
* Fetch objects we don't have but that are reachable from advertised refs.
- *
- * @param monitor
- * progress monitor to update the end-user about the amount of
- * work completed, or to indicate cancellation.
- * @param want
- * one or more refs advertised by this connection that the caller
- * wants to store locally.
- * @throws TransportException
- * objects could not be copied due to a network failure,
- * protocol error, or error on remote side.
- */
- public final void fetch(final ProgressMonitor monitor,
- final Collection<Ref> want) throws TransportException {
- if (startedFetch)
- throw new TransportException("Only one fetch call supported.");
- startedFetch = true;
- doFetch(monitor, want);
- }
-
- /**
- * Fetch objects this repository does not yet contain.
+ * <p>
+ * Only one call per connection is allowed. Subsequent calls will result in
+ * {@link TransportException}.
+ * </p>
* <p>
* Implementations are free to use network connections as necessary to
* efficiently (for both client and server) transfer objects from the remote
@@ -147,22 +74,24 @@ public abstract class FetchConnection {
* avoid replacing/overwriting/duplicating an object already available in
* the local destination repository. Locally available objects and packs
* should always be preferred over remotely available objects and packs.
+ * {@link Transport#isFetchThin()} should be honored if applicable.
+ * </p>
*
* @param monitor
- * progress feedback to inform the end-user about the status of
- * the object transfer. Implementors should poll the monitor at
- * regular intervals to look for cancellation requests from the
- * user.
+ * progress monitor to inform the end-user about the amount of
+ * work completed, or to indicate cancellation. Implementations
+ * should poll the monitor at regular intervals to look for
+ * cancellation requests from the user.
* @param want
- * one or more refs that were previously passed to
- * {@link #available(Map)} by the implementation. These refs
- * indicate the objects the caller wants copied.
+ * one or more refs advertised by this connection that the caller
+ * wants to store locally.
* @throws TransportException
* objects could not be copied due to a network failure,
- * protocol error, or error on remote side.
+ * protocol error, or error on remote side, or connection was
+ * already used for fetch.
*/
- protected abstract void doFetch(ProgressMonitor monitor,
- Collection<Ref> want) throws TransportException;
+ public void fetch(final ProgressMonitor monitor, final Collection<Ref> want)
+ throws TransportException;
/**
* Did the last {@link #fetch(ProgressMonitor, Collection)} get tags?
@@ -170,9 +99,9 @@ public abstract class FetchConnection {
* Some Git aware transports are able to implicitly grab an annotated tag if
* {@link TagOpt#AUTO_FOLLOW} or {@link TagOpt#FETCH_TAGS} was selected and
* the object the tag peels to (references) was transferred as part of the
- * last {@link #doFetch(ProgressMonitor, Collection)} call. If it is
- * possible for such tags to have been included in the transfer this method
- * returns true, allowing the caller to attempt tag discovery.
+ * last {@link #fetch(ProgressMonitor, Collection)} call. If it is possible
+ * for such tags to have been included in the transfer this method returns
+ * true, allowing the caller to attempt tag discovery.
* <p>
* By returning only true/false (and not the actual list of tags obtained)
* the transport itself does not need to be aware of whether or not tags
@@ -181,17 +110,5 @@ public abstract class FetchConnection {
* @return true if the last fetch call implicitly included tag objects;
* false if tags were not implicitly obtained.
*/
- public boolean didFetchIncludeTags() {
- return false;
- }
-
- /**
- * Close any resources used by this connection.
- * <p>
- * If the remote repository is contacted by a network socket this method
- * must close that network socket, disconnecting the two peers. If the
- * remote repository is actually local (same system) this method must close
- * any open file handles used to read the "remote" repository.
- */
- public abstract void close();
-}
+ public boolean didFetchIncludeTags();
+}
\ No newline at end of file
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java
index e33b35b..c765c12 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java
@@ -97,7 +97,7 @@ class FetchProcess {
conn = transport.openFetch();
try {
- result.setAdvertisedRefs(conn.getCachedRefs());
+ result.setAdvertisedRefs(conn.getRefsMap());
final Set<Ref> matched = new HashSet<Ref>();
for (final RefSpec spec : toFetch) {
if (spec.isWildcard())
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PackTransport.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PackTransport.java
index 177e065..50708d3 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/PackTransport.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PackTransport.java
@@ -46,7 +46,8 @@ import org.spearce.jgit.lib.Repository;
* forth by creating pack files on the source side and indexing them on the
* receiving side.
*
- * @see PackFetchConnection
+ * @see BasePackFetchConnection
+ * @see BasePackPushConnection
*/
abstract class PackTransport extends Transport {
PackTransport(final Repository local, final URIish u) {
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PushConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PushConnection.java
index 316bb95..835b15c 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/PushConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PushConnection.java
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
- *
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ *
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
@@ -37,6 +38,12 @@
package org.spearce.jgit.transport;
+import java.util.Map;
+
+import org.spearce.jgit.errors.TransportException;
+import org.spearce.jgit.lib.ProgressMonitor;
+import org.spearce.jgit.transport.RemoteRefUpdate.Status;
+
/**
* Lists known refs from the remote and sends objects to the remote.
* <p>
@@ -55,14 +62,47 @@ package org.spearce.jgit.transport;
*
* @see Transport
*/
-public abstract class PushConnection {
+public interface PushConnection extends Connection {
+
/**
- * Close any resources used by this connection.
+ * Pushes to the remote repository basing on provided specification. This
+ * possibly result in update/creation/deletion of refs on remote repository
+ * and sending objects that remote repository need to have a consistent
+ * objects graph from new refs.
+ * <p>
+ * <p>
+ * Only one call per connection is allowed. Subsequent calls will result in
+ * {@link TransportException}.
+ * </p>
* <p>
- * If the remote repository is contacted by a network socket this method
- * must close that network socket, disconnecting the two peers. If the
- * remote repository is actually local (same system) this method must close
- * any open file handles used to read the "remote" repository.
+ * Implementation may use local repository to send a minimum set of objects
+ * needed by remote repository in efficient way.
+ * {@link Transport#isPushThin()} should be honored if applicable.
+ * refUpdates should be filled with information about status of each update.
+ * </p>
+ *
+ * @param monitor
+ * progress monitor to update the end-user about the amount of
+ * work completed, or to indicate cancellation. Implementors
+ * should poll the monitor at regular intervals to look for
+ * cancellation requests from the user.
+ * @param refUpdates
+ * map of remote refnames to remote refs update
+ * specifications/statuses. Can't be empty. This indicate what
+ * refs caller want to update on remote side. Only refs updates
+ * with {@link Status#NOT_ATTEMPTED} should passed.
+ * Implementation must ensure that and appropriate status with
+ * optional message should be set during call. No refUpdate with
+ * {@link Status#AWAITING_REPORT} or {@link Status#NOT_ATTEMPTED}
+ * can be leaved by implementation after return from this call.
+ * @throws TransportException
+ * objects could not be copied due to a network failure,
+ * critical protocol error, or error on remote side, or
+ * connection was already used for push - new connection must be
+ * created. Non-critical errors concerning only isolated refs
+ * should be placed in refUpdates.
*/
- public abstract void close();
+ public void push(final ProgressMonitor monitor,
+ final Map<String, RemoteRefUpdate> refUpdates)
+ throws TransportException;
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java
index 2c173fd..48120a8 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java
@@ -95,7 +95,7 @@ class TransportBundle extends PackTransport {
return new BundleFetchConnection();
}
- class BundleFetchConnection extends FetchConnection {
+ class BundleFetchConnection extends BaseFetchConnection {
FileInputStream in;
RewindBufferedInputStream bin;
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java
index e37757a..a7a419e 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java
@@ -99,7 +99,7 @@ class TransportGitAnon extends PackTransport {
pckOut.flush();
}
- class TcpFetchConnection extends PackFetchConnection {
+ class TcpFetchConnection extends BasePackFetchConnection {
private Socket sock;
TcpFetchConnection() throws TransportException {
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
index 8944df7..f6e456a 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
@@ -188,7 +188,7 @@ class TransportGitSsh extends PackTransport {
}
}
- class SshFetchConnection extends PackFetchConnection {
+ class SshFetchConnection extends BasePackFetchConnection {
private Session session;
private ChannelExec channel;
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
index cde648d..e109cf4 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
@@ -83,7 +83,7 @@ class TransportLocal extends PackTransport {
return new LocalFetchConnection();
}
- class LocalFetchConnection extends PackFetchConnection {
+ class LocalFetchConnection extends BasePackFetchConnection {
private Process uploadPack;
LocalFetchConnection() throws TransportException {
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java
index 45c2ded..78116b2 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java
@@ -95,7 +95,7 @@ import org.spearce.jgit.treewalk.TreeWalk;
*
* @see WalkRemoteObjectDatabase
*/
-class WalkFetchConnection extends FetchConnection {
+class WalkFetchConnection extends BaseFetchConnection {
/** The repository this transport fetches into, or pushes out of. */
private final Repository local;
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 08/23] Support for fetchThin and pushThin options in Transport
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-8-git-send-email-marek.zawirski@gmail.com>
This option determines whether we should use thin pack when possible
during fetching from or pushing to a remote repo.
For fetching the default is to produce a thin pack when remote side
supports it, while for pushing the default setting is to not produce a
thin pack.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../jgit/transport/PackFetchConnection.java | 4 +-
.../src/org/spearce/jgit/transport/Transport.java | 63 ++++++++++++++++++++
2 files changed, 66 insertions(+), 1 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java
index 5f15a8d..6209030 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PackFetchConnection.java
@@ -150,6 +150,7 @@ abstract class PackFetchConnection extends FetchConnection {
local = packTransport.local;
uri = packTransport.uri;
includeTags = packTransport.getTagOpt() != TagOpt.NO_TAGS;
+ thinPack = packTransport.isFetchThin();
walk = new RevWalk(local);
reachableCommits = new RevCommitList<RevCommit>();
@@ -363,7 +364,8 @@ abstract class PackFetchConnection extends FetchConnection {
includeTags = wantCapability(line, OPTION_INCLUDE_TAG);
wantCapability(line, OPTION_OFS_DELTA);
multiAck = wantCapability(line, OPTION_MULTI_ACK);
- thinPack = wantCapability(line, OPTION_THIN_PACK);
+ if (thinPack)
+ thinPack = wantCapability(line, OPTION_THIN_PACK);
if (wantCapability(line, OPTION_SIDE_BAND_64K))
sideband = true;
else if (wantCapability(line, OPTION_SIDE_BAND))
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java
index 6cc38ec..c4b71eb 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java
@@ -142,6 +142,16 @@ public abstract class Transport {
throw new NotSupportedException("URI not supported: " + remote);
}
+ /**
+ * Default setting for {@link #fetchThin} option.
+ */
+ public static final boolean DEFAULT_FETCH_THIN = true;
+
+ /**
+ * Default setting for {@link #pushThin} option.
+ */
+ public static final boolean DEFAULT_PUSH_THIN = false;
+
/** The repository this transport fetches into, or pushes out of. */
protected final Repository local;
@@ -165,6 +175,12 @@ public abstract class Transport {
*/
private TagOpt tagopt = TagOpt.NO_TAGS;
+ /** Should fetch request thin-pack if remote repository can produce it. */
+ private boolean fetchThin = DEFAULT_FETCH_THIN;
+
+ /** Should push produce thin-pack when sending objects to remote repository. */
+ private boolean pushThin = DEFAULT_PUSH_THIN;
+
/**
* Create a new transport instance.
*
@@ -234,6 +250,53 @@ public abstract class Transport {
}
/**
+ * Default setting is: {@link #DEFAULT_FETCH_THIN}
+ *
+ * @return true if fetch should request thin-pack when possible; false
+ * otherwise
+ * @see PackTransport
+ */
+ public boolean isFetchThin() {
+ return fetchThin;
+ }
+
+ /**
+ * Set the thin-pack preference for fetch operation. Default setting is:
+ * {@link #DEFAULT_FETCH_THIN}
+ *
+ * @param fetchThin
+ * true when fetch should request thin-pack when possible; false
+ * when it shouldn't
+ * @see PackTransport
+ */
+ public void setFetchThin(final boolean fetchThin) {
+ this.fetchThin = fetchThin;
+ }
+
+ /**
+ * Default setting is: {@value #DEFAULT_PUSH_THIN}
+ *
+ * @return true if push should produce thin-pack in pack transports
+ * @see PackTransport
+ */
+ public boolean isPushThin() {
+ return pushThin;
+ }
+
+ /**
+ * Set thin-pack preference for push operation. Default setting is:
+ * {@value #DEFAULT_PUSH_THIN}
+ *
+ * @param pushThin
+ * true when push should produce thin-pack in pack transports;
+ * false when it shouldn't
+ * @see PackTransport
+ */
+ public void setPushThin(final boolean pushThin) {
+ this.pushThin = pushThin;
+ }
+
+ /**
* Fetch objects and refs from the remote repository to the local one.
* <p>
* This is a utility function providing standard fetch behavior. Local
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 07/23] Add PushResult class
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-7-git-send-email-marek.zawirski@gmail.com>
Class represents result of push operation. In addition to the data
provided by OperationResult it also holds information about remote
refs updates.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../src/org/spearce/jgit/transport/PushResult.java | 84 ++++++++++++++++++++
1 files changed, 84 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/PushResult.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PushResult.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PushResult.java
new file mode 100644
index 0000000..11e5928
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PushResult.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Result of push operation to the remote repository. Holding information of
+ * {@link OperationResult} and remote refs updates status.
+ *
+ * @see Transport#push(org.spearce.jgit.lib.ProgressMonitor, Collection)
+ */
+public class PushResult extends OperationResult {
+ private Map<String, RemoteRefUpdate> remoteUpdates = Collections.emptyMap();
+
+ /**
+ * Get status of remote refs updates. Together with
+ * {@link #getAdvertisedRefs()} it provides full description/status of each
+ * ref update.
+ * <p>
+ * Returned collection is not sorted in any order.
+ * </p>
+ *
+ * @return collection of remote refs updates
+ */
+ public Collection<RemoteRefUpdate> getRemoteUpdates() {
+ return Collections.unmodifiableCollection(remoteUpdates.values());
+ }
+
+ /**
+ * Get status of specific remote ref update by remote ref name. Together
+ * with {@link #getAdvertisedRef(String)} it provide full description/status
+ * of this ref update.
+ *
+ * @param refName
+ * remote ref name
+ * @return status of remote ref update
+ */
+ public RemoteRefUpdate getRemoteUpdate(final String refName) {
+ return remoteUpdates.get(refName);
+ }
+
+ protected void setRemoteUpdates(
+ final Map<String, RemoteRefUpdate> remoteUpdates) {
+ this.remoteUpdates = remoteUpdates;
+ }
+}
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 06/23] Refactor: extract superclass OperationResult from FetchResult
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-6-git-send-email-marek.zawirski@gmail.com>
New superclass holds information about advertised refs and updated
tracking refs, which is all common to fetch and push operations.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../org/spearce/jgit/transport/FetchResult.java | 74 +------------
.../spearce/jgit/transport/OperationResult.java | 119 ++++++++++++++++++++
2 files changed, 120 insertions(+), 73 deletions(-)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/OperationResult.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchResult.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchResult.java
index bd94b5f..cc8557f 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchResult.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchResult.java
@@ -40,94 +40,22 @@ package org.spearce.jgit.transport;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import org.spearce.jgit.lib.Ref;
/**
* Final status after a successful fetch from a remote repository.
*
* @see Transport#fetch(org.spearce.jgit.lib.ProgressMonitor, Collection)
*/
-public class FetchResult {
- private final SortedMap<String, TrackingRefUpdate> updates;
-
+public class FetchResult extends OperationResult {
private final List<FetchHeadRecord> forMerge;
- private Map<String, Ref> advertisedRefs;
-
FetchResult() {
- updates = new TreeMap<String, TrackingRefUpdate>();
forMerge = new ArrayList<FetchHeadRecord>();
- advertisedRefs = Collections.<String, Ref> emptyMap();
- }
-
- void add(final TrackingRefUpdate u) {
- updates.put(u.getLocalName(), u);
}
void add(final FetchHeadRecord r) {
if (!r.notForMerge)
forMerge.add(r);
}
-
- void setAdvertisedRefs(final Map<String, Ref> ar) {
- advertisedRefs = ar;
- }
-
- /**
- * Get the complete list of refs advertised by the remote.
- * <p>
- * The returned refs may appear in any order. If the caller needs these to
- * be sorted, they should be copied into a new array or List and then sorted
- * by the caller as necessary.
- *
- * @return available/advertised refs. Never null. Not modifiable. The
- * collection can be empty if the remote side has no refs (it is an
- * empty/newly created repository).
- */
- public Collection<Ref> getAdvertisedRefs() {
- return advertisedRefs.values();
- }
-
- /**
- * Get a single advertised ref by name.
- * <p>
- * The name supplied should be valid ref name. To get a peeled value for a
- * ref (aka <code>refs/tags/v1.0^{}</code>) use the base name (without
- * the <code>^{}</code> suffix) and look at the peeled object id.
- *
- * @param name
- * name of the ref to obtain.
- * @return the requested ref; null if the remote did not advertise this ref.
- */
- public final Ref getAdvertisedRef(final String name) {
- return advertisedRefs.get(name);
- }
-
- /**
- * Get the status of all local tracking refs that were updated.
- *
- * @return unmodifiable collection of local updates. Never null. Empty if
- * there were no local tracking refs updated.
- */
- public Collection<TrackingRefUpdate> getTrackingRefUpdates() {
- return Collections.unmodifiableCollection(updates.values());
- }
-
- /**
- * Get the status for a specific local tracking ref update.
- *
- * @param localName
- * name of the local ref (e.g. "refs/remotes/origin/master").
- * @return status of the local ref; null if this local ref was not touched
- * during this fetch.
- */
- public TrackingRefUpdate getTrackingRefUpdate(final String localName) {
- return updates.get(localName);
- }
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/OperationResult.java b/org.spearce.jgit/src/org/spearce/jgit/transport/OperationResult.java
new file mode 100644
index 0000000..9b411e1
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/OperationResult.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.spearce.jgit.lib.Ref;
+
+/**
+ * Class holding result of operation on remote repository. This includes refs
+ * advertised by remote repo and local tracking refs updates.
+ */
+public abstract class OperationResult {
+
+ protected Map<String, Ref> advertisedRefs = Collections.emptyMap();
+
+ protected final SortedMap<String, TrackingRefUpdate> updates = new TreeMap<String, TrackingRefUpdate>();
+
+ /**
+ * Get the complete list of refs advertised by the remote.
+ * <p>
+ * The returned refs may appear in any order. If the caller needs these to
+ * be sorted, they should be copied into a new array or List and then sorted
+ * by the caller as necessary.
+ *
+ * @return available/advertised refs. Never null. Not modifiable. The
+ * collection can be empty if the remote side has no refs (it is an
+ * empty/newly created repository).
+ */
+ public Collection<Ref> getAdvertisedRefs() {
+ return Collections.unmodifiableCollection(advertisedRefs.values());
+ }
+
+ /**
+ * Get a single advertised ref by name.
+ * <p>
+ * The name supplied should be valid ref name. To get a peeled value for a
+ * ref (aka <code>refs/tags/v1.0^{}</code>) use the base name (without
+ * the <code>^{}</code> suffix) and look at the peeled object id.
+ *
+ * @param name
+ * name of the ref to obtain.
+ * @return the requested ref; null if the remote did not advertise this ref.
+ */
+ public final Ref getAdvertisedRef(final String name) {
+ return advertisedRefs.get(name);
+ }
+
+ /**
+ * Get the status of all local tracking refs that were updated.
+ *
+ * @return unmodifiable collection of local updates. Never null. Empty if
+ * there were no local tracking refs updated.
+ */
+ public Collection<TrackingRefUpdate> getTrackingRefUpdates() {
+ return Collections.unmodifiableCollection(updates.values());
+ }
+
+ /**
+ * Get the status for a specific local tracking ref update.
+ *
+ * @param localName
+ * name of the local ref (e.g. "refs/remotes/origin/master").
+ * @return status of the local ref; null if this local ref was not touched
+ * during this operation.
+ */
+ public TrackingRefUpdate getTrackingRefUpdate(final String localName) {
+ return updates.get(localName);
+ }
+
+ protected void setAdvertisedRefs(final Map<String, Ref> ar) {
+ advertisedRefs = ar;
+ }
+
+ protected void add(final TrackingRefUpdate u) {
+ updates.put(u.getLocalName(), u);
+ }
+}
\ No newline at end of file
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 05/23] Add RemoteRefUpdate class
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-5-git-send-email-marek.zawirski@gmail.com>
This class holds specification and status of remote ref update during
push operation.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../spearce/jgit/transport/RemoteRefUpdate.java | 315 ++++++++++++++++++++
1 files changed, 315 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/RemoteRefUpdate.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/RemoteRefUpdate.java b/org.spearce.jgit/src/org/spearce/jgit/transport/RemoteRefUpdate.java
new file mode 100644
index 0000000..3737c7a
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/RemoteRefUpdate.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the remoteName of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.io.IOException;
+
+import org.spearce.jgit.lib.ObjectId;
+import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.revwalk.RevWalk;
+
+/**
+ * Represent request and status of a remote ref update. Specification is
+ * provided by client, while status is handled by {@link PushProcess} class,
+ * being read-only for client.
+ * <p>
+ * Client can create instances of this class directly, basing on user
+ * specification and advertised refs ({@link Connection} or through
+ * {@link Transport} helper methods. Apply this specification on remote
+ * repository using
+ * {@link Transport#push(org.spearce.jgit.lib.ProgressMonitor, java.util.Collection)}
+ * method.
+ * </p>
+ *
+ */
+public class RemoteRefUpdate {
+ /**
+ * Represent current status of a remote ref update.
+ */
+ public static enum Status {
+ /**
+ * Push process hasn't yet attempted to update this ref. This is the
+ * default status, prior to push process execution.
+ */
+ NOT_ATTEMPTED,
+
+ /**
+ * Remote ref was up to date, there was no need to update anything.
+ */
+ UP_TO_DATE,
+
+ /**
+ * Remote ref update was rejected, as it would cause non fast-forward
+ * update.
+ */
+ REJECTED_NONFASTFORWARD,
+
+ /**
+ * Remote ref update was rejected, because remote side doesn't
+ * support/allow deleting refs.
+ */
+ REJECTED_NODELETE,
+
+ /**
+ * Remote ref update was rejected, because old object id on remote
+ * repository wasn't the same as defined expected old object.
+ */
+ REJECTED_REMOTE_CHANGED,
+
+ /**
+ * Remote ref update was rejected for other reason, possibly described
+ * in {@link RemoteRefUpdate#getMessage()}.
+ */
+ REJECTED_OTHER_REASON,
+
+ /**
+ * Remote ref didn't exist. Can occur on delete request of a non
+ * existing ref.
+ */
+ NON_EXISTING,
+
+ /**
+ * Push process is awaiting update report from remote repository. This
+ * is a temporary state or state after critical error in push process.
+ */
+ AWAITING_REPORT,
+
+ /**
+ * Remote ref was successfully updated.
+ */
+ OK;
+ }
+
+ private final ObjectId expectedOldObjectId;
+
+ private final ObjectId newObjectId;
+
+ private final String remoteName;
+
+ private final TrackingRefUpdate trackingRefUpdate;
+
+ private String srcRef;
+
+ private final boolean forceUpdate;
+
+ private Status status;
+
+ private boolean fastForward;
+
+ private String message;
+
+ /**
+ * Construct remote ref update request by providing an update specification.
+ * Object is created with default {@link Status#NOT_ATTEMPTED} status and no
+ * message.
+ *
+ * @param db
+ * repository to push from.
+ * @param srcRef
+ * source revision - any string resolvable by
+ * {@link Repository#resolve(String)}. This resolves to the new
+ * object that the caller want remote ref to be after update. Use
+ * null or {@link ObjectId#zeroId()} string for delete request.
+ * @param remoteName
+ * full name of a remote ref to update, e.g. "refs/heads/master"
+ * (no wildcard, no short name).
+ * @param forceUpdate
+ * true when caller want remote ref to be updated regardless
+ * whether it is fast-forward update (old object is ancestor of
+ * new object).
+ * @param localName
+ * optional full name of a local stored tracking branch, to
+ * update after push, e.g. "refs/remotes/zawir/dirty" (no
+ * wildcard, no short name); null if no local tracking branch
+ * should be updated.
+ * @param expectedOldObjectId
+ * optional object id that caller is expecting, requiring to be
+ * advertised by remote side before update; update will take
+ * place ONLY if remote side advertise exactly this expected id;
+ * null if caller doesn't care what object id remote side
+ * advertise. Use {@link ObjectId#zeroId()} when expecting no
+ * remote ref with this name.
+ * @throws IOException
+ * when I/O error occurred during creating
+ * {@link TrackingRefUpdate} for local tracking branch.
+ * @throws IllegalArgumentException
+ * if some required parameter was null or srcRef can't be
+ * resolved to any object.
+ */
+ public RemoteRefUpdate(final Repository db, final String srcRef,
+ final String remoteName, final boolean forceUpdate,
+ final String localName, final ObjectId expectedOldObjectId)
+ throws IOException {
+ if (remoteName == null)
+ throw new IllegalArgumentException("remote name can't be null");
+ this.srcRef = srcRef;
+ this.newObjectId = (srcRef == null ? ObjectId.zeroId() : db
+ .resolve(srcRef));
+ if (newObjectId == null)
+ throw new IllegalArgumentException(
+ "source ref doesn't resolve to any object");
+ this.remoteName = remoteName;
+ this.forceUpdate = forceUpdate;
+ if (localName != null && db != null)
+ trackingRefUpdate = new TrackingRefUpdate(db, localName,
+ remoteName, forceUpdate, newObjectId, "push");
+ else
+ trackingRefUpdate = null;
+ this.expectedOldObjectId = expectedOldObjectId;
+ this.status = Status.NOT_ATTEMPTED;
+ }
+
+ /**
+ * @return expectedOldObjectId required to be advertised by remote side, as
+ * set in constructor; may be null.
+ */
+ public ObjectId getExpectedOldObjectId() {
+ return expectedOldObjectId;
+ }
+
+ /**
+ * @return true if some object is required to be advertised by remote side,
+ * as set in constructor; false otherwise.
+ */
+ public boolean isExpectingOldObjectId() {
+ return expectedOldObjectId != null;
+ }
+
+ /**
+ * @return newObjectId for remote ref, as set in constructor.
+ */
+ public ObjectId getNewObjectId() {
+ return newObjectId;
+ }
+
+ /**
+ * @return true if this update is deleting update; false otherwise.
+ */
+ public boolean isDelete() {
+ return ObjectId.zeroId().equals(newObjectId);
+ }
+
+ /**
+ * @return name of remote ref to update, as set in constructor.
+ */
+ public String getRemoteName() {
+ return remoteName;
+ }
+
+ /**
+ * @return local tracking branch update if localName was set in constructor.
+ */
+ public TrackingRefUpdate getTrackingRefUpdate() {
+ return trackingRefUpdate;
+ }
+
+ /**
+ * @return source revision as specified by user (in constructor), could be
+ * any string parseable by {@link Repository#resolve(String)}; can
+ * be null if specified that way in constructor - this stands for
+ * delete request.
+ */
+ public String getSrcRef() {
+ return srcRef;
+ }
+
+ /**
+ * @return true if user specified a local tracking branch for remote update;
+ * false otherwise.
+ */
+ public boolean hasTrackingRefUpdate() {
+ return trackingRefUpdate != null;
+ }
+
+ /**
+ * @return true if this update is forced regardless of old remote ref
+ * object; false otherwise.
+ */
+ public boolean isForceUpdate() {
+ return forceUpdate;
+ }
+
+ /**
+ * @return status of remote ref update operation.
+ */
+ public Status getStatus() {
+ return status;
+ }
+
+ /**
+ * Check whether update was fast-forward. Note that this result is
+ * meaningful only after successful update (when status is {@link Status#OK}).
+ *
+ * @return true if update was fast-forward; false otherwise.
+ */
+ public boolean isFastForward() {
+ return fastForward;
+ }
+
+ /**
+ * @return message describing reasons of status when needed/possible; may be
+ * null.
+ */
+ public String getMessage() {
+ return message;
+ }
+
+ protected void setStatus(final Status status) {
+ this.status = status;
+ }
+
+ protected void setFastForward(boolean fastForward) {
+ this.fastForward = fastForward;
+ }
+
+ protected void setMessage(final String message) {
+ this.message = message;
+ }
+
+ /**
+ * Update locally stored tracking branch with the new object.
+ *
+ * @param walk
+ * walker used for checking update properties.
+ * @throws IOException
+ * when I/O error occurred during update
+ */
+ protected void updateTrackingRef(final RevWalk walk) throws IOException {
+ trackingRefUpdate.update(walk);
+ }
+}
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 04/23] New constructor without RefSpec for TrackingRefUpdate
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-4-git-send-email-marek.zawirski@gmail.com>
New constructor operates directly on RefSpec components: remote name,
local name, force flag.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../spearce/jgit/transport/TrackingRefUpdate.java | 13 ++++++++++---
1 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java
index 771e77a..a84b38a 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java
@@ -55,9 +55,16 @@ public class TrackingRefUpdate {
TrackingRefUpdate(final Repository db, final RefSpec spec,
final AnyObjectId nv, final String msg) throws IOException {
- remoteName = spec.getSource();
- update = db.updateRef(spec.getDestination());
- update.setForceUpdate(spec.isForceUpdate());
+ this(db, spec.getDestination(), spec.getSource(), spec.isForceUpdate(),
+ nv, msg);
+ }
+
+ TrackingRefUpdate(final Repository db, final String localName,
+ final String remoteName, final boolean forceUpdate,
+ final AnyObjectId nv, final String msg) throws IOException {
+ this.remoteName = remoteName;
+ update = db.updateRef(localName);
+ update.setForceUpdate(forceUpdate);
update.setNewObjectId(nv);
update.setRefLogMessage(msg, true);
}
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 03/23] Refactor TrackingRefUpdate to not hold RefSpec
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-3-git-send-email-marek.zawirski@gmail.com>
Just remoteName is needed, not a whole RefSpec.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../spearce/jgit/transport/TrackingRefUpdate.java | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java
index 56234a1..771e77a 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TrackingRefUpdate.java
@@ -49,14 +49,14 @@ import org.spearce.jgit.revwalk.RevWalk;
/** Update of a locally stored tracking branch. */
public class TrackingRefUpdate {
- private final RefSpec spec;
+ private final String remoteName;
private final RefUpdate update;
- TrackingRefUpdate(final Repository db, final RefSpec s,
+ TrackingRefUpdate(final Repository db, final RefSpec spec,
final AnyObjectId nv, final String msg) throws IOException {
- spec = s;
- update = db.updateRef(s.getDestination());
+ remoteName = spec.getSource();
+ update = db.updateRef(spec.getDestination());
update.setForceUpdate(spec.isForceUpdate());
update.setNewObjectId(nv);
update.setRefLogMessage(msg, true);
@@ -70,7 +70,7 @@ public class TrackingRefUpdate {
* @return the name used within the remote repository.
*/
public String getRemoteName() {
- return spec.getSource();
+ return remoteName;
}
/**
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 02/23] RefUpdate: new possible result Result.IO_FAILURE
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-2-git-send-email-marek.zawirski@gmail.com>
This result indicates that I/O error (beyond of IOException) occurred
during RefUpdate#update().
Hitherto behaviour was to just throw IOException and leave result with
value Result.NOT_ATTEMPTED. It was just less informative.
Fetch class from pgm package needed new conditions for printing. Other
classes were reviewed and should still work just fine.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../src/org/spearce/jgit/lib/RefUpdate.java | 27 +++++++++++++++++--
.../src/org/spearce/jgit/pgm/Fetch.java | 5 +++
2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java
index 48044fb..369cb37 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java
@@ -105,7 +105,18 @@ public class RefUpdate {
* update to take place, so ref still contains the old value. No
* previous history was lost.
*/
- REJECTED
+ REJECTED,
+
+ /**
+ * The ref was probably not updated because of I/O error.
+ * <p>
+ * Unexpected I/O error occurred when writing new ref. Such error may
+ * result in uncertain state, but most probably ref was not updated.
+ * <p>
+ * This kind of error doesn't include {@link #LOCK_FAILURE}, which is a
+ * different case.
+ */
+ IO_FAILURE
}
/** Repository the ref is stored in. */
@@ -256,7 +267,12 @@ public class RefUpdate {
*/
public Result forceUpdate() throws IOException {
requireCanDoUpdate();
- return result = forceUpdateImpl();
+ try {
+ return result = forceUpdateImpl();
+ } catch (IOException x) {
+ result = Result.IO_FAILURE;
+ throw x;
+ }
}
private Result forceUpdateImpl() throws IOException {
@@ -310,7 +326,12 @@ public class RefUpdate {
*/
public Result update(final RevWalk walk) throws IOException {
requireCanDoUpdate();
- return result = updateImpl(walk);
+ try {
+ return result = updateImpl(walk);
+ } catch (IOException x) {
+ result = Result.IO_FAILURE;
+ throw x;
+ }
}
private Result updateImpl(final RevWalk walk) throws IOException {
diff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java
index 6277970..3a81575 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java
@@ -109,6 +109,9 @@ class Fetch extends TextBuiltin {
if (r == RefUpdate.Result.LOCK_FAILURE)
return "[lock fail]";
+ if (r == RefUpdate.Result.IO_FAILURE)
+ return "[i/o error]";
+
if (r == RefUpdate.Result.NEW) {
if (u.getRemoteName().startsWith(REFS_HEADS))
return "[new branch]";
@@ -143,6 +146,8 @@ class Fetch extends TextBuiltin {
private static char shortTypeOf(final RefUpdate.Result r) {
if (r == RefUpdate.Result.LOCK_FAILURE)
return '!';
+ if (r == RefUpdate.Result.IO_FAILURE)
+ return '!';
if (r == RefUpdate.Result.NEW)
return '*';
if (r == RefUpdate.Result.FORCED)
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 01/23] Fix: let FetchProcess use fetch() instead of doFetch()
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-1-git-send-email-marek.zawirski@gmail.com>
doFetch() call didn't check whether fetch() was already performed
(it is intended for internal use), while fetch() does.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../org/spearce/jgit/transport/FetchProcess.java | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java
index afaf9e2..e33b35b 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java
@@ -139,7 +139,7 @@ class FetchProcess {
if (!askFor.isEmpty() && (!includedTags || !askForIsComplete())) {
reopenConnection();
if (!askFor.isEmpty())
- conn.doFetch(monitor, askFor.values());
+ conn.fetch(monitor, askFor.values());
}
}
} finally {
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 00/23] Push implementation
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
Finally, series with push implementation. It has taken a "while" to
squash all bugs this time and polish the series, uhh.
Part of this series is signifficant refactor of .transport package to
support code reuse between fetch and push implementations + minor
fixes/improvements.
Needed push operation elements were created. Implementation provides
basis for different push protocols by common push process and its
dendendencies. Push over git-receive-pack based transports is
implemented.
Shawn is now working on support for push over less git-inteligent
protocols. I'm moving into GUI stuff.
Beside of JUnit test cases for (IMO) 2 most complex classes that
revealed few bugs, I've tested manually pgm.Push extensively.
Each protocol (SSH, local, git-daemon) was tested at least 1 time.
So now I can say, that this branch is available on
http://repo.or.cz/w/egit/zawir.git?a=shortlog;h=refs/heads/push
and it was pushed with jgit push! :) Yeah!
It is based (together with packwriter stuff, not old packwrite branch)
on egit's master: 4cf736fdf3.
BTW, in case of any comments, requests, please consider that I'm
semi-off-line next ~2,5weeks, I can sync my laptop each few days,
but certainly not everyday.
PS I saw that Shawn's sftp-push branch also contains new
TransportException constructors conversion, so we may have to
resolve this duplication, I added it as last commit.
Marek Zawirski (23):
Fix: let FetchProcess use fetch() instead of doFetch()
RefUpdate: new possible result Result.IO_FAILURE
Refactor TrackingRefUpdate to not hold RefSpec
New constructor without RefSpec for TrackingRefUpdate
Add RemoteRefUpdate class
Refactor: extract superclass OperationResult from FetchResult
Add PushResult class
Support for fetchThin and pushThin options in Transport
Big refactor: *Connection hierarchy
Add ignoreMissingUninteresting option to PackWriter
Add BasePackPushConnection implementing git-send-pack protocol
Fix: let RevWalk reset correctly before isMergedInto()
Add PushProcess class implementing git-send-pack logic
Clarify Repository#resolve() documentation
Add String versions of methods in RefSpec
Transport* - general support for push() and implementations
Test cases for PushProcess
Test cases for RefSpec to RemoteRefUpdate conversions
Repository search for command line tools
Push command line utility
Don't accept RefSpec with null source for fetch
Add new handy constructors to TransportException,
PackProtocolException
Use new TransportException constructors
.../tst/org/spearce/jgit/lib/PackWriterTest.java | 45 ++-
.../spearce/jgit/transport/PushProcessTest.java | 407 ++++++++++++++++++++
.../org/spearce/jgit/transport/TransportTest.java | 181 +++++++++
.../spearce/jgit/errors/PackProtocolException.java | 30 ++
.../spearce/jgit/errors/TransportException.java | 31 ++
.../src/org/spearce/jgit/lib/PackWriter.java | 37 ++-
.../src/org/spearce/jgit/lib/RefUpdate.java | 27 ++-
.../src/org/spearce/jgit/lib/Repository.java | 2 +-
.../src/org/spearce/jgit/pgm/Fetch.java | 41 +--
.../src/org/spearce/jgit/pgm/Main.java | 24 +-
.../src/org/spearce/jgit/pgm/Push.java | 235 +++++++++++
.../src/org/spearce/jgit/pgm/TextBuiltin.java | 21 +
.../src/org/spearce/jgit/revwalk/RevWalk.java | 2 +-
.../org/spearce/jgit/transport/BaseConnection.java | 103 +++++
.../jgit/transport/BaseFetchConnection.java | 86 ++++
.../spearce/jgit/transport/BasePackConnection.java | 217 +++++++++++
...onnection.java => BasePackFetchConnection.java} | 169 +--------
.../jgit/transport/BasePackPushConnection.java | 226 +++++++++++
.../src/org/spearce/jgit/transport/Connection.java | 104 +++++
.../spearce/jgit/transport/FetchConnection.java | 127 +-----
.../org/spearce/jgit/transport/FetchProcess.java | 8 +-
.../org/spearce/jgit/transport/FetchResult.java | 74 +----
.../spearce/jgit/transport/OperationResult.java | 119 ++++++
.../org/spearce/jgit/transport/PackTransport.java | 3 +-
.../org/spearce/jgit/transport/PushConnection.java | 56 +++-
.../org/spearce/jgit/transport/PushProcess.java | 224 +++++++++++
.../src/org/spearce/jgit/transport/PushResult.java | 84 ++++
.../src/org/spearce/jgit/transport/RefSpec.java | 46 ++-
.../spearce/jgit/transport/RemoteRefUpdate.java | 315 +++++++++++++++
.../spearce/jgit/transport/TrackingRefUpdate.java | 19 +-
.../src/org/spearce/jgit/transport/Transport.java | 252 ++++++++++++-
.../spearce/jgit/transport/TransportBundle.java | 8 +-
.../spearce/jgit/transport/TransportGitAnon.java | 52 +++-
.../spearce/jgit/transport/TransportGitSsh.java | 67 +++-
.../org/spearce/jgit/transport/TransportLocal.java | 114 ++++--
.../org/spearce/jgit/transport/TransportSftp.java | 12 +-
.../jgit/transport/WalkFetchConnection.java | 2 +-
.../org/spearce/jgit/transport/WalkTransport.java | 7 +
38 files changed, 3103 insertions(+), 474 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/transport/PushProcessTest.java
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BaseConnection.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java
rename org.spearce.jgit/src/org/spearce/jgit/transport/{PackFetchConnection.java => BasePackFetchConnection.java} (75%)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/Connection.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/OperationResult.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/PushResult.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/RemoteRefUpdate.java
^ permalink raw reply
* Re: [PATCH] shrink git-shell by avoiding redundant dependencies
From: Junio C Hamano @ 2008-06-27 21:55 UTC (permalink / raw)
To: Dmitry Potapov; +Cc: Git Mailing List
In-Reply-To: <1214602538-7888-1-git-send-email-dpotapov@gmail.com>
Dmitry Potapov <dpotapov@gmail.com> writes:
> diff --git a/abspath.c b/abspath.c
> new file mode 100644
> index 0000000..4becedf
> --- /dev/null
> +++ b/abspath.c
> @@ -0,0 +1,80 @@
> +/*
> + * I'm tired of doing "vsnprintf()" etc just to open a
> + * file, so here's a "return static buffer with printf"
> + * interface for paths.
> + *
> + * It's obviously not thread-safe. Sue me. But it's quite
> + * useful for doing things like
> + *
> + * f = open(mkpath("%s/%s.git", base, name), O_RDONLY);
> + *
> + * which is what it's designed for.
> + */
This is not a comment you would want to move to the resulting file that
contains only make_absolute_path().
^ permalink raw reply
* Re: is rebase the same as merging every commit?
From: Junio C Hamano @ 2008-06-27 21:51 UTC (permalink / raw)
To: しらいしななこ; +Cc: David Jeske, git
In-Reply-To: <20080627193328.6117@nanako3.lavabit.com>
しらいしななこ <nanako3@lavabit.com> writes:
> Quoting Junio C Hamano <gitster@pobox.com>:
>
>> "David Jeske" <jeske@willowmail.com> writes:
>>
>>> If I understand it right (and that's a BIG if), it's the same as doing a merge
>>> of C into G where every individual commit in the C-line is individually
>>> committed into the new C' line.
>>>
>>> ...........-------------A---B---C
>>> ........../ / / /
>>> ........./ /---A'--B'--C' topic
>>> ......../ /
>>> ....D---E---F---G - master
>>>
>>>
>>> (1) Is the above model a valid explanation?
>>
>> I would presume that the resulting trees A' in the second picture and in
>> the first picture would be the same, so are B' and C'. But that is only
>> true when commits between A and C do not have any duplicate with the
>> development that happened between E and G.
>
> Sorry, but I think you are wrong, Junio.
> ...
> I agree that your explanation why A is not recorded as a parent of A' is
> right for the philosophical reason (the purpose of rebasing to create A'
> is so that you do not have to record them). But from the point-of-view
> of correctness of commit history, I think A must not be recorded as a
> parent of A', either.
All correct. Sorry about the confusion.
^ permalink raw reply
* Re: 'next' will be rewound shortly
From: Miklos Vajna @ 2008-06-27 21:36 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Stephan Beyer, git
In-Reply-To: <7vd4m2r2iq.fsf@gitster.siamese.dyndns.org>
[-- Attachment #1: Type: text/plain, Size: 504 bytes --]
On Fri, Jun 27, 2008 at 02:28:29PM -0700, Junio C Hamano <gitster@pobox.com> wrote:
> Following git tradition, manpage came after the command's behaviour has
> been long established. It will be a behaviour change, and it is open to
> debate if the new behaviour is better or if the proposed change of
> behaviour hurts existing users.
If my opinion counts, I like the current ("prepend") one, and I think
the best would be to add a new option (and/or make it configurable) for
the new ("replace") one.
[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* [PATCH] shrink git-shell by avoiding redundant dependencies
From: Dmitry Potapov @ 2008-06-27 21:35 UTC (permalink / raw)
To: Git Mailing List; +Cc: Dmitry Potapov
A lot of modules that have nothing to do with git-shell functionality
were linked in, bloating git-shell more than 8 times.
This patch cuts off redundant dependencies by:
1. providing stubs for three functions that make no sense for git-shell;
2. moving quote_path_fully from environment.c to quote.c to make the
later self sufficient;
3. moving make_absolute_path into a new separate file.
The following numbers have been received with the default optimization
settings on master using GCC 4.1.2:
Before:
text data bss dec hex filename
143915 1348 93168 238431 3a35f git-shell
After:
text data bss dec hex filename
17670 788 8232 26690 6842 git-shell
---
Makefile | 1 +
abspath.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
environment.c | 1 -
path.c | 67 -----------------------------------------------
quote.c | 2 +
shell.c | 8 +++++
6 files changed, 91 insertions(+), 68 deletions(-)
create mode 100644 abspath.c
diff --git a/Makefile b/Makefile
index 3584b8c..bf77292 100644
--- a/Makefile
+++ b/Makefile
@@ -378,6 +378,7 @@ LIB_H += unpack-trees.h
LIB_H += utf8.h
LIB_H += wt-status.h
+LIB_OBJS += abspath.o
LIB_OBJS += alias.o
LIB_OBJS += alloc.o
LIB_OBJS += archive.o
diff --git a/abspath.c b/abspath.c
new file mode 100644
index 0000000..4becedf
--- /dev/null
+++ b/abspath.c
@@ -0,0 +1,80 @@
+/*
+ * I'm tired of doing "vsnprintf()" etc just to open a
+ * file, so here's a "return static buffer with printf"
+ * interface for paths.
+ *
+ * It's obviously not thread-safe. Sue me. But it's quite
+ * useful for doing things like
+ *
+ * f = open(mkpath("%s/%s.git", base, name), O_RDONLY);
+ *
+ * which is what it's designed for.
+ */
+#include "cache.h"
+
+/* We allow "recursive" symbolic links. Only within reason, though. */
+#define MAXDEPTH 5
+
+const char *make_absolute_path(const char *path)
+{
+ static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
+ char cwd[1024] = "";
+ int buf_index = 1, len;
+
+ int depth = MAXDEPTH;
+ char *last_elem = NULL;
+ struct stat st;
+
+ if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
+ die ("Too long path: %.*s", 60, path);
+
+ while (depth--) {
+ if (stat(buf, &st) || !S_ISDIR(st.st_mode)) {
+ char *last_slash = strrchr(buf, '/');
+ if (last_slash) {
+ *last_slash = '\0';
+ last_elem = xstrdup(last_slash + 1);
+ } else {
+ last_elem = xstrdup(buf);
+ *buf = '\0';
+ }
+ }
+
+ if (*buf) {
+ if (!*cwd && !getcwd(cwd, sizeof(cwd)))
+ die ("Could not get current working directory");
+
+ if (chdir(buf))
+ die ("Could not switch to '%s'", buf);
+ }
+ if (!getcwd(buf, PATH_MAX))
+ die ("Could not get current working directory");
+
+ if (last_elem) {
+ int len = strlen(buf);
+ if (len + strlen(last_elem) + 2 > PATH_MAX)
+ die ("Too long path name: '%s/%s'",
+ buf, last_elem);
+ buf[len] = '/';
+ strcpy(buf + len + 1, last_elem);
+ free(last_elem);
+ last_elem = NULL;
+ }
+
+ if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
+ len = readlink(buf, next_buf, PATH_MAX);
+ if (len < 0)
+ die ("Invalid symlink: %s", buf);
+ next_buf[len] = '\0';
+ buf = next_buf;
+ buf_index = 1 - buf_index;
+ next_buf = bufs[buf_index];
+ } else
+ break;
+ }
+
+ if (*cwd && chdir(cwd))
+ die ("Could not change back to '%s'", cwd);
+
+ return buf;
+}
diff --git a/environment.c b/environment.c
index 084ac8a..4a88a17 100644
--- a/environment.c
+++ b/environment.c
@@ -13,7 +13,6 @@ char git_default_email[MAX_GITNAME];
char git_default_name[MAX_GITNAME];
int user_ident_explicitly_given;
int trust_executable_bit = 1;
-int quote_path_fully = 1;
int has_symlinks = 1;
int ignore_case;
int assume_unchanged;
diff --git a/path.c b/path.c
index 6e3df18..496123c 100644
--- a/path.c
+++ b/path.c
@@ -327,9 +327,6 @@ const char *make_nonrelative_path(const char *path)
return buf;
}
-/* We allow "recursive" symbolic links. Only within reason, though. */
-#define MAXDEPTH 5
-
const char *make_relative_path(const char *abs, const char *base)
{
static char buf[PATH_MAX + 1];
@@ -346,67 +343,3 @@ const char *make_relative_path(const char *abs, const char *base)
strcpy(buf, abs + baselen);
return buf;
}
-
-const char *make_absolute_path(const char *path)
-{
- static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
- char cwd[1024] = "";
- int buf_index = 1, len;
-
- int depth = MAXDEPTH;
- char *last_elem = NULL;
- struct stat st;
-
- if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
- die ("Too long path: %.*s", 60, path);
-
- while (depth--) {
- if (stat(buf, &st) || !S_ISDIR(st.st_mode)) {
- char *last_slash = strrchr(buf, '/');
- if (last_slash) {
- *last_slash = '\0';
- last_elem = xstrdup(last_slash + 1);
- } else {
- last_elem = xstrdup(buf);
- *buf = '\0';
- }
- }
-
- if (*buf) {
- if (!*cwd && !getcwd(cwd, sizeof(cwd)))
- die ("Could not get current working directory");
-
- if (chdir(buf))
- die ("Could not switch to '%s'", buf);
- }
- if (!getcwd(buf, PATH_MAX))
- die ("Could not get current working directory");
-
- if (last_elem) {
- int len = strlen(buf);
- if (len + strlen(last_elem) + 2 > PATH_MAX)
- die ("Too long path name: '%s/%s'",
- buf, last_elem);
- buf[len] = '/';
- strcpy(buf + len + 1, last_elem);
- free(last_elem);
- last_elem = NULL;
- }
-
- if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
- len = readlink(buf, next_buf, PATH_MAX);
- if (len < 0)
- die ("Invalid symlink: %s", buf);
- next_buf[len] = '\0';
- buf = next_buf;
- buf_index = 1 - buf_index;
- next_buf = bufs[buf_index];
- } else
- break;
- }
-
- if (*cwd && chdir(cwd))
- die ("Could not change back to '%s'", cwd);
-
- return buf;
-}
diff --git a/quote.c b/quote.c
index d5cf9d8..6a52085 100644
--- a/quote.c
+++ b/quote.c
@@ -1,6 +1,8 @@
#include "cache.h"
#include "quote.h"
+int quote_path_fully = 1;
+
/* Help to copy the thing properly quoted for the shell safety.
* any single quote is replaced with '\'', any exclamation point
* is replaced with '\!', and the whole thing is enclosed in a
diff --git a/shell.c b/shell.c
index b27d01c..91ca7de 100644
--- a/shell.c
+++ b/shell.c
@@ -3,6 +3,14 @@
#include "exec_cmd.h"
#include "strbuf.h"
+/* Stubs for functions that make no sense for git-shell. These stubs
+ * are provided here to avoid linking in external redundant modules.
+ */
+void release_pack_memory(size_t need, int fd){}
+void trace_argv_printf(const char **argv, const char *fmt, ...){}
+void trace_printf(const char *fmt, ...){}
+
+
static int do_generic_cmd(const char *me, char *arg)
{
const char *my_argv[4];
--
1.5.6.1
^ permalink raw reply related
* Re: 'next' will be rewound shortly
From: Junio C Hamano @ 2008-06-27 21:28 UTC (permalink / raw)
To: Miklos Vajna; +Cc: Stephan Beyer, git
In-Reply-To: <20080627192819.GC2058@genesis.frugalware.org>
Miklos Vajna <vmiklos@frugalware.org> writes:
> On Fri, Jun 27, 2008 at 07:19:48PM +0200, Stephan Beyer <s-beyer@gmx.net> wrote:
>> -m <msg>::
>> The commit message to be used for the merge commit (in case
>> it is created). The `git-fmt-merge-msg` script can be used
>> to give a good default for automated `git-merge` invocations.
>>
>> So it is not mentioned that a standard message is appended, and thus the
>> original behavior is somehow "buggy" :)
>
> Ah, OK. Then the code and the documentation differs and that's a bug,
> sure.
>
> From git-merge.sh:
>
> # All the rest are the commits being merged; prepare
> # the standard merge summary message to be appended to
> # the given message.
>
> I did builtin-merge based on git-merge.sh, not the manpage. ;-)
Following git tradition, manpage came after the command's behaviour has
been long established. It will be a behaviour change, and it is open to
debate if the new behaviour is better or if the proposed change of
behaviour hurts existing users.
^ permalink raw reply
* Make test on AIX
From: Craig L. Ching @ 2008-06-27 21:13 UTC (permalink / raw)
To: git
Hi all,
I just got through a rather painful build and install of 1.5.6.1 on AIX
and I was wondering if anyone has any clues on how to get the tests to
run a bit better there.
The first thing I encountered was that because the tests all use
#!/bin/sh the exit code was not what the tests expected. So I ended up
running 'make SHELL=`which bash` all' directly in the git/t/ directory.
That seemed to shake out and work for most of the tests except for
t/t7502-commit.sh. Try as I might, I could not get SHELL_PATH set to
anything but /bin/sh except to hard-code the SHELL_PATH in this script.
Am I missing something? Is there an easier way to get the test suite to
work? If so, I appreciate any advice. If not, does anyone have any
ideas on how I might fix this and create a patch for git to submit? I
don't claim to be a make or bash expert, so go easy on me if I've missed
something obvious ;-)
Any help appreciated!
Cheers,
Craig
^ permalink raw reply
* Re: An alternate model for preparing partial commits
From: David Jeske @ 2008-06-27 20:51 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <g43jlg$54g$1@ger.gmane.org>
-- Jakub Narebski wrote:
> git rebase --interactive?
> Any patch management interface (StGIT, Guilt)?
Yes, as I said, that set of operations can be performed with git today.
What git can't do, is let me "supercede" the old DAG-subset, so people I shared
them with can get my new changes without hurting their world. Currently git
seems to rely on the idea that "if you accept changes into your tree that will
be later rebased, it's up to you to figure it out". I don't see why that is the
case.
^ permalink raw reply
* Re: An alternate model for preparing partial commits
From: David Jeske @ 2008-06-27 20:51 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <g43jlg$54g$1@ger.gmane.org>
-- Jakub Narebski wrote:
> git rebase --interactive?
> Any patch management interface (StGIT, Guilt)?
Yes, as I said, that set of operations can be performed with git today.
What git can't do, is let me "supercede" the old DAG-subset, so people I shared
them with can get my new changes without hurting their world. Currently git
seems to rely on the idea that "if you accept changes into your tree that will
be later rebased, it's up to you to figure it out". I don't see why that is the
case.
^ permalink raw reply
* found some nice git scripts
From: Raimund Bauer @ 2008-06-27 20:49 UTC (permalink / raw)
To: git
Maybe somebody else find them useful too:
http://git-wt-commit.rubyforge.org/
regards,
Ray
^ permalink raw reply
* Re: An alternate model for preparing partial commits
From: Jakub Narebski @ 2008-06-27 20:47 UTC (permalink / raw)
To: git
In-Reply-To: <16460.6618382551$1214599182@news.gmane.org>
David Jeske wrote:
> reorder: Picture that a list of commits on this branch opens in an editor. You
> are free to rearrange the lines in any order you want, but you have to keep all
> the lines. When you are done reordering the lines, the tool creates a new topic
> branch and applies the changes (probably with cherrypick) to the new topic
> branch. If there are no conflicts, you're done.
>
> merge: Picture now that in your editor you can create groupings of those
> individual commits that should make up separate topic-branches. The operation
> can still be performed automatically, and at the end, it can compose those
> topic branches into a single branch just like your original. At this point, you
> can "isolate" any one of those topic branches and test/push that topic branch.
git rebase --interactive?
Any patch management interface (StGIT, Guilt)?
--
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
^ permalink raw reply
* Re: An alternate model for preparing partial commits
From: David Jeske @ 2008-06-27 20:45 UTC (permalink / raw)
To: Stephen Sinclair; +Cc: Git Mailing List
In-Reply-To: <9b3e2dc20806271331l2870ef94o4cd413ee40ab0d39@mail.gmail.com>
-- Stephen Sinclair wrote:
> However, having gotten used to the git way of things, I
> personally don't see the problem with allowing
> bad commits, as long as they are not pushed to public.
Of course developers need to be able to make bad-commits. If they can't, we
quickly end up back in the "don't checkin" mentality of CVS. I want to be able
to do bad-commits. Further, I recognize that even with the best of intentions
bad-commits will enter the mainline. What I think is missing is a mechanism for
re-summarizing a set of committs that does not rely on the fact that they've
never been published. See my other email on "supercede"..
Consider a big public tree that is using bisect, but discovers that there is a
bad commit in the mainline. I have no idea what you would do with current git
to fix this. However, if I could pick two endpoints and "supercede" them, I
would have a bunch of options:
- I could supercede 2-commits with 1, effectively making the bad-commit
disappear in the linear history. Users who already have the history, however,
would be unaffected, because the start/end endpoints are the same.
- I could supercede 2-commits with two different commits, one that makes the
test pass correctly, and one that trues-it-up with the next patch, that somehow
made all the tests pass correctly again. (possibly by hoisting a diff out of
the 2nd commit that actually fixed the first issue)
While repairing an old test build problem may seem like an infrequent issue,
this mechanism has a much more frequent and more important benefit... which is
that people can share changes and then later rebase them -- and others who have
a copy of that branch will receive automatic merge/rebase support. (assuming
there are not reasons for conflict)
^ permalink raw reply
* Re: An alternate model for preparing partial commits
From: David Jeske @ 2008-06-27 20:45 UTC (permalink / raw)
To: Stephen Sinclair; +Cc: Git Mailing List
In-Reply-To: <9b3e2dc20806271331l2870ef94o4cd413ee40ab0d39@mail.gmail.com>
-- Stephen Sinclair wrote:
> However, having gotten used to the git way of things, I
> personally don't see the problem with allowing
> bad commits, as long as they are not pushed to public.
Of course developers need to be able to make bad-commits. If they can't, we
quickly end up back in the "don't checkin" mentality of CVS. I want to be able
to do bad-commits. Further, I recognize that even with the best of intentions
bad-commits will enter the mainline. What I think is missing is a mechanism for
re-summarizing a set of committs that does not rely on the fact that they've
never been published. See my other email on "supercede"..
Consider a big public tree that is using bisect, but discovers that there is a
bad commit in the mainline. I have no idea what you would do with current git
to fix this. However, if I could pick two endpoints and "supercede" them, I
would have a bunch of options:
- I could supercede 2-commits with 1, effectively making the bad-commit
disappear in the linear history. Users who already have the history, however,
would be unaffected, because the start/end endpoints are the same.
- I could supercede 2-commits with two different commits, one that makes the
test pass correctly, and one that trues-it-up with the next patch, that somehow
made all the tests pass correctly again. (possibly by hoisting a diff out of
the 2nd commit that actually fixed the first issue)
While repairing an old test build problem may seem like an infrequent issue,
this mechanism has a much more frequent and more important benefit... which is
that people can share changes and then later rebase them -- and others who have
a copy of that branch will receive automatic merge/rebase support. (assuming
there are not reasons for conflict)
^ permalink raw reply
* Re: An alternate model for preparing partial commits
From: David Jeske @ 2008-06-27 20:29 UTC (permalink / raw)
To: Robert Anderson; +Cc: Git Mailing List
In-Reply-To: <9af502e50806262350t6e794a92g7751147f1882965@mail.gmail.com>
Robert, I'm new to git, but I understand where you are going.
Why limit it only to working tree changes? For me, the stash machinery is of no
help here, because I commit super-often. What I end up with is 30 commits in a
topic branch, but where not every point passes 100% of tests. I want to go back
through and order them properly, and decide which points are sensible as
upstream committs. (especially as I read more about bisect).
git has all the concepts I want except one. However, it makes the process
pretty manual. Here is an idea about automating it. I'll talk about that one
new concept at the bottom.
I think of this as reorder/merge/split...
reorder: Picture that a list of commits on this branch opens in an editor. You
are free to rearrange the lines in any order you want, but you have to keep all
the lines. When you are done reordering the lines, the tool creates a new topic
branch and applies the changes (probably with cherrypick) to the new topic
branch. If there are no conflicts, you're done.
merge: Picture now that in your editor you can create groupings of those
individual commits that should make up separate topic-branches. The operation
can still be performed automatically, and at the end, it can compose those
topic branches into a single branch just like your original. At this point, you
can "isolate" any one of those topic branches and test/push that topic branch.
split: Picture now that you can list the same commit in more than one of the
topic-branches. This is a little more tricky, and there is no way to do it
automatically.. It drops you into an editor and asks you to select the lines of
the diff for the first topic. The remaining lines are put in the next topic.
This can continue for multiple topics.
This seems like something that could be assembled pretty easily on top of the
current git mechanisms, except for one thing.
If you use merge, the history will be a mess. If you use rebase, anyone else
who pulled your topic branch will be in a world of hurt.
I've been thinking about a solution for this I think of as "supercede".
Once you have completed the above reorder/merge/split, your new topic branch
should be EXACTLY the same as your old topic branch. (if it's not, it needs to
be trued up to be so). At that point, it is safe to ask for that new line of
commits to supercede the old line. Other people who have pulled in your older
ordered topic branch would then be able to pull/rebase/etc, and the merge
machinery would be able to back out their set of changes, and supercede them
with your new ordering.
This mechanism is intended to combine the benefits of rebase-clean-history and
the benefits of the dag-links for merging. I find it convenient to think of it
as stack push/pop for portions of the dag. Because of the supercede - the
history knows it can avoid showing you all the superceded dag nodes, however,
because those nodes are there, it can still use them to compute merges.
If this behaves the way I think, this has another powerful effect. You can pull
in a set of draft changes; you can build off them; you can periodically rebase
them, and if those draft changes end up in the mainline, because the
merge-history is still there, git can 'do the right thing' and remove those
changes from your topic branch. In fact, because of the SHA1 strong naming, it
doesn't even matter where you got them from. You could apply a patch from the
mailing list and as long as everyone applies that patch as only a single
commit, when the string of supercedes shows up on the main branch git will just
'do-the right thing' to remove them from your topic branch when you rebase (or
skip them during a merge down to your topic branch).
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox