blob: 4604e1c460e6f18ed0f5d6896f2e4ee5476ef9d5 [file] [log] [blame]
/*
* Copyright (c) 2014-2016, 2018 Eike Stepper (Loehne, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.oomph.internal.version;
import org.eclipse.oomph.internal.version.Activator.LaxLowerBoundCheckMode;
import org.eclipse.oomph.internal.version.Activator.ReleaseCheckMode;
import org.eclipse.oomph.util.IOUtil;
import org.eclipse.oomph.util.StringUtil;
import org.eclipse.oomph.version.IElement;
import org.eclipse.oomph.version.IElement.Type;
import org.eclipse.oomph.version.IElementResolver;
import org.eclipse.oomph.version.IRelease;
import org.eclipse.oomph.version.IReleaseManager;
import org.eclipse.oomph.version.Markers;
import org.eclipse.oomph.version.VersionUtil;
import org.eclipse.oomph.version.VersionValidator;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.osgi.service.resolver.BaseDescription;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.service.resolver.BundleSpecification;
import org.eclipse.osgi.service.resolver.ExportPackageDescription;
import org.eclipse.osgi.service.resolver.ImportPackageSpecification;
import org.eclipse.osgi.service.resolver.VersionConstraint;
import org.eclipse.osgi.service.resolver.VersionRange;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.IModel;
import org.eclipse.pde.core.plugin.IPluginBase;
import org.eclipse.pde.core.plugin.IPluginExtensionPoint;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.plugin.PluginRegistry;
import org.osgi.framework.Version;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Eike Stepper
*/
public class VersionBuilder extends IncrementalProjectBuilder implements IElementResolver
{
private static final Path DESCRIPTION_PATH = new Path(".project"); //$NON-NLS-1$
private static final Path OPTIONS_PATH = new Path(".options"); //$NON-NLS-1$
private static final Path MAVEN_POM_PATH = new Path("pom.xml"); //$NON-NLS-1$
private static final Path MANIFEST_PATH = new Path("META-INF/MANIFEST.MF"); //$NON-NLS-1$
private static final Path FEATURE_PATH = new Path("feature.xml"); //$NON-NLS-1$
public static final String INTEGRATION_PROPERTY_KEY = "baseline.for.integration"; //$NON-NLS-1$
public static final String SERVICE_PROPERTY_KEY = "provide.service"; //$NON-NLS-1$
public static final String DEVIATIONS_PROPERTY_KEY = "show.deviations"; //$NON-NLS-1$
public static final String ROOT_PROJECTS_KEY = "root.projects"; //$NON-NLS-1$
public static final String IGNORED_REFERENCES_KEY = "ignored.references"; //$NON-NLS-1$
private static final Pattern DEBUG_OPTION_PATTERN = Pattern.compile("^( *)([^/ \\n\\r]+)/([^ =]+)( *=.*)$", Pattern.MULTILINE); //$NON-NLS-1$
private static final String AUTOMATIC_MODULE_NAME_HEADER = "Automatic-Module-Name"; //$NON-NLS-1$
private static final Pattern AUTOMATIC_MODULE_NAME_PATTERN = Pattern.compile(AUTOMATIC_MODULE_NAME_HEADER + ":( *)(.*)"); //$NON-NLS-1$
private static final Set<String> releasePaths = new HashSet<String>();
private static final Map<IElement, IElement> elementCache = new HashMap<IElement, IElement>();
private static final Map<IElement, Set<IElement>> elementReferences = new HashMap<IElement, Set<IElement>>();
private static IResourceChangeListener postBuildListener;
private static SAXParserFactory parserFactory;
private IRelease release;
private Boolean integration;
private Boolean service;
private Boolean deviations;
private Set<String> rootProjects;
private Set<String> ignoredReferences;
private VersionBuilderArguments arguments;
public VersionBuilder()
{
}
public IElement resolveElement(IElement key)
{
try
{
ensureCacheExists();
return elementCache.get(key);
}
catch (Exception ex)
{
Activator.log(ex);
return null;
}
}
public Set<IElement> resolveReferences(IElement key)
{
try
{
ensureCacheExists();
return elementReferences.get(key);
}
catch (Exception ex)
{
Activator.log(ex);
return null;
}
}
private void ensureCacheExists() throws NoSuchAlgorithmException, CoreException, IOException
{
for (String path : Activator.getReleasePaths())
{
if (releasePaths.add(path))
{
Map<IElement, IElement> elements = IReleaseManager.INSTANCE.createElements(path, false);
elementCache.putAll(elements);
for (IElement element : elements.keySet())
{
IElement.Type type = element.getType();
if (type == IElement.Type.FEATURE || type == IElement.Type.PRODUCT)
{
for (IElement child : element.getChildren())
{
Set<IElement> references = elementReferences.get(child);
if (references == null)
{
references = new HashSet<IElement>();
elementReferences.put(child, references);
}
references.add(element);
}
}
}
}
}
}
@Override
protected void clean(IProgressMonitor monitor) throws CoreException
{
IProject project = getProject();
monitor.beginTask("", 1); //$NON-NLS-1$
monitor.subTask(NLS.bind(Messages.VersionBuilder_Clean_task, project.getName()));
try
{
Activator.clearBuildState(project);
Markers.deleteAllMarkers(project);
}
finally
{
monitor.done();
}
}
@Override
protected final IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException
{
List<IProject> buildDependencies = new UniqueEList<IProject>();
build(kind, args, monitor, buildDependencies);
return buildDependencies.toArray(new IProject[buildDependencies.size()]);
}
private void build(int kind, Map<String, String> args, IProgressMonitor monitor, List<IProject> buildDependencies) throws CoreException
{
arguments = new VersionBuilderArguments(args);
VersionValidator validator = null;
IProject project = getProject();
IFile projectDescription = project.getFile(DESCRIPTION_PATH);
if (postBuildListener == null)
{
postBuildListener = new IResourceChangeListener()
{
public void resourceChanged(IResourceChangeEvent event)
{
elementCache.clear();
elementReferences.clear();
releasePaths.clear();
arguments = null;
}
};
project.getWorkspace().addResourceChangeListener(postBuildListener, IResourceChangeEvent.POST_BUILD);
Activator.setPostBuildListener(postBuildListener);
}
BuildState buildState = Activator.getBuildState(project);
byte[] releaseSpecDigest = buildState.getReleaseSpecDigest();
VersionBuilderArguments oldVersionBuilderArguments = new VersionBuilderArguments(buildState.getArguments());
buildState.setArguments(arguments);
IResourceDelta delta = releaseSpecDigest == null || kind == FULL_BUILD || kind == CLEAN_BUILD || !oldVersionBuilderArguments.equals(arguments) ? null
: getDelta(project);
monitor.beginTask("", 1); //$NON-NLS-1$
monitor.subTask(NLS.bind(Messages.VersionBuilder_Checking_task, project.getName()));
try
{
/*
* Determine release data to validate against
*/
String releasePathArg = arguments.getReleasePath();
if (releasePathArg == null)
{
String msg = Messages.VersionBuilder_NoReleaseSpecFile_message;
Markers.addMarker(projectDescription, msg, IMarker.SEVERITY_ERROR, "(" + VersionUtil.BUILDER_ID + ")"); //$NON-NLS-1$ //$NON-NLS-2$
return;
}
if (Activator.getReleaseCheckMode(releasePathArg) == ReleaseCheckMode.NONE)
{
return;
}
IPath releasePath = new Path(releasePathArg);
try
{
IFile releaseSpecFile = ResourcesPlugin.getWorkspace().getRoot().getFile(releasePath);
buildDependencies.add(releaseSpecFile.getProject());
IRelease release;
if (!releaseSpecFile.exists())
{
release = IReleaseManager.INSTANCE.createRelease(releaseSpecFile);
}
else
{
release = IReleaseManager.INSTANCE.getRelease(releaseSpecFile);
}
byte[] digest = VersionUtil.getSHA1(releaseSpecFile);
if (releaseSpecDigest == null || !MessageDigest.isEqual(digest, releaseSpecDigest))
{
buildState.setReleaseSpecDigest(digest);
delta = null;
}
this.release = release;
Markers.deleteAllMarkers(projectDescription, Markers.RELEASE_PATH_PROBLEM);
}
catch (Exception ex)
{
Activator.log(ex, IStatus.WARNING);
String msg = NLS.bind(Messages.VersionBuilder_ReleaseSpecProblem_message, releasePath, ex.getMessage());
IMarker marker = Markers.addMarker(projectDescription, msg, IMarker.SEVERITY_ERROR, "(" + releasePath.toString().replace(".", "\\.") + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
if (marker != null)
{
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.RELEASE_PATH_PROBLEM);
}
return;
}
IFile propertiesFile = VersionUtil.getFile(releasePath, "properties"); //$NON-NLS-1$
long propertiesTimeStamp = propertiesFile.getLocalTimeStamp();
boolean formerDeviations = buildState.isDeviations();
boolean deleteDeviationMarkers = false;
if (buildState.getPropertiesTimeStamp() != propertiesTimeStamp)
{
if (initReleaseProperties(propertiesFile))
{
delta = null;
}
buildState.setDeviations(deviations);
buildState.setIntegration(integration);
buildState.setService(service);
buildState.setRootProjects(rootProjects);
buildState.setIgnoredReferences(ignoredReferences);
buildState.setPropertiesTimeStamp(propertiesTimeStamp);
if (formerDeviations && !deviations)
{
deleteDeviationMarkers = true;
}
}
else
{
deviations = formerDeviations;
integration = buildState.isIntegration();
service = buildState.isService();
rootProjects = buildState.getRootProjects();
ignoredReferences = buildState.getIgnoredReferences();
}
for (IModel componentModel : VersionUtil.getComponentModels(project))
{
IFile componentModelFile = (IFile)componentModel.getUnderlyingResource();
if (deleteDeviationMarkers)
{
Markers.deleteAllMarkers(componentModelFile, Markers.DEVIATION_INFO);
}
IPath componentModelPath = componentModelFile.getProjectRelativePath();
boolean checkComponentModel = delta == null || delta.findMember(componentModelPath) != null;
if (!arguments.isIgnoreLaxLowerBoundDependencyVersions() && componentModel instanceof IPluginModelBase)
{
addDependencies(buildDependencies, project);
}
IElement element = IReleaseManager.INSTANCE.createElement(componentModel, true, false);
IElement.Type elementType = element.getType();
for (IElement child : element.getAllChildren(this, release))
{
IProject childProject = getProject(child);
if (childProject != null)
{
buildDependencies.add(childProject);
if (checkComponentModel)
{
IModel childProjectComponentModel = VersionUtil.getComponentModel(childProject);
if (childProjectComponentModel != null)
{
IResource underlyingResource = childProjectComponentModel.getUnderlyingResource();
Markers.deleteAllMarkers(underlyingResource, Markers.UNREFERENCED_ELEMENT_PROBLEM);
}
}
}
}
if (elementType != IElement.Type.PRODUCT)
{
Markers.deleteAllMarkers(componentModelFile, Markers.UNREFERENCED_ELEMENT_PROBLEM);
if (Activator.getReleaseCheckMode(releasePathArg) == ReleaseCheckMode.FULL && !rootProjects.contains(project.getName()))
{
Set<IElement> elementReference = resolveReferences(element);
if (elementReference == null || elementReference.isEmpty())
{
addUnreferencedElementMarker(componentModelFile, element);
}
}
}
IElement releaseElement = release.getElements().get(element.trimVersion());
boolean contentMustChange = false;
if (elementType == IElement.Type.PLUGIN)
{
if (!arguments.isIgnoreSchemaBuilder())
{
if (delta == null || delta.findMember(DESCRIPTION_PATH) != null)
{
checkSchemaBuilder((IPluginModelBase)componentModel, projectDescription);
}
}
else if (!oldVersionBuilderArguments.isIgnoreSchemaBuilder())
{
Markers.deleteAllMarkers(projectDescription, Markers.SCHEMA_BUILDER_PROBLEM);
}
if (!arguments.isIgnoreDebugOptions())
{
if (delta == null || delta.findMember(OPTIONS_PATH) != null)
{
checkDebugOptions((IPluginModelBase)componentModel);
}
}
else if (!oldVersionBuilderArguments.isIgnoreDebugOptions())
{
Markers.deleteAllMarkers(project.getFile(OPTIONS_PATH), Markers.DEBUG_OPTION_PROBLEM);
}
if (!arguments.isIgnoreAutomaticModuleName())
{
if (delta == null || delta.findMember(MANIFEST_PATH) != null)
{
checkAutomaticModuleName((IPluginModelBase)componentModel);
}
}
else if (!oldVersionBuilderArguments.isIgnoreDebugOptions())
{
Markers.deleteAllMarkers(project.getFile(MANIFEST_PATH), Markers.DEBUG_OPTION_PROBLEM);
}
if (!arguments.isIgnoreMissingDependencyRanges())
{
if (checkComponentModel)
{
checkDependencyRanges((IPluginModelBase)componentModel);
}
}
else if (!oldVersionBuilderArguments.isIgnoreMissingDependencyRanges())
{
Markers.deleteAllMarkers(getProject().getFile(MANIFEST_PATH), Markers.LOWER_BOUND_VERSION_PROBLEM);
}
LaxLowerBoundCheckMode laxLowerBoundCheckMode = Activator.getLaxLowerBoundCheckMode(releasePathArg);
// Only check the lower bounds if the element itself has been modified.
// Only in this case does it potentially use changes to the bundles/packages it uses (except maybe for new overloaded methods).
if (!arguments.isIgnoreLaxLowerBoundDependencyVersions()
&& (releaseElement == null || !releaseElement.getVersion().equals(element.getVersion()) || laxLowerBoundCheckMode == LaxLowerBoundCheckMode.ALL))
{
contentMustChange = !checkLowerBoundVersions((IPluginModelBase)componentModel, laxLowerBoundCheckMode);
}
else if (!oldVersionBuilderArguments.isIgnoreLaxLowerBoundDependencyVersions())
{
Markers.deleteAllMarkers(getProject().getFile(MANIFEST_PATH), Markers.LOWER_BOUND_VERSION_PROBLEM);
}
if (!arguments.isIgnoreMissingExportVersions())
{
if (checkComponentModel)
{
checkPackageExports((IPluginModelBase)componentModel);
}
}
else if (!oldVersionBuilderArguments.isIgnoreMissingExportVersions())
{
Markers.deleteAllMarkers(getProject().getFile(MANIFEST_PATH), Markers.EXPORT_VERSION_PROBLEM);
}
if (hasAPIToolsMarker((IPluginModelBase)componentModel))
{
continue;
}
}
else if (elementType == IElement.Type.FEATURE)
{
if (!arguments.isIgnoreFeatureNature())
{
if (delta == null || delta.findMember(DESCRIPTION_PATH) != null)
{
checkFeatureNature(projectDescription);
}
}
else if (!oldVersionBuilderArguments.isIgnoreFeatureNature())
{
Markers.deleteAllMarkers(projectDescription, Markers.FEATURE_NATURE_PROBLEM);
}
}
if (!arguments.isIgnoreMalformedVersions())
{
if (checkComponentModel)
{
if (checkMalformedVersions(componentModel))
{
continue;
}
}
}
else if (!oldVersionBuilderArguments.isIgnoreMalformedVersions())
{
Markers.deleteAllMarkers(componentModelFile, Markers.MALFORMED_VERSION_PROBLEM);
}
if (arguments.isCheckMavenPom())
{
if (delta == null || delta.findMember(MAVEN_POM_PATH) != null || delta.findMember(componentModelPath) != null)
{
checkMavenPom(element);
}
}
else if (oldVersionBuilderArguments.isCheckMavenPom())
{
Markers.deleteAllMarkers(project.getFile(MAVEN_POM_PATH), Markers.MAVEN_POM_PROBLEM);
}
if (releaseElement == null)
{
if (VersionUtil.DEBUG)
{
System.out.println(NLS.bind(Messages.VersionBuilder_UnresolveProject_message, project.getName()));
}
continue;
}
Markers.deleteAllMarkers(componentModelFile, Markers.VERSION_NATURE_PROBLEM);
for (IElement child : element.getChildren())
{
IModel childComponentModel = ReleaseManager.INSTANCE.getComponentModel(child);
if (childComponentModel != null)
{
IResource childComponentModelFile = childComponentModel.getUnderlyingResource();
if (childComponentModelFile != null)
{
IProject childProject = childComponentModelFile.getProject();
if (!childProject.hasNature(VersionNature.NATURE_ID))
{
Type childType = child.getType();
String name = child.getName();
String label = childType.toString();
String tag = childType.getTag();
String msg = NLS.bind(Messages.VersionBuilder_MissingVersionBuilder_message, label, name);
IMarker marker = addFeatureChildMarker(componentModelFile, Markers.VERSION_NATURE_PROBLEM, tag, name, msg, child.isLicenseFeature(), false,
null, IMarker.SEVERITY_ERROR);
marker.setAttribute(Markers.QUICK_FIX_NATURE, VersionNature.NATURE_ID);
marker.setAttribute(Markers.QUICK_FIX_PROJECT, childProject.getName());
}
}
}
}
Version elementVersion = element.getVersion();
Version releaseVersion = releaseElement.getVersion();
Version nextVersion = getNextVersion(releaseVersion);
int comparison = releaseVersion.compareTo(elementVersion);
if (comparison != 0 && deviations && checkComponentModel)
{
addDeviationMarker(componentModelFile, element, releaseVersion);
}
Markers.deleteAllMarkers(componentModelFile, Markers.COMPONENT_VERSION_PROBLEM, Markers.FEATURE_CLOSURE_PROBLEM);
boolean versionProperlyIncreased = false;
if (comparison < 0)
{
versionProperlyIncreased = nextVersion.equals(elementVersion);
if (!versionProperlyIncreased)
{
boolean noOtherIncrements = elementVersion.getMajor() == nextVersion.getMajor() && elementVersion.getMinor() == nextVersion.getMinor();
if (noOtherIncrements)
{
addVersionMarker(componentModelFile, NLS.bind(Messages.VersionBuilder_VersionShouldBe_message, nextVersion), nextVersion);
}
}
if (elementType == IElement.Type.PLUGIN)
{
continue;
}
}
if (comparison > 0)
{
addVersionMarker(componentModelFile, NLS.bind(Messages.VersionBuilder_VersionDecreased_message, releaseVersion), releaseVersion);
continue;
}
if (elementType == IElement.Type.FEATURE || elementType == IElement.Type.PRODUCT)
{
if (!arguments.isIgnoreFeatureContentRedundancy())
{
checkFeatureRedundancy(componentModelFile, element);
}
if (arguments.isCheckFeatureClosureCompleteness())
{
checkFeatureClosureCompleteness(componentModelFile, element);
}
if (!arguments.isIgnoreFeatureContentChanges())
{
List<Problem> problems = new ArrayList<Problem>();
checkFeatureReferences(componentModelFile, element, problems);
if (!problems.isEmpty())
{
createMarkers(componentModelFile, problems, ComponentReferenceType.UNRESOLVED);
continue;
}
ComponentReferenceType change = checkFeatureContentChanges(element, releaseElement, problems);
if (change != ComponentReferenceType.UNCHANGED)
{
Version nextFeatureVersion = getNextFeatureVersion(releaseVersion, nextVersion, change);
if (elementVersion.compareTo(nextFeatureVersion) < 0)
{
IMarker marker = addVersionMarker(componentModelFile,
NLS.bind(Messages.VersionBuilder_VersionMustBeIncreaseReferencesChanged_message, nextFeatureVersion, elementType.toString().toLowerCase()),
nextFeatureVersion);
if (marker != null)
{
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_CONTENT_CHANGES_ARGUMENT);
}
createMarkers(componentModelFile, problems, change);
}
continue;
}
if (!elementVersion.equals(releaseVersion))
{
continue;
}
}
}
if (versionProperlyIncreased || elementVersion.getMajor() > nextVersion.getMajor() || elementVersion.getMinor() > nextVersion.getMinor())
{
continue;
}
if (contentMustChange)
{
addVersionMarker(componentModelFile, NLS.bind(Messages.VersionBuilder_VersionMustBeIncreasedManifestMustChange_message, nextVersion), nextVersion);
continue;
}
// Initialize the validator on demand.
if (validator == null)
{
String validatorClassName = arguments.getValidatorClassName();
if (validatorClassName == null)
{
validatorClassName = IVersionBuilderArguments.DEFAULT_VALIDATOR_CLASS_NAME;
}
try
{
Markers.deleteAllMarkers(projectDescription, Markers.VALIDATOR_CLASS_PROBLEM);
Class<?> c = Class.forName(validatorClassName, true, VersionBuilder.class.getClassLoader());
validator = (VersionValidator)c.getDeclaredConstructor().newInstance();
if (VersionUtil.DEBUG)
{
System.out.println(validator.getClass().getName() + ": " + project.getName()); //$NON-NLS-1$
}
}
catch (Exception ex)
{
String msg = ex.getLocalizedMessage() + ": " + validatorClassName; //$NON-NLS-1$
IMarker marker = Markers.addMarker(projectDescription, msg, IMarker.SEVERITY_ERROR, ".*(" + validatorClassName + ").*"); //$NON-NLS-1$ //$NON-NLS-2$
if (marker != null)
{
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.VALIDATOR_CLASS_PROBLEM);
}
return;
}
String validatorVersion = validator.getVersion();
if (!VersionUtil.equals(validatorClassName, buildState.getValidatorClass())
|| !VersionUtil.equals(validatorVersion, buildState.getValidatorVersion()))
{
buildState.clearValidatorStates();
delta = null;
}
buildState.setValidatorClass(validatorClassName);
buildState.setValidatorVersion(validatorVersion);
}
// Apply the validator.
validator.updateBuildState(buildState, release, project, delta, componentModel, monitor);
if (buildState.isChangedSinceRelease())
{
addVersionMarker(componentModelFile, NLS.bind(Messages.VersionBuilder_VersionMustBeIncreasedProjectContentsChanged_message, nextVersion),
nextVersion);
}
}
}
catch (Exception ex)
{
try
{
if (validator != null)
{
validator.abort(buildState, project, ex, monitor);
}
Activator.log(ex);
}
catch (Exception ignore)
{
Activator.log(ignore);
}
}
finally
{
deviations = null;
integration = null;
service = null;
release = null;
monitor.done();
}
}
private void addDependencies(List<IProject> buildDependencies, IProject project)
{
IModel childProjectComponentModel = VersionUtil.getComponentModel(project);
if (childProjectComponentModel instanceof IPluginModelBase)
{
BundleDescription bundleDescription = ((IPluginModelBase)childProjectComponentModel).getBundleDescription();
if (bundleDescription != null)
{
BundleDescription[] requiredBundles = bundleDescription.getResolvedRequires();
if (requiredBundles != null)
{
for (BundleDescription requiredBundleDescription : requiredBundles)
{
IElement element = new Element(Type.PLUGIN, requiredBundleDescription.getSymbolicName(), null, false);
IProject childProject = getProject(element);
if (childProject != null)
{
buildDependencies.add(childProject);
}
}
}
}
}
}
private void createMarkers(IFile componentModelFile, List<Problem> problems, ComponentReferenceType change)
{
for (Problem problem : problems)
{
ComponentReferenceType componentReferenceType = problem.getComponentReferenceType();
if (componentReferenceType.ordinal() >= change.ordinal())
{
addIncludeMarker(componentModelFile, problem.getElement(), problem.getSeverity(), problem.getVersion(), componentReferenceType);
}
}
}
private boolean hasAPIToolsMarker(IPluginModelBase pluginModel)
{
try
{
IResource manifest = pluginModel.getUnderlyingResource();
for (IMarker marker : manifest.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO))
{
if (marker.getType().startsWith("org.eclipse.pde.api.tools")) //$NON-NLS-1$
{
return true;
}
}
}
catch (CoreException ex)
{
Activator.log(ex);
}
return false;
}
private boolean initReleaseProperties(IFile propertiesFile) throws CoreException, IOException
{
if (propertiesFile.exists())
{
InputStream contents = null;
try
{
boolean result = false;
contents = propertiesFile.getContents();
Properties properties = new Properties();
properties.load(contents);
deviations = Boolean.valueOf(properties.getProperty(DEVIATIONS_PROPERTY_KEY, "false")); //$NON-NLS-1$
rootProjects = new HashSet<String>();
for (String rootProject : Arrays.asList(properties.getProperty(ROOT_PROJECTS_KEY, "").split(" "))) //$NON-NLS-1$ //$NON-NLS-2$
{
rootProjects.add(rootProject.replace("\\ ", " ").replace("\\\\", "\\")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
ignoredReferences = new HashSet<String>();
for (String ignoredReference : Arrays.asList(properties.getProperty(IGNORED_REFERENCES_KEY, "").split(" "))) //$NON-NLS-1$ //$NON-NLS-2$
{
ignoredReferences.add(ignoredReference.replace("\\ ", " ").replace("\\\\", "\\")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
Boolean newIntegrationValue = Boolean.valueOf(properties.getProperty(INTEGRATION_PROPERTY_KEY, "true")); //$NON-NLS-1$
if (!newIntegrationValue.equals(integration))
{
integration = newIntegrationValue;
result = true;
}
Boolean newServiceValue = Boolean.valueOf(properties.getProperty(SERVICE_PROPERTY_KEY, "true")); //$NON-NLS-1$
if (!newServiceValue.equals(service))
{
service = newServiceValue;
result = true;
}
return result;
}
finally
{
IOUtil.closeSilent(contents);
}
}
deviations = false;
integration = true;
service = true;
rootProjects = new HashSet<String>();
ignoredReferences = new HashSet<String>();
String lineDelimiter = VersionUtil.getLineDelimiter(propertiesFile);
String contents = INTEGRATION_PROPERTY_KEY + " = " + integration + lineDelimiter + SERVICE_PROPERTY_KEY + " = " + service + lineDelimiter //$NON-NLS-1$ //$NON-NLS-2$
+ DEVIATIONS_PROPERTY_KEY + " = " + deviations + lineDelimiter + ROOT_PROJECTS_KEY + " = "; //$NON-NLS-1$ //$NON-NLS-2$
String charsetName = propertiesFile.getCharset();
byte[] bytes = contents.getBytes(charsetName);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
propertiesFile.create(bais, true, new NullProgressMonitor());
return true;
}
private Version getNextVersion(Version releaseVersion)
{
if (service)
{
return new Version(releaseVersion.getMajor(), releaseVersion.getMinor(), releaseVersion.getMicro() + (integration ? 100 : 1));
}
return new Version(releaseVersion.getMajor(), releaseVersion.getMinor() + 1, 0);
}
private Version getNextFeatureVersion(Version releaseVersion, Version nextImplementationVersion, ComponentReferenceType change)
{
switch (change)
{
case REMOVED:
case MAJOR_CHANGED:
return new Version(releaseVersion.getMajor() + 1, 0, 0);
case ADDED:
case FRAGMENT_REMOVED:
case MINOR_CHANGED:
return new Version(releaseVersion.getMajor(), releaseVersion.getMinor() + 1, 0);
case MICRO_CHANGED:
return nextImplementationVersion;
default:
throw new IllegalArgumentException();
}
}
private void checkFeatureReferences(IFile file, IElement element, List<Problem> problems)
{
for (IElement child : element.getChildren())
{
// PDE already warns for unresolved references, except for license features, see bug 387750
//
boolean hasSpecificVersion = !child.isVersionUnresolved();
if (hasSpecificVersion)
{
IElement resolvedChild = resolveElement(child);
if (resolvedChild == null)
{
resolvedChild = resolveElement(child.trimVersion());
Version resolvedChildVersion = resolvedChild == null ? null : resolvedChild.getVersion();
addProblem(child, IMarker.SEVERITY_ERROR, ComponentReferenceType.UNRESOLVED, resolvedChildVersion, problems);
}
}
}
}
private void checkFeatureRedundancy(IFile file, IElement element)
{
Map<IElement, IElement> allFeatureChildren = new HashMap<IElement, IElement>();
List<IElement> children = element.getChildren();
for (IElement child : children)
{
if (child.getType() == IElement.Type.FEATURE)
{
child = resolveElement(child);
if (child != null)
{
Set<IElement> allChildren = child.getAllChildren(this, release);
for (IElement featureChild : allChildren)
{
allFeatureChildren.put(featureChild, child);
}
}
}
}
int i = 0;
for (IElement child : children)
{
IElement featureElement = allFeatureChildren.get(child);
if (featureElement != null && !child.isLicenseFeature())
{
try
{
addRedundancyMarker(file, child, featureElement);
}
catch (Exception ex)
{
Activator.log(ex);
}
}
if (children.indexOf(child) != i)
{
addRedundancyMarker(file, child, null);
}
++i;
}
}
private void checkFeatureClosureCompleteness(IFile file, IElement element)
{
List<IElement> children = element.getChildren();
Set<IElement> plugins = new HashSet<IElement>();
Map<IElement, IElement> closure = new HashMap<IElement, IElement>();
for (IElement child : children)
{
if (child.getType() == IElement.Type.FEATURE)
{
collectFeatureClosure(child, child, closure);
}
else
{
plugins.add(child);
}
}
for (Map.Entry<IElement, IElement> entry : closure.entrySet())
{
IElement plugin = entry.getKey();
if (plugins.add(plugin))
{
try
{
IElement mainFeature = entry.getValue();
addFeatureClosureMarker(file, plugin, mainFeature);
}
catch (Exception ex)
{
Activator.log(ex);
}
}
}
}
private void collectFeatureClosure(IElement feature, IElement mainFeature, Map<IElement, IElement> closure)
{
feature = resolveElement(feature);
if (feature != null)
{
for (IElement child : feature.getChildren())
{
if (child.getType() == IElement.Type.PLUGIN)
{
if (!closure.containsKey(child))
{
closure.put(child, mainFeature);
}
}
else
{
collectFeatureClosure(child, mainFeature, closure);
}
}
}
}
private ComponentReferenceType checkFeatureContentChanges(IElement element, IElement releasedElement, List<Problem> problems)
{
ComponentReferenceType biggestChange = ComponentReferenceType.UNCHANGED;
Collection<IElement> children = arguments.isCheckFeatureClosureContent() ? element.getAllChildren(this, release) : element.getChildren();
for (IElement child : children)
{
ComponentReferenceType change = checkFeatureContentChanges(element, releasedElement, child, problems);
biggestChange = ComponentReferenceType.values()[Math.max(biggestChange.ordinal(), change.ordinal())];
}
Collection<IElement> allChildren = element.getAllChildren(this, release);
Collection<IElement> releasedElementChildren = arguments.isCheckFeatureClosureContent() ? releasedElement.getAllChildren(release, this)
: releasedElement.getChildren();
for (IElement releasedElementsChild : releasedElementChildren)
{
IElement trimmedVersion = releasedElementsChild.trimVersion();
if (!children.contains(trimmedVersion))
{
// IElement resolvedElement = resolveElement(trimmedVersion);
// if (resolvedElement != null && !resolvedElement.isVersionUnresolved())
{
ComponentReferenceType componentReferenceType = releasedElementsChild.isFragment() ? ComponentReferenceType.FRAGMENT_REMOVED
: ComponentReferenceType.REMOVED;
if (addProblem(releasedElementsChild, IMarker.SEVERITY_WARNING, componentReferenceType, null, problems))
{
// If we've removed a redundant plugin or feature, we don't want it to be considered a remove that requires a major version increment.
biggestChange = ComponentReferenceType.values()[Math.max(biggestChange.ordinal(),
allChildren.contains(trimmedVersion) ? ComponentReferenceType.MINOR_CHANGED.ordinal() : componentReferenceType.ordinal())];
}
}
}
}
return biggestChange;
}
private ComponentReferenceType checkFeatureContentChanges(IElement element, IElement releasedElement, IElement childElement, List<Problem> problems)
{
IElement releasedElementsChild = releasedElement.getChild(release, this, childElement);
if (releasedElementsChild == null)
{
// Don't consider it added if it was present with a different version.
//
releasedElementsChild = releasedElement.getChild(release, this, childElement.trimVersion());
if (releasedElementsChild == null)
{
if (addProblem(childElement, IMarker.SEVERITY_WARNING, ComponentReferenceType.ADDED, null, problems))
{
return ComponentReferenceType.ADDED;
}
}
}
IElement childsReleasedElement = release.getElements().get(childElement);
if (childsReleasedElement == null)
{
childsReleasedElement = release.getElements().get(childElement.trimVersion());
if (childsReleasedElement == null)
{
return ComponentReferenceType.UNCHANGED;
}
}
if (!childsReleasedElement.isVersionUnresolved())
{
Version releasedVersion = childsReleasedElement.getVersion();
Version version = childElement.trimVersion().getResolvedVersion();
if (!version.equals(Version.emptyVersion))
{
if (version.getMajor() != releasedVersion.getMajor())
{
if (addProblem(childsReleasedElement, IMarker.SEVERITY_WARNING, ComponentReferenceType.MAJOR_CHANGED, version, problems))
{
return ComponentReferenceType.MAJOR_CHANGED;
}
}
if (version.getMinor() != releasedVersion.getMinor())
{
if (addProblem(childsReleasedElement, IMarker.SEVERITY_WARNING, ComponentReferenceType.MINOR_CHANGED, version, problems))
{
return ComponentReferenceType.MINOR_CHANGED;
}
}
if (version.getMicro() != releasedVersion.getMicro())
{
if (addProblem(childsReleasedElement, IMarker.SEVERITY_WARNING, ComponentReferenceType.MICRO_CHANGED, version, problems))
{
return ComponentReferenceType.MICRO_CHANGED;
}
}
}
}
return ComponentReferenceType.UNCHANGED;
}
private SAXParser getParser() throws ParserConfigurationException, SAXException
{
if (parserFactory == null)
{
parserFactory = SAXParserFactory.newInstance();
}
return parserFactory.newSAXParser();
}
private void checkMavenPom(IElement element) throws CoreException
{
final IFile file = getProject().getFile(MAVEN_POM_PATH);
if (file.isAccessible())
{
Markers.deleteAllMarkers(file, Markers.MAVEN_POM_PROBLEM);
final String componentName = element.getID() == null ? element.getName() : element.getID();
final String componentVersion = StringUtil.removeSuffix(element.getVersion().toString(), ".qualifier"); //$NON-NLS-1$
final String componentType = element.getType().toString().toLowerCase();
InputStream contents = null;
try
{
contents = file.getContents();
SAXParser parser = getParser();
parser.parse(new BufferedInputStream(contents), new DefaultHandler()
{
private Locator locator;
private int level;
private int lineNumber;
private int found;
private StringBuilder builder;
@Override
public void setDocumentLocator(Locator locator)
{
this.locator = locator;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
if (++level == 2)
{
if ("artifactId".equals(qName) || "version".equals(qName)) //$NON-NLS-1$ //$NON-NLS-2$
{
lineNumber = locator.getLineNumber();
builder = new StringBuilder();
}
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException
{
if (builder != null)
{
builder.append(ch, start, length);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException
{
--level;
if (builder != null)
{
String textContent = builder.toString().replace('\n', ' ').replace('\r', ' ').replace('\t', ' ').trim();
if ("artifactId".equals(qName)) //$NON-NLS-1$
{
if (!textContent.equals(componentName))
{
addMarker(file, NLS.bind(Messages.VersionBuilder_MavenBadArtifactID_message, new Object[] { textContent, componentType, componentName }),
textContent, componentName);
}
}
else
{
String version = StringUtil.removeSuffix(textContent, "-SNAPSHOT"); //$NON-NLS-1$
if (!version.equals(componentVersion))
{
addMarker(file, NLS.bind(Messages.VersionBuilder_MavenBadVersion_message, new Object[] { version, componentType, componentVersion }), version,
componentVersion);
}
}
if (++found == 2)
{
throw new SAXException("STOP-EARLY"); //$NON-NLS-1$
}
}
builder = null;
}
private void addMarker(IFile file, String message, String pomValue, String componentValue)
{
StringBuilder regexBuilder = new StringBuilder();
for (int i = 1; i < lineNumber; i++)
{
regexBuilder.append('$');
}
regexBuilder.append(".*(" + pomValue.replace(".", "\\.") + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
String regex = regexBuilder.toString();
try
{
IMarker marker = Markers.addMarker(file, message, IMarker.SEVERITY_ERROR, regex);
if (marker != null)
{
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.MAVEN_POM_PROBLEM);
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
marker.setAttribute(Markers.QUICK_FIX_REPLACEMENT, componentValue);
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.CHECK_MAVEN_POM_ARGUMENT);
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_VALUE, "false"); //$NON-NLS-1$
}
}
catch (Exception ex)
{
Activator.log(ex);
}
}
});
}
catch (SAXException ex)
{
if (!"STOP-EARLY".equals(ex.getMessage())) //$NON-NLS-1$
{
Activator.log(ex);
}
}
catch (Exception ex)
{
Activator.log(ex);
}
finally
{
IOUtil.closeSilent(contents);
}
}
}
private boolean addProblem(IElement element, int severity, ComponentReferenceType componentReferenceType, Version version, List<Problem> problems)
{
String elementName = element.getName();
if (!ignoredReferences.contains(elementName))
{
problems.add(new Problem(element, severity, componentReferenceType, version));
return true;
}
return false;
}
private IProject getProject(IElement element)
{
String name = element.getName();
if (element.getType() == IElement.Type.PLUGIN)
{
return getPluginProject(name);
}
return getFeatureProject(name);
}
private IProject getPluginProject(String name)
{
IPluginModelBase pluginModel = PluginRegistry.findModel(name);
if (pluginModel != null)
{
IResource resource = pluginModel.getUnderlyingResource();
if (resource != null)
{
return resource.getProject();
}
}
return null;
}
@SuppressWarnings("restriction")
private IProject getFeatureProject(String name)
{
org.eclipse.pde.internal.core.ifeature.IFeatureModel[] featureModels = org.eclipse.pde.internal.core.PDECore.getDefault().getFeatureModelManager()
.getWorkspaceModels();
for (org.eclipse.pde.internal.core.ifeature.IFeatureModel featureModel : featureModels)
{
IResource resource = featureModel.getUnderlyingResource();
if (resource != null && name.equals(featureModel.getFeature().getId()))
{
return resource.getProject();
}
}
return null;
}
private boolean checkMalformedVersions(IModel componentModel) throws CoreException
{
IResource underlyingResource = componentModel.getUnderlyingResource();
if (underlyingResource != null)
{
Markers.deleteAllMarkers(underlyingResource, Markers.MALFORMED_VERSION_PROBLEM);
IProject project = underlyingResource.getProject();
if (project.isAccessible())
{
IFile file = null;
String regex = null;
IElement.Type type = VersionUtil.getType(componentModel);
if (type == IElement.Type.PLUGIN)
{
file = project.getFile(MANIFEST_PATH);
regex = "Bundle-Version: *(\\d+(\\.\\d+(\\.\\d+(\\.[-_a-zA-Z0-9]+)?)?)?)"; //$NON-NLS-1$
}
else if (type == IElement.Type.FEATURE)
{
file = project.getFile(FEATURE_PATH);
regex = "feature.*?version\\s*=\\s*[\"'](\\d+(\\.\\d+(\\.\\d+(\\.[-_a-zA-Z0-9]+)?)?)?)"; //$NON-NLS-1$
}
else if (type == IElement.Type.PRODUCT)
{
file = (IFile)underlyingResource;
regex = "product.*?version\\s*=\\s*[\"'](\\d+(\\.\\d+(\\.\\d+(\\.[-_a-zA-Z0-9]+)?)?)?)"; //$NON-NLS-1$
}
if (file.exists())
{
try
{
String content = VersionUtil.getContents(file);
Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE | Pattern.DOTALL);
Matcher matcher = pattern.matcher(content);
if (matcher.find())
{
String version = matcher.group(1);
if (matcher.groupCount() < 4 || !".qualifier".equals(matcher.group(4))) //$NON-NLS-1$
{
Version expectedVersion = new Version(version);
addMalformedVersionMarker(file, regex,
new Version(expectedVersion.getMajor(), expectedVersion.getMinor(), expectedVersion.getMicro(), "qualifier")); //$NON-NLS-1$
return true;
}
}
}
catch (Exception ex)
{
Activator.log(ex);
}
}
}
}
return false;
}
private void checkDependencyRanges(IPluginModelBase pluginModel) throws CoreException, IOException
{
BundleDescription description = pluginModel.getBundleDescription();
if (description == null)
{
return;
}
IFile file = getProject().getFile(MANIFEST_PATH);
Markers.deleteAllMarkers(file, Markers.DEPENDENCY_RANGE_PROBLEM);
for (BundleSpecification requiredBundle : description.getRequiredBundles())
{
VersionRange range = requiredBundle.getVersionRange();
if (isUnspecified(getMaximum(range)))
{
VersionRange expectedVersionRange = null;
boolean missing;
if (VersionRange.emptyRange.equals(range))
{
missing = true;
String name = requiredBundle.getName();
for (BundleDescription bundleDescription : description.getResolvedRequires())
{
if (name.equals(bundleDescription.getSymbolicName()))
{
expectedVersionRange = createVersionRange(bundleDescription.getVersion());
break;
}
}
}
else
{
missing = false;
Version minVersion = range.getMinimum();
Version maxVersion = new Version(minVersion.getMajor() + 1, 0, 0);
expectedVersionRange = new VersionRange(minVersion, range.getIncludeMinimum(), maxVersion, false);
}
addRequireMarker(file, requiredBundle.getName(), Messages.VersionBuilder_VersionRangeRequired_message, missing, expectedVersionRange);
}
else
{
if (!range.getIncludeMinimum())
{
VersionRange expectedVersionRange = new VersionRange(range.getMinimum(), true, getMaximum(range), false);
addRequireMarker(file, requiredBundle.getName(), Messages.VersionBuilder_DependencyRangeMustIncludeMinimum_message, false, expectedVersionRange);
}
if (range.getIncludeMaximum())
{
VersionRange expectedVersionRange = new VersionRange(range.getMinimum(), true, getMaximum(range), false);
addRequireMarker(file, requiredBundle.getName(), Messages.VersionBuilder_DependencyRangeMustNotIncludeMaximum_message, false, expectedVersionRange);
}
}
}
LOOP: for (ImportPackageSpecification importPackage : description.getImportPackages())
{
VersionRange range = importPackage.getVersionRange();
if (isUnspecified(getMaximum(range)))
{
VersionRange expectedVersionRange = null;
boolean missing;
if (VersionRange.emptyRange.equals(range))
{
// Don't report a problem if the package import resolves to a package with the empty version.
for (ExportPackageDescription exportPackageDescription : description.getResolvedImports())
{
if (exportPackageDescription.getName().equals(importPackage.getName()))
{
Version version = exportPackageDescription.getVersion();
if (Version.emptyVersion.equals(version))
{
continue LOOP;
}
expectedVersionRange = createVersionRange(version);
break;
}
}
missing = true;
}
else
{
missing = false;
Version minVersion = range.getMinimum();
Version maxVersion = new Version(minVersion.getMajor() + 1, 0, 0);
expectedVersionRange = new VersionRange(minVersion, range.getIncludeMinimum(), maxVersion, false);
}
addImportMarker(file, importPackage.getName(), Messages.VersionBuilder_VersionRangeRequired_message, missing, expectedVersionRange);
}
else
{
if (!range.getIncludeMinimum())
{
VersionRange expectedVersionRange = new VersionRange(range.getMinimum(), true, getMaximum(range), false);
addImportMarker(file, importPackage.getName(), Messages.VersionBuilder_DependencyRangeMustIncludeMinimum_message, false, expectedVersionRange);
}
if (range.getIncludeMaximum())
{
VersionRange expectedVersionRange = new VersionRange(range.getMinimum(), true, getMaximum(range), false);
addImportMarker(file, importPackage.getName(), Messages.VersionBuilder_DependencyRangeMustNotIncludeMaximum_message, false, expectedVersionRange);
}
}
}
}
private boolean checkLowerBoundVersions(IPluginModelBase pluginModel, LaxLowerBoundCheckMode laxLowerBoundCheckMode) throws CoreException, IOException
{
boolean result = true;
BundleDescription description = pluginModel.getBundleDescription();
if (description != null)
{
IFile file = getProject().getFile(MANIFEST_PATH);
Markers.deleteAllMarkers(file, Markers.LOWER_BOUND_VERSION_PROBLEM);
String releasePath = arguments.getReleasePath();
for (BundleSpecification requiredBundle : description.getRequiredBundles())
{
if (!checkLowerBoundVersions(file, releasePath, requiredBundle, "bundle-version", laxLowerBoundCheckMode)) //$NON-NLS-1$
{
result = false;
}
}
for (ImportPackageSpecification importPackage : description.getImportPackages())
{
if (!checkLowerBoundVersions(file, releasePath, importPackage, "version", laxLowerBoundCheckMode)) //$NON-NLS-1$
{
result = false;
}
}
}
return result;
}
private boolean checkLowerBoundVersions(IFile file, String releasePath, VersionConstraint versionConstraint, String versionAttribute,
LaxLowerBoundCheckMode laxLowerBoundCheckMode)
{
VersionRange requiredVersionRange = versionConstraint.getVersionRange();
if (!VersionRange.emptyRange.equals(requiredVersionRange))
{
BaseDescription supplier = versionConstraint.getSupplier();
if (supplier != null)
{
Version version = supplier.getVersion();
version = new Version(version.getMajor(), version.getMinor(), 0);
Version minimumRequiredVersion = requiredVersionRange.getMinimum();
if (!minimumRequiredVersion.equals(version))
{
BundleDescription supplierBundle = supplier.getSupplier();
if (supplierBundle != null)
{
IElement element = resolveElement(new Element(Type.PLUGIN, supplierBundle.getName(), null, supplierBundle.getHost() != null));
if (element != null)
{
IModel componentModel = ReleaseManager.INSTANCE.getComponentModel(element.trimVersion());
if (componentModel != null)
{
IResource underlyingResource = componentModel.getUnderlyingResource();
if (underlyingResource != null && underlyingResource.isAccessible())
{
IProject project = underlyingResource.getProject();
VersionBuilderArguments versionBuilderArguments = new VersionBuilderArguments(project);
String elementReleasePath = versionBuilderArguments.getReleasePath();
if (releasePath.equals(elementReleasePath) || laxLowerBoundCheckMode == LaxLowerBoundCheckMode.ANY_RELEASE && elementReleasePath != null
|| laxLowerBoundCheckMode == LaxLowerBoundCheckMode.ALL)
{
String name = versionConstraint.getName();
VersionRange expectedVersionRange = new VersionRange(version, true, getMaximum(requiredVersionRange),
requiredVersionRange.getIncludeMaximum());
addLaxLowerBoundMarker(file, name, NLS.bind(Messages.VersionBuilder_DependencyRangeMin_message, version), expectedVersionRange,
versionAttribute);
return false;
}
}
}
}
else if (laxLowerBoundCheckMode == LaxLowerBoundCheckMode.ALL)
{
String name = versionConstraint.getName();
VersionRange expectedVersionRange = new VersionRange(version, true, getMaximum(requiredVersionRange), requiredVersionRange.getIncludeMaximum());
addLaxLowerBoundMarker(file, name, NLS.bind(Messages.VersionBuilder_DependencyRangeMin_message, version), expectedVersionRange, versionAttribute);
return false;
}
}
}
}
}
return true;
}
@SuppressWarnings("deprecation")
private Version getMaximum(VersionRange range)
{
DeprecationUtil.someDeprecatedCode(); // Just make sure that this method refers to some deprecated code
return range.getMaximum();
}
private boolean isUnspecified(Version version)
{
if (version.getMajor() != Integer.MAX_VALUE)
{
return false;
}
if (version.getMinor() != Integer.MAX_VALUE)
{
return false;
}
if (version.getMicro() != Integer.MAX_VALUE)
{
return false;
}
return true;
}
private void checkPackageExports(IPluginModelBase pluginModel) throws CoreException, IOException
{
IFile file = getProject().getFile(MANIFEST_PATH);
Markers.deleteAllMarkers(file, Markers.EXPORT_VERSION_PROBLEM);
BundleDescription description = pluginModel.getBundleDescription();
String bundleName = description.getSymbolicName();
Version bundleVersion = VersionUtil.normalize(description.getVersion());
for (ExportPackageDescription packageExport : description.getExportPackages())
{
String packageName = packageExport.getName();
if (isBundlePackage(packageName, bundleName))
{
Version packageVersion = packageExport.getVersion();
if (packageVersion != null && !packageVersion.equals(Version.emptyVersion) && !packageVersion.equals(bundleVersion))
{
addExportMarker(file, packageName, bundleVersion);
}
}
}
}
private void checkFeatureNature(IFile file) throws CoreException, IOException
{
IProject project = file.getProject();
Markers.deleteAllMarkers(project, Markers.FEATURE_NATURE_PROBLEM);
IProjectDescription description = project.getDescription();
// Check that FeatureBuilder is configured.
for (ICommand command : description.getBuildSpec())
{
if ("org.eclipse.pde.FeatureBuilder".equals(command.getBuilderName())) //$NON-NLS-1$
{
if (project.hasNature("org.eclipse.pde.FeatureNature")) //$NON-NLS-1$
{
return;
}
}
}
String regex = "<buildSpec\\s*>()"; //$NON-NLS-1$
String msg = Messages.VersionBuilder_FeatureBuilderMissing_message;
IMarker marker = Markers.addMarker(file, msg, IMarker.SEVERITY_WARNING, regex);
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.FEATURE_NATURE_PROBLEM);
marker.setAttribute(Markers.QUICK_FIX_NATURE, "org.eclipse.pde.FeatureNature"); //$NON-NLS-1$
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_FEATURE_NATURE_ARGUMENT);
}
private void checkSchemaBuilder(IPluginModelBase pluginModel, IFile file) throws CoreException, IOException
{
Markers.deleteAllMarkers(file, Markers.SCHEMA_BUILDER_PROBLEM);
IProjectDescription description = getProject().getDescription();
IPluginBase pluginBase = pluginModel.getPluginBase();
if (pluginBase != null)
{
IPluginExtensionPoint[] extensionPoints = pluginBase.getExtensionPoints();
if (extensionPoints != null & extensionPoints.length != 0)
{
// Plugin has an extension point. Check that SchemaBuilder is configured.
for (ICommand command : description.getBuildSpec())
{
if ("org.eclipse.pde.SchemaBuilder".equals(command.getBuilderName())) //$NON-NLS-1$
{
return;
}
}
String regex = "<buildCommand\\s*>\\s*<name>\\s*org.eclipse.pde.ManifestBuilder\\s*</name>.*?</buildCommand>(\\s*)"; //$NON-NLS-1$
String msg = Messages.VersionBuilder_SchemaBuilderMissing_message;
IMarker marker = Markers.addMarker(file, msg, IMarker.SEVERITY_WARNING, regex);
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.SCHEMA_BUILDER_PROBLEM);
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
String lineDelimiter = VersionUtil.getLineDelimiter(file);
marker.setAttribute(Markers.QUICK_FIX_REPLACEMENT,
lineDelimiter + "\t\t<buildCommand>" + lineDelimiter + "\t\t\t<name>org.eclipse.pde.SchemaBuilder</name>" + lineDelimiter + "\t\t\t<arguments>" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ lineDelimiter + "\t\t\t</arguments>" + lineDelimiter + "\t\t</buildCommand>" + lineDelimiter + "\t\t"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_SCHEMA_BUILDER_ARGUMENT);
return;
}
}
// Plugin has no extension point(s). Check that SchemaBuilder is not configured.
for (ICommand command : description.getBuildSpec())
{
if ("org.eclipse.pde.SchemaBuilder".equals(command.getBuilderName())) //$NON-NLS-1$
{
String regex = "(<buildCommand\\s*>\\s*<name>\\s*org.eclipse.pde.SchemaBuilder\\s*</name>.*?</buildCommand>)\\s*"; //$NON-NLS-1$
String msg = Messages.VersionBuilder_NoSchemaBuilderNeed_message;
IMarker marker = Markers.addMarker(file, msg, IMarker.SEVERITY_WARNING, regex);
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.SCHEMA_BUILDER_PROBLEM);
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_SCHEMA_BUILDER_ARGUMENT);
break;
}
}
}
private void checkDebugOptions(IPluginModelBase pluginModel) throws CoreException, IOException
{
IFile file = getProject().getFile(OPTIONS_PATH);
if (file.isAccessible())
{
Markers.deleteAllMarkers(file, Markers.DEBUG_OPTION_PROBLEM);
String symbolicName = pluginModel.getBundleDescription().getSymbolicName();
String content = VersionUtil.getContents(file);
Matcher matcher = DEBUG_OPTION_PATTERN.matcher(content);
while (matcher.find())
{
String pluginID = matcher.group(2);
if (!symbolicName.equals(pluginID))
{
String prefix = matcher.group(1);
String suffix = "/" + (matcher.group(3) + matcher.group(4)).replace(".", "\\."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
pluginID = pluginID.replace(".", "\\."); //$NON-NLS-1$ //$NON-NLS-2$
String regex = prefix + "(" + pluginID + ")" + suffix; //$NON-NLS-1$ //$NON-NLS-2$
String msg = NLS.bind(Messages.VersionBuilder_DebugOption_message, symbolicName, matcher.group(3));
IMarker marker = Markers.addMarker(file, msg, IMarker.SEVERITY_ERROR, regex);
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.DEBUG_OPTION_PROBLEM);
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
marker.setAttribute(Markers.QUICK_FIX_REPLACEMENT, symbolicName);
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_DEBUG_OPTIONS_ARGUMENT);
}
}
}
}
@SuppressWarnings("restriction")
private void checkAutomaticModuleName(IPluginModelBase pluginModel) throws CoreException, IOException
{
IFile file = getProject().getFile(MANIFEST_PATH);
if (file.isAccessible())
{
Markers.deleteAllMarkers(file, Markers.AUTOMATIC_MODULE_NAME_PROBLEM);
if (pluginModel instanceof org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase)
{
org.eclipse.pde.internal.core.ibundle.IBundleModel bundleModel = ((org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase)pluginModel)
.getBundleModel();
if (bundleModel != null)
{
org.eclipse.pde.internal.core.ibundle.IBundle bundle = bundleModel.getBundle();
if (bundle != null)
{
String header = bundle.getHeader(AUTOMATIC_MODULE_NAME_HEADER);
if (header != null)
{
String symbolicName = pluginModel.getBundleDescription().getSymbolicName();
if (!header.equals(symbolicName))
{
String content = VersionUtil.getContents(file);
Matcher matcher = AUTOMATIC_MODULE_NAME_PATTERN.matcher(content);
while (matcher.find())
{
String moduleName = matcher.group(2);
if (!symbolicName.equals(moduleName))
{
String whitespace = matcher.group(1);
moduleName = moduleName.replace(".", "\\."); //$NON-NLS-1$ //$NON-NLS-2$
String regex = AUTOMATIC_MODULE_NAME_HEADER + ":" + whitespace + "(" + moduleName + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
String msg = NLS.bind(Messages.VersionBuilder_AutomaticModule_message, symbolicName);
IMarker marker = Markers.addMarker(file, msg, IMarker.SEVERITY_ERROR, regex);
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.AUTOMATIC_MODULE_NAME_PROBLEM);
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
marker.setAttribute(Markers.QUICK_FIX_REPLACEMENT, symbolicName);
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_AUTOMATIC_MODULE_NAME_ARGUMENT);
}
}
}
}
}
}
}
}
}
private boolean isBundlePackage(String packageName, String bundleName)
{
if (packageName.startsWith(bundleName))
{
return true;
}
int lastDot = bundleName.lastIndexOf('.');
if (lastDot != -1)
{
String bundleStart = bundleName.substring(0, lastDot);
String bundleEnd = bundleName.substring(lastDot + 1);
if (packageName.startsWith(bundleStart + ".internal." + bundleEnd)) //$NON-NLS-1$
{
return true;
}
if (packageName.startsWith(bundleStart + ".spi." + bundleEnd)) //$NON-NLS-1$
{
return true;
}
}
return false;
}
private void addRequireMarker(IFile file, String name, String message, boolean missing, VersionRange versionRange)
{
try
{
String regex = missing ? "^Require-Bundle: (?:\r?\n |[^\r\n])*" + name.replace(".", "\\.") + "()(;[^,]*?)?(,|$)" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
: name.replace(".", "\\.") + ";bundle-version=\"([^\\\"]*)\""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
IMarker marker = Markers.addMarker(file, "'" + name + "' " + message, IMarker.SEVERITY_ERROR, regex); //$NON-NLS-1$ //$NON-NLS-2$
if (marker != null)
{
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.DEPENDENCY_RANGE_PROBLEM);
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_DEPENDENCY_RANGES_ARGUMENT);
if (versionRange != null)
{
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
marker.setAttribute(Markers.QUICK_FIX_REPLACEMENT, missing ? ";bundle-version=\"" + versionRange.toString() + '"' : versionRange.toString()); //$NON-NLS-1$
}
}
}
catch (Exception ex)
{
Activator.log(ex);
}
}
private VersionRange createVersionRange(Version version)
{
Version minVersion = new Version(version.getMajor(), version.getMinor(), 0);
Version maxVersion = new Version(version.getMajor() + 1, 0, 0);
VersionRange versionRange = new VersionRange(minVersion, true, maxVersion, false);
return versionRange;
}
private void addLaxLowerBoundMarker(IFile file, String name, String message, VersionRange versionRange, String versionAttribute)
{
try
{
String regex = name.replace(".", "\\.") + ";" + versionAttribute + "=\"([^\\\"]*)\""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
IMarker marker = Markers.addMarker(file, "'" + name + "' " + message, IMarker.SEVERITY_ERROR, regex); //$NON-NLS-1$ //$NON-NLS-2$
if (marker != null)
{
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.LOWER_BOUND_VERSION_PROBLEM);
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
marker.setAttribute(Markers.QUICK_FIX_REPLACEMENT, versionRange.toString());
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_LAX_LOWER_BOUND_VERSIONS_ARGUMENT);
}
}
catch (Exception ex)
{
Activator.log(ex);
}
}
private void addImportMarker(IFile file, String name, String message, boolean missing, VersionRange versionRange)
{
try
{
String regex = missing ? "^Import-Package: (?:\r?\n |[^\r\n])*" + name.replace(".", "\\.") + "()(;[^,]*?)?(,|$)" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
: name.replace(".", "\\.") + ";version=\"([^\\\"]*)\""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
IMarker marker = Markers.addMarker(file, "'" + name + "' " + message, IMarker.SEVERITY_ERROR, regex); //$NON-NLS-1$ //$NON-NLS-2$
if (marker != null)
{
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.DEPENDENCY_RANGE_PROBLEM);
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_DEPENDENCY_RANGES_ARGUMENT);
if (versionRange != null)
{
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
marker.setAttribute(Markers.QUICK_FIX_REPLACEMENT, missing ? ";version=\"" + versionRange.toString() + '"' : versionRange.toString()); //$NON-NLS-1$
}
}
}
catch (Exception ex)
{
Activator.log(ex);
}
}
private void addExportMarker(IFile file, String name, Version bundleVersion)
{
String versionString = bundleVersion.toString();
try
{
String message = NLS.bind(Messages.VersionBuilder_PackageRequiresVersion_message, name, versionString);
String regex = name.replace(".", "\\.") + ";version=\"([0123456789\\.]*)\""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
IMarker marker = Markers.addMarker(file, message, IMarker.SEVERITY_ERROR, regex);
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.EXPORT_VERSION_PROBLEM);
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
marker.setAttribute(Markers.QUICK_FIX_REPLACEMENT, versionString);
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_EXPORT_VERSIONS_ARGUMENT);
}
catch (Exception ex)
{
Activator.log(ex);
}
}
private void addMalformedVersionMarker(IFile file, String regex, Version version)
{
try
{
String versionString = version.toString();
IMarker marker = Markers.addMarker(file, NLS.bind(Messages.VersionBuilder_BadVersion_message, versionString), IMarker.SEVERITY_ERROR, regex);
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.MALFORMED_VERSION_PROBLEM);
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
marker.setAttribute(Markers.QUICK_FIX_REPLACEMENT, versionString);
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_MALFORMED_VERSIONS_ARGUMENT);
}
catch (Exception ex)
{
Activator.log(ex);
}
}
private IMarker addUnreferencedElementMarker(IFile file, IElement element)
{
try
{
String type = element.getType().toString();
String message = NLS.bind(Messages.VersionBuilder_NotReferenceByFeature_message, type, element.getName());
String regex;
if (file.getFullPath().lastSegment().equals("MANIFEST.MF")) //$NON-NLS-1$
{
regex = "Bundle-SymbolicName: *([^;\n\r]*)"; //$NON-NLS-1$
}
else
{
regex = "feature.*?id\\s*=\\s*[\"']([^\"']*)"; //$NON-NLS-1$
}
IMarker marker = Markers.addMarker(file, message, IMarker.SEVERITY_ERROR, regex);
if (marker != null)
{
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.UNREFERENCED_ELEMENT_PROBLEM);
}
return marker;
}
catch (Exception ex)
{
Activator.log(ex);
return null;
}
}
private IMarker addDeviationMarker(IFile file, IElement element, Version releasedVersion)
{
try
{
String type = element.getType().toString();
Version version = element.getVersion();
String message = NLS.bind(Messages.VersionBuilder_HasBeenChanged_message, new Object[] { type, element.getName(), releasedVersion, version });
IMarker marker = addVersionMarker(file, message, version, IMarker.SEVERITY_INFO);
if (marker != null)
{
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.DEVIATION_INFO);
}
return marker;
}
catch (Exception ex)
{
Activator.log(ex);
return null;
}
}
private IMarker addVersionMarker(IFile file, String message, Version version)
{
try
{
IMarker marker = addVersionMarker(file, message, version, IMarker.SEVERITY_ERROR);
if (marker != null)
{
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.COMPONENT_VERSION_PROBLEM);
}
return marker;
}
catch (Exception ex)
{
Activator.log(ex);
return null;
}
}
private IMarker addVersionMarker(IFile file, String message, Version version, int severity)
{
try
{
String regex;
if (file.getFullPath().lastSegment().equals("MANIFEST.MF")) //$NON-NLS-1$
{
regex = "Bundle-Version: *(\\d+(\\.\\d+(\\.\\d+)?)?)"; //$NON-NLS-1$
}
else if (!file.getName().endsWith(".product")) //$NON-NLS-1$
{
regex = "feature.*?version\\s*=\\s*[\"'](\\d+(\\.\\d+(\\.\\d+)?)?)"; //$NON-NLS-1$
}
else
{
regex = "product.*?version\\s*=\\s*[\"'](\\d+(\\.\\d+(\\.\\d+)?)?)"; //$NON-NLS-1$
}
IMarker marker = Markers.addMarker(file, message, severity, regex);
if (severity != IMarker.SEVERITY_INFO)
{
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
marker.setAttribute(Markers.QUICK_FIX_REPLACEMENT, version.toString());
}
return marker;
}
catch (Exception ex)
{
Activator.log(ex);
return null;
}
}
private void addRedundancyMarker(IFile file, IElement child, IElement feature)
{
try
{
String name = child.getName();
Type type = child.getType();
String cause = feature != null ? NLS.bind(Messages.VersionBuilder_AlredyIncluded_message, feature.getName())
: Messages.VersionBuilder_RedundantInclude_message;
String msg = NLS.bind(Messages.VersionBuilder_RedundantReference_message, new Object[] { type, name, cause });
IMarker marker = addFeatureChildMarker(file, Markers.COMPONENT_VERSION_PROBLEM, type.getTag(), name, msg, false, true, null, IMarker.SEVERITY_WARNING);
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_CONTENT_REDUNDANCY_ARGUMENT);
}
catch (Exception ex)
{
Activator.log(ex);
}
}
private void addFeatureClosureMarker(IFile file, IElement pluginChild, IElement featureChild)
{
try
{
String pluginName = pluginChild.getName();
String featureName = featureChild.getName();
String msg = NLS.bind(Messages.VersionBuilder_MissingPlugin_message, pluginName, featureName);
String lineDelimiter = VersionUtil.getLineDelimiter(file);
IMarker marker = addFeatureChildMarker(file, Markers.FEATURE_CLOSURE_PROBLEM, "includes", featureName, msg, false, true, null, IMarker.SEVERITY_WARNING); //$NON-NLS-1$
marker.setAttribute(Markers.QUICK_FIX_PATTERN, "(([ \t]*)<includes(\\s*)id\\s*=\\s*\"" + featureName + "\")"); //$NON-NLS-1$ //$NON-NLS-2$
marker.setAttribute(Markers.QUICK_FIX_REPLACEMENT, "\\2<plugin\\3id=\"" + pluginName //$NON-NLS-1$
+ "\"\\3download-size=\"0\"\\3install-size=\"0\"\\3version=\"0.0.0\"\\3unpack=\"false\"/>" + lineDelimiter + lineDelimiter + "\\1"); //$NON-NLS-1$ //$NON-NLS-2$
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.CHECK_CLOSURE_COMPLETENESS_ARGUMENT);
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_VALUE, "false"); //$NON-NLS-1$
}
catch (Exception ex)
{
Activator.log(ex);
}
}
private void addIncludeMarker(IFile file, IElement element, int severity, Version version, ComponentReferenceType componentReferenceType)
{
try
{
String label;
String tag;
if (element.getType() == IElement.Type.PLUGIN)
{
label = Messages.VersionBuilder_Plugin_label;
tag = "plugin"; //$NON-NLS-1$
}
else if (file.getName().endsWith(".product")) //$NON-NLS-1$
{
label = Messages.VersionBuilder_Feature_label;
tag = "feature"; //$NON-NLS-1$
}
else
{
label = Messages.VersionBuilder_FeatureLabel;
tag = "includes"; //$NON-NLS-1$
}
String name = element.getName();
if (componentReferenceType == ComponentReferenceType.REMOVED || componentReferenceType == ComponentReferenceType.FRAGMENT_REMOVED)
{
String msg = NLS.bind(Messages.VersionBuilder_Remove_message, label, name);
IMarker marker = Markers.addMarker(file, msg, severity);
marker.setAttribute(Markers.PROBLEM_TYPE, Markers.COMPONENT_VERSION_PROBLEM);
marker.setAttribute(Markers.QUICK_FIX_REFERENCE, name);
}
else
{
String msg;
Version replacementVersion = null;
switch (componentReferenceType)
{
case UNRESOLVED:
{
if (version == null)
{
msg = NLS.bind(Messages.VersionBuilder_Unresolved_message, label, name);
}
else
{
msg = NLS.bind(Messages.VersionBuilder_ResolvesDifferently_message, new Object[] { label, name, version });
replacementVersion = version;
}
break;
}
case ADDED:
{
msg = NLS.bind(Messages.VersionBuilder_Added_message, new Object[] { label, name, element.getResolvedVersion() });
break;
}
case MAJOR_CHANGED:
case MINOR_CHANGED:
case MICRO_CHANGED:
{
msg = NLS.bind(Messages.VersionBuilder_Changed_message, new Object[] { label, name, element.getVersion(), version });
break;
}
default:
{
throw new IllegalStateException(Messages.VersionBuilder_Unreachable_message);
}
}
IMarker marker = addFeatureChildMarker(file, Markers.COMPONENT_VERSION_PROBLEM, tag, name, msg, element.isLicenseFeature(),
componentReferenceType == ComponentReferenceType.ADDED, replacementVersion, severity);
if (severity == IMarker.SEVERITY_ERROR)
{
marker.setAttribute(Markers.QUICK_FIX_CONFIGURE_OPTION, IVersionBuilderArguments.IGNORE_CONTENT_CHANGES_ARGUMENT);
}
else
{
marker.setAttribute(Markers.QUICK_FIX_REFERENCE, name);
}
}
}
catch (Exception ex)
{
Activator.log(ex);
}
}
private IMarker addFeatureChildMarker(IFile file, String problemType, String tag, String name, String msg, boolean isLicense, boolean hasQuickFix,
Version version, int severity) throws CoreException, IOException
{
String regex = isLicense ? "\\s+.*?license-feature-version\\s*=\\s*[\"']([^\"']*)[\"']" //$NON-NLS-1$
: version != null ? "[ \\t\\x0B\\f]*<" + tag + "\\s+[^<]*id\\s*=\\s*[\"']" + name.replace(".", "\\.") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ "[\"'].*?version\\s*=\\s*[\"']([^\"']*)[\"'].*?/>([ \\t\\x0B\\f]*[\\n\\r])*" //$NON-NLS-1$
: "[ \\t\\x0B\\f]*<" + tag + "\\s+[^<]*id\\s*=\\s*[\"'](" + name.replace(".", "\\.") + ")[\"'].*?/>([ \\t\\x0B\\f]*[\\n\\r])*"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
IMarker marker = Markers.addMarker(file, msg, severity, regex);
marker.setAttribute(Markers.PROBLEM_TYPE, problemType);
if (version != null)
{
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
marker.setAttribute(Markers.QUICK_FIX_REPLACEMENT, version.toString());
marker.setAttribute(Markers.QUICK_FIX_ALTERNATIVE_REPLACEMENT, "0.0.0"); //$NON-NLS-1$
}
else if (hasQuickFix)
{
marker.setAttribute(Markers.QUICK_FIX_PATTERN, regex);
}
return marker;
}
/**
* Order of the enumerations is important for determining the "biggest" change.
* @author Eike Stepper
*/
private static enum ComponentReferenceType
{
UNRESOLVED, UNCHANGED, MICRO_CHANGED, MINOR_CHANGED, ADDED, FRAGMENT_REMOVED, MAJOR_CHANGED, REMOVED
}
private static class Problem
{
private IElement element;
private int severity;
private ComponentReferenceType componentReferenceType;
private Version version;
public Problem(IElement element, int severity, ComponentReferenceType componentReferenceType, Version version)
{
this.element = element;
this.severity = severity;
this.componentReferenceType = componentReferenceType;
this.version = version;
}
public IElement getElement()
{
return element;
}
public int getSeverity()
{
return severity;
}
public ComponentReferenceType getComponentReferenceType()
{
return componentReferenceType;
}
public Version getVersion()
{
return version;
}
}
}