Package org.apache.maven.cli

Source Code of org.apache.maven.cli.App

package org.apache.maven.cli;

/* ====================================================================
*   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 org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.ParseException;
import org.apache.commons.jelly.JellyException;
import org.apache.commons.jelly.XMLOutput;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.maven.MavenConstants;
import org.apache.maven.MavenException;
import org.apache.maven.MavenSession;
import org.apache.maven.MavenUtils;
import org.apache.maven.UnknownGoalException;
import org.apache.maven.jelly.MavenJellyContext;
import org.apache.maven.project.Project;
import org.apache.maven.verifier.ChecksumVerificationException;
import org.apache.maven.verifier.RepoConfigException;
import org.apache.maven.verifier.UnsatisfiedDependencyException;
import org.apache.maven.werkz.NoActionDefinitionException;
import org.apache.maven.werkz.NoSuchGoalException;
import org.apache.maven.werkz.UnattainableGoalException;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.BreakIterator;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;

/**
* The CLI wrapper for controlling MavenSession processes which are encapsulated in the MavenSession bean.
*
* @author <a href="mailto:jason@zenplex.com">Jason van Zyl</a>
*
* @version $Id: App.java 530196 2007-04-18 23:04:51Z aheritier $
*
* @todo Separate the computation of the available goals from the display of the goals. The goal computation logic needs
*       to be moved out of this class and be placed in MavenSession.java proper.
* @todo All logging needs to be done via commons-logging. No System.err.* and Jelly needs to be taught to take a
*       logger. In an attempt to isolate everything in MavenSession.java.
*/
public class App
{
    /** Default file name for an XML-based POM. */
    public static final String POM_FILE_NAME = "project.xml";

    /** Default console width - for formatting output. */
    private static final int CONSOLE_WIDTH = 80;

    /** Links properties */
    private static final Properties LINKS_PROPERTIES = new Properties();

    /** logger for output */
    private static final Log LOGGER = LogFactory.getLog( App.class );

    /** Convenience constant for new line character. */
    private static final String LS = System.getProperty( "line.separator", "\n" );

    /** Console banner option. */
    private static final String OPT_CONSOLE_BANNER = "b";

    /** Debug option. */
    private static final String OPT_DEBUG = "X";

    /** Display goals options. */
    private static final String OPT_DISPLAY_GOALS = "g";

    /** Display help option. */
    private static final String OPT_DISPLAY_HELP = "h";

    /** Display info option. */
    private static final String OPT_DISPLAY_INFO = "i";

    /** Display plugin help option. */
    private static final String OPT_DISPLAY_PLUGIN_HELP = "P";

    /** Display stack trace option. */
    private static final String OPT_DISPLAY_STACKTRACE = "e";

    /** Display project help option. */
    private static final String OPT_DISPLAY_USAGE = "u";

    /** Display version option. */
    private static final String OPT_DISPLAY_VERSION = "v";

    /** Emacs output option. */
    private static final String OPT_EMACS_OUTPUT = "E";

    /** Find POM option. */
    private static final String OPT_FIND_POM_DESCRIPTOR = "f";

    /** Quiet option. */
    private static final String OPT_QUIET = "q";

    /** Set POM descriptor option. */
    private static final String OPT_SET_POM_DESCRIPTOR = "p";

    /** System property option. */
    private static final String OPT_SET_SYSTEM_PROPERTY = "D";

    /** Work offline option. */
    private static final String OPT_WORK_OFFLINE = "o";

    /** Working dir option. */
    private static final String OPT_WORKING_DIR = "d";

    /** return code from command prompt when a bad argument is passed */
    private static final int RC_BAD_ARG = 10;

    /** return code for a failure due to Jelly issues */
    private static final int RC_BAD_JELLY = 80;

    /** return code for bad repository configuration */
    private static final int RC_BAD_REPO = 40;

    /** return code for a goal with no actions */
    private static final int RC_EMPTY_GOAL = 50;

    /** return code for a failure due to failed dependency */
    private static final int RC_FAILED_DEPENDENCY = 100;

    /** return code for a goal that failed */
    private static final int RC_GOAL_FAILED = 60;

    /** return code from command prompt when initialization fails */
    private static final int RC_INIT_ERROR = 20;

    /** return code for a goal failed from jelly exception being thrown */
    private static final int RC_JELLY_FAILED = 70;

    /** return code from command prompt when a goal isn't found */
    private static final int RC_NO_GOAL = 30;

    /** return code for ok processing */
    private static final int RC_OK = 0;

    /** return code for a failure due to anything else */
    private static final int RC_OTHER_FAILURE = 90;

    /** Default wrap indent. */
    private static final int WRAP_INDENT = 35;

