From: James Moger Date: Tue, 18 Mar 2014 02:27:58 +0000 (-0400) Subject: Revise dispatchers and move command classes X-Git-Tag: v1.5.0~68^2~70 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=261ddf0fcf9a55fbb5b4e7c6c2cdb4c2f8c860fe;p=gitblit.git Revise dispatchers and move command classes --- diff --git a/src/main/java/com/gitblit/transport/ssh/CommandMetaData.java b/src/main/java/com/gitblit/transport/ssh/CommandMetaData.java deleted file mode 100644 index 0d39f33f..00000000 --- a/src/main/java/com/gitblit/transport/ssh/CommandMetaData.java +++ /dev/null @@ -1,33 +0,0 @@ -//Copyright (C) 2013 The Android Open Source Project -// -//Licensed 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 com.gitblit.transport.ssh; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** -* Annotation tagged on a concrete Command to describe what it is doing -*/ -@Target({ElementType.TYPE}) -@Retention(RUNTIME) -public @interface CommandMetaData { -String name(); -String description() default ""; -boolean admin() default false; -boolean hidden() default false; -} diff --git a/src/main/java/com/gitblit/transport/ssh/SshCommandContext.java b/src/main/java/com/gitblit/transport/ssh/SshCommandContext.java deleted file mode 100644 index 163d0795..00000000 --- a/src/main/java/com/gitblit/transport/ssh/SshCommandContext.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed 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 com.gitblit.transport.ssh; - -import com.gitblit.manager.IGitblit; - -public class SshCommandContext { - - private final IGitblit gitblit; - private final SshDaemonClient client; - private final String commandLine; - - public SshCommandContext(IGitblit gitblit, SshDaemonClient client, String commandLine) { - this.gitblit = gitblit; - this.client = client; - this.commandLine = commandLine; - } - - public IGitblit getGitblit() { - return gitblit; - } - - public SshDaemonClient getClient() { - return client; - } - - public String getCommandLine() { - return commandLine; - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/SshCommandFactory.java b/src/main/java/com/gitblit/transport/ssh/SshCommandFactory.java deleted file mode 100644 index 2b2093ea..00000000 --- a/src/main/java/com/gitblit/transport/ssh/SshCommandFactory.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed 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 com.gitblit.transport.ssh; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.sshd.server.Command; -import org.apache.sshd.server.CommandFactory; -import org.apache.sshd.server.Environment; -import org.apache.sshd.server.ExitCallback; -import org.apache.sshd.server.SessionAware; -import org.apache.sshd.server.session.ServerSession; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.gitblit.manager.IGitblit; -import com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.commands.DispatchCommand; -import com.gitblit.transport.ssh.git.GitDispatchCommand; -import com.gitblit.transport.ssh.gitblit.GitblitDispatchCommand; -import com.gitblit.utils.IdGenerator; -import com.gitblit.utils.WorkQueue; -import com.google.common.util.concurrent.Atomics; - -/** - * - * @author Eric Myhre - * - */ -public class SshCommandFactory implements CommandFactory { - private static final Logger logger = LoggerFactory.getLogger(SshCommandFactory.class); - - private final IGitblit gitblit; - private final ScheduledExecutorService startExecutor; - - public SshCommandFactory(IGitblit gitblit, IdGenerator idGenerator) { - this.gitblit = gitblit; - - int threads = 2;// cfg.getInt("sshd","commandStartThreads", 2); - WorkQueue workQueue = new WorkQueue(idGenerator); - startExecutor = workQueue.createQueue(threads, "SshCommandStart"); - } - - /** - * Creates the root dispatcher command which builds up the available commands. - * - * @param the client - * @param the command line - * @return the root dispatcher command - */ - protected DispatchCommand createRootDispatcher(SshDaemonClient client, String cmdLine) { - final UserModel user = client.getUser(); - - DispatchCommand root = new DispatchCommand() { - }; - root.setContext(new SshCommandContext(gitblit, client, cmdLine)); - - // TODO convert these dispatchers to plugin extension points - root.registerDispatcher(user, GitblitDispatchCommand.class); - root.registerDispatcher(user, GitDispatchCommand.class); - - return root; - } - - @Override - public Command createCommand(final String commandLine) { - return new Trampoline(commandLine); - } - - private class Trampoline implements Command, SessionAware { - private final String[] argv; - private ServerSession session; - private InputStream in; - private OutputStream out; - private OutputStream err; - private ExitCallback exit; - private Environment env; - private String cmdLine; - private DispatchCommand cmd; - private final AtomicBoolean logged; - private final AtomicReference> task; - - Trampoline(String line) { - if (line.startsWith("git-")) { - line = "git " + line; - } - cmdLine = line; - argv = split(line); - logged = new AtomicBoolean(); - task = Atomics.newReference(); - } - - @Override - public void setSession(ServerSession session) { - this.session = session; - } - - @Override - public void setInputStream(final InputStream in) { - this.in = in; - } - - @Override - public void setOutputStream(final OutputStream out) { - this.out = out; - } - - @Override - public void setErrorStream(final OutputStream err) { - this.err = err; - } - - @Override - public void setExitCallback(final ExitCallback callback) { - this.exit = callback; - } - - @Override - public void start(final Environment env) throws IOException { - this.env = env; - task.set(startExecutor.submit(new Runnable() { - @Override - public void run() { - try { - onStart(); - } catch (Exception e) { - logger.warn("Cannot start command ", e); - } - } - - @Override - public String toString() { - return "start (user " + session.getUsername() + ")"; - } - })); - } - - private void onStart() throws IOException { - synchronized (this) { - SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY); - try { - cmd = createRootDispatcher(client, cmdLine); - cmd.setArguments(argv); - cmd.setInputStream(in); - cmd.setOutputStream(out); - cmd.setErrorStream(err); - cmd.setExitCallback(new ExitCallback() { - @Override - public void onExit(int rc, String exitMessage) { - exit.onExit(translateExit(rc), exitMessage); - log(rc); - } - - @Override - public void onExit(int rc) { - exit.onExit(translateExit(rc)); - log(rc); - } - }); - cmd.start(env); - } finally { - client = null; - } - } - } - - private int translateExit(final int rc) { - return rc; - // - // switch (rc) { - // case BaseCommand.STATUS_NOT_ADMIN: - // return 1; - // - // case BaseCommand.STATUS_CANCEL: - // return 15 /* SIGKILL */; - // - // case BaseCommand.STATUS_NOT_FOUND: - // return 127 /* POSIX not found */; - // - // default: - // return rc; - // } - - } - - private void log(final int rc) { - if (logged.compareAndSet(false, true)) { - // log.onExecute(cmd, rc); - logger.info("onExecute: {} exits with: {}", cmd.getClass().getSimpleName(), rc); - } - } - - @Override - public void destroy() { - Future future = task.getAndSet(null); - if (future != null) { - future.cancel(true); - // destroyExecutor.execute(new Runnable() { - // @Override - // public void run() { - // onDestroy(); - // } - // }); - } - } - - @SuppressWarnings("unused") - private void onDestroy() { - synchronized (this) { - if (cmd != null) { - // final Context old = sshScope.set(ctx); - try { - cmd.destroy(); - // log(BaseCommand.STATUS_CANCEL); - } finally { - // ctx = null; - cmd = null; - // sshScope.set(old); - } - } - } - } - } - - /** Split a command line into a string array. */ - static public String[] split(String commandLine) { - final List list = new ArrayList(); - boolean inquote = false; - boolean inDblQuote = false; - StringBuilder r = new StringBuilder(); - for (int ip = 0; ip < commandLine.length();) { - final char b = commandLine.charAt(ip++); - switch (b) { - case '\t': - case ' ': - if (inquote || inDblQuote) - r.append(b); - else if (r.length() > 0) { - list.add(r.toString()); - r = new StringBuilder(); - } - continue; - case '\"': - if (inquote) - r.append(b); - else - inDblQuote = !inDblQuote; - continue; - case '\'': - if (inDblQuote) - r.append(b); - else - inquote = !inquote; - continue; - case '\\': - if (inquote || ip == commandLine.length()) - r.append(b); // literal within a quote - else - r.append(commandLine.charAt(ip++)); - continue; - default: - r.append(b); - continue; - } - } - if (r.length() > 0) { - list.add(r.toString()); - } - return list.toArray(new String[list.size()]); - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java index da9a3726..aeb6ce51 100644 --- a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java +++ b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java @@ -34,6 +34,7 @@ import com.gitblit.Constants; import com.gitblit.IStoredSettings; import com.gitblit.Keys; import com.gitblit.manager.IGitblit; +import com.gitblit.transport.ssh.commands.SshCommandFactory; import com.gitblit.utils.IdGenerator; import com.gitblit.utils.StringUtils; diff --git a/src/main/java/com/gitblit/transport/ssh/WelcomeShell.java b/src/main/java/com/gitblit/transport/ssh/WelcomeShell.java index 819028c5..ccf2586b 100644 --- a/src/main/java/com/gitblit/transport/ssh/WelcomeShell.java +++ b/src/main/java/com/gitblit/transport/ssh/WelcomeShell.java @@ -35,6 +35,7 @@ import com.gitblit.IStoredSettings; import com.gitblit.Keys; import com.gitblit.models.UserModel; import com.gitblit.transport.ssh.commands.DispatchCommand; +import com.gitblit.transport.ssh.commands.SshCommandFactory; import com.gitblit.utils.StringUtils; /** diff --git a/src/main/java/com/gitblit/transport/ssh/commands/BaseCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/BaseCommand.java index a3df787c..7088fefa 100644 --- a/src/main/java/com/gitblit/transport/ssh/commands/BaseCommand.java +++ b/src/main/java/com/gitblit/transport/ssh/commands/BaseCommand.java @@ -37,7 +37,6 @@ import org.kohsuke.args4j.Option; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.gitblit.transport.ssh.SshCommandContext; import com.gitblit.utils.IdGenerator; import com.gitblit.utils.WorkQueue; import com.gitblit.utils.WorkQueue.CancelableRunnable; diff --git a/src/main/java/com/gitblit/transport/ssh/commands/CommandMetaData.java b/src/main/java/com/gitblit/transport/ssh/commands/CommandMetaData.java new file mode 100644 index 00000000..133b9cbf --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/commands/CommandMetaData.java @@ -0,0 +1,33 @@ +//Copyright (C) 2013 The Android Open Source Project +// +//Licensed 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 com.gitblit.transport.ssh.commands; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** +* Annotation tagged on a concrete Command to describe what it is doing +*/ +@Target({ElementType.TYPE}) +@Retention(RUNTIME) +public @interface CommandMetaData { +String name(); +String description() default ""; +boolean admin() default false; +boolean hidden() default false; +} diff --git a/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java index dd581f4d..f7c78d28 100644 --- a/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java +++ b/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java @@ -31,7 +31,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.CommandMetaData; import com.gitblit.utils.StringUtils; import com.gitblit.utils.cli.SubcommandHandler; import com.google.common.base.Charsets; @@ -48,15 +47,15 @@ public abstract class DispatchCommand extends BaseCommand { @Argument(index = 1, multiValued = true, metaVar = "ARG") private List args = new ArrayList(); - private Set> commands; + private final Set> commands; private Map> map; private Map dispatchers; - public DispatchCommand() { + protected DispatchCommand() { commands = new HashSet>(); } - public void registerDispatcher(UserModel user, Class cmd) { + protected void registerDispatcher(UserModel user, Class cmd) { if (!cmd.isAnnotationPresent(CommandMetaData.class)) { throw new RuntimeException(MessageFormat.format("{0} must be annotated with {1}!", cmd.getName(), CommandMetaData.class.getName())); @@ -80,8 +79,7 @@ public abstract class DispatchCommand extends BaseCommand { } } - protected void registerCommands(UserModel user) { - } + protected abstract void registerCommands(UserModel user); /** @@ -90,7 +88,7 @@ public abstract class DispatchCommand extends BaseCommand { * @param user * @param cmd */ - public void registerCommand(UserModel user, Class cmd) { + protected void registerCommand(UserModel user, Class cmd) { if (!cmd.isAnnotationPresent(CommandMetaData.class)) { throw new RuntimeException(MessageFormat.format("{0} must be annotated with {1}!", cmd.getName(), CommandMetaData.class.getName())); diff --git a/src/main/java/com/gitblit/transport/ssh/commands/RootDispatcher.java b/src/main/java/com/gitblit/transport/ssh/commands/RootDispatcher.java new file mode 100644 index 00000000..5d9eb197 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/commands/RootDispatcher.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed 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 com.gitblit.transport.ssh.commands; + +import com.gitblit.manager.IGitblit; +import com.gitblit.models.UserModel; +import com.gitblit.transport.ssh.SshDaemonClient; +import com.gitblit.transport.ssh.git.GitDispatcher; +import com.gitblit.transport.ssh.gitblit.GitblitDispatcher; + +/** + * The root dispatcher is the dispatch command that handles registering all + * other commands. + * + */ +public class RootDispatcher extends DispatchCommand { + + public RootDispatcher(IGitblit gitblit, SshDaemonClient client, String cmdLine) { + super(); + setContext(new SshCommandContext(gitblit, client, cmdLine)); + + final UserModel user = client.getUser(); + registerDispatcher(user, GitblitDispatcher.class); + registerDispatcher(user, GitDispatcher.class); + + // TODO register plugin dispatchers here + } + + @Override + protected final void registerCommands(UserModel user) { + } + + @Override + protected final void registerCommand(UserModel user, Class cmd) { + throw new RuntimeException("The root dispatcher does not accept commands, only dispatchers!"); + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/transport/ssh/commands/SshCommandContext.java b/src/main/java/com/gitblit/transport/ssh/commands/SshCommandContext.java new file mode 100644 index 00000000..15f7a8fe --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/commands/SshCommandContext.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed 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 com.gitblit.transport.ssh.commands; + +import com.gitblit.manager.IGitblit; +import com.gitblit.transport.ssh.SshDaemonClient; + +public class SshCommandContext { + + private final IGitblit gitblit; + private final SshDaemonClient client; + private final String commandLine; + + public SshCommandContext(IGitblit gitblit, SshDaemonClient client, String commandLine) { + this.gitblit = gitblit; + this.client = client; + this.commandLine = commandLine; + } + + public IGitblit getGitblit() { + return gitblit; + } + + public SshDaemonClient getClient() { + return client; + } + + public String getCommandLine() { + return commandLine; + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/commands/SshCommandFactory.java b/src/main/java/com/gitblit/transport/ssh/commands/SshCommandFactory.java new file mode 100644 index 00000000..3eefcae7 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/commands/SshCommandFactory.java @@ -0,0 +1,272 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed 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 com.gitblit.transport.ssh.commands; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.sshd.server.Command; +import org.apache.sshd.server.CommandFactory; +import org.apache.sshd.server.Environment; +import org.apache.sshd.server.ExitCallback; +import org.apache.sshd.server.SessionAware; +import org.apache.sshd.server.session.ServerSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gitblit.manager.IGitblit; +import com.gitblit.transport.ssh.SshDaemonClient; +import com.gitblit.utils.IdGenerator; +import com.gitblit.utils.WorkQueue; +import com.google.common.util.concurrent.Atomics; + +/** + * + * @author Eric Myhre + * + */ +public class SshCommandFactory implements CommandFactory { + private static final Logger logger = LoggerFactory.getLogger(SshCommandFactory.class); + + private final IGitblit gitblit; + private final ScheduledExecutorService startExecutor; + + public SshCommandFactory(IGitblit gitblit, IdGenerator idGenerator) { + this.gitblit = gitblit; + + int threads = 2;// cfg.getInt("sshd","commandStartThreads", 2); + WorkQueue workQueue = new WorkQueue(idGenerator); + startExecutor = workQueue.createQueue(threads, "SshCommandStart"); + } + + public RootDispatcher createRootDispatcher(SshDaemonClient client, String commandLine) { + return new RootDispatcher(gitblit, client, commandLine); + } + + @Override + public Command createCommand(final String commandLine) { + return new Trampoline(commandLine); + } + + private class Trampoline implements Command, SessionAware { + private final String[] argv; + private ServerSession session; + private InputStream in; + private OutputStream out; + private OutputStream err; + private ExitCallback exit; + private Environment env; + private String cmdLine; + private DispatchCommand cmd; + private final AtomicBoolean logged; + private final AtomicReference> task; + + Trampoline(String line) { + if (line.startsWith("git-")) { + line = "git " + line; + } + cmdLine = line; + argv = split(line); + logged = new AtomicBoolean(); + task = Atomics.newReference(); + } + + @Override + public void setSession(ServerSession session) { + this.session = session; + } + + @Override + public void setInputStream(final InputStream in) { + this.in = in; + } + + @Override + public void setOutputStream(final OutputStream out) { + this.out = out; + } + + @Override + public void setErrorStream(final OutputStream err) { + this.err = err; + } + + @Override + public void setExitCallback(final ExitCallback callback) { + this.exit = callback; + } + + @Override + public void start(final Environment env) throws IOException { + this.env = env; + task.set(startExecutor.submit(new Runnable() { + @Override + public void run() { + try { + onStart(); + } catch (Exception e) { + logger.warn("Cannot start command ", e); + } + } + + @Override + public String toString() { + return "start (user " + session.getUsername() + ")"; + } + })); + } + + private void onStart() throws IOException { + synchronized (this) { + SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY); + try { + cmd = createRootDispatcher(client, cmdLine); + cmd.setArguments(argv); + cmd.setInputStream(in); + cmd.setOutputStream(out); + cmd.setErrorStream(err); + cmd.setExitCallback(new ExitCallback() { + @Override + public void onExit(int rc, String exitMessage) { + exit.onExit(translateExit(rc), exitMessage); + log(rc); + } + + @Override + public void onExit(int rc) { + exit.onExit(translateExit(rc)); + log(rc); + } + }); + cmd.start(env); + } finally { + client = null; + } + } + } + + private int translateExit(final int rc) { + return rc; + // + // switch (rc) { + // case BaseCommand.STATUS_NOT_ADMIN: + // return 1; + // + // case BaseCommand.STATUS_CANCEL: + // return 15 /* SIGKILL */; + // + // case BaseCommand.STATUS_NOT_FOUND: + // return 127 /* POSIX not found */; + // + // default: + // return rc; + // } + + } + + private void log(final int rc) { + if (logged.compareAndSet(false, true)) { + // log.onExecute(cmd, rc); + logger.info("onExecute: {} exits with: {}", cmd.getClass().getSimpleName(), rc); + } + } + + @Override + public void destroy() { + Future future = task.getAndSet(null); + if (future != null) { + future.cancel(true); + // destroyExecutor.execute(new Runnable() { + // @Override + // public void run() { + // onDestroy(); + // } + // }); + } + } + + @SuppressWarnings("unused") + private void onDestroy() { + synchronized (this) { + if (cmd != null) { + // final Context old = sshScope.set(ctx); + try { + cmd.destroy(); + // log(BaseCommand.STATUS_CANCEL); + } finally { + // ctx = null; + cmd = null; + // sshScope.set(old); + } + } + } + } + } + + /** Split a command line into a string array. */ + static public String[] split(String commandLine) { + final List list = new ArrayList(); + boolean inquote = false; + boolean inDblQuote = false; + StringBuilder r = new StringBuilder(); + for (int ip = 0; ip < commandLine.length();) { + final char b = commandLine.charAt(ip++); + switch (b) { + case '\t': + case ' ': + if (inquote || inDblQuote) + r.append(b); + else if (r.length() > 0) { + list.add(r.toString()); + r = new StringBuilder(); + } + continue; + case '\"': + if (inquote) + r.append(b); + else + inDblQuote = !inDblQuote; + continue; + case '\'': + if (inDblQuote) + r.append(b); + else + inquote = !inquote; + continue; + case '\\': + if (inquote || ip == commandLine.length()) + r.append(b); // literal within a quote + else + r.append(commandLine.charAt(ip++)); + continue; + default: + r.append(b); + continue; + } + } + if (r.length() > 0) { + list.add(r.toString()); + } + return list.toArray(new String[list.size()]); + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/git/GitDispatchCommand.java b/src/main/java/com/gitblit/transport/ssh/git/GitDispatchCommand.java deleted file mode 100644 index adeace52..00000000 --- a/src/main/java/com/gitblit/transport/ssh/git/GitDispatchCommand.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed 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 com.gitblit.transport.ssh.git; - -import com.gitblit.git.GitblitReceivePackFactory; -import com.gitblit.git.GitblitUploadPackFactory; -import com.gitblit.git.RepositoryResolver; -import com.gitblit.manager.IGitblit; -import com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.CommandMetaData; -import com.gitblit.transport.ssh.SshCommandContext; -import com.gitblit.transport.ssh.SshDaemonClient; -import com.gitblit.transport.ssh.commands.BaseCommand; -import com.gitblit.transport.ssh.commands.DispatchCommand; - -@CommandMetaData(name = "git", description="Dispatcher for git receive and upload commands", hidden = true) -public class GitDispatchCommand extends DispatchCommand { - - protected RepositoryResolver repositoryResolver; - protected GitblitUploadPackFactory uploadPackFactory; - protected GitblitReceivePackFactory receivePackFactory; - - @Override - public void setContext(SshCommandContext context) { - super.setContext(context); - - IGitblit gitblit = context.getGitblit(); - repositoryResolver = new RepositoryResolver(gitblit); - uploadPackFactory = new GitblitUploadPackFactory(gitblit); - receivePackFactory = new GitblitReceivePackFactory(gitblit); - } - - @Override - protected void registerCommands(UserModel user) { - registerCommand(user, Upload.class); - registerCommand(user, Receive.class); - } - - @Override - protected void provideStateTo(final BaseCommand cmd) { - super.provideStateTo(cmd); - - BaseGitCommand a = (BaseGitCommand) cmd; - a.setRepositoryResolver(repositoryResolver); - a.setUploadPackFactory(uploadPackFactory); - a.setReceivePackFactory(receivePackFactory); - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/git/GitDispatcher.java b/src/main/java/com/gitblit/transport/ssh/git/GitDispatcher.java new file mode 100644 index 00000000..fa1dfbd4 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/git/GitDispatcher.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed 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 com.gitblit.transport.ssh.git; + +import com.gitblit.git.GitblitReceivePackFactory; +import com.gitblit.git.GitblitUploadPackFactory; +import com.gitblit.git.RepositoryResolver; +import com.gitblit.manager.IGitblit; +import com.gitblit.models.UserModel; +import com.gitblit.transport.ssh.SshDaemonClient; +import com.gitblit.transport.ssh.commands.BaseCommand; +import com.gitblit.transport.ssh.commands.CommandMetaData; +import com.gitblit.transport.ssh.commands.DispatchCommand; +import com.gitblit.transport.ssh.commands.SshCommandContext; + +@CommandMetaData(name = "git", description="Dispatcher for git receive and upload commands", hidden = true) +public class GitDispatcher extends DispatchCommand { + + protected RepositoryResolver repositoryResolver; + protected GitblitUploadPackFactory uploadPackFactory; + protected GitblitReceivePackFactory receivePackFactory; + + @Override + public void setContext(SshCommandContext context) { + super.setContext(context); + + IGitblit gitblit = context.getGitblit(); + repositoryResolver = new RepositoryResolver(gitblit); + uploadPackFactory = new GitblitUploadPackFactory(gitblit); + receivePackFactory = new GitblitReceivePackFactory(gitblit); + } + + @Override + protected void registerCommands(UserModel user) { + registerCommand(user, Upload.class); + registerCommand(user, Receive.class); + } + + @Override + protected void provideStateTo(final BaseCommand cmd) { + super.provideStateTo(cmd); + + BaseGitCommand a = (BaseGitCommand) cmd; + a.setRepositoryResolver(repositoryResolver); + a.setUploadPackFactory(uploadPackFactory); + a.setReceivePackFactory(receivePackFactory); + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/git/Receive.java b/src/main/java/com/gitblit/transport/ssh/git/Receive.java index 4089f1df..9597eb4d 100644 --- a/src/main/java/com/gitblit/transport/ssh/git/Receive.java +++ b/src/main/java/com/gitblit/transport/ssh/git/Receive.java @@ -17,7 +17,7 @@ package com.gitblit.transport.ssh.git; import org.eclipse.jgit.transport.ReceivePack; -import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.CommandMetaData; @CommandMetaData(name = "git-receive-pack", description = "Receives pushes from a client") public class Receive extends BaseGitCommand { diff --git a/src/main/java/com/gitblit/transport/ssh/git/Upload.java b/src/main/java/com/gitblit/transport/ssh/git/Upload.java index 5793c3e6..5de6b4d2 100644 --- a/src/main/java/com/gitblit/transport/ssh/git/Upload.java +++ b/src/main/java/com/gitblit/transport/ssh/git/Upload.java @@ -17,7 +17,7 @@ package com.gitblit.transport.ssh.git; import org.eclipse.jgit.transport.UploadPack; -import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.CommandMetaData; @CommandMetaData(name = "git-upload-pack", description = "Sends packs to a client for clone and fetch") public class Upload extends BaseGitCommand { diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/AddKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/AddKeyCommand.java index 6d5c85c7..ae24dfb3 100644 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/AddKeyCommand.java +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/AddKeyCommand.java @@ -23,7 +23,7 @@ import org.kohsuke.args4j.Argument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.CommandMetaData; /** * Add a key to the current user's authorized keys list. diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/CreateRepository.java b/src/main/java/com/gitblit/transport/ssh/gitblit/CreateRepository.java index b2e1b1b0..2917b6d2 100644 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/CreateRepository.java +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/CreateRepository.java @@ -18,7 +18,7 @@ package com.gitblit.transport.ssh.gitblit; import org.kohsuke.args4j.Option; -import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.CommandMetaData; import com.gitblit.transport.ssh.commands.SshCommand; @CommandMetaData(name = "create-repository", description = "Create new GIT repository", admin = true, hidden = true) diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatchCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatchCommand.java deleted file mode 100644 index 9eff9bd1..00000000 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatchCommand.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed 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 com.gitblit.transport.ssh.gitblit; - -import com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.CommandMetaData; -import com.gitblit.transport.ssh.commands.DispatchCommand; - -@CommandMetaData(name = "gitblit", description = "Gitblit server commands") -public class GitblitDispatchCommand extends DispatchCommand { - - @Override - protected void registerCommands(UserModel user) { - // normal usage commands - registerCommand(user, VersionCommand.class); - registerCommand(user, AddKeyCommand.class); - registerCommand(user, RemoveKeyCommand.class); - registerCommand(user, LsCommand.class); - registerCommand(user, ReviewCommand.class); - - // administrative commands - registerCommand(user, LsUsersCommand.class); - registerCommand(user, CreateRepository.class); - registerCommand(user, SetAccountCommand.class); - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatcher.java b/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatcher.java new file mode 100644 index 00000000..eb3bb0c6 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatcher.java @@ -0,0 +1,39 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed 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 com.gitblit.transport.ssh.gitblit; + +import com.gitblit.models.UserModel; +import com.gitblit.transport.ssh.commands.CommandMetaData; +import com.gitblit.transport.ssh.commands.DispatchCommand; + +@CommandMetaData(name = "gitblit", description = "Gitblit server commands") +public class GitblitDispatcher extends DispatchCommand { + + @Override + protected void registerCommands(UserModel user) { + // normal usage commands + registerCommand(user, VersionCommand.class); + registerCommand(user, AddKeyCommand.class); + registerCommand(user, RemoveKeyCommand.class); + registerCommand(user, LsCommand.class); + registerCommand(user, ReviewCommand.class); + + // administrative commands + registerCommand(user, LsUsersCommand.class); + registerCommand(user, CreateRepository.class); + registerCommand(user, SetAccountCommand.class); + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/LsCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/LsCommand.java index cf50a2ee..75cb2d83 100644 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/LsCommand.java +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/LsCommand.java @@ -27,7 +27,7 @@ import com.gitblit.manager.IGitblit; import com.gitblit.models.ProjectModel; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.CommandMetaData; import com.gitblit.transport.ssh.commands.SshCommand; @CommandMetaData(name = "ls", description = "List repositories or projects") diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/LsUsersCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/LsUsersCommand.java index dd269213..752afaf6 100644 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/LsUsersCommand.java +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/LsUsersCommand.java @@ -24,7 +24,7 @@ import org.parboiled.common.StringUtils; import com.gitblit.manager.IGitblit; import com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.CommandMetaData; import com.gitblit.transport.ssh.commands.SshCommand; @CommandMetaData(name = "ls-users", description = "List users", admin = true) diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/RemoveKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/RemoveKeyCommand.java index 7c9abfd4..af307303 100644 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/RemoveKeyCommand.java +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/RemoveKeyCommand.java @@ -23,7 +23,7 @@ import org.kohsuke.args4j.Argument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.CommandMetaData; /** diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/ReviewCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/ReviewCommand.java index 9e4d8ba7..b3691cbb 100644 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/ReviewCommand.java +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/ReviewCommand.java @@ -25,7 +25,7 @@ import com.gitblit.models.TicketModel.Change; import com.gitblit.models.TicketModel.Patchset; import com.gitblit.models.TicketModel.Score; import com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.CommandMetaData; import com.gitblit.transport.ssh.commands.SshCommand; import com.gitblit.wicket.GitBlitWebSession; diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/SetAccountCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/SetAccountCommand.java index 28ac9e19..aebe3b1f 100644 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/SetAccountCommand.java +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/SetAccountCommand.java @@ -22,7 +22,7 @@ import java.util.List; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; -import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.CommandMetaData; /** Set a user's account settings. **/ @CommandMetaData(name = "set-account", description = "Change an account's settings", admin = true) diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/VersionCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/VersionCommand.java index 513f6d96..384c6ce4 100644 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/VersionCommand.java +++ b/src/main/java/com/gitblit/transport/ssh/gitblit/VersionCommand.java @@ -17,7 +17,7 @@ package com.gitblit.transport.ssh.gitblit; import com.gitblit.Constants; -import com.gitblit.transport.ssh.CommandMetaData; +import com.gitblit.transport.ssh.commands.CommandMetaData; import com.gitblit.transport.ssh.commands.SshCommand; @CommandMetaData(name="version", description = "Display the Gitblit version")