You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2014/06/04 20:32:13 UTC

[1/4] git commit: [SSHD-314] Add support for PTY allocation to ChannelExec

Repository: mina-sshd
Updated Branches:
  refs/heads/master c9974d18a -> aca9f5349


[SSHD-314] Add support for PTY allocation to ChannelExec

Submitted by Stephen Connolly (stephenc at apache)


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/f645adf6
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/f645adf6
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/f645adf6

Branch: refs/heads/master
Commit: f645adf69efee0c69b859a79314e1a584bb341c8
Parents: 8c09eef
Author: Stephen Connolly <st...@gmail.com>
Authored: Tue Apr 22 12:01:42 2014 +0100
Committer: Stephen Connolly <st...@gmail.com>
Committed: Tue Apr 22 12:01:42 2014 +0100

----------------------------------------------------------------------
 .../apache/sshd/client/channel/ChannelExec.java |  11 +-
 .../sshd/client/channel/ChannelShell.java       | 159 +--------------
 .../channel/PtyCapableChannelSession.java       | 197 +++++++++++++++++++
 3 files changed, 211 insertions(+), 156 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f645adf6/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java
index 5f46cdc..ed60346 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java
@@ -19,20 +19,27 @@
 package org.apache.sshd.client.channel;
 
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
 
+import org.apache.sshd.common.PtyMode;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.common.util.SttySupport;
 
 /**
  * TODO Add javadoc
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class ChannelExec extends ChannelSession {
+public class ChannelExec extends PtyCapableChannelSession {
 
     private final String command;
 
     public ChannelExec(String command) {
+        super(false);
         if (command == null) {
             throw new IllegalArgumentException("command must not be null");
         }
@@ -40,6 +47,8 @@ public class ChannelExec extends ChannelSession {
     }
 
     protected void doOpen() throws IOException {
+        doOpenPty();
+
         log.debug("Send SSH_MSG_CHANNEL_REQUEST exec");
         Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
         buffer.putInt(recipient);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f645adf6/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
index 0b8f552..0188a3a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
@@ -34,168 +34,17 @@ import org.apache.sshd.common.util.SttySupport;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class ChannelShell extends ChannelSession {
-
-    private boolean agentForwarding;
-    private boolean usePty = true;
-    private String ptyType;
-    private int ptyColumns;
-    private int ptyLines;
-    private int ptyWidth;
-    private int ptyHeight;
-    private Map<PtyMode, Integer> ptyModes;
-    private Map<String, String> env = new LinkedHashMap<String, String>();
+public class ChannelShell extends PtyCapableChannelSession {
 
     public ChannelShell() {
-        ptyType = System.getenv("TERM");
-        if (ptyType == null) {
-            ptyType = "dummy";
-        }
-        ptyColumns = 80;
-        ptyLines = 24;
-        ptyWidth = 640;
-        ptyHeight = 480;
-        // Set up default pty modes
-        ptyModes = new HashMap<PtyMode, Integer>();
-        ptyModes.put(PtyMode.ISIG, 1);
-        ptyModes.put(PtyMode.ICANON, 1);
-        ptyModes.put(PtyMode.ECHO, 1);
-        ptyModes.put(PtyMode.ECHOE, 1);
-        ptyModes.put(PtyMode.ECHOK, 1);
-        ptyModes.put(PtyMode.ECHONL, 0);
-        ptyModes.put(PtyMode.NOFLSH, 0);
-    }
-
-    public void setupSensibleDefaultPty() {
-        try {
-            if (OsUtils.isUNIX()) {
-                ptyModes = SttySupport.getUnixPtyModes();
-                ptyColumns = SttySupport.getTerminalWidth();
-                ptyLines = SttySupport.getTerminalHeight();
-            } else {
-                ptyType = "windows";
-            }
-        } catch (Throwable t) {
-            // Ignore exceptions
-        }
-    }
-
-    public boolean isAgentForwarding() {
-        return agentForwarding;
-    }
-
-    public void setAgentForwarding(boolean agentForwarding) {
-        this.agentForwarding = agentForwarding;
-    }
-
-    public boolean isUsePty() {
-        return usePty;
-    }
-
-    public void setUsePty(boolean usePty) {
-        this.usePty = usePty;
-    }
-
-    public String getPtyType() {
-        return ptyType;
-    }
-
-    public void setPtyType(String ptyType) {
-        this.ptyType = ptyType;
-    }
-
-    public int getPtyColumns() {
-        return ptyColumns;
-    }
-
-    public void setPtyColumns(int ptyColumns) {
-        this.ptyColumns = ptyColumns;
-    }
-
-    public int getPtyLines() {
-        return ptyLines;
-    }
-
-    public void setPtyLines(int ptyLines) {
-        this.ptyLines = ptyLines;
-    }
-
-    public int getPtyWidth() {
-        return ptyWidth;
-    }
-
-    public void setPtyWidth(int ptyWidth) {
-        this.ptyWidth = ptyWidth;
-    }
-
-    public int getPtyHeight() {
-        return ptyHeight;
-    }
-
-    public void setPtyHeight(int ptyHeight) {
-        this.ptyHeight = ptyHeight;
-    }
-
-    public Map<PtyMode, Integer> getPtyModes() {
-        return ptyModes;
-    }
-
-    public void setPtyModes(Map<PtyMode, Integer> ptyModes) {
-        this.ptyModes = ptyModes;
-    }
-
-    public void setEnv(String key, String value) {
-        env.put(key, value);
+        super(true);
     }
 
     protected void doOpen() throws IOException {
-        Buffer buffer;
-
-        if (agentForwarding) {
-            log.debug("Send agent forwarding request");
-            buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
-            buffer.putInt(recipient);
-            buffer.putString("auth-agent-req@openssh.com");
-            buffer.putBoolean(false);
-            writePacket(buffer);
-        }
-
-        if (usePty) {
-            log.debug("Send SSH_MSG_CHANNEL_REQUEST pty-req");
-            buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
-            buffer.putInt(recipient);
-            buffer.putString("pty-req");
-            buffer.putBoolean(false);
-            buffer.putString(ptyType);
-            buffer.putInt(ptyColumns);
-            buffer.putInt(ptyLines);
-            buffer.putInt(ptyHeight);
-            buffer.putInt(ptyWidth);
-            Buffer modes = new Buffer();
-            for (PtyMode mode : ptyModes.keySet()) {
-                modes.putByte((byte) mode.toInt());
-                modes.putInt(ptyModes.get(mode));
-            }
-            modes.putByte((byte) 0);
-            buffer.putBytes(modes.getCompactData());
-            writePacket(buffer);
-        }
-
-        if (!env.isEmpty()) {
-            log.debug("Send SSH_MSG_CHANNEL_REQUEST env");
-            for (Map.Entry<String, String> entry : env.entrySet()) {
-                buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
-                buffer.putInt(recipient);
-                buffer.putString("env");
-                buffer.putBoolean(false);
-                buffer.putString(entry.getKey());
-                buffer.putString(entry.getValue());
-                writePacket(buffer);
-            }
-        }
+        doOpenPty();
 
         log.debug("Send SSH_MSG_CHANNEL_REQUEST shell");
-        buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
+        Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
         buffer.putInt(recipient);
         buffer.putString("shell");
         buffer.putBoolean(false);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f645adf6/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
new file mode 100644
index 0000000..bbcb016
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.client.channel;
+
+import org.apache.sshd.common.PtyMode;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.common.util.SttySupport;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class PtyCapableChannelSession extends ChannelSession {
+    private boolean agentForwarding;
+    private boolean usePty;
+    private String ptyType;
+    private int ptyColumns;
+    private int ptyLines;
+    private int ptyWidth;
+    private int ptyHeight;
+    private Map<PtyMode, Integer> ptyModes;
+    private Map<String, String> env = new LinkedHashMap<String, String>();
+
+    public PtyCapableChannelSession(boolean usePty) {
+        this.usePty = usePty;
+        ptyType = System.getenv("TERM");
+        if (ptyType == null) {
+            ptyType = "dummy";
+        }
+        ptyColumns = 80;
+        ptyLines = 24;
+        ptyWidth = 640;
+        ptyHeight = 480;
+        // Set up default pty modes
+        ptyModes = new HashMap<PtyMode, Integer>();
+        ptyModes.put(PtyMode.ISIG, 1);
+        ptyModes.put(PtyMode.ICANON, 1);
+        ptyModes.put(PtyMode.ECHO, 1);
+        ptyModes.put(PtyMode.ECHOE, 1);
+        ptyModes.put(PtyMode.ECHOK, 1);
+        ptyModes.put(PtyMode.ECHONL, 0);
+        ptyModes.put(PtyMode.NOFLSH, 0);
+    }
+
+    public void setupSensibleDefaultPty() {
+        try {
+            if (OsUtils.isUNIX()) {
+                ptyModes = SttySupport.getUnixPtyModes();
+                ptyColumns = SttySupport.getTerminalWidth();
+                ptyLines = SttySupport.getTerminalHeight();
+            } else {
+                ptyType = "windows";
+            }
+        } catch (Throwable t) {
+            // Ignore exceptions
+        }
+    }
+
+    public boolean isAgentForwarding() {
+        return agentForwarding;
+    }
+
+    public void setAgentForwarding(boolean agentForwarding) {
+        this.agentForwarding = agentForwarding;
+    }
+
+    public boolean isUsePty() {
+        return usePty;
+    }
+
+    public void setUsePty(boolean usePty) {
+        this.usePty = usePty;
+    }
+
+    public String getPtyType() {
+        return ptyType;
+    }
+
+    public void setPtyType(String ptyType) {
+        this.ptyType = ptyType;
+    }
+
+    public int getPtyColumns() {
+        return ptyColumns;
+    }
+
+    public void setPtyColumns(int ptyColumns) {
+        this.ptyColumns = ptyColumns;
+    }
+
+    public int getPtyLines() {
+        return ptyLines;
+    }
+
+    public void setPtyLines(int ptyLines) {
+        this.ptyLines = ptyLines;
+    }
+
+    public int getPtyWidth() {
+        return ptyWidth;
+    }
+
+    public void setPtyWidth(int ptyWidth) {
+        this.ptyWidth = ptyWidth;
+    }
+
+    public int getPtyHeight() {
+        return ptyHeight;
+    }
+
+    public void setPtyHeight(int ptyHeight) {
+        this.ptyHeight = ptyHeight;
+    }
+
+    public Map<PtyMode, Integer> getPtyModes() {
+        return ptyModes;
+    }
+
+    public void setPtyModes(Map<PtyMode, Integer> ptyModes) {
+        this.ptyModes = ptyModes;
+    }
+
+    public void setEnv(String key, String value) {
+        env.put(key, value);
+    }
+
+    protected void doOpenPty() throws IOException {
+        Buffer buffer;
+
+        if (agentForwarding) {
+            log.debug("Send agent forwarding request");
+            buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
+            buffer.putInt(recipient);
+            buffer.putString("auth-agent-req@openssh.com");
+            buffer.putBoolean(false);
+            writePacket(buffer);
+        }
+
+        if (usePty) {
+            log.debug("Send SSH_MSG_CHANNEL_REQUEST pty-req");
+            buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
+            buffer.putInt(recipient);
+            buffer.putString("pty-req");
+            buffer.putBoolean(false);
+            buffer.putString(ptyType);
+            buffer.putInt(ptyColumns);
+            buffer.putInt(ptyLines);
+            buffer.putInt(ptyHeight);
+            buffer.putInt(ptyWidth);
+            Buffer modes = new Buffer();
+            for (PtyMode mode : ptyModes.keySet()) {
+                modes.putByte((byte) mode.toInt());
+                modes.putInt(ptyModes.get(mode));
+            }
+            modes.putByte((byte) 0);
+            buffer.putBytes(modes.getCompactData());
+            writePacket(buffer);
+        }
+
+        if (!env.isEmpty()) {
+            log.debug("Send SSH_MSG_CHANNEL_REQUEST env");
+            for (Map.Entry<String, String> entry : env.entrySet()) {
+                buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST);
+                buffer.putInt(recipient);
+                buffer.putString("env");
+                buffer.putBoolean(false);
+                buffer.putString(entry.getKey());
+                buffer.putString(entry.getValue());
+                writePacket(buffer);
+            }
+        }
+    }
+}


[3/4] git commit: Merge branch 'sshd-314' of https://github.com/stephenc/mina-sshd

Posted by gn...@apache.org.
Merge branch 'sshd-314' of https://github.com/stephenc/mina-sshd


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/b82143f3
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/b82143f3
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/b82143f3

Branch: refs/heads/master
Commit: b82143f3ed920de7fa1fca78ed1ba540200fcb77
Parents: c9974d1 1bb555d
Author: Guillaume Nodet <gn...@apache.org>
Authored: Tue Jun 3 22:29:56 2014 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Tue Jun 3 22:29:56 2014 +0200

----------------------------------------------------------------------
 .../apache/sshd/client/channel/ChannelExec.java |   5 +-
 .../sshd/client/channel/ChannelShell.java       | 165 +---------------
 .../channel/PtyCapableChannelSession.java       | 197 +++++++++++++++++++
 3 files changed, 205 insertions(+), 162 deletions(-)
----------------------------------------------------------------------



[4/4] git commit: [SSHD-241] Git/SSH command support

Posted by gn...@apache.org.
[SSHD-241] Git/SSH command support

Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/aca9f534
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/aca9f534
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/aca9f534

Branch: refs/heads/master
Commit: aca9f53497d8b9b1bdb48b5d688c919e9cce720a
Parents: b82143f
Author: Guillaume Nodet <gn...@apache.org>
Authored: Wed Jun 4 20:31:59 2014 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Wed Jun 4 20:31:59 2014 +0200

----------------------------------------------------------------------
 pom.xml                                         |  17 +-
 sshd-git/pom.xml                                |  16 +-
 .../java/org/apache/sshd/git/GitCommand.java    | 177 --------------
 .../org/apache/sshd/git/GitCommandFactory.java  |  51 ----
 .../apache/sshd/git/pack/GitPackCommand.java    | 193 +++++++++++++++
 .../sshd/git/pack/GitPackCommandFactory.java    |  54 +++++
 .../sshd/git/pgm/EmbeddedCommandRunner.java     | 238 +++++++++++++++++++
 .../org/apache/sshd/git/pgm/GitPgmCommand.java  | 183 ++++++++++++++
 .../sshd/git/pgm/GitPgmCommandFactory.java      |  54 +++++
 .../git/transport/GitSshdSessionFactory.java    | 136 +++++++++++
 .../java/org/apache/sshd/git/GitServerTest.java |  67 ------
 .../sshd/git/pack/GitPackCommandTest.java       |  82 +++++++
 .../apache/sshd/git/pgm/GitPgmCommandTest.java  |  98 ++++++++
 .../java/org/apache/sshd/git/util/Utils.java    |  14 ++
 14 files changed, 1077 insertions(+), 303 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 6223d71..92d65aa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,6 +74,11 @@
             <name>Apache ServiceMix Repository</name>
             <url>http://svn.apache.org/repos/asf/servicemix/m2-repo</url>
         </repository>
+        <repository>
+            <id>jgit</id>
+            <name>Eclipse JGit repository</name>
+            <url>http://repo.eclipse.org/content/groups/jgit</url>
+        </repository>
     </repositories>
 
     <scm>
@@ -185,6 +190,16 @@
                 <artifactId>ganymed-ssh2</artifactId>
                 <version>build210</version>
             </dependency>
+            <dependency>
+                <groupId>org.eclipse.jgit</groupId>
+                <artifactId>org.eclipse.jgit</artifactId>
+                <version>3.4.0.201405281120-rc2</version>
+            </dependency>
+            <dependency>
+                <groupId>org.eclipse.jgit</groupId>
+                <artifactId>org.eclipse.jgit.pgm</artifactId>
+                <version>3.4.0.201405281120-rc2</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 
@@ -287,9 +302,7 @@
         <module>sshd-core</module>
         <module>sshd-pam</module>
         <module>sshd-sftp</module>
-        <!--
         <module>sshd-git</module>
-        -->
         <module>assembly</module>
     </modules>
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/pom.xml
----------------------------------------------------------------------
diff --git a/sshd-git/pom.xml b/sshd-git/pom.xml
index 3dcdc4a..904a0dd 100644
--- a/sshd-git/pom.xml
+++ b/sshd-git/pom.xml
@@ -24,12 +24,12 @@
     <parent>
         <groupId>org.apache.sshd</groupId>
         <artifactId>sshd</artifactId>
-        <version>0.9.0-SNAPSHOT</version>
+        <version>0.11.1-SNAPSHOT</version>
     </parent>
 
     <groupId>org.apache.sshd</groupId>
     <artifactId>sshd-git</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.11.1-SNAPSHOT</version>
     <name>Apache Mina SSHD :: Git</name>
     <packaging>jar</packaging>
     <inceptionYear>2008</inceptionYear>
@@ -46,12 +46,10 @@
         <dependency>
             <groupId>org.eclipse.jgit</groupId>
             <artifactId>org.eclipse.jgit</artifactId>
-            <version>3.1.0-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.eclipse.jgit</groupId>
             <artifactId>org.eclipse.jgit.pgm</artifactId>
-            <version>3.1.0-SNAPSHOT</version>
         </dependency>
 
         <dependency>
@@ -70,8 +68,13 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>bouncycastle</groupId>
-            <artifactId>bcprov-jdk15</artifactId>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcpg-jdk15on</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcpkix-jdk15on</artifactId>
             <scope>test</scope>
         </dependency>
     </dependencies>
@@ -92,6 +95,7 @@
                     <instructions>
                         <Bundle-SymbolicName>org.apache.sshd.git</Bundle-SymbolicName>
                         <Import-Package>
+                            org.eclipse.jgit.pgm;resolution:=optional,
                             *
                         </Import-Package>
                         <Export-Package>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/src/main/java/org/apache/sshd/git/GitCommand.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/main/java/org/apache/sshd/git/GitCommand.java b/sshd-git/src/main/java/org/apache/sshd/git/GitCommand.java
deleted file mode 100644
index 9a8684b..0000000
--- a/sshd-git/src/main/java/org/apache/sshd/git/GitCommand.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.git;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.sshd.common.channel.ChannelOutputStream;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.Environment;
-import org.apache.sshd.server.ExitCallback;
-import org.eclipse.jgit.pgm.EmbeddedCommandRunner;
-import org.eclipse.jgit.pgm.TextBuiltin;
-import org.eclipse.jgit.pgm.opt.SubcommandHandler;
-import org.kohsuke.args4j.Argument;
-import org.kohsuke.args4j.Option;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class GitCommand implements Command, Runnable {
-
-    private String command;
-    private InputStream in;
-    private OutputStream out;
-    private OutputStream err;
-    private ExitCallback callback;
-
-    public GitCommand(String command) {
-        this.command = command;
-    }
-
-    public void setInputStream(InputStream in) {
-        this.in = in;
-    }
-
-    public void setOutputStream(OutputStream out) {
-        this.out = out;
-        if (out instanceof ChannelOutputStream) {
-            ((ChannelOutputStream) out).setNoDelay(true);
-        }
-    }
-
-    public void setErrorStream(OutputStream err) {
-        this.err = err;
-        if (err instanceof ChannelOutputStream) {
-            ((ChannelOutputStream) err).setNoDelay(true);
-        }
-    }
-
-    public void setExitCallback(ExitCallback callback) {
-        this.callback = callback;
-    }
-
-    public void start(Environment env) throws IOException {
-        new Thread(this).start();
-    }
-
-    public void run() {
-        try {
-            List<String> strs = parseDelimitedString(command, " ", true);
-            String[] args = strs.toArray(new String[strs.size()]);
-            for (int i = 0; i < args.length; i++) {
-                if (args[i].startsWith("'") && args[i].endsWith("'")) {
-                    args[i] = args[i].substring(1, args[i].length() - 1);
-                }
-                if (args[i].startsWith("\"") && args[i].endsWith("\"")) {
-                    args[i] = args[i].substring(1, args[i].length() - 1);
-                }
-            }
-            new EmbeddedCommandRunner().execute(args, in, out, err);
-        } catch (Throwable t) {
-            t.printStackTrace();
-        }
-        if (callback != null) {
-            callback.onExit(0);
-        }
-    }
-
-    public void destroy() {
-        //To change body of implemented methods use File | Settings | File Templates.
-    }
-
-    /**
-     * Parses delimited string and returns an array containing the tokens. This
-     * parser obeys quotes, so the delimiter character will be ignored if it is
-     * inside of a quote. This method assumes that the quote character is not
-     * included in the set of delimiter characters.
-     *
-     * @param value the delimited string to parse.
-     * @param delim the characters delimiting the tokens.
-     * @return a list of string or an empty list if there are none.
-     */
-    private static List<String> parseDelimitedString(String value, String delim, boolean trim) {
-        if (value == null) {
-            value = "";
-        }
-
-        List<String> list = new ArrayList<String>();
-
-        int CHAR = 1;
-        int DELIMITER = 2;
-        int STARTQUOTE = 4;
-        int ENDQUOTE = 8;
-
-        StringBuilder sb = new StringBuilder();
-
-        int expecting = (CHAR | DELIMITER | STARTQUOTE);
-
-        boolean isEscaped = false;
-        for (int i = 0; i < value.length(); i++) {
-            char c = value.charAt(i);
-
-            boolean isDelimiter = (delim.indexOf(c) >= 0);
-
-            if (!isEscaped && (c == '\\')) {
-                isEscaped = true;
-                continue;
-            }
-
-            if (isEscaped) {
-                sb.append(c);
-            } else if (isDelimiter && ((expecting & DELIMITER) > 0)) {
-                if (trim) {
-                    list.add(sb.toString().trim());
-                } else {
-                    list.add(sb.toString());
-                }
-                sb.delete(0, sb.length());
-                expecting = (CHAR | DELIMITER | STARTQUOTE);
-            } else if ((c == '"') && ((expecting & STARTQUOTE) > 0)) {
-                sb.append(c);
-                expecting = CHAR | ENDQUOTE;
-            } else if ((c == '"') && ((expecting & ENDQUOTE) > 0)) {
-                sb.append(c);
-                expecting = (CHAR | STARTQUOTE | DELIMITER);
-            } else if ((expecting & CHAR) > 0) {
-                sb.append(c);
-            } else {
-                throw new IllegalArgumentException("Invalid delimited string: " + value);
-            }
-
-            isEscaped = false;
-        }
-
-        if (sb.length() > 0) {
-            if (trim) {
-                list.add(sb.toString().trim());
-            } else {
-                list.add(sb.toString());
-            }
-        }
-
-        return list;
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/src/main/java/org/apache/sshd/git/GitCommandFactory.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/main/java/org/apache/sshd/git/GitCommandFactory.java b/sshd-git/src/main/java/org/apache/sshd/git/GitCommandFactory.java
deleted file mode 100644
index 3148202..0000000
--- a/sshd-git/src/main/java/org/apache/sshd/git/GitCommandFactory.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.git;
-
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.CommandFactory;
-import org.apache.sshd.server.command.UnknownCommand;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class GitCommandFactory implements CommandFactory {
-
-    private CommandFactory delegate;
-
-    public GitCommandFactory() {
-    }
-
-    public GitCommandFactory(CommandFactory delegate) {
-        this.delegate = delegate;
-    }
-
-    public Command createCommand(String command) {
-        if (command.startsWith("git-")) {
-            return new GitCommand(command.substring("git-".length()));
-        } else if (delegate != null) {
-            return delegate.createCommand(command);
-        } else {
-            return new UnknownCommand(command);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommand.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommand.java b/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommand.java
new file mode 100644
index 0000000..d8b4c80
--- /dev/null
+++ b/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommand.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git.pack;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sshd.common.channel.ChannelOutputStream;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.ExitCallback;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryCache;
+import org.eclipse.jgit.transport.ReceivePack;
+import org.eclipse.jgit.transport.UploadPack;
+import org.eclipse.jgit.util.FS;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class GitPackCommand implements Command, Runnable {
+
+    private String rootDir;
+    private String command;
+    private InputStream in;
+    private OutputStream out;
+    private OutputStream err;
+    private ExitCallback callback;
+
+    public GitPackCommand(String rootDir, String command) {
+        this.rootDir = rootDir;
+        this.command = command;
+    }
+
+    public void setInputStream(InputStream in) {
+        this.in = in;
+    }
+
+    public void setOutputStream(OutputStream out) {
+        this.out = out;
+        if (out instanceof ChannelOutputStream) {
+            ((ChannelOutputStream) out).setNoDelay(true);
+        }
+    }
+
+    public void setErrorStream(OutputStream err) {
+        this.err = err;
+        if (err instanceof ChannelOutputStream) {
+            ((ChannelOutputStream) err).setNoDelay(true);
+        }
+    }
+
+    public void setExitCallback(ExitCallback callback) {
+        this.callback = callback;
+    }
+
+    public void start(Environment env) throws IOException {
+        new Thread(this).start();
+    }
+
+    public void run() {
+        try {
+            List<String> strs = parseDelimitedString(command, " ", true);
+            String[] args = strs.toArray(new String[strs.size()]);
+            for (int i = 0; i < args.length; i++) {
+                if (args[i].startsWith("'") && args[i].endsWith("'")) {
+                    args[i] = args[i].substring(1, args[i].length() - 1);
+                }
+                if (args[i].startsWith("\"") && args[i].endsWith("\"")) {
+                    args[i] = args[i].substring(1, args[i].length() - 1);
+                }
+            }
+
+            if (args.length != 2) {
+                throw new IllegalArgumentException("Invalid git command line: " + command);
+            }
+            File srcGitdir = new File(rootDir, args[1]);
+            RepositoryCache.FileKey key = RepositoryCache.FileKey.lenient(srcGitdir, FS.DETECTED);
+            Repository db = key.open(true /* must exist */);
+            if ("git-upload-pack".equals(args[0])) {
+                new UploadPack(db).upload(in, out, err);
+            } else if ("git-receive-pack".equals(args[0])) {
+                new ReceivePack(db).receive(in, out, err);
+            } else {
+                throw new IllegalArgumentException("Unknown git command: " + command);
+            }
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+        if (callback != null) {
+            callback.onExit(0);
+        }
+    }
+
+    public void destroy() {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    /**
+     * Parses delimited string and returns an array containing the tokens. This
+     * parser obeys quotes, so the delimiter character will be ignored if it is
+     * inside of a quote. This method assumes that the quote character is not
+     * included in the set of delimiter characters.
+     *
+     * @param value the delimited string to parse.
+     * @param delim the characters delimiting the tokens.
+     * @return a list of string or an empty list if there are none.
+     */
+    private static List<String> parseDelimitedString(String value, String delim, boolean trim) {
+        if (value == null) {
+            value = "";
+        }
+
+        List<String> list = new ArrayList<String>();
+
+        int CHAR = 1;
+        int DELIMITER = 2;
+        int STARTQUOTE = 4;
+        int ENDQUOTE = 8;
+
+        StringBuilder sb = new StringBuilder();
+
+        int expecting = (CHAR | DELIMITER | STARTQUOTE);
+
+        boolean isEscaped = false;
+        for (int i = 0; i < value.length(); i++) {
+            char c = value.charAt(i);
+
+            boolean isDelimiter = (delim.indexOf(c) >= 0);
+
+            if (!isEscaped && (c == '\\')) {
+                isEscaped = true;
+                continue;
+            }
+
+            if (isEscaped) {
+                sb.append(c);
+            } else if (isDelimiter && ((expecting & DELIMITER) > 0)) {
+                if (trim) {
+                    list.add(sb.toString().trim());
+                } else {
+                    list.add(sb.toString());
+                }
+                sb.delete(0, sb.length());
+                expecting = (CHAR | DELIMITER | STARTQUOTE);
+            } else if ((c == '"') && ((expecting & STARTQUOTE) > 0)) {
+                sb.append(c);
+                expecting = CHAR | ENDQUOTE;
+            } else if ((c == '"') && ((expecting & ENDQUOTE) > 0)) {
+                sb.append(c);
+                expecting = (CHAR | STARTQUOTE | DELIMITER);
+            } else if ((expecting & CHAR) > 0) {
+                sb.append(c);
+            } else {
+                throw new IllegalArgumentException("Invalid delimited string: " + value);
+            }
+
+            isEscaped = false;
+        }
+
+        if (sb.length() > 0) {
+            if (trim) {
+                list.add(sb.toString().trim());
+            } else {
+                list.add(sb.toString());
+            }
+        }
+
+        return list;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommandFactory.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommandFactory.java b/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommandFactory.java
new file mode 100644
index 0000000..87bfc65
--- /dev/null
+++ b/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommandFactory.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git.pack;
+
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.CommandFactory;
+import org.apache.sshd.server.command.UnknownCommand;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class GitPackCommandFactory implements CommandFactory {
+
+    private final String rootDir;
+    private final CommandFactory delegate;
+
+    public GitPackCommandFactory(String rootDir) {
+        this(rootDir,  null);
+    }
+
+    public GitPackCommandFactory(String rootDir, CommandFactory delegate) {
+        this.rootDir = rootDir;
+        this.delegate = delegate;
+    }
+
+    public Command createCommand(String command) {
+        if (command.startsWith("git-")) {
+            return new GitPackCommand(rootDir, command);
+        } else if (delegate != null) {
+            return delegate.createCommand(command);
+        } else {
+            return new UnknownCommand(command);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/src/main/java/org/apache/sshd/git/pgm/EmbeddedCommandRunner.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/main/java/org/apache/sshd/git/pgm/EmbeddedCommandRunner.java b/sshd-git/src/main/java/org/apache/sshd/git/pgm/EmbeddedCommandRunner.java
new file mode 100644
index 0000000..fc1958d
--- /dev/null
+++ b/sshd-git/src/main/java/org/apache/sshd/git/pgm/EmbeddedCommandRunner.java
@@ -0,0 +1,238 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git.pgm;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryBuilder;
+import org.eclipse.jgit.pgm.CommandCatalog;
+import org.eclipse.jgit.pgm.CommandRef;
+import org.eclipse.jgit.pgm.Die;
+import org.eclipse.jgit.pgm.TextBuiltin;
+import org.eclipse.jgit.pgm.internal.CLIText;
+import org.eclipse.jgit.pgm.opt.CmdLineParser;
+import org.eclipse.jgit.pgm.opt.SubcommandHandler;
+import org.eclipse.jgit.util.io.ThrowingPrintWriter;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.ExampleMode;
+import org.kohsuke.args4j.Option;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class EmbeddedCommandRunner {
+    @Option(name = "--help", usage = "usage_displayThisHelpText", aliases = { "-h" })
+    private boolean help;
+
+    @Option(name = "--show-stack-trace", usage = "usage_displayThejavaStackTraceOnExceptions")
+    private boolean showStackTrace;
+
+    @Option(name = "--git-dir", metaVar = "metaVar_gitDir", usage = "usage_setTheGitRepositoryToOperateOn")
+    private String gitdir;
+
+    @Argument(index = 0, metaVar = "metaVar_command", required = true, handler = SubcommandHandler.class)
+    private TextBuiltin subcommand;
+
+    @Argument(index = 1, metaVar = "metaVar_arg")
+    private List<String> arguments = new ArrayList<String>();
+
+    private String rootDir;
+
+    public EmbeddedCommandRunner(String rootDir) {
+        this.rootDir = rootDir;
+    }
+
+    /**
+     * Execute a command.
+     *
+     * @param argv
+     *          the command and its arguments
+     * @param in
+     *          the input stream, may be null in which case the system input stream will be used
+     * @param out
+     *          the output stream, may be null in which case the system output stream will be used
+     * @param err
+     *          the error stream, may be null in which case the system error stream will be used
+     * @throws Exception
+     *          if an error occurs
+     */
+    public void execute(final String[] argv, InputStream in, OutputStream out, OutputStream err) throws Exception {
+        final CmdLineParser clp = new CmdLineParser(this);
+        PrintWriter writer = new PrintWriter(err != null ? err : System.err);
+        try {
+            clp.parseArgument(argv);
+        } catch (CmdLineException e) {
+            if (argv.length > 0 && !help) {
+                writer.println(MessageFormat.format(CLIText.get().fatalError, e.getMessage()));
+                writer.flush();
+                throw new Die(true);
+            }
+        }
+
+        if (argv.length == 0 || help) {
+            final String ex = clp.printExample(ExampleMode.ALL, CLIText.get().resourceBundle());
+            writer.println("jgit" + ex + " command [ARG ...]"); //$NON-NLS-1$
+            if (help) {
+                writer.println();
+                clp.printUsage(writer, CLIText.get().resourceBundle());
+                writer.println();
+            } else if (subcommand == null) {
+                writer.println();
+                writer.println(CLIText.get().mostCommonlyUsedCommandsAre);
+                final CommandRef[] common = CommandCatalog.common();
+                int width = 0;
+                for (final CommandRef c : common)
+                    width = Math.max(width, c.getName().length());
+                width += 2;
+
+                for (final CommandRef c : common) {
+                    writer.print(' ');
+                    writer.print(c.getName());
+                    for (int i = c.getName().length(); i < width; i++)
+                        writer.print(' ');
+                    writer.print(CLIText.get().resourceBundle().getString(c.getUsage()));
+                    writer.println();
+                }
+                writer.println();
+            }
+            writer.flush();
+            throw new Die(true);
+        }
+
+        gitdir = new File(rootDir, gitdir).getPath();
+
+        final TextBuiltin cmd = subcommand;
+//        cmd.ins = in;
+//        cmd.outs = out;
+//        cmd.errs = err;
+//        if (cmd.requiresRepository())
+//            cmd.init(openGitDir(gitdir), null);
+//        else
+//            cmd.init(null, gitdir);
+//        try {
+//            cmd.execute(arguments.toArray(new String[arguments.size()]));
+//        } finally {
+//            if (cmd.outw != null)
+//                cmd.outw.flush();
+//            if (cmd.errw != null)
+//                cmd.errw.flush();
+//        }
+        set(cmd, "ins", in);
+        set(cmd, "outs", out);
+        set(cmd, "errs", err);
+        if ((Boolean) call(cmd, "requiresRepository")) {
+            call(cmd, "init", new Class[] { Repository.class, String.class }, new Object[] { openGitDir(gitdir), gitdir });
+        } else {
+            call(cmd, "init", new Class[] { Repository.class, String.class }, new Object[] { null, gitdir });
+        }
+        try {
+            cmd.execute(arguments.toArray(new String[arguments.size()]));
+        } finally {
+            if (get(cmd, "outw") != null)
+                ((ThrowingPrintWriter) get(cmd, "outw")).flush();
+            if (get(cmd, "errw") != null)
+                ((ThrowingPrintWriter) get(cmd, "errw")).flush();
+        }
+    }
+
+    private Object get(Object obj, String name) throws IllegalAccessException, NoSuchFieldException {
+        Class clazz = obj.getClass();
+        while (clazz != null) {
+            try {
+                Field field = clazz.getDeclaredField(name);
+                field.setAccessible(true);
+                return field.get(obj);
+            } catch (NoSuchFieldException e) {
+                clazz = clazz.getSuperclass();
+            }
+        }
+        throw new NoSuchFieldException(name);
+    }
+
+    private void set(Object obj, String name, Object val) throws IllegalAccessException, NoSuchFieldException {
+        Class clazz = obj.getClass();
+        while (clazz != null) {
+            try {
+                Field field = clazz.getDeclaredField(name);
+                field.setAccessible(true);
+                field.set(obj, val);
+                return;
+            } catch (NoSuchFieldException e) {
+                clazz = clazz.getSuperclass();
+            }
+        }
+        throw new NoSuchFieldException(name);
+    }
+
+    private Object call(Object obj, String name) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+        return call(obj, name, new Class[0], new Object[0]);
+    }
+
+    private Object call(Object obj, String name, Class<?>[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+        Class<?> clazz = obj.getClass();
+        while (clazz != null) {
+            try {
+                Method method = clazz.getDeclaredMethod(name, types);
+                method.setAccessible(true);
+                return method.invoke(obj, args);
+            } catch (NoSuchMethodException e) {
+                clazz = clazz.getSuperclass();
+            }
+        }
+        throw new NoSuchMethodException(name);
+    }
+
+    /**
+     * Evaluate the {@code --git-dir} option and open the repository.
+     *
+     * @param gitdir
+     *            the {@code --git-dir} option given on the command line. May be
+     *            null if it was not supplied.
+     * @return the repository to operate on.
+     * @throws IOException
+     *             the repository cannot be opened.
+     */
+    protected Repository openGitDir(String gitdir) throws IOException {
+        return Git.open(new File(gitdir)).getRepository();
+        /*
+        RepositoryBuilder rb = new RepositoryBuilder() //
+                .setGitDir(gitdir != null ? new File(gitdir) : null) //
+                .readEnvironment() //
+                .findGitDir();
+        if (rb.getGitDir() == null)
+            throw new Die(CLIText.get().cantFindGitDirectory);
+        return rb.build();
+        */
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommand.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommand.java b/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommand.java
new file mode 100644
index 0000000..22a2f11
--- /dev/null
+++ b/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommand.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git.pgm;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sshd.common.channel.ChannelOutputStream;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.ExitCallback;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class GitPgmCommand implements Command, Runnable {
+
+    private String rootDir;
+    private String command;
+    private InputStream in;
+    private OutputStream out;
+    private OutputStream err;
+    private ExitCallback callback;
+
+    public GitPgmCommand(String rootDir, String command) {
+        this.rootDir = rootDir;
+        this.command = command;
+    }
+
+    public void setInputStream(InputStream in) {
+        this.in = in;
+    }
+
+    public void setOutputStream(OutputStream out) {
+        this.out = out;
+        if (out instanceof ChannelOutputStream) {
+            ((ChannelOutputStream) out).setNoDelay(true);
+        }
+    }
+
+    public void setErrorStream(OutputStream err) {
+        this.err = err;
+        if (err instanceof ChannelOutputStream) {
+            ((ChannelOutputStream) err).setNoDelay(true);
+        }
+    }
+
+    public void setExitCallback(ExitCallback callback) {
+        this.callback = callback;
+    }
+
+    public void start(Environment env) throws IOException {
+        new Thread(this).start();
+    }
+
+    public void run() {
+        try {
+            List<String> strs = parseDelimitedString(command, " ", true);
+            String[] args = strs.toArray(new String[strs.size()]);
+            for (int i = 0; i < args.length; i++) {
+                if (args[i].startsWith("'") && args[i].endsWith("'")) {
+                    args[i] = args[i].substring(1, args[i].length() - 1);
+                }
+                if (args[i].startsWith("\"") && args[i].endsWith("\"")) {
+                    args[i] = args[i].substring(1, args[i].length() - 1);
+                }
+            }
+
+            new EmbeddedCommandRunner(rootDir).execute(args, in, out, err);
+            if (callback != null) {
+                callback.onExit(0);
+            }
+        } catch (Throwable t) {
+            try {
+                err.write((t.getMessage() + "\n").getBytes());
+                err.flush();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            if (callback != null) {
+                callback.onExit(-1);
+            }
+        }
+    }
+
+    public void destroy() {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    /**
+     * Parses delimited string and returns an array containing the tokens. This
+     * parser obeys quotes, so the delimiter character will be ignored if it is
+     * inside of a quote. This method assumes that the quote character is not
+     * included in the set of delimiter characters.
+     *
+     * @param value the delimited string to parse.
+     * @param delim the characters delimiting the tokens.
+     * @return a list of string or an empty list if there are none.
+     */
+    private static List<String> parseDelimitedString(String value, String delim, boolean trim) {
+        if (value == null) {
+            value = "";
+        }
+
+        List<String> list = new ArrayList<String>();
+
+        int CHAR = 1;
+        int DELIMITER = 2;
+        int STARTQUOTE = 4;
+        int ENDQUOTE = 8;
+
+        StringBuilder sb = new StringBuilder();
+
+        int expecting = (CHAR | DELIMITER | STARTQUOTE);
+
+        boolean isEscaped = false;
+        for (int i = 0; i < value.length(); i++) {
+            char c = value.charAt(i);
+
+            boolean isDelimiter = (delim.indexOf(c) >= 0);
+
+            if (!isEscaped && (c == '\\')) {
+                isEscaped = true;
+                continue;
+            }
+
+            if (isEscaped) {
+                sb.append(c);
+            } else if (isDelimiter && ((expecting & DELIMITER) > 0)) {
+                if (trim) {
+                    list.add(sb.toString().trim());
+                } else {
+                    list.add(sb.toString());
+                }
+                sb.delete(0, sb.length());
+                expecting = (CHAR | DELIMITER | STARTQUOTE);
+            } else if ((c == '"') && ((expecting & STARTQUOTE) > 0)) {
+                sb.append(c);
+                expecting = CHAR | ENDQUOTE;
+            } else if ((c == '"') && ((expecting & ENDQUOTE) > 0)) {
+                sb.append(c);
+                expecting = (CHAR | STARTQUOTE | DELIMITER);
+            } else if ((expecting & CHAR) > 0) {
+                sb.append(c);
+            } else {
+                throw new IllegalArgumentException("Invalid delimited string: " + value);
+            }
+
+            isEscaped = false;
+        }
+
+        if (sb.length() > 0) {
+            if (trim) {
+                list.add(sb.toString().trim());
+            } else {
+                list.add(sb.toString());
+            }
+        }
+
+        return list;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommandFactory.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommandFactory.java b/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommandFactory.java
new file mode 100644
index 0000000..e3741a4
--- /dev/null
+++ b/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommandFactory.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git.pgm;
+
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.CommandFactory;
+import org.apache.sshd.server.command.UnknownCommand;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class GitPgmCommandFactory implements CommandFactory {
+
+    private final String rootDir;
+    private final CommandFactory delegate;
+
+    public GitPgmCommandFactory(String rootDir) {
+        this(rootDir,  null);
+    }
+
+    public GitPgmCommandFactory(String rootDir, CommandFactory delegate) {
+        this.rootDir = rootDir;
+        this.delegate = delegate;
+    }
+
+    public Command createCommand(String command) {
+        if (command.startsWith("git ")) {
+            return new GitPgmCommand(rootDir, command.substring("git ".length()));
+        } else if (delegate != null) {
+            return delegate.createCommand(command);
+        } else {
+            return new UnknownCommand(command);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionFactory.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionFactory.java b/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionFactory.java
new file mode 100644
index 0000000..aca4e3c
--- /dev/null
+++ b/sshd-git/src/main/java/org/apache/sshd/git/transport/GitSshdSessionFactory.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git.transport;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.client.channel.ChannelExec;
+import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.transport.CredentialItem;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.RemoteSession;
+import org.eclipse.jgit.transport.SshSessionFactory;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.util.FS;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class GitSshdSessionFactory extends SshSessionFactory {
+
+    @Override
+    public RemoteSession getSession(URIish uri, CredentialsProvider credentialsProvider, FS fs, int tms) throws TransportException {
+        try {
+            return new SshdSession(uri, credentialsProvider, fs, tms);
+        } catch (Exception e) {
+            throw new TransportException("Unable to connect", e);
+        }
+    }
+
+    protected SshClient createClient() {
+        return SshClient.setUpDefaultClient();
+    }
+
+    public class SshdSession implements RemoteSession {
+
+        private final SshClient client;
+        private final ClientSession session;
+
+        public SshdSession(URIish uri, CredentialsProvider credentialsProvider, FS fs, int tms) throws IOException, InterruptedException {
+            String user = uri.getUser();
+            final String pass = uri.getPass();
+            String host = uri.getHost();
+            int port = uri.getPort();
+            char[] pass2 = null;
+
+            if (!credentialsProvider.isInteractive()) {
+                CredentialItem.Username usrItem = new CredentialItem.Username();
+                CredentialItem.Password pwdItem = new CredentialItem.Password();
+                if (credentialsProvider.get(uri, usrItem, pwdItem)) {
+                    if (user == null) {
+                        user = usrItem.getValue();
+                    } else if (user.equals(usrItem.getValue())) {
+                        pass2 = pwdItem.getValue();
+                    }
+                }
+
+            }
+
+            client = createClient();
+            client.start();
+            session = client.connect(user, host, port).await().getSession();
+            if (pass != null) {
+                session.addPasswordIdentity(pass);
+            }
+            if (pass2 != null) {
+                session.addPasswordIdentity(new String(pass2));
+            }
+            session.auth().verify();
+
+        }
+
+        public Process exec(String commandName, int timeout) throws IOException {
+            final ChannelExec channel = session.createExecChannel(commandName);
+            channel.open().verify();
+            return new Process() {
+                @Override
+                public OutputStream getOutputStream() {
+                    return channel.getInvertedIn();
+                }
+
+                @Override
+                public InputStream getInputStream() {
+                    return channel.getInvertedOut();
+                }
+
+                @Override
+                public InputStream getErrorStream() {
+                    return channel.getInvertedErr();
+                }
+
+                @Override
+                public int waitFor() throws InterruptedException {
+                    return channel.waitFor(ClientChannel.CLOSED, 0);
+                }
+
+                @Override
+                public int exitValue() {
+                    return channel.getExitStatus();
+                }
+
+                @Override
+                public void destroy() {
+                    channel.close(true);
+                }
+            };
+        }
+
+        public void disconnect() {
+            client.close(true);
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/src/test/java/org/apache/sshd/git/GitServerTest.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/test/java/org/apache/sshd/git/GitServerTest.java b/sshd-git/src/test/java/org/apache/sshd/git/GitServerTest.java
deleted file mode 100644
index ed0a17e..0000000
--- a/sshd-git/src/test/java/org/apache/sshd/git/GitServerTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.git;
-
-import java.util.Arrays;
-
-import org.apache.sshd.SshServer;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.git.util.BogusPasswordAuthenticator;
-import org.apache.sshd.git.util.EchoShellFactory;
-import org.apache.sshd.git.util.Utils;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.CommandFactory;
-import org.apache.sshd.server.command.UnknownCommand;
-import org.apache.sshd.server.sftp.SftpSubsystem;
-import org.junit.Ignore;
-import org.junit.Test;
-
-/**
- */
-public class GitServerTest {
-
-    @Test
-    @Ignore
-    public void testGit() {
-
-    }
-
-    public static void main(String[] args) throws Exception {
-        SshServer sshd = SshServer.setUpDefaultServer();
-        sshd.getProperties().put(SshServer.IDLE_TIMEOUT, "10000");
-        sshd.setPort(8001);
-        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
-        sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystem.Factory()));
-        sshd.setShellFactory(new EchoShellFactory());
-//        sshd.setCommandFactory(new ScpCommandFactory());
-        sshd.setCommandFactory(new CommandFactory() {
-            public Command createCommand(String command) {
-                if (command.startsWith("git-")) {
-                    return new GitCommand(command.substring("git-".length()));
-                } else {
-                    return new UnknownCommand(command);
-                }
-            }
-        });
-        sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
-        sshd.start();
-        Thread.sleep(100000);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/src/test/java/org/apache/sshd/git/pack/GitPackCommandTest.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/test/java/org/apache/sshd/git/pack/GitPackCommandTest.java b/sshd-git/src/test/java/org/apache/sshd/git/pack/GitPackCommandTest.java
new file mode 100644
index 0000000..b27becb
--- /dev/null
+++ b/sshd-git/src/test/java/org/apache/sshd/git/pack/GitPackCommandTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git.pack;
+
+import java.io.File;
+import java.util.Arrays;
+
+import com.jcraft.jsch.JSch;
+import org.apache.sshd.SshServer;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.git.transport.GitSshdSessionFactory;
+import org.apache.sshd.git.util.BogusPasswordAuthenticator;
+import org.apache.sshd.git.util.EchoShellFactory;
+import org.apache.sshd.git.util.Utils;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.sftp.SftpSubsystem;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
+import org.junit.Test;
+
+/**
+ */
+public class GitPackCommandTest {
+
+    @Test
+    public void testGitPack() throws Exception {
+        SshServer sshd = SshServer.setUpDefaultServer();
+        sshd.setPort(8001);
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+        sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystem.Factory()));
+        sshd.setShellFactory(new EchoShellFactory());
+        sshd.setCommandFactory(new GitPackCommandFactory("target/git/server"));
+        sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+        sshd.start();
+
+        File serverDir = new File("target/git/server/test.git");
+        Utils.deleteRecursive(serverDir);
+        Git.init().setBare(true).setDirectory(serverDir).call();
+
+        JSch.setConfig("StrictHostKeyChecking", "no");
+        CredentialsProvider.setDefault(new UsernamePasswordCredentialsProvider("sshd", "sshd"));
+        GitSshdSessionFactory.setInstance(new GitSshdSessionFactory());
+
+        File dir = new File("target/git/local/test.git");
+        Utils.deleteRecursive(dir);
+        Git.cloneRepository()
+                .setURI("ssh://sshd@localhost:8001/test.git")
+                .setDirectory(dir)
+                .call();
+
+        Git git = Git.open(dir);
+        git.commit().setMessage("First Commit").setCommitter("sshd", "sshd@apache.org").call();
+        git.push().call();
+
+        new File("target/git/local/test.git/readme.txt").createNewFile();
+        git.add().addFilepattern("readme.txt").call();
+        git.commit().setMessage("readme").setCommitter("sshd", "sshd@apache.org").call();
+        git.push().call();
+
+        git.pull().setRebase(true).call();
+
+        sshd.stop();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/src/test/java/org/apache/sshd/git/pgm/GitPgmCommandTest.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/test/java/org/apache/sshd/git/pgm/GitPgmCommandTest.java b/sshd-git/src/test/java/org/apache/sshd/git/pgm/GitPgmCommandTest.java
new file mode 100644
index 0000000..f45f60d
--- /dev/null
+++ b/sshd-git/src/test/java/org/apache/sshd/git/pgm/GitPgmCommandTest.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git.pgm;
+
+import java.io.File;
+import java.util.Arrays;
+
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.SshServer;
+import org.apache.sshd.client.channel.ChannelExec;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.git.util.BogusPasswordAuthenticator;
+import org.apache.sshd.git.util.EchoShellFactory;
+import org.apache.sshd.git.util.Utils;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.sftp.SftpSubsystem;
+import org.eclipse.jgit.api.Git;
+import org.junit.Test;
+
+/**
+ */
+public class GitPgmCommandTest {
+
+    @Test
+    public void testGitpgm() throws Exception {
+
+        //
+        // TODO: the GitpgmCommandFactory is kept in the test tree
+        // TODO: because it's quite limited for now
+        //
+
+        SshServer sshd = SshServer.setUpDefaultServer();
+        sshd.setPort(8001);
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+        sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystem.Factory()));
+        sshd.setShellFactory(new EchoShellFactory());
+        sshd.setCommandFactory(new GitPgmCommandFactory("target/git/pgm"));
+        sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+        sshd.start();
+
+        File serverDir = new File("target/git/pgm");
+        Utils.deleteRecursive(serverDir);
+
+        File repo = new File(serverDir, "test");
+
+        SshClient client = SshClient.setUpDefaultClient();
+        client.start();
+
+        ClientSession session = client.connect("sshd", "localhost", 8001).await().getSession();
+        session.addPasswordIdentity("sshd");
+        session.auth().verify();
+
+        Git.init().setDirectory(repo).call();
+        Git git = Git.open(repo);
+        git.commit().setMessage("First Commit").setCommitter("sshd", "sshd@apache.org").call();
+
+        new File("target/git/pgm/test/readme.txt").createNewFile();
+        execute(session, "git --git-dir test add readme.txt");
+
+        execute(session, "git --git-dir test commit -m \"readme\"");
+
+        client.stop();
+        sshd.stop();
+    }
+
+    private void execute(ClientSession session, String command) throws Exception {
+        ChannelExec channel = session.createExecChannel(command);
+        channel.setOut(System.out);
+        channel.setErr(System.err);
+        channel.open().verify();
+        channel.waitFor(ClientChannel.CLOSED, 0);
+        if (channel.getExitStatus() != null) {
+            int s = channel.getExitStatus();
+            if (s != 0) {
+                throw new Exception("Command failed with status " + s);
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/aca9f534/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java b/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java
index 2558d9c..2ecbd01 100644
--- a/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java
+++ b/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java
@@ -55,4 +55,18 @@ public class Utils {
         return f.toString();
     }
 
+    public static void deleteRecursive(File file) {
+        if (file != null) {
+            if (file.isDirectory()) {
+                File[] children = file.listFiles();
+                if (children != null) {
+                    for (File child : children) {
+                        deleteRecursive(child);
+                    }
+                }
+            }
+            file.delete();
+        }
+    }
+
 }


[2/4] git commit: Optimize Imports

Posted by gn...@apache.org.
Optimize Imports


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/1bb555da
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/1bb555da
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/1bb555da

Branch: refs/heads/master
Commit: 1bb555dae90cbb60b6c68eafc24e5d09602048bd
Parents: f645adf
Author: Stephen Connolly <st...@gmail.com>
Authored: Tue Apr 22 12:10:27 2014 +0100
Committer: Stephen Connolly <st...@gmail.com>
Committed: Tue Apr 22 12:10:27 2014 +0100

----------------------------------------------------------------------
 .../main/java/org/apache/sshd/client/channel/ChannelExec.java  | 6 ------
 .../main/java/org/apache/sshd/client/channel/ChannelShell.java | 6 ------
 2 files changed, 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1bb555da/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java
index ed60346..3a1f2ee 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelExec.java
@@ -19,15 +19,9 @@
 package org.apache.sshd.client.channel;
 
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
 
-import org.apache.sshd.common.PtyMode;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.util.Buffer;
-import org.apache.sshd.common.util.OsUtils;
-import org.apache.sshd.common.util.SttySupport;
 
 /**
  * TODO Add javadoc

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1bb555da/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
index 0188a3a..355a3da 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
@@ -19,15 +19,9 @@
 package org.apache.sshd.client.channel;
 
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
 
-import org.apache.sshd.common.PtyMode;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.util.Buffer;
-import org.apache.sshd.common.util.OsUtils;
-import org.apache.sshd.common.util.SttySupport;
 
 /**
  * TODO Add javadoc