    static
    {
        URL urlLog4j = App.class.getResource( "/log4j.properties" );

        if ( urlLog4j == null )
        {
            throw new RuntimeException( "Configuration error: can not find the resource log4j.properties" );
        }

        PropertyConfigurator.configure( urlLog4j );

        URL urlLinks = App.class.getResource( "/links.properties" );

        if ( urlLinks == null )
        {
            throw new RuntimeException( "Configuration error: can not find the resource links.properties" );
        }

        try
        {
            LINKS_PROPERTIES.load( urlLinks.openStream() );
        }
        catch ( IOException e )
        {
            throw new RuntimeException( "Configuration error: Unable to load the resource links.properties", e );
        }
    }

    /**
     * Main CLI entry point for MavenSession.
     *
     * @param args
     *            CLI arguments.
     */
    public static void main( String[] args )
    {
        Date start = new Date();
        App app = new App();
        app.doMain( args, start );
    }

    /**
     * Format a time string.
     *
     * @param ms
     *            Duration in ms.
     * @return String The formatted time string.
     */
    protected static String formatTime( long ms )
    {
        long secs = ms / 1000;
        long min = secs / 60;
        secs = secs % 60;

        if ( min > 0 )
        {
            return min + MavenUtils.getMessage( "formatTime.minutes" ) + secs
                            + MavenUtils.getMessage( "formatTime.seconds" );
        }
        else
        {
            return secs + MavenUtils.getMessage( "formatTime.seconds" );
        }
    }

    /** CLI Parser */
    private CommandLine commandLine;

    /** the session to run builds */
    private MavenSession mavenSession;

    /** MavenSession Jelly rootContext. */
    private MavenJellyContext rootContext;

    /** Jelly's underlying writer. */
    private Writer writer;

    /** Constructor. */
    public App()
    {
    }

    /**
     * Perform main operations in a non-static method.
     *
     * @param args
     *            Arguments passed in from main().
     * @param fullStart
     *            Date the mavenSession process was started.
     */
    public void doMain( String[] args, Date fullStart )
    {
        initializeMain( args );

        displayHelp();
        displayVersion();

        int returnCode = RC_OK;

        if ( !getCli().hasOption( OPT_CONSOLE_BANNER ) )
        {
            printConsoleMavenHeader();
        }

        if ( !MavenSession.getRootDescriptorFile().exists() )
        {
            LOGGER.warn( MavenUtils.getMessage( "build.no.pom.found" ) );
            LOGGER.warn( "" );
        }

        boolean failed = false;
        boolean displayStackTrace = getCli().hasOption( OPT_DISPLAY_STACKTRACE ) || getCli().hasOption( OPT_DEBUG );

        try
        {
            mavenSession.initialize();

            displayInfo();
            displayProjectHelp();
            displayPluginHelp();

            if ( getCli().hasOption( OPT_DISPLAY_GOALS ) )
            {
                displayGoals();
                exit( returnCode );
            }
            else
            {
                mavenSession.attainGoals( mavenSession.getRootProject(), getCli().getArgList() );
            }
        }
        catch ( UnsatisfiedDependencyException e )
        {
            failed = true;
            displayBuildFailed( e, false, true, displayStackTrace );
            returnCode = RC_FAILED_DEPENDENCY;
        }
        catch ( ChecksumVerificationException e )
        {
            failed = true;
            displayBuildFailed( e, false, true, displayStackTrace );
            returnCode = RC_FAILED_DEPENDENCY;
        }
        catch ( UnknownGoalException e )
        {
            failed = true;
            LOGGER.info( MavenUtils.getMessage( "line" ) );
            LOGGER.info( MavenUtils.getMessage( "build.unknownGoalException", e.getGoalName() ) );
            displayBuildFailed( e, false, false, displayStackTrace );
            returnCode = RC_NO_GOAL;
        }
        catch ( NoSuchGoalException e )
        {
            failed = true;
            displayBuildFailed( e, false, true, displayStackTrace );
            returnCode = RC_NO_GOAL;
        }
        catch ( RepoConfigException e )
        {
            failed = true;
            displayBuildFailed( e, false, true, displayStackTrace );
            returnCode = RC_BAD_REPO;
        }
        catch ( NoActionDefinitionException e )
        {
            failed = true;
            LOGGER.info( MavenUtils.getMessage( "line" ) );
            LOGGER.info( MavenUtils.getMessage( "build.internalError" ) );
            LOGGER.info( MavenUtils.getMessage( "build.noActionDefinitionException", e.getGoal().getName() ) );
            displayBuildFailed( e, true, false, displayStackTrace );
            returnCode = RC_EMPTY_GOAL;
        }
        catch ( UnattainableGoalException e )
        {
            failed = true;
            displayBuildFailed( e, false, true, displayStackTrace );
            if ( e.getCause() instanceof JellyException )
            {
                returnCode = RC_JELLY_FAILED;
            }
            else
            {
                returnCode = RC_GOAL_FAILED;
            }
        }
        catch ( JellyException e )
        {
            failed = true;
            displayBuildFailed( e, true, true, displayStackTrace );
            returnCode = RC_BAD_JELLY;
        }
        catch ( MavenException e )
        {
            failed = true;
            displayBuildFailed( e, MavenUtils.MAVEN_UNKNOWN_ERROR.equals( e.getMessage() ), true, displayStackTrace );
            returnCode = RC_OTHER_FAILURE;
        }
        catch ( Throwable t )
        {
            failed = true;
            displayBuildFailed( t, true, true, displayStackTrace );
            returnCode = RC_OTHER_FAILURE;
        }

        if ( !failed )
        {
            LOGGER.warn( MavenUtils.getMessage( "line" ) );
            LOGGER.warn( MavenUtils.getMessage( "build.successful" ) );
        }
        LOGGER.warn( MavenUtils.getMessage( "line" ) );
        Date fullStop = new Date();
        DateFormat defaultDate = DateFormat.getDateTimeInstance( DateFormat.FULL, DateFormat.LONG );
        long fullDiff = fullStop.getTime() - fullStart.getTime();
        LOGGER.warn( MavenUtils.getMessage( "build.total.time", formatTime( fullDiff ) ) );
        LOGGER.warn( MavenUtils.getMessage( "build.finished.time", defaultDate.format( fullStop ) ) );
        final long mb = 1024 * 1024;
        System.gc();
        Runtime r = Runtime.getRuntime();
        LOGGER.warn( MavenUtils.getMessage( "build.final.memory", ( ( r.totalMemory() - r.freeMemory() ) / mb ) + "M/"
                        + ( r.totalMemory() / mb ) + "M" ) );
        LOGGER.warn( MavenUtils.getMessage( "line" ) );
        exit( returnCode );
    }

