Can you create a JIRA for this? thanks ashish
On Sat, Apr 30, 2011 at 9:10 PM, Boris Okunskiy <[email protected]> wrote: > Hi everyone, > > Whole last day I've tried to implement a managed SSH access for Git. The > problem I faced was not quite trivial: whenever I try to `git clone` > something over SSH transport I either get successfully cloned repository or > `fatal: early EOF`. After hours of investigating I finally managed to > identify a problem. It is in `InvertedShellWrapper.pumpStreams`: > > for (;;) { > if (!shell.isAlive()) { > callback.onExit(shell.exitValue()); > // risk of loosing process data > return; > } > if (pumpStream(in, shellIn, buffer)) { > continue; > } > if (pumpStream(shellOut, out, buffer)) { > continue; > } > if (pumpStream(shellErr, err, buffer)) { > continue; > } > Thread.sleep(1); > } > > In most Unix systems a process may exit as soon as it writes everything into > a stream. If the streams are buffered, then there is a chance of dropping > everything that is left in STDOUT and STDERR (`shellOut` and `shellErr`) > after the `shell.isAlive` has reported that the underlying process has > finished. > > The solution is simple: you just pump streams one more time until no more > data is left in STDOUT or STDERR. Here is what I came up with (sorry for > Scala): > > class GitShellFactory(val verb: String, val path: String) > extends ProcessShellFactory(Array[String](verb, path)) { > override def create() = new SshShellWrapper(new ProcessShell()) > } > > class SshShellWrapper(shell: InvertedShell) extends SimpleCommand { > var buffer = new Array[Byte](4096) > var stdin: OutputStream = _ > var stdout: InputStream = _ > var stderr: InputStream = _ > def start(env: Environment): Unit = { > shell.start(env.getEnv) > stdin = shell.getInputStream > stdout = shell.getOutputStream > stderr = shell.getErrorStream > > new Thread() { > override def run() = try { > while (shell.isAlive) { > copyStream(in, stdin) > copyStream(stdout, out) > copyStream(stderr, err) > Thread.sleep(1) > } > copyStream(stdout, out) > copyStream(stderr, err) > } finally { > shell.destroy() > exit(shell.exitValue) > } > }.start() > } > def destroy = if (shell != null) shell.destroy > def copyStream(in: InputStream, out: OutputStream): Unit = > while (in.available > 0) { > val len = in.read(buffer) > if (len > 0) { > out.write(buffer, 0, len) > out.flush > } > } > } > > Then I simply use GitShellFactory instead of ProcessShellFactory and > everything works perfectly. > > Hope it will save some time for those who stuck with the same issue. It would > be great to have this fixed in later releases, though. > > Best regards, > Boris Okunskiy -- thanks ashish Blog: http://www.ashishpaliwal.com/blog My Photo Galleries: http://www.pbase.com/ashishpaliwal
