All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.util.maven.jbuilding.VersionsMojo Maven / Gradle / Ivy

There is a newer version: 1.0.37
Show newest version
/**
 * OW2 Util
 * Copyright (C) 2009 Bull S.A.S.
 * Contact: [email protected]
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * --------------------------------------------------------------------------
 * $Id: VersionsMojo.java 4955 2009-05-13 12:24:17Z fornacif $
 * --------------------------------------------------------------------------
 */

package org.ow2.util.maven.jbuilding;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import java.util.TreeMap;
import java.util.regex.Pattern;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.resolver.ArtifactCollector;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ResolutionNode;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.codehaus.plexus.util.FileUtils;

/**
 * Process a project and explore artifacts versions.
 * @goal versions
 * @phase process-sources
 * @author Guillaume Sauthier
 */
public class VersionsMojo extends AbstractResolverMojo {

    /**
     * Property pattern.
     */
    private static Pattern PROPERTY_NAME_PATTERN = Pattern.compile(".*\\.version$");

    /**
     * Location of the versions.properties to be created.
     * @parameter expression="${project.build.directory}/versions.properties"
     * @required
     */
    private File output;

    /**
     * Group Ids to be joined if they share the same version.
     * @parameter
     */
    private List joinedGroupIds = new ArrayList();

    /**
     * @parameter expression="${jbuilding.versions.properties}" default-value="false"
     */
    private boolean browseProperties = false;

    /**
     * @parameter
     */
    private String[] preferedGroupIds;

    /**
     * Dependencies depth filtering.
     * @parameter
     */
    private int depth = 3;

    /**
     * ArtifactCollector filtering on artifact's scope.
     * @parameter
     */
    private String collectScope = Artifact.SCOPE_COMPILE;

    /**
     * The collector artifact used to discover dependencies childrens.
     * @component
     * @required
     * @readonly
     */
    private ArtifactCollector collector;

    /**
     * @component
     * @required
     * @readonly
     */
    private ArtifactMetadataSource artifactMetadataSource;

    /**
     * Joined groupIds with their default version.
     */
    private Map joinGroups = new HashMap();

    /**
     * Llist of resolvables artifacts (to be used with the collector to resolve first depth dependencies).
     */
    private Set collectableArtifacts = new HashSet();

    /**
     * Default Bean constructor.
     */
    public VersionsMojo() {
        // Default value : no preferences
        preferedGroupIds = new String[1];
        preferedGroupIds[0] = "*";
    }

    /**
     * Writes the versions.properties file.
     * @throws MojoExecutionException
     * @throws MojoFailureException
     */
    public void execute() throws MojoExecutionException, MojoFailureException {

        getLog().debug("Introspecting project " + getProject().getGroupId() + ":" + getProject().getArtifactId());

        // Resolve the artifacts provided in the plugin configuration
        Map> map = resolveArtifacts(SERVER_SIDE, BOTH_MODE, ALL_ARTIFACT_ITEMS);

        // Init the Version map
        Map versionsProperties = new TreeMap();

        // Browse properties
        if (browseProperties) {
            getVersionsFromModelProperties(versionsProperties);
            getVersionsFromProjectProperties(versionsProperties);
        }

        // Browse dependencies
        getVersionsFromArtifactItems(map, versionsProperties);
        getVersionsFromProjectDependencies(versionsProperties);

        // Browse transitive dependencies
        getVersionsFromTransitiveDependencies(versionsProperties);

        // Don't forget joined group Ids
        getVersionsFromJoinedGroupIds(versionsProperties);

        // Store the file
        try {
            getLog().debug("Storing in " + output);
            storeVersionsProperties(versionsProperties);
        } catch (IOException ioe) {
            throw new MojoExecutionException("Cannot store " + output, ioe);
        }
    }

    /**
     * Extract version information from project's runtime properties
     * @param versions versions
     */
    public void getVersionsFromProjectProperties(final Map versions) {

        getLog().debug("Looking in project's properties");
        // Look on the project runtime properties
        filterProperties(getProject().getProperties(), versions);
    }

    /**
     * Extract version information from project's model properties
     * @param versions versions
     */
    public void getVersionsFromModelProperties(final Map versions) {

        getLog().debug("Looking in project's model properties");
        // Look on the ${project.properties.*} values
        filterProperties(getProject().getModel().getProperties(), versions);
    }

