Merge "Make the code to format projects as a tree reusable"
This commit is contained in:
@@ -39,6 +39,7 @@ 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.OptionHandlerFactory;
|
import com.google.gerrit.util.cli.OptionHandlerFactory;
|
||||||
@@ -80,6 +81,7 @@ 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);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ package com.google.gerrit.sshd.commands;
|
|||||||
|
|
||||||
import com.google.gerrit.reviewdb.Project;
|
import com.google.gerrit.reviewdb.Project;
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
import com.google.gerrit.server.config.AllProjectsName;
|
|
||||||
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.project.ProjectCache;
|
||||||
import com.google.gerrit.server.project.ProjectControl;
|
import com.google.gerrit.server.project.ProjectControl;
|
||||||
@@ -35,19 +34,15 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.SortedSet;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
final class ListProjects extends BaseCommand {
|
final class ListProjects extends BaseCommand {
|
||||||
private static final Logger log = LoggerFactory.getLogger(ListProjects.class);
|
private static final Logger log = LoggerFactory.getLogger(ListProjects.class);
|
||||||
|
|
||||||
private static final String NODE_PREFIX = "|-- ";
|
|
||||||
private static final String LAST_NODE_PREFIX = "`-- ";
|
|
||||||
private static final String DEFAULT_TAB_SEPARATOR = "|";
|
|
||||||
private static final String NOT_VISIBLE_PROJECT = "(x)";
|
|
||||||
|
|
||||||
static enum FilterType {
|
static enum FilterType {
|
||||||
CODE {
|
CODE {
|
||||||
@Override
|
@Override
|
||||||
@@ -84,7 +79,7 @@ final class ListProjects extends BaseCommand {
|
|||||||
private GitRepositoryManager repoManager;
|
private GitRepositoryManager repoManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private AllProjectsName allProjectsName;
|
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")
|
||||||
@@ -103,8 +98,6 @@ 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;
|
||||||
|
|
||||||
private String currentTabSeparator = DEFAULT_TAB_SEPARATOR;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(final Environment env) {
|
public void start(final Environment env) {
|
||||||
startThread(new CommandRunnable() {
|
startThread(new CommandRunnable() {
|
||||||
@@ -126,7 +119,8 @@ final class ListProjects extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final PrintWriter stdout = toPrintWriter(out);
|
final PrintWriter stdout = toPrintWriter(out);
|
||||||
final TreeMap<String, TreeNode> treeMap = new TreeMap<String, TreeNode>();
|
final TreeMap<Project.NameKey, ProjectNode> treeMap =
|
||||||
|
new TreeMap<Project.NameKey, ProjectNode>();
|
||||||
try {
|
try {
|
||||||
for (final Project.NameKey projectName : projectCache.all()) {
|
for (final Project.NameKey projectName : projectCache.all()) {
|
||||||
final ProjectState e = projectCache.get(projectName);
|
final ProjectState e = projectCache.get(projectName);
|
||||||
@@ -139,7 +133,8 @@ final class ListProjects extends BaseCommand {
|
|||||||
final ProjectControl pctl = e.controlFor(currentUser);
|
final ProjectControl pctl = e.controlFor(currentUser);
|
||||||
final boolean isVisible = pctl.isVisible() || (all && pctl.isOwner());
|
final boolean isVisible = pctl.isVisible() || (all && pctl.isOwner());
|
||||||
if (showTree) {
|
if (showTree) {
|
||||||
treeMap.put(projectName.get(), new TreeNode(pctl.getProject(), isVisible));
|
treeMap.put(projectName,
|
||||||
|
projectNodeFactory.create(pctl.getProject(), isVisible));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,23 +209,18 @@ final class ListProjects extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void printProjectTree(final PrintWriter stdout,
|
private void printProjectTree(final PrintWriter stdout,
|
||||||
final TreeMap<String, TreeNode> treeMap) {
|
final TreeMap<Project.NameKey, ProjectNode> treeMap) {
|
||||||
final List<TreeNode> sortedNodes = new ArrayList<TreeNode>();
|
final SortedSet<ProjectNode> sortedNodes = new TreeSet<ProjectNode>();
|
||||||
|
|
||||||
// Builds the inheritance tree using a list.
|
// Builds the inheritance tree using a list.
|
||||||
//
|
//
|
||||||
for (TreeNode key : treeMap.values()) {
|
for (final ProjectNode key : treeMap.values()) {
|
||||||
if (allProjectsName.equals(key.getProject().getNameKey())) {
|
if (key.isAllProjects()) {
|
||||||
sortedNodes.add(key);
|
sortedNodes.add(key);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String parentName = key.getParentName();
|
ProjectNode node = treeMap.get(key.getParentName());
|
||||||
if (parentName == null) {
|
|
||||||
parentName = allProjectsName.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
TreeNode node = treeMap.get(parentName);
|
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
node.addChild(key);
|
node.addChild(key);
|
||||||
} else {
|
} else {
|
||||||
@@ -238,10 +228,8 @@ final class ListProjects extends BaseCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builds a fake root node, which contains the sorted projects.
|
final TreeFormatter treeFormatter = new TreeFormatter(stdout);
|
||||||
//
|
treeFormatter.printTree(sortedNodes);
|
||||||
final TreeNode fakeRoot = new TreeNode(null, sortedNodes, false);
|
|
||||||
printElement(stdout, fakeRoot, -1, false, sortedNodes.get(sortedNodes.size() - 1));
|
|
||||||
stdout.flush();
|
stdout.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,139 +265,4 @@ final class ListProjects extends BaseCommand {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Class created to manipulate the nodes of the project inheritance tree **/
|
|
||||||
private static class TreeNode {
|
|
||||||
private final List<TreeNode> children;
|
|
||||||
private final Project project;
|
|
||||||
private final boolean isVisible;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* @param p Project
|
|
||||||
*/
|
|
||||||
public TreeNode(Project p, boolean visible) {
|
|
||||||
this.children = new ArrayList<TreeNode>();
|
|
||||||
this.project = p;
|
|
||||||
this.isVisible = visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used for creating the fake node
|
|
||||||
* @param p Project
|
|
||||||
* @param c List of nodes
|
|
||||||
*/
|
|
||||||
public TreeNode(Project p, List<TreeNode> c, boolean visible) {
|
|
||||||
this.children = c;
|
|
||||||
this.project = p;
|
|
||||||
this.isVisible = visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns if the the node is leaf
|
|
||||||
* @return True if is lead, false, otherwise
|
|
||||||
*/
|
|
||||||
public boolean isLeaf() {
|
|
||||||
return children.size() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the project parent name
|
|
||||||
* @return Project parent name
|
|
||||||
*/
|
|
||||||
public String getParentName() {
|
|
||||||
if (project.getParent() != null) {
|
|
||||||
return project.getParent().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a child to the list
|
|
||||||
* @param node TreeNode child
|
|
||||||
*/
|
|
||||||
public void addChild(TreeNode node) {
|
|
||||||
children.add(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the project instance
|
|
||||||
* @return Project instance
|
|
||||||
*/
|
|
||||||
public Project getProject() {
|
|
||||||
return project;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of children nodes
|
|
||||||
* @return List of children nodes
|
|
||||||
*/
|
|
||||||
public List<TreeNode> getChildren() {
|
|
||||||
return children;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns if the project is visible to the user
|
|
||||||
* @return True if is visible, false, otherwise
|
|
||||||
*/
|
|
||||||
public boolean isVisible() {
|
|
||||||
return isVisible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to display the project inheritance tree recursively
|
|
||||||
* @param stdout PrintWriter used do print
|
|
||||||
* @param node Tree node
|
|
||||||
* @param level Current level of the tree
|
|
||||||
* @param isLast True, if is the last node of a level, false, otherwise
|
|
||||||
* @param lastParentNode Last "root" parent node
|
|
||||||
*/
|
|
||||||
private void printElement(final PrintWriter stdout, TreeNode node, int level, boolean isLast,
|
|
||||||
final TreeNode lastParentNode) {
|
|
||||||
// Checks if is not the "fake" root project.
|
|
||||||
//
|
|
||||||
if (node.getProject() != null) {
|
|
||||||
|
|
||||||
// Check if is not the last "root" parent node,
|
|
||||||
// so the "|" separator will not longer be needed.
|
|
||||||
//
|
|
||||||
if (!currentTabSeparator.equals(" ")) {
|
|
||||||
final String nodeProject = node.getProject().getName();
|
|
||||||
final String lastParentProject = lastParentNode.getProject().getName();
|
|
||||||
|
|
||||||
if (nodeProject.equals(lastParentProject)) {
|
|
||||||
currentTabSeparator = " ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level > 0) {
|
|
||||||
stdout.print(String.format("%-" + 4 * level + "s", currentTabSeparator));
|
|
||||||
}
|
|
||||||
|
|
||||||
final String prefix = isLast ? LAST_NODE_PREFIX : NODE_PREFIX ;
|
|
||||||
|
|
||||||
String printout;
|
|
||||||
|
|
||||||
if (node.isVisible()) {
|
|
||||||
printout = prefix + node.getProject().getName();
|
|
||||||
} else {
|
|
||||||
printout = prefix + NOT_VISIBLE_PROJECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout.print(printout + "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.isLeaf()) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
final List<TreeNode> children = node.getChildren();
|
|
||||||
++level;
|
|
||||||
for(TreeNode treeNode : children) {
|
|
||||||
final boolean isLastIndex = children.indexOf(treeNode) == children.size() - 1;
|
|
||||||
printElement(stdout, treeNode, level, isLastIndex, lastParentNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
// Copyright (C) 2011 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.reviewdb.Project;
|
||||||
|
import com.google.gerrit.server.config.AllProjectsName;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.assistedinject.Assisted;
|
||||||
|
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
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,
|
||||||
|
@Assisted final Project project, @Assisted final boolean isVisible) {
|
||||||
|
this.allProjectsName = allProjectsName;
|
||||||
|
this.project = project;
|
||||||
|
this.isVisible = isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the project parent name.
|
||||||
|
*
|
||||||
|
* @return Project parent name, <code>null</code> for the 'All-Projects' root
|
||||||
|
* project
|
||||||
|
*/
|
||||||
|
public Project.NameKey getParentName() {
|
||||||
|
if (project.getParent() != null) {
|
||||||
|
return project.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (project.getNameKey().equals(allProjectsName)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return allProjectsName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAllProjects() {
|
||||||
|
return allProjectsName.equals(project.getNameKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
return project.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isVisible() {
|
||||||
|
return isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SortedSet<? extends TreeNode> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addChild(final ProjectNode child) {
|
||||||
|
children.add(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(final ProjectNode o) {
|
||||||
|
return project.getNameKey().compareTo(o.project.getNameKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
// Copyright (C) 2011 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 java.io.PrintWriter;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
|
||||||
|
public class TreeFormatter {
|
||||||
|
|
||||||
|
public static final String NOT_VISIBLE_NODE = "(x)";
|
||||||
|
|
||||||
|
private static final String NODE_PREFIX = "|-- ";
|
||||||
|
private static final String LAST_NODE_PREFIX = "`-- ";
|
||||||
|
private static final String DEFAULT_TAB_SEPARATOR = "|";
|
||||||
|
|
||||||
|
private final PrintWriter stdout;
|
||||||
|
private String currentTabSeparator = " ";
|
||||||
|
|
||||||
|
public TreeFormatter(final PrintWriter stdout) {
|
||||||
|
this.stdout = stdout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printTree(final SortedSet<? extends TreeNode> rootNodes) {
|
||||||
|
if (rootNodes.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rootNodes.size() == 1) {
|
||||||
|
printTree(rootNodes.first());
|
||||||
|
} else {
|
||||||
|
currentTabSeparator = DEFAULT_TAB_SEPARATOR;
|
||||||
|
for (final TreeNode rootNode : rootNodes) {
|
||||||
|
final boolean isLastRoot = rootNodes.last().equals(rootNode);
|
||||||
|
if (isLastRoot) {
|
||||||
|
currentTabSeparator = " ";
|
||||||
|
}
|
||||||
|
printTree(rootNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printTree(final TreeNode rootNode) {
|
||||||
|
printTree(rootNode, 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printTree(final TreeNode node, final int level,
|
||||||
|
final boolean isLast) {
|
||||||
|
printNode(node, level, isLast);
|
||||||
|
final SortedSet<? extends TreeNode> childNodes = node.getChildren();
|
||||||
|
for (final TreeNode childNode : childNodes) {
|
||||||
|
final boolean isLastChild = childNodes.last().equals(childNode);
|
||||||
|
printTree(childNode, level + 1, isLastChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printIndention(final int level) {
|
||||||
|
if (level > 0) {
|
||||||
|
stdout.print(String.format("%-" + 4 * level + "s", currentTabSeparator));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printNode(final TreeNode node, final int level,
|
||||||
|
final boolean isLast) {
|
||||||
|
printIndention(level);
|
||||||
|
stdout.print(isLast ? LAST_NODE_PREFIX : NODE_PREFIX);
|
||||||
|
if (node.isVisible()) {
|
||||||
|
stdout.print(node.getDisplayName());
|
||||||
|
} else {
|
||||||
|
stdout.print(NOT_VISIBLE_NODE);
|
||||||
|
}
|
||||||
|
stdout.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (C) 2011 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 java.util.SortedSet;
|
||||||
|
|
||||||
|
public interface TreeNode {
|
||||||
|
public String getDisplayName();
|
||||||
|
public boolean isVisible();
|
||||||
|
public SortedSet<? extends TreeNode> getChildren();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user