Package org.locationtech.geogig.api.plumbing

Source Code of org.locationtech.geogig.api.plumbing.RefParse

/* Copyright (c) 2012-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:
* Gabriel Roldan (Boundless) - initial implementation
*/
package org.locationtech.geogig.api.plumbing;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.locationtech.geogig.api.AbstractGeoGigOp;
import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.api.Ref;
import org.locationtech.geogig.api.SymRef;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableSet;

/**
* Resolve a ref name to the stored {@link Ref reference} object
*/
public class RefParse extends AbstractGeoGigOp<Optional<Ref>> {

    private static final Set<String> STANDARD_REFS = ImmutableSet.of(Ref.HEAD, Ref.MASTER,
            Ref.ORIGIN, Ref.STAGE_HEAD, Ref.WORK_HEAD);

    private String refSpec;

    /**
     * @param name the name of the ref to parse
     * @return {@code this}
     */
    public RefParse setName(String name) {
        this.refSpec = name;
        return this;
    }

    /**
     * Parses a geogig reference string (possibly abbreviated) and return the resolved {@link Ref}
     * or {@code absent} if the ref spec didn't resolve to any actual reference.
     *
     * Combinations of these operators are supported:
     * <ul>
     * <li><b>HEAD</b>, <b>MERGE_HEAD</b>, <b>FETCH_HEAD</b>, <b>STAGE_HEAD</b>, <b>WORK_HEAD</b></li>
     * <li><b>refs/...</b>: a complete reference name</li>
     * <li><b>short-name</b>: a short reference name under {@code refs/heads}, {@code refs/tags}, or
     * {@code refs/remotes} namespace, in that order of precedence</li>
     * </ul>
     *
     * @return an {@code Optional} that contains a {@link Ref reference} or
     *         {@link Optional#absent()} if revstr can't be resolved to any {@link ObjectId}
     * @throws IllegalArgumentException if {@code refSpec} resolves to more than one ref on the same
     *         namespace
     */
    @Override
    protected Optional<Ref> _call() {
        Preconditions.checkState(refSpec != null, "name has not been set");

        if (STANDARD_REFS.contains(refSpec) || refSpec.startsWith("refs/")) {
            return getRef(refSpec);
        }

        // is it a top level ref?
        if (!refSpec.startsWith("refs/")) {
            Optional<Ref> ref = getRef(refSpec);
            if (ref.isPresent()) {
                return ref;
            }
        }

        Map<String, String> allRefs = refDatabase().getAll();

        class PrePostfixPredicate implements Predicate<String> {

            private String prefix;

            private String suffix;

            public PrePostfixPredicate(String prefix, String suffix) {
                this.prefix = prefix;
                this.suffix = suffix;
            }

            @Override
            public boolean apply(String refName) {
                boolean applies = refName.startsWith(prefix) && refName.endsWith(suffix);
                return applies;
            }

        }
        Collection<String> heads = Collections2.filter(allRefs.keySet(), new PrePostfixPredicate(
                "refs/heads", "/" + refSpec));
        Collection<String> tags = Collections2.filter(allRefs.keySet(), new PrePostfixPredicate(
                "refs/tags", "/" + refSpec));
        Collection<String> remotes = Collections2.filter(allRefs.keySet(), new PrePostfixPredicate(
                "refs/remotes", "/" + refSpec));

        String refName;
        refName = resolveSingle(heads);
        if (refName == null) {
            refName = resolveSingle(tags);
        }
        if (refName == null) {
            refName = resolveSingle(remotes);
        }
        if (refName == null) {
            return Optional.absent();
        }
        return getRef(refName);
    }

    private String resolveSingle(Collection<String> refNames) {
        if (refNames.isEmpty()) {
            return null;
        }
        if (refNames.size() == 1) {
            return refNames.iterator().next();
        }
        throw new IllegalArgumentException(refSpec + " resolves to more than one ref: " + refNames);
    }

    private Optional<Ref> getRef(final String name) {
        String storedValue;
        boolean sym = false;
        try {
            storedValue = refDatabase().getRef(name);
        } catch (IllegalArgumentException notARef) {
            storedValue = refDatabase().getSymRef(name);
            if (null == storedValue) {
                return Optional.absent();
            }
            sym = true;
        }
        if (null == storedValue) {
            storedValue = refDatabase().getSymRef(name);
            if (null == storedValue) {
                return Optional.absent();
            }
            sym = true;
        }

        if (sym) {
            Optional<Ref> target = getRef(storedValue);
            if (!target.isPresent()) {
                throw new RuntimeException("target '" + storedValue
                        + "' was not present for symref " + name + " -> '" + storedValue + "'");
            }
            Ref resolved = new SymRef(name, target.get());
            return Optional.of(resolved);
        }
        ObjectId objectId = ObjectId.valueOf(storedValue);
        return Optional.of(new Ref(name, objectId));
    }

}
TOP

Related Classes of org.locationtech.geogig.api.plumbing.RefParse

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.