001package org.apache.maven.extensions.enforcer;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.Reader;
025import java.nio.charset.StandardCharsets;
026import java.nio.file.Files;
027import java.nio.file.Path;
028import java.nio.file.Paths;
029import java.util.ArrayList;
030import java.util.Collections;
031import java.util.List;
032import java.util.Properties;
033
034import javax.inject.Named;
035
036import org.apache.maven.AbstractMavenLifecycleParticipant;
037import org.apache.maven.MavenExecutionException;
038import org.apache.maven.execution.MavenSession;
039import org.apache.maven.model.Build;
040import org.apache.maven.model.Plugin;
041import org.apache.maven.model.PluginExecution;
042import org.apache.maven.project.MavenProject;
043import org.codehaus.plexus.util.xml.Xpp3Dom;
044import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
045import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
046
047/**
048 * Extends every MavenProject with the maven-enforcer-plugin, adding executions as defined in 
049 * <code>.mvn/enforcer-extension.xml</code>
050 * 
051 * @since 3.0.0
052 */
053@Named( "enforcer" )
054public class EnforceExtension extends AbstractMavenLifecycleParticipant
055{
056    private static final String ENFORCER_EXTENSION_XML = ".mvn/enforcer-extension.xml";
057
058    private static final String POM_PROPERTIES =
059        "/META-INF/maven/org.apache.maven.extensions/maven-enforcer-extension/pom.properties";
060
061    @Override
062    public void afterProjectsRead( MavenSession session )
063        throws MavenExecutionException
064    {
065        Xpp3Dom configuration;
066        Path config = Paths.get( session.getExecutionRootDirectory(), ENFORCER_EXTENSION_XML );
067        if ( Files.isRegularFile( config ) )
068        {
069            try ( Reader reader = Files.newBufferedReader( config, StandardCharsets.UTF_8 ) )
070            {
071                configuration = Xpp3DomBuilder.build( reader );
072            }
073            catch ( XmlPullParserException | IOException e )
074            {
075                throw new MavenExecutionException( "Failed to read " + ENFORCER_EXTENSION_XML, e );
076            }
077        }
078        else
079        {
080            return;
081        }
082
083        List<PluginExecution> executions = null;
084        Xpp3Dom executionsDom = configuration.getChild( "executions" );
085        if ( executionsDom != null )
086        {
087            executions = new ArrayList<>();
088            for ( Xpp3Dom executionDom : executionsDom.getChildren( "execution" ) )
089            {
090                executions.add( getPluginExecution( executionDom ) );
091
092            }
093        }
094
095        if ( executions == null )
096        {
097            return;
098        }
099
100        for ( MavenProject project : session.getProjects() )
101        {
102            Plugin enforcerPlugin = null;
103            for ( Plugin plugin : project.getBuildPlugins() )
104            {
105                if ( "maven-enforcer-plugin".equals( plugin.getArtifactId() )
106                    && "org.apache.maven.plugins".equals( plugin.getGroupId() ) )
107                {
108                    enforcerPlugin = plugin;
109                }
110            }
111            
112            if ( enforcerPlugin == null )
113            {
114                enforcerPlugin = new Plugin();
115                enforcerPlugin.setGroupId( "org.apache.maven.plugins" );
116                enforcerPlugin.setArtifactId( "maven-enforcer-plugin" );
117
118                try ( InputStream is = EnforceExtension.class.getResourceAsStream( POM_PROPERTIES ) )
119                {
120                    Properties properties = new Properties();
121                    properties.load( is );
122                    enforcerPlugin.setVersion( properties.getProperty( "version" ) );
123                }
124                catch ( IOException e )
125                {
126                    // noop
127                }
128                
129                if ( project.getBuildPlugins().isEmpty() )
130                {
131                    Build build = project.getBuild();
132                    if ( build == null )
133                    {
134                        build = new Build();
135                        project.setBuild( build );
136                    }
137                    build.setPlugins( Collections.singletonList( enforcerPlugin ) );
138                }
139                else
140                {
141                    List<Plugin> buildPlugins = new ArrayList<>( project.getBuildPlugins() );
142                    buildPlugins.add( enforcerPlugin );
143                    project.getBuild().setPlugins( buildPlugins );
144                }
145            }
146
147            for ( PluginExecution pe : executions )
148            {
149                enforcerPlugin.addExecution( pe );
150            }
151        }
152    }
153
154    private static PluginExecution getPluginExecution( Xpp3Dom execution )
155    {
156        PluginExecution pluginExecution = new PluginExecution();
157        pluginExecution.setId( get( execution, "id", "default-extension" ) );
158        pluginExecution.addGoal( "enforce" );
159        pluginExecution.setPhase( get( execution, "phase", "validate" ) );
160        // here we must use Mavens internal configuration implementation
161        pluginExecution.setConfiguration( execution.getChild( "configuration" ) );
162        return pluginExecution;
163    }
164
165    private static String get( Xpp3Dom elm, String name, String defaultValue )
166    {
167        if ( elm == null || elm.getChild( name ) == null )
168        {
169            return defaultValue;
170        }
171        else
172        {
173            return elm.getChild( name ).getValue();
174        }
175    }
176}