/* 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.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Iterator;
import java.util.List;
import org.locationtech.geogig.api.GeoGIG;
import org.locationtech.geogig.api.plumbing.diff.DiffEntry;
import org.locationtech.geogig.api.plumbing.diff.Patch;
import org.locationtech.geogig.api.plumbing.diff.PatchSerializer;
import org.locationtech.geogig.api.porcelain.CreatePatchOp;
import org.locationtech.geogig.api.porcelain.DiffOp;
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.collect.Iterators;
import com.google.common.collect.Lists;
/**
* Store changes between two version of the repository in a patch file
*
* Usage is identical to that of the diff command, but adding a destination file where the patch is
* to be saved
*
* @see Diff
*/
@ReadOnly
@Parameters(commandNames = "format-patch", commandDescription = "Creates a patch with a set of changes")
public class FormatPatch extends AbstractCommand implements CLICommand {
@Parameter(description = "[<commit> [<commit>]] [-- <path>...]", arity = 2)
private List<String> refSpec = Lists.newArrayList();
@Parameter(names = "--", hidden = true, variableArity = true)
private List<String> paths = Lists.newArrayList();
@Parameter(names = { "-f", "--file" }, description = "The patch file")
private String file;
@Parameter(names = "--cached", description = "compares the specified tree (commit, branch, etc) and the staging area")
private boolean cached;
/**
* Executes the format-patch command with the specified options.
*/
@Override
protected void runInternal(GeogigCLI cli) throws IOException {
checkParameter(refSpec.size() < 3, "Commit list is too long :%s", refSpec);
GeoGIG geogig = cli.getGeogig();
checkParameter(file != null, "Patch file not specified");
DiffOp diff = geogig.command(DiffOp.class).setReportTrees(true);
String oldVersion = resolveOldVersion();
String newVersion = resolveNewVersion();
diff.setOldVersion(oldVersion).setNewVersion(newVersion).setCompareIndex(cached);
Iterator<DiffEntry> entries;
if (paths.isEmpty()) {
entries = diff.setProgressListener(cli.getProgressListener()).call();
} else {
entries = Iterators.emptyIterator();
for (String path : paths) {
Iterator<DiffEntry> moreEntries = diff.setFilter(path)
.setProgressListener(cli.getProgressListener()).call();
entries = Iterators.concat(entries, moreEntries);
}
}
if (!entries.hasNext()) {
cli.getConsole().println("No differences found");
return;
}
Patch patch = geogig.command(CreatePatchOp.class).setDiffs(entries).call();
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8");
PatchSerializer.write(out, patch);
}
private String resolveOldVersion() {
return refSpec.size() > 0 ? refSpec.get(0) : null;
}
private String resolveNewVersion() {
return refSpec.size() > 1 ? refSpec.get(1) : null;
}
}