use of org.locationtech.geogig.api.ProgressListener 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.ProgressListener in project GeoGig by boundlessgeo.
the class WriteTree2 method _call.
/**
* Executes the write tree operation.
*
* @return the new root tree id, the current HEAD tree id if there are no differences between
* the index and the HEAD, or {@code null} if the operation has been cancelled (as
* indicated by the {@link #getProgressListener() progress listener}.
*/
@Override
protected ObjectId _call() {
final ProgressListener progress = getProgressListener();
TreeDifference treeDifference = computeTreeDifference();
if (treeDifference.areEqual()) {
MutableTree leftTree = treeDifference.getLeftTree();
Node leftNode = leftTree.getNode();
ObjectId leftOid = leftNode.getObjectId();
return leftOid;
}
final MutableTree oldLeftTree = treeDifference.getLeftTree().clone();
Preconditions.checkState(oldLeftTree.equals(treeDifference.getLeftTree()));
// handle renames before new and deleted trees for the computation of new and deleted to be
// accurate
Set<String> ignoreList = Sets.newHashSet();
handleRenames(treeDifference, ignoreList);
handlePureMetadataChanges(treeDifference, ignoreList);
handleNewTrees(treeDifference, ignoreList);
handleDeletedTrees(treeDifference, ignoreList);
handleRemainingDifferences(treeDifference, ignoreList);
progress.complete();
MutableTree newLeftTree = treeDifference.getLeftTree();
final ObjectDatabase repositoryDatabase = objectDatabase();
final RevTree newRoot = newLeftTree.build(stagingDatabase(), repositoryDatabase);
if (newRoot.trees().isPresent()) {
for (Node n : newRoot.trees().get()) {
if (n.getMetadataId().isPresent())
deepMove(n.getMetadataId().get());
}
}
ObjectId newRootId = newRoot.getId();
return newRootId;
}
use of org.locationtech.geogig.api.ProgressListener in project GeoGig by boundlessgeo.
the class CommitOpTest method testCancel.
@Test
public void testCancel() throws Exception {
ProgressListener listener1 = mock(ProgressListener.class);
when(listener1.isCanceled()).thenReturn(true);
ProgressListener listener2 = mock(ProgressListener.class);
when(listener2.isCanceled()).thenReturn(false, true);
ProgressListener listener3 = mock(ProgressListener.class);
when(listener3.isCanceled()).thenReturn(false, false, true);
try {
geogig.command(AddOp.class).addPattern(".").call();
geogig.command(CommitOp.class).call();
fail("expected NothingToCommitException");
} catch (NothingToCommitException e) {
assertTrue(true);
}
CommitOp commitCommand1 = geogig.command(CommitOp.class);
commitCommand1.setProgressListener(listener1);
assertNull(commitCommand1.setAllowEmpty(true).call());
CommitOp commitCommand2 = geogig.command(CommitOp.class);
commitCommand2.setProgressListener(listener2);
assertNull(commitCommand2.setAllowEmpty(true).call());
CommitOp commitCommand3 = geogig.command(CommitOp.class);
commitCommand3.setProgressListener(listener3);
assertNull(commitCommand3.setAllowEmpty(true).call());
}
use of org.locationtech.geogig.api.ProgressListener in project GeoGig by boundlessgeo.
the class OSMImportOp method parseDataFileAndInsert.
private OSMReport parseDataFileAndInsert(@Nullable File file, final InputStream dataIn, final EntityConverter converter) {
final boolean pbf;
final CompressionMethod compression;
if (file == null) {
pbf = false;
compression = CompressionMethod.None;
} else {
pbf = file.getName().endsWith(".pbf");
compression = resolveCompressionMethod(file);
}
RunnableSource reader;
if (pbf) {
reader = new OsmosisReader(dataIn);
} else {
reader = new org.locationtech.geogig.osm.internal.XmlReader(dataIn, true, compression);
}
final WorkingTree workTree = workingTree();
if (!add) {
workTree.delete(OSMUtils.NODE_TYPE_NAME);
workTree.delete(OSMUtils.WAY_TYPE_NAME);
}
final int queueCapacity = 100 * 1000;
final int timeout = 1;
final TimeUnit timeoutUnit = TimeUnit.SECONDS;
// With this iterator and the osm parsing happening on a separate thread, we follow a
// producer/consumer approach so that the osm parse thread produces featrures into the
// iterator's queue, and WorkingTree.insert consumes them on this thread
QueueIterator<Feature> iterator = new QueueIterator<Feature>(queueCapacity, timeout, timeoutUnit);
ProgressListener progressListener = getProgressListener();
ConvertAndImportSink sink = new ConvertAndImportSink(converter, iterator, platform(), mapping, noRaw, new SubProgressListener(progressListener, 100));
reader.setSink(sink);
Thread readerThread = new Thread(reader, "osm-import-reader-thread");
readerThread.start();
Function<Feature, String> parentTreePathResolver = new Function<Feature, String>() {
@Override
public String apply(Feature input) {
if (input instanceof MappedFeature) {
return ((MappedFeature) input).getPath();
}
return input.getType().getName().getLocalPart();
}
};
// used to set the task status name, but report no progress so it does not interfere
// with the progress reported by the reader thread
SubProgressListener noPorgressReportingListener = new SubProgressListener(progressListener, 0) {
@Override
public void setProgress(float progress) {
// no-op
}
};
workTree.insert(parentTreePathResolver, iterator, noPorgressReportingListener, null, null);
if (sink.getCount() == 0) {
throw new EmptyOSMDownloadException();
}
OSMReport report = new OSMReport(sink.getCount(), sink.getNodeCount(), sink.getWayCount(), sink.getUnprocessedCount(), sink.getLatestChangeset(), sink.getLatestTimestamp());
return report;
}
use of org.locationtech.geogig.api.ProgressListener in project GeoGig by boundlessgeo.
the class OSMHistoryImport method commit.
/**
* @param cli
* @param changeset
* @throws IOException
*/
private void commit(GeogigCLI cli, Changeset changeset) throws IOException {
Preconditions.checkArgument(!changeset.isOpen());
ConsoleReader console = cli.getConsole();
console.print("Committing changeset " + changeset.getId() + "...");
console.flush();
GeoGIG geogig = cli.getGeogig();
CommitOp command = geogig.command(CommitOp.class);
command.setAllowEmpty(true);
String message = "";
if (changeset.getComment().isPresent()) {
message = changeset.getComment().get() + "\nchangeset " + changeset.getId();
} else {
message = "changeset " + changeset.getId();
}
command.setMessage(message);
final String userName = changeset.getUserName();
command.setAuthor(userName, null);
command.setAuthorTimestamp(changeset.getCreated());
// osm timestamps are in GMT
command.setAuthorTimeZoneOffset(0);
if (userName != null) {
command.setCommitter(userName, null);
}
command.setCommitterTimestamp(changeset.getClosed().get());
// osm timestamps are in GMT
command.setCommitterTimeZoneOffset(0);
ProgressListener listener = cli.getProgressListener();
listener.setProgress(0f);
listener.started();
command.setProgressListener(listener);
try {
RevCommit commit = command.call();
Ref head = geogig.command(RefParse.class).setName(Ref.HEAD).call().get();
Preconditions.checkState(commit.getId().equals(head.getObjectId()));
updateBranchChangeset(geogig, changeset.getId());
listener.complete();
console.println("Commit " + commit.getId().toString());
console.flush();
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
Aggregations