[MNG-3119] Modifying MavenProject.addAttachment(..) and MavenProjectHelper.attachArtifact(..) implementations to throw an unchecked exception when a project attachment will collide with existing attachments. This includes tests to verify the behavior. The unchecked exception allows Maven to deal with it as a real build failure, while avoiding the need to modify the MavenProjectHelper API, which is part of Maven's core and which would render many existing plugins incompatible with new Maven releases.

git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@618497 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
John Dennis Casey 2008-02-05 00:09:27 +00:00
parent e38fa6fcc5
commit 10da177f1d
14 changed files with 414 additions and 27 deletions

View File

@ -25,6 +25,7 @@ import org.apache.maven.lifecycle.LifecycleExecutor;
import org.apache.maven.lifecycle.LifecycleLoaderException;
import org.apache.maven.lifecycle.LifecycleSpecificationException;
import org.apache.maven.lifecycle.plan.LifecyclePlannerException;
import org.apache.maven.project.DuplicateArtifactAttachmentException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.plugin.DefaultPluginManager;
import org.apache.maven.plugin.PluginManager;
@ -75,10 +76,18 @@ public privileged aspect LifecycleErrorReporterAspect
execution( private * DefaultLifecycleExecutor.getMojoDescriptorForDirectInvocation( String, MavenSession, MavenProject ) )
&& args( task, session, project )
{
System.out.println( "BINGO" );
getReporter().reportInvalidPluginForDirectInvocation( task, session, project, cause );
}
after( MojoBinding binding,
MavenProject project) throwing ( DuplicateArtifactAttachmentException cause ):
cflow( le_executeGoalAndHandleFailures( binding ) )
&& cflow( pm_executeMojo( project ) )
&& call( void Mojo+.execute() )
{
getReporter().reportDuplicateAttachmentException( binding, project, cause );
}
after( MojoBinding binding,
MavenProject project) throwing ( MojoExecutionException cause ):
cflow( le_executeGoalAndHandleFailures( binding ) )

View File

@ -32,6 +32,7 @@ import org.apache.maven.plugin.descriptor.Parameter;
import org.apache.maven.plugin.loader.PluginLoaderException;
import org.apache.maven.plugin.version.PluginVersionNotFoundException;
import org.apache.maven.plugin.version.PluginVersionResolutionException;
import org.apache.maven.project.DuplicateArtifactAttachmentException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
@ -128,4 +129,6 @@ public interface CoreErrorReporter
void reportInvalidPluginForDirectInvocation( String task, MavenSession session, MavenProject project, InvalidPluginException err );
void reportDuplicateAttachmentException( MojoBinding binding, MavenProject project, DuplicateArtifactAttachmentException cause );
}

View File

@ -20,6 +20,7 @@ import org.apache.maven.plugin.descriptor.Parameter;
import org.apache.maven.plugin.loader.PluginLoaderException;
import org.apache.maven.plugin.version.PluginVersionNotFoundException;
import org.apache.maven.plugin.version.PluginVersionResolutionException;
import org.apache.maven.project.DuplicateArtifactAttachmentException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
import org.apache.maven.project.interpolation.ModelInterpolationException;
@ -318,4 +319,12 @@ public final class CoreErrorTips
return null;
}
public static List getDuplicateAttachmentTips( MojoBinding binding,
MavenProject project,
DuplicateArtifactAttachmentException cause )
{
// TODO Auto-generated method stub
return null;
}
}

View File

@ -37,6 +37,7 @@ import org.apache.maven.plugin.descriptor.Parameter;
import org.apache.maven.plugin.loader.PluginLoaderException;
import org.apache.maven.plugin.version.PluginVersionNotFoundException;
import org.apache.maven.plugin.version.PluginVersionResolutionException;
import org.apache.maven.project.DuplicateArtifactAttachmentException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
@ -1698,4 +1699,35 @@ public class DefaultCoreErrorReporter
registerBuildError( err, writer.toString() );
}
public void reportDuplicateAttachmentException( MojoBinding binding,
MavenProject project,
DuplicateArtifactAttachmentException cause )
{
StringWriter writer = new StringWriter();
writer.write( NEWLINE );
writer.write( "Your build attempted to attach multiple artifacts with the same classifier to the main project." );
writer.write( NEWLINE );
writer.write( NEWLINE );
writer.write( "Mojo responsible for second attachment attempt:" );
writer.write( MojoBindingUtils.toString( binding ) );
writer.write( NEWLINE );
writer.write( NEWLINE );
writer.write( "Reported for project:" );
// Note: Using cause.getProject(), since an aggregator mojo (or, really, any sort)
// could try to attach to any of the projects in the reactor, and in the case of the aggregator,
// the project passed into the mojo execution and passed on here would just be the root project.
writeProjectCoordinate( cause.getProject(), writer );
writer.write( NEWLINE );
writer.write( NEWLINE );
writer.write( "Artifact attachment:" );
writeArtifactInfo( cause.getArtifact(), writer, false );
addTips( CoreErrorTips.getDuplicateAttachmentTips( binding, project, cause ), writer );
registerBuildError( cause, writer.toString() );
}
}

