/* Copyright (c) 2013-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.osm.internal;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Iterator;
import java.util.List;
import org.locationtech.geogig.api.AbstractGeoGigOp;
import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.api.Ref;
import org.locationtech.geogig.api.RevCommit;
import org.locationtech.geogig.api.SymRef;
import org.locationtech.geogig.api.plumbing.RefParse;
import org.locationtech.geogig.api.porcelain.BranchCreateOp;
import org.locationtech.geogig.api.porcelain.CheckoutOp;
import org.locationtech.geogig.api.porcelain.LogOp;
import org.locationtech.geogig.api.porcelain.MergeOp;
import org.locationtech.geogig.api.porcelain.RebaseOp;
import org.locationtech.geogig.osm.internal.log.OSMLogEntry;
import org.locationtech.geogig.osm.internal.log.ReadOSMFilterFile;
import org.locationtech.geogig.osm.internal.log.ReadOSMLogEntries;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
/**
* Updates the OSM data using the existing filter.
*
*/
public class OSMUpdateOp extends AbstractGeoGigOp<Optional<OSMReport>> {
private String apiUrl;
private String message;
private boolean rebase;
/**
* If specified, use rebase instead of merge after updating the data.
*
* @param rebase whether or not to rebase changes
* @return {@code this}
*/
public OSMUpdateOp setRebase(boolean rebase) {
this.rebase = rebase;
return this;
}
/**
* Sets the URL of the OSM API.
*
* @param url the url of the OSM API
* @return {@code this}
*/
public OSMUpdateOp setAPIUrl(String url) {
this.apiUrl = url;
return this;
}
/**
* Sets the commit message to use when committing the updates.
*
* @param message the commit message to use
* @return {@code this}
*/
public OSMUpdateOp setMessage(String message) {
this.message = message;
return this;
}
/**
* Executes the {@code OSMUpdateOp} operation.
*
* @return a {@link OSMDownloadReport} of the operation
*/
@Override
protected Optional<OSMReport> _call() {
final Optional<Ref> currHead = command(RefParse.class).setName(Ref.HEAD).call();
Preconditions.checkState(currHead.isPresent(), "Repository has no HEAD, can't update.");
Preconditions.checkState(currHead.get() instanceof SymRef,
"Can't update from detached HEAD");
List<OSMLogEntry> entries = command(ReadOSMLogEntries.class).call();
checkArgument(!entries.isEmpty(), "Not in a geogig repository with OSM data");
Iterator<RevCommit> log = command(LogOp.class).setFirstParentOnly(false)
.setTopoOrder(false).call();
RevCommit lastCommit = null;
OSMLogEntry lastEntry = null;
while (log.hasNext()) {
RevCommit commit = log.next();
for (OSMLogEntry entry : entries) {
if (entry.getId().equals(commit.getTreeId())) {
lastCommit = commit;
lastEntry = entry;
break;
}
}
if (lastCommit != null) {
break;
}
}
checkNotNull(lastCommit, "The current branch does not contain OSM data");
command(BranchCreateOp.class).setSource(lastCommit.getId().toString())
.setName(OSMUtils.OSM_FETCH_BRANCH).setAutoCheckout(true).setForce(true).call();
Optional<String> filter = command(ReadOSMFilterFile.class).setEntry(lastEntry).call();
Preconditions.checkState(filter.isPresent(), "Filter file not found");
message = message == null ? "Updated OSM data" : message;
Optional<OSMReport> report = command(OSMImportOp.class).setMessage(message)
.setFilter(filter.get()).setDataSource(apiUrl)
.setProgressListener(getProgressListener()).call();
if (!report.isPresent()) {
return report;
}
if (!getProgressListener().isCanceled()) {
command(CheckoutOp.class).setSource(((SymRef) currHead.get()).getTarget()).call();
Optional<Ref> upstreamRef = command(RefParse.class).setName(OSMUtils.OSM_FETCH_BRANCH)
.call();
Supplier<ObjectId> commitSupplier = Suppliers.ofInstance(upstreamRef.get()
.getObjectId());
if (rebase) {
getProgressListener().setDescription("Rebasing updated features...");
command(RebaseOp.class).setUpstream(commitSupplier)
.setProgressListener(getProgressListener()).call();
} else {
getProgressListener().setDescription("Merging updated features...");
command(MergeOp.class).addCommit(commitSupplier)
.setProgressListener(getProgressListener()).call();
}
}
return report;
}
}