    /**
     * Retrieve the Jelly rootContext.
     *
     * @return The Jelly rootContext.
     */
    public MavenJellyContext getRootContext()
    {
        return rootContext;
    }

    /**
     * Perform initialization.
     *
     * @param args
     *            The command-line arguments.
     *
     * @throws ParseException
     *             If there is an error parsing the command-line.
     * @throws IOException
     *             If there is an error while reading the project descriptor.
     * @throws MalformedURLException
     *             If any of the the URLs denoting the local or remote repositories is malformed.
     */
    public void initialize( String[] args ) throws ParseException, MalformedURLException, IOException
    {
        setCli( CLIManager.parse( args ) );

        initializeSystemProperties();
        initializeRootContext();
        initializeMavenSession();
        customizeLogging();
    }

    /**
     * Setup any system properties that have been specified on the CLI.
     */
    public void initializeSystemProperties()
    {
        if ( getCli().hasOption( OPT_SET_SYSTEM_PROPERTY ) )
        {
            String[] defStrs = getCli().getOptionValues( OPT_SET_SYSTEM_PROPERTY );

            for ( int i = 0; i < defStrs.length; ++i )
            {
                setCliProperty( defStrs[i] );
            }
        }
    }

    /**
     * Set Jelly rootContext.
     *
     * @param rootContext
     *            The mavenSession jelly rootContext.
     */
    public void setRootContext( MavenJellyContext rootContext )
    {
        this.rootContext = rootContext;
    }

    /**
     * Display helpful information regarding all documented goals.
     */
    protected void displayGoals()
    {
        displayGoals( false, null );
    }

    /**
     * Display helpful information regarding all documented goals.
     *
     * @param pluginOnly
     *            show information for the given plugin only
     * @param plugin
     *            plugin to show info for
     */
    protected void displayGoals( boolean pluginOnly, String plugin )
    {
        String title = MavenUtils.getMessage( "displayGoals.title" );
        if ( pluginOnly )
        {
            title =
                ( plugin == null ? MavenUtils.getMessage( "displayGoals.title.pluginOnly.null" )
                                : MavenUtils.getMessage( "displayGoals.title.pluginOnly.notNull" ) + plugin );
        }
        LOGGER.info( title );
        LOGGER.info( format( "", title.length(), '=' ) );

        Set goals = mavenSession.getAllGoalNames();
        displayGoals( pluginOnly, plugin, goals );
    }

    /**
     * To allow subclasses stop the app from exiting
     *
     * @param status
     *            the value to exit with
     */
    protected void exit( int status )
    {
        System.exit( status );
    }

