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

org.codehaus.mojo.unix.maven.MojoHelper Maven / Gradle / Ivy

package org.codehaus.mojo.unix.maven;

/*
 * The MIT License
 *
 * Copyright 2009 The Codehaus.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

import fj.*;
import static fj.Function.*;
import static fj.Ord.*;
import static fj.P.*;
import fj.data.List;
import static fj.data.List.join;
import static fj.data.List.*;
import static fj.data.List.single;
import fj.data.*;
import static fj.data.Option.*;
import fj.data.Set;
import static fj.data.Set.*;
import static java.lang.String.*;
import org.apache.commons.logging.*;
import org.apache.commons.vfs.*;
import org.apache.maven.artifact.*;
import org.apache.maven.plugin.*;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.*;
import org.codehaus.mojo.unix.*;
import static org.codehaus.mojo.unix.PackageParameters.*;
import org.codehaus.mojo.unix.core.*;
import org.codehaus.mojo.unix.java.*;
import static org.codehaus.mojo.unix.java.StringF.*;
import org.codehaus.mojo.unix.maven.logging.*;
import org.codehaus.mojo.unix.maven.plugin.*;
import org.codehaus.mojo.unix.maven.plugin.Package;
import static org.codehaus.mojo.unix.util.FileModulator.*;
import org.codehaus.mojo.unix.util.*;
import org.codehaus.mojo.unix.util.line.*;

import java.io.*;
import java.text.*;
import java.util.*;
import java.util.TreeMap;

/**
 * Utility class encapsulating how to create a package. Used by all packaging Mojos.
 *
 * @author Trygve Laugstøl
 */
public abstract class MojoHelper
{
    public static final String ATTACHED_NO_ARTIFACTS_CONFIGURED = "When running in attached mode at least one package has to be configured.";
    public static final String DUPLICATE_CLASSIFIER = "Duplicate package classifier: '%s'.";
    public static final String DUPLICATE_UNCLASSIFIED = "There can only be one package without an classifier.";

