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

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

There is a newer version: 2.4.0
Show newest version
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.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.mojo.license.header.transformer.FileHeaderTransformer;
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.FileUtils;

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

/**
 * The goal to remove the header on project source files.
 *
 * @author tchemit [email protected]
 * @since 1.11
 */
@Mojo( name = "remove-file-header", threadSafe = true )
public class RemoveFileHeaderMojo extends AbstractLicenseNameMojo
{

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

    /**
     * A flag to skip the goal.
     *
     * @since 1.11
     */
    @Parameter( property = "license.skipRemoveLicense", defaultValue = "false" )
    private boolean skipRemoveLicense;

    /**
     * A flag to test plugin but modify no file.
     *
     * @since 1.11
     */
    @Parameter( property = "dryRun", defaultValue = "false" )
    private boolean dryRun;

    /**
     * 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. *

* * @since 1.11 */ @Parameter( property = "license.ignoreNoFileToScan", defaultValue = "false" ) private 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. * * @since 1.11 */ @Parameter( property = "license.roots" ) private String[] roots; /** * Specific files to includes, separated by a comma. By default, it is "** /*". * * @since 1.11 */ @Parameter( property = "license.includes" ) private String[] includes; /** * Specific files to excludes, separated by a comma. * By default, those file types are excluded: *

    *
  • modelisation
  • *
  • images
  • *
* * @since 1.11 */ @Parameter( property = "license.excludes" ) private 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>
     * 
* * @since 1.11 */ @Parameter private Map extraExtensions; /** * To associate extra files to an existing comment style. *

* Keys of the map are the name of extra files to treat, and the value * is the comment style you want to associate. *

* For example, to treat a file named {@code DockerFile} as {@code properties} files * (says using the {@code properties} comment style, declare this in your plugin configuration : *

     * <extraFiles>
     * <DockerFile>properties</DockerFile>
     * </extraFiles>
     * 
* * @since 1.11 */ @Parameter private Map extraFiles; /** * 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" ) private String ignoreTag; // ---------------------------------------------------------------------- // Plexus components // ---------------------------------------------------------------------- /** * All available header transformers. * * @since 1.0 */ @Component( role = FileHeaderTransformer.class ) private Map transformers; // ---------------------------------------------------------------------- // Private fields // ---------------------------------------------------------------------- /** * timestamp used for generation. */ private long timestamp; /** * 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> filesToTreatByCommentStyle; // ---------------------------------------------------------------------- // AbstractLicenceMojo Implementation // ---------------------------------------------------------------------- @Override public boolean isSkip() { return skipRemoveLicense; } // ---------------------------------------------------------------------- // AbstractLicenseMojo Implementaton // ---------------------------------------------------------------------- @Override public void init() throws Exception { if ( StringUtils.isEmpty( ignoreTag ) ) { // use default value this.ignoreTag = "%" + "%Ignore-License"; } if ( isVerbose() ) { // print available 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( transformers, 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(); 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 ) ); } } Map extensionToCommentStyle = new TreeMap<>(); // add default extensions from header transformers for ( Map.Entry entry : transformers.entrySet() ) { String commentStyle = entry.getKey(); FileHeaderTransformer aTransformer = entry.getValue(); 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( transformers, commentStyle ); if ( isVerbose() ) { getLog().info( "Associate extension '" + extension + "' to comment style '" + commentStyle + "'" ); } extensionToCommentStyle.put( extension, commentStyle ); } } if ( extraFiles == null ) { extraFiles = Collections.emptyMap(); } // get all files to treat indexed by their comment style filesToTreatByCommentStyle = obtainFilesToProcessByCommentStyle( extraFiles, roots, includes, excludes, extensionToCommentStyle, transformers ); } @Override public void doAction() throws Exception { long t0 = System.nanoTime(); processedFiles = new HashSet<>(); result = new EnumMap<>( FileState.class ); try { for ( Map.Entry> commentStyleFiles : filesToTreatByCommentStyle.entrySet() ) { String commentStyle = commentStyleFiles.getKey(); List files = commentStyleFiles.getValue(); processCommentStyle( commentStyle, files ); } } finally { 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( result, state, buffer ); } getLog().info( buffer.toString() ); } } } private boolean isDryRun() { return dryRun; } /** * 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 */ private 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 FileHeaderTransformer transformer = getTransformer( transformers, commentStyle ); for ( File file : filesToTreat ) { processFile( transformer, file ); } filesToTreat.clear(); } private boolean processFile( FileHeaderTransformer transformer, File file, File processFile ) throws IOException { String content; try { 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; } String commentStartTag = transformer.getCommentStartTag(); int firstIndex = content.indexOf( commentStartTag ); if ( firstIndex == -1 ) { FileState.uptodate.addFile( file, result ); return false; } char lastchar = ' '; while ( lastchar != '\n' && firstIndex > 0 ) { lastchar = content.charAt( ( --firstIndex ) ); } String commentEndTag = transformer.getCommentEndTag(); int lastIndex = content.indexOf( commentEndTag ); if ( lastIndex == -1 ) { FileState.uptodate.addFile( file, result ); return false; } lastchar = ' '; while ( lastchar != '\n' ) { lastchar = content.charAt( ( ++lastIndex ) ); } if ( isVerbose() ) { getLog().info( " - header was removed for " + file ); } String contentWithoutHeader = content.substring( 0, firstIndex ) + content.substring( lastIndex + 1 ); FileUtils.fileWrite( processFile, contentWithoutHeader ); FileState.remove.addFile( file, result ); return true; } /** * Process the given file (will copy it, process the clone file and finally finalizeFile after process)... * * @param transformer current file header transformer * @param file original file to process * @throws IOException if any IO error while processing this file */ private void processFile( FileHeaderTransformer transformer, 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( transformer, 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 { // whatever was the result, this file is treated. processedFiles.add( file ); if ( doFinalize ) { finalizeFile( file, processFile ); } else { FileUtil.deleteFile( processFile ); } } } /** * 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 */ private 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() ); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy