Search in sources :

Example 1 with SubProgressListener

use of org.locationtech.geogig.api.SubProgressListener 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;
}
Also used : ReportMergeScenarioOp(org.locationtech.geogig.api.plumbing.merge.ReportMergeScenarioOp) SubProgressListener(org.locationtech.geogig.api.SubProgressListener) FeatureInfo(org.locationtech.geogig.api.FeatureInfo) MergeScenarioReport(org.locationtech.geogig.api.plumbing.merge.MergeScenarioReport) UpdateSymRef(org.locationtech.geogig.api.plumbing.UpdateSymRef) SymRef(org.locationtech.geogig.api.SymRef) RevCommit(org.locationtech.geogig.api.RevCommit) DiffEntry(org.locationtech.geogig.api.plumbing.diff.DiffEntry) ObjectId(org.locationtech.geogig.api.ObjectId) UpdateRef(org.locationtech.geogig.api.plumbing.UpdateRef) UpdateRef(org.locationtech.geogig.api.plumbing.UpdateRef) UpdateSymRef(org.locationtech.geogig.api.plumbing.UpdateSymRef) Ref(org.locationtech.geogig.api.Ref) SymRef(org.locationtech.geogig.api.SymRef) NodeRef(org.locationtech.geogig.api.NodeRef) ProgressListener(org.locationtech.geogig.api.ProgressListener) SubProgressListener(org.locationtech.geogig.api.SubProgressListener) Conflict(org.locationtech.geogig.api.plumbing.merge.Conflict) FindCommonAncestor(org.locationtech.geogig.api.plumbing.FindCommonAncestor)

Example 2 with SubProgressListener

use of org.locationtech.geogig.api.SubProgressListener 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;
}
Also used : SubProgressListener(org.locationtech.geogig.api.SubProgressListener) LineString(com.vividsolutions.jts.geom.LineString) Feature(org.opengis.feature.Feature) RunnableSource(org.openstreetmap.osmosis.core.task.v0_6.RunnableSource) Point(com.vividsolutions.jts.geom.Point) WorkingTree(org.locationtech.geogig.repository.WorkingTree) Function(com.google.common.base.Function) ProgressListener(org.locationtech.geogig.api.ProgressListener) SubProgressListener(org.locationtech.geogig.api.SubProgressListener) CompressionMethod(org.openstreetmap.osmosis.xml.common.CompressionMethod) TimeUnit(java.util.concurrent.TimeUnit) OsmosisReader(crosby.binary.osmosis.OsmosisReader)

Example 3 with SubProgressListener

use of org.locationtech.geogig.api.SubProgressListener in project GeoGig by boundlessgeo.

the class OSMApplyDiffOp method parseDiffFileAndInsert.

public OSMReport parseDiffFileAndInsert() {
    final WorkingTree workTree = workingTree();
    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 features into the
    // iterator's queue, and WorkingTree.insert consumes them on this thread
    QueueIterator<Feature> target = new QueueIterator<Feature>(queueCapacity, timeout, timeoutUnit);
    XmlChangeReader reader = new XmlChangeReader(file, true, resolveCompressionMethod(file));
    ProgressListener progressListener = getProgressListener();
    ConvertAndImportSink sink = new ConvertAndImportSink(target, context, workingTree(), platform(), new SubProgressListener(progressListener, 100));
    reader.setChangeSink(sink);
    Thread readerThread = new Thread(reader, "osm-diff-reader-thread");
    readerThread.start();
    // 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 noProgressReportingListener = new SubProgressListener(progressListener, 0) {

        @Override
        public void setProgress(float progress) {
        // no-op
        }
    };
    Function<Feature, String> parentTreePathResolver = new Function<Feature, String>() {

        @Override
        public String apply(Feature input) {
            return input.getType().getName().getLocalPart();
        }
    };
    workTree.insert(parentTreePathResolver, target, noProgressReportingListener, null, null);
    OSMReport report = new OSMReport(sink.getCount(), sink.getNodeCount(), sink.getWayCount(), sink.getUnprocessedCount(), sink.getLatestChangeset(), sink.getLatestTimestamp());
    return report;
}
Also used : SubProgressListener(org.locationtech.geogig.api.SubProgressListener) LineString(com.vividsolutions.jts.geom.LineString) Feature(org.opengis.feature.Feature) Point(com.vividsolutions.jts.geom.Point) WorkingTree(org.locationtech.geogig.repository.WorkingTree) Function(com.google.common.base.Function) ProgressListener(org.locationtech.geogig.api.ProgressListener) SubProgressListener(org.locationtech.geogig.api.SubProgressListener) XmlChangeReader(org.openstreetmap.osmosis.xml.v0_6.XmlChangeReader) TimeUnit(java.util.concurrent.TimeUnit)

Aggregations

ProgressListener (org.locationtech.geogig.api.ProgressListener)3 SubProgressListener (org.locationtech.geogig.api.SubProgressListener)3 Function (com.google.common.base.Function)2 LineString (com.vividsolutions.jts.geom.LineString)2 Point (com.vividsolutions.jts.geom.Point)2 TimeUnit (java.util.concurrent.TimeUnit)2 WorkingTree (org.locationtech.geogig.repository.WorkingTree)2 Feature (org.opengis.feature.Feature)2 OsmosisReader (crosby.binary.osmosis.OsmosisReader)1 FeatureInfo (org.locationtech.geogig.api.FeatureInfo)1 NodeRef (org.locationtech.geogig.api.NodeRef)1 ObjectId (org.locationtech.geogig.api.ObjectId)1 Ref (org.locationtech.geogig.api.Ref)1 RevCommit (org.locationtech.geogig.api.RevCommit)1 SymRef (org.locationtech.geogig.api.SymRef)1 FindCommonAncestor (org.locationtech.geogig.api.plumbing.FindCommonAncestor)1 UpdateRef (org.locationtech.geogig.api.plumbing.UpdateRef)1 UpdateSymRef (org.locationtech.geogig.api.plumbing.UpdateSymRef)1 DiffEntry (org.locationtech.geogig.api.plumbing.diff.DiffEntry)1 Conflict (org.locationtech.geogig.api.plumbing.merge.Conflict)1