View File

@ -51,6 +51,7 @@ import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugin.version.PluginVersionManager;
import org.apache.maven.plugin.version.PluginVersionNotFoundException;
import org.apache.maven.plugin.version.PluginVersionResolutionException;
import org.apache.maven.project.DuplicateArtifactAttachmentException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectBuilder;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
@ -540,7 +541,19 @@ public class DefaultPluginManager
Thread.currentThread().setContextClassLoader( pluginRealm );
mojo.execute();
// NOTE: DuplicateArtifactAttachmentException is currently unchecked, so be careful removing this try/catch!
// This is necessary to avoid creating compatibility problems for existing plugins that use
// MavenProjectHelper.attachArtifact(..).
try
{
mojo.execute();
}
catch( DuplicateArtifactAttachmentException e )
{
session.getEventDispatcher().dispatchError( event, goalExecId, e );
throw new PluginExecutionException( mojoExecution, project, e );
}
// NEW: If the mojo that just executed is a report, store it in the LifecycleExecutionContext
// for reference by future mojos.

View File

@ -1,5 +1,6 @@
package org.apache.maven.plugin;
import org.apache.maven.project.DuplicateArtifactAttachmentException;
import org.apache.maven.project.MavenProject;
public class PluginExecutionException
@ -24,6 +25,14 @@ public class PluginExecutionException
this.mojoExecution = mojoExecution;
}
public PluginExecutionException( MojoExecution mojoExecution,
MavenProject project,
DuplicateArtifactAttachmentException cause )
{
super( mojoExecution.getMojoDescriptor(), project, "Mojo execution failed.", cause );
this.mojoExecution = mojoExecution;
}
public MojoExecution getMojoExecution()
{
return mojoExecution;

View File

@ -0,0 +1,54 @@
<?xml version='1.0' encoding='UTF-8'?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.maven.errortest</groupId>
<artifactId>duplicated-attachments-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>1</version>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.0.7</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.3.1</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.3</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.1</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
</plugin>
<plugin>
<artifactId>maven-plugin-plugin</artifactId>
<version>2.3</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@ -0,0 +1,50 @@
package org.plugin;
import org.apache.maven.plugin.Mojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProjectHelper;
import org.apache.maven.project.MavenProject;
/**
* @goal test
*
* @author jdcasey
*/
public class TestPlugin
implements Mojo
{
private Log log;
/**
* @component
*/
private MavenProjectHelper mavenProjectHelper;
/**
* @parameter default-value="${project}"
* @required
* @readonly
*/
private MavenProject project;
public void execute()
throws MojoExecutionException, MojoFailureException
{
mavenProjectHelper.attachArtifact( project, "pom", "classifier", project.getFile() );
mavenProjectHelper.attachArtifact( project, "pom", "classifier", project.getFile() );
}
public Log getLog()
{
return log;
}
public void setLog( Log log )
{
this.log = log;
}
}

View File

@ -0,0 +1,25 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.maven</groupId>
<artifactId>duplicated-attachments</artifactId>
<version>1</version>
</project>

View File

@ -1505,4 +1505,39 @@ public class ErrorReporterPointcutTest
reporterCtl.verify();
}
public void testReportDuplicateAttachmentException()
throws IOException
{
File projectDir = prepareProjectDir( "duplicated-attachments" );
File plugin = new File( projectDir, "plugin" );
File project = new File( projectDir, "project" );
buildTestAccessory( plugin );
Settings settings = new Settings();
settings.addPluginGroup( "org.apache.maven.errortest" );
reporter.reportDuplicateAttachmentException( null, null, null );
reporterCtl.setMatcher( MockControl.ALWAYS_MATCHER );
reporterCtl.setVoidCallable();
reporterCtl.replay();
MavenExecutionRequest request = new DefaultMavenExecutionRequest().setBaseDirectory( project )
.setSettings( settings )
.setShowErrors( true )
.setErrorReporter( reporter )
.setGoals( Arrays.asList( new String[] {
"duplicated-attachments:test"
} ) );
MavenExecutionResult result = maven.execute( request );
assertTrue( result.hasExceptions() );
reportExceptions( result, project );
reporterCtl.verify();
}
}

View File

