Merge changes Ic8052b4d,I41829d35,Ia2d112eb,Ieb95a0ed,I38b15303
* changes: Refactor ls-projects code to gerrit-server Support parsing command line options from a map Allow command line parsing to happen on a different object Refactor display of --help/-h to be common Move parsing of --help/-h to CmdLineParser
This commit is contained in:
@@ -34,9 +34,6 @@ public abstract class AbstractProgram {
|
|||||||
@Option(name = "--show-stack-trace", usage = "display stack trace on failure")
|
@Option(name = "--show-stack-trace", usage = "display stack trace on failure")
|
||||||
protected boolean showStackTrace;
|
protected boolean showStackTrace;
|
||||||
|
|
||||||
@Option(name = "--help", usage = "display this help text", aliases = {"-h"})
|
|
||||||
private boolean help;
|
|
||||||
|
|
||||||
private String getName() {
|
private String getName() {
|
||||||
String n = getClass().getName();
|
String n = getClass().getName();
|
||||||
int dot = n.lastIndexOf('.');
|
int dot = n.lastIndexOf('.');
|
||||||
@@ -52,21 +49,15 @@ public abstract class AbstractProgram {
|
|||||||
try {
|
try {
|
||||||
clp.parseArgument(argv);
|
clp.parseArgument(argv);
|
||||||
} catch (CmdLineException err) {
|
} catch (CmdLineException err) {
|
||||||
if (!help) {
|
if (!clp.wasHelpRequestedByOption()) {
|
||||||
System.err.println("fatal: " + err.getMessage());
|
System.err.println("fatal: " + err.getMessage());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (help) {
|
if (clp.wasHelpRequestedByOption()) {
|
||||||
final StringWriter msg = new StringWriter();
|
StringWriter msg = new StringWriter();
|
||||||
msg.write(getName());
|
clp.printDetailedUsage(getName(), msg);
|
||||||
clp.printSingleLineUsage(msg, null);
|
|
||||||
msg.write('\n');
|
|
||||||
|
|
||||||
msg.write('\n');
|
|
||||||
clp.printUsage(msg, null);
|
|
||||||
msg.write('\n');
|
|
||||||
System.err.println(msg.toString());
|
System.err.println(msg.toString());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,12 @@ limitations under the License.
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.gerrit</groupId>
|
||||||
|
<artifactId>gerrit-util-cli</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.gerrit</groupId>
|
<groupId>com.google.gerrit</groupId>
|
||||||
<artifactId>gerrit-util-ssl</artifactId>
|
<artifactId>gerrit-util-ssl</artifactId>
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ import com.google.gerrit.server.project.ChangeControl;
|
|||||||
import com.google.gerrit.server.project.PermissionCollection;
|
import com.google.gerrit.server.project.PermissionCollection;
|
||||||
import com.google.gerrit.server.project.ProjectCacheImpl;
|
import com.google.gerrit.server.project.ProjectCacheImpl;
|
||||||
import com.google.gerrit.server.project.ProjectControl;
|
import com.google.gerrit.server.project.ProjectControl;
|
||||||
|
import com.google.gerrit.server.project.ProjectNode;
|
||||||
import com.google.gerrit.server.project.ProjectState;
|
import com.google.gerrit.server.project.ProjectState;
|
||||||
import com.google.gerrit.server.project.SectionSortCache;
|
import com.google.gerrit.server.project.SectionSortCache;
|
||||||
import com.google.gerrit.server.tools.ToolsCatalog;
|
import com.google.gerrit.server.tools.ToolsCatalog;
|
||||||
@@ -118,6 +119,7 @@ public class GerritGlobalModule extends FactoryModule {
|
|||||||
factory(AccountInfoCacheFactory.Factory.class);
|
factory(AccountInfoCacheFactory.Factory.class);
|
||||||
factory(CapabilityControl.Factory.class);
|
factory(CapabilityControl.Factory.class);
|
||||||
factory(GroupInfoCacheFactory.Factory.class);
|
factory(GroupInfoCacheFactory.Factory.class);
|
||||||
|
factory(ProjectNode.Factory.class);
|
||||||
factory(ProjectState.Factory.class);
|
factory(ProjectState.Factory.class);
|
||||||
factory(MaterializedGroupMembership.Factory.class);
|
factory(MaterializedGroupMembership.Factory.class);
|
||||||
bind(PermissionCollection.Factory.class);
|
bind(PermissionCollection.Factory.class);
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import com.google.gerrit.server.patch.PublishComments;
|
|||||||
import com.google.gerrit.server.patch.RemoveReviewer;
|
import com.google.gerrit.server.patch.RemoveReviewer;
|
||||||
import com.google.gerrit.server.project.ChangeControl;
|
import com.google.gerrit.server.project.ChangeControl;
|
||||||
import com.google.gerrit.server.project.CreateProject;
|
import com.google.gerrit.server.project.CreateProject;
|
||||||
|
import com.google.gerrit.server.project.ListProjects;
|
||||||
import com.google.gerrit.server.project.PerRequestProjectControlCache;
|
import com.google.gerrit.server.project.PerRequestProjectControlCache;
|
||||||
import com.google.gerrit.server.project.ProjectControl;
|
import com.google.gerrit.server.project.ProjectControl;
|
||||||
import com.google.gerrit.server.project.SuggestParentCandidates;
|
import com.google.gerrit.server.project.SuggestParentCandidates;
|
||||||
@@ -71,6 +72,7 @@ public class GerritRequestModule extends FactoryModule {
|
|||||||
bind(MetaDataUpdate.User.class).in(RequestScoped.class);
|
bind(MetaDataUpdate.User.class).in(RequestScoped.class);
|
||||||
bind(AccountResolver.class);
|
bind(AccountResolver.class);
|
||||||
bind(ChangeQueryRewriter.class);
|
bind(ChangeQueryRewriter.class);
|
||||||
|
bind(ListProjects.class);
|
||||||
|
|
||||||
bind(AnonymousUser.class).in(RequestScoped.class);
|
bind(AnonymousUser.class).in(RequestScoped.class);
|
||||||
bind(PerRequestProjectControlCache.class).in(RequestScoped.class);
|
bind(PerRequestProjectControlCache.class).in(RequestScoped.class);
|
||||||
|
|||||||
@@ -12,18 +12,14 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package com.google.gerrit.sshd.commands;
|
package com.google.gerrit.server.project;
|
||||||
|
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
import com.google.gerrit.server.project.ProjectCache;
|
import com.google.gerrit.server.util.TreeFormatter;
|
||||||
import com.google.gerrit.server.project.ProjectControl;
|
|
||||||
import com.google.gerrit.server.project.ProjectState;
|
|
||||||
import com.google.gerrit.sshd.BaseCommand;
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
import org.apache.sshd.server.Environment;
|
|
||||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
import org.eclipse.jgit.lib.Ref;
|
||||||
@@ -32,18 +28,23 @@ import org.kohsuke.args4j.Option;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
final class ListProjects extends BaseCommand {
|
/** List projects visible to the calling user. */
|
||||||
|
public class ListProjects {
|
||||||
private static final Logger log = LoggerFactory.getLogger(ListProjects.class);
|
private static final Logger log = LoggerFactory.getLogger(ListProjects.class);
|
||||||
|
|
||||||
static enum FilterType {
|
public static enum FilterType {
|
||||||
CODE {
|
CODE {
|
||||||
@Override
|
@Override
|
||||||
boolean matches(Repository git) throws IOException {
|
boolean matches(Repository git) throws IOException {
|
||||||
@@ -69,24 +70,18 @@ final class ListProjects extends BaseCommand {
|
|||||||
abstract boolean matches(Repository git) throws IOException;
|
abstract boolean matches(Repository git) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
private final CurrentUser currentUser;
|
||||||
private IdentifiedUser currentUser;
|
private final ProjectCache projectCache;
|
||||||
|
private final GitRepositoryManager repoManager;
|
||||||
@Inject
|
private final ProjectNode.Factory projectNodeFactory;
|
||||||
private ProjectCache projectCache;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private GitRepositoryManager repoManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private ProjectNode.Factory projectNodeFactory;
|
|
||||||
|
|
||||||
@Option(name = "--show-branch", aliases = {"-b"}, multiValued = true,
|
@Option(name = "--show-branch", aliases = {"-b"}, multiValued = true,
|
||||||
usage = "displays the sha of each project in the specified branch")
|
usage = "displays the sha of each project in the specified branch")
|
||||||
private List<String> showBranch;
|
private List<String> showBranch;
|
||||||
|
|
||||||
@Option(name = "--tree", aliases = {"-t"}, usage = "displays project inheritance in a tree-like format\n" +
|
@Option(name = "--tree", aliases = {"-t"}, usage =
|
||||||
"this option does not work together with the show-branch option")
|
"displays project inheritance in a tree-like format\n"
|
||||||
|
+ "this option does not work together with the show-branch option")
|
||||||
private boolean showTree;
|
private boolean showTree;
|
||||||
|
|
||||||
@Option(name = "--type", usage = "type of project")
|
@Option(name = "--type", usage = "type of project")
|
||||||
@@ -98,27 +93,37 @@ final class ListProjects extends BaseCommand {
|
|||||||
@Option(name = "--all", usage = "display all projects that are accessible by the calling user")
|
@Option(name = "--all", usage = "display all projects that are accessible by the calling user")
|
||||||
private boolean all;
|
private boolean all;
|
||||||
|
|
||||||
@Override
|
@Inject
|
||||||
public void start(final Environment env) {
|
protected ListProjects(CurrentUser currentUser, ProjectCache projectCache,
|
||||||
startThread(new CommandRunnable() {
|
GitRepositoryManager repoManager,
|
||||||
@Override
|
ProjectNode.Factory projectNodeFactory) {
|
||||||
public void run() throws Exception {
|
this.currentUser = currentUser;
|
||||||
parseCommandLine();
|
this.projectCache = projectCache;
|
||||||
ListProjects.this.display();
|
this.repoManager = repoManager;
|
||||||
}
|
this.projectNodeFactory = projectNodeFactory;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void display() throws Failure {
|
public List<String> getShowBranch() {
|
||||||
if (showTree && (showBranch != null)) {
|
return showBranch;
|
||||||
throw new UnloggedFailure(1, "fatal: --tree and --show-branch options are not compatible.");
|
}
|
||||||
|
|
||||||
|
public boolean isShowTree() {
|
||||||
|
return showTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShowDescription() {
|
||||||
|
return showDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(OutputStream out) {
|
||||||
|
final PrintWriter stdout;
|
||||||
|
try {
|
||||||
|
stdout = new PrintWriter(new BufferedWriter(new OutputStreamWriter(out, "UTF-8")));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
// Our encoding is required by the specifications for the runtime.
|
||||||
|
throw new RuntimeException("JVM lacks UTF-8 encoding", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showTree && showDescription) {
|
|
||||||
throw new UnloggedFailure(1, "fatal: --tree and --description options are not compatible.");
|
|
||||||
}
|
|
||||||
|
|
||||||
final PrintWriter stdout = toPrintWriter(out);
|
|
||||||
final TreeMap<Project.NameKey, ProjectNode> treeMap =
|
final TreeMap<Project.NameKey, ProjectNode> treeMap =
|
||||||
new TreeMap<Project.NameKey, ProjectNode>();
|
new TreeMap<Project.NameKey, ProjectNode>();
|
||||||
try {
|
try {
|
||||||
@@ -12,32 +12,31 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package com.google.gerrit.sshd.commands;
|
package com.google.gerrit.server.project;
|
||||||
|
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
import com.google.gerrit.server.config.AllProjectsName;
|
import com.google.gerrit.server.config.AllProjectsName;
|
||||||
import com.google.gerrit.sshd.commands.TreeFormatter.TreeNode;
|
import com.google.gerrit.server.util.TreeFormatter.TreeNode;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.assistedinject.Assisted;
|
import com.google.inject.assistedinject.Assisted;
|
||||||
|
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
/** Node of a Project in a tree formatted by {@link ListProjects}. */
|
||||||
public class ProjectNode implements TreeNode, Comparable<ProjectNode> {
|
public class ProjectNode implements TreeNode, Comparable<ProjectNode> {
|
||||||
|
|
||||||
public interface Factory {
|
public interface Factory {
|
||||||
ProjectNode create(final Project project, final boolean isVisible);
|
ProjectNode create(final Project project, final boolean isVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final AllProjectsName allProjectsName;
|
private final AllProjectsName allProjectsName;
|
||||||
|
|
||||||
private final Project project;
|
private final Project project;
|
||||||
private final boolean isVisible;
|
private final boolean isVisible;
|
||||||
|
|
||||||
private final SortedSet<ProjectNode> children = new TreeSet<ProjectNode>();
|
private final SortedSet<ProjectNode> children = new TreeSet<ProjectNode>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ProjectNode(final AllProjectsName allProjectsName,
|
protected ProjectNode(final AllProjectsName allProjectsName,
|
||||||
@Assisted final Project project, @Assisted final boolean isVisible) {
|
@Assisted final Project project, @Assisted final boolean isVisible) {
|
||||||
this.allProjectsName = allProjectsName;
|
this.allProjectsName = allProjectsName;
|
||||||
this.project = project;
|
this.project = project;
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package com.google.gerrit.sshd.commands;
|
package com.google.gerrit.server.util;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
@@ -60,9 +60,6 @@ public abstract class BaseCommand implements Command {
|
|||||||
static final int STATUS_NOT_FOUND = PRIVATE_STATUS | 2;
|
static final int STATUS_NOT_FOUND = PRIVATE_STATUS | 2;
|
||||||
public static final int STATUS_NOT_ADMIN = PRIVATE_STATUS | 3;
|
public static final int STATUS_NOT_ADMIN = PRIVATE_STATUS | 3;
|
||||||
|
|
||||||
@Option(name = "--help", usage = "display this help text", aliases = {"-h"})
|
|
||||||
private boolean help;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Option(name = "--", usage = "end of options", handler = EndOfOptionsHandler.class)
|
@Option(name = "--", usage = "end of options", handler = EndOfOptionsHandler.class)
|
||||||
private boolean endOfOptions;
|
private boolean endOfOptions;
|
||||||
@@ -155,28 +152,37 @@ public abstract class BaseCommand implements Command {
|
|||||||
* @see Argument
|
* @see Argument
|
||||||
*/
|
*/
|
||||||
protected void parseCommandLine() throws UnloggedFailure {
|
protected void parseCommandLine() throws UnloggedFailure {
|
||||||
final CmdLineParser clp = newCmdLineParser();
|
parseCommandLine(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the command line argument, injecting parsed values into fields.
|
||||||
|
* <p>
|
||||||
|
* This method must be explicitly invoked to cause a parse.
|
||||||
|
*
|
||||||
|
* @param options object whose fields declare Option and Argument annotations
|
||||||
|
* to describe the parameters of the command. Usually {@code this}.
|
||||||
|
* @throws UnloggedFailure if the command line arguments were invalid.
|
||||||
|
* @see Option
|
||||||
|
* @see Argument
|
||||||
|
*/
|
||||||
|
protected void parseCommandLine(Object options) throws UnloggedFailure {
|
||||||
|
final CmdLineParser clp = newCmdLineParser(options);
|
||||||
try {
|
try {
|
||||||
clp.parseArgument(argv);
|
clp.parseArgument(argv);
|
||||||
} catch (IllegalArgumentException err) {
|
} catch (IllegalArgumentException err) {
|
||||||
if (!help) {
|
if (!clp.wasHelpRequestedByOption()) {
|
||||||
throw new UnloggedFailure(1, "fatal: " + err.getMessage());
|
throw new UnloggedFailure(1, "fatal: " + err.getMessage());
|
||||||
}
|
}
|
||||||
} catch (CmdLineException err) {
|
} catch (CmdLineException err) {
|
||||||
if (!help) {
|
if (!clp.wasHelpRequestedByOption()) {
|
||||||
throw new UnloggedFailure(1, "fatal: " + err.getMessage());
|
throw new UnloggedFailure(1, "fatal: " + err.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (help) {
|
if (clp.wasHelpRequestedByOption()) {
|
||||||
final StringWriter msg = new StringWriter();
|
StringWriter msg = new StringWriter();
|
||||||
msg.write(commandName);
|
clp.printDetailedUsage(commandName, msg);
|
||||||
clp.printSingleLineUsage(msg, null);
|
|
||||||
msg.write('\n');
|
|
||||||
|
|
||||||
msg.write('\n');
|
|
||||||
clp.printUsage(msg, null);
|
|
||||||
msg.write('\n');
|
|
||||||
msg.write(usage());
|
msg.write(usage());
|
||||||
throw new UnloggedFailure(1, msg.toString());
|
throw new UnloggedFailure(1, msg.toString());
|
||||||
}
|
}
|
||||||
@@ -187,8 +193,8 @@ public abstract class BaseCommand implements Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Construct a new parser for this command's received command line. */
|
/** Construct a new parser for this command's received command line. */
|
||||||
protected CmdLineParser newCmdLineParser() {
|
protected CmdLineParser newCmdLineParser(Object options) {
|
||||||
return cmdLineParserFactory.create(this);
|
return cmdLineParserFactory.create(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ import com.google.gerrit.sshd.args4j.PatchSetIdHandler;
|
|||||||
import com.google.gerrit.sshd.args4j.ProjectControlHandler;
|
import com.google.gerrit.sshd.args4j.ProjectControlHandler;
|
||||||
import com.google.gerrit.sshd.args4j.SocketAddressHandler;
|
import com.google.gerrit.sshd.args4j.SocketAddressHandler;
|
||||||
import com.google.gerrit.sshd.commands.DefaultCommandModule;
|
import com.google.gerrit.sshd.commands.DefaultCommandModule;
|
||||||
import com.google.gerrit.sshd.commands.ProjectNode;
|
|
||||||
import com.google.gerrit.sshd.commands.QueryShell;
|
import com.google.gerrit.sshd.commands.QueryShell;
|
||||||
import com.google.gerrit.util.cli.CmdLineParser;
|
import com.google.gerrit.util.cli.CmdLineParser;
|
||||||
import com.google.gerrit.util.cli.OptionHandlerUtil;
|
import com.google.gerrit.util.cli.OptionHandlerUtil;
|
||||||
@@ -79,7 +78,6 @@ public class SshModule extends FactoryModule {
|
|||||||
bind(QueueProvider.class).to(CommandExecutorQueueProvider.class).in(SINGLETON);
|
bind(QueueProvider.class).to(CommandExecutorQueueProvider.class).in(SINGLETON);
|
||||||
bind(AccountManager.class);
|
bind(AccountManager.class);
|
||||||
factory(ChangeUserName.Factory.class);
|
factory(ChangeUserName.Factory.class);
|
||||||
factory(ProjectNode.Factory.class);
|
|
||||||
|
|
||||||
bind(PublickeyAuthenticator.class).to(DatabasePubKeyAuth.class);
|
bind(PublickeyAuthenticator.class).to(DatabasePubKeyAuth.class);
|
||||||
bind(KeyPairProvider.class).toProvider(HostKeyProvider.class).in(SINGLETON);
|
bind(KeyPairProvider.class).toProvider(HostKeyProvider.class).in(SINGLETON);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class DefaultCommandModule extends CommandModule {
|
|||||||
|
|
||||||
command(gerrit).toProvider(new DispatchCommandProvider(gerrit));
|
command(gerrit).toProvider(new DispatchCommandProvider(gerrit));
|
||||||
command(gerrit, "flush-caches").to(FlushCaches.class);
|
command(gerrit, "flush-caches").to(FlushCaches.class);
|
||||||
command(gerrit, "ls-projects").to(ListProjects.class);
|
command(gerrit, "ls-projects").to(ListProjectsCommand.class);
|
||||||
command(gerrit, "ls-groups").to(ListGroupsCommand.class);
|
command(gerrit, "ls-groups").to(ListGroupsCommand.class);
|
||||||
command(gerrit, "query").to(Query.class);
|
command(gerrit, "query").to(Query.class);
|
||||||
command(gerrit, "show-caches").to(ShowCaches.class);
|
command(gerrit, "show-caches").to(ShowCaches.class);
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (C) 2009 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.commands;
|
||||||
|
|
||||||
|
import com.google.gerrit.server.project.ListProjects;
|
||||||
|
import com.google.gerrit.sshd.BaseCommand;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
import org.apache.sshd.server.Environment;
|
||||||
|
|
||||||
|
final class ListProjectsCommand extends BaseCommand {
|
||||||
|
@Inject
|
||||||
|
private ListProjects impl;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(final Environment env) {
|
||||||
|
startThread(new CommandRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() throws Exception {
|
||||||
|
parseCommandLine(impl);
|
||||||
|
if (impl.isShowTree() && (impl.getShowBranch() != null)) {
|
||||||
|
throw new UnloggedFailure(1, "fatal: --tree and --show-branch options are not compatible.");
|
||||||
|
}
|
||||||
|
if (impl.isShowTree() && impl.isShowDescription()) {
|
||||||
|
throw new UnloggedFailure(1, "fatal: --tree and --description options are not compatible.");
|
||||||
|
}
|
||||||
|
impl.display(out);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,8 +57,8 @@ public class ReviewCommand extends BaseCommand {
|
|||||||
LoggerFactory.getLogger(ReviewCommand.class);
|
LoggerFactory.getLogger(ReviewCommand.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final CmdLineParser newCmdLineParser() {
|
protected final CmdLineParser newCmdLineParser(Object options) {
|
||||||
final CmdLineParser parser = super.newCmdLineParser();
|
final CmdLineParser parser = super.newCmdLineParser(options);
|
||||||
for (ApproveOption c : optionList) {
|
for (ApproveOption c : optionList) {
|
||||||
parser.addOption(c, c);
|
parser.addOption(c, c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,13 +42,19 @@ import com.google.inject.assistedinject.Assisted;
|
|||||||
import org.kohsuke.args4j.Argument;
|
import org.kohsuke.args4j.Argument;
|
||||||
import org.kohsuke.args4j.CmdLineException;
|
import org.kohsuke.args4j.CmdLineException;
|
||||||
import org.kohsuke.args4j.IllegalAnnotationError;
|
import org.kohsuke.args4j.IllegalAnnotationError;
|
||||||
|
import org.kohsuke.args4j.NamedOptionDef;
|
||||||
import org.kohsuke.args4j.Option;
|
import org.kohsuke.args4j.Option;
|
||||||
import org.kohsuke.args4j.OptionDef;
|
import org.kohsuke.args4j.OptionDef;
|
||||||
|
import org.kohsuke.args4j.spi.BooleanOptionHandler;
|
||||||
import org.kohsuke.args4j.spi.OptionHandler;
|
import org.kohsuke.args4j.spi.OptionHandler;
|
||||||
import org.kohsuke.args4j.spi.Setter;
|
import org.kohsuke.args4j.spi.Setter;
|
||||||
|
|
||||||
|
import java.io.StringWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,6 +66,7 @@ import java.util.ResourceBundle;
|
|||||||
* args4j style format prior to invoking args4j for parsing.
|
* args4j style format prior to invoking args4j for parsing.
|
||||||
*/
|
*/
|
||||||
public class CmdLineParser {
|
public class CmdLineParser {
|
||||||
|
|
||||||
public interface Factory {
|
public interface Factory {
|
||||||
CmdLineParser create(Object bean);
|
CmdLineParser create(Object bean);
|
||||||
}
|
}
|
||||||
@@ -102,6 +109,19 @@ public class CmdLineParser {
|
|||||||
parser.printUsage(out, rb);
|
parser.printUsage(out, rb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void printDetailedUsage(String name, StringWriter out) {
|
||||||
|
out.write(name);
|
||||||
|
printSingleLineUsage(out, null);
|
||||||
|
out.write('\n');
|
||||||
|
out.write('\n');
|
||||||
|
printUsage(out, null);
|
||||||
|
out.write('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean wasHelpRequestedByOption() {
|
||||||
|
return parser.help.value;
|
||||||
|
}
|
||||||
|
|
||||||
public void parseArgument(final String... args) throws CmdLineException {
|
public void parseArgument(final String... args) throws CmdLineException {
|
||||||
final ArrayList<String> tmp = new ArrayList<String>(args.length);
|
final ArrayList<String> tmp = new ArrayList<String>(args.length);
|
||||||
for (int argi = 0; argi < args.length; argi++) {
|
for (int argi = 0; argi < args.length; argi++) {
|
||||||
@@ -123,13 +143,86 @@ public class CmdLineParser {
|
|||||||
|
|
||||||
tmp.add(str);
|
tmp.add(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.parseArgument(tmp.toArray(new String[tmp.size()]));
|
parser.parseArgument(tmp.toArray(new String[tmp.size()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void parseOptionMap(Map<String, String[]> parameters)
|
||||||
|
throws CmdLineException {
|
||||||
|
ArrayList<String> tmp = new ArrayList<String>();
|
||||||
|
for (Map.Entry<String, String[]> ent : parameters.entrySet()) {
|
||||||
|
String name = ent.getKey();
|
||||||
|
if (!name.startsWith("-")) {
|
||||||
|
if (name.length() == 1) {
|
||||||
|
name = "-" + name;
|
||||||
|
} else {
|
||||||
|
name = "--" + name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (findHandler(name) instanceof BooleanOptionHandler) {
|
||||||
|
boolean on = false;
|
||||||
|
for (String value : ent.getValue()) {
|
||||||
|
on = toBoolean(ent.getKey(), value);
|
||||||
|
}
|
||||||
|
if (on) {
|
||||||
|
tmp.add(name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (String value : ent.getValue()) {
|
||||||
|
tmp.add(name);
|
||||||
|
tmp.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parser.parseArgument(tmp.toArray(new String[tmp.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private OptionHandler findHandler(String name) {
|
||||||
|
for (OptionHandler handler : parser.options) {
|
||||||
|
if (handler.option instanceof NamedOptionDef) {
|
||||||
|
NamedOptionDef def = (NamedOptionDef) handler.option;
|
||||||
|
if (name.equals(def.name())) {
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
for (String alias : def.aliases()) {
|
||||||
|
if (name.equals(alias)) {
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean toBoolean(String name, String value) throws CmdLineException {
|
||||||
|
if ("true".equals(value) || "t".equals(value)
|
||||||
|
|| "yes".equals(value) || "y".equals(value)
|
||||||
|
|| "on".equals(value)
|
||||||
|
|| "1".equals(value)
|
||||||
|
|| value == null || "".equals(value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("false".equals(value) || "f".equals(value)
|
||||||
|
|| "no".equals(value) || "n".equals(value)
|
||||||
|
|| "off".equals(value)
|
||||||
|
|| "0".equals(value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new CmdLineException(parser, String.format(
|
||||||
|
"invalid boolean \"%s=%s\"", name, value));
|
||||||
|
}
|
||||||
|
|
||||||
private class MyParser extends org.kohsuke.args4j.CmdLineParser {
|
private class MyParser extends org.kohsuke.args4j.CmdLineParser {
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private List<OptionHandler> options;
|
||||||
|
private HelpOption help;
|
||||||
|
|
||||||
MyParser(final Object bean) {
|
MyParser(final Object bean) {
|
||||||
super(bean);
|
super(bean);
|
||||||
|
ensureOptionsInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
@@ -137,7 +230,7 @@ public class CmdLineParser {
|
|||||||
protected OptionHandler createOptionHandler(final OptionDef option,
|
protected OptionHandler createOptionHandler(final OptionDef option,
|
||||||
final Setter setter) {
|
final Setter setter) {
|
||||||
if (isHandlerSpecified(option) || isEnum(setter) || isPrimitive(setter)) {
|
if (isHandlerSpecified(option) || isEnum(setter) || isPrimitive(setter)) {
|
||||||
return super.createOptionHandler(option, setter);
|
return add(super.createOptionHandler(option, setter));
|
||||||
}
|
}
|
||||||
|
|
||||||
final Key<OptionHandlerFactory<?>> key =
|
final Key<OptionHandlerFactory<?>> key =
|
||||||
@@ -145,12 +238,28 @@ public class CmdLineParser {
|
|||||||
Injector i = injector;
|
Injector i = injector;
|
||||||
while (i != null) {
|
while (i != null) {
|
||||||
if (i.getBindings().containsKey(key)) {
|
if (i.getBindings().containsKey(key)) {
|
||||||
return i.getInstance(key).create(this, option, setter);
|
return add(i.getInstance(key).create(this, option, setter));
|
||||||
}
|
}
|
||||||
i = i.getParent();
|
i = i.getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.createOptionHandler(option, setter);
|
return add(super.createOptionHandler(option, setter));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private OptionHandler add(OptionHandler handler) {
|
||||||
|
ensureOptionsInitialized();
|
||||||
|
options.add(handler);
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private void ensureOptionsInitialized() {
|
||||||
|
if (options == null) {
|
||||||
|
help = new HelpOption();
|
||||||
|
options = new ArrayList<OptionHandler>();
|
||||||
|
addOption(help, help);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isHandlerSpecified(final OptionDef option) {
|
private boolean isHandlerSpecified(final OptionDef option) {
|
||||||
@@ -165,4 +274,63 @@ public class CmdLineParser {
|
|||||||
return setter.getType().isPrimitive();
|
return setter.getType().isPrimitive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class HelpOption implements Option, Setter<Boolean> {
|
||||||
|
private boolean value;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return "--help";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] aliases() {
|
||||||
|
return new String[] {"-h"};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String usage() {
|
||||||
|
return "display this help text";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addValue(Boolean val) {
|
||||||
|
value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends OptionHandler<Boolean>> handler() {
|
||||||
|
return BooleanOptionHandler.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String metaVar() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean multiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean required() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Annotation> annotationType() {
|
||||||
|
return Option.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<Boolean> getType() {
|
||||||
|
return Boolean.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return multiValued();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user