/******************************************************************************* * Copyright (c) 2008-2011 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Sonatype, Inc. - initial API and implementation * Andrew Eisenberg - Work on Bug 350414 *******************************************************************************/ package org.eclipse.m2e.core.ui.internal.editing; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.ARTIFACT_ID; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.BUILD; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.CONFIGURATION; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.GOAL; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.GOALS; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.GROUP_ID; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.PLUGIN; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.PLUGINS; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.PLUGIN_MANAGEMENT; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.childEquals; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.createElementWithText; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.findChild; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.findChilds; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.format; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.getChild; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.getTextValue; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.setText; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; import org.apache.maven.artifact.versioning.VersionRange; import org.eclipse.m2e.core.internal.lifecyclemapping.LifecycleMappingFactory; import org.eclipse.m2e.core.lifecyclemapping.model.PluginExecutionAction; import org.eclipse.m2e.core.ui.internal.editing.PomEdits.Operation; public class LifecycleMappingOperation implements Operation { private static final Logger log = LoggerFactory.getLogger(LifecycleMappingOperation.class); private static final String LIFECYCLE_PLUGIN_VERSION = LifecycleMappingFactory.LIFECYCLE_MAPPING_PLUGIN_VERSION; private static final String LIFECYCLE_PLUGIN_ARTIFACTID = LifecycleMappingFactory.LIFECYCLE_MAPPING_PLUGIN_ARTIFACTID; private static final String LIFECYCLE_PLUGIN_GROUPID = LifecycleMappingFactory.LIFECYCLE_MAPPING_PLUGIN_GROUPID; private String version; private String groupId; private String artifactId; private PluginExecutionAction action; private String[] goals; /** * If set to true, then the lifecycle mapping metadata is created at the top level of the file, rather than within a * plugin. For use when not inside a pom */ private boolean createAtTopLevel = false; public LifecycleMappingOperation(String pluginGroupId, String pluginArtifactId, String pluginVersion, PluginExecutionAction action, String[] goals) { this(pluginGroupId, pluginArtifactId, pluginVersion, action, goals, false); } public LifecycleMappingOperation(String pluginGroupId, String pluginArtifactId, String pluginVersion, PluginExecutionAction action, String[] goals, boolean createAtTopLevel) { this.artifactId = pluginArtifactId; this.groupId = pluginGroupId; this.version = pluginVersion; assert !PluginExecutionAction.configurator.equals(action); this.action = action; this.goals = goals; this.createAtTopLevel = createAtTopLevel; } public void process(Document document) { Element root = document.getDocumentElement(); Element pluginExecutions; // add the new plugins here //now find the lifecycle stuff if it's there. if(createAtTopLevel) { if(root == null) { // probably an empty document root = document.createElement("lifecycleMappingMetadata"); //$NON-NLS-1$ document.appendChild(root); } pluginExecutions = getChild(root, "pluginExecutions"); //$NON-NLS-1$ } else { Element managedPlugins = getChild(root, BUILD, PLUGIN_MANAGEMENT, PLUGINS); Element lifecyclePlugin = findChild(managedPlugins, PLUGIN, childEquals(GROUP_ID, LIFECYCLE_PLUGIN_GROUPID), childEquals(ARTIFACT_ID, LIFECYCLE_PLUGIN_ARTIFACTID)); if(lifecyclePlugin == null) { //not found, create lifecyclePlugin = PomHelper.createPlugin(managedPlugins, LIFECYCLE_PLUGIN_GROUPID, LIFECYCLE_PLUGIN_ARTIFACTID, LIFECYCLE_PLUGIN_VERSION); //mkleint: a bit scared to have this text localized, with chinese/japanese locales, it could write garbage into the pom file.. Comment comment = document .createComment("This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself."); //$NON-NLS-1$ managedPlugins.insertBefore(comment, lifecyclePlugin); format(comment); } pluginExecutions = getChild(lifecyclePlugin, CONFIGURATION, "lifecycleMappingMetadata", "pluginExecutions"); //$NON-NLS-1$ //$NON-NLS-2$ } //now find the plugin execution for the plugin we have.. Element execution = null; for(Element exec : findChilds(pluginExecutions, "pluginExecution")) { //$NON-NLS-1$ Element filter = findChild(exec, "pluginExecutionFilter", //$NON-NLS-1$ childEquals(GROUP_ID, groupId), childEquals(ARTIFACT_ID, artifactId)); //the action needs to match the action we want.. Element actionEl = findChild(findChild(exec, "action"), action.toString()); //$NON-NLS-1$ if(filter != null && actionEl != null) { String versionRange = getTextValue(getChild(filter, "versionRange")); //$NON-NLS-1$ if(versionRange != null) { // paranoid null check //now we shall do some smart matching on the existing versionRange and our version.. //so far the "smart" thing involves just overwriting the range. try { VersionRange range = VersionRange.createFromVersionSpec(versionRange); if(!range.containsVersion(new DefaultArtifactVersion(version))) { Element rangeEl = findChild(filter, "versionRange"); //$NON-NLS-1$ setText(rangeEl, "[" + version + ",)"); //$NON-NLS-1$ //$NON-NLS-2$ } } catch(InvalidVersionSpecificationException e) { log.error("Failed to parse version range:" + versionRange, e); //$NON-NLS-1$ } } execution = exec; break; } } if(execution == null) { execution = createPluginExecution(document, pluginExecutions); } //now enter/update the goal(s).. Element goalsEl = getChild(execution, "pluginExecutionFilter", GOALS); //$NON-NLS-1$ List<String> toAddGoals = new ArrayList<String>(Arrays.asList(goals)); for(Element existingGoal : findChilds(goalsEl, GOAL)) { String glValue = getTextValue(existingGoal); if(glValue != null && toAddGoals.contains(glValue)) { toAddGoals.remove(glValue); } } if(toAddGoals.size() > 0) { for(String goal : toAddGoals) { format(createElementWithText(goalsEl, GOAL, goal)); } } } private Element createPluginExecution(Document document, Element parent) { Element exec = document.createElement("pluginExecution"); //$NON-NLS-1$ parent.appendChild(exec); Element filter = document.createElement("pluginExecutionFilter"); //$NON-NLS-1$ exec.appendChild(filter); createElementWithText(filter, GROUP_ID, groupId); createElementWithText(filter, ARTIFACT_ID, artifactId); createElementWithText(filter, "versionRange", "[" + version + ",)"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ Element actionEl = document.createElement("action"); //$NON-NLS-1$ exec.appendChild(actionEl); Element actionEl2 = document.createElement(action.toString()); actionEl.appendChild(actionEl2); if(PluginExecutionAction.execute.equals(action)) { //mkleint: a bit scared to have this text localized, with chinese/japanese locales, it could write garbage into the pom file.. actionEl2 .appendChild(document .createComment("use <runOnIncremental>false</runOnIncremental>to only execute the mojo during full/clean build")); //$NON-NLS-1$ } format(exec); return exec; } }