/* 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 static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import org.locationtech.geogig.api.AbstractGeoGigOp;
import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.api.RevCommit;
import org.locationtech.geogig.api.RevObject.TYPE;
import org.locationtech.geogig.api.RevTag;
import org.locationtech.geogig.api.RevTree;
import com.google.common.base.Optional;
/**
* Resolves the given "ref spec" to a tree id in the repository's object database.
*/
public class ResolveTreeish extends AbstractGeoGigOp<Optional<ObjectId>> {
private String treeishRefSpec;
private ObjectId treeish;
/**
* @param treeishRefSpec a ref spec that ultimately resolves to a tree id
* @return {@code this}
*/
public ResolveTreeish setTreeish(String treeishRefSpec) {
checkNotNull(treeishRefSpec);
this.treeishRefSpec = treeishRefSpec;
this.treeish = null;
return this;
}
/**
* @param treeish an object id that ultimately resolves to a tree id (i.e. a commit id, a tree
* id)
* @return {@code this}
*/
public ResolveTreeish setTreeish(ObjectId treeish) {
checkNotNull(treeish);
this.treeish = treeish;
this.treeishRefSpec = null;
return this;
}
/**
* Executes the command.
*
* @return an {@link Optional} of the {@link ObjectId} that was resolved, or
* {@link Optional#absent()} if it did not resolve.
*/
@Override
protected Optional<ObjectId> _call() {
checkState(treeishRefSpec != null || treeish != null, "tree-ish ref spec not set");
Optional<ObjectId> resolved;
if (treeishRefSpec != null) {
resolved = command(RevParse.class).setRefSpec(treeishRefSpec).call();
} else {
resolved = Optional.of(treeish);
}
return call(resolved);
}
/**
* @param resolved an {@link Optional} with an ObjectId to resolve
* @return an {@link Optional} of the {@link ObjectId} that was resolved, or
* {@link Optional#absent()} if it did not resolve.
*/
private Optional<ObjectId> call(Optional<ObjectId> resolved) {
if (!resolved.isPresent()) {
return Optional.absent();
}
ObjectId objectId = resolved.get();
if (objectId.isNull()) {// might be an empty commit ref
return Optional.of(RevTree.EMPTY_TREE_ID);
}
final TYPE objectType = command(ResolveObjectType.class).setObjectId(objectId).call();
switch (objectType) {
case TREE:
// ok
break;
case COMMIT: {
Optional<RevCommit> commit = command(RevObjectParse.class).setObjectId(objectId).call(
RevCommit.class);
if (commit.isPresent()) {
objectId = commit.get().getTreeId();
} else {
objectId = null;
}
break;
}
case TAG: {
Optional<RevTag> tag = command(RevObjectParse.class).setObjectId(objectId).call(
RevTag.class);
if (tag.isPresent()) {
ObjectId commitId = tag.get().getCommitId();
return call(Optional.of(commitId));
}
}
default:
throw new IllegalArgumentException(String.format(
"Provided ref spec ('%s') doesn't resolve to a tree-ish object: %s",
treeishRefSpec, String.valueOf(objectType)));
}
return Optional.fromNullable(objectId);
}
}