/* * Copyright (c) 2012 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.session; import java.io.File; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import org.apache.maven.mae.project.key.FullProjectKey; import org.apache.maven.mae.project.key.ProjectKey; import org.apache.maven.mae.project.key.VersionlessProjectKey; import org.apache.maven.mae.project.session.SimpleProjectToolsSession; import org.apache.maven.model.Dependency; import org.apache.maven.model.Model; import org.apache.maven.model.Parent; import org.apache.maven.model.Plugin; import org.apache.maven.model.ReportPlugin; import org.apache.maven.model.Repository; import org.apache.maven.project.MavenProject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonatype.aether.RepositorySystemSession; import org.sonatype.aether.artifact.ArtifactType; import org.sonatype.aether.artifact.ArtifactTypeRegistry; import org.sonatype.aether.util.DefaultRepositorySystemSession; import com.redhat.rcm.version.VManException; import com.redhat.rcm.version.maven.VManWorkspaceReader; import com.redhat.rcm.version.maven.WildcardProjectKey; import com.redhat.rcm.version.model.DependencyManagementKey; import com.redhat.rcm.version.model.Project; import com.redhat.rcm.version.report.Report; import com.redhat.rcm.version.util.ActivityLog; public class VersionManagerSession extends SimpleProjectToolsSession { private final Logger logger = LoggerFactory.getLogger( getClass() ); private final List<Throwable> errors = new ArrayList<Throwable>(); private final Map<File, ActivityLog> logs = new LinkedHashMap<File, ActivityLog>(); private final Map<VersionlessProjectKey, Set<VersionlessProjectKey>> childPluginRefs = new HashMap<VersionlessProjectKey, Set<VersionlessProjectKey>>(); private final File backups; private final File downloads; private final boolean preserveFiles; private final File workspace; private final File reports; private final String versionSuffix; private String settingsXml; private File capturePom; private final ManagedInfo managedInfo; private final ChangeInfo changeInfo; private final boolean strict; private final String versionModifier; private VManWorkspaceReader workspaceReader; private final boolean useEffectivePoms; public VersionManagerSession( final File workspace, final File reports, final String versionSuffix, final String versionModifier, final Collection<String> removedPlugins, final Collection<String> removedTests, final Collection<String> extensionsWhitelist, final List<String> modderKeys, final boolean preserveFiles, final boolean strict, final boolean useEffectivePoms, final Map<String, String> relocatedCoords, final Map<String, String> propertyMappings, final Set<VersionlessProjectKey> excludedModulePoms, final Map<String, String> userProperties ) { this.workspace = workspace; this.reports = reports; this.versionSuffix = versionSuffix; this.versionModifier = versionModifier; this.strict = strict; this.useEffectivePoms = useEffectivePoms; backups = new File( workspace, "backups" ); backups.mkdirs(); downloads = getDownloadsDir( workspace ); this.preserveFiles = preserveFiles; managedInfo = new ManagedInfo( this, removedPlugins, removedTests, extensionsWhitelist, modderKeys, relocatedCoords, propertyMappings, excludedModulePoms, userProperties ); changeInfo = new ChangeInfo(); } public boolean isUseEffectivePoms() { return useEffectivePoms; } public static File getDownloadsDir( final File workspace ) { final File downloads = new File( workspace, "downloads" ); downloads.mkdirs(); return downloads; } public Set<VersionlessProjectKey> getExcludedModulePoms() { return managedInfo.getExcludedModulePoms(); } public boolean isStrict() { return strict; } public String getVersionSuffix() { return versionSuffix; } public String getVersionModifier() { return versionModifier; } public FullProjectKey getRelocation( final ProjectKey key ) { return managedInfo.getRelocation( key ); } public Map<File, ActivityLog> getLogs() { return logs; } public synchronized ActivityLog getLog( final File pom ) { ActivityLog log = logs.get( pom ); if ( log == null ) { log = new ActivityLog(); logs.put( pom, log ); } return log; } public void addUnmanagedPlugin( final File pom, final ReportPlugin plugin ) { final Plugin p = new Plugin(); p.setGroupId( plugin.getGroupId() ); p.setArtifactId( plugin.getArtifactId() ); p.setVersion( plugin.getVersion() ); addUnmanagedPlugin( pom, p ); } public synchronized VersionManagerSession addUnmanagedPlugin( final File pom, final Plugin plugin ) { changeInfo.addUnmanagedPlugin( pom, plugin ); return this; } public void addMissingParent( final Project project ) { changeInfo.addMissingParent( project ); } public synchronized VersionManagerSession addMissingDependency( final Project project, final Dependency dep ) { changeInfo.addMissingDependency( project, dep ); return this; } public VersionManagerSession addError( final Throwable error ) { errors.add( error ); return this; } public File getWorkspace() { return workspace; } public File getReports() { return reports; } public File getBackups() { return backups; } public File getDownloads() { return downloads; } public boolean isPreserveFiles() { return preserveFiles; } public void addMissingVersionProperty( final String key, final String version ) { changeInfo.addMissingVersionProperty( key, version ); } public Map<String, String> getMissingVersionProperties() { return changeInfo.getMissingVersionProperties(); } public Map<VersionlessProjectKey, Set<Plugin>> getUnmanagedPluginRefs() { return changeInfo.getUnmanagedPluginRefs(); } public Map<File, Set<VersionlessProjectKey>> getUnmanagedPlugins() { return changeInfo.getUnmanagedPlugins(); } public Set<VersionlessProjectKey> getUnmanagedPlugins( final File pom ) { return changeInfo.getUnmanagedPlugins( pom ); } public Set<Project> getProjectsWithMissingParent() { return changeInfo.getProjectsWithMissingParent(); } public boolean isMissingParent( final Project project ) { return changeInfo.isMissingParent( project ); } public Map<VersionlessProjectKey, Set<Dependency>> getMissingDependencies() { return changeInfo.getMissingDependencies(); } public Set<Dependency> getMissingDependencies( final VersionlessProjectKey key ) { return changeInfo.getMissingDependencies( key ); } public Map<FullProjectKey, Set<File>> getMissingVersions() { return changeInfo.getMissingVersions(); } public Set<VersionlessProjectKey> getMissingVersions( final ProjectKey key ) { return changeInfo.getMissingVersions( key ); } public List<Throwable> getErrors() { return errors; } public boolean hasDependencyMap() { return managedInfo.hasDependencyMap(); } public Dependency getManagedDependency( final DependencyManagementKey key ) { return managedInfo.getManagedDependency( key ); } public Map<File, Map<DependencyManagementKey, String>> getMappedDependenciesByBom() { return managedInfo.getMappedDependenciesByBom(); } public List<FullProjectKey> getBomCoords() { return managedInfo.getBomCoords(); } public VersionManagerSession addBOM( final File bom, final MavenProject project ) throws VManException { managedInfo.addBOM( bom, project ); return this; } public CoordinateRelocations getRelocations() { return managedInfo.getRelocations(); } public MavenProject getToolchainProject() { return managedInfo.getToolchainProject(); } public MavenProject getBOMProject( final FullProjectKey key ) { return managedInfo.getBOMProject( key ); } public VersionManagerSession setToolchain( final File toolchainFile, final MavenProject project ) { managedInfo.setToolchain( toolchainFile, project ); return this; } public Set<VersionlessProjectKey> getRemovedPlugins() { return managedInfo.getRemovedPlugins(); } public List<WildcardProjectKey> getRemovedTests() { return managedInfo.getRemovedTests(); } /** NEVER null. */ public Set<VersionlessProjectKey> getExtensionsWhitelist() { return managedInfo.getExtensionsWhitelist(); } public FullProjectKey getToolchainKey() { return managedInfo.getToolchainKey(); } public Plugin getManagedPlugin( final VersionlessProjectKey key ) { return managedInfo.getManagedPlugin( key ); } public Map<VersionlessProjectKey, Plugin> getInjectedPlugins() { return managedInfo.getInjectedPlugins(); } public Set<VersionlessProjectKey> getChildPluginReferences( final VersionlessProjectKey owner ) { Set<VersionlessProjectKey> refs = childPluginRefs.get( owner ); if ( refs == null ) { refs = Collections.emptySet(); } return refs; } public VersionManagerSession addChildPluginReference( final VersionlessProjectKey owner, final VersionlessProjectKey plugin ) { Set<VersionlessProjectKey> plugins = childPluginRefs.get( owner ); if ( plugins == null ) { plugins = new HashSet<VersionlessProjectKey>(); childPluginRefs.put( owner, plugins ); } plugins.add( plugin ); return this; } public boolean isBom( final FullProjectKey key ) { return managedInfo.hasBom( key ); } public void setRemoteRepositories( final String remoteRepositories ) throws MalformedURLException { String id = "vman"; int repoIndex = 1; final String repos[] = remoteRepositories.split( "," ); final ArrayList<Repository> resolveRepos = new ArrayList<Repository>(); for ( final String repository : repos ) { String u = repository; final int idx = u.indexOf( '|' ); if ( idx > 0 ) { id = u.substring( 0, idx ); u = u.substring( idx + 1 ); } final Repository resolveRepo = new Repository(); resolveRepo.setId( id + '-' + repoIndex++ ); resolveRepo.setUrl( u ); resolveRepos.add( resolveRepo ); } setResolveRepositories( resolveRepos.toArray( new Repository[resolveRepos.size()] ) ); } public boolean isToolchainReference( final Parent parent ) { return managedInfo.isToolchainReference( parent ); } public boolean inCurrentSession( final Parent parent ) { return managedInfo.isCurrentProject( new VersionlessProjectKey( parent ) ); } public void setSettingsXml( final String settingsXml ) { this.settingsXml = settingsXml; } public String getSettingsXml() { return settingsXml; } public void setCapturePom( final File capturePom ) { this.capturePom = capturePom; } public File getCapturePom() { return capturePom; } public void setPeekedPoms( final Map<FullProjectKey, File> peekedPoms ) { managedInfo.setPeekedPoms( peekedPoms ); } public boolean isExcludedModulePom( final File pom ) { return managedInfo.isExcludedModulePom( pom ); } public Map<FullProjectKey, File> getPeekedPoms() { return managedInfo.getPeekedPoms(); } public File getPeekedPom( final FullProjectKey key ) { return managedInfo.getPeekedPom( key ); } public LinkedHashSet<Project> getCurrentProjects() { return managedInfo.getCurrentProjects(); } public Project getCurrentProject( final ProjectKey key ) { return managedInfo.getCurrentProject( key ); } public boolean isCurrentProject( final ProjectKey key ) { return managedInfo.isCurrentProject( key ); } public boolean isCurrentProject( final Parent parent ) { if ( parent == null ) { return false; } return managedInfo.isCurrentProject( new FullProjectKey( parent ) ); } public String getUserProperty( final String key ) { return managedInfo.getUserProperty( key ); } public List<String> getModderKeys() { return managedInfo.getModderKeys(); } public PropertyMappings getPropertyMappings() { return managedInfo.getPropertyMapping(); } public Map<ProjectKey, FullProjectKey> getRelocatedCoordinates( final File pom ) { return changeInfo.getRelocatedCoordinates( pom ); } public void addRelocatedCoordinate( final File pom, final ProjectKey old, final FullProjectKey relocation ) { changeInfo.addRelocatedCoordinate( pom, old, relocation ); } public Map<File, Map<ProjectKey, FullProjectKey>> getRelocatedCoordinatesByFile() { return changeInfo.getRelocatedCoordinatesByFile(); } public void setCurrentProjects( final Set<Project> projects ) { managedInfo.setCurrentProjects( projects ); } public void setWorkspaceReader( final VManWorkspaceReader workspaceReader ) { this.workspaceReader = workspaceReader; final RepositorySystemSession rss = getRepositorySystemSession(); final DefaultRepositorySystemSession drss; if ( rss == null ) { drss = new DefaultRepositorySystemSession(); } else if ( rss instanceof DefaultRepositorySystemSession ) { drss = (DefaultRepositorySystemSession) rss; } else { drss = new DefaultRepositorySystemSession( rss ); } drss.setWorkspaceReader( workspaceReader ); initialize( drss, getProjectBuildingRequest(), getArtifactRepositoriesForResolution(), getRemoteRepositoriesForResolution() ); } public VManWorkspaceReader getWorkspaceReader() { return workspaceReader; } /* * This should search through the defined properties. It will look for * versionmapper.<groupId>-<artifactId> * version.<groupId>-<artifactId> * and return the value held there. */ public String replacePropertyVersion( final Project project, final String groupId, final String artifactId, final String type, final String classifier ) { String result = null; final Model model = isUseEffectivePoms() ? project.getEffectiveModel() : project.getOriginalModel(); if ( model == null ) { // TODO: This needs more thought. return null; } final String mapper = "versionmapper." + groupId + '-' + artifactId; final String direct = "version." + groupId + '-' + artifactId; Properties props = model.getProperties(); Set<String> commonKeys = props.stringPropertyNames(); for ( final String key : commonKeys ) { result = evaluateKey( props, direct, mapper, key ); if ( result != null ) { break; } } // Can't find a matching substitution in current pom chain; check the toolchain. if ( result == null && getToolchainProject() != null ) { props = getToolchainProject().getProperties(); commonKeys = props.stringPropertyNames(); for ( final String key : commonKeys ) { result = evaluateKey( props, direct, mapper, key ); if ( result != null ) { break; } } } if ( result == null ) { String version = "MISSING VERSION"; Dependency managed = getManagedDependency( new DependencyManagementKey( groupId, artifactId, type, classifier ) ); if ( managed == null ) { // if we don't find the one with the specific type/classifier, look for the generic one // if we find that, we can list the specific one as a missing dep and use the info from // the generic one for the version, etc. managed = getManagedDependency( new DependencyManagementKey( groupId, artifactId ) ); if ( managed != null ) { final Dependency d = new Dependency(); d.setGroupId( groupId ); d.setArtifactId( artifactId ); d.setVersion( managed.getVersion() ); if ( type != null ) { d.setType( "pom" ); } if ( classifier != null ) { d.setClassifier( classifier ); } addMissingDependency( project, d ); } } if ( managed != null ) { version = managed.getVersion(); } else { addMissingVersionProperty( direct, version ); } project.getModel() .getProperties() .setProperty( direct, version ); result = "${" + direct + "}"; } else { logger.info( "Successfully located mapper property: " + result + " for " + groupId + ':' + artifactId ); } return result; } private String evaluateKey( final Properties props, final String direct, final String mapper, final String key ) { String result = null; if ( key.equals( mapper ) ) { final String value = props.getProperty( key ); if ( Character.isDigit( value.charAt( 0 ) ) ) { // Versionmapper references an explicit version e.g. 2.0. result = value; } else { result = "${" + value + "}"; } } else if ( key.equals( direct ) ) { result = "${" + direct + "}"; } return result; } public void addPeekPom( final FullProjectKey key, final File pom ) { managedInfo.addPeekPom( key, pom ); } public synchronized ArtifactType getArtifactType( final Project project ) { final ArtifactTypeRegistry typeRegistry = getRepositorySystemSession().getArtifactTypeRegistry(); return typeRegistry.get( project.getPackaging() ); } public VersionManagerSession addDependencyModification( final VersionlessProjectKey key, final Dependency from, final Dependency to ) { logger.info( "Recording modification in: {}. {} modified to: {}", key, from, to ); changeInfo.addDependencyModification( key, from, to ); return this; } public Map<Dependency, Dependency> getDependencyModifications( final VersionlessProjectKey key ) { return changeInfo.getDependencyModifications( key ); } public String getReportProperty( final Report report, final String key ) { return getUserProperty( "report." + report.getId() + "." + key ); } }