    public static Execution create( Map platforms,
                                    String platformType,
                                    Map formats,
                                    String formatType,
                                    MavenProjectWrapper project,
                                    boolean debug,
                                    boolean attachedMode,
                                    F validateMojoSettingsAndApplyFormatSpecificSettingsToPackage,
                                    PackagingMojoParameters mojoParameters,
                                    final Log log )
        throws MojoFailureException, MojoExecutionException
    {
        MavenCommonLoggingLogFactory.setMavenLogger( log );

        PackagingFormat format = (PackagingFormat) formats.get( formatType );

        if ( format == null )
        {
            throw new MojoFailureException( "INTERNAL ERROR: could not find format: '" + formatType + "'." );
        }

        UnixPlatform platform = (UnixPlatform) platforms.get( platformType );

        if ( platform == null )
        {
            throw new MojoFailureException( "INTERNAL ERROR: could not find platform: '" + platformType + "'." );
        }

        /*
        // TODO: This is using a private Maven API that might change. Perhaps use some reflection magic here.
        String timestamp = snapshotTransformation.getDeploymentTimestamp();
        */

        // This chunk replaces the above getDeploymentTimestamp. However, it not ensure that all files get the
        // same timestamp. Need to look into how this is done with Maven 3
        DateFormat utcDateFormatter = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
        utcDateFormatter.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
        String timestamp = utcDateFormatter.format( new Date() );

        FileObject buildDirectory;

        try
        {
            FileSystemManager fileSystemManager = VFS.getManager();

            buildDirectory = fileSystemManager.resolveFile( project.buildDirectory.getAbsolutePath() );
        }
        catch ( FileSystemException e )
        {
            throw new MojoExecutionException( "Error while initializing Commons VFS", e );
        }

        PackageVersion version = PackageVersion.packageVersion( project.version, timestamp,
                                                                project.artifact.isSnapshot(), mojoParameters.revision );

        List>> packages = nil();

        for ( Package pakke : validatePackages( mojoParameters.packages, attachedMode ) )
        {
            try
            {
                String name = "unix/root-" + formatType + pakke.classifier.map( dashString ).orSome( "" );

                FileObject packageRoot = buildDirectory.resolveFile( name );
                packageRoot.createFolder();

                PackageParameters parameters = calculatePackageParameters( project,
                                                                           version,
                                                                           platform,
                                                                           mojoParameters,
                                                                           pakke );

                UnixPackage unixPackage = format.start().
                    parameters( parameters ).
                    setVersion( version ).                      // TODO: This should go away
                    workingDirectory( packageRoot ).
                    debug( debug ).
                    basedir( project.basedir );

                // -----------------------------------------------------------------------
                // Let the implementation add its metadata
                // -----------------------------------------------------------------------

                unixPackage = validateMojoSettingsAndApplyFormatSpecificSettingsToPackage.f( unixPackage );

                // TODO: here the logic should be different if many packages are to be created.
                // Example: name should be taken from mojoParameters if there is only a single package, if not
                //          it should come from the Pakke object. This should also be validated, at least for
                //          name

                List assemblyOperations = createAssemblyOperations( project,
                                                                                       parameters,
                                                                                       unixPackage,
                                                                                       project.basedir,
                                                                                       buildDirectory,
                                                                                       mojoParameters.assembly,
                                                                                       pakke.assembly );

                // -----------------------------------------------------------------------
                // Dump the execution
                // -----------------------------------------------------------------------

                if ( debug )
                {
                    log.info( "=======================================================================" );
                    log.info( "Package parameters: " + parameters.id );
                    log.info( "Default file attributes: " );
                    log.info( " File      : " + parameters.defaultFileAttributes );
                    log.info( " Directory : " + parameters.defaultDirectoryAttributes );

                    log.info( "Assembly operations: " );
                    for ( AssemblyOperation operation : assemblyOperations )
                    {
                        operation.streamTo( new AbstractLineStreamWriter()
                        {
                            protected void onLine( String line )
                            {
                                log.info( line );
                            }
                        } );
                    }
                }

                packages = packages.cons( p( unixPackage, pakke, assemblyOperations ) );
            }
            catch ( UnknownArtifactException e )
            {
                Map map = new TreeMap( e.artifactMap );

                // TODO: Do not log here, throw a CouldNotFindArtifactException with the map as an argument
                log.warn( "Could not find artifact:" + e.artifact );
                log.warn( "Available artifacts:" );
                for ( Object o : map.keySet() )
                {
                    log.warn( o.toString() );
                }

                throw new MojoFailureException( "Unable to find artifact: '" + e.artifact + "'. See log for available artifacts." );
            }
            catch ( MissingSettingException e )
            {
                String msg = "Missing required setting '" + e.getSetting() + "'";
                if ( !pakke.classifier.isNone() )
                {
                    msg += ", for '" + pakke.classifier.some() + "'";
                }
                msg += ", format '" + formatType + "'.";
                throw new MojoFailureException( msg );
            }
            catch ( IOException e )
            {
                throw new MojoExecutionException( "Error creating package " + (pakke.classifier.isSome() ? "classifier '" + pakke.classifier + "'" : "") + ", format '" + formatType + "'.", e );
            }
        }

        return new Execution( packages, project, formatType, attachedMode );
    }

    public static class Execution
    {
        private final List>> packages;

        private final MavenProjectWrapper project;

        private final String formatType;

        private final boolean attachedMode;

        public Execution( List>> packages, MavenProjectWrapper project,
                          String formatType, boolean attachedMode )
        {
            this.packages = packages;
            this.project = project;
            this.formatType = formatType;
            this.attachedMode = attachedMode;
        }

        public void execute( String artifactType, MavenProject mavenProject, MavenProjectHelper mavenProjectHelper, ScriptUtil.Strategy strategy )
            throws MojoExecutionException, MojoFailureException
        {
            // Save and restore the system property for commons logging.
            String key = LogFactory.class.getName();
            String value = System.getProperty( key );

            System.setProperty( key, MavenCommonLoggingLogFactory.class.getName() );

            try
            {
                execute_( artifactType, mavenProject, mavenProjectHelper, strategy );
            }
            finally {
                if(value == null) {
                    System.getProperties().remove( key );
                }
                else {
                    System.setProperty( key, value );
                }
            }
        }

