| package org.apache.maven.plugin.resources.remote; |
| |
| /* |
| * 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.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.TreeMap; |
| |
| import org.apache.maven.model.Dependency; |
| import org.apache.maven.model.Plugin; |
| import org.apache.maven.model.PluginContainer; |
| import org.apache.maven.model.PluginExecution; |
| import org.apache.maven.model.Repository; |
| import org.codehaus.plexus.util.xml.Xpp3Dom; |
| |
| /** HELPER CLASS */ |
| public final class ModelUtils |
| { |
| |
| /** |
| * This should be the resulting ordering of plugins after merging: |
| * <p> |
| * Given: |
| * <pre> |
| * parent: X -> A -> B -> D -> E |
| * child: Y -> A -> C -> D -> F |
| * </pre> |
| * Result: |
| * <pre> |
| * X -> Y -> A -> B -> C -> D -> E -> F |
| * </pre> |
| */ |
| public static void mergePluginLists( PluginContainer childContainer, PluginContainer parentContainer, |
| boolean handleAsInheritance ) |
| { |
| if ( ( childContainer == null ) || ( parentContainer == null ) ) |
| { |
| // nothing to do. |
| return; |
| } |
| |
| List<Plugin> parentPlugins = parentContainer.getPlugins(); |
| |
| if ( ( parentPlugins != null ) && !parentPlugins.isEmpty() ) |
| { |
| parentPlugins = new ArrayList<>( parentPlugins ); |
| |
| // If we're processing this merge as an inheritance, we have to build up a list of |
| // plugins that were considered for inheritance. |
| if ( handleAsInheritance ) |
| { |
| for ( Iterator<Plugin> it = parentPlugins.iterator(); it.hasNext(); ) |
| { |
| Plugin plugin = it.next(); |
| |
| String inherited = plugin.getInherited(); |
| |
| if ( ( inherited != null ) && !Boolean.parseBoolean( inherited ) ) |
| { |
| it.remove(); |
| } |
| } |
| } |
| |
| List<Plugin> assembledPlugins = new ArrayList<>(); |
| |
| Map<String, Plugin> childPlugins = childContainer.getPluginsAsMap(); |
| |
| for ( Plugin parentPlugin : parentPlugins ) |
| { |
| String parentInherited = parentPlugin.getInherited(); |
| |
| // only merge plugin definition from the parent if at least one |
| // of these is true: |
| // 1. we're not processing the plugins in an inheritance-based merge |
| // 2. the parent's <inherited/> flag is not set |
| // 3. the parent's <inherited/> flag is set to true |
| if ( !handleAsInheritance || ( parentInherited == null ) |
| || Boolean.parseBoolean( parentInherited ) ) |
| { |
| Plugin childPlugin = childPlugins.get( parentPlugin.getKey() ); |
| |
| if ( ( childPlugin != null ) && !assembledPlugins.contains( childPlugin ) ) |
| { |
| Plugin assembledPlugin = childPlugin; |
| |
| mergePluginDefinitions( childPlugin, parentPlugin, handleAsInheritance ); |
| |
| // fix for MNG-2221 (assembly cache was not being populated for later reference): |
| assembledPlugins.add( assembledPlugin ); |
| } |
| |
| // if we're processing this as an inheritance-based merge, and |
| // the parent's <inherited/> flag is not set, then we need to |
| // clear the inherited flag in the merge result. |
| if ( handleAsInheritance && ( parentInherited == null ) ) |
| { |
| parentPlugin.unsetInheritanceApplied(); |
| } |
| } |
| |
| // very important to use the parentPlugins List, rather than parentContainer.getPlugins() |
| // since this list is a local one, and may have been modified during processing. |
| List<Plugin> results = |
| ModelUtils.orderAfterMerge( assembledPlugins, parentPlugins, childContainer.getPlugins() ); |
| |
| childContainer.setPlugins( results ); |
| |
| childContainer.flushPluginMap(); |
| } |
| } |
| } |
| |
| public static List<Plugin> orderAfterMerge( List<Plugin> merged, List<Plugin> highPrioritySource, |
| List<Plugin> lowPrioritySource ) |
| { |
| List<Plugin> results = new ArrayList<>(); |
| |
| if ( !merged.isEmpty() ) |
| { |
| results.addAll( merged ); |
| } |
| |
| List<Plugin> missingFromResults = new ArrayList<>(); |
| |
| List<List<Plugin>> sources = new ArrayList<>(); |
| |
| sources.add( highPrioritySource ); |
| sources.add( lowPrioritySource ); |
| |
| for ( List<Plugin> source : sources ) |
| { |
| for ( Plugin item : source ) |
| { |
| if ( results.contains( item ) ) |
| { |
| if ( !missingFromResults.isEmpty() ) |
| { |
| int idx = results.indexOf( item ); |
| |
| if ( idx < 0 ) |
| { |
| idx = 0; |
| } |
| |
| results.addAll( idx, missingFromResults ); |
| |
| missingFromResults.clear(); |
| } |
| } |
| else |
| { |
| missingFromResults.add( item ); |
| } |
| } |
| |
| if ( !missingFromResults.isEmpty() ) |
| { |
| results.addAll( missingFromResults ); |
| |
| missingFromResults.clear(); |
| } |
| } |
| |
| return results; |
| } |
| |
| |
| public static void mergePluginDefinitions( Plugin child, Plugin parent, boolean handleAsInheritance ) |
| { |
| if ( ( child == null ) || ( parent == null ) ) |
| { |
| // nothing to do. |
| return; |
| } |
| |
| if ( parent.isExtensions() ) |
| { |
| child.setExtensions( true ); |
| } |
| |
| if ( ( child.getVersion() == null ) && ( parent.getVersion() != null ) ) |
| { |
| child.setVersion( parent.getVersion() ); |
| } |
| |
| Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration(); |
| Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration(); |
| |
| childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration ); |
| |
| child.setConfiguration( childConfiguration ); |
| |
| child.setDependencies( mergeDependencyList( child.getDependencies(), parent.getDependencies() ) ); |
| |
| // from here to the end of the method is dealing with merging of the <executions/> section. |
| String parentInherited = parent.getInherited(); |
| |
| boolean parentIsInherited = ( parentInherited == null ) || Boolean.parseBoolean( parentInherited ); |
| |
| List<PluginExecution> parentExecutions = parent.getExecutions(); |
| |
| if ( ( parentExecutions != null ) && !parentExecutions.isEmpty() ) |
| { |
| List<PluginExecution> mergedExecutions = new ArrayList<>(); |
| |
| Map<String, PluginExecution> assembledExecutions = new TreeMap<>(); |
| |
| Map<String, PluginExecution> childExecutions = child.getExecutionsAsMap(); |
| |
| for ( PluginExecution parentExecution : parentExecutions ) |
| { |
| String inherited = parentExecution.getInherited(); |
| |
| boolean parentExecInherited = |
| parentIsInherited && ( ( inherited == null ) || Boolean.parseBoolean( inherited ) ); |
| |
| if ( !handleAsInheritance || parentExecInherited ) |
| { |
| PluginExecution assembled = parentExecution; |
| |
| PluginExecution childExecution = childExecutions.get( parentExecution.getId() ); |
| |
| if ( childExecution != null ) |
| { |
| mergePluginExecutionDefinitions( childExecution, parentExecution ); |
| |
| assembled = childExecution; |
| } |
| else if ( handleAsInheritance && ( parentInherited == null ) ) |
| { |
| parentExecution.unsetInheritanceApplied(); |
| } |
| |
| assembledExecutions.put( assembled.getId(), assembled ); |
| mergedExecutions.add( assembled ); |
| } |
| } |
| |
| for ( PluginExecution childExecution : child.getExecutions() ) |
| { |
| if ( !assembledExecutions.containsKey( childExecution.getId() ) ) |
| { |
| mergedExecutions.add( childExecution ); |
| } |
| } |
| |
| child.setExecutions( mergedExecutions ); |
| |
| child.flushExecutionMap(); |
| } |
| |
| } |
| |
| private static void mergePluginExecutionDefinitions( PluginExecution child, PluginExecution parent ) |
| { |
| if ( child.getPhase() == null ) |
| { |
| child.setPhase( parent.getPhase() ); |
| } |
| |
| List<String> parentGoals = parent.getGoals(); |
| List<String> childGoals = child.getGoals(); |
| |
| List<String> goals = new ArrayList<>(); |
| |
| if ( ( childGoals != null ) && !childGoals.isEmpty() ) |
| { |
| goals.addAll( childGoals ); |
| } |
| |
| if ( parentGoals != null ) |
| { |
| for ( String goal : parentGoals ) |
| { |
| if ( !goals.contains( goal ) ) |
| { |
| goals.add( goal ); |
| } |
| } |
| } |
| |
| child.setGoals( goals ); |
| |
| Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration(); |
| Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration(); |
| |
| childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration ); |
| |
| child.setConfiguration( childConfiguration ); |
| } |
| |
| public static List<Repository> mergeRepositoryLists( List<Repository> dominant, List<Repository> recessive ) |
| { |
| |
| List<Repository> repositories = new ArrayList<>( dominant ); |
| |
| for ( Repository repository : recessive ) |
| { |
| if ( !repositories.contains( repository ) ) |
| { |
| repositories.add( repository ); |
| } |
| } |
| |
| return repositories; |
| } |
| |
| public static void mergeFilterLists( List<String> childFilters, List<String> parentFilters ) |
| { |
| for ( String f : parentFilters ) |
| { |
| if ( !childFilters.contains( f ) ) |
| { |
| childFilters.add( f ); |
| } |
| } |
| } |
| |
| private static List<Dependency> mergeDependencyList( List<Dependency> child, List<Dependency> parent ) |
| { |
| Map<String, Dependency> depsMap = new LinkedHashMap<>(); |
| |
| if ( parent != null ) |
| { |
| for ( Dependency dependency : parent ) |
| { |
| depsMap.put( dependency.getManagementKey(), dependency ); |
| } |
| } |
| |
| if ( child != null ) |
| { |
| for ( Dependency dependency : child ) |
| { |
| depsMap.put( dependency.getManagementKey(), dependency ); |
| } |
| } |
| |
| return new ArrayList<>( depsMap.values() ); |
| } |
| |
| } |