    /**
     * Produce a formatted/padded string.
     *
     * @param orig
     *            The string to format.
     * @param width
     *            The width of the resulting formatted string.
     * @param pad
     *            The trailing pad character.
     *
     * @return The formatted string, or the original string if the length is already &gt;= <code>width</code>.
     */
    protected String format( String orig, int width, char pad )
    {
        if ( orig.length() >= width )
        {
            return orig;
        }

        StringBuffer buf = new StringBuffer().append( orig );

        int diff = width - orig.length();

        for ( int i = 0; i < diff; ++i )
        {
            buf.append( pad );
        }

        return buf.toString();
    }

    /**
     * Get the CLI parser.
     *
     * @return CommandLine The command line parser.
     */
    protected CommandLine getCli()
    {
        return this.commandLine;
    }

    /**
     * Initialize the IO streams.
     *
     * @throws IOException
     *             on error creating XML output and handling System.err and out
     */
    protected void initializeRootContext() throws IOException
    {
        this.writer = new OutputStreamWriter( System.out );
        XMLOutput output = XMLOutput.createXMLOutput( writer, false );

        if ( getCli().hasOption( OPT_WORKING_DIR ) )
        {
            String workingDir = getCli().getOptionValue( OPT_WORKING_DIR );
            File dir = new File( workingDir );
            if ( !dir.isAbsolute() )
            {
                workingDir = dir.getAbsolutePath();
            }

            System.setProperty( "user.dir", workingDir );
        }

        // We will assume here that there might not be a project.xml file present
        // and we will create the root context from the directory gleaned from
        // the user.dir system property.
        File basedir = new File( System.getProperty( "user.dir" ) );
        MavenJellyContext c = MavenUtils.createContext( basedir );
        setRootContext( c );
        c.setXMLOutput( output );

        // This is just a start at this mode - there'll still be some output
        if ( getCli().hasOption( OPT_QUIET ) )
        {
            // A little bit of log4j specifics needed here
            Logger.getLogger( "org.apache.maven" ).setLevel( Level.ERROR );
        }

        // -X takes precedence over -q
        if ( getCli().hasOption( OPT_DEBUG ) )
        {
            getRootContext().setDebugOn( Boolean.TRUE );
            // A little bit of log4j specifics needed here
            Logger.getLogger( "org.apache.maven" ).setLevel( Level.DEBUG );
        }
        else
        {
            getRootContext().setDebugOn( Boolean.FALSE );
        }

        if ( getCli().hasOption( OPT_EMACS_OUTPUT ) )
        {
            getRootContext().setEmacsModeOn( Boolean.TRUE );
        }
        else
        {
            getRootContext().setEmacsModeOn( Boolean.FALSE );
        }

        if ( getCli().hasOption( OPT_WORK_OFFLINE ) )
        {
            System.setProperty( MavenConstants.ONLINE, "false" );
        }
    }

    /**
     * Prints the MavenSession header.
     */
    protected void printConsoleMavenHeader()
    {
        Properties p = new Properties();
        InputStream is = getClass().getResourceAsStream( "/driver.properties" );
        try
        {
            p.load( is );
        }
        catch ( IOException e )
        {
            LOGGER.error( MavenUtils.getMessage( "printConsoleMavenHeader.error" ) + e );
        }
        finally
        {
            try
            {
                is.close();
            }
            catch ( IOException e )
            {
                LOGGER.debug( "WARNING: Cannot close stream!", e );
            }
        }

        LOGGER.info( " __  __" );
        LOGGER.info( "|  \\/  |__ _Apache__ ___" );
        LOGGER.info( "| |\\/| / _` \\ V / -_) ' \\  ~ intelligent projects ~" );
        LOGGER.info( "|_|  |_\\__,_|\\_/\\___|_||_|  v. " + p.getProperty( "maven.application.version" ) );
        LOGGER.info( "" );

    }

    /**
     * Set the cli parser.
     *
     * @param commandLine
     *            The command line parser.
     */
    protected void setCli( CommandLine commandLine )
    {
        this.commandLine = commandLine;
    }

    /**
     * Nicely wraps a message for console output, using a word BreakIterator instance to determine wrapping breaks.
     *
     * @param msg
     *            the string message for the console
     * @param wrapIndent
     *            the number of characters to indent all lines after the first one
     * @param lineWidth
     *            the console width that determines where to wrap
     * @return the message wrapped for the console
     */
    protected String wrapConsoleMessage( String msg, int wrapIndent, int lineWidth )
    {
        if ( ( msg.indexOf( '\n' ) < 0 ) && ( msg.indexOf( '\r' ) < 0 ) )
        {
            return wrapConsoleLine( msg, wrapIndent, lineWidth );
        }

        StringBuffer buf = new StringBuffer();
        StringTokenizer tok = new StringTokenizer( msg, "\n\r" );
        while ( tok.hasMoreTokens() )
        {
            String token = tok.nextToken().trim();
            if ( token.length() > 0 )
            {
                buf.append( wrapConsoleLine( token, wrapIndent, lineWidth ) );
                buf.append( LS );
            }
        }
        return buf.toString();
    }

