/******************************************************************************* * 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.ant.tasks; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.buckminster.ant.Messages; import org.eclipse.buckminster.core.CorePlugin; import org.eclipse.buckminster.core.actor.AbstractActor; import org.eclipse.buckminster.core.cspec.model.ComponentIdentifier; import org.eclipse.buckminster.core.helpers.BMProperties; import org.eclipse.buckminster.core.helpers.UnmodifiableMapUnion; import org.eclipse.buckminster.core.version.IQualifierGenerator; import org.eclipse.buckminster.core.version.VersionHelper; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.buckminster.runtime.IOUtils; import org.eclipse.core.runtime.CoreException; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.osgi.util.NLS; /** * @author Thomas Hallgren * */ public class VersionQualifierTask { public static final String GENERATOR_PREFIX = "generator:"; //$NON-NLS-1$ public static final String QUALIFIER_SUFFIX = "qualifier"; //$NON-NLS-1$ public static final String PROPERTY_CONTEXT = "context"; //$NON-NLS-1$ public static final String PROPERTY_NONE = "none"; //$NON-NLS-1$ private static final String QUALIFIER_REPLACEMENT_PREFIX = "qualifier.replacement."; //$NON-NLS-1$ private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmm"); //$NON-NLS-1$ private final Map<String, ? extends Object> properties; private final String qualifier; public VersionQualifierTask(File propertiesFile, String qualifier) throws CoreException { this.qualifier = qualifier; Map<String, ? extends Object> globalProps = AbstractActor.getActiveContext().getProperties(); if (propertiesFile == null) properties = globalProps; else { InputStream input = null; try { input = new BufferedInputStream(new FileInputStream(propertiesFile)); properties = new UnmodifiableMapUnion<String, Object>(new BMProperties(input), globalProps); } catch (IOException e) { throw BuckminsterException.fromMessage(e, NLS.bind(Messages.VersionQualifierTask_Unable_to_read_properties_from_0, propertiesFile)); } finally { IOUtils.close(input); } } } public Map<String, ? extends Object> getProperties() { return properties; } public boolean isContextReplacement() { return qualifier == null || qualifier.equalsIgnoreCase(PROPERTY_CONTEXT); } public boolean isUsingGenerator(ComponentIdentifier ci) { Version version = ci.getVersion(); if (version == null) return false; String vq = VersionHelper.getQualifier(version); if (vq == null || !vq.endsWith(QUALIFIER_SUFFIX)) return false; String newQualifier = getQualifierReplacement(ci); return newQualifier != null && newQualifier.startsWith(GENERATOR_PREFIX); } public Version replaceQualifier(ComponentIdentifier ci, List<ComponentIdentifier> deps) { Version version = ci.getVersion(); if (version == null) return version; String vq = VersionHelper.getQualifier(version); if (vq == null) return version; if (!vq.endsWith(QUALIFIER_SUFFIX)) return version; String newQualifier = getQualifierReplacement(ci); if (newQualifier == null) return VersionHelper.replaceQualifier(version, null); if (newQualifier.startsWith(GENERATOR_PREFIX)) { String generatorId = newQualifier.substring(GENERATOR_PREFIX.length()); try { IQualifierGenerator generator = CorePlugin.getDefault().getQualifierGenerator(generatorId); version = generator.generateQualifier(AbstractActor.getActiveContext(), ci, deps); } catch (CoreException e) { CorePlugin.getLogger().error(e, Messages.VersionQualifierTask_Unable_to_qualify_version); } } else { newQualifier = vq.replaceFirst(QUALIFIER_SUFFIX, newQualifier); if (!vq.equals(newQualifier)) version = VersionHelper.replaceQualifier(version, newQualifier); } return version; } private String getQualifierReplacement(ComponentIdentifier id) { String newQualifier = null; if (isContextReplacement()) { if (properties.size() != 0) { // First we check to see if there is a match for a precise // version // StringBuilder bld = new StringBuilder(); bld.append(id.getName()); bld.append(','); int lenWithId = bld.length(); // Lookup using id,<version without the .qualifier suffix> // String versionStr = id.getVersion().toString(); bld.append(versionStr, 0, versionStr.length() - QUALIFIER_SUFFIX.length() - 1); String idName = bld.toString(); bld.setLength(lenWithId); bld.append("0.0.0"); //$NON-NLS-1$ String idNameWithEmptyVersion = bld.toString(); int bestMatchLength = -1; for (Map.Entry<String, ? extends Object> entry : properties.entrySet()) { String key = entry.getKey(); if (!key.startsWith(QUALIFIER_REPLACEMENT_PREFIX)) continue; int idx = QUALIFIER_REPLACEMENT_PREFIX.length(); int top = key.length(); int exprLength = top - idx; if (exprLength <= bestMatchLength) continue; StringBuilder matchBld = new StringBuilder(); matchBld.append('^'); while (idx < top) { char c = key.charAt(idx++); switch (c) { case '?': matchBld.append('.'); continue; case '*': matchBld.append(".*"); //$NON-NLS-1$ continue; case '(': case ')': case '[': case ']': case '{': case '}': case '.': case '$': case '|': matchBld.append('\\'); matchBld.append(c); continue; default: matchBld.append(c); } } matchBld.append('$'); Pattern pattern = Pattern.compile(matchBld.toString()); Matcher m = pattern.matcher(idName); if (!m.matches()) { m = pattern.matcher(idNameWithEmptyVersion); if (!m.matches()) continue; } bestMatchLength = exprLength; newQualifier = entry.getValue().toString(); } } if (newQualifier == null) { synchronized (dateFormat) { newQualifier = dateFormat.format(new Date()); } } } else if (!qualifier.equalsIgnoreCase(PROPERTY_NONE)) newQualifier = qualifier; return newQualifier; } }