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:16 UTC
[4/4] git commit: [SSHD-241] Git/SSH command support
[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();
+ }
+ }
+
}