Skip to content

Commit

Permalink
Improve conflict handling of lifecycle mappings eclipse-m2e#549
Browse files Browse the repository at this point in the history
- 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 <[email protected]>
  • Loading branch information
laeubi committed Feb 5, 2022
1 parent beaac63 commit a08b9c0
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 38 deletions.
Original file line number Diff line number Diff line change
@@ -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;
}

}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand All @@ -22,29 +26,27 @@
* 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)
* @see java.lang.Throwable#getMessage()
*/
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(", ", "'", "'"));
}


}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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<PluginExecutionMetadata> 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;
}

}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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
}

Expand All @@ -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;
}
Expand All @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -59,20 +61,21 @@ public List<LifecycleMappingMetadataSource> 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<LifecycleMappingMetadata> 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
Expand Down
Loading

0 comments on commit a08b9c0

Please sign in to comment.