    /**
     * Extract versions informations from ArtifactItems listed in the jbuilding plugin configuration.
     * @param groups groups of ArtifactItems
     * @param versions versions
     */
    public void getVersionsFromArtifactItems(final Map> groups, final Map versions) {

        // Iterates over groups (~ deployment-plans)
        for (Map.Entry> group : groups.entrySet()) {

            // Iterates over artifact items in the group
            for (Artifact artifact : group.getValue()) {

                String groupId = artifact.getGroupId();
                String artifactVersion = artifact.getVersion();

                if (!filterGroupId(groupId, artifactVersion)) {
                    // if the artifact did need to be filtered, just write the property
                    String name = getArtifactName(artifact.getGroupId(),
                                                  artifact.getArtifactId());
                    addVersion(versions, name, artifactVersion);
                }

                // Add this artifact
                collectableArtifacts.add(artifact);
            }
        }
    }

    /**
     * Extract versions informations from project's dependencies.
     * @param versions versions
     */
    @SuppressWarnings({"unchecked"})
    public void getVersionsFromProjectDependencies(final Map versions) {

        // Iterates on all project's dependencies
        List dependencies = getProject().getDependencies();
        if (dependencies != null) {
            for (Dependency dependency : dependencies) {

                String groupId = dependency.getGroupId();
                String artifactId = dependency.getArtifactId();
                String dependencyVersion = dependency.getVersion();
                String dependencyType = dependency.getType();
                String dependencyClassifier = dependency.getClassifier();

                if (!filterGroupId(groupId, dependencyVersion)) {
                    // if the artifact didn't need to be filtered, just write the property
                    String name = getArtifactName(groupId,
                                                  artifactId);
                    addVersion(versions, name, dependencyVersion);
                }

                // Add this artifact
                collectableArtifacts.add(createArtifact(groupId, artifactId, dependencyVersion, dependencyType, dependencyClassifier));

            }
        }

    }

    /**
     * Extract versions information from transitive dependencies of the
     * collected artifacts (dependencies + bundle items)
     * @param versions versions
     * @throws MojoExecutionException if POM collection failed
     */
    private void getVersionsFromTransitiveDependencies(final Map versions) throws MojoExecutionException {

        try {

            // Collect metadata informations from all the collected artifacts
            // This doesn't download the artifacts, only the POM.
            ArtifactResolutionResult result = collector.collect(collectableArtifacts,
                                                                getProject().getArtifact(),
                                                                getLocal(),
                                                                getRemoteRepositories(),
                                                                artifactMetadataSource,
                                                                new ScopeArtifactFilter(collectScope),
                                                                Collections.emptyList());
            Set nodes = result.getArtifactResolutionNodes();
            for (ResolutionNode node : nodes) {
                // Only manage firsts depths nodes
                if (node.getDepth() < depth) {
                    Artifact artifact = node.getArtifact();

                    String groupId = artifact.getGroupId();
                    String artifactId = artifact.getArtifactId();
                    String dependencyVersion = artifact.getVersion();

                    if (!filterGroupId(groupId, dependencyVersion)) {
                        // if the artifact didn't need to be filtered, just write the property
                        String name = getArtifactName(groupId,
                                                      artifactId);
                        addVersion(versions, name, dependencyVersion);
                    }

                }
            }

        } catch (ArtifactResolutionException e) {
            throw new MojoExecutionException("Cannot resolve artifacts", e);
        }
    }

    /**
     * Extract versions informations from joined groupIds.
     * @param versions versions
     */
    public void getVersionsFromJoinedGroupIds(final Map versions) {

        for (Map.Entry entry : joinGroups.entrySet()) {
            String name = entry.getKey();
            String version = entry.getValue();
            addVersion(versions, name, version);
        }
    }

    /**
     * Filter properties values and only select the one finishing with ".version"
     * @param filteredProperties properties to be filtered
     * @param versions versions
     */
    private void filterProperties(final Properties filteredProperties,
                                  final Map versions) {

        if (filteredProperties != null) {

            // Filter all existing properties
            for (Map.Entry entry : filteredProperties.entrySet()) {
                String name = (String) entry.getKey();
                if (PROPERTY_NAME_PATTERN.matcher(name).matches()) {
                    String value = (String) entry.getValue();
                    addVersion(versions, name, value);

                    getLog().debug(name + "->" + value);
                }
            }
        }
    }