        private void execute_( String artifactType, MavenProject mavenProject, MavenProjectHelper mavenProjectHelper, ScriptUtil.Strategy strategy )
            throws MojoExecutionException, MojoFailureException
        {
            for ( P3> p : packages )
            {
                UnixPackage unixPackage = p._1();
                Package pakke = p._2();

                try
                {
                    // -----------------------------------------------------------------------
                    // Assemble all the files
                    // -----------------------------------------------------------------------

                    for ( AssemblyOperation assemblyOperation : p._3() )
                    {
                        assemblyOperation.perform( unixPackage );
                    }

                    // -----------------------------------------------------------------------
                    // Package the stuff
                    // -----------------------------------------------------------------------

                    String name = project.artifactId +
                        pakke.classifier.map( dashString ).orSome( "" ) +
                        "-" + unixPackage.getVersion().getMavenVersion() +
                        "." + unixPackage.getPackageFileExtension();

                    File packageFile = new File( project.buildDirectory, name );

                    unixPackage.
                        packageToFile( packageFile, strategy );

                    attach( pakke.classifier, artifactType, packageFile, mavenProject, mavenProjectHelper,
                            attachedMode );
                }
                catch ( MojoExecutionException e )
                {
                    throw e;
                }
                catch ( MojoFailureException e )
                {
                    throw e;
                }
                catch ( Exception e )
                {
                    throw new MojoExecutionException( "Unable to create package.", e );
                }
            }
        }

        private void attach( Option classifier, String artifactType, File packageFile,
                             MavenProject project, MavenProjectHelper mavenProjectHelper, boolean attachedMode )
        {
            if ( attachedMode )
            {
                // In attached mode all the packages are required to have an classifier - this used to be correct - trygve
                // For some reason it is allowed to have attached artifacts without classifier as long as the types differ

                if ( classifier.isSome() )
                {
                    mavenProjectHelper.attachArtifact( project, artifactType, classifier.some(), packageFile );
                }
                else
                {
                    mavenProjectHelper.attachArtifact( project, artifactType, null, packageFile );
                }
            }
            else
            {
                if ( classifier.isNone() )
                {
                    project.getArtifact().setFile( packageFile );
                }
                else
                {
                    mavenProjectHelper.attachArtifact( project, formatType, classifier.some(), packageFile );
                }
            }
        }
    }

    public static PackageParameters calculatePackageParameters( final MavenProjectWrapper project,
                                                                PackageVersion version,
                                                                UnixPlatform platform,
                                                                PackagingMojoParameters mojoParameters,
                                                                final Package pakke )
    {
        String id = pakke.id.orSome( new P1()
        {
            public String _1()
            {
                // This used to be ${groupId}-${artifactId}, but it was too long for pkg so this is a more sane default
                return project.artifactId + pakke.classifier.map( dashString ).orSome( "" );
            }
        } );

        P2 defaultFileAttributes =
            calculateDefaultFileAttributes( platform,
                                            mojoParameters.defaults,
                                            pakke.defaults );

        String name = pakke.name.orElse( mojoParameters.name ).orSome( project.name );
        return packageParameters( project.groupId, project.artifactId, version, id, name, pakke.classifier, defaultFileAttributes._1(), defaultFileAttributes._2() ).
            description( pakke.description.orElse( mojoParameters.description ).orElse( project.description ) ).
            contact( mojoParameters.contact ).
            contactEmail( mojoParameters.contactEmail ).
            license( getLicense( project ) ).
            architecture( pakke.architecture.orElse( mojoParameters.architecture ) );
    }

    public static P2 calculateDefaultFileAttributes( UnixPlatform platform,
                                                                                     Defaults mojo,
                                                                                     Defaults pakke )
    {
        return p( calculateFileAttributes( platform.getDefaultFileAttributes(),
                                          mojo.fileAttributes.create(),
                                          pakke.fileAttributes.create() ),
                 calculateFileAttributes( platform.getDefaultDirectoryAttributes(),
                                          mojo.directoryAttributes.create(),
                                          pakke.directoryAttributes.create() ) );
    }

