Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MPH-168] effective-pom should support multi-module project #76

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 104 additions & 22 deletions src/main/java/org/apache/maven/plugins/help/EffectivePomMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* under the License.
*/

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
Expand All @@ -29,8 +30,8 @@
import java.util.Properties;

import org.apache.maven.model.InputLocation;
import org.apache.maven.model.Model;
import org.apache.maven.model.InputSource;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.model.io.xpp3.MavenXpp3WriterExOldSupport;
import org.apache.maven.plugin.MojoExecution;
Expand All @@ -55,7 +56,7 @@
*/
@Mojo( name = "effective-pom", aggregator = true )
public class EffectivePomMojo
extends AbstractEffectiveMojo
extends AbstractEffectiveMojo
{
// ----------------------------------------------------------------------
// Mojo parameters
Expand Down Expand Up @@ -95,35 +96,55 @@ public class EffectivePomMojo

/**
* Output POM input location as comments.
*
*
* @since 3.2.0
*/
@Parameter( property = "verbose", defaultValue = "false" )
private boolean verbose = false;

/**
* Generate an effective pom for each module individually and
* save it in ${project.build.outputDirectory}/effective.pom.xml.
*
* @since 3.3.0
*/
@Parameter( property = "individual", defaultValue = "false" )
private boolean individual = false;

// ----------------------------------------------------------------------
// Public methods
// ----------------------------------------------------------------------

/** {@inheritDoc} */
/**
* {@inheritDoc}
*/
public void execute()
throws MojoExecutionException
throws MojoExecutionException
{
if ( StringUtils.isNotEmpty( artifact ) )
{
project = getMavenProject( artifact );
projects = Collections.singletonList( project );
}
if ( individual )
{
generateIndividualEffectivePom();
}
else
{
generateSingleEffectivePom();
}
}

private void generateSingleEffectivePom() throws MojoExecutionException
{
StringWriter w = new StringWriter();
String encoding = output != null ? project.getModel().getModelEncoding()
: System.getProperty( "file.encoding" );
: System.getProperty( "file.encoding" );
XMLWriter writer =
new PrettyPrintXMLWriter( w, StringUtils.repeat( " ", XmlWriterUtil.DEFAULT_INDENTATION_SIZE ),
encoding, null );
getPrettyPrintXMLWriterForEffectivePom( w, encoding );

writeHeader( writer );

if ( shouldWriteAllEffectivePOMsInReactor() )
{
// outer root element
Expand All @@ -140,24 +161,85 @@ public void execute()
}

String effectivePom = prettyFormat( w.toString(), encoding, false );
effectivePom = prettyFormatVerbose( effectivePom );
reportEffectivePom( effectivePom, output );
}

private void generateIndividualEffectivePom() throws MojoExecutionException
{
String encoding = project.getModel().getModelEncoding();
if ( shouldWriteAllEffectivePOMsInReactor() )
{
// outer root element
for ( MavenProject subProject : projects )
{
StringWriter w = new StringWriter();
XMLWriter writer =
getPrettyPrintXMLWriterForEffectivePom( w, encoding );
writeHeader( writer );
writeEffectivePom( subProject, writer );
String effectivePom = prettyFormat( w.toString(), encoding, false );
effectivePom = prettyFormatVerbose( effectivePom );
File effectiveOutput = output == null ? null
: getRelativeOutput( subProject );
reportEffectivePom( effectivePom, effectiveOutput );
}
}
else
{
StringWriter w = new StringWriter();
XMLWriter writer =
getPrettyPrintXMLWriterForEffectivePom( w, encoding );
writeHeader( writer );
writeEffectivePom( project, writer );
String effectivePom = prettyFormat( w.toString(), encoding, false );
effectivePom = prettyFormatVerbose( effectivePom );
File effectiveOutput = output == null ? null
: getRelativeOutput( project );
reportEffectivePom( effectivePom, effectiveOutput );
}
}

private File getRelativeOutput( MavenProject relativeProject )
{
String rawOutputPath = output.getPath();
String rawBasedirPath = project.getBasedir().getPath();
String result = rawOutputPath.contains( rawBasedirPath )
Copy link

@garretwilson garretwilson Nov 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This brute-force searching of strings is not the correct way to process paths. Even in the best of worlds, there are all sorts of cases this won't work with (e.g. if the paths are not normalized, and contains ../, etc. In addition you're using contains(), which even with this approach isn't correct (it looks even in the middle of the string).

Instead of searching raw strings, you should be using path manipulation methods for semantic Path objects. For example, there's a method made to do exactly what you want: Path.relativize(). And if you don't have a Path, you can create one from a string. You can also can convert from the old File model to the new Java NIO Path model and back.

If you're not used to working with semantic path objects, you might start at Oracle's The Path Class tutorial, which includes Path Operations explanations..

? rawOutputPath.replace( rawBasedirPath, "" )
: output.getName();
return new File( relativeProject.getBuild().getDirectory() + "/" + result );
}

private String prettyFormatVerbose( String effectivePom )
{
if ( verbose )
{
// tweak location tracking comment, that are put on a separate line by pretty print
effectivePom = effectivePom.replaceAll( "(?m)>\\s+<!--}", "> <!-- " );
}
return effectivePom;
}

if ( output != null )
private PrettyPrintXMLWriter getPrettyPrintXMLWriterForEffectivePom( StringWriter w, String encoding )
{
return new PrettyPrintXMLWriter( w, StringUtils.repeat( " ", XmlWriterUtil.DEFAULT_INDENTATION_SIZE ),
encoding, null );
}

private void reportEffectivePom( String effectivePom, File effectiveOutput ) throws MojoExecutionException
{
if ( effectiveOutput != null )
{
try
{
writeXmlFile( output, effectivePom );
writeXmlFile( effectiveOutput, effectivePom );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Cannot write effective-POM to output: " + output, e );
throw new MojoExecutionException( "Cannot write effective POM to output: " + effectiveOutput, e );
}

getLog().info( "Effective-POM written to: " + output );
getLog().info( "Effective POM written to: " + effectiveOutput );
}
else
{
Expand Down Expand Up @@ -198,11 +280,11 @@ private boolean shouldWriteAllEffectivePOMsInReactor()
* Method for writing the effective pom informations of the current build.
*
* @param project the project of the current build, not null.
* @param writer the XML writer , not null, not null.
* @param writer the XML writer , not null, not null.
* @throws MojoExecutionException if any
*/
private void writeEffectivePom( MavenProject project, XMLWriter writer )
throws MojoExecutionException
throws MojoExecutionException
{
Model pom = project.getModel();
cleanModel( pom );
Expand All @@ -213,7 +295,7 @@ private void writeEffectivePom( MavenProject project, XMLWriter writer )
if ( verbose )
{
// try to use Maven core-provided xpp3 extended writer (available since Maven 3.6.1)
if ( ! writeMavenXpp3WriterEx( sWriter, pom ) )
if ( !writeMavenXpp3WriterEx( sWriter, pom ) )
{
// xpp3 extended writer not provided by Maven core, use local code
new EffectiveWriterExOldSupport().write( sWriter, pom );
Expand Down Expand Up @@ -252,19 +334,19 @@ private static void cleanModel( Model pom )
private void warnWriteMavenXpp3WriterEx( Throwable t )
{
getLog().warn( "Unexpected exception while running Maven Model Extended Writer, "
+ "falling back to old internal implementation.", t );
+ "falling back to old internal implementation.", t );
}

private boolean writeMavenXpp3WriterEx( Writer writer, Model model )
throws IOException
throws IOException
{
try
{
Class<?> mavenXpp3WriterExClass = Class.forName( "org.apache.maven.model.io.xpp3.MavenXpp3WriterEx" );
Object mavenXpp3WriterEx = mavenXpp3WriterExClass.getDeclaredConstructor().newInstance();

Method setStringFormatter =
mavenXpp3WriterExClass.getMethod( "setStringFormatter", InputLocation.StringFormatter.class );
mavenXpp3WriterExClass.getMethod( "setStringFormatter", InputLocation.StringFormatter.class );
setStringFormatter.invoke( mavenXpp3WriterEx, new InputLocationStringFormatter() );

Method write = mavenXpp3WriterExClass.getMethod( "write", Writer.class, Model.class );
Expand Down Expand Up @@ -312,7 +394,7 @@ private static String toString( InputLocation location )
}

private static class InputLocationStringFormatter
extends InputLocation.StringFormatter
extends InputLocation.StringFormatter
{

public String toString( InputLocation location )
Expand All @@ -326,7 +408,7 @@ public String toString( InputLocation location )
* Xpp3 extended writer extension to improve default InputSource display
*/
private static class EffectiveWriterExOldSupport
extends MavenXpp3WriterExOldSupport
extends MavenXpp3WriterExOldSupport
{

@Override
Expand All @@ -337,7 +419,7 @@ public String toString( InputLocation location )

@Override
protected void writeXpp3DomToSerializer( Xpp3Dom dom, XmlSerializer serializer )
throws IOException
throws IOException
{
// default method uses Xpp3Dom input location tracking, not available in older Maven versions
// use old Xpp3Dom serialization, without input location tracking
Expand Down