    /**
     * Customize the log4j configuration from properties (read in system, user or project scope).
     */
    private void customizeLogging()
    {
        Iterator iter = getRootContext().getVariableNames();
        Properties log4jProperties = new Properties();
        String propertyName;
        while ( iter.hasNext() )
        {
            propertyName = (String) iter.next();
            if ( propertyName.startsWith( "log4j" ) )
            {
                log4jProperties.put( propertyName, getRootContext().getVariable( propertyName ) );
            }
        }
        // Modify the default log4j settings
        PropertyConfigurator.configure( log4jProperties );
        log4jProperties = null;
        iter = null;
    }

    /**
     * Display information on how to file a bug report if an unknown error occurs.
     */
    private void displayBugReportHelp()
    {
        LOGGER.info( MavenUtils.getMessage( "line" ) );
        StringBuffer sb = new StringBuffer();
        sb.append( MavenUtils.getMessage( "displayBugReportHelp.line1" ) ).append( '\n' );
        sb.append( MavenUtils.getMessage( "displayBugReportHelp.line2" ) ).append( '\n' );
        sb.append( MavenUtils.getMessage( "displayBugReportHelp.line3", LINKS_PROPERTIES.get( "faqUrl" ) ) ).append(
                                                                                                                     '\n' );
        sb.append( MavenUtils.getMessage( "displayBugReportHelp.line4" ) ).append( '\n' );
        sb.append( MavenUtils.getMessage( "displayBugReportHelp.line5", LINKS_PROPERTIES.get( "usersMailingListUrl" ) ) ).append(
                                                                                                                                  '\n' );
        sb.append( MavenUtils.getMessage( "displayBugReportHelp.line6", LINKS_PROPERTIES.get( "issueTrackingUrl" ) ) ).append(
                                                                                                                               '\n' );
        sb.append( MavenUtils.getMessage( "displayBugReportHelp.line7" ) );

        LOGGER.info( "" );
        LOGGER.info( sb.toString() );
        LOGGER.info( "" );
    }

    private void displayBuildFailed( Throwable t, boolean displayBugReportHelp, boolean displayErrors,
                                     boolean displayStackTrace )
    {
        if ( displayBugReportHelp )
            displayBugReportHelp();
        if ( displayErrors )
            displayThrowable( t, displayStackTrace );
        LOGGER.warn( MavenUtils.getMessage( "line" ) );
        LOGGER.warn( MavenUtils.getMessage( "build.failed" ) );
    }

    /**
     * Display helpful information about the given default goal.
     *
     * @param goalName
     *            goal to show info for
     * @param goalDescription
     *            the description of the goal
     * @param newLine
     *            whether to append a newline
     */
    private void displayDefaultGoal( String goalName, String goalDescription, boolean newLine )
    {
        if ( "".equals( goalName ) )
        {
            return;
        }

        String msgPrefix = format( "[" + goalName + "]", WRAP_INDENT, ' ' ) + " ";
        if ( goalDescription == null )
        {
            goalDescription = "( NO DEFAULT GOAL )";
        }

        if ( newLine )
        {
            msgPrefix = LS + msgPrefix;
        }

        LOGGER.info( msgPrefix + wrapConsoleMessage( goalDescription, WRAP_INDENT + 1, CONSOLE_WIDTH ) );
    }

    /**
     * Display helpful information about the given goal.
     *
     * @param goalName
     *            goal to show info for
     * @param goalDescription
     *            the description of the goal
     */
    private void displayGoal( String goalName, String goalDescription )
    {
        if ( "".equals( goalName ) )
        {
            goalName = "( NO GOAL )";
        }

        String msgPrefix = format( "  " + goalName + "  ", WRAP_INDENT, '.' ) + " ";

        LOGGER.info( msgPrefix + wrapConsoleMessage( goalDescription, WRAP_INDENT + 1, CONSOLE_WIDTH ) );
    }

