package org.codehaus.mojo.pomtools.console.screens.custom; /* * Copyright 2005-2006 The Apache Software Foundation. * * Licensed 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.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import org.codehaus.mojo.pomtools.PomToolsPluginContext; import org.codehaus.mojo.pomtools.PomToolsException; import org.codehaus.mojo.pomtools.console.screens.AbstractModelScreen; import org.codehaus.mojo.pomtools.console.screens.ErrorMessageScreen; import org.codehaus.mojo.pomtools.console.screens.HelpScreen; import org.codehaus.mojo.pomtools.console.screens.ModelValidationScreen; import org.codehaus.mojo.pomtools.console.toolkit.ConsoleEvent; import org.codehaus.mojo.pomtools.console.toolkit.ConsoleExecutionException; import org.codehaus.mojo.pomtools.console.toolkit.ConsoleScreen; import org.codehaus.mojo.pomtools.console.toolkit.ConsoleScreenDisplay; import org.codehaus.mojo.pomtools.console.toolkit.event.ConsoleEventDispatcher; import org.codehaus.mojo.pomtools.console.toolkit.event.MatchingListener; import org.codehaus.mojo.pomtools.console.toolkit.event.NumericRangeListener; import org.codehaus.mojo.pomtools.console.toolkit.terminal.Terminal; import org.codehaus.mojo.pomtools.console.toolkit.widgets.LabeledList; import org.codehaus.mojo.pomtools.console.toolkit.widgets.TableColumn; import org.codehaus.mojo.pomtools.console.toolkit.widgets.TableLayout; import org.codehaus.mojo.pomtools.helpers.MetadataHelper; import org.codehaus.mojo.pomtools.helpers.ModelHelper; import org.codehaus.mojo.pomtools.helpers.TransitiveDependencyInfo; import org.codehaus.mojo.pomtools.validation.ProjectValidationResult; import org.apache.maven.project.InvalidProjectModelException; import org.apache.maven.project.ProjectBuildingException; import org.codehaus.plexus.util.StringUtils; /** * * @author <a href="mailto:dhawkins@codehaus.org">David Hawkins</a> * @version $Id$ */ public class ListTransitiveDependenciesScreen extends AbstractModelScreen { private static final String TITLE = "Transitive Dependencies"; private static final String KEY_TOGGLE_POINTS = "t"; private List startpointDeps; private List transitiveDeps; private boolean displayEndpoints = false; private ConsoleScreen errorScreen; public ListTransitiveDependenciesScreen() { super( TITLE ); } public String getHelpText() { StringBuffer sb = new StringBuffer(); sb.append( "Displays a list of both direct and transitive dependencies for this project.\n" ) .append( "You can toggle between viewing starting points and end points.\n\n" ); TableColumn rightColumn = new TableColumn(); rightColumn.setMaxWidth( HelpScreen.HELP_TEXT_MAX_WIDTH - "Starting Point: ".length() ); TableLayout tab = new TableLayout( getTerminal(), new TableColumn[] { TableColumn.ALIGN_LEFT_COLUMN, rightColumn }, HelpScreen.HELP_TEXT_MAX_WIDTH ); tab.add( "Starting Point:", "A direct dependency of this project. Listed in the <dependencies> " + "section of the pom. Selecting an item from the list in this mode will display a " + "tree of transitive dependencies that this item brings into the project." ); tab.addEmptyRow(); tab.add( "End Point:", "A dependency that is included directly or indirectly by " + "this project. Selecting an item from the list will display all " + "of the possible paths which include this artifact. Conflicts, if any, are noted as a " + "comma delimited list of versions along with the number of paths that lead to " + "that version." ); sb.append( tab.getOutput() ); return sb.toString(); } private List getEndPointDependencies() throws PomToolsException, ProjectBuildingException { if ( transitiveDeps == null ) { MetadataHelper metaHelper = getModelContext().getMetadataHelper(); this.transitiveDeps = metaHelper.getTransitiveDependencies(); Collections.sort( this.transitiveDeps, new Comparator() { public int compare( Object arg0, Object arg1 ) { String key0 = ( (TransitiveDependencyInfo) arg0 ).getKey(); String key1 = ( (TransitiveDependencyInfo) arg1 ).getKey(); return key0.compareTo( key1 ); } } ); } return this.transitiveDeps; } List reloadTransitiveDependencies() throws PomToolsException, ProjectBuildingException { this.transitiveDeps = null; return getEndPointDependencies(); } private List getStartPointDependencies() throws PomToolsException, ProjectBuildingException { if ( startpointDeps == null ) { List allDeps = getEndPointDependencies(); startpointDeps = new ArrayList(); for ( Iterator iter = allDeps.iterator(); iter.hasNext(); ) { TransitiveDependencyInfo info = (TransitiveDependencyInfo) iter.next(); if ( info.getSelectedNode().getDepth() == 1 ) { startpointDeps.add( info ); } } } return this.startpointDeps; } public ConsoleScreenDisplay getDisplay() throws ConsoleExecutionException { if ( this.errorScreen != null ) { return errorScreen.getDisplay(); } try { return ( displayEndpoints ) ? getEndPointDisplay() : getStartPointDisplay(); } catch ( Exception e ) { return getErrorScreen( e ).getDisplay(); } } protected ConsoleScreen getErrorScreen( Exception e ) throws ConsoleExecutionException { if ( e instanceof InvalidProjectModelException ) { ProjectValidationResult val = new ProjectValidationResult( PomToolsPluginContext.getInstance() .getActiveProject(), ( (InvalidProjectModelException) e ).getValidationResult() ); this.errorScreen = new ModelValidationScreen( Collections.singletonList( val ), "Unable to resolve transitive dependencies due to the " + "following validation errors:" ); return this.errorScreen; } else if ( e instanceof PomToolsException ) { this.errorScreen = new ErrorMessageScreen( "Error resolving transitive dependencies", "Unable to resolve transitive dependencies due to the " + "following error:\n\n" + e.getCause().getMessage() ); return this.errorScreen; } else { throw new ConsoleExecutionException( e ); } } public ConsoleScreenDisplay getEndPointDisplay() throws PomToolsException, ProjectBuildingException { StringBuffer sb = new StringBuffer( getHeader( TITLE + " [End Points]" ) ); LabeledList lil = new LabeledList( getTerminal(), true, true ); Terminal term = getTerminal(); for ( ListIterator iter = getEndPointDependencies().listIterator(); iter.hasNext(); ) { TransitiveDependencyInfo info = (TransitiveDependencyInfo) iter.next(); StringBuffer conflictSb = new StringBuffer(); if ( info.hasConflicts() ) { conflictSb.append( "\n " + term.bold( "Conflicts: " ) ); List tmp = new ArrayList(); for ( Iterator vi = info.getDistinctVersionCounts().iterator(); vi.hasNext(); ) { TransitiveDependencyInfo.VersionCount vcount = (TransitiveDependencyInfo.VersionCount) vi.next(); tmp.add( term.underline( vcount.getVersion() ) + "(" + vcount.getCount() + ")" ); } conflictSb.append( StringUtils.join( tmp.iterator(), ", " ) ); } lil.add( numberPrompt( iter.nextIndex() ), ModelHelper.versionedKey( info.getSelectedArtifact() ) + conflictSb.toString() ); } sb.append( lil.getOutput() ); addAdditionalOptions( sb ); return createDisplay( sb.toString(), "Select an item to view its detail." ); } protected void addAdditionalOptions( StringBuffer sb ) { OptionsPane options = new OptionsPane(); options.add( KEY_TOGGLE_POINTS, "Toggle display to view " + ( displayEndpoints ? "start" : "end" ) + " points" ); sb.append( options.getOutput() ); } public ConsoleScreenDisplay getStartPointDisplay() throws ConsoleExecutionException, PomToolsException, ProjectBuildingException { StringBuffer sb = new StringBuffer( getHeader( TITLE + " [Start Points]" ) ); LabeledList lil = new LabeledList( getTerminal(), true, true ); for ( ListIterator iter = getStartPointDependencies().listIterator(); iter.hasNext(); ) { TransitiveDependencyInfo info = (TransitiveDependencyInfo) iter.next(); lil.add( numberPrompt( iter.nextIndex() ), ModelHelper.versionedKey( info.getSelectedArtifact() ) ); } sb.append( lil.getOutput() ); addAdditionalOptions( sb ); return createDisplay( sb.toString(), "Select an item to view its detail." ); } public ConsoleEventDispatcher getEventDispatcher() throws ConsoleExecutionException { ConsoleEventDispatcher ced = super.getDefaultEventDispatcher(); final List currentList; try { currentList = ( displayEndpoints ) ? getEndPointDependencies() : getStartPointDependencies(); } catch ( Exception e ) { return getErrorScreen( e ).getEventDispatcher(); } ced.addFirst( new MatchingListener( new String[] { "t", "toggle" }, "Toggle between start points and end points.", "t[oggle]" ) { public void processEvent( ConsoleEvent event ) throws ConsoleExecutionException { displayEndpoints = !displayEndpoints; } } ); final ListTransitiveDependenciesScreen listScreen = this; ced.addFirst( new NumericRangeListener( 1, currentList.size(), "Select an item to view its detail" ) { public void processEvent( ConsoleEvent event ) throws ConsoleExecutionException { int index = Integer.parseInt( event.getConsoleInput() ) - 1; try { if ( displayEndpoints ) { event.setNextScreen( new TransitiveEndPointDetailScreen( currentList, index, listScreen ) ); } else { event.setNextScreen( new TransitiveStartPointDetailScreen( currentList, index ) ); } } catch ( PomToolsException e ) { throw new ConsoleExecutionException( e ); } } } ); return ced; } }