Search in sources :

Example 11 with RevTreeBuilder

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

the class CheckoutOp method _call.

/**
     * @return the id of the new work tree
     */
@Override
protected CheckoutResult _call() {
    checkState(branchOrCommit != null || !paths.isEmpty(), "No branch, tree, or path were specified");
    checkArgument(!(ours && theirs), "Cannot use both --ours and --theirs.");
    checkArgument((ours == theirs) || branchOrCommit == null, "--ours/--theirs is incompatible with switching branches.");
    CheckoutResult result = new CheckoutResult();
    List<Conflict> conflicts = stagingDatabase().getConflicts(null, null);
    if (!paths.isEmpty()) {
        result.setResult(CheckoutResult.Results.UPDATE_OBJECTS);
        Optional<RevTree> tree = Optional.absent();
        List<String> unmerged = lookForUnmerged(conflicts, paths);
        if (!unmerged.isEmpty()) {
            if (!(force || ours || theirs)) {
                StringBuilder msg = new StringBuilder();
                for (String path : unmerged) {
                    msg.append("error: path " + path + " is unmerged.\n");
                }
                throw new CheckoutException(msg.toString(), StatusCode.UNMERGED_PATHS);
            }
        }
        if (branchOrCommit != null) {
            Optional<ObjectId> id = command(ResolveTreeish.class).setTreeish(branchOrCommit).call();
            checkState(id.isPresent(), "'" + branchOrCommit + "' not found in repository.");
            tree = command(RevObjectParse.class).setObjectId(id.get()).call(RevTree.class);
        } else {
            tree = Optional.of(index().getTree());
        }
        Optional<RevTree> mainTree = tree;
        for (String st : paths) {
            if (unmerged.contains(st)) {
                if (ours || theirs) {
                    String refspec = ours ? Ref.ORIG_HEAD : Ref.MERGE_HEAD;
                    Optional<ObjectId> treeId = command(ResolveTreeish.class).setTreeish(refspec).call();
                    if (treeId.isPresent()) {
                        tree = command(RevObjectParse.class).setObjectId(treeId.get()).call(RevTree.class);
                    }
                } else {
                    // --force
                    continue;
                }
            } else {
                tree = mainTree;
            }
            Optional<NodeRef> node = command(FindTreeChild.class).setParent(tree.get()).setIndex(true).setChildPath(st).call();
            if ((ours || theirs) && !node.isPresent()) {
                // remove the node.
                command(RemoveOp.class).addPathToRemove(st).call();
            } else {
                checkState(node.isPresent(), "pathspec '" + st + "' didn't match a feature in the tree");
                if (node.get().getType() == TYPE.TREE) {
                    RevTreeBuilder treeBuilder = new RevTreeBuilder(stagingDatabase(), workingTree().getTree());
                    treeBuilder.remove(st);
                    treeBuilder.put(node.get().getNode());
                    RevTree newRoot = treeBuilder.build();
                    stagingDatabase().put(newRoot);
                    workingTree().updateWorkHead(newRoot.getId());
                } else {
                    ObjectId metadataId = ObjectId.NULL;
                    Optional<NodeRef> parentNode = command(FindTreeChild.class).setParent(workingTree().getTree()).setChildPath(node.get().getParentPath()).setIndex(true).call();
                    RevTreeBuilder treeBuilder = null;
                    if (parentNode.isPresent()) {
                        metadataId = parentNode.get().getMetadataId();
                        Optional<RevTree> parsed = command(RevObjectParse.class).setObjectId(parentNode.get().getNode().getObjectId()).call(RevTree.class);
                        checkState(parsed.isPresent(), "Parent tree couldn't be found in the repository.");
                        treeBuilder = new RevTreeBuilder(stagingDatabase(), parsed.get());
                        treeBuilder.remove(node.get().getNode().getName());
                    } else {
                        treeBuilder = new RevTreeBuilder(stagingDatabase());
                    }
                    treeBuilder.put(node.get().getNode());
                    ObjectId newTreeId = command(WriteBack.class).setAncestor(workingTree().getTree().builder(stagingDatabase())).setChildPath(node.get().getParentPath()).setToIndex(true).setTree(treeBuilder.build()).setMetadataId(metadataId).call();
                    workingTree().updateWorkHead(newTreeId);
                }
            }
        }
    } else {
        if (!conflicts.isEmpty()) {
            if (!(force)) {
                StringBuilder msg = new StringBuilder();
                for (Conflict conflict : conflicts) {
                    msg.append("error: " + conflict.getPath() + " needs merge.\n");
                }
                msg.append("You need to resolve your index first.\n");
                throw new CheckoutException(msg.toString(), StatusCode.UNMERGED_PATHS);
            }
        }
        Optional<Ref> targetRef = Optional.absent();
        Optional<ObjectId> targetCommitId = Optional.absent();
        Optional<ObjectId> targetTreeId = Optional.absent();
        targetRef = command(RefParse.class).setName(branchOrCommit).call();
        if (targetRef.isPresent()) {
            ObjectId commitId = targetRef.get().getObjectId();
            if (targetRef.get().getName().startsWith(Ref.REMOTES_PREFIX)) {
                String remoteName = targetRef.get().getName();
                remoteName = remoteName.substring(Ref.REMOTES_PREFIX.length(), targetRef.get().getName().lastIndexOf("/"));
                if (branchOrCommit.contains(remoteName + '/')) {
                    RevCommit commit = command(RevObjectParse.class).setObjectId(commitId).call(RevCommit.class).get();
                    targetTreeId = Optional.of(commit.getTreeId());
                    targetCommitId = Optional.of(commit.getId());
                    targetRef = Optional.absent();
                } else {
                    Ref branch = command(BranchCreateOp.class).setName(targetRef.get().localName()).setSource(commitId.toString()).call();
                    command(ConfigOp.class).setAction(ConfigAction.CONFIG_SET).setScope(ConfigScope.LOCAL).setName("branches." + branch.localName() + ".remote").setValue(remoteName).call();
                    command(ConfigOp.class).setAction(ConfigAction.CONFIG_SET).setScope(ConfigScope.LOCAL).setName("branches." + branch.localName() + ".merge").setValue(targetRef.get().getName()).call();
                    targetRef = Optional.of(branch);
                    result.setResult(CheckoutResult.Results.CHECKOUT_REMOTE_BRANCH);
                    result.setRemoteName(remoteName);
                }
            }
            if (commitId.isNull()) {
                targetTreeId = Optional.of(ObjectId.NULL);
                targetCommitId = Optional.of(ObjectId.NULL);
            } else {
                Optional<RevCommit> parsed = command(RevObjectParse.class).setObjectId(commitId).call(RevCommit.class);
                checkState(parsed.isPresent());
                checkState(parsed.get() instanceof RevCommit);
                RevCommit commit = parsed.get();
                targetCommitId = Optional.of(commit.getId());
                targetTreeId = Optional.of(commit.getTreeId());
            }
        } else {
            final Optional<ObjectId> addressed = command(RevParse.class).setRefSpec(branchOrCommit).call();
            checkArgument(addressed.isPresent(), "source '" + branchOrCommit + "' not found in repository");
            RevCommit commit = command(RevObjectParse.class).setObjectId(addressed.get()).call(RevCommit.class).get();
            targetTreeId = Optional.of(commit.getTreeId());
            targetCommitId = Optional.of(commit.getId());
        }
        if (targetTreeId.isPresent()) {
            if (!force) {
                if (!index().isClean() || !workingTree().isClean()) {
                    throw new CheckoutException(StatusCode.LOCAL_CHANGES_NOT_COMMITTED);
                }
            }
            // update work tree
            ObjectId treeId = targetTreeId.get();
            workingTree().updateWorkHead(treeId);
            index().updateStageHead(treeId);
            result.setNewTree(treeId);
            if (targetRef.isPresent()) {
                // update HEAD
                Ref target = targetRef.get();
                String refName;
                if (target instanceof SymRef) {
                    // beware of cyclic refs, peel symrefs
                    refName = ((SymRef) target).getTarget();
                } else {
                    refName = target.getName();
                }
                command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(refName).call();
                result.setNewRef(targetRef.get());
                result.setOid(targetCommitId.get());
                result.setResult(CheckoutResult.Results.CHECKOUT_LOCAL_BRANCH);
            } else {
                // set HEAD to a dettached state
                ObjectId commitId = targetCommitId.get();
                command(UpdateRef.class).setName(Ref.HEAD).setNewValue(commitId).call();
                result.setOid(commitId);
                result.setResult(CheckoutResult.Results.DETACHED_HEAD);
            }
            Optional<Ref> ref = command(RefParse.class).setName(Ref.MERGE_HEAD).call();
            if (ref.isPresent()) {
                command(UpdateRef.class).setName(Ref.MERGE_HEAD).setDelete(true).call();
            }
            return result;
        }
    }
    result.setNewTree(workingTree().getTree().getId());
    return result;
}
Also used : NodeRef(org.locationtech.geogig.api.NodeRef) UpdateSymRef(org.locationtech.geogig.api.plumbing.UpdateSymRef) UpdateSymRef(org.locationtech.geogig.api.plumbing.UpdateSymRef) SymRef(org.locationtech.geogig.api.SymRef) RefParse(org.locationtech.geogig.api.plumbing.RefParse) RevCommit(org.locationtech.geogig.api.RevCommit) ObjectId(org.locationtech.geogig.api.ObjectId) UpdateRef(org.locationtech.geogig.api.plumbing.UpdateRef) RevTreeBuilder(org.locationtech.geogig.api.RevTreeBuilder) 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) Conflict(org.locationtech.geogig.api.plumbing.merge.Conflict) CanRunDuringConflict(org.locationtech.geogig.di.CanRunDuringConflict) RevObjectParse(org.locationtech.geogig.api.plumbing.RevObjectParse) RevTree(org.locationtech.geogig.api.RevTree)

