Package org.locationtech.geogig.cli.porcelain

Source Code of org.locationtech.geogig.cli.porcelain.Branch

/* Copyright (c) 2012-2014 Boundless and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/edl-v10.html
*
* Contributors:
* Gabriel Roldan (Boundless) - initial implementation
*/
package org.locationtech.geogig.cli.porcelain;

import java.io.IOException;
import java.util.List;

import jline.console.ConsoleReader;

import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.Ansi.Color;
import org.locationtech.geogig.api.GeoGIG;
import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.api.Ref;
import org.locationtech.geogig.api.RevCommit;
import org.locationtech.geogig.api.SymRef;
import org.locationtech.geogig.api.plumbing.RefParse;
import org.locationtech.geogig.api.porcelain.BranchCreateOp;
import org.locationtech.geogig.api.porcelain.BranchDeleteOp;
import org.locationtech.geogig.api.porcelain.BranchListOp;
import org.locationtech.geogig.api.porcelain.BranchRenameOp;
import org.locationtech.geogig.cli.AbstractCommand;
import org.locationtech.geogig.cli.CLICommand;
import org.locationtech.geogig.cli.GeogigCLI;
import org.locationtech.geogig.cli.annotation.ObjectDatabaseReadOnly;
import org.locationtech.geogig.cli.annotation.StagingDatabaseReadOnly;

import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

/**
* With no arguments the command will display all existing branches with the current branch
* highlighted with the asterisk. The {@code -r} option will list only remote branches and the
* {@code -a} option will list both local and remote branches. Adding the {@code --color} option
* with the value of auto, always, or never will add or remove color from the listing. With the
* {@code -v} option it will list the branches along with the commit id and commit message that the
* branch is currently on.
* <p>
* With a branch name specified it will create a branch of off the current branch. If a start point
* is specified as well then it will be created off of the given start point. If the -c option is
* given it will automatically checkout the branch once it is created.
* <p>
* With the -d option with a branch name specified will delete that branch. You cannot delete the
* branch that you are currently on, checkout a different branch to delete it. Also with the -d
* option you can list multiple branches for deletion.
* <p>
* With the -m option you can specify an oldBranchName to rename with the given newBranchName or you
* can rename the current branch by not specifying oldBranchName. With the --force option you can
* rename a branch to a name that already exists as a branch, however this will delete the other
* branch.
* <p>
* CLI proxy {@link BranchListOp}, {@link BranchCreateOp}, {@link BranchDeleteOp},
* {@link BranchRenameOp}
* <p>
* Usage:
* <ul>
* <li> {@code geogig branch [-c] <branchname>[<startpoint>]}: Creates a new branch with the given
* branchname at the specified startpoint and checks it out immediately
* <li> {@code geogig branch [--color=always] [-v] [-a]}: Lists all branches (Local and Remote) in
* color with commit id and commit message
* <li> {@code geogig branch [-r]}: List only remote branches
* <li> {@code geogig branch [--delete] <branchname>...}: Deletes all the branches listed unless HEAD
* is pointing to it
* <li> {@code geogig branch [--force] [--rename] [<oldBranchName>] <newBranchName>}: Renames a
* branch specified by oldBranchName or current branch if no oldBranchName is given to newBranchName
* </ul>
*
* @see BranchListOp
* @see BranchCreateOp
* @see BranchDeleteOp
* @see BranchRenameOp
*/
@ObjectDatabaseReadOnly
@StagingDatabaseReadOnly
@Parameters(commandNames = "branch", commandDescription = "List, create, or delete branches")
public class Branch extends AbstractCommand implements CLICommand {

    @Parameter(description = "<branch name> [<start point>]")
    private List<String> branchName = Lists.newArrayList();

    @Parameter(names = { "--checkout", "-c" }, description = "automatically checkout the new branch when the command is used to create a branch")
    private boolean checkout;

    @Parameter(names = { "--delete", "-d" })
    private boolean delete = false;

    @Parameter(names = { "--orphan", "-o" }, description = "create an orphan branch")
    private boolean orphan = false;

    @Parameter(names = { "--force", "-f" }, description = "Force renaming/creating of a branch if the specified branc name already exists")
    private boolean force = false;

    @Parameter(names = { "--verbose", "-v",
            "Verbose output for list mode. Shows branch commit id and commit message." })
    private boolean verbose = false;

    @Parameter(names = { "--remote", "-r" }, description = "List or delete (if used with -d) the remote-tracking branches.")
    private boolean remotes = false;

    @Parameter(names = { "--all", "-a" }, description = "List all branches, both local and remote")
    private boolean all = false;

    @Parameter(names = { "--rename", "-m" }, description = "Rename branch ")
    private boolean rename = false;

    @Override
    public void runInternal(final GeogigCLI cli) throws IOException {
        final GeoGIG geogig = cli.getGeogig();

        final ConsoleReader console = cli.getConsole();

        if (delete) {
            checkParameter(!branchName.isEmpty(), "no name specified for deletion");

            for (String br : branchName) {
                Optional<? extends Ref> deletedBranch;
                deletedBranch = geogig.command(BranchDeleteOp.class).setName(br).call();

                checkParameter(deletedBranch.isPresent(), "No branch called '%s'.", br);

                console.println(String.format("Deleted branch '%s'.", br));
            }
            return;
        }

        checkParameter(branchName.size() < 3, "too many arguments: %s", branchName);

        if (rename) {
            checkParameter(!branchName.isEmpty(), "You must specify a branch to rename.");

            if (branchName.size() == 1) {
                Optional<Ref> headRef = geogig.command(RefParse.class).setName(Ref.HEAD).call();
                geogig.command(BranchRenameOp.class).setNewName(branchName.get(0)).setForce(force)
                        .call();
                if (headRef.isPresent()) {
                    SymRef ref = (SymRef) headRef.get();
                    console.println("renamed branch '"
                            + ref.getTarget().substring(Ref.HEADS_PREFIX.length()) + "' to '"
                            + branchName.get(0) + "'");
                }
            } else {
                geogig.command(BranchRenameOp.class).setOldName(branchName.get(0))
                        .setNewName(branchName.get(1)).setForce(force).call();
                console.println("renamed branch '" + branchName.get(0) + "' to '"
                        + branchName.get(1) + "'");
            }
            return;
        }

        if (branchName.isEmpty()) {
            listBranches(cli);
            return;
        }

        final String branch = branchName.get(0);
        final String origin = branchName.size() > 1 ? branchName.get(1) : Ref.HEAD;

        Ref newBranch = geogig.command(BranchCreateOp.class).setName(branch).setForce(force)
                .setOrphan(orphan).setAutoCheckout(checkout).setSource(origin).call();

        console.println("Created branch " + newBranch.getName());
    }

    private void listBranches(GeogigCLI cli) throws IOException {
        final ConsoleReader console = cli.getConsole();
        final GeoGIG geogig = cli.getGeogig();

        boolean local = all || !(remotes);
        boolean remote = all || remotes;

        ImmutableList<Ref> branches = geogig.command(BranchListOp.class).setLocal(local)
                .setRemotes(remote).call();

        final Ref currentHead = geogig.command(RefParse.class).setName(Ref.HEAD).call().get();

        final int largest = verbose ? largestLenght(branches) : 0;

        for (Ref branchRef : branches) {
            final String branchRefName = branchRef.getName();

            Ansi ansi = newAnsi(console.getTerminal());

            if ((currentHead instanceof SymRef)
                    && ((SymRef) currentHead).getTarget().equals(branchRefName)) {
                ansi.a("* ").fg(Color.GREEN);
            } else {
                ansi.a("  ");
            }
            // print unqualified names for local branches
            String branchName = refDisplayString(branchRef);
            ansi.a(branchName);
            ansi.reset();

            if (verbose) {
                ansi.a(Strings.repeat(" ", 1 + (largest - branchName.length())));
                ansi.a(branchRef.getObjectId().toString().substring(0, 7)).a(" ");

                Optional<RevCommit> commit = findCommit(geogig, branchRef);
                if (commit.isPresent()) {
                    ansi.a(messageTitle(commit.get()));
                }
            }

            console.println(ansi.toString());
        }
    }

    private String messageTitle(RevCommit commit) {
        String message = Optional.fromNullable(commit.getMessage()).or("");
        int newline = message.indexOf('\n');
        return newline == -1 ? message : message.substring(0, newline);
    }

    /**
     * @param branchRef
     * @return
     */
    private Optional<RevCommit> findCommit(GeoGIG geogig, Ref branchRef) {
        ObjectId commitId = branchRef.getObjectId();
        if (commitId.isNull()) {
            return Optional.absent();
        }
        RevCommit commit = geogig.getRepository().getCommit(commitId);
        return Optional.of(commit);
    }

    /**
     * @param branches
     * @return
     */
    private int largestLenght(ImmutableList<Ref> branches) {
        int len = 0;
        for (Ref ref : branches) {
            len = Math.max(len, refDisplayString(ref).length());

        }
        return len;
    }

    private String refDisplayString(Ref ref) {

        String branchName = ref.getName();
        if (branchName.startsWith(Ref.HEADS_PREFIX)) {
            branchName = ref.localName();
        } else if (branchName.startsWith(Ref.REMOTES_PREFIX)) {
            branchName = branchName.substring(Ref.REMOTES_PREFIX.length());
        }
        if (ref instanceof SymRef) {
            branchName += " -> " + Ref.localName(((SymRef) ref).getTarget());
        }
        return branchName;
    }
}
TOP

Related Classes of org.locationtech.geogig.cli.porcelain.Branch

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.