You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TransportLocal.java 14KB

Capture non-progress side band #2 messages and put in result Any messages received on side band #2 that aren't scraped as a progress message into our ProgressMonitor are now forwarded to a buffer which is later included into the OperationResult object. Application callers can use this buffer to present the additional messages from the remote peer after the push or fetch operation has concluded. The smart push connections using the native send-pack/receive-pack protocol now request side-band-64k capability if it is available and forward any messages received through that channel onto this message buffer. This makes hook messages available over smart HTTP, or even over SSH. The SSH transport was modified to redirect the remote command's stderr stream into the message buffer, interleaved with any data received over side band #2. Due to buffering between these two different channels in the SSH channel mux itself the order of any writes between the two cannot be ensured, but it tries to stay close. The local fork transport was also modified to redirect the local receive-pack's stderr into the message buffer, rather than going to the invoking JVM's System.err. This gives applications a chance to log the local error messages, rather than needing to redirect their JVM's stderr before startup. To keep things simple, the application has to wait for the entire operation to complete before it can see the messages. This may be a downside if the user is trying to debug a remote hook that is blocking indefinitely, the user would need to abort the connection before they can inspect the message buffer in any sort of UI built on top of JGit. Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
14 years ago
Capture non-progress side band #2 messages and put in result Any messages received on side band #2 that aren't scraped as a progress message into our ProgressMonitor are now forwarded to a buffer which is later included into the OperationResult object. Application callers can use this buffer to present the additional messages from the remote peer after the push or fetch operation has concluded. The smart push connections using the native send-pack/receive-pack protocol now request side-band-64k capability if it is available and forward any messages received through that channel onto this message buffer. This makes hook messages available over smart HTTP, or even over SSH. The SSH transport was modified to redirect the remote command's stderr stream into the message buffer, interleaved with any data received over side band #2. Due to buffering between these two different channels in the SSH channel mux itself the order of any writes between the two cannot be ensured, but it tries to stay close. The local fork transport was also modified to redirect the local receive-pack's stderr into the message buffer, rather than going to the invoking JVM's System.err. This gives applications a chance to log the local error messages, rather than needing to redirect their JVM's stderr before startup. To keep things simple, the application has to wait for the entire operation to complete before it can see the messages. This may be a downside if the user is trying to debug a remote hook that is blocking indefinitely, the user would need to abort the connection before they can inspect the message buffer in any sort of UI built on top of JGit. Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
14 years ago
Capture non-progress side band #2 messages and put in result Any messages received on side band #2 that aren't scraped as a progress message into our ProgressMonitor are now forwarded to a buffer which is later included into the OperationResult object. Application callers can use this buffer to present the additional messages from the remote peer after the push or fetch operation has concluded. The smart push connections using the native send-pack/receive-pack protocol now request side-band-64k capability if it is available and forward any messages received through that channel onto this message buffer. This makes hook messages available over smart HTTP, or even over SSH. The SSH transport was modified to redirect the remote command's stderr stream into the message buffer, interleaved with any data received over side band #2. Due to buffering between these two different channels in the SSH channel mux itself the order of any writes between the two cannot be ensured, but it tries to stay close. The local fork transport was also modified to redirect the local receive-pack's stderr into the message buffer, rather than going to the invoking JVM's System.err. This gives applications a chance to log the local error messages, rather than needing to redirect their JVM's stderr before startup. To keep things simple, the application has to wait for the entire operation to complete before it can see the messages. This may be a downside if the user is trying to debug a remote hook that is blocking indefinitely, the user would need to abort the connection before they can inspect the message buffer in any sort of UI built on top of JGit. Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
14 years ago
Capture non-progress side band #2 messages and put in result Any messages received on side band #2 that aren't scraped as a progress message into our ProgressMonitor are now forwarded to a buffer which is later included into the OperationResult object. Application callers can use this buffer to present the additional messages from the remote peer after the push or fetch operation has concluded. The smart push connections using the native send-pack/receive-pack protocol now request side-band-64k capability if it is available and forward any messages received through that channel onto this message buffer. This makes hook messages available over smart HTTP, or even over SSH. The SSH transport was modified to redirect the remote command's stderr stream into the message buffer, interleaved with any data received over side band #2. Due to buffering between these two different channels in the SSH channel mux itself the order of any writes between the two cannot be ensured, but it tries to stay close. The local fork transport was also modified to redirect the local receive-pack's stderr into the message buffer, rather than going to the invoking JVM's System.err. This gives applications a chance to log the local error messages, rather than needing to redirect their JVM's stderr before startup. To keep things simple, the application has to wait for the entire operation to complete before it can see the messages. This may be a downside if the user is trying to debug a remote hook that is blocking indefinitely, the user would need to abort the connection before they can inspect the message buffer in any sort of UI built on top of JGit. Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
14 years ago
Capture non-progress side band #2 messages and put in result Any messages received on side band #2 that aren't scraped as a progress message into our ProgressMonitor are now forwarded to a buffer which is later included into the OperationResult object. Application callers can use this buffer to present the additional messages from the remote peer after the push or fetch operation has concluded. The smart push connections using the native send-pack/receive-pack protocol now request side-band-64k capability if it is available and forward any messages received through that channel onto this message buffer. This makes hook messages available over smart HTTP, or even over SSH. The SSH transport was modified to redirect the remote command's stderr stream into the message buffer, interleaved with any data received over side band #2. Due to buffering between these two different channels in the SSH channel mux itself the order of any writes between the two cannot be ensured, but it tries to stay close. The local fork transport was also modified to redirect the local receive-pack's stderr into the message buffer, rather than going to the invoking JVM's System.err. This gives applications a chance to log the local error messages, rather than needing to redirect their JVM's stderr before startup. To keep things simple, the application has to wait for the entire operation to complete before it can see the messages. This may be a downside if the user is trying to debug a remote hook that is blocking indefinitely, the user would need to abort the connection before they can inspect the message buffer in any sort of UI built on top of JGit. Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
14 years ago
Capture non-progress side band #2 messages and put in result Any messages received on side band #2 that aren't scraped as a progress message into our ProgressMonitor are now forwarded to a buffer which is later included into the OperationResult object. Application callers can use this buffer to present the additional messages from the remote peer after the push or fetch operation has concluded. The smart push connections using the native send-pack/receive-pack protocol now request side-band-64k capability if it is available and forward any messages received through that channel onto this message buffer. This makes hook messages available over smart HTTP, or even over SSH. The SSH transport was modified to redirect the remote command's stderr stream into the message buffer, interleaved with any data received over side band #2. Due to buffering between these two different channels in the SSH channel mux itself the order of any writes between the two cannot be ensured, but it tries to stay close. The local fork transport was also modified to redirect the local receive-pack's stderr into the message buffer, rather than going to the invoking JVM's System.err. This gives applications a chance to log the local error messages, rather than needing to redirect their JVM's stderr before startup. To keep things simple, the application has to wait for the entire operation to complete before it can see the messages. This may be a downside if the user is trying to debug a remote hook that is blocking indefinitely, the user would need to abort the connection before they can inspect the message buffer in any sort of UI built on top of JGit. Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
14 years ago
Capture non-progress side band #2 messages and put in result Any messages received on side band #2 that aren't scraped as a progress message into our ProgressMonitor are now forwarded to a buffer which is later included into the OperationResult object. Application callers can use this buffer to present the additional messages from the remote peer after the push or fetch operation has concluded. The smart push connections using the native send-pack/receive-pack protocol now request side-band-64k capability if it is available and forward any messages received through that channel onto this message buffer. This makes hook messages available over smart HTTP, or even over SSH. The SSH transport was modified to redirect the remote command's stderr stream into the message buffer, interleaved with any data received over side band #2. Due to buffering between these two different channels in the SSH channel mux itself the order of any writes between the two cannot be ensured, but it tries to stay close. The local fork transport was also modified to redirect the local receive-pack's stderr into the message buffer, rather than going to the invoking JVM's System.err. This gives applications a chance to log the local error messages, rather than needing to redirect their JVM's stderr before startup. To keep things simple, the application has to wait for the entire operation to complete before it can see the messages. This may be a downside if the user is trying to debug a remote hook that is blocking indefinitely, the user would need to abort the connection before they can inspect the message buffer in any sort of UI built on top of JGit. Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
14 years ago
Capture non-progress side band #2 messages and put in result Any messages received on side band #2 that aren't scraped as a progress message into our ProgressMonitor are now forwarded to a buffer which is later included into the OperationResult object. Application callers can use this buffer to present the additional messages from the remote peer after the push or fetch operation has concluded. The smart push connections using the native send-pack/receive-pack protocol now request side-band-64k capability if it is available and forward any messages received through that channel onto this message buffer. This makes hook messages available over smart HTTP, or even over SSH. The SSH transport was modified to redirect the remote command's stderr stream into the message buffer, interleaved with any data received over side band #2. Due to buffering between these two different channels in the SSH channel mux itself the order of any writes between the two cannot be ensured, but it tries to stay close. The local fork transport was also modified to redirect the local receive-pack's stderr into the message buffer, rather than going to the invoking JVM's System.err. This gives applications a chance to log the local error messages, rather than needing to redirect their JVM's stderr before startup. To keep things simple, the application has to wait for the entire operation to complete before it can see the messages. This may be a downside if the user is trying to debug a remote hook that is blocking indefinitely, the user would need to abort the connection before they can inspect the message buffer in any sort of UI built on top of JGit. Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
14 years ago
Capture non-progress side band #2 messages and put in result Any messages received on side band #2 that aren't scraped as a progress message into our ProgressMonitor are now forwarded to a buffer which is later included into the OperationResult object. Application callers can use this buffer to present the additional messages from the remote peer after the push or fetch operation has concluded. The smart push connections using the native send-pack/receive-pack protocol now request side-band-64k capability if it is available and forward any messages received through that channel onto this message buffer. This makes hook messages available over smart HTTP, or even over SSH. The SSH transport was modified to redirect the remote command's stderr stream into the message buffer, interleaved with any data received over side band #2. Due to buffering between these two different channels in the SSH channel mux itself the order of any writes between the two cannot be ensured, but it tries to stay close. The local fork transport was also modified to redirect the local receive-pack's stderr into the message buffer, rather than going to the invoking JVM's System.err. This gives applications a chance to log the local error messages, rather than needing to redirect their JVM's stderr before startup. To keep things simple, the application has to wait for the entire operation to complete before it can see the messages. This may be a downside if the user is trying to debug a remote hook that is blocking indefinitely, the user would need to abort the connection before they can inspect the message buffer in any sort of UI built on top of JGit. Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
14 years ago
Capture non-progress side band #2 messages and put in result Any messages received on side band #2 that aren't scraped as a progress message into our ProgressMonitor are now forwarded to a buffer which is later included into the OperationResult object. Application callers can use this buffer to present the additional messages from the remote peer after the push or fetch operation has concluded. The smart push connections using the native send-pack/receive-pack protocol now request side-band-64k capability if it is available and forward any messages received through that channel onto this message buffer. This makes hook messages available over smart HTTP, or even over SSH. The SSH transport was modified to redirect the remote command's stderr stream into the message buffer, interleaved with any data received over side band #2. Due to buffering between these two different channels in the SSH channel mux itself the order of any writes between the two cannot be ensured, but it tries to stay close. The local fork transport was also modified to redirect the local receive-pack's stderr into the message buffer, rather than going to the invoking JVM's System.err. This gives applications a chance to log the local error messages, rather than needing to redirect their JVM's stderr before startup. To keep things simple, the application has to wait for the entire operation to complete before it can see the messages. This may be a downside if the user is trying to debug a remote hook that is blocking indefinitely, the user would need to abort the connection before they can inspect the message buffer in any sort of UI built on top of JGit. Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
14 years ago
Capture non-progress side band #2 messages and put in result Any messages received on side band #2 that aren't scraped as a progress message into our ProgressMonitor are now forwarded to a buffer which is later included into the OperationResult object. Application callers can use this buffer to present the additional messages from the remote peer after the push or fetch operation has concluded. The smart push connections using the native send-pack/receive-pack protocol now request side-band-64k capability if it is available and forward any messages received through that channel onto this message buffer. This makes hook messages available over smart HTTP, or even over SSH. The SSH transport was modified to redirect the remote command's stderr stream into the message buffer, interleaved with any data received over side band #2. Due to buffering between these two different channels in the SSH channel mux itself the order of any writes between the two cannot be ensured, but it tries to stay close. The local fork transport was also modified to redirect the local receive-pack's stderr into the message buffer, rather than going to the invoking JVM's System.err. This gives applications a chance to log the local error messages, rather than needing to redirect their JVM's stderr before startup. To keep things simple, the application has to wait for the entire operation to complete before it can see the messages. This may be a downside if the user is trying to debug a remote hook that is blocking indefinitely, the user would need to abort the connection before they can inspect the message buffer in any sort of UI built on top of JGit. Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
14 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. /*
  2. * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
  3. * Copyright (C) 2008-2010, Google Inc.
  4. * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
  5. * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
  6. * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
  7. * and other copyright owners as documented in the project's IP log.
  8. *
  9. * This program and the accompanying materials are made available
  10. * under the terms of the Eclipse Distribution License v1.0 which
  11. * accompanies this distribution, is reproduced below, and is
  12. * available at http://www.eclipse.org/org/documents/edl-v10.php
  13. *
  14. * All rights reserved.
  15. *
  16. * Redistribution and use in source and binary forms, with or
  17. * without modification, are permitted provided that the following
  18. * conditions are met:
  19. *
  20. * - Redistributions of source code must retain the above copyright
  21. * notice, this list of conditions and the following disclaimer.
  22. *
  23. * - Redistributions in binary form must reproduce the above
  24. * copyright notice, this list of conditions and the following
  25. * disclaimer in the documentation and/or other materials provided
  26. * with the distribution.
  27. *
  28. * - Neither the name of the Eclipse Foundation, Inc. nor the
  29. * names of its contributors may be used to endorse or promote
  30. * products derived from this software without specific prior
  31. * written permission.
  32. *
  33. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  34. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  35. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  36. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  37. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  38. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  39. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  40. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  41. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  42. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  43. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  44. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  45. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  46. */
  47. package org.eclipse.jgit.transport;
  48. import java.io.BufferedInputStream;
  49. import java.io.File;
  50. import java.io.IOException;
  51. import java.io.InputStream;
  52. import java.io.OutputStream;
  53. import java.io.PipedInputStream;
  54. import java.io.PipedOutputStream;
  55. import java.util.Collections;
  56. import java.util.Map;
  57. import java.util.Set;
  58. import org.eclipse.jgit.errors.NoRemoteRepositoryException;
  59. import org.eclipse.jgit.errors.NotSupportedException;
  60. import org.eclipse.jgit.errors.TransportException;
  61. import org.eclipse.jgit.internal.JGitText;
  62. import org.eclipse.jgit.lib.Repository;
  63. import org.eclipse.jgit.lib.RepositoryBuilder;
  64. import org.eclipse.jgit.lib.RepositoryCache;
  65. import org.eclipse.jgit.util.io.MessageWriter;
  66. import org.eclipse.jgit.util.io.SafeBufferedOutputStream;
  67. import org.eclipse.jgit.util.io.StreamCopyThread;
  68. /**
  69. * Transport to access a local directory as though it were a remote peer.
  70. * <p>
  71. * This transport is suitable for use on the local system, where the caller has
  72. * direct read or write access to the "remote" repository.
  73. * <p>
  74. * By default this transport works by spawning a helper thread within the same
  75. * JVM, and processes the data transfer using a shared memory buffer between the
  76. * calling thread and the helper thread. This is a pure-Java implementation
  77. * which does not require forking an external process.
  78. * <p>
  79. * However, during {@link #openFetch()}, if the Transport has configured
  80. * {@link Transport#getOptionUploadPack()} to be anything other than
  81. * <code>"git-upload-pack"</code> or <code>"git upload-pack"</code>, this
  82. * implementation will fork and execute the external process, using an operating
  83. * system pipe to transfer data.
  84. * <p>
  85. * Similarly, during {@link #openPush()}, if the Transport has configured
  86. * {@link Transport#getOptionReceivePack()} to be anything other than
  87. * <code>"git-receive-pack"</code> or <code>"git receive-pack"</code>, this
  88. * implementation will fork and execute the external process, using an operating
  89. * system pipe to transfer data.
  90. */
  91. class TransportLocal extends Transport implements PackTransport {
  92. static final TransportProtocol PROTO_LOCAL = new TransportProtocol() {
  93. @Override
  94. public String getName() {
  95. return JGitText.get().transportProtoLocal;
  96. }
  97. public Set<String> getSchemes() {
  98. return Collections.singleton("file"); //$NON-NLS-1$
  99. }
  100. @Override
  101. public boolean canHandle(URIish uri, Repository local, String remoteName) {
  102. if (uri.getPath() == null
  103. || uri.getPort() > 0
  104. || uri.getUser() != null
  105. || uri.getPass() != null
  106. || uri.getHost() != null
  107. || (uri.getScheme() != null && !getSchemes().contains(uri.getScheme())))
  108. return false;
  109. return true;
  110. }
  111. @Override
  112. public Transport open(URIish uri, Repository local, String remoteName)
  113. throws NoRemoteRepositoryException {
  114. File localPath = local.isBare() ? local.getDirectory() : local.getWorkTree();
  115. File path = local.getFS().resolve(localPath, uri.getPath());
  116. // If the reference is to a local file, C Git behavior says
  117. // assume this is a bundle, since repositories are directories.
  118. if (path.isFile())
  119. return new TransportBundleFile(local, uri, path);
  120. File gitDir = RepositoryCache.FileKey.resolve(path, local.getFS());
  121. if (gitDir == null)
  122. throw new NoRemoteRepositoryException(uri, JGitText.get().notFound);
  123. return new TransportLocal(local, uri, gitDir);
  124. }
  125. };
  126. private final File remoteGitDir;
  127. TransportLocal(Repository local, URIish uri, File gitDir) {
  128. super(local, uri);
  129. remoteGitDir = gitDir;
  130. }
  131. UploadPack createUploadPack(final Repository dst) {
  132. return new UploadPack(dst);
  133. }
  134. ReceivePack createReceivePack(final Repository dst) {
  135. return new ReceivePack(dst);
  136. }
  137. @Override
  138. public FetchConnection openFetch() throws TransportException {
  139. final String up = getOptionUploadPack();
  140. if ("git-upload-pack".equals(up) || "git upload-pack".equals(up)) //$NON-NLS-1$ //$NON-NLS-2$
  141. return new InternalLocalFetchConnection();
  142. return new ForkLocalFetchConnection();
  143. }
  144. @Override
  145. public PushConnection openPush() throws NotSupportedException,
  146. TransportException {
  147. final String rp = getOptionReceivePack();
  148. if ("git-receive-pack".equals(rp) || "git receive-pack".equals(rp)) //$NON-NLS-1$ //$NON-NLS-2$
  149. return new InternalLocalPushConnection();
  150. return new ForkLocalPushConnection();
  151. }
  152. @Override
  153. public void close() {
  154. // Resources must be established per-connection.
  155. }
  156. protected Process spawn(final String cmd)
  157. throws TransportException {
  158. try {
  159. String[] args = { "." }; //$NON-NLS-1$
  160. ProcessBuilder proc = local.getFS().runInShell(cmd, args);
  161. proc.directory(remoteGitDir);
  162. // Remove the same variables CGit does.
  163. Map<String, String> env = proc.environment();
  164. env.remove("GIT_ALTERNATE_OBJECT_DIRECTORIES"); //$NON-NLS-1$
  165. env.remove("GIT_CONFIG"); //$NON-NLS-1$
  166. env.remove("GIT_CONFIG_PARAMETERS"); //$NON-NLS-1$
  167. env.remove("GIT_DIR"); //$NON-NLS-1$
  168. env.remove("GIT_WORK_TREE"); //$NON-NLS-1$
  169. env.remove("GIT_GRAFT_FILE"); //$NON-NLS-1$
  170. env.remove("GIT_INDEX_FILE"); //$NON-NLS-1$
  171. env.remove("GIT_NO_REPLACE_OBJECTS"); //$NON-NLS-1$
  172. return proc.start();
  173. } catch (IOException err) {
  174. throw new TransportException(uri, err.getMessage(), err);
  175. }
  176. }
  177. class InternalLocalFetchConnection extends BasePackFetchConnection {
  178. private Thread worker;
  179. InternalLocalFetchConnection() throws TransportException {
  180. super(TransportLocal.this);
  181. final Repository dst;
  182. try {
  183. dst = new RepositoryBuilder().setGitDir(remoteGitDir).build();
  184. } catch (IOException err) {
  185. throw new TransportException(uri, JGitText.get().notAGitDirectory);
  186. }
  187. final PipedInputStream in_r;
  188. final PipedOutputStream in_w;
  189. final PipedInputStream out_r;
  190. final PipedOutputStream out_w;
  191. try {
  192. in_r = new PipedInputStream();
  193. in_w = new PipedOutputStream(in_r);
  194. out_r = new PipedInputStream() {
  195. // The client (BasePackFetchConnection) can write
  196. // a huge burst before it reads again. We need to
  197. // force the buffer to be big enough, otherwise it
  198. // will deadlock both threads.
  199. {
  200. buffer = new byte[MIN_CLIENT_BUFFER];
  201. }
  202. };
  203. out_w = new PipedOutputStream(out_r);
  204. } catch (IOException err) {
  205. dst.close();
  206. throw new TransportException(uri, JGitText.get().cannotConnectPipes, err);
  207. }
  208. worker = new Thread("JGit-Upload-Pack") { //$NON-NLS-1$
  209. public void run() {
  210. try {
  211. final UploadPack rp = createUploadPack(dst);
  212. rp.upload(out_r, in_w, null);
  213. } catch (IOException err) {
  214. // Client side of the pipes should report the problem.
  215. err.printStackTrace();
  216. } catch (RuntimeException err) {
  217. // Clients side will notice we went away, and report.
  218. err.printStackTrace();
  219. } finally {
  220. try {
  221. out_r.close();
  222. } catch (IOException e2) {
  223. // Ignore close failure, we probably crashed above.
  224. }
  225. try {
  226. in_w.close();
  227. } catch (IOException e2) {
  228. // Ignore close failure, we probably crashed above.
  229. }
  230. dst.close();
  231. }
  232. }
  233. };
  234. worker.start();
  235. init(in_r, out_w);
  236. readAdvertisedRefs();
  237. }
  238. @Override
  239. public void close() {
  240. super.close();
  241. if (worker != null) {
  242. try {
  243. worker.join();
  244. } catch (InterruptedException ie) {
  245. // Stop waiting and return anyway.
  246. } finally {
  247. worker = null;
  248. }
  249. }
  250. }
  251. }
  252. class ForkLocalFetchConnection extends BasePackFetchConnection {
  253. private Process uploadPack;
  254. private Thread errorReaderThread;
  255. ForkLocalFetchConnection() throws TransportException {
  256. super(TransportLocal.this);
  257. final MessageWriter msg = new MessageWriter();
  258. setMessageWriter(msg);
  259. uploadPack = spawn(getOptionUploadPack());
  260. final InputStream upErr = uploadPack.getErrorStream();
  261. errorReaderThread = new StreamCopyThread(upErr, msg.getRawStream());
  262. errorReaderThread.start();
  263. InputStream upIn = uploadPack.getInputStream();
  264. OutputStream upOut = uploadPack.getOutputStream();
  265. upIn = new BufferedInputStream(upIn);
  266. upOut = new SafeBufferedOutputStream(upOut);
  267. init(upIn, upOut);
  268. readAdvertisedRefs();
  269. }
  270. @Override
  271. public void close() {
  272. super.close();
  273. if (uploadPack != null) {
  274. try {
  275. uploadPack.waitFor();
  276. } catch (InterruptedException ie) {
  277. // Stop waiting and return anyway.
  278. } finally {
  279. uploadPack = null;
  280. }
  281. }
  282. if (errorReaderThread != null) {
  283. try {
  284. errorReaderThread.join();
  285. } catch (InterruptedException e) {
  286. // Stop waiting and return anyway.
  287. } finally {
  288. errorReaderThread = null;
  289. }
  290. }
  291. }
  292. }
  293. class InternalLocalPushConnection extends BasePackPushConnection {
  294. private Thread worker;
  295. InternalLocalPushConnection() throws TransportException {
  296. super(TransportLocal.this);
  297. final Repository dst;
  298. try {
  299. dst = new RepositoryBuilder().setGitDir(remoteGitDir).build();
  300. } catch (IOException err) {
  301. throw new TransportException(uri, JGitText.get().notAGitDirectory);
  302. }
  303. final PipedInputStream in_r;
  304. final PipedOutputStream in_w;
  305. final PipedInputStream out_r;
  306. final PipedOutputStream out_w;
  307. try {
  308. in_r = new PipedInputStream();
  309. in_w = new PipedOutputStream(in_r);
  310. out_r = new PipedInputStream();
  311. out_w = new PipedOutputStream(out_r);
  312. } catch (IOException err) {
  313. dst.close();
  314. throw new TransportException(uri, JGitText.get().cannotConnectPipes, err);
  315. }
  316. worker = new Thread("JGit-Receive-Pack") { //$NON-NLS-1$
  317. public void run() {
  318. try {
  319. final ReceivePack rp = createReceivePack(dst);
  320. rp.receive(out_r, in_w, System.err);
  321. } catch (IOException err) {
  322. // Client side of the pipes should report the problem.
  323. } catch (RuntimeException err) {
  324. // Clients side will notice we went away, and report.
  325. } finally {
  326. try {
  327. out_r.close();
  328. } catch (IOException e2) {
  329. // Ignore close failure, we probably crashed above.
  330. }
  331. try {
  332. in_w.close();
  333. } catch (IOException e2) {
  334. // Ignore close failure, we probably crashed above.
  335. }
  336. dst.close();
  337. }
  338. }
  339. };
  340. worker.start();
  341. init(in_r, out_w);
  342. readAdvertisedRefs();
  343. }
  344. @Override
  345. public void close() {
  346. super.close();
  347. if (worker != null) {
  348. try {
  349. worker.join();
  350. } catch (InterruptedException ie) {
  351. // Stop waiting and return anyway.
  352. } finally {
  353. worker = null;
  354. }
  355. }
  356. }
  357. }
  358. class ForkLocalPushConnection extends BasePackPushConnection {
  359. private Process receivePack;
  360. private Thread errorReaderThread;
  361. ForkLocalPushConnection() throws TransportException {
  362. super(TransportLocal.this);
  363. final MessageWriter msg = new MessageWriter();
  364. setMessageWriter(msg);
  365. receivePack = spawn(getOptionReceivePack());
  366. final InputStream rpErr = receivePack.getErrorStream();
  367. errorReaderThread = new StreamCopyThread(rpErr, msg.getRawStream());
  368. errorReaderThread.start();
  369. InputStream rpIn = receivePack.getInputStream();
  370. OutputStream rpOut = receivePack.getOutputStream();
  371. rpIn = new BufferedInputStream(rpIn);
  372. rpOut = new SafeBufferedOutputStream(rpOut);
  373. init(rpIn, rpOut);
  374. readAdvertisedRefs();
  375. }
  376. @Override
  377. public void close() {
  378. super.close();
  379. if (receivePack != null) {
  380. try {
  381. receivePack.waitFor();
  382. } catch (InterruptedException ie) {
  383. // Stop waiting and return anyway.
  384. } finally {
  385. receivePack = null;
  386. }
  387. }
  388. if (errorReaderThread != null) {
  389. try {
  390. errorReaderThread.join();
  391. } catch (InterruptedException e) {
  392. // Stop waiting and return anyway.
  393. } finally {
  394. errorReaderThread = null;
  395. }
  396. }
  397. }
  398. }
  399. }