Package org.codehaus.mojo.exec

Source Code of org.codehaus.mojo.exec.ExecMojo

package org.codehaus.mojo.exec;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.ExecuteResultHandler;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.OS;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.exec.ShutdownHookProcessDestroyer;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
import org.apache.maven.artifact.resolver.filter.IncludesArtifactFilter;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.toolchain.Toolchain;
import org.apache.maven.toolchain.ToolchainManager;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.cli.CommandLineUtils;

/**
* A Plugin for executing external programs.
*
* @author Jerome Lacoste <jerome@coffeebreaks.org>
* @version $Id$
* @goal exec
* @requiresDependencyResolution test
* @since 1.0
*/
public class ExecMojo
    extends AbstractExecMojo
{
    /**
     * <p>
     * The executable. Can be a full path or a the name executable. In the latter case, the executable must be in the
     * PATH for the execution to work.
     * </p>
     * <p>
     * The plugin will search for the executable in the following order:
     * <ol>
     <li>relative to the root of the project</li>
     <li>as toolchain executable</li>
     <li>relative to the working directory (Windows only)</li>
     <li>relative to the directories specified in the system property PATH (Windows Only)</li>
     * </ol>
     * Otherwise use the executable as is.
     * </p>
     *
     * @parameter expression="${exec.executable}"
     * @required
     * @since 1.0
     */
    private String executable;

    /**
     * The current working directory. Optional. If not specified, basedir will be used.
     *
     * @parameter expression="${exec.workingdir}
     * @since 1.0
     */
    private File workingDirectory;

    /**
     * Program standard and error output will be redirected to the file specified by this optional field. If not
     * specified the standard maven logging is used.
     *
     * @parameter expression="${exec.outputFile}"
     * @since 1.1-beta-2
     */
    private File outputFile;

    /**
     * <p>
     *   A list of arguments passed to the {@code executable},
     *   which should be of type <code>&lt;argument&gt;</code> or <code>&lt;classpath&gt;</code>.
     *   Can be overridden by using the <code>exec.args</code> environment variable.
     * </p>
     *
     * @parameter
     * @since 1.0
     */
    private List arguments;

    /**
     * @parameter default-value="${basedir}"
     * @required
     * @readonly
     * @since 1.0
     */
    private File basedir;

    /**
     * Environment variables to pass to the executed program.
     *
     * @parameter
     * @since 1.1-beta-2
     */
    private Map environmentVariables = new HashMap();

    /**
     * The current build session instance. This is used for toolchain manager API calls.
     *
     * @parameter default-value="${session}"
     * @required
     * @readonly
     */
    private MavenSession session;

    /**
     * Exit codes to be resolved as successful execution for non-compliant applications (applications not returning 0
     * for success).
     *
     * @parameter
     * @since 1.1.1
     */
    private int[] successCodes;

    /**
     * If set to true the classpath and the main class will be written to a MANIFEST.MF file and wrapped into a jar.
     * Instead of '-classpath/-cp CLASSPATH mainClass' the exec plugin executes '-jar maven-exec.jar'.
     *
     * @parameter expression="${exec.longClasspath}" default-value="false"
     * @since 1.1.2
     */
    private boolean longClasspath;

    /**
     * If set to true, the process will be forked (i.e. started in the background).
     *
     * @parameter expression="${exec.background}" default-value="false"
     * @since 1.2.1.jbossorg-1
     */
    private boolean background;

    /**
     * Only applies if background=true. If set, block until able to connect to the specified address or 60 seconds elapses.
     *
     * @parameter expression="${exec.backgroundPollingAddress}"
     * @since 1.2.1.jbossorg-1
     */
    private String backgroundPollingAddress;

    /**
     * Only applies if background=true. Poll the backgroundPollingAddress for this many seconds before failing with
     * an exception.
     *
     * @parameter expression="${exec.backgroundPollingTimeout}" default-value="60"
     * @since 1.2.1.jbossorg-1
     */
    private int backgroundPollingTimeout = 60;

    public static final String CLASSPATH_TOKEN = "%classpath";

    /**
     * priority in the execute method will be to use System properties arguments over the pom specification.
     *
     * @throws MojoExecutionException if a failure happens
     */
    public void execute()
        throws MojoExecutionException
    {
        try
        {
            if ( isSkip() )
            {
                getLog().info( "skipping execute as per configuration" );
                return;
            }

            if ( basedir == null )
            {
                throw new IllegalStateException( "basedir is null. Should not be possible." );
            }

            String argsProp = getSystemProperty( "exec.args" );

            List commandArguments = new ArrayList();

            if ( hasCommandlineArgs() )
            {
                String[] args = parseCommandlineArgs();
                for ( int i = 0; i < args.length; i++ )
                {
                    if ( isLongClassPathArgument( args[i] ) )
                    {
                        // it is assumed that starting from -cp or -classpath the arguments
                        // are: -classpath/-cp %classpath mainClass
                        // the arguments are replaced with: -jar $TMP/maven-exec.jar
                        // NOTE: the jar will contain the classpath and the main class
                        commandArguments.add( "-jar" );
                        File tmpFile = createJar( computeClasspath( null ), args[i + 2] );
                        commandArguments.add( tmpFile.getAbsolutePath() );
                        i += 2;
                    }
                    else if ( CLASSPATH_TOKEN.equals( args[i] ) )
                    {
                        commandArguments.add( computeClasspathString( null ) );
                    }
                    else
                    {
                        commandArguments.add( args[i] );
                    }
                }
            }
            else if ( !StringUtils.isEmpty( argsProp ) )
            {
                getLog().debug( "got arguments from system properties: " + argsProp );

                try
                {
                    String[] args = CommandLineUtils.translateCommandline( argsProp );
                    commandArguments.addAll( Arrays.asList( args ) );
                }
                catch ( Exception e )
                {
                    throw new MojoExecutionException( "Couldn't parse systemproperty 'exec.args'" );
                }
            }
            else
            {
                if ( arguments != null )
                {
                    for ( int i = 0; i < arguments.size(); i++ )
                    {
                        Object argument = arguments.get( i );
                        String arg;
                        if ( argument == null )
                        {
                            throw new MojoExecutionException( "Misconfigured argument, value is null. "
                                + "Set the argument to an empty value if this is the required behaviour." );
                        }
                        else if ( argument instanceof String && isLongClassPathArgument( (String) argument ) )
                        {
                            // it is assumed that starting from -cp or -classpath the arguments
                            // are: -classpath/-cp %classpath mainClass
                            // the arguments are replaced with: -jar $TMP/maven-exec.jar
                            // NOTE: the jar will contain the classpath and the main class
                            commandArguments.add( "-jar" );
                            File tmpFile =
                                createJar( computeClasspath( (Classpath) arguments.get( i + 1 ) ),
                                           (String) arguments.get( i + 2 ) );
                            commandArguments.add( tmpFile.getAbsolutePath() );
                            i += 2;
                        }
                        else if ( argument instanceof Classpath )
                        {
                            Classpath specifiedClasspath = (Classpath) argument;

                            arg = computeClasspathString( specifiedClasspath );
                            commandArguments.add( arg );
                        }
                        else
                        {
                            arg = argument.toString();
                            commandArguments.add( arg );
                        }
                    }
                }
            }

            Map enviro = new HashMap();
            try
            {
                Properties systemEnvVars = CommandLineUtils.getSystemEnvVars();
                enviro.putAll( systemEnvVars );
            }
            catch ( IOException x )
            {
                getLog().error( "Could not assign default system environment variables.", x );
            }

            if ( environmentVariables != null )
            {
                Iterator iter = environmentVariables.keySet().iterator();
                while ( iter.hasNext() )
                {
                    String key = (String) iter.next();
                    String value = (String) environmentVariables.get( key );
                    enviro.put( key, value );
                }
            }

            if ( workingDirectory == null )
            {
                workingDirectory = basedir;
            }

            if ( !workingDirectory.exists() )
            {
                getLog().debug( "Making working directory '" + workingDirectory.getAbsolutePath() + "'." );
                if ( !workingDirectory.mkdirs() )
                {
                    throw new MojoExecutionException( "Could not make working directory: '"
                        + workingDirectory.getAbsolutePath() + "'" );
                }
            }

            CommandLine commandLine = getExecutablePath( enviro, workingDirectory );

            Executor exec = new DefaultExecutor();

            String[] args = new String[commandArguments.size()];
            for ( int i = 0; i < commandArguments.size(); i++ )
            {
                args[i] = (String) commandArguments.get( i );
            }

            commandLine.addArguments( args, false );

            exec.setWorkingDirectory( workingDirectory );

            fillSuccessCodes(exec);
           
            // this code ensures the output gets logged vai maven logging, but at the same time prevents
            // partial line output, like input prompts.
            // final Log outputLog = getExecOutputLog();
            // LogOutputStream stdout = new LogOutputStream()
            // {
            // protected void processLine( String line, int level )
            // {
            // outputLog.info( line );
            // }
            // };
            //
            // LogOutputStream stderr = new LogOutputStream()
            // {
            // protected void processLine( String line, int level )
            // {
            // outputLog.info( line );
            // }
            // };
            OutputStream stdout = System.out;
            OutputStream stderr = System.err;

            try
            {
                if ( background )
                {
                    getLog().debug( "Executing command line in background: " + commandLine );

                    executeCommandLineInBackground( exec, commandLine, enviro, stdout, stderr );
                }
                else
                {
                    getLog().debug( "Executing command line: " + commandLine );

                    int resultCode = executeCommandLine( exec, commandLine, enviro, stdout, stderr );

                    if ( isResultCodeAFailure( resultCode ) )
                    {
                        throw new MojoExecutionException( "Result of " + commandLine + " execution is: '" + resultCode
                            + "'." );
                    }
                }
            }
            catch ( ExecuteException e )
            {
                throw new MojoExecutionException( "Command execution failed.", e );
            }
            catch ( IOException e )
            {
                throw new MojoExecutionException( "Command execution failed.", e );
            }

            registerSourceRoots();
        }
        catch ( IOException e )
        {
            throw new MojoExecutionException( "I/O Error", e );
        }
    }

    private void fillSuccessCodes( Executor exec )
    {
        if ( successCodes != null && successCodes.length > 0 )
        {
            exec.setExitValues( successCodes );
        }
    }

    boolean isResultCodeAFailure( int result )
    {
        if ( successCodes == null || successCodes.length == 0 )
        {
            return result != 0;
        }
        for ( int index = 0; index < successCodes.length; index++ )
        {
            if ( successCodes[index] == result )
            {
                return false;
            }
        }
        return true;
    }

    private boolean isLongClassPathArgument( String arg )
    {
        return longClasspath && ( "-classpath".equals( arg ) || "-cp".equals( arg ) );
    }

    private Log getExecOutputLog()
    {
        Log log = getLog();
        if ( outputFile != null )
        {
            try
            {
                if ( !outputFile.getParentFile().exists() && !outputFile.getParentFile().mkdirs() )
                {
                    getLog().warn( "Could not create non existing parent directories for log file: " + outputFile );
                }
                PrintStream stream = new PrintStream( new FileOutputStream( outputFile ) );

                log = new StreamLog( stream );
            }
            catch ( Exception e )
            {
                getLog().warn( "Could not open " + outputFile + ". Using default log", e );
            }
        }

        return log;
    }

    /**
     * Compute the classpath from the specified Classpath. The computed classpath is based on the classpathScope. The
     * plugin cannot know from maven the phase it is executed in. So we have to depend on the user to tell us he wants
     * the scope in which the plugin is expected to be executed.
     *
     * @param specifiedClasspath Non null when the user restricted the dependencies,
     *   <code>null</code> otherwise (the default classpath will be used)
     * @return a platform specific String representation of the classpath
     */
    private String computeClasspathString( Classpath specifiedClasspath )
    {
        List resultList = computeClasspath( specifiedClasspath );
        StringBuffer theClasspath = new StringBuffer();

        for ( Iterator it = resultList.iterator(); it.hasNext(); )
        {
            String str = (String) it.next();
            addToClasspath( theClasspath, str );
        }

        return theClasspath.toString();
    }

    /**
     * Compute the classpath from the specified Classpath. The computed classpath is based on the classpathScope. The
     * plugin cannot know from maven the phase it is executed in. So we have to depend on the user to tell us he wants
     * the scope in which the plugin is expected to be executed.
     *
     * @param specifiedClasspath Non null when the user restricted the dependencies, <code>null</code>
     *    otherwise (the default classpath will be used)
     * @return a list of class path elements
     */
    private List computeClasspath( Classpath specifiedClasspath )
    {
        List artifacts = new ArrayList();
        List theClasspathFiles = new ArrayList();
        List resultList = new ArrayList();

        collectProjectArtifactsAndClasspath( artifacts, theClasspathFiles );

        if ( ( specifiedClasspath != null ) && ( specifiedClasspath.getDependencies() != null ) )
        {
            artifacts = filterArtifacts( artifacts, specifiedClasspath.getDependencies() );
        }

        for ( Iterator it = theClasspathFiles.iterator(); it.hasNext(); )
        {
            File f = (File) it.next();
            resultList.add( f.getAbsolutePath() );
        }

        for ( Iterator it = artifacts.iterator(); it.hasNext(); )
        {
            Artifact artifact = (Artifact) it.next();
            getLog().debug( "dealing with " + artifact );
            resultList.add( artifact.getFile().getAbsolutePath() );
        }

        return resultList;
    }

    private static void addToClasspath( StringBuffer theClasspath, String toAdd )
    {
        if ( theClasspath.length() > 0 )
        {
            theClasspath.append( File.pathSeparator );
        }
        theClasspath.append( toAdd );
    }

    private List filterArtifacts( List artifacts, Collection dependencies )
    {
        AndArtifactFilter filter = new AndArtifactFilter();

        filter.add( new IncludesArtifactFilter( new ArrayList( dependencies ) ) ); // gosh

        List filteredArtifacts = new ArrayList();
        for ( Iterator it = artifacts.iterator(); it.hasNext(); )
        {
            Artifact artifact = (Artifact) it.next();
            if ( filter.include( artifact ) )
            {
                getLog().debug( "filtering in " + artifact );
                filteredArtifacts.add( artifact );
            }
        }
        return filteredArtifacts;
    }

    CommandLine getExecutablePath( Map enviro, File dir )
    {
        File execFile = new File( executable );
        String exec = null;
        if ( execFile.isFile() )
        {
            getLog().debug( "Toolchains are ignored, 'executable' parameter is set to " + executable );
            exec = execFile.getAbsolutePath();
        }
       
        if ( exec == null )
        {
            Toolchain tc = getToolchain();

            // if the file doesn't exist & toolchain is null, the exec is probably in the PATH...
            // we should probably also test for isFile and canExecute, but the second one is only
            // available in SDK 6.
            if ( tc != null )
            {
                getLog().info( "Toolchain in exec-maven-plugin: " + tc );
                exec = tc.findTool( executable );
            }
            else
            {
                if ( OS.isFamilyWindows() )
                {
                    String ex = executable.indexOf( "." ) < 0 ? executable + ".bat" : executable;
                    File f = new File( dir, ex );
                    if ( f.isFile() )
                    {
                        exec = ex;
                    }
                   
                    if ( exec == null )
                    {
                        // now try to figure the path from PATH, PATHEXT env vars
                        // if bat file, wrap in cmd /c
                        String path = (String) enviro.get( "PATH" );
                        if ( path != null )
                        {
                            String[] elems = StringUtils.split( path, File.pathSeparator );
                            for ( int i = 0; i < elems.length; i++ )
                            {
                                f = new File( new File( elems[i] ), ex );
                                if ( f.isFile() )
                                {
                                    exec = ex;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

        if ( exec == null )
        {
            exec = executable;
        }

        CommandLine toRet;
        if ( OS.isFamilyWindows() && exec.toLowerCase( Locale.getDefault() ).endsWith( ".bat" ) )
        {
            toRet = new CommandLine( "cmd" );
            toRet.addArgument( "/c" );
            toRet.addArgument( exec );
        }
        else
        {
            toRet = new CommandLine( exec );
        }

        return toRet;
    }

    // private String[] DEFAULT_PATH_EXT = new String[] {
    // .COM; .EXE; .BAT; .CMD; .VBS; .VBE; .JS; .JSE; .WSF; .WSH
    // ".COM", ".EXE", ".BAT", ".CMD"
    // };

    //
    // methods used for tests purposes - allow mocking and simulate automatic setters
    //

    protected int executeCommandLine( Executor exec, CommandLine commandLine, Map enviro, OutputStream out,
                                      OutputStream err )
        throws ExecuteException, IOException
    {
        exec.setStreamHandler( new PumpStreamHandler( out, err, System.in ) );
        return exec.execute( commandLine, enviro );
    }

    protected void executeCommandLineInBackground( Executor exec, final CommandLine commandLine, Map enviro,
                                                   OutputStream out, OutputStream err )
            throws ExecuteException, IOException, MojoExecutionException
    {
        ExecuteResultHandler resultHandler = new ExecuteResultHandler( )
        {
            public void onProcessComplete( int resultCode )
            {
                if ( isResultCodeAFailure( resultCode ) )
                {
                    getLog( ).error( "Background process with command line [" + commandLine + "] failed with exit code "
                            + resultCode + "." );
                }
                else
                {
                    getLog( ).info( "Background process with command line [" + commandLine + "] completed with exit code "
                            + resultCode + "." );
                }
            }

            public void onProcessFailed( ExecuteException e )
            {
                getLog( ).error( "An error occurred executing background process with command line [" + commandLine
                        + "].", e );
            }
        };
        exec.setStreamHandler( new PumpStreamHandler( out, err, System.in ) );
        // Kill the process when this JVM exits.
        exec.setProcessDestroyer( new ShutdownHookProcessDestroyer( ) );
        exec.execute( commandLine, enviro, resultHandler );

        if ( backgroundPollingAddress != null )
        {
            int colonIndex = backgroundPollingAddress.lastIndexOf( ':' );
            if ( colonIndex == -1 )
            {
                throw new IllegalStateException( "backgroundBlockingAddress has an illegal value - it should be host:port." );
            }
            String host = backgroundPollingAddress.substring( 0, colonIndex );
            int port = Integer.valueOf( backgroundPollingAddress.substring( colonIndex + 1 ) ).intValue();

            getLog( ).info( "Attempting to connect to " + backgroundPollingAddress + " - will timeout after "
                    + backgroundPollingTimeout + " seconds." );

            InetAddress address = InetAddress.getByName( host );
            InetSocketAddress socketAddress = new InetSocketAddress( address, port );
            int pollingTimeoutMillis = backgroundPollingTimeout * 1000;
            boolean connected = pollSocketAddress( socketAddress, pollingTimeoutMillis );

            if ( connected )
            {
                getLog( ).info( "Connected to " + backgroundPollingAddress + " - assuming process with command line ["
                        + commandLine + "] has fully started." );
            }
            else
            {
                throw new MojoExecutionException( "Failed to connect to " + backgroundPollingAddress
                        + " within " + backgroundPollingTimeout + " seconds." );
            }
        }
    }

    private boolean pollSocketAddress( SocketAddress address, int timeout )
    {
        long startTime = System.currentTimeMillis( );
        boolean connected = false;
        while ( ( System.currentTimeMillis( ) - startTime ) < timeout )
        {
            Socket socket = new Socket( );
            try
            {
                getLog( ).debug( "Attempting to connect to " + address + "..." );
                socket.setReuseAddress( true );
                socket.connect( address, 3000 );
                connected = true;
                try
                {
                    socket.close( );
                    getLog( ).debug( "Closed connection to " + address + "." );
                }
                catch ( IOException e )
                {
                    getLog( ).debug( "Failed to close connection to " + address + ": " + e );
                }
                break;
            }
            catch ( IOException e )
            {
                getLog( ).error( "Failed to connect to " + address + ": " + e );
                try
                {
                    Thread.sleep( 3000 );
                }
                catch ( InterruptedException e1 )
                {
                    // ignore
                }
            }
        }
        return connected;
    }

    void setExecutable( String executable )
    {
        this.executable = executable;
    }

    String getExecutable()
    {
        return executable;
    }

    void setWorkingDirectory( String workingDir )
    {
        setWorkingDirectory( new File( workingDir ) );
    }

    void setWorkingDirectory( File workingDir )
    {
        this.workingDirectory = workingDir;
    }

    void setArguments( List arguments )
    {
        this.arguments = arguments;
    }

    void setBasedir( File basedir )
    {
        this.basedir = basedir;
    }

    void setProject( MavenProject project )
    {
        this.project = project;
    }

    protected String getSystemProperty( String key )
    {
        return System.getProperty( key );
    }

    public void setSuccessCodes( Integer[] list )
    {
        this.successCodes = new int[list.length];
        for ( int index = 0; index < list.length; index++ )
        {
            successCodes[index] = list[index].intValue();
        }
    }

    public int[] getSuccessCodes()
    {
        return successCodes;
    }

    public boolean isBackground() {
        return background;
    }

    public void setBackground(boolean background) {
        this.background = background;
    }

    public String getBackgroundPollingAddress() {
        return backgroundPollingAddress;
    }

    public void setBackgroundPollingAddress(String backgroundPollingAddress) {
        this.backgroundPollingAddress = backgroundPollingAddress;
    }

    public int getBackgroundPollingTimeout() {
        return backgroundPollingTimeout;
    }

    public void setBackgroundPollingTimeout(int backgroundPollingTimeout) {
        if (backgroundPollingTimeout < 0) {
            throw new IllegalArgumentException("backgroundPollingTimeout cannot be negative.");
        }
        this.backgroundPollingTimeout = (backgroundPollingTimeout > 0) ? backgroundPollingTimeout : Integer.MAX_VALUE;
    }

    private Toolchain getToolchain()
    {
        Toolchain tc = null;

        try
        {
            if ( session != null ) // session is null in tests..
            {
                ToolchainManager toolchainManager =
                    (ToolchainManager) session.getContainer().lookup( ToolchainManager.ROLE );

                if ( toolchainManager != null )
                {
                    tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
                }
            }
        }
        catch ( ComponentLookupException componentLookupException )
        {
            // just ignore, could happen in pre-2.0.9 builds..
        }
        return tc;
    }

    /**
     * Create a jar with just a manifest containing a Main-Class entry for SurefireBooter and a Class-Path entry for all
     * classpath elements. Copied from surefire (ForkConfiguration#createJar())
     *
     * @param classPath List&lt;String> of all classpath elements.
     * @return
     * @throws IOException
     */
    private File createJar( List classPath, String mainClass )
        throws IOException
    {
        File file = File.createTempFile( "maven-exec", ".jar" );
        file.deleteOnExit();
        FileOutputStream fos = new FileOutputStream( file );
        JarOutputStream jos = new JarOutputStream( fos );
        jos.setLevel( JarOutputStream.STORED );
        JarEntry je = new JarEntry( "META-INF/MANIFEST.MF" );
        jos.putNextEntry( je );

        Manifest man = new Manifest();

        // we can't use StringUtils.join here since we need to add a '/' to
        // the end of directory entries - otherwise the jvm will ignore them.
        String cp = "";
        for ( Iterator it = classPath.iterator(); it.hasNext(); )
        {
            String el = (String) it.next();
            // NOTE: if File points to a directory, this entry MUST end in '/'.
            cp += UrlUtils.getURL( new File( el ) ).toExternalForm() + " ";
        }

        man.getMainAttributes().putValue( "Manifest-Version", "1.0" );
        man.getMainAttributes().putValue( "Class-Path", cp.trim() );
        man.getMainAttributes().putValue( "Main-Class", mainClass );

        man.write( jos );
        jos.close();

        return file;
    }
}
TOP

Related Classes of org.codehaus.mojo.exec.ExecMojo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.