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