Package org.locationtech.geogig.web.api.commands

Source Code of org.locationtech.geogig.web.api.commands.RevertFeatureWebOp

/* Copyright (c) 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:
* Johnathan Garrett (LMN Solutions) - initial implementation
*/
package org.locationtech.geogig.web.api.commands;

import static com.google.common.base.Preconditions.checkState;

import javax.annotation.Nullable;

import org.locationtech.geogig.api.CommitBuilder;
import org.locationtech.geogig.api.Context;
import org.locationtech.geogig.api.NodeRef;
import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.api.Ref;
import org.locationtech.geogig.api.RevCommit;
import org.locationtech.geogig.api.RevTree;
import org.locationtech.geogig.api.RevTreeBuilder;
import org.locationtech.geogig.api.plumbing.FindCommonAncestor;
import org.locationtech.geogig.api.plumbing.FindTreeChild;
import org.locationtech.geogig.api.plumbing.RefParse;
import org.locationtech.geogig.api.plumbing.ResolveTreeish;
import org.locationtech.geogig.api.plumbing.RevObjectParse;
import org.locationtech.geogig.api.plumbing.WriteBack;
import org.locationtech.geogig.api.plumbing.merge.MergeScenarioReport;
import org.locationtech.geogig.api.plumbing.merge.ReportMergeScenarioOp;
import org.locationtech.geogig.api.porcelain.AddOp;
import org.locationtech.geogig.api.porcelain.MergeOp;
import org.locationtech.geogig.api.porcelain.MergeOp.MergeReport;
import org.locationtech.geogig.web.api.AbstractWebAPICommand;
import org.locationtech.geogig.web.api.CommandContext;
import org.locationtech.geogig.web.api.CommandResponse;
import org.locationtech.geogig.web.api.CommandSpecException;
import org.locationtech.geogig.web.api.ResponseWriter;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Suppliers;
import com.google.common.collect.Lists;

/**
* The interface for the Add operation in GeoGig.
*
* Web interface for {@link AddOp}
*/

public class RevertFeatureWebOp extends AbstractWebAPICommand {

    private String featurePath;

    private ObjectId oldCommitId;

    private ObjectId newCommitId;

    private Optional<String> authorName = Optional.absent();

    private Optional<String> authorEmail = Optional.absent();

    private Optional<String> commitMessage = Optional.absent();

    private Optional<String> mergeMessage = Optional.absent();

    /**
     * Mutator for the featurePath variable
     *
     * @param featurePath - the path to the feature you want to revert
     */
    public void setPath(String featurePath) {
        this.featurePath = featurePath;
    }

    /**
     * Mutator for the oldCommitId variable
     *
     * @param oldCommitId - the commit that contains the version of the feature to revert to
     */
    public void setOldCommitId(String oldCommitId) {
        this.oldCommitId = ObjectId.valueOf(oldCommitId);
    }

    /**
     * Mutator for the newCommitId variable
     *
     * @param newCommitId - the commit that contains the version of the feature that we want to undo
     */
    public void setNewCommitId(String newCommitId) {
        this.newCommitId = ObjectId.valueOf(newCommitId);
    }

    /**
     * @param authorName the author of the merge commit
     */
    public void setAuthorName(@Nullable String authorName) {
        this.authorName = Optional.fromNullable(authorName);
    }

    /**
     * @param authorEmail the email of the author of the merge commit
     */
    public void setAuthorEmail(@Nullable String authorEmail) {
        this.authorEmail = Optional.fromNullable(authorEmail);
    }

    /**
     * @param commitMessage the commit message for the revert
     */
    public void setCommitMessage(@Nullable String commitMessage) {
        this.commitMessage = Optional.fromNullable(commitMessage);
    }

    /**
     * @param mergeMessage the message for the merge of the revert commit
     */
    public void setMergeMessage(@Nullable String mergeMessage) {
        this.mergeMessage = Optional.fromNullable(mergeMessage);
    }

    /**
     * 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();
                }
            });

        }
    }
}
TOP

Related Classes of org.locationtech.geogig.web.api.commands.RevertFeatureWebOp

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.