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

org.codehaus.mojo.license.AbstractFileHeaderMojo Maven / Gradle / Ivy

package org.codehaus.mojo.license;

/*
 * #%L
 * License Maven Plugin
 * %%
 * Copyright (C) 2008 - 2012 CodeLutin, Codehaus, Tony Chemit
 * %%
 * This program 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 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import freemarker.template.Template;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.mojo.license.api.FreeMarkerHelper;
import org.codehaus.mojo.license.header.FileHeader;
import org.codehaus.mojo.license.header.FileHeaderFilter;
import org.codehaus.mojo.license.header.FileHeaderProcessor;
import org.codehaus.mojo.license.header.FileHeaderProcessorConfiguration;
import org.codehaus.mojo.license.header.InvalideFileHeaderException;
import org.codehaus.mojo.license.header.UpdateFileHeaderFilter;
import org.codehaus.mojo.license.header.transformer.FileHeaderTransformer;
import org.codehaus.mojo.license.header.transformer.JavaFileHeaderTransformer;
import org.codehaus.mojo.license.model.Copyright;
import org.codehaus.mojo.license.model.License;
import org.codehaus.mojo.license.utils.FileUtil;
import org.codehaus.mojo.license.utils.MojoHelper;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.FileUtils;
import org.nuiton.processor.Processor;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
 * Abstract mojo for file-header operations (check, update, report,...).
 *
 * @author tchemit [email protected]
 * @since 1.2
 */
public abstract class AbstractFileHeaderMojo
    extends AbstractLicenseNameMojo
    implements FileHeaderProcessorConfiguration
{

    // ----------------------------------------------------------------------
    // Constants
    // ----------------------------------------------------------------------

    public static final String[] DEFAULT_INCLUDES = new String[]{ "**/*" };

    public static final String[] DEFAULT_EXCLUDES =
        new String[]{ "**/*.zargo", "**/*.uml", "**/*.umldi", "**/*.xmi", /* modelisation */
            "**/*.img", "**/*.png", "**/*.jpg", "**/*.jpeg", "**/*.gif", /* images */
            "**/*.zip", "**/*.jar", "**/*.war", "**/*.ear", "**/*.tgz", "**/*.gz" };

    public static final String[] DEFAULT_ROOTS =
        new String[]{ "src", "target/generated-sources", "target/processed-sources" };

    // ----------------------------------------------------------------------
    // Mojo Parameters
    // ----------------------------------------------------------------------

    /**
     * To overwrite the processStartTag used to build header model.
     *
     * See http://mojo.codehaus.org/license-maven-plugin/header.html#Configuration .
     *
     * @since 1.1
     */
    @Parameter( property = "license.processStartTag" )
    protected String processStartTag;

    /**
     * To overwrite the processEndTag used to build header model.
     *
     * See http://mojo.codehaus.org/license-maven-plugin/header.html#Configuration .
     *
     * @since 1.1
     */
    @Parameter( property = "license.processEndTag" )
    protected String processEndTag;

    /**
     * To overwrite the sectionDelimiter used to build header model.
     *
     * See http://mojo.codehaus.org/license-maven-plugin/header.html#Configuration .
     *
     * @since 1.1
     */
    @Parameter( property = "license.sectionDelimiter" )
    protected String sectionDelimiter;

    /**
     * A flag to add svn:keywords on new header.
     *
     * Will add svn keywords :
     * 
Id, HeadURL
* * Note: This parameter is used by the {@link #descriptionTemplate}, so if you change this * template, the parameter could be no more used (depends what you put in your own template...). * * @since 1.0 */ @Parameter( property = "license.addSvnKeyWords", defaultValue = "false" ) protected boolean addSvnKeyWords; /** * A flag to authorize update of the description part of the header. * * Note: By default, do NOT authorize it since description can change * on each file). * * @since 1.0 */ @Parameter( property = "license.canUpdateDescription", defaultValue = "false" ) protected boolean canUpdateDescription; /** * A flag to authorize update of the copyright part of the header. * * Note: By default, do NOT authorize it since copyright part should be * handled by developpers (holder can change on each file for example). * * @since 1.0 */ @Parameter( property = "license.canUpdateCopyright", defaultValue = "false" ) protected boolean canUpdateCopyright; /** * A flag to authorize update of the license part of the header. * * Note: By default, authorize it since license part should always be * generated by the plugin. * * @since 1.0 */ @Parameter( property = "license.canUpdateLicense", defaultValue = "true" ) protected boolean canUpdateLicense; /** * A tag to place on files that will be ignored by the plugin. * * Sometimes, it is necessary to do this when file is under a specific license. * * Note: If no sets, will use the default tag {@code %% Ignore-License} * * @since 1.0 */ @Parameter( property = "license.ignoreTag" ) protected String ignoreTag; /** * A flag to clear everything after execution. * * Note: This property should ONLY be used for test purpose. * * @since 1.0 */ @Parameter( property = "license.clearAfterOperation", defaultValue = "true" ) protected boolean clearAfterOperation; /** * A flag to add the license header in java files after the package statement. * * This is a practice used by many people (apache, codehaus, ...). * * Note: By default this property is then to {@code true} since it is a good practice. * * @since 1.2 */ @Parameter( property = "license.addJavaLicenseAfterPackage", defaultValue = "true" ) protected boolean addJavaLicenseAfterPackage; /** * A flag to use for java comment start tag with no reformat syntax {@code /*-}. *

* See http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-141999.html#350 * * @since 1.9 */ @Parameter( property = "license.useJavaNoReformatCommentStartTag", defaultValue = "true" ) protected boolean useJavaNoReformatCommentStartTag; /** * A flag to indicate if there should be an empty line after the header. *

* Checkstyle requires empty line between license header and package statement. * If you are using addJavaLicenseAfterPackage=false it could make sense to set this to true. *

* Note: By default this property is set to {@code false} to keep old behavior. * * @since 1.9 */ @Parameter( property = "license.emptyLineAfterHeader", defaultValue = "false" ) protected boolean emptyLineAfterHeader; /** * A flag to ignore no files to scan. *

* This flag will suppress the "No file to scan" warning. This will allow you to set the plug-in in the root pom of * your project without getting a lot of warnings for aggregation modules / artifacts. *

* Note: By default this property is set to {@code false} to keep old behavior. * * @since 1.9 */ @Parameter( property = "license.ignoreNoFileToScan", defaultValue = "false" ) protected boolean ignoreNoFileToScan; /** * To specify the base dir from which we apply the license. * * Should be on form "root1,root2,rootn". * * By default, the main roots are "src, target/generated-sources, target/processed-sources". * * Note: If some of these roots do not exist, they will be simply * ignored. * * Note: This parameter is not useable if you are still using a project file descriptor. * * @since 1.0 */ @Parameter( property = "license.roots" ) protected String[] roots; /** * Specific files to includes, separated by a comma. By default, it is "** /*". * * Note: This parameter is not usable if you are still using a project file descriptor. * * @since 1.0 */ @Parameter( property = "license.includes" ) protected String[] includes; /** * Specific files to excludes, separated by a comma. * By default, thoses file type are excluded: *
    *
  • modelisation
  • *
  • images
  • *
* * Note: This parameter is not useable if you are still using a project file descriptor. * * @since 1.0 */ @Parameter( property = "license.excludes" ) protected String[] excludes; /** * To associate extra extension files to an existing comment style. * * Keys of the map are the extension of extra files to treat, and the value * is the comment style you want to associate. * * For example, to treat file with extensions {@code java2} and {@code jdata} * as {@code java} files (says using the {@code java} comment style, declare this * in your plugin configuration : *
     * <extraExtensions>
     * <java2>java</java2>
     * <jdata>java</jdata>
     * </extraExtensions>
     * 
* * Note: This parameter is not useable if you are still using a project file descriptor. * * @parameter * @since 1.0 */ @Parameter protected Map extraExtensions; /** * Template used to build the description section of the license header. * * (This template use freemarker). * * @since 1.1 */ @Parameter( property = "license.descriptionTemplate", defaultValue = "/org/codehaus/mojo/license/default-file-header-description.ftl" ) protected String descriptionTemplate; // ---------------------------------------------------------------------- // Plexus components // ---------------------------------------------------------------------- /** * @since 1.0 */ @Component( role = Processor.class, hint = "file-header" ) private FileHeaderProcessor processor; /** * The processor filter used to change header content. * * @since 1.0 */ @Component( role = FileHeaderFilter.class, hint = "update-file-header" ) private UpdateFileHeaderFilter filter; /** * All available header transformers. * * @since 1.0 */ @Component( role = FileHeaderTransformer.class ) private Map transformers; // ---------------------------------------------------------------------- // Private fields // ---------------------------------------------------------------------- /** * internal file header transformer. */ private FileHeaderTransformer transformer; /** * internal default file header. */ private FileHeader header; /** * timestamp used for generation. */ private long timestamp; /** * The dictionary of extension indexed by their associated comment style. * * @since 1.0 */ private Map extensionToCommentStyle; /** * The freemarker template used to render the description section of the file header. * * @since 1.1 */ private Template descriptionTemplate0; /** * set of processed files */ private Set processedFiles; /** * Dictionary of treated files indexed by their state. */ private EnumMap> result; /** * Dictionary of files to treat indexed by their CommentStyle. */ private Map> filesToTreateByCommentStyle; /** * Freemarker helper component. * * @since 1.0 */ private FreeMarkerHelper freeMarkerHelper = FreeMarkerHelper.newDefaultHelper(); // ---------------------------------------------------------------------- // Abstract Methods // ---------------------------------------------------------------------- /** * @return {@code true} if mojo must be a simple dry run (says do not modifiy any scanned files), * {@code false} otherise. */ protected abstract boolean isDryRun(); /** * @return {@code true} if mojo should fails if dryRun and there is some missing license header, {@code false} otherwise. */ protected abstract boolean isFailOnMissingHeader(); /** * @return {@code true} if mojo should fails if dryRun and there is some obsolete license header, {@code false} otherwise. */ protected abstract boolean isFailOnNotUptodateHeader(); // ---------------------------------------------------------------------- // AbstractLicenseMojo Implementaton // ---------------------------------------------------------------------- /** * {@inheritDoc} */ @Override public void init() throws Exception { if ( StringUtils.isEmpty( ignoreTag ) ) { // use default value this.ignoreTag = "%" + "%Ignore-License"; } if ( !isDryRun() ) { if ( isFailOnMissingHeader() ) { getLog().warn( "The failOnMissingHeader has no effect if the property dryRun is not set." ); } if ( isFailOnNotUptodateHeader() ) { getLog().warn( "The failOnNotUptodateHeader has no effect if the property dryRun is not set." ); } } if ( isVerbose() ) { // print availables comment styles (transformers) StringBuilder buffer = new StringBuilder(); buffer.append( "config - available comment styles :" ); String commentFormat = "\n * %1$s (%2$s)"; for ( String transformerName : transformers.keySet() ) { FileHeaderTransformer aTransformer = getTransformer( transformerName ); String str = String.format( commentFormat, aTransformer.getName(), aTransformer.getDescription() ); buffer.append( str ); } getLog().info( buffer.toString() ); } // set timestamp used for temporary files this.timestamp = System.nanoTime(); // add flags to authorize or not updates of header filter.setUpdateCopyright( canUpdateCopyright ); filter.setUpdateDescription( canUpdateDescription ); filter.setUpdateLicense( canUpdateLicense ); filter.setLog( getLog() ); processor.setConfiguration( this ); processor.setFilter( filter ); super.init(); if ( roots == null || roots.length == 0 ) { roots = DEFAULT_ROOTS; if ( isVerbose() ) { getLog().info( "Will use default roots " + Arrays.toString( roots ) ); } } if ( includes == null || includes.length == 0 ) { includes = DEFAULT_INCLUDES; if ( isVerbose() ) { getLog().info( "Will use default includes " + Arrays.toString( includes ) ); } } if ( excludes == null || excludes.length == 0 ) { excludes = DEFAULT_EXCLUDES; if ( isVerbose() ) { getLog().info( "Will use default excludes" + Arrays.toString( excludes ) ); } } extensionToCommentStyle = new TreeMap(); processStartTag = cleanHeaderConfiguration( processStartTag, FileHeaderTransformer.DEFAULT_PROCESS_START_TAG ); if ( isVerbose() ) { getLog().info( "Will use processStartTag: " + processEndTag ); } processEndTag = cleanHeaderConfiguration( processEndTag, FileHeaderTransformer.DEFAULT_PROCESS_END_TAG ); if ( isVerbose() ) { getLog().info( "Will use processEndTag: " + processEndTag ); } sectionDelimiter = cleanHeaderConfiguration( sectionDelimiter, FileHeaderTransformer.DEFAULT_SECTION_DELIMITER ); if ( isVerbose() ) { getLog().info( "Will use sectionDelimiter: " + sectionDelimiter ); } // add default extensions from header transformers for ( Map.Entry entry : transformers.entrySet() ) { String commentStyle = entry.getKey(); FileHeaderTransformer aTransformer = entry.getValue(); aTransformer.setProcessStartTag( processStartTag ); aTransformer.setProcessEndTag( processEndTag ); aTransformer.setSectionDelimiter( sectionDelimiter ); aTransformer.setEmptyLineAfterHeader( emptyLineAfterHeader ); if ( aTransformer instanceof JavaFileHeaderTransformer ) { JavaFileHeaderTransformer javaFileHeaderTransformer = (JavaFileHeaderTransformer) aTransformer; javaFileHeaderTransformer.setAddJavaLicenseAfterPackage( addJavaLicenseAfterPackage ); javaFileHeaderTransformer.setUseNoReformatCommentStartTag( useJavaNoReformatCommentStartTag ); } String[] extensions = aTransformer.getDefaultAcceptedExtensions(); for ( String extension : extensions ) { if ( isVerbose() ) { getLog().info( "Associate extension " + extension + " to comment style " + commentStyle ); } extensionToCommentStyle.put( extension, commentStyle ); } } if ( extraExtensions != null ) { // fill extra extensions for each transformer for ( Map.Entry entry : extraExtensions.entrySet() ) { String extension = entry.getKey(); if ( extensionToCommentStyle.containsKey( extension ) ) { // override existing extension mapping getLog().warn( "The extension " + extension + " is already accepted for comment style " + extensionToCommentStyle.get( extension ) ); } String commentStyle = entry.getValue(); // check transformer exists getTransformer( commentStyle ); if ( isVerbose() ) { getLog().info( "Associate extension '" + extension + "' to comment style '" + commentStyle + "'" ); } extensionToCommentStyle.put( extension, commentStyle ); } } // get all files to treat indexed by their comment style filesToTreateByCommentStyle = obtainFilesToProcessByCommentStyle(); // build the description template if ( isVerbose() ) { getLog().info( "Use description template : " + descriptionTemplate ); } descriptionTemplate0 = freeMarkerHelper.getTemplate( descriptionTemplate ); } /** * {@inheritDoc} */ @Override public void doAction() throws Exception { long t0 = System.nanoTime(); clear(); processedFiles = new HashSet(); result = new EnumMap>( FileState.class ); try { for ( Map.Entry> commentStyleFiles : filesToTreateByCommentStyle.entrySet() ) { String commentStyle = commentStyleFiles.getKey(); List files = commentStyleFiles.getValue(); processCommentStyle( commentStyle, files ); } } finally { checkResults( result ); int nbFiles = processedFiles.size(); if ( nbFiles == 0 && !ignoreNoFileToScan ) { getLog().warn( "No file to scan." ); } else { String delay = MojoHelper.convertTime( System.nanoTime() - t0 ); String message = String.format( "Scan %s file%s header done in %s.", nbFiles, nbFiles > 1 ? "s" : "", delay ); getLog().info( message ); } Set states = result.keySet(); if ( states.size() == 1 && states.contains( FileState.uptodate ) ) { // all files where up to date getLog().info( "All files are up-to-date." ); } else { StringBuilder buffer = new StringBuilder(); for ( FileState state : FileState.values() ) { reportType( state, buffer ); } getLog().info( buffer.toString() ); } // clean internal states if ( clearAfterOperation ) { clear(); } } } // ---------------------------------------------------------------------- // FileHeaderProcessorConfiguration Implementaton // ---------------------------------------------------------------------- /** * {@inheritDoc} */ public FileHeader getFileHeader() { return header; } /** * {@inheritDoc} */ public FileHeaderTransformer getTransformer() { return transformer; } // ---------------------------------------------------------------------- // Protected Methods // ---------------------------------------------------------------------- /** * Gets all files to process indexed by their comment style. * * @return for each comment style, list of files to process */ protected Map> obtainFilesToProcessByCommentStyle() { Map> results = new HashMap>(); // add for all known comment style (says transformer) a empty list // this permits not to have to test if there is an already list each time // we wants to add a new file... for ( String commentStyle : transformers.keySet() ) { results.put( commentStyle, new ArrayList() ); } List rootsList = new ArrayList( roots.length ); for ( String root : roots ) { File f = new File( root ); if ( f.isAbsolute() ) { rootsList.add( f.getAbsolutePath() ); } else { f = new File( getProject().getBasedir(), root ); } if ( f.exists() ) { getLog().info( "Will search files to update from root " + f ); rootsList.add( f.getAbsolutePath() ); } else { if ( isVerbose() ) { getLog().info( "Skip not found root " + f ); } } } // Obtain all files to treat Map allFiles = new HashMap(); getFilesToTreateForRoots( includes, excludes, rootsList, allFiles ); // filter all these files according to their extension for ( Map.Entry entry : allFiles.entrySet() ) { File root = entry.getKey(); String[] filesPath = entry.getValue(); // sort them by the associated comment style to their extension for ( String path : filesPath ) { String extension = FileUtils.extension( path ); String commentStyle = extensionToCommentStyle.get( extension ); if ( StringUtils.isEmpty( commentStyle ) ) { // unknown extension, do not treat this file continue; } // File file = new File( root, path ); List files = results.get( commentStyle ); files.add( file ); } } return results; } /** * Checks the results of the mojo execution using the {@link #isFailOnMissingHeader()} and * {@link #isFailOnNotUptodateHeader()}. * * @param result processed files by their status * @throws MojoFailureException if check is not ok (some file with no header or to update) */ protected void checkResults( EnumMap> result ) throws MojoFailureException { Set states = result.keySet(); StringBuilder builder = new StringBuilder(); if ( isDryRun() && isFailOnMissingHeader() && states.contains( FileState.add ) ) { List files = FileUtil.orderFiles( result.get( FileState.add ) ); builder.append( "There are " ).append( files.size() ).append( " file(s) with no header :" ); for ( File file : files ) { builder.append( "\n" ).append( file ); } } if ( isDryRun() && isFailOnNotUptodateHeader() && states.contains( FileState.update ) ) { List files = FileUtil.orderFiles( result.get( FileState.update ) ); builder.append( "\nThere are " ).append( files.size() ).append( " file(s) with header to update:" ); for ( File file : files ) { builder.append( "\n" ).append( file ); } } String message = builder.toString(); if ( StringUtils.isNotBlank( message ) ) { throw new MojoFailureException( builder.toString() ); } } /** * Process a given comment style to all his detected files. * * @param commentStyle comment style to treat * @param filesToTreat files using this comment style to treat * @throws IOException if any IO error while processing files */ protected void processCommentStyle( String commentStyle, List filesToTreat ) throws IOException { // obtain license from definition License license = getLicense( getLicenseName(), true ); if ( isVerbose() ) { getLog().info( "Process header '" + commentStyle + "'" ); getLog().info( " - using " + license.getDescription() ); } // use header transformer according to comment style given in header this.transformer = getTransformer( commentStyle ); // file header to use if no header is found on a file this.header = buildDefaultFileHeader( license, getEncoding() ); // update processor filter processor.populateFilter(); for ( File file : filesToTreat ) { processFile( file ); } filesToTreat.clear(); } /** * Process the given file (will copy it, process the clone file and finally finalizeFile after process)... * * @param file original file to process * @throws IOException if any IO error while processing this file */ protected void processFile( File file ) throws IOException { if ( processedFiles.contains( file ) ) { getLog().info( " - skip already processed file " + file ); return; } // output file File processFile = new File( file.getAbsolutePath() + "_" + timestamp ); boolean doFinalize = false; try { doFinalize = processFile( file, processFile ); } catch ( Exception e ) { getLog().warn( "skip failed file : " + e.getMessage() + ( e.getCause() == null ? "" : " Cause : " + e.getCause().getMessage() ), e ); FileState.fail.addFile( file, result ); doFinalize = false; } finally { // always clean processor internal states processor.reset(); // whatever was the result, this file is treated. processedFiles.add( file ); if ( doFinalize ) { finalizeFile( file, processFile ); } else { FileUtil.deleteFile( processFile ); } } } /** * Process the given {@code file} and save the result in the given * {@code processFile}. * * @param file the file to process * @param processFile the ouput processed file * @return {@code true} if prepareProcessFile can be finalize, otherwise need to be delete * @throws java.io.IOException if any pb while treatment */ protected boolean processFile( File file, File processFile ) throws IOException { if ( getLog().isDebugEnabled() ) { getLog().debug( " - process file " + file ); getLog().debug( " - will process into file " + processFile ); } // update the file header description updateFileHeaderDescription( file ); String content; try { // check before all that file should not be skip by the ignoreTag // this is a costy operation //TODO-TC-20100411 We should process always from the read content not reading again from file content = FileUtil.readAsString( file, getEncoding() ); } catch ( IOException e ) { throw new IOException( "Could not obtain content of file " + file ); } //check that file is not marked to be ignored if ( content.contains( ignoreTag ) ) { getLog().info( " - ignore file (detected " + ignoreTag + ") " + file ); FileState.ignore.addFile( file, result ); return false; } // process file to detect header try { processor.process( file, processFile ); } catch ( IllegalStateException e ) { // could not obtain existing header throw new InvalideFileHeaderException( "Could not extract header on file " + file + " for reason " + e.getMessage() ); } catch ( Exception e ) { if ( e instanceof InvalideFileHeaderException ) { throw (InvalideFileHeaderException) e; } throw new IOException( "Could not process file " + file + " for reason " + e.getMessage() ); } if ( processor.isTouched() ) { if ( isVerbose() ) { getLog().info( " - header was updated for " + file ); } if ( processor.isModified() ) { // header content has changed // must copy back process file to file (if not dry run) FileState.update.addFile( file, result ); return true; } FileState.uptodate.addFile( file, result ); return false; } // header was not fully (or not at all) detected in file if ( processor.isDetectHeader() ) { // file has not a valid header (found a start process atg, but // not an ending one), can not do anything throw new InvalideFileHeaderException( "Could not find header end on file " + file ); } // no header at all, add a new header if ( isVerbose() ) { getLog().info( " - adding license header on file " + file ); } //FIXME tchemit 20100409 xml files must add header after a xml prolog line content = getTransformer().addHeader( filter.getFullHeaderContent(), content ); if ( !isDryRun() ) { FileUtil.printString( processFile, content, getEncoding() ); } FileState.add.addFile( file, result ); return true; } /** * Finalize the process of a file. * * If ad DryRun then just remove processed file, else use process file as original file. * * @param file the original file * @param processFile the processed file * @throws IOException if any IO error while finalizing file */ protected void finalizeFile( File file, File processFile ) throws IOException { if ( isKeepBackup() && !isDryRun() ) { File backupFile = FileUtil.getBackupFile( file ); if ( backupFile.exists() ) { // always delete backup file, before the renaming FileUtil.deleteFile( backupFile ); } if ( isVerbose() ) { getLog().debug( " - backup original file " + file ); } FileUtil.renameFile( file, backupFile ); } if ( isDryRun() ) { // dry run, delete temporary file FileUtil.deleteFile( processFile ); } else { try { // replace file with the updated one FileUtil.renameFile( processFile, file ); } catch ( IOException e ) { getLog().warn( e.getMessage() ); } } } /** * {@inheritDoc} */ @Override protected void finalize() throws Throwable { super.finalize(); clear(); } /** * Clear internal states of the mojo after execution. (will only invoked if {@link #clearAfterOperation} if on). */ protected void clear() { if ( processedFiles != null ) { processedFiles.clear(); } if ( result != null ) { for ( Set fileSet : result.values() ) { fileSet.clear(); } result.clear(); } } /** * Reports into the given {@code buffer} stats for the given {@code state}. * * @param state state of file to report * @param buffer where to report */ protected void reportType( FileState state, StringBuilder buffer ) { String operation = state.name(); Set set = getFiles( state ); if ( set == null || set.isEmpty() ) { if ( isVerbose() ) { buffer.append( "\n * no header to " ); buffer.append( operation ); buffer.append( "." ); } return; } buffer.append( "\n * " ).append( operation ).append( " header on " ); buffer.append( set.size() ); if ( set.size() == 1 ) { buffer.append( " file." ); } else { buffer.append( " files." ); } if ( isVerbose() ) { for ( File file : set ) { buffer.append( "\n - " ).append( file ); } } } /** * Build a default header given the parameters. * * @param license the license type ot use in header * @param encoding encoding used to read or write files * @return the new file header * @throws java.io.IOException if any problem while creating file header */ protected FileHeader buildDefaultFileHeader( License license, String encoding ) throws IOException { FileHeader defaultFileHeader = new FileHeader(); if ( inceptionYear == null ) { getLog().warn( "No inceptionYear defined (will use current year)" ); } Copyright copyright = getCopyright( getCopyrightOwners() ); defaultFileHeader.setCopyright( copyright ); // Calendar cal = Calendar.getInstance(); // cal.setTime( new Date() ); // Integer lastYear = cal.get( Calendar.YEAR ); // Integer firstYear; // if ( inceptionYear == null ) // { // getLog().warn( "No inceptionYear defined (will use current year)" ); // firstYear = lastYear; // } // else // { // firstYear = Integer.valueOf( inceptionYear ); // } // defaultFileHeader.setCopyrightFirstYear( firstYear ); // if ( firstYear < lastYear ) // { // defaultFileHeader.setCopyrightLastYear( lastYear ); // } // defaultFileHeader.setCopyrightHolder( organizationName ); String licenseContent = license.getHeaderContent( encoding ); if ( license.isHeaderContentTemplateAware() ) { licenseContent = processLicenseContext( licenseContent ); } defaultFileHeader.setLicense( licenseContent ); return defaultFileHeader; } /** * Update in file header the description parts given the current file. * * @param file current file to treat * @throws java.io.IOException if any problem while creating file header */ protected void updateFileHeaderDescription( File file ) throws IOException { Map descriptionParameters = new HashMap(); descriptionParameters.put( "project", getProject() ); descriptionParameters.put( "addSvnKeyWords", addSvnKeyWords ); descriptionParameters.put( "projectName", projectName ); descriptionParameters.put( "inceptionYear", inceptionYear ); descriptionParameters.put( "organizationName", organizationName ); descriptionParameters.put( "file", file ); getLog().debug( "Description parameters:" + descriptionParameters ); String description = freeMarkerHelper.renderTemplate( descriptionTemplate0, descriptionParameters ); header.setDescription( description ); getLog().debug( "Computed description: " + description ); filter.resetContent(); if ( getLog().isDebugEnabled() ) { getLog().debug( "header description : " + header.getDescription() ); } } /** * Obtains the {@link FileHeaderTransformer} given his name. * * @param transformerName the name of the transformer to find * @return the transformer for the givne tramsformer name */ protected FileHeaderTransformer getTransformer( String transformerName ) { if ( StringUtils.isEmpty( transformerName ) ) { throw new IllegalArgumentException( "transformerName can not be null, nor empty!" ); } if ( transformers == null ) { throw new IllegalStateException( "No transformers initialized!" ); } FileHeaderTransformer transformer = transformers.get( transformerName ); if ( transformer == null ) { throw new IllegalArgumentException( "transformerName " + transformerName + " is unknow, use one this one : " + transformers.keySet() ); } return transformer; } /** * Obtain for a given value, a trim version of it. If value is empty then use the given default value * * @param value the value to trim (if not empty) * @param defaultValue the default value to use if value is empty * @return the trim value (or default value if value is empty) */ protected String cleanHeaderConfiguration( String value, String defaultValue ) { String resultHeader; if ( StringUtils.isEmpty( value ) ) { // use default value resultHeader = defaultValue; } else { // clean all spaces of it resultHeader = value.replaceAll( "\\s", "" ); } return resultHeader; } /** * Gets all files for the given {@code state}. * * @param state state of files to get * @return all files of the given state */ protected Set getFiles( FileState state ) { return result.get( state ); } /** * Collects some file. * * @param includes includes * @param excludes excludes * @param roots root directories to treat * @param files cache of file detected indexed by their root directory */ protected void getFilesToTreateForRoots( String[] includes, String[] excludes, List roots, Map files ) { DirectoryScanner ds = new DirectoryScanner(); ds.setIncludes( includes ); if ( excludes != null ) { ds.setExcludes( excludes ); } for ( String src : roots ) { File f = new File( src ); if ( !f.exists() ) { // do nothing on a non-existent continue; } if ( getLog().isDebugEnabled() ) { getLog().debug( "discovering source files in " + src ); } ds.setBasedir( f ); // scan ds.scan(); // get files String[] tmp = ds.getIncludedFiles(); if ( tmp.length < 1 ) { // no files found continue; } List toTreate = new ArrayList(); Collections.addAll( toTreate, tmp ); if ( toTreate.isEmpty() ) { // no file or all are up-to-date continue; } // register files files.put( f, toTreate.toArray( new String[toTreate.size()] ) ); } } /** * Defines state of a file after process. * * @author tchemit [email protected] * @since 1.0 */ public static enum FileState { /** * file was updated */ update, /** * file was up to date */ uptodate, /** * something was added on file */ add, /** * file was ignored */ ignore, /** * treatment failed for file */ fail; /** * Register a file for this state on result dictionary. * * @param file file to add * @param results dictionary to update */ public void addFile( File file, EnumMap> results ) { Set fileSet = results.get( this ); if ( fileSet == null ) { fileSet = new HashSet(); results.put( this, fileSet ); } fileSet.add( file ); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy