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

oe.maven.plugins.revision.RevisionMojo Maven / Gradle / Ivy

Go to download

This plugin retrieves the revision number and the status of the Subversion working copy directory.

There is a newer version: 1.7
Show newest version
/*-
 * Copyright (c) 2009, Oleg Estekhin
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the distribution.
 *  * Neither the names of the copyright holders nor the names of their
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

package oe.maven.plugins.revision;

import java.io.File;
import java.util.HashSet;
import java.util.Set;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry;
import org.tmatesoft.svn.core.wc.ISVNStatusHandler;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNStatus;
import org.tmatesoft.svn.core.wc.SVNStatusClient;
import org.tmatesoft.svn.core.wc.SVNStatusType;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

/**
 * Retrieves the status and revision number of the subversion working copy directory.
 *
 * @goal revision
 * @phase initialize
 * @requiresProject
 */
public class RevisionMojo extends AbstractMojo {

    static {
        DAVRepositoryFactory.setup(); // http, https
        SVNRepositoryFactoryImpl.setup(); // svn, svn+xxx
        FSRepositoryFactory.setup(); // file
    }


    /**
     * The maven project.
     *
     * @parameter expression="${project}"
     * @readonly
     */
    private MavenProject project;

    /**
     * The subversion working copy directory.
     * The plugin will evaluate the aggregated status and revision number of this directory and its contents.
     *
     * @parameter expression="${workingCopyDirectory}" default-value="${basedir}"
     * @required
     */
    private File workingCopyDirectory;

    /**
     * The name of the property that will contain the root of the remote repository of the working copy directory
     * entry.
     *
     * @parameter expression="${repositoryPropertyName}" default-value="workingCopyDirectory.repository"
     */
    private String repositoryPropertyName;

    /**
     * The name of the property that will contain the path of the working copy directory entry relative
     * to the root of the remote repository.
     *
     * @parameter expression="${pathPropertyName}" default-value="workingCopyDirectory.path"
     */
    private String pathPropertyName;

    /**
     * The name of the property that will contain the aggregated status and revision number of the  working copy
     * directory.
     *
     * @parameter expression="${revisionPropertyName}" default-value="workingCopyDirectory.revision"
     */
    private String revisionPropertyName;


    /**
     * Whether to report the mixed revisions information. If set to {@code false} then only the maximum revision number
     * will be reported.
     *
     * @parameter expression="${reportMixedRevisions}" default-value="true"
     */
    private boolean reportMixedRevisions;

    /**
     * Whether to report the status information. If set to {@code false} then only the revision number will be
     * reported.
     *
     * @parameter expression="${reportStatus}" default-value="true"
     */
    private boolean reportStatus;

    /**
     * Whether to collect the status information on items that are not under version control.
     *
     * @parameter expression="${reportUnversioned}" default-value="true"
     */
    private boolean reportUnversioned;

    /**
     * Whether to collect the status information on items that were set to be ignored.
     *
     * @parameter expression="${reportIgnored}" default-value="false"
     */
    private boolean reportIgnored;

    /**
     * Whether to check the remote repository and report if the local items are out-of-date.
     *
     * @parameter expression="${reportOutOfDate}" default-value="false"
     */
    private boolean reportOutOfDate;

    /**
     * Provides detailed messages while this goal is running.
     *
     * @parameter expression="${verbose}" default-value="false"
     */
    private boolean verbose;


