use of org.locationtech.geogig.api.plumbing.diff.DiffEntry in project GeoGig by boundlessgeo.
the class Diff method runInternal.
/**
* Executes the diff command with the specified options.
*/
@Override
protected void runInternal(GeogigCLI cli) throws IOException {
checkParameter(refSpec.size() <= 2, "Commit list is too long :%s", refSpec);
checkParameter(!(nogeom && summary), "Only one printing mode allowed");
checkParameter(!(bounds && count), "Only one of --bounds or --count is allowed");
checkParameter(!(cached && refSpec.size() > 1), "--cached allows zero or one ref specs to compare the index with.");
GeoGIG geogig = cli.getGeogig();
String oldVersion = resolveOldVersion();
String newVersion = resolveNewVersion();
List<String> paths = removeEmptyPaths();
if (bounds) {
DiffBounds diff = geogig.command(DiffBounds.class).setOldVersion(oldVersion).setNewVersion(newVersion).setCompareIndex(cached);
diff.setPathFilters(paths);
CoordinateReferenceSystem crs = parseCrs();
if (crs != null) {
diff.setCRS(crs);
}
DiffSummary<BoundingBox, BoundingBox> diffBounds = diff.call();
BoundsDiffPrinter.print(geogig, cli.getConsole(), diffBounds);
return;
}
if (count) {
if (oldVersion == null) {
oldVersion = Ref.HEAD;
}
if (newVersion == null) {
newVersion = cached ? Ref.STAGE_HEAD : Ref.WORK_HEAD;
}
DiffCount cdiff = geogig.command(DiffCount.class).setOldVersion(oldVersion).setNewVersion(newVersion);
cdiff.setFilter(paths);
DiffObjectCount count = cdiff.call();
ConsoleReader console = cli.getConsole();
console.println(String.format("Trees changed: %d, features changed: %,d", count.treeCount(), count.featureCount()));
console.flush();
return;
}
DiffOp diff = geogig.command(DiffOp.class);
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;
}
DiffPrinter printer;
if (summary) {
printer = new SummaryDiffPrinter();
} else {
printer = new FullDiffPrinter(nogeom, false);
}
DiffEntry entry;
while (entries.hasNext()) {
entry = entries.next();
printer.print(geogig, cli.getConsole(), entry);
}
}
use of org.locationtech.geogig.api.plumbing.diff.DiffEntry in project GeoGig by boundlessgeo.
the class ApplyPatchOpTest method testModifyFeatureAttributePatch.
@Test
public void testModifyFeatureAttributePatch() throws Exception {
insert(points1);
Patch patch = new Patch();
String path = NodeRef.appendChild(pointsName, points1.getIdentifier().getID());
Map<PropertyDescriptor, AttributeDiff> map = Maps.newHashMap();
Optional<?> oldValue = Optional.fromNullable(points1.getProperty("sp").getValue());
GenericAttributeDiffImpl diff = new GenericAttributeDiffImpl(oldValue, Optional.of("new"));
map.put(pointsType.getDescriptor("sp"), diff);
FeatureDiff feaureDiff = new FeatureDiff(path, map, RevFeatureTypeImpl.build(pointsType), RevFeatureTypeImpl.build(pointsType));
patch.addModifiedFeature(feaureDiff);
geogig.command(ApplyPatchOp.class).setPatch(patch).call();
RevTree root = repo.workingTree().getTree();
Optional<Node> featureBlobId = findTreeChild(root, path);
assertTrue(featureBlobId.isPresent());
Iterator<DiffEntry> unstaged = repo.workingTree().getUnstaged(pointsName);
ArrayList<DiffEntry> diffs = Lists.newArrayList(unstaged);
assertEquals(2, diffs.size());
Optional<RevFeature> feature = geogig.command(RevObjectParse.class).setRefSpec("WORK_HEAD:" + path).call(RevFeature.class);
assertTrue(feature.isPresent());
ImmutableList<Optional<Object>> values = feature.get().getValues();
assertEquals("new", values.get(0).get());
}
use of org.locationtech.geogig.api.plumbing.diff.DiffEntry in project GeoGig by boundlessgeo.
the class MergeOp method _call.
/**
* Executes the merge operation.
*
* @return always {@code true}
*/
@Override
protected MergeReport _call() throws RuntimeException {
Preconditions.checkArgument(commits.size() > 0, "No commits specified for merge.");
Preconditions.checkArgument(!(ours && theirs), "Cannot use both --ours and --theirs.");
final Optional<Ref> currHead = command(RefParse.class).setName(Ref.HEAD).call();
Preconditions.checkState(currHead.isPresent(), "Repository has no HEAD, can't rebase.");
Ref headRef = currHead.get();
ObjectId oursId = headRef.getObjectId();
// Preconditions.checkState(currHead.get() instanceof SymRef,
// "Can't rebase from detached HEAD");
// SymRef headRef = (SymRef) currHead.get();
// final String currentBranch = headRef.getTarget();
getProgressListener().started();
boolean fastForward = true;
boolean changed = false;
Optional<MergeScenarioReport> mergeScenario = Optional.absent();
List<CommitAncestorPair> pairs = Lists.newArrayList();
boolean hasConflictsOrAutomerge;
List<RevCommit> revCommits = Lists.newArrayList();
if (!ObjectId.NULL.equals(headRef.getObjectId())) {
revCommits.add(repository().getCommit(headRef.getObjectId()));
}
for (ObjectId commitId : commits) {
revCommits.add(repository().getCommit(commitId));
}
hasConflictsOrAutomerge = command(CheckMergeScenarioOp.class).setCommits(revCommits).call().booleanValue();
if (hasConflictsOrAutomerge && !theirs) {
Preconditions.checkState(commits.size() < 2, "Conflicted merge.\nCannot merge more than two commits when conflicts exist" + " or features have been modified in several histories");
RevCommit headCommit = repository().getCommit(headRef.getObjectId());
ObjectId commitId = commits.get(0);
Preconditions.checkArgument(!ObjectId.NULL.equals(commitId), "Cannot merge a NULL commit.");
Preconditions.checkArgument(repository().commitExists(commitId), "Not a valid commit: " + commitId.toString());
final RevCommit targetCommit = repository().getCommit(commitId);
Optional<ObjectId> ancestorCommit = command(FindCommonAncestor.class).setLeft(headCommit).setRight(targetCommit).call();
pairs.add(new CommitAncestorPair(commitId, ancestorCommit.get()));
mergeScenario = Optional.of(command(ReportMergeScenarioOp.class).setMergeIntoCommit(headCommit).setToMergeCommit(targetCommit).call());
List<FeatureInfo> merged = mergeScenario.get().getMerged();
for (FeatureInfo feature : merged) {
this.workingTree().insert(NodeRef.parentPath(feature.getPath()), feature.getFeature());
Iterator<DiffEntry> unstaged = workingTree().getUnstaged(null);
index().stage(getProgressListener(), unstaged, 0);
changed = true;
fastForward = false;
}
List<DiffEntry> unconflicting = mergeScenario.get().getUnconflicted();
if (!unconflicting.isEmpty()) {
index().stage(getProgressListener(), unconflicting.iterator(), 0);
changed = true;
fastForward = false;
}
workingTree().updateWorkHead(index().getTree().getId());
List<Conflict> conflicts = mergeScenario.get().getConflicts();
if (!ours && !conflicts.isEmpty()) {
// In case we use the "ours" strategy, we do nothing. We ignore conflicting
// changes and leave the current elements
command(UpdateRef.class).setName(Ref.MERGE_HEAD).setNewValue(commitId).call();
command(UpdateRef.class).setName(Ref.ORIG_HEAD).setNewValue(headCommit.getId()).call();
command(ConflictsWriteOp.class).setConflicts(conflicts).call();
StringBuilder msg = new StringBuilder();
Optional<Ref> ref = command(ResolveBranchId.class).setObjectId(commitId).call();
if (ref.isPresent()) {
msg.append("Merge branch " + ref.get().getName());
} else {
msg.append("Merge commit '" + commitId.toString() + "'. ");
}
msg.append("\n\nConflicts:\n");
for (Conflict conflict : mergeScenario.get().getConflicts()) {
msg.append("\t" + conflict.getPath() + "\n");
}
command(SaveMergeCommitMessageOp.class).setMessage(msg.toString()).call();
StringBuilder sb = new StringBuilder();
for (Conflict conflict : conflicts) {
sb.append("CONFLICT: Merge conflict in " + conflict.getPath() + "\n");
}
sb.append("Automatic merge failed. Fix conflicts and then commit the result.\n");
throw new MergeConflictsException(sb.toString(), headCommit.getId(), commitId);
}
} else {
Preconditions.checkState(!hasConflictsOrAutomerge || commits.size() < 2, "Conflicted merge.\nCannot merge more than two commits when conflicts exist" + " or features have been modified in several histories");
for (ObjectId commitId : commits) {
ProgressListener subProgress = subProgress(100.f / commits.size());
Preconditions.checkArgument(!ObjectId.NULL.equals(commitId), "Cannot merge a NULL commit.");
Preconditions.checkArgument(repository().commitExists(commitId), "Not a valid commit: " + commitId.toString());
subProgress.started();
if (ObjectId.NULL.equals(headRef.getObjectId())) {
// Fast-forward
if (headRef instanceof SymRef) {
final String currentBranch = ((SymRef) headRef).getTarget();
command(UpdateRef.class).setName(currentBranch).setNewValue(commitId).call();
headRef = (SymRef) command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(currentBranch).call().get();
} else {
headRef = command(UpdateRef.class).setName(headRef.getName()).setNewValue(commitId).call().get();
}
workingTree().updateWorkHead(commitId);
index().updateStageHead(commitId);
subProgress.complete();
changed = true;
continue;
}
RevCommit headCommit = repository().getCommit(headRef.getObjectId());
final RevCommit targetCommit = repository().getCommit(commitId);
Optional<ObjectId> ancestorCommit = command(FindCommonAncestor.class).setLeft(headCommit).setRight(targetCommit).call();
pairs.add(new CommitAncestorPair(commitId, ancestorCommit.get()));
subProgress.setProgress(10.f);
Preconditions.checkState(ancestorCommit.isPresent(), "No ancestor commit could be found.");
if (commits.size() == 1) {
mergeScenario = Optional.of(command(ReportMergeScenarioOp.class).setMergeIntoCommit(headCommit).setToMergeCommit(targetCommit).call());
if (ancestorCommit.get().equals(headCommit.getId())) {
// Fast-forward
if (headRef instanceof SymRef) {
final String currentBranch = ((SymRef) headRef).getTarget();
command(UpdateRef.class).setName(currentBranch).setNewValue(commitId).call();
headRef = (SymRef) command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(currentBranch).call().get();
} else {
headRef = command(UpdateRef.class).setName(headRef.getName()).setNewValue(commitId).call().get();
}
workingTree().updateWorkHead(commitId);
index().updateStageHead(commitId);
subProgress.complete();
changed = true;
continue;
} else if (ancestorCommit.get().equals(commitId)) {
continue;
}
}
// get changes
Iterator<DiffEntry> diff = command(DiffTree.class).setOldTree(ancestorCommit.get()).setNewTree(targetCommit.getId()).setReportTrees(true).call();
// stage changes
index().stage(new SubProgressListener(subProgress, 100.f), diff, 0);
changed = true;
fastForward = false;
workingTree().updateWorkHead(index().getTree().getId());
subProgress.complete();
}
}
if (!changed) {
throw new NothingToCommitException("The branch has already been merged.");
}
RevCommit mergeCommit = commit(fastForward);
MergeReport result = new MergeReport(mergeCommit, mergeScenario, oursId, pairs);
return result;
}
use of org.locationtech.geogig.api.plumbing.diff.DiffEntry in project GeoGig by boundlessgeo.
the class RebaseOp method applyCommit.
/**
* Applies the passed command.
*
* @param commitToApply the commit to apply
* @param useCommitChanges if true, applies the command completely, staging its changes before
* committing. If false, it commits the currently staged changes, ignoring the changes in
* the commit and using just its author and message
*/
private void applyCommit(RevCommit commitToApply, boolean useCommitChanges) {
Repository repository = repository();
Platform platform = platform();
if (useCommitChanges) {
ObjectId parentTreeId;
ObjectId parentCommitId = ObjectId.NULL;
if (commitToApply.getParentIds().size() > 0) {
parentCommitId = commitToApply.getParentIds().get(0);
}
parentTreeId = ObjectId.NULL;
if (repository.commitExists(parentCommitId)) {
parentTreeId = repository.getCommit(parentCommitId).getTreeId();
}
// get changes
Iterator<DiffEntry> diff = command(DiffTree.class).setOldTree(parentTreeId).setNewTree(commitToApply.getTreeId()).setReportTrees(true).call();
// see if there are conflicts
MergeScenarioReport report = command(ReportCommitConflictsOp.class).setCommit(commitToApply).call();
if (report.getConflicts().isEmpty()) {
// stage changes
index().stage(getProgressListener(), diff, 0);
// write new tree
ObjectId newTreeId = command(WriteTree2.class).call();
long timestamp = platform.currentTimeMillis();
// Create new commit
CommitBuilder builder = new CommitBuilder(commitToApply);
builder.setParentIds(Arrays.asList(rebaseHead));
builder.setTreeId(newTreeId);
builder.setCommitterTimestamp(timestamp);
builder.setCommitterTimeZoneOffset(platform.timeZoneOffset(timestamp));
RevCommit newCommit = builder.build();
repository.objectDatabase().put(newCommit);
rebaseHead = newCommit.getId();
command(UpdateRef.class).setName(currentBranch).setNewValue(rebaseHead).call();
command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(currentBranch).call();
workingTree().updateWorkHead(newTreeId);
index().updateStageHead(newTreeId);
} else {
Iterator<DiffEntry> unconflicted = report.getUnconflicted().iterator();
// stage unconflicted changes
index().stage(getProgressListener(), unconflicted, 0);
workingTree().updateWorkHead(index().getTree().getId());
// mark conflicted elements
command(ConflictsWriteOp.class).setConflicts(report.getConflicts()).call();
// created exception message
StringBuilder msg = new StringBuilder();
msg.append("error: could not apply ");
msg.append(commitToApply.getId().toString().substring(0, 7));
msg.append(" " + commitToApply.getMessage() + "\n");
for (Conflict conflict : report.getConflicts()) {
msg.append("CONFLICT: conflict in " + conflict.getPath() + "\n");
}
File branchFile = new File(getRebaseFolder(), "branch");
try {
Files.write(currentBranch, branchFile, Charsets.UTF_8);
} catch (IOException e) {
throw new IllegalStateException("Cannot create current branch info file");
}
throw new RebaseConflictsException(msg.toString());
}
} else {
// write new tree
ObjectId newTreeId = command(WriteTree2.class).call();
long timestamp = platform.currentTimeMillis();
// Create new commit
CommitBuilder builder = new CommitBuilder(commitToApply);
builder.setParentIds(Arrays.asList(rebaseHead));
builder.setTreeId(newTreeId);
builder.setCommitterTimestamp(timestamp);
builder.setCommitterTimeZoneOffset(platform.timeZoneOffset(timestamp));
RevCommit newCommit = builder.build();
repository.objectDatabase().put(newCommit);
rebaseHead = newCommit.getId();
command(UpdateRef.class).setName(currentBranch).setNewValue(rebaseHead).call();
command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(currentBranch).call();
workingTree().updateWorkHead(newTreeId);
index().updateStageHead(newTreeId);
}
}
use of org.locationtech.geogig.api.plumbing.diff.DiffEntry in project GeoGig by boundlessgeo.
the class RevertOp method applyRevertedChanges.
private List<Conflict> applyRevertedChanges(RevCommit commit) {
ObjectId parentCommitId = ObjectId.NULL;
if (commit.getParentIds().size() > 0) {
parentCommitId = commit.getParentIds().get(0);
}
ObjectId parentTreeId = ObjectId.NULL;
Repository repository = repository();
if (repository.commitExists(parentCommitId)) {
parentTreeId = repository.getCommit(parentCommitId).getTreeId();
}
// get changes (in reverse)
Iterator<DiffEntry> reverseDiff = command(DiffTree.class).setNewTree(parentTreeId).setOldTree(commit.getTreeId()).setReportTrees(false).call();
ObjectId headTreeId = repository.getCommit(revertHead).getTreeId();
final RevTree headTree = repository.getTree(headTreeId);
ArrayList<Conflict> conflicts = new ArrayList<Conflict>();
DiffEntry diff;
while (reverseDiff.hasNext()) {
diff = reverseDiff.next();
if (diff.isAdd()) {
// Feature was deleted
Optional<NodeRef> node = command(FindTreeChild.class).setChildPath(diff.newPath()).setIndex(true).setParent(headTree).call();
// make sure it is still deleted
if (node.isPresent()) {
conflicts.add(new Conflict(diff.newPath(), diff.oldObjectId(), node.get().objectId(), diff.newObjectId()));
} else {
index().stage(getProgressListener(), Iterators.singletonIterator(diff), 1);
}
} else {
// Feature was added or modified
Optional<NodeRef> node = command(FindTreeChild.class).setChildPath(diff.oldPath()).setIndex(true).setParent(headTree).call();
ObjectId nodeId = node.get().getNode().getObjectId();
// Make sure it wasn't changed
if (node.isPresent() && nodeId.equals(diff.oldObjectId())) {
index().stage(getProgressListener(), Iterators.singletonIterator(diff), 1);
} else {
// do not mark as conflict if reverting to the same feature currently in HEAD
if (!nodeId.equals(diff.newObjectId())) {
conflicts.add(new Conflict(diff.newPath(), diff.oldObjectId(), node.get().objectId(), diff.newObjectId()));
}
}
}
}
return conflicts;
}
Aggregations