Example 12 with RevTreeBuilder

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

the class RevertFeatureWebOp method run.

/**
     * Runs the command and builds the appropriate response
     * 
     * @param context - the context to use for this command
     * 
     * @throws CommandSpecException
     */
@Override
public void run(CommandContext context) {
    if (this.getTransactionId() == null) {
        throw new CommandSpecException("No transaction was specified, revert feature requires a transaction to preserve the stability of the repository.");
    }
    final Context geogig = this.getCommandLocator(context);
    Optional<RevTree> newTree = Optional.absent();
    Optional<RevTree> oldTree = Optional.absent();
    // get tree from new commit
    Optional<ObjectId> treeId = geogig.command(ResolveTreeish.class).setTreeish(newCommitId).call();
    Preconditions.checkState(treeId.isPresent(), "New commit id did not resolve to a valid tree.");
    newTree = geogig.command(RevObjectParse.class).setRefSpec(treeId.get().toString()).call(RevTree.class);
    Preconditions.checkState(newTree.isPresent(), "Unable to read the new commit tree.");
    // get tree from old commit
    treeId = geogig.command(ResolveTreeish.class).setTreeish(oldCommitId).call();
    Preconditions.checkState(treeId.isPresent(), "Old commit id did not resolve to a valid tree.");
    oldTree = geogig.command(RevObjectParse.class).setRefSpec(treeId.get().toString()).call(RevTree.class);
    Preconditions.checkState(newTree.isPresent(), "Unable to read the old commit tree.");
    // get feature from old tree
    Optional<NodeRef> node = geogig.command(FindTreeChild.class).setParent(oldTree.get()).setIndex(true).setChildPath(featurePath).call();
    boolean delete = false;
    if (!node.isPresent()) {
        delete = true;
        node = geogig.command(FindTreeChild.class).setParent(newTree.get()).setIndex(true).setChildPath(featurePath).call();
        Preconditions.checkState(node.isPresent(), "The feature was not found in either commit tree.");
    }
    // get the new parent tree
    ObjectId metadataId = ObjectId.NULL;
    Optional<NodeRef> parentNode = geogig.command(FindTreeChild.class).setParent(newTree.get()).setChildPath(node.get().getParentPath()).setIndex(true).call();
    RevTreeBuilder treeBuilder = null;
    if (parentNode.isPresent()) {
        metadataId = parentNode.get().getMetadataId();
        Optional<RevTree> parsed = geogig.command(RevObjectParse.class).setObjectId(parentNode.get().getNode().getObjectId()).call(RevTree.class);
        checkState(parsed.isPresent(), "Parent tree couldn't be found in the repository.");
        treeBuilder = new RevTreeBuilder(geogig.stagingDatabase(), parsed.get());
        treeBuilder.remove(node.get().getNode().getName());
    } else {
        treeBuilder = new RevTreeBuilder(geogig.stagingDatabase());
    }
    // put the old feature into the new tree
    if (!delete) {
        treeBuilder.put(node.get().getNode());
    }
    ObjectId newTreeId = geogig.command(WriteBack.class).setAncestor(newTree.get().builder(geogig.stagingDatabase())).setChildPath(node.get().getParentPath()).setToIndex(true).setTree(treeBuilder.build()).setMetadataId(metadataId).call();
    // build new commit with parent of new commit and the newly built tree
    CommitBuilder builder = new CommitBuilder();
    builder.setParentIds(Lists.newArrayList(newCommitId));
    builder.setTreeId(newTreeId);
    builder.setAuthor(authorName.orNull());
    builder.setAuthorEmail(authorEmail.orNull());
    builder.setMessage(commitMessage.or("Reverted changes made to " + featurePath + " at " + newCommitId.toString()));
    RevCommit mapped = builder.build();
    context.getGeoGIG().getRepository().objectDatabase().put(mapped);
    // merge commit into current branch
    final Optional<Ref> currHead = geogig.command(RefParse.class).setName(Ref.HEAD).call();
    if (!currHead.isPresent()) {
        throw new CommandSpecException("Repository has no HEAD, can't merge.");
    }
    MergeOp merge = geogig.command(MergeOp.class);
    merge.setAuthor(authorName.orNull(), authorEmail.orNull());
    merge.addCommit(Suppliers.ofInstance(mapped.getId()));
    merge.setMessage(mergeMessage.or("Merged revert of " + featurePath));
    try {
        final MergeReport report = merge.call();
        context.setResponseContent(new CommandResponse() {

            @Override
            public void write(ResponseWriter out) throws Exception {
                out.start();
                out.writeMergeResponse(Optional.fromNullable(report.getMergeCommit()), report.getReport().get(), geogig, report.getOurs(), report.getPairs().get(0).getTheirs(), report.getPairs().get(0).getAncestor());
                out.finish();
            }
        });
    } catch (Exception e) {
        final RevCommit ours = context.getGeoGIG().getRepository().getCommit(currHead.get().getObjectId());
        final RevCommit theirs = context.getGeoGIG().getRepository().getCommit(mapped.getId());
        final Optional<ObjectId> ancestor = geogig.command(FindCommonAncestor.class).setLeft(ours).setRight(theirs).call();
        context.setResponseContent(new CommandResponse() {

            final MergeScenarioReport report = geogig.command(ReportMergeScenarioOp.class).setMergeIntoCommit(ours).setToMergeCommit(theirs).call();

            @Override
            public void write(ResponseWriter out) throws Exception {
                out.start();
                Optional<RevCommit> mergeCommit = Optional.absent();
                out.writeMergeResponse(mergeCommit, report, geogig, ours.getId(), theirs.getId(), ancestor.get());
                out.finish();
            }
        });
    }
}
Also used : CommitBuilder(org.locationtech.geogig.api.CommitBuilder) MergeOp(org.locationtech.geogig.api.porcelain.MergeOp) CommandResponse(org.locationtech.geogig.web.api.CommandResponse) MergeScenarioReport(org.locationtech.geogig.api.plumbing.merge.MergeScenarioReport) NodeRef(org.locationtech.geogig.api.NodeRef) ResolveTreeish(org.locationtech.geogig.api.plumbing.ResolveTreeish) CommandSpecException(org.locationtech.geogig.web.api.CommandSpecException) RevCommit(org.locationtech.geogig.api.RevCommit) Context(org.locationtech.geogig.api.Context) CommandContext(org.locationtech.geogig.web.api.CommandContext) Optional(com.google.common.base.Optional) ObjectId(org.locationtech.geogig.api.ObjectId) FindTreeChild(org.locationtech.geogig.api.plumbing.FindTreeChild) RevTreeBuilder(org.locationtech.geogig.api.RevTreeBuilder) CommandSpecException(org.locationtech.geogig.web.api.CommandSpecException) MergeReport(org.locationtech.geogig.api.porcelain.MergeOp.MergeReport) Ref(org.locationtech.geogig.api.Ref) NodeRef(org.locationtech.geogig.api.NodeRef) ResponseWriter(org.locationtech.geogig.web.api.ResponseWriter) RevObjectParse(org.locationtech.geogig.api.plumbing.RevObjectParse) RevTree(org.locationtech.geogig.api.RevTree)

Example 13 with RevTreeBuilder

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

the class WriteTree2Test method tree.

/**
     * Creates a tree reference for testing, forcing the specified id and metadata id, and with the
     * specified number of features (zero or more).
     * <p>
     * Note the tree is saved to the specified database only if its a leaf tree (more than zero
     * features), in order for the {@link #createFromRefs} method to be able of saving the parent
     */
private NodeRef tree(ObjectDatabase db, String path, String id, String mdId, int numFeatures) {
    Preconditions.checkArgument(numFeatures != 0 || EMPTY_ID.equals(id), "for zero features trees use RevTree.EMPTY_TREE_ID");
    final ObjectId treeId = id(id);
    final ObjectId metadataId = id(mdId);
    final String feturePrefix = NodeRef.nodeFromPath(path);
    RevTreeBuilder b = new RevTreeBuilder(db);
    if (numFeatures > 0) {
        for (int i = 0; i < numFeatures; i++) {
            Node fn = feature(db, feturePrefix, i);
            b.put(fn);
        }
    }
    RevTree fakenId = forceTreeId(b, treeId);
    if (!db.exists(fakenId.getId())) {
        db.put(fakenId);
    }
    if (!metadataId.isNull()) {
        RevFeatureType fakeType = new RevFeatureTypeImpl(metadataId, pointsType);
        if (!db.exists(fakeType.getId())) {
            db.put(fakeType);
        }
    }
    String name = NodeRef.nodeFromPath(path);
    String parent = NodeRef.parentPath(path);
    Envelope bounds = SpatialOps.boundsOf(fakenId);
    Node node = Node.create(name, treeId, metadataId, TYPE.TREE, bounds);
    return new NodeRef(node, parent, ObjectId.NULL);
}
Also used : NodeRef(org.locationtech.geogig.api.NodeRef) RevFeatureTypeImpl(org.locationtech.geogig.api.RevFeatureTypeImpl) ObjectId(org.locationtech.geogig.api.ObjectId) Node(org.locationtech.geogig.api.Node) RevTreeBuilder(org.locationtech.geogig.api.RevTreeBuilder) Envelope(com.vividsolutions.jts.geom.Envelope) RevFeatureType(org.locationtech.geogig.api.RevFeatureType) RevTree(org.locationtech.geogig.api.RevTree)

Example 14 with RevTreeBuilder

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

the class WriteBackTest method testSiblingsSingleLevel.

@Test
public void testSiblingsSingleLevel() {
    RevTreeBuilder ancestor = new RevTreeBuilder(odb);
    RevTree tree1 = new RevTreeBuilder(odb).put(blob("blob")).build();
    RevTree tree2 = new RevTreeBuilder(odb).put(blob("blob")).build();
    ObjectId newRootId1 = writeBack.setAncestor(ancestor).setChildPath("subtree1").setTree(tree1).call();
    ancestor = odb.getTree(newRootId1).builder(odb);
    ObjectId newRootId2 = writeBack.setAncestor(ancestor).setChildPath("subtree2").setTree(tree2).call();
    // created the intermediate tree node?
    DepthSearch depthSearch = new DepthSearch(odb);
    assertTrue(depthSearch.find(newRootId2, "subtree1").isPresent());
    assertTrue(depthSearch.find(newRootId2, "subtree2").isPresent());
    assertTrue(depthSearch.find(newRootId2, "subtree1/blob").isPresent());
    assertTrue(depthSearch.find(newRootId2, "subtree2/blob").isPresent());
}
Also used : DepthSearch(org.locationtech.geogig.repository.DepthSearch) ObjectId(org.locationtech.geogig.api.ObjectId) RevTreeBuilder(org.locationtech.geogig.api.RevTreeBuilder) RevTree(org.locationtech.geogig.api.RevTree) Test(org.junit.Test)

Example 15 with RevTreeBuilder

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

the class WriteBackTest method testPreserveMetadataId.

@Test
public void testPreserveMetadataId() {
    RevTreeBuilder oldRoot = new RevTreeBuilder(odb);
    RevTree tree = new RevTreeBuilder(odb).put(blob("blob")).build();
    final ObjectId treeMetadataId = ObjectId.forString("fakeMdId");
    ObjectId newRootId = writeBack.setAncestor(oldRoot).setChildPath("level1/level2").setTree(tree).setMetadataId(treeMetadataId).call();
    Optional<NodeRef> ref;
    DepthSearch depthSearch = new DepthSearch(odb);
    ref = depthSearch.find(newRootId, "level1/level2");
    assertTrue(ref.isPresent());
    assertTrue(ref.get().getNode().getMetadataId().isPresent());
    assertFalse(ref.get().getNode().getMetadataId().get().isNull());
    assertEquals(treeMetadataId, ref.get().getNode().getMetadataId().get());
}
Also used : NodeRef(org.locationtech.geogig.api.NodeRef) DepthSearch(org.locationtech.geogig.repository.DepthSearch) ObjectId(org.locationtech.geogig.api.ObjectId) RevTreeBuilder(org.locationtech.geogig.api.RevTreeBuilder) RevTree(org.locationtech.geogig.api.RevTree) Test(org.junit.Test)

