/* 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:
* Johnathan Garrett (LMN Solutions) - initial implementation
*/
package org.locationtech.geogig.cli.porcelain;
import java.io.IOException;
import java.util.List;
import jline.console.ConsoleReader;
import org.locationtech.geogig.api.GeoGIG;
import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.api.Ref;
import org.locationtech.geogig.api.plumbing.DiffCount;
import org.locationtech.geogig.api.plumbing.diff.DiffObjectCount;
import org.locationtech.geogig.api.porcelain.TransferSummary;
import org.locationtech.geogig.api.porcelain.PullOp;
import org.locationtech.geogig.api.porcelain.PullResult;
import org.locationtech.geogig.api.porcelain.SynchronizationException;
import org.locationtech.geogig.cli.AbstractCommand;
import org.locationtech.geogig.cli.CLICommand;
import org.locationtech.geogig.cli.CommandFailedException;
import org.locationtech.geogig.cli.GeogigCLI;
import org.locationtech.geogig.cli.annotation.RemotesReadOnly;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.base.Objects;
/**
* Incorporates changes from a remote repository into the current branch.
* <p>
* More precisely, {@code geogig pull} runs {@code geogig fetch} with the given parameters and calls
* {@code geogig merge} to merge the retrieved branch heads into the current branch. With
* {@code --rebase}, it runs {@code geogig rebase} instead of {@code geogig merge}.
* <p>
* CLI proxy for {@link PullOp}
* <p>
* Usage:
* <ul>
* <li> {@code geogig pull [options] [<repository> [<refspec>...]]}
* </ul>
*
* @see PullOp
*/
@RemotesReadOnly
@Parameters(commandNames = "pull", commandDescription = "Fetch from and merge with another repository or a local branch")
public class Pull extends AbstractCommand implements CLICommand {
@Parameter(names = "--all", description = "Fetch all remotes.")
private boolean all = false;
@Parameter(names = "--rebase", description = "Rebase the current branch on top of the upstream branch after fetching.")
private boolean rebase = false;
@Parameter(names = { "--depth" }, description = "Depth of the pull.")
private int depth = 0;
@Parameter(names = { "--fulldepth" }, description = "Pull the full history from the repository.")
private boolean fulldepth = false;
@Parameter(description = "[<repository> [<refspec>...]]")
private List<String> args;
/**
* Executes the pull command using the provided options.
*/
@Override
public void runInternal(GeogigCLI cli) throws IOException {
checkParameter(depth > 0 ? !fulldepth : true,
"Cannot specify a depth and full depth. Use --depth <depth> or --fulldepth.");
GeoGIG geogig = cli.getGeogig();
if (depth > 0 || fulldepth) {
if (!geogig.getRepository().getDepth().isPresent()) {
throw new CommandFailedException(
"Depth operations can only be used on a shallow clone.");
}
}
PullOp pull = geogig.command(PullOp.class);
pull.setProgressListener(cli.getProgressListener());
pull.setAll(all).setRebase(rebase).setFullDepth(fulldepth);
pull.setDepth(depth);
if (args != null) {
if (args.size() > 0) {
pull.setRemote(args.get(0));
}
for (int i = 1; i < args.size(); i++) {
pull.addRefSpec(args.get(i));
}
}
try {
final PullResult result = pull.call();
ConsoleReader console = cli.getConsole();
TransferSummary fetchResult = result.getFetchResult();
FetchResultPrinter.print(fetchResult, console);
final Ref oldRef = result.getOldRef();
final Ref newRef = result.getNewRef();
if (oldRef == null && newRef == null) {
console.println("Nothing to pull.");
} else if (Objects.equal(oldRef, newRef)) {
String name = oldRef == null ? newRef.getName() : oldRef.getName();
name = Ref.localName(name);
console.println(name + " already up to date.");
} else {
String oldTreeish;
String newTreeish = newRef.getObjectId().toString();
if (oldRef == null) {
console.println("From " + result.getRemoteName());
console.println(" * [new branch] " + newRef.localName() + " -> "
+ newRef.getName());
oldTreeish = ObjectId.NULL.toString();
} else {
oldTreeish = oldRef.getObjectId().toString();
}
DiffObjectCount count = geogig.command(DiffCount.class).setOldVersion(oldTreeish)
.setNewVersion(newTreeish).call();
long added = count.getFeaturesAdded();
long removed = count.getFeaturesRemoved();
long modified = count.getFeaturesChanged();
console.println(String.format("Features Added: %,d Removed: %,d Modified: %,d",
added, removed, modified));
}
} catch (SynchronizationException e) {
switch (e.statusCode) {
case HISTORY_TOO_SHALLOW:
default:
throw new CommandFailedException("Unable to pull, the remote history is shallow.",
e);
}
}
}
}