From a08b9c04d2cd2f4cb57636d9030e3ba9a00f2e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Sat, 5 Feb 2022 19:07:55 +0100 Subject: [PATCH] Improve conflict handling of lifecycle mappings #549 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - record what is causing the conflict - add the exception to the maven problem - show problem markers at the correct location in the pom Signed-off-by: Christoph Läubrich --- ...cateLifecycleMappingMetadataException.java | 43 +++++++++++ .../DuplicateMappingException.java | 24 ++++--- ...icatePluginExecutionMetadataException.java | 42 +++++++++++ .../FailedMappingMetadataSource.java | 71 +++++++++++++++++++ .../LifecycleMappingFactory.java | 24 ++++--- .../SimpleMappingMetadataSource.java | 25 ++++--- .../internal/markers/MavenProblemInfo.java | 26 +++++-- 7 files changed, 217 insertions(+), 38 deletions(-) create mode 100644 org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/DuplicateLifecycleMappingMetadataException.java create mode 100644 org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/DuplicatePluginExecutionMetadataException.java create mode 100644 org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/FailedMappingMetadataSource.java diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/DuplicateLifecycleMappingMetadataException.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/DuplicateLifecycleMappingMetadataException.java new file mode 100644 index 0000000000..554155cf0e --- /dev/null +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/DuplicateLifecycleMappingMetadataException.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2022 Christoph Läubrich and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ + +package org.eclipse.m2e.core.internal.lifecyclemapping; + +import java.util.Arrays; + +import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadata; +import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadataSource; + + +/** + * DuplicateLifecycleMappingMetadataException + * + */ +public class DuplicateLifecycleMappingMetadataException extends DuplicateMappingException { + + private LifecycleMappingMetadata[] lifecyclemappings; + + public DuplicateLifecycleMappingMetadataException(LifecycleMappingMetadata... lifecyclemappings) { + super(Arrays.stream(lifecyclemappings).map(LifecycleMappingMetadata::getSource) + .toArray(LifecycleMappingMetadataSource[]::new)); + this.lifecyclemappings = lifecyclemappings; + } + + /** + * @return Returns the lifecyclemappings. + */ + public LifecycleMappingMetadata[] getConflictingMappings() { + return this.lifecyclemappings; + } + +} diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/DuplicateMappingException.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/DuplicateMappingException.java index b9611feab1..cc243778fc 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/DuplicateMappingException.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/DuplicateMappingException.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010 Sonatype, Inc. + * Copyright (c) 2010, 2022 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -9,10 +9,14 @@ * * Contributors: * Sonatype, Inc. - initial API and implementation + * Christoph Läubrich - #549 - Improve conflict handling of lifecycle mappings *******************************************************************************/ package org.eclipse.m2e.core.internal.lifecyclemapping; +import java.util.Arrays; +import java.util.stream.Collectors; + 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.PluginExecutionMetadata; @@ -22,18 +26,16 @@ * Exception thrown when multiple metadata source for either {@link PluginExecutionMetadata} or * {@link LifecycleMappingMetadata} are found for the same plugin/packaging. */ -public class DuplicateMappingException extends RuntimeException { +public abstract class DuplicateMappingException extends RuntimeException { private static final String DESCRIPTION_UNKNOWN_SOURCE = "unknown source"; private static final long serialVersionUID = -7303637464019592307L; - private final LifecycleMappingMetadataSource source1; + private final LifecycleMappingMetadataSource[] sources; - private final LifecycleMappingMetadataSource source2; - public DuplicateMappingException(LifecycleMappingMetadataSource source1, LifecycleMappingMetadataSource source2) { - this.source1 = source1; - this.source2 = source2; + protected DuplicateMappingException(LifecycleMappingMetadataSource... sources) { + this.sources = sources; } /* (non-Javadoc) @@ -41,10 +43,10 @@ public DuplicateMappingException(LifecycleMappingMetadataSource source1, Lifecyc */ public String getMessage() { // sources might be either bundle, artifact or "default", "workspace" or MavenProject (all should provide proper toString() implementations) - String source1Description = source1 != null ? source1.getSource().toString() : DESCRIPTION_UNKNOWN_SOURCE; - String source2Description = source2 != null ? source2.getSource().toString() : DESCRIPTION_UNKNOWN_SOURCE; - - return "Mapping defined in '" + source1Description + "' and '" + source2Description + "'"; + return "Duplicate Mappings defined in " + + Arrays.stream(sources).map(s -> s.getSource()).map(s -> s == null ? DESCRIPTION_UNKNOWN_SOURCE : s.toString()) + .collect(Collectors.joining(", ", "'", "'")); } + } diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/DuplicatePluginExecutionMetadataException.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/DuplicatePluginExecutionMetadataException.java new file mode 100644 index 0000000000..d839cc973c --- /dev/null +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/DuplicatePluginExecutionMetadataException.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2022 Christoph Läubrich and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.core.internal.lifecyclemapping; + +import java.util.Arrays; + +import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadataSource; +import org.eclipse.m2e.core.internal.lifecyclemapping.model.PluginExecutionMetadata; + + +/** + * DuplicatePluginExecutionMetadataException + * + */ +public class DuplicatePluginExecutionMetadataException extends DuplicateMappingException{ + + private PluginExecutionMetadata[] pluginExecutionMetadatas; + + public DuplicatePluginExecutionMetadataException(PluginExecutionMetadata... pluginExecutionMetadatas) { + super( + Arrays.stream(pluginExecutionMetadatas).map(PluginExecutionMetadata::getSource) + .toArray(LifecycleMappingMetadataSource[]::new)); + this.pluginExecutionMetadatas = pluginExecutionMetadatas; + } + + /** + * @return Returns the sources. + */ + public PluginExecutionMetadata[] getConflictingMetadata() { + return this.pluginExecutionMetadatas; + } +} diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/FailedMappingMetadataSource.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/FailedMappingMetadataSource.java new file mode 100644 index 0000000000..bb147fcebc --- /dev/null +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/lifecyclemapping/FailedMappingMetadataSource.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2022 Christoph Läubrich and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.core.internal.lifecyclemapping; + +import java.util.List; + +import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadata; +import org.eclipse.m2e.core.internal.lifecyclemapping.model.PluginExecutionMetadata; +import org.eclipse.m2e.core.project.configurator.MojoExecutionKey; + + +/** + * FailedMappingMetadataSource + * + */ +public class FailedMappingMetadataSource implements MappingMetadataSource { + + private DuplicateMappingException failure; + + private MappingMetadataSource source; + + /** + * @param source + * @param failure + */ + public FailedMappingMetadataSource(MappingMetadataSource source, DuplicateMappingException e) { + this.source = source; + this.failure = e; + } + + /* (non-Javadoc) + * @see org.eclipse.m2e.core.internal.lifecyclemapping.MappingMetadataSource#getLifecycleMappingMetadata(java.lang.String) + */ + @Override + public LifecycleMappingMetadata getLifecycleMappingMetadata(String packagingType) throws DuplicateMappingException { + throw failure; + } + + /* (non-Javadoc) + * @see org.eclipse.m2e.core.internal.lifecyclemapping.MappingMetadataSource#getPluginExecutionMetadata(org.eclipse.m2e.core.project.configurator.MojoExecutionKey) + */ + @Override + public List getPluginExecutionMetadata(MojoExecutionKey execution) { + return source.getPluginExecutionMetadata(execution); + } + + /** + * @return Returns the failure. + */ + public DuplicateMappingException getFailure() { + return this.failure; + } + + /** + * @return Returns the source. + */ + public MappingMetadataSource getSource() { + return this.source; + } + +} 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 5672cc0274..917ec6f2a5 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008-2015 Sonatype, Inc. and others. + * Copyright (c) 2008, 2022 Sonatype, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -12,6 +12,7 @@ * Andrew Eisenberg - Work on Bug 350414 * Fred Bricon (Red Hat) - project configurator sort (Bug #449495) * Anton Tanasenko - Refactor marker resolutions and quick fixes (Bug #484359) + * Christoph Läubrich - #549 - Improve conflict handling of lifecycle mappings *******************************************************************************/ package org.eclipse.m2e.core.internal.lifecyclemapping; @@ -536,10 +537,13 @@ public static void calculateEffectiveLifecycleMappingMetadata(final LifecycleMap break; } } catch(DuplicateMappingException e) { + SourceLocation location = SourceLocationHelper.findPackagingLocation(mavenProject); log.error("Duplicate lifecycle mapping metadata for {}.", mavenProject, e); - result.addProblem(new MavenProblemInfo(1, - NLS.bind(Messages.LifecycleDuplicate, mavenProject.getPackaging(), e.getMessage()))); - return; // fatal error + result.addProblem(new MavenProblemInfo(location, + NLS.bind(Messages.LifecycleDuplicate, mavenProject.getPackaging(), e.getMessage()), e)); + originalMetadataSource = new FailedMappingMetadataSource(source, e); + metadataSources.add(i, originalMetadataSource); + break; } } @@ -598,7 +602,8 @@ public static void calculateEffectiveLifecycleMappingMetadata(final LifecycleMap } catch(CycleDetectedException ex) { log.error(ex.getMessage(), ex); result.addProblem(new MavenProblemInfo(1, - NLS.bind("Cyclic dependency detected between project configurators for {0}", mavenProject.toString()))); + NLS.bind("Cyclic dependency detected between project configurators for {0}", mavenProject.toString()), + ex)); return;// fatal error } @@ -608,7 +613,7 @@ public static void calculateEffectiveLifecycleMappingMetadata(final LifecycleMap for(PluginExecutionMetadata executionMetadata : entry.getValue()) { if(isPrimaryMapping(executionMetadata, sorter)) { if(primaryMetadata != null) { - throw new DuplicateMappingException(primaryMetadata.getSource(), executionMetadata.getSource()); + throw new DuplicatePluginExecutionMetadataException(primaryMetadata, executionMetadata); } primaryMetadata = executionMetadata; } @@ -619,16 +624,17 @@ public static void calculateEffectiveLifecycleMappingMetadata(final LifecycleMap } } catch(DuplicateMappingException e) { primaryMetadata = null; + SourceLocation location = SourceLocationHelper.findLocation(mavenProject, executionKey); log.debug("Duplicate plugin execution mapping metadata for {}.", executionKey, e); result.addProblem( - new MavenProblemInfo(1, - NLS.bind(Messages.PluginExecutionMappingDuplicate, executionKey.toString(), e.getMessage()))); + new MavenProblemInfo(location, + NLS.bind(Messages.PluginExecutionMappingDuplicate, executionKey.toString(), e.getMessage()), e)); } if(primaryMetadata != null && !isValidPluginExecutionMetadata(primaryMetadata)) { log.debug("Invalid plugin execution mapping metadata for {}.", executionKey); result.addProblem( - new MavenProblemInfo(1, NLS.bind(Messages.PluginExecutionMappingInvalid, executionKey.toString()))); + new MavenProblemInfo(1, NLS.bind(Messages.PluginExecutionMappingInvalid, executionKey.toString()), null)); primaryMetadata = null; } 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 74970ea969..63ea13ee73 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010 Sonatype, Inc. + * Copyright (c) 2010, 2022 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -9,12 +9,14 @@ * * Contributors: * Sonatype, Inc. - initial API and implementation + * Christoph Läubrich - #549 - Improve conflict handling of lifecycle mappings *******************************************************************************/ package org.eclipse.m2e.core.internal.lifecyclemapping; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadata; import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadataSource; @@ -59,20 +61,21 @@ public List getSources() { } @Override - public LifecycleMappingMetadata getLifecycleMappingMetadata(String packagingType) throws DuplicateMappingException { + public LifecycleMappingMetadata getLifecycleMappingMetadata(String packagingType) + throws DuplicateLifecycleMappingMetadataException { if(packagingType == null) { return null; } - LifecycleMappingMetadata mapping = null; - for(LifecycleMappingMetadata _mapping : lifecycleMappings) { - if(packagingType.equals(_mapping.getPackagingType())) { - if(mapping != null) { - throw new DuplicateMappingException(mapping.getSource(), _mapping.getSource()); - } - mapping = _mapping; - } + + List matching = lifecycleMappings.stream() + .filter(mapping -> packagingType.equals(mapping.getPackagingType())).collect(Collectors.toList()); + if(matching.isEmpty()) { + return null; + } + if(matching.size() == 1) { + return matching.get(0); } - return mapping; + throw new DuplicateLifecycleMappingMetadataException(matching.toArray(LifecycleMappingMetadata[]::new)); } @Override diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/markers/MavenProblemInfo.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/markers/MavenProblemInfo.java index 16900a1f67..1f90b40ef3 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/markers/MavenProblemInfo.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/markers/MavenProblemInfo.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010 Sonatype, Inc. + * Copyright (c) 2010, 2022 Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -9,6 +9,7 @@ * * Contributors: * Sonatype, Inc. - initial API and implementation + * Christoph Läubrich - #549 - Improve conflict handling of lifecycle mappings *******************************************************************************/ package org.eclipse.m2e.core.internal.markers; @@ -29,16 +30,33 @@ public class MavenProblemInfo { private final int severity; + private Throwable error; + public MavenProblemInfo(int line, Throwable error) { this(new SourceLocation(line, 0, 0), error); } public MavenProblemInfo(SourceLocation location, Throwable error) { this.location = location; + this.error = error; this.message = getErrorMessage(error); this.severity = IMarker.SEVERITY_ERROR; } + public MavenProblemInfo(SourceLocation location, String message, Throwable error) { + this.location = location; + this.error = error; + this.message = message; + this.severity = IMarker.SEVERITY_ERROR; + } + + public MavenProblemInfo(int line, String message, Throwable error) { + this.error = error; + this.location = new SourceLocation(line, 0, 0); + this.message = message; + this.severity = IMarker.SEVERITY_ERROR; + } + public MavenProblemInfo(MavenProject mavenProject, LifecycleMappingConfigurationException error) { SourceLocation errorLocation = error.getLocation(); if(errorLocation != null) { @@ -55,12 +73,6 @@ public MavenProblemInfo(MavenProject mavenProject, LifecycleMappingConfiguration this.severity = IMarker.SEVERITY_ERROR; } - public MavenProblemInfo(int line, String message) { - //TODO - this.location = new SourceLocation(line, 0, 0); - this.message = message; - this.severity = IMarker.SEVERITY_ERROR; - } public MavenProblemInfo(String message, SourceLocation location) { this(message, IMarker.SEVERITY_ERROR, location);