    public static FileAttributes calculateFileAttributes( FileAttributes platform,
                                                          FileAttributes mojo,
                                                          FileAttributes pakke )
    {
        // Calculate default file and directory attributes.
        // Priority order (last one wins): platform -> mojo defaults -> package defaults

        return platform.
            useAsDefaultsFor( mojo ).
            useAsDefaultsFor( pakke );
    }

    public static List createAssemblyOperations( MavenProjectWrapper project,
                                                                    PackageParameters parameters,
                                                                    UnixPackage unixPackage,
                                                                    File basedir,
                                                                    FileObject buildDirectory,
                                                                    List mojoAssembly,
                                                                    List packageAssembly )
        throws IOException, MojoFailureException, UnknownArtifactException
    {
        unixPackage.beforeAssembly( parameters.defaultDirectoryAttributes );

        // Create the default set of assembly operations
        String unix = new File( basedir, "src/main/unix/files" ).getAbsolutePath();

        String classifierOrDefault = parameters.classifier.orSome( "default" );

        List defaultAssemblyOp = nil();

        // It would be possible to use the AssemblyOperations here but this just make it easier to document
        // as it has a one-to-one relationship with what the user would configure in a POM
        for ( String s : modulatePath( classifierOrDefault, unixPackage.getPackageFileExtension(), unix ) )
        {
            File file = new File( s );

            if ( !file.isDirectory() )
            {
                continue;
            }

            CopyDirectory op = new CopyDirectory();
            op.setFrom( file );
            defaultAssemblyOp = defaultAssemblyOp.cons( op );
        }

        // Create the complete list of assembly operations.
        // Order: defaults -> mojo -> pakke
        List assemblyOps = join( list( defaultAssemblyOp.reverse(), mojoAssembly, packageAssembly ) );

        List operations = nil();

        for ( AssemblyOp assemblyOp : assemblyOps )
        {
            assemblyOp.setArtifactMap( project.artifactConflictIdMap );

            AssemblyOperation operation = assemblyOp.createOperation( buildDirectory,
                parameters.defaultFileAttributes,
                parameters.defaultDirectoryAttributes );

            operations = operations.cons( operation );
        }

        return operations.reverse();
    }

    public static List validatePackages( List packages, boolean attachedMode )
        throws MojoFailureException
    {
        if ( packages.isEmpty() )
        {
            packages = single( new Package() );
        }

        Set names = empty( stringOrd );
        List outPackages = nil();

        Option defaultPackage = none();

        for ( Package pakke : packages )
        {
            if ( pakke.classifier.exists( curry( StringF.equals, "default" ) ) )
            {
                pakke.classifier = none();
            }

            if ( pakke.classifier.isNone() )
            {
                if ( defaultPackage.isSome() )
                {
                    throw new MojoFailureException( DUPLICATE_UNCLASSIFIED );
                }

                defaultPackage = some( pakke );
            }
            else
            {
                if ( names.member( pakke.classifier.some() ) )
                {
                    throw new MojoFailureException( format( DUPLICATE_CLASSIFIER, pakke.classifier ) );
                }

                names = names.insert( pakke.classifier.some() );
                outPackages = outPackages.cons( pakke );
            }
        }

        if ( attachedMode )
        {
            outPackages = defaultPackage.toList().append( outPackages );

            if ( outPackages.isEmpty() )
            {
                throw new MojoFailureException( ATTACHED_NO_ARTIFACTS_CONFIGURED );
            }

            return outPackages;
        }

        if ( defaultPackage.isNone() )
        {
            throw new MojoFailureException( "When running in 'primary artifact mode' either one package has to have 'default' as classifier or there has to be one without any classifier." );
        }

        return defaultPackage.toList().append( outPackages );
    }

    private static Option getLicense( MavenProjectWrapper project )
    {
        if ( project.licenses.size() == 0 )
        {
            return none();
        }

        return some( project.licenses.get( 0 ).getName() );
    }

    static F dashString = curry( concat, "-" );
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy