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

Reply via email to