Aggregations

RevTreeBuilder (org.locationtech.geogig.api.RevTreeBuilder)58 RevTree (org.locationtech.geogig.api.RevTree)47 ObjectId (org.locationtech.geogig.api.ObjectId)27 Test (org.junit.Test)25 NodeRef (org.locationtech.geogig.api.NodeRef)24 Node (org.locationtech.geogig.api.Node)14 DepthSearch (org.locationtech.geogig.repository.DepthSearch)6 RevFeatureType (org.locationtech.geogig.api.RevFeatureType)5 Stopwatch (com.google.common.base.Stopwatch)4 Envelope (com.vividsolutions.jts.geom.Envelope)4 Map (java.util.Map)4 Context (org.locationtech.geogig.api.Context)4 FindTreeChild (org.locationtech.geogig.api.plumbing.FindTreeChild)4 RevObjectParse (org.locationtech.geogig.api.plumbing.RevObjectParse)4 ObjectDatabase (org.locationtech.geogig.storage.ObjectDatabase)4 Before (org.junit.Before)3 FindOrCreateSubtree (org.locationtech.geogig.api.plumbing.FindOrCreateSubtree)3 WriteBack (org.locationtech.geogig.api.plumbing.WriteBack)3 DepthTreeIterator (org.locationtech.geogig.api.plumbing.diff.DepthTreeIterator)3 DiffEntry (org.locationtech.geogig.api.plumbing.diff.DiffEntry)3