/*******************************************************************************
* Copyright (c) 2006-2013, Cloudsmith Inc.
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the copyright holder
* listed above, as the Initial Contributor under such license. The text of
* such license is available at www.eclipse.org.
******************************************************************************/
package org.eclipse.buckminster.core.version;
import java.util.Date;
import java.util.List;
import org.eclipse.buckminster.core.Messages;
import org.eclipse.buckminster.core.ctype.IComponentType;
import org.eclipse.buckminster.core.resolver.NodeQuery;
import org.eclipse.buckminster.core.resolver.ResolverDecisionType;
import org.eclipse.buckminster.core.rmap.model.Provider;
import org.eclipse.buckminster.runtime.MonitorUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.metadata.VersionRange;
import org.eclipse.osgi.util.NLS;
/**
* @author Thomas Hallgren
*/
public abstract class AbstractSCCSVersionFinder extends AbstractVersionFinder {
protected static class RevisionEntry {
private final String entryName;
private final String revision;
private final Date timestamp;
public RevisionEntry(String entryName, Date timestamp, long revision) {
this.entryName = entryName;
this.timestamp = timestamp;
this.revision = revision == -1 ? null : Long.toString(revision);
}
public RevisionEntry(String entryName, Date timestamp, String revision) {
this.entryName = entryName;
this.timestamp = timestamp;
this.revision = revision;
}
public String getEntryName() {
return entryName;
}
public String getRevision() {
return revision;
}
public Date getTimestamp() {
return timestamp;
}
public boolean satisfiesRevision(String rev) {
return VersionMatch.satisfiesRevision(rev, revision);
}
}
protected AbstractSCCSVersionFinder(Provider provider, IComponentType componentType, NodeQuery query) {
super(provider, componentType, query);
}
@Override
public VersionMatch getBestVersion(IProgressMonitor monitor) throws CoreException {
try {
NodeQuery query = getQuery();
VersionSelector[] branchTagPath = query.getBranchTagPath();
int idx = branchTagPath.length;
boolean branches = false;
boolean tags = false;
boolean trunk = (idx == 0); // Use trunk if no branches or tags has
// been specified
while (--idx >= 0) {
VersionSelector branchOrTag = branchTagPath[idx];
if (branchOrTag.getType() == VersionSelector.BRANCH)
branches = true;
else
tags = true;
if (branchOrTag.isDefault())
trunk = true;
}
IVersionConverter versionConverter = getProvider().getVersionConverter();
if (versionConverter != null) {
// We are using a versionConverter. This rules out anything
// found
// on the trunk.
//
logDecision(ResolverDecisionType.USING_VERSION_CONVERTER, versionConverter.getId());
trunk = false;
// Exactly one of the tags or branches must be valid
//
if (versionConverter.getSelectorType() == VersionSelector.BRANCH) {
if (tags == false)
branches = true;
} else {
if (branches == false)
tags = true;
}
// And perhaps this ruled out this finder all together?
//
if (!(branches || tags)) {
MonitorUtils.complete(monitor);
return null;
}
}
int ticks = 0;
if (trunk) {
logDecision(ResolverDecisionType.SEARCHING_TRUNK);
ticks += 10;
}
if (branches) {
logDecision(ResolverDecisionType.SEARCHING_BRANCHES);
ticks += 10;
}
if (tags) {
logDecision(ResolverDecisionType.SEARCHING_TAGS);
ticks += 10;
}
monitor.beginTask(null, ticks);
VersionMatch best = null;
if (branches)
best = getBestBranchOrTagMatch(true, MonitorUtils.subMonitor(monitor, 10));
if (tags) {
VersionMatch match = getBestBranchOrTagMatch(false, MonitorUtils.subMonitor(monitor, 10));
if (best == null)
best = match;
else if (match != null && query.compare(match, best) > 0) {
logDecision(ResolverDecisionType.MATCH_REJECTED, best, NLS.bind(Messages._0_is_a_better_match, match));
best = match;
}
}
if (trunk) {
VersionMatch match = getBestTrunkMatch(MonitorUtils.subMonitor(monitor, 10));
if (best == null)
best = match;
else if (match != null && query.compare(match, best) > 0) {
logDecision(ResolverDecisionType.MATCH_REJECTED, best, NLS.bind(Messages._0_is_a_better_match, match));
best = match;
}
}
return best;
} finally {
monitor.done();
}
}
protected abstract boolean checkComponentExistence(VersionMatch versionMatch, IProgressMonitor monitor) throws CoreException;
protected VersionMatch getBestBranchOrTagMatch(boolean branches, IProgressMonitor monitor) throws CoreException {
monitor.beginTask(null, 100);
try {
List<RevisionEntry> entries = getBranchesOrTags(branches, MonitorUtils.subMonitor(monitor, 50));
return getBestBranchOrTagMatch(branches, entries, MonitorUtils.subMonitor(monitor, 50));
} finally {
monitor.done();
}
}
protected VersionMatch getBestBranchOrTagMatch(boolean branches, List<RevisionEntry> entries, IProgressMonitor monitor) throws CoreException {
int top = entries.size();
if (top == 0) {
logDecision(branches ? ResolverDecisionType.NO_BRANCHES_FOUND : ResolverDecisionType.NO_TAGS_FOUND);
MonitorUtils.complete(monitor);
return null;
}
IVersionConverter vConverter = getProvider().getVersionConverter();
if (vConverter != null && vConverter.getSelectorType() != (branches ? VersionSelector.BRANCH : VersionSelector.TAG)) {
// Version converter not for the desired type so we will not find
// anything
//
if (branches)
logDecision(ResolverDecisionType.VERSION_SELECTOR_MISMATCH, "tags", "branches"); //$NON-NLS-1$ //$NON-NLS-2$
else
logDecision(ResolverDecisionType.VERSION_SELECTOR_MISMATCH, "branches", "tags"); //$NON-NLS-1$ //$NON-NLS-2$
MonitorUtils.complete(monitor);
return null;
}
monitor.beginTask(null, top * 10);
NodeQuery query = getQuery();
VersionSelector[] branchTagPath = query.getBranchTagPath();
VersionRange versionRange = query.getVersionRange();
String revision = query.getRevision();
Date timestamp = query.getTimestamp();
VersionMatch best = null;
for (RevisionEntry entry : entries) {
// Rule out anything that is above a given revision
//
if (!entry.satisfiesRevision(revision)) {
logDecision(ResolverDecisionType.REVISION_REJECTED, Long.valueOf(entry.getRevision()), "too high"); //$NON-NLS-1$
continue;
}
// Rule out anything that is later then a given time
//
if (timestamp != null) {
Date entryTs = entry.getTimestamp();
if (entryTs != null && entryTs.compareTo(timestamp) > 0) {
logDecision(ResolverDecisionType.TIMESTAMP_REJECTED, entryTs, "too young"); //$NON-NLS-1$
continue;
}
}
String name = entry.getEntryName();
VersionSelector branchOrTag = branches ? VersionSelector.branch(name) : VersionSelector.tag(name);
if (branchTagPath.length > 0 && VersionSelector.indexOf(branchTagPath, branchOrTag) < 0) {
// This one will be discriminated anyway so there's no need to
// include it
//
logDecision(branches ? ResolverDecisionType.BRANCH_REJECTED : ResolverDecisionType.TAG_REJECTED, branchOrTag, NLS.bind(
Messages.r_not_in_path_0, VersionSelector.toString(branchTagPath)));
continue;
}
Version version;
VersionMatch match = null;
if (vConverter != null) {
version = vConverter.createVersion(branchOrTag);
if (version == null) {
// Converter could not make sense of this tag. Skip it
//
logDecision(branches ? ResolverDecisionType.BRANCH_REJECTED : ResolverDecisionType.TAG_REJECTED, branchOrTag,
Messages.VersionSelector_cannot_make_sense_of_it);
MonitorUtils.worked(monitor, 10);
continue;
}
// We need to assert that the component really exists on this
// branch
// or with this tag.
//
match = new VersionMatch(version, branchOrTag, entry.getRevision(), entry.getTimestamp(), null);
if (!checkComponentExistence(match, MonitorUtils.subMonitor(monitor, 10))) {
logDecision(branches ? ResolverDecisionType.BRANCH_REJECTED : ResolverDecisionType.TAG_REJECTED, branchOrTag,
Messages.No_component_was_found);
continue;
}
logDecision(branches ? ResolverDecisionType.USING_BRANCH_CONVERTED_VERSION : ResolverDecisionType.USING_TAG_CONVERTED_VERSION,
version, branchOrTag);
} else {
try {
version = getVersionFromArtifacts(branchOrTag, MonitorUtils.subMonitor(monitor, 10));
} catch (CoreException e) {
// Something is not right with this entry. Skip it.
//
logDecision(branches ? ResolverDecisionType.BRANCH_REJECTED : ResolverDecisionType.TAG_REJECTED, branchOrTag, e.getMessage());
continue;
}
}
if (!(versionRange == null || versionRange.isIncluded(version))) {
// Discriminated by our designator
//
logDecision(ResolverDecisionType.VERSION_REJECTED, version, NLS.bind(Messages.Not_designated_by_0, versionRange));
continue;
}
if (match == null)
match = new VersionMatch(version, branchOrTag, entry.getRevision(), entry.getTimestamp(), null);
if (version == null) {
// Unknown component type will not check the existence of any
// artifacts. We need to
// do that here
//
if (!checkComponentExistence(match, MonitorUtils.subMonitor(monitor, 10))) {
logDecision(branches ? ResolverDecisionType.BRANCH_REJECTED : ResolverDecisionType.TAG_REJECTED, branchOrTag,
Messages.No_component_was_found);
continue;
}
}
if (best == null || query.compare(match, best) > 0) {
if (best != null)
logDecision(ResolverDecisionType.MATCH_REJECTED, best, NLS.bind(Messages._0_is_a_better_match, match));
best = match;
if (vConverter != null && versionRange != null && versionRange.getMinimum().equals(versionRange.getMaximum())) {
// Explicit hit on a version converted tag or branch. This
// will do just fine.
//
break;
}
}
}
monitor.done();
return best;
}
protected VersionMatch getBestTrunkMatch(IProgressMonitor monitor) throws CoreException {
monitor.beginTask(null, 100);
try {
RevisionEntry entry = getTrunk(MonitorUtils.subMonitor(monitor, 50));
if (entry == null)
return null;
NodeQuery query = getQuery();
// Rule out anything that is above a given revision
//
String revision = query.getRevision();
if (!entry.satisfiesRevision(revision)) {
logDecision(ResolverDecisionType.REVISION_REJECTED, Long.valueOf(entry.getRevision()), Messages.Too_high);
return null;
}
// Rule out anything that is later then a given time
//
Date timestamp = query.getTimestamp();
if (timestamp != null) {
Date entryTs = entry.getTimestamp();
if (entryTs != null && entryTs.compareTo(timestamp) > 0) {
logDecision(ResolverDecisionType.TIMESTAMP_REJECTED, entryTs, Messages.Too_young);
return null;
}
}
Version version = null;
try {
version = getVersionFromArtifacts(null, MonitorUtils.subMonitor(monitor, 50));
} catch (CoreException e) {
// Something is not right with this entry. Skip it.
//
logDecision(ResolverDecisionType.MAIN_REJECTED, e.getMessage());
return null;
}
VersionRange versionDesignator = query.getVersionRange();
if (!(versionDesignator == null || versionDesignator.isIncluded(version))) {
// Discriminated by our designator
//
logDecision(ResolverDecisionType.VERSION_REJECTED, version, NLS.bind(Messages.Not_designated_by_0, versionDesignator));
return null;
}
return new VersionMatch(version, null, entry.getRevision(), entry.getTimestamp(), null);
} finally {
monitor.done();
}
}
protected abstract List<RevisionEntry> getBranchesOrTags(boolean branches, IProgressMonitor monitor) throws CoreException;
protected abstract RevisionEntry getTrunk(IProgressMonitor monitor) throws CoreException;
}