diff options
author | Anton Tanasenko | 2016-05-29 22:55:12 +0000 |
---|---|---|
committer | Fred Bricon | 2016-05-31 19:39:18 +0000 |
commit | b5df3e6ad3307e3a7f107af307efeee7e66fbb08 (patch) | |
tree | d1bf9419979ebb4c10274cda1c9ee9fd16ab89ee | |
parent | a216aad800082fcf7c8243c8faf470ecb6a3f407 (diff) | |
download | m2e-core-b5df3e6ad3307e3a7f107af307efeee7e66fbb08.tar.gz m2e-core-b5df3e6ad3307e3a7f107af307efeee7e66fbb08.tar.xz m2e-core-b5df3e6ad3307e3a7f107af307efeee7e66fbb08.zip |
494858 Support processing instructions for lifecycle mapping
Change-Id: I015f648fba3bab8d792543177b68c4f051150e4b
Signed-off-by: Anton Tanasenko <atg.sleepless@gmail.com>
6 files changed, 343 insertions, 15 deletions
diff --git a/org.eclipse.m2e.core/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.m2e.core/.settings/org.eclipse.jdt.ui.prefs index 595d9975..6cc57db7 100644 --- a/org.eclipse.m2e.core/.settings/org.eclipse.jdt.ui.prefs +++ b/org.eclipse.m2e.core/.settings/org.eclipse.jdt.ui.prefs @@ -28,7 +28,7 @@ sp_cleanup.always_use_this_for_non_static_method_access=false sp_cleanup.convert_to_enhanced_for_loop=false sp_cleanup.correct_indentation=false sp_cleanup.format_source_code=true -sp_cleanup.format_source_code_changes_only=false +sp_cleanup.format_source_code_changes_only=true sp_cleanup.make_local_variable_final=false sp_cleanup.make_parameters_final=false sp_cleanup.make_private_fields_final=true diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/Messages.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/Messages.java index d5d48924..3cd24b0d 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/Messages.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/Messages.java @@ -252,6 +252,10 @@ public class Messages extends NLS { public static String AbstractMavenRuntime_unknownProject; + public static String AnnotationMappingMetadataSource_ErrorParsingInstruction; + + public static String AnnotationMappingMetadataSource_UnsupportedInstructionFormat; + public static String ProjectConfiguratorToRunBeforeNotAvailable; public static String ProjectConfiguratorToRunAfterNotAvailable; diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/AnnotationMappingMetadataSource.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/AnnotationMappingMetadataSource.java new file mode 100644 index 00000000..aaf1fd23 --- /dev/null +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/AnnotationMappingMetadataSource.java @@ -0,0 +1,306 @@ +/*******************************************************************************
+ * Copyright (c) 2016 Anton Tanasenko.
+ * 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:
+ * Anton Tanasenko - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.lifecyclemapping;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableMap;
+
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.pull.MXParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+import org.apache.maven.model.InputLocation;
+import org.apache.maven.model.InputLocationTracker;
+import org.apache.maven.model.InputSource;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginContainer;
+import org.apache.maven.model.PluginExecution;
+import org.apache.maven.project.MavenProject;
+
+import org.eclipse.m2e.core.internal.Messages;
+import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadata;
+import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadataSource;
+import org.eclipse.m2e.core.internal.lifecyclemapping.model.PluginExecutionFilter;
+import org.eclipse.m2e.core.internal.lifecyclemapping.model.PluginExecutionMetadata;
+import org.eclipse.m2e.core.internal.markers.SourceLocation;
+import org.eclipse.m2e.core.lifecyclemapping.model.PluginExecutionAction;
+import org.eclipse.m2e.core.project.configurator.MojoExecutionKey;
+
+
+/**
+ * AnnotationMappingMetadataSource
+ *
+ * @author atgsl
+ */
+public class AnnotationMappingMetadataSource implements MappingMetadataSource {
+
+ private static final String SELF = ""; //$NON-NLS-1$
+
+ private final MavenProject project;
+
+ private final String projectId;
+
+ private final List<PI> pis;
+
+ public static AnnotationMappingMetadataSource get(MavenProject project) {
+ List<PI> pis = parsePIs(project);
+ if(!pis.isEmpty()) {
+ return new AnnotationMappingMetadataSource(project, pis);
+ }
+ return null;
+ }
+
+ private AnnotationMappingMetadataSource(MavenProject project, List<PI> pis) {
+ this.project = project;
+ this.pis = pis;
+ projectId = project.getModel().getLocation(SELF).getSource().getModelId();
+ }
+
+ public List<PluginExecutionMetadata> getPluginExecutionMetadata(MojoExecutionKey execution) {
+ Xpp3Dom action = getAction(execution);
+ if(action != null) {
+ return Collections.singletonList(createMetadata(action));
+ }
+ return Collections.emptyList();
+ }
+
+ private Xpp3Dom getAction(MojoExecutionKey execution) {
+
+ String key = Plugin.constructKey(execution.getGroupId(), execution.getArtifactId());
+ Plugin plugin = getPlugin(project.getBuild(), key);
+ Plugin mplugin = getPlugin(project.getPluginManagement(), key);
+
+ String executionId = execution.getExecutionId();
+ if(executionId != null) {
+
+ // find pi for the executionId
+ if(plugin != null) {
+ PluginExecution pluginExecution = plugin.getExecutionsAsMap().get(executionId);
+ if(pluginExecution != null) {
+ Xpp3Dom action = getAction(pluginExecution);
+ if(action != null)
+ return action;
+ }
+ }
+ if(mplugin != null) {
+ PluginExecution pluginExecution = mplugin.getExecutionsAsMap().get(executionId);
+ if(pluginExecution != null) {
+ Xpp3Dom action = getAction(pluginExecution);
+ if(action != null)
+ return action;
+ }
+ }
+
+ // find pi for the whole plugin
+ if(plugin != null) {
+ Xpp3Dom action = getAction(plugin);
+ if(action != null)
+ return action;
+ }
+ if(mplugin != null) {
+ Xpp3Dom action = getAction(mplugin);
+ if(action != null)
+ return action;
+ }
+ }
+ return null;
+ }
+
+ private Plugin getPlugin(PluginContainer plugins, String key) {
+ return plugins == null ? null : plugins.getPluginsAsMap().get(key);
+ }
+
+ public LifecycleMappingMetadata getLifecycleMappingMetadata(String packagingType) throws DuplicateMappingException {
+ return null;
+ }
+
+ private Xpp3Dom getAction(InputLocationTracker tracker) {
+ InputLocation location = tracker.getLocation(SELF);
+
+ if(location != null && location.getSource() != null && projectId.equals(location.getSource().getModelId())) {
+ int l = location.getLineNumber();
+ int c = location.getColumnNumber();
+ for(PI pi : pis) {
+ if(pi.l == l && pi.c == c) {
+ return pi.action;
+ }
+ }
+ }
+ return null;
+ }
+
+ private PluginExecutionMetadata createMetadata(Xpp3Dom action) {
+ Xpp3Dom actionDom = new Xpp3Dom("action"); //$NON-NLS-1$
+ actionDom.addChild(action);
+
+ PluginExecutionMetadata md = new PluginExecutionMetadata();
+ md.setActionDom(actionDom);
+ LifecycleMappingMetadataSource source = new LifecycleMappingMetadataSource();
+ source.setSource(project);
+ md.setSource(source);
+ md.setFilter(new PluginExecutionFilter());
+ return md;
+ }
+
+ private static List<PI> parsePIs(MavenProject project) {
+
+ File pom = project.getFile();
+ InputSource source = project.getModel().getLocation(SELF).getSource();
+
+ List<PI> pis = new ArrayList<>();
+
+ XmlPullParser parser = new MXParser();
+
+ try (InputStream in = new FileInputStream(pom)) {
+ parser.setInput(ReaderFactory.newXmlReader(in));
+
+ Deque<State> stack = new LinkedList<>();
+
+ int eventType = parser.getEventType();
+ while(eventType != XmlPullParser.END_DOCUMENT) {
+
+ if(eventType == XmlPullParser.START_TAG) {
+
+ stack.push(new State(parser.getLineNumber(), parser.getColumnNumber()));
+
+ } else if(eventType == XmlPullParser.END_TAG) {
+
+ stack.pop();
+
+ } else if(eventType == XmlPullParser.PROCESSING_INSTRUCTION && !stack.isEmpty()) {
+
+
+ String text = parser.getText();
+ if(text.startsWith("m2e ")) { //$NON-NLS-1$
+ // found it
+ Xpp3Dom dom = parse(text.substring(4));
+ if(dom == null) {
+ SourceLocation location = new SourceLocation(source.getLocation(), source.getModelId(),
+ parser.getLineNumber(), parser.getColumnNumber(), text.length() + 4);
+ throw new LifecycleMappingConfigurationException(Messages.AnnotationMappingMetadataSource_UnsupportedInstructionFormat, location);
+ }
+ State s = stack.peek();
+ PI pi = new PI(s.l, s.c, dom);
+ pis.add(pi);
+ }
+ }
+
+ eventType = parser.nextToken();
+ }
+
+ } catch(XmlPullParserException | IOException ex) {
+ SourceLocation location = new SourceLocation(source.getLocation(), source.getModelId(), parser.getLineNumber(),
+ parser.getColumnNumber(), 1);
+ throw new LifecycleMappingConfigurationException(Messages.AnnotationMappingMetadataSource_ErrorParsingInstruction, location);
+ }
+
+ return pis;
+ }
+
+ private static final Splitter PI_SPLITTER = Splitter.on(CharMatcher.WHITESPACE).omitEmptyStrings().limit(2);
+
+ private static final Splitter EXECUTE_SPLITTER = Splitter.on(',').omitEmptyStrings();
+
+ private static final Map<String, String> EXECUTE_OPTIONS = new ImmutableMap.Builder<String, String>()
+ .put("onConfiguration", LifecycleMappingFactory.ELEMENT_RUN_ON_CONFIGURATION) //$NON-NLS-1$
+ .put("onIncremental", LifecycleMappingFactory.ELEMENT_RUN_ON_INCREMENTAL).build(); //$NON-NLS-1$
+
+ private static Xpp3Dom parse(String pi) {
+
+ List<String> split = PI_SPLITTER.splitToList(pi);
+
+ PluginExecutionAction a = getAction(split.get(0));
+ if(a == null) {
+ return null;
+ }
+ switch(a) {
+ case ignore:
+ return new Xpp3Dom("ignore"); //$NON-NLS-1$
+
+ case configurator:
+ if(split.size() != 2) {
+ return null;
+ }
+ Xpp3Dom conf = new Xpp3Dom("configurator"); //$NON-NLS-1$
+ Xpp3Dom id = new Xpp3Dom("id"); //$NON-NLS-1$
+ id.setValue(split.get(1));
+ conf.addChild(id);
+ return conf;
+
+ case execute:
+ Xpp3Dom exec = new Xpp3Dom("execute"); //$NON-NLS-1$
+ if(split.size() > 1) {
+ for(String option : EXECUTE_SPLITTER.split(split.get(1))) {
+ String value = EXECUTE_OPTIONS.get(option);
+ if(value == null) {
+ return null;
+ }
+ Xpp3Dom opt = new Xpp3Dom(value);
+ opt.setValue("true"); //$NON-NLS-1$
+ exec.addChild(opt);
+ }
+ }
+ return exec;
+
+ default:
+ return null;
+ }
+ }
+
+ private static PluginExecutionAction getAction(String value) {
+ for(PluginExecutionAction a : PluginExecutionAction.values()) {
+ if(value.toLowerCase().equals(a.name())) {
+ return a;
+ }
+ }
+ return null;
+ }
+
+ private static class State {
+ final int l;
+
+ final int c;
+
+ State(int l, int c) {
+ this.l = l;
+ this.c = c;
+ }
+ }
+
+ private static class PI {
+ final int l;
+
+ final int c;
+
+ final Xpp3Dom action;
+
+ PI(int l, int c, Xpp3Dom action) {
+ this.l = l;
+ this.c = c;
+ this.action = action;
+ }
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/LifecycleMappingFactory.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/LifecycleMappingFactory.java index 9343cc1c..93f12331 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/LifecycleMappingFactory.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/LifecycleMappingFactory.java @@ -152,9 +152,9 @@ public class LifecycleMappingFactory { private static final String ELEMENT_MESSAGE = "message"; //$NON-NLS-1$ - private static final String ELEMENT_RUN_ON_INCREMENTAL = "runOnIncremental"; + static final String ELEMENT_RUN_ON_INCREMENTAL = "runOnIncremental"; - private static final String ELEMENT_RUN_ON_CONFIGURATION = "runOnConfiguration"; + static final String ELEMENT_RUN_ON_CONFIGURATION = "runOnConfiguration"; private static final String ATTR_GROUPID = "groupId"; @@ -266,7 +266,7 @@ public class LifecycleMappingFactory { // List order // 1. preferences in project (*** not implemented yet) // 2. preferences in ancestor project (*** not implemented yet) - // 3. this pom embedded, this pom referenced, parent embedded, parent referenced, grand parent embedded... + // 3. this pom (annotated, embedded, referenced), parent (annotated, embedded, referenced), grand parent (embedded... // 4. preferences in workspace // 5. sources contributed by eclipse extensions // 6. maven-plugin embedded metadata @@ -275,10 +275,8 @@ public class LifecycleMappingFactory { // TODO validate metadata and replace invalid entries with error mapping List<MappingMetadataSource> metadataSources = new ArrayList<MappingMetadataSource>(); - for(LifecycleMappingMetadataSource source : getPomMappingMetadataSources(mavenProject, monitor)) { - metadataSources.add(new SimpleMappingMetadataSource(source)); - } - metadataSourcesMap.put("pomMappingMetadataSources", metadataSources); + + metadataSourcesMap.put("pomMappingMetadataSources", getPomMappingMetadataSources(mavenProject, monitor)); metadataSourcesMap.put("workspaceMetadataSources", // Collections @@ -838,11 +836,11 @@ public class LifecycleMappingFactory { * * @throws CoreException if metadata sources cannot be resolved or read */ - public static List<LifecycleMappingMetadataSource> getPomMappingMetadataSources(MavenProject mavenProject, + public static List<MappingMetadataSource> getPomMappingMetadataSources(MavenProject mavenProject, IProgressMonitor monitor) throws CoreException { IMaven maven = MavenPlugin.getMaven(); - ArrayList<LifecycleMappingMetadataSource> sources = new ArrayList<LifecycleMappingMetadataSource>(); + List<MappingMetadataSource> sources = new ArrayList<MappingMetadataSource>(); HashSet<String> referenced = new LinkedHashSet<String>(); @@ -851,17 +849,27 @@ public class LifecycleMappingFactory { if(monitor.isCanceled()) { break; } + boolean detach = false; + AnnotationMappingMetadataSource annSource = AnnotationMappingMetadataSource.get(project); + if(annSource != null) { + detach = true; + sources.add(annSource); + } LifecycleMappingMetadataSource embeddedSource = getEmbeddedMetadataSource(project); if(embeddedSource != null) { - maven.detachFromSession(project); // don't cache maven session + detach = true; embeddedSource.setSource(project); - sources.add(embeddedSource); + sources.add(new SimpleMappingMetadataSource(embeddedSource)); } for(LifecycleMappingMetadataSource referencedSource : getReferencedMetadataSources(referenced, project, monitor)) { - sources.add(referencedSource); + sources.add(new SimpleMappingMetadataSource(referencedSource)); + } + + if(detach) { + maven.detachFromSession(project); // don't cache maven session } // TODO ideally, we need to reuse the same parent MavenProject instance in all child modules diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/SimpleMappingMetadataSource.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/SimpleMappingMetadataSource.java index 79052c2d..b9519afe 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/SimpleMappingMetadataSource.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/SimpleMappingMetadataSource.java @@ -27,16 +27,20 @@ import org.eclipse.m2e.core.project.configurator.MojoExecutionKey; */ public class SimpleMappingMetadataSource implements MappingMetadataSource { - private final List<LifecycleMappingMetadata> lifecycleMappings = new ArrayList<LifecycleMappingMetadata>(); + private final List<LifecycleMappingMetadataSource> sources = new ArrayList<>(); - private final List<PluginExecutionMetadata> pluginExecutions = new ArrayList<PluginExecutionMetadata>(); + private final List<LifecycleMappingMetadata> lifecycleMappings = new ArrayList<>(); + + private final List<PluginExecutionMetadata> pluginExecutions = new ArrayList<>(); public SimpleMappingMetadataSource(LifecycleMappingMetadataSource source) { + this.sources.add(source); this.lifecycleMappings.addAll(source.getLifecycleMappings()); this.pluginExecutions.addAll(source.getPluginExecutions()); } public SimpleMappingMetadataSource(List<LifecycleMappingMetadataSource> sources) { + this.sources.addAll(sources); for(LifecycleMappingMetadataSource source : sources) { this.lifecycleMappings.addAll(source.getLifecycleMappings()); this.pluginExecutions.addAll(source.getPluginExecutions()); @@ -48,6 +52,10 @@ public class SimpleMappingMetadataSource implements MappingMetadataSource { this.pluginExecutions.addAll(lifecycleMapping.getPluginExecutions()); } + public List<LifecycleMappingMetadataSource> getSources() { + return this.sources; + } + public LifecycleMappingMetadata getLifecycleMappingMetadata(String packagingType) throws DuplicateMappingException { if(packagingType == null) { return null; diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/messages.properties b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/messages.properties index cc1c8418..cbfb0fa2 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/messages.properties +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/messages.properties @@ -7,6 +7,8 @@ AbstractTransferListenerAdapter_cancelled=Transfer is canceled AbstractTransferListenerAdapter_kb=KB AbstractTransferListenerAdapter_mb=MB AbstractTransferListenerAdapter_subtask=error {0} +AnnotationMappingMetadataSource_ErrorParsingInstruction=Error parsing lifecycle processing instructions +AnnotationMappingMetadataSource_UnsupportedInstructionFormat=Unsupported instruction format ArchetypeCatalogFactory_default_local=Default Local ArchetypeCatalogFactory_error_missing_catalog=Error looking up archetype catalog; {0} ArchetypeCatalogFactory_indexer_catalog=Nexus Indexer |