    /**
     * Display helpful information regarding all documented goals.
     *
     * @param pluginOnly
     *            show information for the given plugin only
     * @param plugin
     *            plugin to show info for
     * @param goals
     *            the set of goals
     */
    private void displayGoals( boolean pluginOnly, String plugin, Set goals )
    {
        Map map = new HashMap();
        for ( Iterator i = goals.iterator(); i.hasNext(); )
        {
            String goal = (String) i.next();
            String pluginName = "";
            int index = goal.indexOf( ':' );
            if ( index >= 0 )
            {
                pluginName = goal.substring( 0, index );
            }
            List l = (List) map.get( pluginName );
            if ( l == null )
            {
                l = new ArrayList();
                map.put( pluginName, l );
            }
            l.add( goal.substring( index + 1 ) );
        }

        List goalList = (List) map.get( "" );
        if ( goalList != null )
        {
            for ( Iterator i = goalList.iterator(); i.hasNext(); )
            {
                String goal = (String) i.next();
                if ( map.containsKey( goal ) )
                {
                    i.remove();
                    List pluginGoals = (List) map.get( goal );
                    if ( pluginGoals == null )
                    {
                        pluginGoals = new ArrayList();
                        map.put( goal, pluginGoals );
                    }
                    // don't add the empty goal as we always attempt to display the default
                }
            }
        }

        List keys = new ArrayList( map.keySet() );
        Collections.sort( keys );

        List undocumentedGoals = new ArrayList();

        for ( Iterator i = keys.iterator(); i.hasNext(); )
        {
            String pluginName = (String) i.next();
            if ( pluginOnly )
            {
                if ( plugin == null )
                {
                    // only show default goal
                    displayDefaultGoal( pluginName, mavenSession.getGoalDescription( pluginName ), false );
                    continue;
                }
                else if ( !pluginName.equals( plugin ) )
                {
                    continue;
                }
            }

            displayDefaultGoal( pluginName, mavenSession.getGoalDescription( pluginName ), true );
            List l = (List) map.get( pluginName );
            Collections.sort( l );
            for ( Iterator j = l.iterator(); j.hasNext(); )
            {
                String goalName = (String) j.next();
                String fullGoalName = pluginName.length() == 0 ? goalName : pluginName + ":" + goalName;
                String goalDescription = mavenSession.getGoalDescription( fullGoalName );
                if ( goalDescription != null )
                {
                    displayGoal( goalName, goalDescription );
                }
                else
                {
                    undocumentedGoals.add( fullGoalName );
                }
            }
        }

        if ( undocumentedGoals.isEmpty() == false )
        {
            displayGoalsWithoutDescriptions( undocumentedGoals );
        }
        LOGGER.info( "" );
    }

    /**
     * Display goals without descriptions.
     *
     * @param list
     *            List of undocument goal names.
     */
    private void displayGoalsWithoutDescriptions( List list )
    {
        LOGGER.info( "" );
        LOGGER.info( MavenUtils.getMessage( "displayGoalsWithoutDescriptions.info" ) );
        LOGGER.info( "" );

        for ( Iterator i = list.iterator(); i.hasNext(); )
        {
            String goalName = (String) i.next();

            LOGGER.info( "  " + goalName );
        }
    }

    /**
     * Display the command line help if the option is present, then exit
     */
    private void displayHelp()
    {
        if ( getCli().hasOption( OPT_DISPLAY_HELP ) )
        {
            CLIManager.displayHelp();
            LOGGER.info( "" );
            exit( RC_OK );
        }
    }

    /**
     * Display the command line info if the option is present, then exit
     */
    private void displayInfo()
    {
        if ( getCli().hasOption( OPT_DISPLAY_INFO ) )
        {
            CLIManager.displayInfo();
            LOGGER.info( "" );
            LOGGER.info( MavenUtils.getMessage( "displayInfo.info1" ) );
            for ( Iterator i = mavenSession.getPluginList().iterator(); i.hasNext(); )
            {
                LOGGER.info( "  " + i.next() );
            }

            Properties buildProperties = new Properties();
            FileInputStream fis = null;
            try
            {
                fis = new FileInputStream( System.getProperty( "user.home" ) + "/build.properties" );
                buildProperties.load( fis );
            }
            catch ( IOException e )
            {
                LOGGER.error( MavenUtils.getMessage( "displayInfo.error" ) + e.getMessage() );
            }
            finally
            {
                if ( fis != null )
                {
                    try
                    {
                        fis.close();
                    }
                    catch ( IOException e )
                    {
                        LOGGER.debug( "WARNING: Cannot close stream!", e );
                    }
                    fis = null;
                }
            }
            LOGGER.info( MavenUtils.getMessage( "displayInfo.info2" ) + buildProperties );
            exit( RC_OK );
        }
    }

    /**
     * Display the plugin help if the option is present, then exit.
     *
     * @throws MavenException
     *             when anything goes wrong
     */
    private void displayPluginHelp() throws MavenException
    {
        if ( getCli().hasOption( OPT_DISPLAY_PLUGIN_HELP ) )
        {
            String plugin = getCli().getOptionValue( OPT_DISPLAY_PLUGIN_HELP );

            displayGoals( true, plugin );

            if ( plugin != null )
            {
                Project project = mavenSession.getPluginProjectFromGoal( plugin );
                if ( ( project != null ) && ( project.getDescription() != null ) )
                {
                    LOGGER.info( wrapConsoleMessage( project.getDescription(), 0, CONSOLE_WIDTH ) );
                }
            }

            exit( RC_OK );
        }
    }