    /**
     * Store the collected versions in the versions.propertier file.
     * @param versions collected versions
     * @throws IOException if File creation failed
     */
    public void storeVersionsProperties(final Map versions) throws IOException {

        // Sort the output using specified patterns
        Stack patterns = createSortingPatterns();

        StringBuilder sb = new StringBuilder();
        sb.append("# Generated the ");
        sb.append(new Date());
        sb.append(" by OW2 Util.\n\n");

        // Used to group artifacts using their grouptId
        String lastGroupId = "";

        // Browse the map using the patterns as a guideline
        while (!patterns.isEmpty()) {
            Pattern pattern = patterns.pop();

            // Extract the keys as an array because we change the Map during the process
            String[] entries = versions.keySet().toArray(new String[versions.size()]);
            for (String name : entries) {

                // Only print the value if it matches the current pattern
                if (pattern.matcher(name).matches()) {

                    String groupId = getGroupId(name);
                    // Add an empty line separating artifacts using their groupIds
                    if (!groupId.startsWith(lastGroupId)) {
                        sb.append("\n");
                    }

                    // print the property
                    sb.append(name);
                    sb.append("   ");
                    sb.append(versions.get(name));
                    sb.append("\n");

                    // remember the last group
                    lastGroupId = groupId;

                    // Remove the property
                    versions.remove(name);
                }
            }
        }

        // Write the file
        FileUtils.fileWrite(output.getPath(), sb.toString());

    }

    /**
     * Extract the group Id the the property name.
     * The property name is of the following form: groupId[_artifactId]
     * @param name The property name
     * @return the groupId contained in this property name
     */
    private String getGroupId(final String name) {

        int index = name.indexOf('_');
        if (index == -1) {
            return name;
        } else {
            return name.substring(0, index);
        }
    }

    /**
     * Create a Stack of pattern used to sort the output.
     * @return new Stack
     */
    private Stack createSortingPatterns() {

        Stack patterns = new Stack();

        // if the last item is not a '*', add it
        String last = preferedGroupIds[preferedGroupIds.length - 1];
        if (!last.equals("*")) {
            patterns.push(createPattern("*"));
        }

        // Inverted iteration (most wanted pattern to be included on top of the stack)
        for (int i = preferedGroupIds.length - 1; i >= 0 ; i--) {
            patterns.push(createPattern(preferedGroupIds[i]));
        }
        return patterns;
    }

    /**
     * Create a pattern using a pseudo regular expression.
     * @param expression pseudo regular expression
     * @return a pattern corresponding to the given expression
     */
    public Pattern createPattern(String expression) {

        if (expression.contains(".")) {
            // protect existing '.' char
            expression = expression.replaceAll("\\.", "\\\\.");
        }

        if (expression.contains("*")) {
            // convert '*' pseudo regular expression to valid pattern
            // '*' -> '.*'
            expression = expression.replaceAll("\\*", "\\.\\*");
        }
        return Pattern.compile(expression);
    }

    /**
     * Add the couple name/version in the versions Map
     * @param versions versions
     * @param name property name
     * @param version property value
     */
    private void addVersion(final Map versions, final String name, final String version) {
        versions.put(name, version);
    }

    /**
     * Create an artifact name from an artifact groupId and artifactId.
     * @param groupId groupId
     * @param artifactId artifactId
     * @return a composed artifact name
     */
    private String getArtifactName(final String groupId, final String artifactId) {
        StringBuilder sb = new StringBuilder();
        // groupId
        sb.append(groupId);
        sb.append("_");

        // artifactId
        String id = artifactId;
        if (artifactId.startsWith(groupId) && (!artifactId.equals(groupId))) {
            // simplify artifact Id
            id = artifactId.substring(groupId.length() + 1);
        }
        sb.append(id);
        return sb.toString();
    }

    /**
     * Filter a groupId.
     * If the given groupId/version couple is already registered (same group, same
     * version), the artifact will be filtered (excluded).
     * @param groupId under test group
     * @param version under test version
     * @return true if the groupId is filtered, false otherwise
     */
    private boolean filterGroupId(final String groupId, final String version) {
        if (joinedGroupIds.contains(groupId)) {
            // This artifact may need to be filtered

            if (joinGroups.containsKey(groupId)) {
                // A previous bundle of the same group has already been filtered

                String storedVersion = joinGroups.get(groupId);
                if (storedVersion.equals(version)) {
                    // Continue to the next artifact
                    return true;
                }
            } else {
                // This group needs to be filtered
                // We just encountered the first artifact that belongs to this group.
                // Store the default version
                joinGroups.put(groupId, version);

                // and continue to the next artifact
                return true;
            }
        }
        return false;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy