/* * Copyright (c) 2010 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses>. */ package com.redhat.rcm.version.mgr.capture; import static org.apache.commons.io.IOUtils.closeQuietly; import static org.apache.commons.lang.StringUtils.isEmpty; import static org.apache.commons.lang.StringUtils.isNotEmpty; import java.io.File; import java.io.IOException; import java.io.Writer; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.maven.mae.project.key.FullProjectKey; import org.apache.maven.mae.project.key.VersionlessProjectKey; import org.apache.maven.model.Build; import org.apache.maven.model.Dependency; import org.apache.maven.model.DependencyManagement; import org.apache.maven.model.Model; import org.apache.maven.model.Parent; import org.apache.maven.model.Plugin; import org.apache.maven.model.PluginManagement; import org.apache.maven.model.io.xpp3.MavenXpp3Writer; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.util.WriterFactory; import org.sonatype.aether.artifact.ArtifactType; import org.sonatype.aether.util.version.GenericVersionScheme; import org.sonatype.aether.version.InvalidVersionSpecificationException; import org.sonatype.aether.version.Version; import org.sonatype.aether.version.VersionScheme; import com.redhat.rcm.version.Cli; import com.redhat.rcm.version.VManException; import com.redhat.rcm.version.mgr.session.VersionManagerSession; import com.redhat.rcm.version.model.DependencyManagementKey; import com.redhat.rcm.version.model.Project; @Component( role = MissingInfoCapture.class ) public class MissingInfoCapture { private static final String VERSION_DATE_PATTERN = "yyyyMMdd.HHmm"; public void captureMissing( final VersionManagerSession session ) { final Map<VersionlessProjectKey, Set<Dependency>> missingDeps = session.getMissingDependencies(); final Map<VersionlessProjectKey, Set<Plugin>> missingPlugins = session.getUnmanagedPluginRefs(); final Set<Project> missingParents = session.getProjectsWithMissingParent(); final Map<String, String> missingVersionProps = session.getMissingVersionProperties(); final boolean procDeps = notEmpty( missingDeps ); final boolean procPlugs = notEmpty( missingPlugins ); final boolean procParents = notEmpty( missingParents ); final boolean procProps = notEmpty( missingVersionProps ); if ( procProps || procDeps || procPlugs ) { final SimpleDateFormat format = new SimpleDateFormat( VERSION_DATE_PATTERN ); final Model model = new Model(); model.setModelVersion( "4.0.0" ); model.setGroupId( Cli.class.getPackage() .getName() ); model.setArtifactId( "vman-missing-capture" ); model.setVersion( format.format( new Date() ) ); model.setPackaging( "pom" ); boolean write = false; write = processCurrentProjects( session, model ) || write; if ( procProps ) { write = processProperties( missingVersionProps, model ) || write; } if ( procDeps ) { write = processDependencies( missingDeps, model ) || write; } if ( procPlugs ) { write = processPlugins( missingPlugins, model ) || write; } if ( procParents ) { write = processParents( missingParents, model ) || write; } if ( write ) { final File capturePom = session.getCapturePom(); Writer writer = null; try { final File dir = capturePom.getAbsoluteFile() .getParentFile(); if ( dir != null && !dir.exists() ) { dir.mkdirs(); } writer = WriterFactory.newXmlWriter( capturePom ); new MavenXpp3Writer().write( writer, model ); } catch ( final IOException e ) { session.addError( new VManException( "Failed to write capture POM: %s. Reason: %s", e, capturePom, e.getMessage() ) ); } finally { closeQuietly( writer ); } } } } private boolean processProperties( final Map<String, String> props, final Model model ) { for ( final Map.Entry<String, String> entry : props.entrySet() ) { model.getProperties() .setProperty( entry.getKey(), entry.getValue() ); } return true; } private boolean processCurrentProjects( final VersionManagerSession session, final Model model ) { final DependencyManagement dm = getDependencyManagement( model ); boolean changed = false; for ( final Project project : session.getCurrentProjects() ) { final Dependency managed = session.getManagedDependency( new DependencyManagementKey( project.getGroupId(), project.getArtifactId(), "pom", null ) ); if ( managed == null ) { final Dependency dep = new Dependency(); dep.setGroupId( project.getGroupId() ); dep.setArtifactId( project.getArtifactId() ); dep.setVersion( project.getVersion() ); final ArtifactType at = session.getArtifactType( project ); if ( at != null ) { dep.setType( at.getExtension() ); dep.setClassifier( at.getClassifier() ); } else { dep.setType( project.getPackaging() ); } dm.addDependency( dep ); changed = true; } } return changed; } private boolean processParents( final Set<Project> missingParents, final Model model ) { final DependencyManagement dm = getDependencyManagement( model ); final Map<FullProjectKey, Dependency> parents = new HashMap<FullProjectKey, Dependency>(); for ( final Project project : missingParents ) { final Parent parent = project.getParent(); final FullProjectKey key = new FullProjectKey( parent ); if ( !parents.containsKey( key ) ) { final Dependency dep = new Dependency(); dep.setGroupId( parent.getGroupId() ); dep.setArtifactId( parent.getArtifactId() ); dep.setVersion( parent.getVersion() ); parents.put( key, dep ); } } final Set<FullProjectKey> depKeys = new HashSet<FullProjectKey>(); for ( final Dependency dep : dm.getDependencies() ) { depKeys.add( new FullProjectKey( dep ) ); } boolean result = false; for ( final Map.Entry<FullProjectKey, Dependency> entry : parents.entrySet() ) { if ( !depKeys.contains( entry.getKey() ) ) { dm.addDependency( entry.getValue() ); result = true; } } return result; } private DependencyManagement getDependencyManagement( final Model model ) { DependencyManagement dm = model.getDependencyManagement(); if ( dm == null ) { dm = new DependencyManagement(); model.setDependencyManagement( dm ); } return dm; } private boolean processPlugins( final Map<VersionlessProjectKey, Set<Plugin>> missingPlugins, final Model model ) { final Build build = new Build(); final PluginManagement pm = new PluginManagement(); build.setPluginManagement( pm ); for ( final Map.Entry<VersionlessProjectKey, Set<Plugin>> entry : missingPlugins.entrySet() ) { final Map<String, Set<Plugin>> mks = new HashMap<String, Set<Plugin>>(); for ( final Plugin plugin : entry.getValue() ) { final String key = plugin.getKey(); Set<Plugin> ds = mks.get( key ); if ( ds == null ) { ds = new HashSet<Plugin>(); mks.put( key, ds ); } ds.add( plugin ); } for ( final Set<Plugin> ds : mks.values() ) { if ( ds == null || ds.isEmpty() ) { continue; } final List<Plugin> pluginList = new ArrayList<Plugin>( ds ); Collections.sort( pluginList, new PluginVersionComparator() ); pm.addPlugin( pluginList.get( 0 ) ); } } if ( pm.getPlugins() != null && !pm.getPlugins() .isEmpty() ) { Collections.sort( pm.getPlugins(), new PluginArtifactIdComparator() ); model.setBuild( build ); return true; } return false; } private boolean processDependencies( final Map<VersionlessProjectKey, Set<Dependency>> missingDeps, final Model model ) { final DependencyManagement dm = getDependencyManagement( model ); for ( final Map.Entry<VersionlessProjectKey, Set<Dependency>> entry : missingDeps.entrySet() ) { final Map<String, Set<Dependency>> mks = new HashMap<String, Set<Dependency>>(); for ( final Dependency dep : entry.getValue() ) { final String key = dep.getManagementKey(); Set<Dependency> ds = mks.get( key ); if ( ds == null ) { ds = new HashSet<Dependency>(); mks.put( key, ds ); } ds.add( dep ); } for ( final Set<Dependency> ds : mks.values() ) { if ( ds == null || ds.isEmpty() ) { continue; } final List<Dependency> depList = new ArrayList<Dependency>( ds ); Collections.sort( depList, new DependencyVersionComparator() ); dm.addDependency( depList.get( 0 ) ); } } if ( dm.getDependencies() != null && !dm.getDependencies() .isEmpty() ) { Collections.sort( dm.getDependencies(), new DependencyArtifactIdComparator() ); model.setDependencyManagement( dm ); return true; } return false; } private boolean notEmpty( final Map<?, ?> map ) { return map != null && !map.isEmpty(); } private boolean notEmpty( final Collection<?> coll ) { return coll != null && !coll.isEmpty(); } public static final class DependencyVersionComparator implements Comparator<Dependency> { private final VersionScheme versionScheme = new GenericVersionScheme(); @Override public int compare( final Dependency o1, final Dependency o2 ) { int result = 0; if ( isEmpty( o1.getVersion() ) && isNotEmpty( o2.getVersion() ) ) { result = -1; } else if ( isNotEmpty( o1.getVersion() ) && isEmpty( o2.getVersion() ) ) { result = 1; } else { Version v1 = null; try { v1 = versionScheme.parseVersion( o1.getVersion() ); } catch ( final InvalidVersionSpecificationException e ) { result = -1; } if ( v1 != null ) { try { final Version v2 = versionScheme.parseVersion( o2.getVersion() ); result = v1.compareTo( v2 ); } catch ( final InvalidVersionSpecificationException e ) { result = 1; } } } return result; } } public static final class PluginVersionComparator implements Comparator<Plugin> { private final VersionScheme versionScheme = new GenericVersionScheme(); @Override public int compare( final Plugin o1, final Plugin o2 ) { int result = 0; if ( isEmpty( o1.getVersion() ) && isNotEmpty( o2.getVersion() ) ) { result = -1; } else if ( isNotEmpty( o1.getVersion() ) && isEmpty( o2.getVersion() ) ) { result = 1; } else { Version v1 = null; try { v1 = versionScheme.parseVersion( o1.getVersion() ); } catch ( final InvalidVersionSpecificationException e ) { result = -1; } if ( v1 != null ) { try { final Version v2 = versionScheme.parseVersion( o2.getVersion() ); result = v1.compareTo( v2 ); } catch ( final InvalidVersionSpecificationException e ) { result = 1; } } } return result; } } public class DependencyArtifactIdComparator implements Comparator<Dependency> { @Override public int compare( final Dependency o1, final Dependency o2 ) { return o1.getArtifactId() .compareTo( o2.getArtifactId() ); } } public class PluginArtifactIdComparator implements Comparator<Plugin> { @Override public int compare( final Plugin o1, final Plugin o2 ) { return o1.getArtifactId() .compareTo( o2.getArtifactId() ); } } }