com.google.gerrit.sshd.commands.ListProjects.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gerrit.sshd.commands.ListProjects.java

Source

// 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.reviewdb.Project;
import com.google.gerrit.server.IdentifiedUser;
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.inject.Inject;

import org.apache.sshd.server.Environment;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.kohsuke.args4j.Option;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

final class ListProjects extends BaseCommand {
    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)";

    @Inject
    private IdentifiedUser currentUser;

    @Inject
    private ProjectCache projectCache;

    @Inject
    private GitRepositoryManager repoManager;

    @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")
    private boolean showTree;

    private String currentTabSeparator = DEFAULT_TAB_SEPARATOR;

    @Override
    public void start(final Environment env) {
        startThread(new CommandRunnable() {
            @Override
            public void run() throws Exception {
                parseCommandLine();
                ListProjects.this.display();
            }
        });
    }

    private void display() throws Failure {
        if (showTree && (showBranch != null)) {
            throw new UnloggedFailure(1, "fatal: --tree and --show-branch options are not compatible.");
        }

        final PrintWriter stdout = toPrintWriter(out);

        TreeMap<String, TreeNode> treeMap = null;

        if (showTree) {
            treeMap = new TreeMap<String, TreeNode>();
        }

        try {
            for (final Project.NameKey projectName : projectCache.all()) {
                final ProjectState e = projectCache.get(projectName);
                if (e == null) {
                    // If we can't get it from the cache, pretend its not present.
                    //
                    continue;
                }

                final ProjectControl pctl = e.controlFor(currentUser);

                if (!showTree) {

                    if (!pctl.isVisible()) {
                        // Require the project itself to be visible to the user.
                        //
                        continue;
                    }

                    if (showBranch != null) {
                        final List<Ref> refs = getBranchRefs(projectName);
                        if (refs == null) {
                            continue;
                        }

                        boolean hasVisibleRefs = false;
                        for (int i = 0; i < refs.size(); i++) {
                            Ref ref = refs.get(i);
                            if (ref == null || ref.getObjectId() == null
                                    || !pctl.controlForRef(ref.getLeaf().getName()).isVisible()) {
                                // No branch, or the user can't see this branch, so remove it.
                                refs.set(i, null);
                            } else {
                                hasVisibleRefs = true;
                            }
                        }

                        if (!hasVisibleRefs) {
                            continue;
                        }

                        for (Ref ref : refs) {
                            if (ref == null) {
                                // Print stub (forty '-' symbols)
                                stdout.print("----------------------------------------");
                            } else {
                                stdout.print(ref.getObjectId().name());
                            }
                            stdout.print(' ');
                        }
                    }

                    stdout.print(projectName.get() + "\n");
                } else {
                    treeMap.put(projectName.get(), new TreeNode(pctl.getProject(), pctl.isVisible()));
                }
            }

            if (showTree && treeMap.size() > 0) {
                final List<TreeNode> sortedNodes = new ArrayList<TreeNode>();

                // Builds the inheritance tree using a list.
                //
                for (final TreeNode key : treeMap.values()) {
                    final String parentName = key.getParentName();
                    if (parentName != null) {
                        final TreeNode node = treeMap.get(parentName);
                        if (node != null) {
                            node.addChild(key);
                        } else {
                            sortedNodes.add(key);
                        }
                    } else {
                        sortedNodes.add(key);
                    }
                }

                // Builds a fake root node, which contains the sorted projects.
                //
                final TreeNode fakeRoot = new TreeNode(null, sortedNodes, false);
                printElement(stdout, fakeRoot, -1, false, sortedNodes.get(sortedNodes.size() - 1));
                stdout.flush();
            }
        } finally {
            stdout.flush();
        }
    }

    private List<Ref> getBranchRefs(Project.NameKey projectName) {
        try {
            final Repository r = repoManager.openRepository(projectName);
            try {
                final List<Ref> result = new ArrayList<Ref>(showBranch.size());
                for (String branch : showBranch) {
                    result.add(r.getRef(branch));
                }
                return result;
            } finally {
                r.close();
            }
        } catch (IOException ioe) {
            return null;
        }
    }

    /** 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);
            }
        }
    }
}