View Javadoc
1   package org.apache.maven.plugin.assembly.interpolation;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.Collections;
25  import java.util.HashSet;
26  import java.util.List;
27  import java.util.Properties;
28  import java.util.Set;
29  
30  import org.apache.maven.execution.MavenSession;
31  import org.apache.maven.plugin.assembly.AssemblerConfigurationSource;
32  import org.apache.maven.plugin.assembly.model.Assembly;
33  import org.apache.maven.plugin.assembly.utils.AssemblyFileUtils;
34  import org.apache.maven.plugin.assembly.utils.InterpolationConstants;
35  import org.apache.maven.project.MavenProject;
36  import org.codehaus.plexus.interpolation.InterpolationException;
37  import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
38  import org.codehaus.plexus.interpolation.Interpolator;
39  import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
40  import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
41  import org.codehaus.plexus.interpolation.PrefixedPropertiesValueSource;
42  import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
43  import org.codehaus.plexus.interpolation.RecursionInterceptor;
44  import org.codehaus.plexus.interpolation.StringSearchInterpolator;
45  import org.codehaus.plexus.interpolation.object.FieldBasedObjectInterpolator;
46  import org.codehaus.plexus.interpolation.object.ObjectInterpolationWarning;
47  import org.codehaus.plexus.logging.AbstractLogEnabled;
48  import org.codehaus.plexus.logging.Logger;
49  import org.codehaus.plexus.logging.console.ConsoleLogger;
50  import org.codehaus.plexus.util.cli.CommandLineUtils;
51  
52  /**
53   * @version $Id: AssemblyInterpolator.java 1601216 2014-06-08 11:58:09Z khmarbaise $
54   */
55  public class AssemblyInterpolator
56      extends AbstractLogEnabled
57  {
58      private static final Set<String> INTERPOLATION_BLACKLIST;
59  
60      private static final Properties ENVIRONMENT_VARIABLES;
61  
62      static
63      {
64          final Set<String> blacklist = new HashSet<String>();
65  
66          blacklist.add( "outputFileNameMapping" );
67          blacklist.add( "outputDirectoryMapping" );
68          blacklist.add( "outputDirectory" );
69  
70          INTERPOLATION_BLACKLIST = blacklist;
71  
72          Properties environmentVariables;
73          try
74          {
75              environmentVariables = CommandLineUtils.getSystemEnvVars( false );
76          }
77          catch ( final IOException e )
78          {
79              environmentVariables = new Properties();
80          }
81  
82          ENVIRONMENT_VARIABLES = environmentVariables;
83      }
84  
85      public AssemblyInterpolator()
86          throws IOException
87      {
88      }
89  
90      public Assembly interpolate( final Assembly assembly, final MavenProject project,
91                                   final AssemblerConfigurationSource configSource )
92          throws AssemblyInterpolationException
93      {
94          @SuppressWarnings( "unchecked" )
95          final Set<String> blacklistFields =
96              new HashSet<String>( FieldBasedObjectInterpolator.DEFAULT_BLACKLISTED_FIELD_NAMES );
97          blacklistFields.addAll( INTERPOLATION_BLACKLIST );
98  
99          @SuppressWarnings( "unchecked" )
100         final Set<String> blacklistPkgs = FieldBasedObjectInterpolator.DEFAULT_BLACKLISTED_PACKAGE_PREFIXES;
101 
102         final FieldBasedObjectInterpolator objectInterpolator =
103             new FieldBasedObjectInterpolator( blacklistFields, blacklistPkgs );
104         final Interpolator interpolator = buildInterpolator( project, configSource );
105 
106         // TODO: Will this adequately detect cycles between prefixed property references and prefixed project
107         // references??
108         final RecursionInterceptor interceptor =
109             new PrefixAwareRecursionInterceptor( InterpolationConstants.PROJECT_PREFIXES, true );
110 
111         try
112         {
113             objectInterpolator.interpolate( assembly, interpolator, interceptor );
114         }
115         catch ( final InterpolationException e )
116         {
117             throw new AssemblyInterpolationException( "Failed to interpolate assembly with ID: " + assembly.getId()
118                             + ". Reason: " + e.getMessage(), e );
119         }
120         finally
121         {
122             interpolator.clearAnswers();
123         }
124 
125         if ( objectInterpolator.hasWarnings() && getLogger().isDebugEnabled() )
126         {
127             final StringBuilder sb = new StringBuilder();
128 
129             sb.append("One or more minor errors occurred while interpolating the assembly with ID: ").append(assembly.getId()).append(":\n");
130 
131             @SuppressWarnings( "unchecked" )
132             final List<ObjectInterpolationWarning> warnings = objectInterpolator.getWarnings();
133             for (final ObjectInterpolationWarning warning : warnings) {
134                 sb.append('\n').append(warning);
135             }
136 
137             sb.append( "\n\nThese values were SKIPPED, but the assembly process will continue.\n" );
138 
139             getLogger().debug( sb.toString() );
140         }
141 
142         return assembly;
143     }
144 
145     public static Interpolator buildInterpolator( final MavenProject project,
146                                                   final AssemblerConfigurationSource configSource )
147     {
148         final StringSearchInterpolator interpolator = new StringSearchInterpolator();
149         interpolator.setCacheAnswers( true );
150 
151         final MavenSession session = configSource.getMavenSession();
152 
153         if ( session != null )
154         {
155             Properties userProperties = null;
156             try
157             {
158                 userProperties = session.getExecutionProperties();
159             }
160             catch ( final NoSuchMethodError nsmer )
161             {
162                 // OK, so user is using Maven <= 2.0.8. No big deal.
163             }
164 
165             if ( userProperties != null )
166             {
167                 // 4
168                 interpolator.addValueSource( new PropertiesBasedValueSource( userProperties ) );
169             }
170         }
171 
172         interpolator.addValueSource( new PrefixedPropertiesValueSource(
173                                                                         InterpolationConstants.PROJECT_PROPERTIES_PREFIXES,
174                                                                         project.getProperties(), true ) );
175         interpolator.addValueSource( new PrefixedObjectValueSource( InterpolationConstants.PROJECT_PREFIXES, project,
176                                                                     true ) );
177 
178         final Properties settingsProperties = new Properties();
179         if ( configSource.getLocalRepository() != null )
180         {
181             settingsProperties.setProperty( "localRepository", configSource.getLocalRepository().getBasedir() );
182             settingsProperties.setProperty( "settings.localRepository", configSource.getLocalRepository().getBasedir() );
183         }
184         else if ( session != null && session.getSettings() != null )
185         {
186             settingsProperties.setProperty( "localRepository", session.getSettings().getLocalRepository() );
187             settingsProperties.setProperty( "settings.localRepository", configSource.getLocalRepository().getBasedir() );
188         }
189 
190         interpolator.addValueSource( new PropertiesBasedValueSource( settingsProperties ) );
191 
192         Properties commandLineProperties = System.getProperties();
193         if ( session != null )
194         {
195             commandLineProperties = new Properties();
196             if ( session.getExecutionProperties() != null )
197             {
198                 commandLineProperties.putAll( session.getExecutionProperties() );
199             }
200             
201             if ( session.getUserProperties() != null )
202             {
203                 commandLineProperties.putAll( session.getUserProperties() );
204             }
205         }
206 
207         // 7
208         interpolator.addValueSource( new PropertiesBasedValueSource( commandLineProperties ) );
209         interpolator.addValueSource( new PrefixedPropertiesValueSource( Collections.singletonList( "env." ),
210                                                                         ENVIRONMENT_VARIABLES, true ) );
211 
212         interpolator.addPostProcessor( new PathTranslatingPostProcessor( project.getBasedir() ) );
213         return interpolator;
214     }
215 
216     @Override
217     protected Logger getLogger()
218     {
219         Logger logger = super.getLogger();
220 
221         if ( logger == null )
222         {
223             logger = new ConsoleLogger( Logger.LEVEL_INFO, "interpolator-internal" );
224 
225             enableLogging( logger );
226         }
227 
228         return logger;
229     }
230 
231     private static final class PathTranslatingPostProcessor
232         implements InterpolationPostProcessor
233     {
234 
235         private final File basedir;
236 
237         public PathTranslatingPostProcessor( final File basedir )
238         {
239             this.basedir = basedir;
240         }
241 
242         public Object execute( final String expression, final Object value )
243         {
244             final String path = String.valueOf( value );
245             return AssemblyFileUtils.makePathRelativeTo( path, basedir );
246         }
247 
248     }
249 }