Refactor ls-projects code to gerrit-server

Move the implementation to gerrit-server, making it available to
both the SSH and HTTP environments. Later we will define a new
REST-ful API over HTTP that supports the same sort of query as
`ssh gerrit ls-projects`.

Change-Id: Ic8052b4dd3c70809feb4b43e5b2bae6b72b10503
This commit is contained in:
Shawn O. Pearce
2012-04-04 11:44:41 -07:00
parent 246461cf4a
commit 1bc77620bd
9 changed files with 103 additions and 48 deletions

View File

@@ -121,6 +121,12 @@ limitations under the License.
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-util-cli</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-util-ssl</artifactId>

View File

@@ -57,6 +57,7 @@ import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.PermissionCollection;
import com.google.gerrit.server.project.ProjectCacheImpl;
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.SectionSortCache;
import com.google.gerrit.server.tools.ToolsCatalog;
@@ -118,6 +119,7 @@ public class GerritGlobalModule extends FactoryModule {
factory(AccountInfoCacheFactory.Factory.class);
factory(CapabilityControl.Factory.class);
factory(GroupInfoCacheFactory.Factory.class);
factory(ProjectNode.Factory.class);
factory(ProjectState.Factory.class);
factory(MaterializedGroupMembership.Factory.class);
bind(PermissionCollection.Factory.class);

View File

@@ -53,6 +53,7 @@ import com.google.gerrit.server.patch.PublishComments;
import com.google.gerrit.server.patch.RemoveReviewer;
import com.google.gerrit.server.project.ChangeControl;
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.ProjectControl;
import com.google.gerrit.server.project.SuggestParentCandidates;
@@ -71,6 +72,7 @@ public class GerritRequestModule extends FactoryModule {
bind(MetaDataUpdate.User.class).in(RequestScoped.class);
bind(AccountResolver.class);
bind(ChangeQueryRewriter.class);
bind(ListProjects.class);
bind(AnonymousUser.class).in(RequestScoped.class);
bind(PerRequestProjectControlCache.class).in(RequestScoped.class);

View File

@@ -12,18 +12,14 @@
// See the License for the specific language governing permissions and
// 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.server.IdentifiedUser;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.git.GitRepositoryManager;
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.BaseCommand;
import com.google.gerrit.server.util.TreeFormatter;
import com.google.inject.Inject;
import org.apache.sshd.server.Environment;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
@@ -32,18 +28,23 @@ import org.kohsuke.args4j.Option;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeMap;
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);
static enum FilterType {
public static enum FilterType {
CODE {
@Override
boolean matches(Repository git) throws IOException {
@@ -69,24 +70,18 @@ final class ListProjects extends BaseCommand {
abstract boolean matches(Repository git) throws IOException;
}
@Inject
private IdentifiedUser currentUser;
@Inject
private ProjectCache projectCache;
@Inject
private GitRepositoryManager repoManager;
@Inject
private ProjectNode.Factory projectNodeFactory;
private final CurrentUser currentUser;
private final ProjectCache projectCache;
private final GitRepositoryManager repoManager;
private final ProjectNode.Factory projectNodeFactory;
@Option(name = "--show-branch", aliases = {"-b"}, multiValued = true,
usage = "displays the sha of each project in the specified branch")
private List<String> showBranch;
@Option(name = "--tree", aliases = {"-t"}, usage = "displays project inheritance in a tree-like format\n" +
"this option does not work together with the show-branch option")
@Option(name = "--tree", aliases = {"-t"}, usage =
"displays project inheritance in a tree-like format\n"
+ "this option does not work together with the show-branch option")
private boolean showTree;
@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")
private boolean all;
@Override
public void start(final Environment env) {
startThread(new CommandRunnable() {
@Override
public void run() throws Exception {
parseCommandLine();
ListProjects.this.display();
}
});
@Inject
protected ListProjects(CurrentUser currentUser, ProjectCache projectCache,
GitRepositoryManager repoManager,
ProjectNode.Factory projectNodeFactory) {
this.currentUser = currentUser;
this.projectCache = projectCache;
this.repoManager = repoManager;
this.projectNodeFactory = projectNodeFactory;
}
private void display() throws Failure {
if (showTree && (showBranch != null)) {
throw new UnloggedFailure(1, "fatal: --tree and --show-branch options are not compatible.");
public List<String> getShowBranch() {
return showBranch;
}
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 =
new TreeMap<Project.NameKey, ProjectNode>();
try {

View File

@@ -12,32 +12,31 @@
// See the License for the specific language governing permissions and
// 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.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.assistedinject.Assisted;
import java.util.SortedSet;
import java.util.TreeSet;
/** Node of a Project in a tree formatted by {@link ListProjects}. */
public class ProjectNode implements TreeNode, Comparable<ProjectNode> {
public interface Factory {
ProjectNode create(final Project project, final boolean isVisible);
}
private final AllProjectsName allProjectsName;
private final Project project;
private final boolean isVisible;
private final SortedSet<ProjectNode> children = new TreeSet<ProjectNode>();
@Inject
public ProjectNode(final AllProjectsName allProjectsName,
protected ProjectNode(final AllProjectsName allProjectsName,
@Assisted final Project project, @Assisted final boolean isVisible) {
this.allProjectsName = allProjectsName;
this.project = project;

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.sshd.commands;
package com.google.gerrit.server.util;
import java.io.PrintWriter;
import java.util.SortedSet;

View File

@@ -40,7 +40,6 @@ import com.google.gerrit.sshd.args4j.PatchSetIdHandler;
import com.google.gerrit.sshd.args4j.ProjectControlHandler;
import com.google.gerrit.sshd.args4j.SocketAddressHandler;
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.util.cli.CmdLineParser;
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(AccountManager.class);
factory(ChangeUserName.Factory.class);
factory(ProjectNode.Factory.class);
bind(PublickeyAuthenticator.class).to(DatabasePubKeyAuth.class);
bind(KeyPairProvider.class).toProvider(HostKeyProvider.class).in(SINGLETON);

View File

@@ -36,7 +36,7 @@ public class DefaultCommandModule extends CommandModule {
command(gerrit).toProvider(new DispatchCommandProvider(gerrit));
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, "query").to(Query.class);
command(gerrit, "show-caches").to(ShowCaches.class);

View File

@@ -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);
}
});
}
}