@ -24,62 +24,79 @@ import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
import org.apache.maven.model.Resource;
import org.apache.maven.project.artifact.AttachedArtifact;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import java.io.File;
import java.util.List;
public class DefaultMavenProjectHelper
extends AbstractLogEnabled
implements MavenProjectHelper
{
private ArtifactHandlerManager artifactHandlerManager;
public void attachArtifact( MavenProject project, String artifactType, String artifactClassifier, File artifactFile )
{
String type = artifactType;
ArtifactHandler handler = null;
if ( type != null )
{
handler = artifactHandlerManager.getArtifactHandler( artifactType );
}
if ( handler == null )
{
handler = artifactHandlerManager.getArtifactHandler( "jar" );
}
Artifact artifact = new AttachedArtifact( project.getArtifact(), artifactType, artifactClassifier, handler );
artifact.setFile( artifactFile );
artifact.setResolved( true );
project.addAttachedArtifact( artifact );
attachArtifact(project, artifact);
}
public void attachArtifact( MavenProject project, String artifactType, File artifactFile )
{
ArtifactHandler handler = artifactHandlerManager.getArtifactHandler( artifactType );
Artifact artifact = new AttachedArtifact( project.getArtifact(), artifactType, handler );
artifact.setFile( artifactFile );
artifact.setResolved( true );
project.addAttachedArtifact( artifact );
attachArtifact(project, artifact);
}
public void attachArtifact( MavenProject project, File artifactFile, String artifactClassifier )
{
Artifact projectArtifact = project.getArtifact();
Artifact artifact = new AttachedArtifact( projectArtifact, projectArtifact.getType(), artifactClassifier, projectArtifact.getArtifactHandler() );
artifact.setFile( artifactFile );
artifact.setResolved( true );
project.addAttachedArtifact( artifact );
attachArtifact(project, artifact);
}
public void attachArtifact(MavenProject project, Artifact artifact)
{
try
{
project.addAttachedArtifact( artifact );
}
catch (DuplicateArtifactAttachmentException dae)
{
getLogger().warn(dae.getMessage());
// We can throw this because it's unchecked, and won't change the MavenProjectHelper API, which would break backward compat if it did.
throw dae;
}
}
public void addResource( MavenProject project, String resourceDirectory, List includes, List excludes )

View File

@ -0,0 +1,66 @@
package org.apache.maven.project;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.maven.artifact.Artifact;
/**
* This exception is thrown if an application attempts to attach
* two of the same artifacts to a single project.
*
* @author pgier
* @author jdcasey
*
* @todo Make this a checked exception, and modify the API of MavenProjectHelper.
* Currently, this modification would create compatibility problems for existing plugins.
*/
public class DuplicateArtifactAttachmentException
extends RuntimeException
{
private static final String DEFAULT_MESSAGE = "Duplicate artifact attachment detected.";
private Artifact artifact;
private final MavenProject project;
public DuplicateArtifactAttachmentException( MavenProject project, Artifact artifact )
{
super( constructMessage( project, artifact ) );
this.project = project;
this.artifact = artifact;
}
private static String constructMessage( MavenProject project,
Artifact artifact )
{
return DEFAULT_MESSAGE + " (project: " + project.getId() + "; illegal attachment: " + artifact.getId() + ")";
}
public MavenProject getProject()
{
return project;
}
public Artifact getArtifact()
{
return artifact;
}
}

View File

@ -1336,7 +1336,15 @@ public class MavenProject
}
public void addAttachedArtifact( Artifact artifact )
throws DuplicateArtifactAttachmentException
{
List attachedArtifacts = getAttachedArtifacts();
if ( attachedArtifacts.contains( artifact ) )
{
throw new DuplicateArtifactAttachmentException( this, artifact );
}
getAttachedArtifacts().add( artifact );
}
@ -1757,23 +1765,23 @@ public class MavenProject
{
StringBuffer sb = new StringBuffer(30);
sb.append( "MavenProject: " );
sb.append( this.getGroupId() );
sb.append( getGroupId() );
sb.append( ":" );
sb.append( this.getArtifactId() );
sb.append( getArtifactId() );
sb.append( ":" );
sb.append( this.getVersion() );
sb.append( getVersion() );
sb.append( " @ " );
try
try
{
sb.append( this.getFile().getPath() );
sb.append( getFile().getPath() );
}
catch (NullPointerException e)
{
//don't log it.
}
return sb.toString();
return sb.toString();
}
}

View File

@ -0,0 +1,57 @@
package org.apache.maven.project;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.model.Model;
import org.codehaus.plexus.PlexusTestCase;
import java.io.File;
public class DefaultMavenProjectHelperTest
extends PlexusTestCase
{
private MavenProjectHelper mavenProjectHelper;
private ArtifactFactory artifactFactory;
public void setUp()
throws Exception
{
super.setUp();
mavenProjectHelper = (MavenProjectHelper) lookup( MavenProjectHelper.ROLE );
artifactFactory = (ArtifactFactory) lookup( ArtifactFactory.ROLE );
}
public void testShouldThrowExceptionWhenDuplicateAttachmentIsAdded()
{
Model model = new Model();
model.setGroupId( "group" );
model.setArtifactId( "artifact" );
model.setVersion( "1" );
MavenProject project = new MavenProject();
Artifact projectArtifact = artifactFactory.createBuildArtifact( model.getGroupId(), model.getArtifactId(), model.getVersion(), "jar" );
project.setArtifact( projectArtifact );
File artifactFile = new File( "nothing" );
File artifactFile2 = new File( "nothing-else" );
mavenProjectHelper.attachArtifact( project, "jar", "c", artifactFile );
try
{
mavenProjectHelper.attachArtifact( project, "jar", "c", artifactFile2 );
fail( "Should throw DuplicateArtifactAttachmentException" );
}
catch( DuplicateArtifactAttachmentException e )
{
assertEquals( artifactFile2, e.getArtifact().getFile() );
assertSame( project, e.getProject() );
}
}
}