com.adaptiweb.mojo.BuildNumberMojo.java Source code

Java tutorial

Introduction

Here is the source code for com.adaptiweb.mojo.BuildNumberMojo.java

Source

package com.adaptiweb.mojo;

/*
 * Copyright 2001-2005 The Apache Software Foundation.
 *
 * Licensed 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 java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.codehaus.plexus.util.SelectorUtils;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNInfo;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNStatus;
import org.tmatesoft.svn.core.wc.SVNStatusType;

/**
 * Goal which provide some dynamic information in build time thru project properties.
 * <br>Right now are supported these four properties:<ol>
 * <li><b>{@link #buildNumberProperty}</b></li>
 * <li><b>{@link #timestampProperty}</b></li>
 * <li><b>{@link #revisionNumberProperty}</b></li>
 * <li><b>{@link #lastCommittedRevisionProperty}</b></li>
 * </ol>
 * 
 * @goal create
 * @phase validate
 * @requiresProject
 */
public class BuildNumberMojo extends AbstractMojo {
    private static final String[] DEFAULT_EXCLUDES = { "**/.svn", "**/.svn/**", "**/*~" };

    /**
     * Working copy of project resources managed by Subverion. Default ${basedir}. 
     * 
     * @parameter expression="${basedir}"
     */
    private File basedir;

    /**
     * Name of property for build number. Default 'buildNumber'.
     * 
     * @parameter default-value=""
     */
    private String buildNumberProperty;

    /**
     * Name of property for timestamp.
     * No property name is set by default.
     * Value of property is formated by {@link #timestampFormat} parameter.
     * @parameter default-value=""
     */
    private String timestampProperty;

    /**
     * Name of property for revision number.
     * No property name is set by default.
     * This parameter is ignored if project isn't under subversion control.
     * 
     * @parameter default-value=""
     */
    private String revisionNumberProperty;

    /**
     * Name of property for last commited revision number.
     * No property name is set by default.
     * This parameter is ignored if project isn't under subversion control.
     * 
     * @parameter default-value=""
     */
    private String lastCommittedRevisionProperty;

    /**
     * Properties are sets even they already exists. Default {@code false}.
     * 
     * @parameter default-value="false"
     */
    private boolean overwriteProperties;

    /**
     * Format for timestamp property. Default 'Y-m-d H:M:S'.
     * 
     * @parameter default-value="Y-m-d H:M:S"
     */
    private String timestampFormat;

    /**
     * The maven project properties. For exporting.
     * 
     * @parameter expression="${project.properties}"
     * @required
     * @readonly
     */
    private Properties projectProperties;

    /**
     * The maven project version. Used for build number property.
     * 
     * @parameter expression="${project.version}"
     * @required
     * @readonly
     */
    private String projectVersion;

    /**
     * If {@code true} (default) unversioned resources are ignored
     * while checking SVN status. 
     * 
     * @parameter default-value="true"
     */
    private boolean ignoreUnversioned;

    /**
     * List of patterns to match resources includes for SVN checking.
     * 
     * @parameter
     */
    private String[] includes;

    /**
     * List of patterns to match resources excludes from SVN checking.
     * 
     * @parameter
     */
    private String[] excludes;

    /**
     * Check if files in working copy are up to date and commited.
     * @parameter expression="${maven.buildNumber.doCheck}" default-value="true"
     */
    private boolean doCheck;

    /**
     * Project build never fails, even if SVN check find some problems.
     * @parameter expression="${neverFail}" default-value="true"
     */
    private boolean neverFail;

    /**
     * All exported properties for information log message.
     */
    private Map<String, String> exportedProperties = new HashMap<String, String>();

    /**
     * Value for timestamp initialized by {@link System#currentTimeMillis()}.
     */
    private long now;

    /**
     * API for working with subversion data.
     */
    private SVNClientManager svnManager;

    /**
     * Subversion info data for {@link #basedir}.
     */
    private SVNInfo svnInfo;

    /**
     * @see org.apache.maven.plugin.Mojo#execute()
     */
    public void execute() throws MojoExecutionException {
        now = System.currentTimeMillis();

        if (isPropertyWanted(buildNumberProperty))
            doExportProperty(buildNumberProperty, getVersion());
        if (isPropertyWanted(timestampProperty))
            doExportProperty(timestampProperty, getTimeStamp(timestampFormat));
        if (isWorkingCopy()) {
            if (doCheck && !doCheck() && !neverFail)
                throw new MojoExecutionException("Checking working copy fails!");
            if (isPropertyWanted(revisionNumberProperty))
                doExportProperty(revisionNumberProperty, String.valueOf(getSVNInfo().getRevision()));
            if (isPropertyWanted(lastCommittedRevisionProperty))
                doExportProperty(lastCommittedRevisionProperty,
                        String.valueOf(getSVNInfo().getCommittedRevision()));
        }

        getLog().info("Exported properties: " + exportedProperties);
    }

    private boolean doCheck() throws MojoExecutionException {
        correctPathPatterns(DEFAULT_EXCLUDES);
        if (includes != null)
            correctPathPatterns(includes);
        if (excludes != null)
            correctPathPatterns(excludes);
        return checkFile(basedir, "");
    }

    private void correctPathPatterns(String[] patterns) {
        for (int i = 0; i < patterns.length; i++) {
            patterns[i] = patterns[i].replace('/', File.separatorChar).replace('\\', File.separatorChar);
            if (patterns[i].endsWith(File.separator))
                patterns[i] += "**";
        }
    }

    private boolean checkFile(File file, String matchPrefix) throws MojoExecutionException {
        SVNStatus status = getSVNStatus(file);
        SVNStatusType statusType = status.getContentsStatus();

        boolean checked = true;

        if (!isStatusOk(statusType)) {
            reportStatus(statusType, toProjectBasePath(file));
            checked = false;
        }

        if (file.isDirectory() && shouldSinkDeeper(statusType))
            for (String f : file.list())
                if (isIncluded(matchPrefix + f))
                    checked &= checkFile(new File(file, f), matchPrefix + f + "/");

        return checked;
    }

    private boolean isIncluded(String path) {
        for (String exclude : DEFAULT_EXCLUDES)
            if (SelectorUtils.match(exclude, path))
                return false;

        if (includes != null) {
            boolean included = false;
            for (String include : includes) {
                if (SelectorUtils.match(include, path)) {
                    included = true;
                    break;
                }
            }
            if (!included)
                return false;
        }

        if (excludes != null)
            for (String exclude : excludes)
                if (SelectorUtils.match(exclude, path))
                    return false;

        return true;
    }

    private void reportStatus(SVNStatusType status, String path) {
        getLog().warn(String.format("%12s: %s", status, path));
    }

    private String toProjectBasePath(File file) {
        return file.getAbsolutePath().substring(basedir.getAbsolutePath().length());
    }

    private boolean shouldSinkDeeper(SVNStatusType status) {
        return status != SVNStatusType.STATUS_IGNORED && status != SVNStatusType.STATUS_UNVERSIONED;
    }

    private boolean isStatusOk(SVNStatusType status) {
        return status == SVNStatusType.STATUS_NONE || status == SVNStatusType.STATUS_NORMAL
                || status == SVNStatusType.STATUS_IGNORED
                || status == SVNStatusType.STATUS_UNVERSIONED && ignoreUnversioned;
    }

    private SVNInfo getSVNInfo() throws MojoExecutionException {
        if (svnInfo == null)
            try {
                svnInfo = getSVNManager().getWCClient().doInfo(basedir, SVNRevision.BASE);
            } catch (SVNException e) {
                throw new MojoExecutionException(e.getMessage(), e);
            }
        return svnInfo;
    }

    private SVNStatus getSVNStatus(File file) throws MojoExecutionException {
        try {
            return getSVNManager().getStatusClient().doStatus(file, false);
        } catch (SVNException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    private SVNClientManager getSVNManager() {
        if (svnManager == null)
            svnManager = SVNClientManager.newInstance();
        return svnManager;
    }

    private boolean isPropertyWanted(String propertyName) {
        return propertyName != null && propertyName.length() > 0
                && (overwriteProperties || !existProperty(propertyName));
    }

    private boolean existProperty(String propertyName) {
        return projectProperties.containsKey(propertyName) || System.getProperty(propertyName) != null;
    }

    private void doExportProperty(String propertyName, String propertyValue) {
        if (propertyValue != null) {
            projectProperties.put(propertyName, propertyValue);
            exportedProperties.put(propertyName, propertyValue);
        }
    }

    private String getVersion() {
        String version = projectVersion;

        if (version.contains("SNAPSHOT"))
            version = version.replace("SNAPSHOT", getTimeStamp("YmdHMS"));

        return version;
    }

    private String getTimeStamp(String format) {
        StringBuffer result = new StringBuffer(format.length() * 5);

        for (char c : format.toCharArray()) {
            if (Character.isLetter(c))
                result.append("%1$t");
            result.append(c);
        }
        return String.format(result.toString(), now);
    }

    private boolean isWorkingCopy() {
        return new File(basedir, ".svn").exists();
    }
}