Display command description in ssh gerrit --help

Show one line description for each ssh command. Make COMMAND
argument optional, so that --help argument is not needed.

This approach is working for core gerrit commands, aliases, nested
commands and plugin's own ssh commands.

To provide a description ssh command must be annotated with
CommandMetaData annotation, i. e.:

@CommandMetaData(name="print", descr="Print greeting in different languages")
public final class PrintHelloWorldCommand extends SshCommand { ...

Syntactic sugar for command registration is provided to reflect the fact,
that both name and description are included in CommandMetaData annotation.

To register command and alias in plugin:
protected void configureCommands() {
  command(PrintHelloWorldCommand.class);
  alias("say-hello", PrintHelloWorldCommand.class);
[...]

With the outcome:
$ ssh gerrit helloworld
Available commands of helloworld are:

   print       Print greeting in different languages
   say-hello   Print greeting in different languages

Change-Id: I2e5440378023ecc5425092d8131f121da2f20a30
This commit is contained in:
David Ostrovsky 2013-01-13 16:00:45 +01:00
parent 1756441516
commit e51c428fe5
39 changed files with 281 additions and 62 deletions

View File

@ -60,26 +60,26 @@ public class AliasCommand extends BaseCommand {
}
private void begin(Environment env) throws UnloggedFailure, IOException {
Map<String, Provider<Command>> map = root.getMap();
Map<String, CommandProvider> map = root.getMap();
for (String name : chain(command)) {
Provider<? extends Command> p = map.get(name);
CommandProvider p = map.get(name);
if (p == null) {
throw new UnloggedFailure(1, getName() + ": not found");
}
Command cmd = p.get();
Command cmd = p.getProvider().get();
if (!(cmd instanceof DispatchCommand)) {
throw new UnloggedFailure(1, getName() + ": not found");
}
map = ((DispatchCommand) cmd).getMap();
}
Provider<? extends Command> p = map.get(command.value());
CommandProvider p = map.get(command.value());
if (p == null) {
throw new UnloggedFailure(1, getName() + ": not found");
}
Command cmd = p.get();
Command cmd = p.getProvider().get();
checkRequiresCapability(cmd);
if (cmd instanceof BaseCommand) {
BaseCommand bc = (BaseCommand)cmd;

View File

@ -0,0 +1,31 @@
// 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.google.gerrit.sshd;
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 descr() default "";
}

View File

@ -48,7 +48,7 @@ public abstract class CommandModule extends AbstractModule {
/**
* Configure a command to be invoked by name.
*
*@param parent context of the parent command, that this command is a
* @param parent context of the parent command, that this command is a
* subcommand of.
* @param name the name of the command the client will provide in order to
* call the command.
@ -60,6 +60,42 @@ public abstract class CommandModule extends AbstractModule {
return bind(Commands.key(parent, name));
}
/**
* Configure a command to be invoked by name. The command is bound to the passed class.
*
* @param parent context of the parent command, that this command is a
* subcommand of.
* @param clazz class of the command with {@link CommandMetaData} annotation
* to retrieve the name and the description from
*/
protected void command(final CommandName parent,
final Class<? extends BaseCommand> clazz) {
CommandMetaData meta = (CommandMetaData)clazz.getAnnotation(CommandMetaData.class);
if (meta == null) {
throw new IllegalStateException("no CommandMetaData annotation found");
}
bind(Commands.key(parent, meta.name(), meta.descr())).to(clazz);
}
/**
* Alias one command to another. The alias is bound to the passed class.
*
* @param parent context of the parent command, that this command is a
* subcommand of.
* @param name the name of the command the client will provide in order to
* call the command.
* @param clazz class of the command with {@link CommandMetaData} annotation
* to retrieve the description from
*/
protected void alias(final CommandName parent, final String name,
final Class<? extends BaseCommand> clazz) {
CommandMetaData meta = (CommandMetaData)clazz.getAnnotation(CommandMetaData.class);
if (meta == null) {
throw new IllegalStateException("no CommandMetaData annotation found");
}
bind(Commands.key(parent, name, meta.descr())).to(clazz);
}
/**
* Alias one command to another.
*

View File

@ -0,0 +1,38 @@
// 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.google.gerrit.sshd;
import com.google.inject.Provider;
import org.apache.sshd.server.Command;
final class CommandProvider {
private final Provider<Command> provider;
private final String description;
CommandProvider(final Provider<Command> p, final String d) {
this.provider = p;
this.description = d;
}
public Provider<Command> getProvider() {
return provider;
}
public String getDescription() {
return description;
}
}

View File

@ -16,6 +16,7 @@ package com.google.gerrit.sshd;
import com.google.inject.Key;
import org.apache.commons.lang.StringUtils;
import org.apache.sshd.server.Command;
import java.lang.annotation.Annotation;
@ -41,6 +42,11 @@ public class Commands {
return Key.get(Command.class, named(parent, name));
}
public static Key<Command> key(final CommandName parent,
final String name, final String descr) {
return Key.get(Command.class, named(parent, name, descr));
}
/** Create a CommandName annotation for the supplied name. */
public static CommandName named(final String name) {
return new CommandName() {
@ -78,6 +84,12 @@ public class Commands {
return new NestedCommandNameImpl(parent, name);
}
/** Create a CommandName annotation for the supplied name and description. */
public static CommandName named(final CommandName parent, final String name,
final String descr) {
return new NestedCommandNameImpl(parent, name, descr);
}
/** Return the name of this command, possibly including any parents. */
public static String nameOf(final CommandName name) {
if (name instanceof NestedCommandNameImpl) {
@ -104,13 +116,22 @@ public class Commands {
return null;
}
private static final class NestedCommandNameImpl implements CommandName {
static final class NestedCommandNameImpl implements CommandName {
private final CommandName parent;
private final String name;
private final String descr;
NestedCommandNameImpl(final CommandName parent, final String name) {
this.parent = parent;
this.name = name;
this.descr = StringUtils.EMPTY;
}
NestedCommandNameImpl(final CommandName parent, final String name,
final String descr) {
this.parent = parent;
this.name = name;
this.descr = descr;
}
@Override
@ -118,6 +139,10 @@ public class Commands {
return name;
}
public String descr() {
return descr;
}
@Override
public Class<? extends Annotation> annotationType() {
return CommandName.class;

View File

@ -14,6 +14,7 @@
package com.google.gerrit.sshd;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Atomics;
import com.google.gerrit.extensions.annotations.RequiresCapability;
@ -29,6 +30,7 @@ import org.apache.sshd.server.Environment;
import org.kohsuke.args4j.Argument;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -39,14 +41,14 @@ import java.util.concurrent.atomic.AtomicReference;
*/
final class DispatchCommand extends BaseCommand {
interface Factory {
DispatchCommand create(Map<String, Provider<Command>> map);
DispatchCommand create(Map<String, CommandProvider> map);
}
private final Provider<CurrentUser> currentUser;
private final Map<String, Provider<Command>> commands;
private final Map<String, CommandProvider> commands;
private final AtomicReference<Command> atomicCmd;
@Argument(index = 0, required = true, metaVar = "COMMAND", handler = SubcommandHandler.class)
@Argument(index = 0, required = false, metaVar = "COMMAND", handler = SubcommandHandler.class)
private String commandName;
@Argument(index = 1, multiValued = true, metaVar = "ARG")
@ -54,13 +56,13 @@ final class DispatchCommand extends BaseCommand {
@Inject
DispatchCommand(final Provider<CurrentUser> cu,
@Assisted final Map<String, Provider<Command>> all) {
@Assisted final Map<String, CommandProvider> all) {
currentUser = cu;
commands = all;
atomicCmd = Atomics.newReference();
}
Map<String, Provider<Command>> getMap() {
Map<String, CommandProvider> getMap() {
return commands;
}
@ -68,8 +70,13 @@ final class DispatchCommand extends BaseCommand {
public void start(final Environment env) throws IOException {
try {
parseCommandLine();
if (Strings.isNullOrEmpty(commandName)) {
StringWriter msg = new StringWriter();
msg.write(usage());
throw new UnloggedFailure(1, msg.toString());
}
final Provider<Command> p = commands.get(commandName);
final CommandProvider p = commands.get(commandName);
if (p == null) {
String msg =
(getName().isEmpty() ? "Gerrit Code Review" : getName()) + ": "
@ -77,7 +84,7 @@ final class DispatchCommand extends BaseCommand {
throw new UnloggedFailure(1, msg);
}
final Command cmd = p.get();
final Command cmd = p.getProvider().get();
checkRequiresCapability(cmd);
if (cmd instanceof BaseCommand) {
final BaseCommand bc = (BaseCommand) cmd;
@ -138,9 +145,17 @@ final class DispatchCommand extends BaseCommand {
}
usage.append(" are:\n");
usage.append("\n");
int maxLength = -1;
for (String name : commands.keySet()) {
maxLength = Math.max(maxLength, name.length());
}
String format = "%-" + maxLength + "s %s";
for (String name : Sets.newTreeSet(commands.keySet())) {
final CommandProvider p = commands.get(name);
usage.append(" ");
usage.append(name);
usage.append(String.format(format, name,
Strings.nullToEmpty(p.getDescription())));
usage.append("\n");
}
usage.append("\n");

View File

@ -39,7 +39,7 @@ public class DispatchCommandProvider implements Provider<DispatchCommand> {
private DispatchCommand.Factory factory;
private final CommandName parent;
private volatile ConcurrentMap<String, Provider<Command>> map;
private volatile ConcurrentMap<String, CommandProvider> map;
public DispatchCommandProvider(final CommandName cn) {
this.parent = cn;
@ -52,8 +52,8 @@ public class DispatchCommandProvider implements Provider<DispatchCommand> {
public RegistrationHandle register(final CommandName name,
final Provider<Command> cmd) {
final ConcurrentMap<String, Provider<Command>> m = getMap();
if (m.putIfAbsent(name.value(), cmd) != null) {
final ConcurrentMap<String, CommandProvider> m = getMap();
if (m.putIfAbsent(name.value(), new CommandProvider(cmd, null)) != null) {
throw new IllegalArgumentException(name.value() + " exists");
}
return new RegistrationHandle() {
@ -66,8 +66,8 @@ public class DispatchCommandProvider implements Provider<DispatchCommand> {
public RegistrationHandle replace(final CommandName name,
final Provider<Command> cmd) {
final ConcurrentMap<String, Provider<Command>> m = getMap();
m.put(name.value(), cmd);
final ConcurrentMap<String, CommandProvider> m = getMap();
m.put(name.value(), new CommandProvider(cmd, null));
return new RegistrationHandle() {
@Override
public void remove() {
@ -76,7 +76,7 @@ public class DispatchCommandProvider implements Provider<DispatchCommand> {
};
}
ConcurrentMap<String, Provider<Command>> getMap() {
ConcurrentMap<String, CommandProvider> getMap() {
if (map == null) {
synchronized (this) {
if (map == null) {
@ -88,14 +88,21 @@ public class DispatchCommandProvider implements Provider<DispatchCommand> {
}
@SuppressWarnings("unchecked")
private ConcurrentMap<String, Provider<Command>> createMap() {
ConcurrentMap<String, Provider<Command>> m = Maps.newConcurrentMap();
private ConcurrentMap<String, CommandProvider> createMap() {
ConcurrentMap<String, CommandProvider> m = Maps.newConcurrentMap();
for (final Binding<?> b : allCommands()) {
final Annotation annotation = b.getKey().getAnnotation();
if (annotation instanceof CommandName) {
String descr = null;
if (annotation instanceof Commands.NestedCommandNameImpl) {
Commands.NestedCommandNameImpl impl =
((Commands.NestedCommandNameImpl) annotation);
descr = impl.descr();
}
final CommandName n = (CommandName) annotation;
if (!Commands.CMD_ROOT.equals(n) && Commands.isChild(parent, n)) {
m.put(n.value(), (Provider<Command>) b.getProvider());
m.put(n.value(),
new CommandProvider((Provider<Command>) b.getProvider(), descr));
}
}
}

View File

@ -16,21 +16,17 @@ package com.google.gerrit.sshd;
import com.google.common.base.Preconditions;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.sshd.CommandName;
import com.google.gerrit.sshd.Commands;
import com.google.gerrit.sshd.DispatchCommandProvider;
import com.google.inject.AbstractModule;
import com.google.inject.binder.LinkedBindingBuilder;
import org.apache.sshd.server.Command;
import javax.inject.Inject;
public abstract class PluginCommandModule extends AbstractModule {
public abstract class PluginCommandModule extends CommandModule {
private CommandName command;
@Inject
void setPluginName(@PluginName String name) {
void setPluginName(@PluginName String name, final String descr) {
this.command = Commands.named(name);
}
@ -46,4 +42,13 @@ public abstract class PluginCommandModule extends AbstractModule {
protected LinkedBindingBuilder<Command> command(String subCmd) {
return bind(Commands.key(command, subCmd));
}
protected void command(Class<? extends BaseCommand> clazz) {
command(command, clazz);
}
protected void alias(final String name, Class<? extends BaseCommand> clazz) {
alias(command, name, clazz);
}
}

View File

@ -17,6 +17,7 @@ package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.sshd.AdminHighPriorityCommand;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
@ -25,6 +26,7 @@ import org.kohsuke.args4j.Option;
/** Opens a query processor. */
@AdminHighPriorityCommand
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@CommandMetaData(name = "gsql", descr = "Administrative interface to active database")
final class AdminQueryShell extends SshCommand {
@Inject
private QueryShell.Factory factory;

View File

@ -23,6 +23,7 @@ import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
@ -40,6 +41,7 @@ import java.util.List;
import java.util.Set;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@CommandMetaData(name = "set-project-parent", descr = "Change the project permissions are inherited from")
final class AdminSetParent extends SshCommand {
private static final Logger log = LoggerFactory.getLogger(AdminSetParent.class);

View File

@ -19,6 +19,7 @@ import com.google.gerrit.server.git.BanCommit;
import com.google.gerrit.server.git.BanCommitResult;
import com.google.gerrit.server.git.MergeException;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
@ -32,6 +33,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@CommandMetaData(name = "ban-commit", descr = "Ban a commit from a project's repository")
public class BanCommitCommand extends SshCommand {
@Option(name = "--reason", aliases = {"-r"}, metaVar = "REASON", usage = "reason for banning the commit")
private String reason;

View File

@ -28,6 +28,7 @@ import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountByEmailCache;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.ssh.SshKeyCache;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gwtorm.server.OrmDuplicateKeyException;
import com.google.gwtorm.server.OrmException;
@ -47,6 +48,7 @@ import java.util.List;
/** Create a new user account. **/
@RequiresCapability(GlobalCapability.CREATE_ACCOUNT)
@CommandMetaData(name = "create-account", descr = "Create a new batch/role account")
final class CreateAccountCommand extends SshCommand {
@Option(name = "--group", aliases = {"-g"}, metaVar = "GROUP", usage = "groups to add account to")
private List<AccountGroup.Id> groups = new ArrayList<AccountGroup.Id>();

View File

@ -21,6 +21,7 @@ import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.account.PerformCreateGroup;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@ -37,6 +38,7 @@ import java.util.Set;
* Optionally, puts an initial set of user in the newly created group.
*/
@RequiresCapability(GlobalCapability.CREATE_GROUP)
@CommandMetaData(name = "create-group", descr = "Create a new account group")
final class CreateGroupCommand extends SshCommand {
@Option(name = "--owner", aliases = {"-o"}, metaVar = "GROUP", usage = "owning group, if not specified the group will be self-owning")
private AccountGroup.Id ownerGroupId;

View File

@ -25,6 +25,7 @@ import com.google.gerrit.server.project.CreateProject;
import com.google.gerrit.server.project.CreateProjectArgs;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.SuggestParentCandidates;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
@ -35,6 +36,7 @@ import java.util.List;
/** Create a new project. **/
@RequiresCapability(GlobalCapability.CREATE_PROJECT)
@CommandMetaData(name = "create-project", descr = "Create a new project and associated Git repository")
final class CreateProjectCommand extends SshCommand {
@Option(name = "--name", aliases = {"-n"}, metaVar = "NAME", usage = "name of project to be created (deprecated option)")
void setProjectNameFromOption(String name) {

View File

@ -36,26 +36,27 @@ public class DefaultCommandModule extends CommandModule {
// SlaveCommandModule.
command(gerrit).toProvider(new DispatchCommandProvider(gerrit));
command(gerrit, "ban-commit").to(BanCommitCommand.class);
command(gerrit, "flush-caches").to(FlushCaches.class);
command(gerrit, "ls-projects").to(ListProjectsCommand.class);
command(gerrit, "ls-groups").to(ListGroupsCommand.class);
command(gerrit, "ls-user-refs").to(LsUserRefs.class);
command(gerrit, "query").to(Query.class);
command(gerrit, "show-caches").to(ShowCaches.class);
command(gerrit, "show-connections").to(ShowConnections.class);
command(gerrit, "show-queue").to(ShowQueue.class);
command(gerrit, "stream-events").to(StreamEvents.class);
command(gerrit, "version").to(VersionCommand.class);
command(gerrit, BanCommitCommand.class);
command(gerrit, FlushCaches.class);
command(gerrit, ListProjectsCommand.class);
command(gerrit, ListGroupsCommand.class);
command(gerrit, LsUserRefs.class);
command(gerrit, Query.class);
command(gerrit, ShowCaches.class);
command(gerrit, ShowConnections.class);
command(gerrit, ShowQueue.class);
command(gerrit, StreamEvents.class);
command(gerrit, VersionCommand.class);
command(gerrit, "plugin").toProvider(new DispatchCommandProvider(plugin));
command(plugin, "ls").to(PluginLsCommand.class);
command(plugin, "enable").to(PluginEnableCommand.class);
command(plugin, "install").to(PluginInstallCommand.class);
command(plugin, "reload").to(PluginReloadCommand.class);
command(plugin, "remove").to(PluginRemoveCommand.class);
command(plugin, "add").to(Commands.key(plugin, "install"));
command(plugin, "rm").to(Commands.key(plugin, "remove"));
command(plugin, PluginLsCommand.class);
command(plugin, PluginEnableCommand.class);
command(plugin, PluginInstallCommand.class);
command(plugin, PluginReloadCommand.class);
command(plugin, PluginRemoveCommand.class);
alias(plugin, "add", PluginInstallCommand.class);
alias(plugin, "rm", PluginRemoveCommand.class);
command(git).toProvider(new DispatchCommandProvider(git));
command(git, "receive-pack").to(Commands.key(gerrit, "receive-pack"));

View File

@ -19,6 +19,7 @@ import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.sshd.BaseCommand;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.inject.Inject;
import com.google.inject.Provider;
@ -31,6 +32,7 @@ import java.util.SortedSet;
/** Causes the caches to purge all entries and reload. */
@RequiresCapability(GlobalCapability.FLUSH_CACHES)
@CommandMetaData(name = "flush-caches", descr = "Flush some/all server caches from memory")
final class FlushCaches extends CacheCommand {
private static final String WEB_SESSIONS = "web_sessions";

View File

@ -16,10 +16,12 @@ package com.google.gerrit.sshd.commands;
import com.google.gerrit.server.group.ListGroups;
import com.google.gerrit.sshd.BaseCommand;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.inject.Inject;
import org.apache.sshd.server.Environment;
@CommandMetaData(name = "ls-groups", descr = "List groups visible to the caller")
public class ListGroupsCommand extends BaseCommand {
@Inject
private ListGroups impl;

View File

@ -16,10 +16,12 @@ package com.google.gerrit.sshd.commands;
import com.google.gerrit.server.project.ListProjects;
import com.google.gerrit.sshd.BaseCommand;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.inject.Inject;
import org.apache.sshd.server.Environment;
@CommandMetaData(name = "ls-projects", descr = "List projects visible to the caller")
final class ListProjectsCommand extends BaseCommand {
@Inject
private ListProjects impl;

View File

@ -26,6 +26,7 @@ import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.TagCache;
import com.google.gerrit.server.git.VisibleRefFilter;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@ -39,6 +40,7 @@ import java.io.IOException;
import java.util.Map;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@CommandMetaData(name = "ls-user-refs", descr = "List refs visible to a specific user")
public class LsUserRefs extends SshCommand {
@Inject
private AccountResolver accountResolver;

View File

@ -27,21 +27,23 @@ public class MasterCommandModule extends CommandModule {
final CommandName gerrit = Commands.named("gerrit");
final CommandName testSubmit = Commands.named(gerrit, "test-submit");
command(gerrit, "approve").to(ReviewCommand.class);
command(gerrit, "create-account").to(CreateAccountCommand.class);
command(gerrit, "create-group").to(CreateGroupCommand.class);
command(gerrit, "rename-group").to(RenameGroupCommand.class);
command(gerrit, "create-project").to(CreateProjectCommand.class);
command(gerrit, "gsql").to(AdminQueryShell.class);
command(gerrit, "set-reviewers").to(SetReviewersCommand.class);
command(gerrit, "receive-pack").to(Receive.class);
command(gerrit, "set-project-parent").to(AdminSetParent.class);
command(gerrit, "review").to(ReviewCommand.class);
command(gerrit, "set-account").to(SetAccountCommand.class);
command(gerrit, "set-project").to(SetProjectCommand.class);
command(gerrit, CreateAccountCommand.class);
command(gerrit, CreateGroupCommand.class);
command(gerrit, RenameGroupCommand.class);
command(gerrit, CreateProjectCommand.class);
command(gerrit, AdminQueryShell.class);
command(gerrit, TestSubmitRule.class);
command(gerrit, SetReviewersCommand.class);
command(gerrit, Receive.class);
command(gerrit, AdminSetParent.class);
command(gerrit, ReviewCommand.class);
// deprecated alias to review command
alias(gerrit, "approve", ReviewCommand.class);
command(gerrit, SetAccountCommand.class);
command(gerrit, SetProjectCommand.class);
command(gerrit, "test-submit").toProvider(new DispatchCommandProvider(testSubmit));
command(testSubmit, "rule").to(TestSubmitRule.class);
command(testSubmit, "type").to(TestSubmitType.class);
command(testSubmit, TestSubmitRule.class);
command(testSubmit, TestSubmitType.class);
}
}

View File

@ -19,6 +19,7 @@ import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.plugins.PluginInstallException;
import com.google.gerrit.server.plugins.PluginLoader;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
@ -27,6 +28,7 @@ import org.kohsuke.args4j.Argument;
import java.util.List;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@CommandMetaData(name = "enable", descr = "Enable plugins")
final class PluginEnableCommand extends SshCommand {
@Argument(index = 0, metaVar = "NAME", required = true, usage = "plugin(s) to enable")
List<String> names;

View File

@ -19,6 +19,7 @@ import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.plugins.PluginInstallException;
import com.google.gerrit.server.plugins.PluginLoader;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
@ -34,6 +35,7 @@ import java.net.MalformedURLException;
import java.net.URL;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@CommandMetaData(name = "install", descr = "Install/Add a plugin")
final class PluginInstallCommand extends SshCommand {
@Option(name = "--name", aliases = {"-n"}, usage = "install under name")
private String name;

View File

@ -18,6 +18,7 @@ import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.plugins.ListPlugins;
import com.google.gerrit.sshd.BaseCommand;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.inject.Inject;
import org.apache.sshd.server.Environment;
@ -25,6 +26,7 @@ import org.apache.sshd.server.Environment;
import java.io.IOException;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@CommandMetaData(name = "ls", descr = "List the installed plugins")
final class PluginLsCommand extends BaseCommand {
@Inject
private ListPlugins impl;

View File

@ -19,6 +19,7 @@ import com.google.gerrit.server.plugins.InvalidPluginException;
import com.google.gerrit.server.plugins.PluginInstallException;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.plugins.PluginLoader;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
@ -27,6 +28,7 @@ import org.kohsuke.args4j.Argument;
import java.util.List;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@CommandMetaData(name = "reload", descr = "Reload/Restart plugins")
final class PluginReloadCommand extends SshCommand {
@Argument(index = 0, metaVar = "NAME", usage = "plugins to reload/restart")
private List<String> names;

View File

@ -18,6 +18,7 @@ import com.google.common.collect.Sets;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.plugins.PluginLoader;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
@ -26,6 +27,7 @@ import org.kohsuke.args4j.Argument;
import java.util.List;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@CommandMetaData(name = "remove", descr = "Disable plugins")
final class PluginRemoveCommand extends SshCommand {
@Argument(index = 0, metaVar = "NAME", required = true, usage = "plugin to remove")
List<String> names;

View File

@ -15,6 +15,7 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.server.query.change.QueryProcessor;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
@ -23,6 +24,7 @@ import org.kohsuke.args4j.Option;
import java.util.List;
@CommandMetaData(name = "query", descr = "Query the change database")
class Query extends SshCommand {
@Inject
private QueryProcessor processor;

View File

@ -22,6 +22,7 @@ import com.google.gerrit.server.git.ReceiveCommits;
import com.google.gerrit.server.git.TransferConfig;
import com.google.gerrit.server.git.VisibleRefFilter;
import com.google.gerrit.sshd.AbstractGitCommand;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.inject.Inject;
import org.eclipse.jgit.errors.TooLargeObjectInPackException;
@ -41,6 +42,7 @@ import java.util.Map;
import java.util.Set;
/** Receives change upload over SSH using the Git receive-pack protocol. */
@CommandMetaData(name = "receive-pack", descr = "Standard Git server side command for client side git push")
final class Receive extends AbstractGitCommand {
private static final Logger log = LoggerFactory.getLogger(Receive.class);

View File

@ -18,12 +18,14 @@ import com.google.gerrit.common.errors.InvalidNameException;
import com.google.gerrit.common.errors.NameAlreadyUsedException;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.server.account.PerformRenameGroup;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import org.kohsuke.args4j.Argument;
@CommandMetaData(name = "rename-group", descr = "Rename an account group")
public class RenameGroupCommand extends SshCommand {
@Argument(index = 0, required = true, metaVar = "GROUP", usage = "name of the group to be renamed")
private String groupName;

View File

@ -41,6 +41,7 @@ import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gerrit.util.cli.CmdLineParser;
import com.google.gwtorm.server.OrmException;
@ -60,6 +61,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
@CommandMetaData(name = "review", descr = "Verify, approve and/or submit one or more patch sets")
public class ReviewCommand extends SshCommand {
private static final Logger log =
LoggerFactory.getLogger(ReviewCommand.class);

View File

@ -29,6 +29,7 @@ import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.ssh.SshKeyCache;
import com.google.gerrit.sshd.BaseCommand;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.ResultSet;
import com.google.inject.Inject;
@ -46,6 +47,7 @@ import java.util.Collections;
import java.util.List;
/** Set a user's account settings. **/
@CommandMetaData(name = "set-account", descr = "Change an account's settings")
final class SetAccountCommand extends BaseCommand {
@Argument(index = 0, required = true, metaVar = "USER", usage = "full name, email-address, ssh username or account id")

View File

@ -24,6 +24,7 @@ import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
@ -37,6 +38,7 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@CommandMetaData(name = "set-project", descr = "Change a project's settings")
final class SetProjectCommand extends SshCommand {
private static final Logger log = LoggerFactory
.getLogger(SetProjectCommand.class);

View File

@ -25,6 +25,7 @@ import com.google.gerrit.server.patch.RemoveReviewer;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.ResultSet;
@ -42,6 +43,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
@CommandMetaData(name = "set-reviewers", descr = "Add or remove reviewers on a change")
public class SetReviewersCommand extends SshCommand {
private static final Logger log =
LoggerFactory.getLogger(SetReviewersCommand.class);

View File

@ -25,6 +25,7 @@ import com.google.gerrit.server.cache.h2.H2CacheImpl;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.WorkQueue.Task;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshDaemon;
import com.google.inject.Inject;
import com.google.inject.Provider;
@ -50,6 +51,7 @@ import java.util.SortedMap;
/** Show the current cache states. */
@RequiresCapability(GlobalCapability.VIEW_CACHES)
@CommandMetaData(name = "show-caches", descr = "Display current cache statistics")
final class ShowCaches extends CacheCommand {
private static volatile long serverStarted;

View File

@ -19,6 +19,7 @@ import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.util.IdGenerator;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.gerrit.sshd.SshDaemon;
import com.google.gerrit.sshd.SshSession;
@ -41,6 +42,7 @@ import java.util.List;
/** Show the current SSH connections. */
@RequiresCapability(GlobalCapability.VIEW_CONNECTIONS)
@CommandMetaData(name = "show-connections", descr = "Display active client SSH connections")
final class ShowConnections extends SshCommand {
@Option(name = "--numeric", aliases = {"-n"}, usage = "don't resolve names")
private boolean numeric;

View File

@ -23,6 +23,7 @@ import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.util.IdGenerator;
import com.google.gerrit.sshd.AdminHighPriorityCommand;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
@ -39,6 +40,7 @@ import java.util.concurrent.TimeUnit;
/** Display the current work queue. */
@AdminHighPriorityCommand
@CommandMetaData(name = "show-queue", descr = "Display the background work queues, including replication")
final class ShowQueue extends SshCommand {
@Option(name = "-w", usage = "display without line width truncation")
private boolean wide;

View File

@ -21,6 +21,7 @@ import com.google.gerrit.server.events.ChangeEvent;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.WorkQueue.CancelableRunnable;
import com.google.gerrit.sshd.BaseCommand;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.StreamCommandExecutor;
import com.google.gson.Gson;
import com.google.inject.Inject;
@ -32,6 +33,7 @@ import java.io.PrintWriter;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
@CommandMetaData(name = "stream-events", descr = "Monitor events occurring in real time")
final class StreamEvents extends BaseCommand {
/** Maximum number of events that may be queued up for each connection. */
private static final int MAX_EVENTS = 128;

View File

@ -24,6 +24,7 @@ import com.google.gerrit.server.events.SubmitLabelAttribute;
import com.google.gerrit.server.events.SubmitRecordAttribute;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.SubmitRuleEvaluator;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gson.reflect.TypeToken;
import com.googlecode.prolog_cafe.lang.ListTerm;
@ -33,6 +34,7 @@ import java.util.LinkedList;
import java.util.List;
/** Command that allows testing of prolog submit-rules in a live instance. */
@CommandMetaData(name = "rule", descr = "Test prolog submit rules")
final class TestSubmitRule extends BaseTestSubmit {
protected SubmitRuleEvaluator createEvaluator(PatchSet ps) throws Exception {

View File

@ -19,12 +19,14 @@ import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.SubmitRuleEvaluator;
import com.google.gerrit.sshd.CommandMetaData;
import com.googlecode.prolog_cafe.lang.ListTerm;
import com.googlecode.prolog_cafe.lang.Term;
import java.util.List;
@CommandMetaData(name = "type", descr = "Test prolog submit type")
final class TestSubmitType extends BaseTestSubmit {
@Override

View File

@ -15,9 +15,12 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.Version;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
@CommandMetaData(name = "version", descr = "Display gerrit version")
final class VersionCommand extends SshCommand {
@Override
protected void run() throws Failure {
String v = Version.getVersion();