/* Copyright (c) 2013-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:
* Victor Olaya (Boundless) - initial implementation
*/
package org.locationtech.geogig.cli.porcelain;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import jline.console.ConsoleReader;
import org.locationtech.geogig.api.NodeRef;
import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.api.RevObject.TYPE;
import org.locationtech.geogig.api.plumbing.LsTreeOp;
import org.locationtech.geogig.api.plumbing.LsTreeOp.Strategy;
import org.locationtech.geogig.cli.AbstractCommand;
import org.locationtech.geogig.cli.CLICommand;
import org.locationtech.geogig.cli.GeogigCLI;
import org.locationtech.geogig.cli.annotation.ReadOnly;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.base.Function;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
/**
*
*/
@ReadOnly
@Parameters(commandNames = "ls", commandDescription = "Obtain information about features in the index and the working tree.")
public class Ls extends AbstractCommand implements CLICommand {
@Parameter(description = "<[refspec]:[path]>", arity = 1)
private List<String> refList = Lists.newArrayList();
@Parameter(names = { "-t" }, description = "Show tree entries even when going to recurse them. Has no effect if -r was not passed. -d implies -t.")
private boolean includeTrees;
@Parameter(names = { "-d" }, description = "Show only the named tree entry itself, not its children.")
private boolean onlyTrees;
@Parameter(names = { "-r" }, description = "Recurse into sub-trees.")
private boolean recursive;
@Parameter(names = { "-v", "--verbose" }, description = "Verbose output, include metadata and object id")
private boolean verbose;
@Parameter(names = { "-a", "--abbrev" }, description = "Instead of showing the full 40-byte hexadecimal object lines, show only a partial prefix. "
+ "Non default number of digits can be specified with --abbrev <n>.")
private Integer abbrev;
@Override
public void runInternal(GeogigCLI cli) throws IOException {
String ref;
if (refList.isEmpty()) {
ref = null;
} else {
ref = refList.get(0);
}
Strategy lsStrategy = Strategy.CHILDREN;
if (recursive) {
if (includeTrees) {
lsStrategy = Strategy.DEPTHFIRST;
} else if (onlyTrees) {
lsStrategy = Strategy.DEPTHFIRST_ONLY_TREES;
} else {
lsStrategy = Strategy.DEPTHFIRST_ONLY_FEATURES;
}
} else {
if (onlyTrees) {
lsStrategy = Strategy.TREES_ONLY;
}
}
Iterator<NodeRef> iter = cli.getGeogig().command(LsTreeOp.class).setReference(ref)
.setStrategy(lsStrategy).call();
final ConsoleReader console = cli.getConsole();
if (!iter.hasNext()) {
if (ref == null) {
console.println("The working tree is empty");
} else {
console.println("The specified path is empty");
}
return;
}
int depth = 0;
if (ref == null) {
console.println("Root tree/");
} else {
console.println(ref + "/");
depth = ref.split("/").length - 1;
}
final int rootDepth = depth;
Function<NodeRef, CharSequence> printFunctor = new Function<NodeRef, CharSequence>() {
@Override
public CharSequence apply(NodeRef input) {
String path = input.path();
int depth = path.split("/").length - rootDepth;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append('\t');
}
sb.append(input.getNode().getName());
if (input.getType().equals(TYPE.TREE)) {
sb.append('/');
}
if (verbose) {
sb.append(' ').append(abbrev(input.getMetadataId())).append(' ')
.append(abbrev(input.objectId()));
}
return sb.toString();
}
private String abbrev(ObjectId oid) {
return abbrev == null ? oid.toString() : oid.toString().substring(0,
abbrev.intValue());
}
};
Iterator<CharSequence> lines = Iterators.transform(iter, printFunctor);
while (lines.hasNext()) {
console.println(lines.next());
}
console.flush();
}
}