    /**
     * Display the project help if the option is present, then exit.
     *
     * @throws MavenException
     *             when anything goes wrong
     */
    private void displayProjectHelp() throws MavenException
    {
        if ( getCli().hasOption( OPT_DISPLAY_USAGE ) )
        {
            Set goals = mavenSession.getProjectGoals( mavenSession.getRootProject() );

            String title = MavenUtils.getMessage( "displayProjectHelp.title" );
            LOGGER.info( title );
            LOGGER.info( format( "", title.length(), '=' ) );
            LOGGER.info( "" );

            Project rootProject = mavenSession.getRootProject();
            if ( ( rootProject.getBuild() != null ) && ( rootProject.getBuild().getDefaultGoal() != null ) )
            {
                String defaultGoal = rootProject.getBuild().getDefaultGoal();
                String msg = MavenUtils.getMessage( "displayGoals.defaultGoal" ) + defaultGoal;
                LOGGER.info( wrapConsoleMessage( msg, WRAP_INDENT + 1, CONSOLE_WIDTH ) );
            }

            displayGoals( false, null, goals );

            String msg = mavenSession.getRootProject().getDescription();
            if ( msg != null )
            {
                LOGGER.info( wrapConsoleMessage( msg, 0, CONSOLE_WIDTH ) );
            }

            exit( RC_OK );
        }
    }

    private void displayThrowable( Throwable t, boolean displayStackTrace )
    {
        LOGGER.info( MavenUtils.getMessage( "line" ) );
        if ( displayStackTrace )
            LOGGER.info( MavenUtils.getMessage( "build.errors.stack" ) );
        Throwable localThrowable = t;
        while ( localThrowable != null )
        {
            if ( localThrowable instanceof JellyException )
            {
                JellyException jellyEx = (JellyException) localThrowable;
                if ( jellyEx.getCause() == null )
                {
                    LOGGER.info( MavenUtils.getMessage( "exception.cause" ) + jellyEx.getReason() );
                }
                if ( displayStackTrace )
                {
                    LOGGER.info( MavenUtils.getMessage( "build.jellyException.file", jellyEx.getFileName() ) );
                    LOGGER.info( MavenUtils.getMessage( "build.jellyException.element", jellyEx.getElementName() ) );
                    LOGGER.info( MavenUtils.getMessage( "build.jellyException.line",
                                                        Integer.toString( jellyEx.getLineNumber() ) ) );
                    LOGGER.info( MavenUtils.getMessage( "build.jellyException.column",
                                                        Integer.toString( jellyEx.getColumnNumber() ) ) );
                }
            }
            else if ( localThrowable.getLocalizedMessage() != null )
                LOGGER.info( MavenUtils.getMessage( "exception.cause" ) + localThrowable.getLocalizedMessage() );
            else
                LOGGER.info( MavenUtils.getMessage( "exception.cause" ) + localThrowable.getClass().getName() );

            localThrowable = localThrowable.getCause();
        }
        if ( displayStackTrace )
        {
            LOGGER.info( "" );
            LOGGER.info( MavenUtils.getMessage( "build.stacktrace" ), t );
        }
    }

    /**
     * Display the Maven version info if the option is present, then exit
     */
    private void displayVersion()
    {
        if ( getCli().hasOption( OPT_DISPLAY_VERSION ) )
        {
            printConsoleMavenHeader();
            exit( RC_OK );
        }
    }

    /**
     * From the CWD search through the directory hierarchy for an XML-based POM.
     *
     * @param start
     *            The starting directory for the POM search.
     * @param suffix
     *            The suffix for the file to be searched for.
     * @return The found project.xml file.
     */
    private File find( File start, String suffix )
    {
        if ( start == null )
        {
            return null;
        }

        File dir = start.getAbsoluteFile();
        File file = new File( dir, suffix );

        return file.exists() ? file : find( dir.getParentFile(), suffix );
    }

    /**
     * From the CWD search through the directory hierarchy for an XML-based POM.
     *
     * @param filename
     *            The filename to find.
     * @return The found file.
     */
    private File find( String filename )
    {
        // An empty string should resolve to the current directory (user.dir)
        return find( new File( "" ), filename );
    }

    /**
     * Get the project descriptor file.
     *
     * @return The project descriptor file.
     * @throws IOException
     *             when the project.xml parent can't be resolved
     */
    private File getDescriptorFile() throws IOException
    {
        File descriptorFile = null;
        String descriptorName = null;

        // Determine what the name of the XML POM descriptor is. If it is
        // specified then we will what the user requests, otherwise we will
        // default to using 'project.xml'.
        if ( getCli().hasOption( OPT_SET_POM_DESCRIPTOR ) )
        {
            descriptorName = getCli().getOptionValue( OPT_SET_POM_DESCRIPTOR );
        }
        else
        {
            descriptorName = POM_FILE_NAME;
        }

        if ( getCli().hasOption( OPT_FIND_POM_DESCRIPTOR ) )
        {
            descriptorFile = find( descriptorName );

            if ( descriptorFile == null )
            {
                descriptorFile = new File( descriptorName );
            }
        }
        else
        {
            descriptorFile = new File( descriptorName );
        }
        if ( getCli().hasOption( OPT_SET_POM_DESCRIPTOR ) && !descriptorFile.exists() )
        {
            throw new FileNotFoundException( "Project file '" + descriptorName + "' not found" );
        }

        descriptorFile = descriptorFile.getAbsoluteFile();
        if ( !getCli().hasOption( OPT_WORKING_DIR ) )
        {
            System.setProperty( "user.dir", descriptorFile.getParentFile().getCanonicalPath() );
        }

        return descriptorFile;
    }

    /**
     * Intialize main and exit if failures occur
     *
     * @param args
     *            command line args
     */
    private void initializeMain( String[] args )
    {
        int returnCode = RC_OK;

        try
        {
            initialize( args );
        }
        catch ( ParseException e )
        {
            LOGGER.info( e.getLocalizedMessage() );
            CLIManager.displayHelp();
            returnCode = RC_BAD_ARG;
        }
        catch ( IOException e )
        {
            LOGGER.info( e.getLocalizedMessage() );
            returnCode = RC_INIT_ERROR;
        }
        catch ( Exception e )
        {
            e.printStackTrace();
            returnCode = RC_INIT_ERROR;
        }

        if ( returnCode != RC_OK )
        {
            LOGGER.info( "" );
            exit( returnCode );
        }

    }

    /**
     * Initialize the mavenSession bean.
     *
     * @throws IOException
     *             when the descriptor file parent can't be resolved
     */
    private void initializeMavenSession() throws IOException
    {
        // Even though the rootProject contains the rootContext we set both in
        // the even that there is no rootProject and the user is requesting goals
        // to be attained that do not directly relate to a project. A goaly that
        // may, say, generate the skeletal maven application build.

        mavenSession = new MavenSession();
        mavenSession.setRootContext( getRootContext() );
        // note: setRootDescriptor file is a static method
        MavenSession.setRootDescriptorFile( getDescriptorFile() );
    }

    /**
     * Set a property based upon a commandline <code>name=value</code> string.
     *
     * @param defStr
     *            The <code>name=value</code> string.
     */
    private void setCliProperty( String defStr )
    {
        String name = null;
        String value = null;
        int equalLoc = defStr.indexOf( "=" );

        if ( equalLoc <= 0 )
        {
            name = defStr.trim();
            value = "true";
        }
        else
        {
            name = defStr.substring( 0, equalLoc ).trim();
            value = defStr.substring( equalLoc + 1 ).trim();
        }

        if ( name.length() > 0 )
        {
            System.setProperty( name, value );
        }
    }

    /**
     * Reformat a message to display on the console.
     *
     * @param msg
     *            the message to display
     * @param wrapIndent
     *            indent
     * @param lineWidth
     *            line width
     * @return String
     */
    private String wrapConsoleLine( String msg, int wrapIndent, int lineWidth )
    {
        int offset = lineWidth - wrapIndent;
        if ( msg.length() <= offset )
        {
            return msg;
        }

        BreakIterator bIter = BreakIterator.getWordInstance();
        StringBuffer buf = new StringBuffer();
        String pad = " ";
        int currentPos = 0;
        bIter.setText( msg );

        while ( offset < bIter.getText().getEndIndex() )
        {
            if ( Character.isWhitespace( bIter.getText().first() ) )
            {
                // remove leading whitespace and continue
                msg = msg.substring( 1 );
                bIter.setText( msg );
                continue;
            }

            // get the last boundary before the specified offset
            currentPos = bIter.preceding( offset );
            // append from the start to currentPos
            buf.append( msg.substring( 0, currentPos ) );

            // start next line
            buf.append( LS );

            // pad with spaces to create indent
            for ( int i = 0; ( i != wrapIndent ) && ( i < lineWidth ); i++ )
            {
                buf.append( pad );
            }

            // set the text of the break iterator to be the rest
            // of the string not already appended
            msg = msg.substring( currentPos );

            // reset the text for another go
            bIter.setText( msg );
        }

        // remove leading whitespace and continue
        while ( Character.isWhitespace( msg.charAt( 0 ) ) )
        {
            msg = msg.substring( 1 );
        }
        buf.append( msg );
        return buf.toString();
    }
}
TOP

Related Classes of org.apache.maven.cli.App

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.