    public void execute() throws MojoExecutionException, MojoFailureException {
        if (verbose) {
            getLog().info("${workingCopyDirectory}: " + workingCopyDirectory);
            getLog().info("report mixed revisions: " + reportMixedRevisions);
            getLog().info("report status: " + reportStatus);
            getLog().info("report unversioned: " + reportUnversioned);
            getLog().info("report ignored: " + reportIgnored);
            getLog().info("report out-of-date: " + reportOutOfDate);
        }
        try {
            String repository;
            String path;
            String revision;
            if (SVNWCUtil.isVersionedDirectory(workingCopyDirectory)) {
                SVNClientManager clientManager = SVNClientManager.newInstance();
                SVNStatusClient statusClient = clientManager.getStatusClient();

                SVNEntry entry = statusClient.doStatus(workingCopyDirectory, false).getEntry();
                repository = entry.getRepositoryRoot();
                path = entry.getURL().substring(repository.length());
                if (path.startsWith("/")) {
                    path = path.substring(1);
                }

                StatusCollector statusCollector = new StatusCollector();
                statusClient.doStatus(workingCopyDirectory,
                        SVNRevision.HEAD, SVNDepth.INFINITY,
                        reportOutOfDate, true, reportIgnored, false,
                        statusCollector,
                        null);
                revision = statusCollector.toString();
            } else {
                repository = "";
                path = "";
                revision = "unversioned";
            }
            project.getProperties().setProperty(repositoryPropertyName, repository);
            project.getProperties().setProperty(pathPropertyName, path);
            project.getProperties().setProperty(revisionPropertyName, revision);
            if (verbose) {
                getLog().info("${" + repositoryPropertyName + "} is set to \"" + repository + '\"');
                getLog().info("${" + pathPropertyName + "} is set to \"" + path + '\"');
                getLog().info("${" + revisionPropertyName + "} is set to \"" + revision + '\"');
            }
        } catch (SVNException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }


    private final class StatusCollector implements ISVNStatusHandler {

        private long maximumRevisionNumber;

        private long minimumRevisionNumber;

        private Set localStatusTypes;

        private boolean remoteChanges;

        private StatusCollector() {
            maximumRevisionNumber = Long.MIN_VALUE;
            minimumRevisionNumber = Long.MAX_VALUE;
            localStatusTypes = new HashSet();
        }

        public void handleStatus(SVNStatus status) {
            SVNStatusType contentsStatusType = status.getContentsStatus();
            localStatusTypes.add(contentsStatusType);
            long revisionNumber = status.getRevision().getNumber();
            if (revisionNumber >= 0L) {
                maximumRevisionNumber = Math.max(maximumRevisionNumber, revisionNumber);
            }
            if (revisionNumber > 0L) {
                minimumRevisionNumber = Math.min(minimumRevisionNumber, revisionNumber);
            }
            SVNStatusType propertiesStatusType = status.getPropertiesStatus();
            localStatusTypes.add(propertiesStatusType);
            boolean remoteStatusTypes = !SVNStatusType.STATUS_NONE.equals(status.getRemotePropertiesStatus())
                    || !SVNStatusType.STATUS_NONE.equals(status.getRemoteContentsStatus());
            remoteChanges = remoteChanges || remoteStatusTypes;
            if (verbose) {
                StringBuilder buffer = new StringBuilder();
                buffer.append(status.getContentsStatus().getCode()).append(status.getPropertiesStatus().getCode());
                buffer.append(remoteStatusTypes ? '*' : ' ');
                buffer.append(' ').append(String.format("%6d", status.getRevision().getNumber()));
                buffer.append(' ').append(status.getFile());
                getLog().info(buffer.toString());
            }
        }

        @Override
        public String toString() {
            StringBuilder result = new StringBuilder();
            if (maximumRevisionNumber != Long.MIN_VALUE) {
                result.append('r').append(maximumRevisionNumber);
                if (minimumRevisionNumber != maximumRevisionNumber && reportMixedRevisions) {
                    result.append('-').append('r').append(minimumRevisionNumber);
                }
            }
            if (reportStatus) {
                localStatusTypes.remove(SVNStatusType.STATUS_NONE);
                localStatusTypes.remove(SVNStatusType.STATUS_NORMAL);
                if (!localStatusTypes.isEmpty()) {
                    result.append(' ');
                }
                if (localStatusTypes.remove(SVNStatusType.STATUS_MODIFIED)) {
                    result.append(SVNStatusType.STATUS_MODIFIED.getCode());
                }
                if (localStatusTypes.remove(SVNStatusType.STATUS_ADDED)) {
                    result.append(SVNStatusType.STATUS_ADDED.getCode());
                }
                if (localStatusTypes.remove(SVNStatusType.STATUS_DELETED)) {
                    result.append(SVNStatusType.STATUS_DELETED.getCode());
                }
                if (localStatusTypes.remove(SVNStatusType.STATUS_UNVERSIONED) && reportUnversioned) {
                    result.append(SVNStatusType.STATUS_UNVERSIONED.getCode());
                }
                if (localStatusTypes.remove(SVNStatusType.STATUS_MISSING)) {
                    result.append(SVNStatusType.STATUS_MISSING.getCode());
                    localStatusTypes.remove(SVNStatusType.STATUS_INCOMPLETE); // same status code '!'
                }
                if (localStatusTypes.remove(SVNStatusType.STATUS_REPLACED)) {
                    result.append(SVNStatusType.STATUS_REPLACED.getCode());
                }
                if (localStatusTypes.remove(SVNStatusType.STATUS_CONFLICTED)) {
                    result.append(SVNStatusType.STATUS_CONFLICTED.getCode());
                }
                if (localStatusTypes.remove(SVNStatusType.STATUS_OBSTRUCTED)) {
                    result.append(SVNStatusType.STATUS_OBSTRUCTED.getCode());
                }
                if (localStatusTypes.remove(SVNStatusType.STATUS_IGNORED) && reportIgnored) {
                    result.append(SVNStatusType.STATUS_IGNORED.getCode());
                }
                if (localStatusTypes.remove(SVNStatusType.STATUS_INCOMPLETE)) {
                    result.append(SVNStatusType.STATUS_CONFLICTED.getCode());
                }
                if (localStatusTypes.remove(SVNStatusType.STATUS_EXTERNAL)) {
                    result.append(SVNStatusType.STATUS_EXTERNAL.getCode());
                }
                if (!localStatusTypes.isEmpty()) {
                    getLog().warn("unprocessed svn statuses: " + localStatusTypes);
                }
                if (remoteChanges && reportOutOfDate) {
                    result.append('*');
                }
            }
            return result.toString();
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy