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.io.DefaultAssemblyReader;
33  import org.apache.maven.plugin.assembly.model.Assembly;
34  import org.apache.maven.plugin.assembly.utils.AssemblyFileUtils;
35  import org.apache.maven.plugin.assembly.utils.InterpolationConstants;
36  import org.apache.maven.project.MavenProject;
37  import org.codehaus.plexus.interpolation.InterpolationException;
38  import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
39  import org.codehaus.plexus.interpolation.Interpolator;
40  import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
41  import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
42  import org.codehaus.plexus.interpolation.PrefixedPropertiesValueSource;
43  import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
44  import org.codehaus.plexus.interpolation.RecursionInterceptor;
45  import org.codehaus.plexus.interpolation.StringSearchInterpolator;
46  import org.codehaus.plexus.interpolation.object.FieldBasedObjectInterpolator;
47  import org.codehaus.plexus.interpolation.object.ObjectInterpolationWarning;
48  import org.codehaus.plexus.logging.AbstractLogEnabled;
49  import org.codehaus.plexus.logging.Logger;
50  import org.codehaus.plexus.logging.console.ConsoleLogger;
51  import org.codehaus.plexus.util.cli.CommandLineUtils;
52  
53  /**
54   * @version $Id: AssemblyInterpolator.java 1632861 2014-10-18 23:23:32Z khmarbaise $
55   */
56  public class AssemblyInterpolator
57      extends AbstractLogEnabled
58  {
59      private static final Set<String> INTERPOLATION_BLACKLIST;
60  
61      private static final Properties ENVIRONMENT_VARIABLES;
62  
63      static
64      {
65          final Set<String> blacklist = new HashSet<String>();
66  
67          blacklist.add( "outputFileNameMapping" );
68          blacklist.add( "outputDirectoryMapping" );
69          blacklist.add( "outputDirectory" );
70  
71          INTERPOLATION_BLACKLIST = blacklist;
72  
73          Properties environmentVariables;
74          try
75          {
76              environmentVariables = CommandLineUtils.getSystemEnvVars( false );
77          }
78          catch ( final IOException e )
79          {
80              environmentVariables = new Properties();
81          }
82  
83          ENVIRONMENT_VARIABLES = environmentVariables;
84      }
85  
86      public AssemblyInterpolator()
87          throws IOException
88      {
89      }
90  
91      public Assembly interpolate( final Assembly assembly, final MavenProject project,
92                                   final AssemblerConfigurationSource configSource )
93          throws AssemblyInterpolationException
94      {
95          @SuppressWarnings( "unchecked" )
96          final Set<String> blacklistFields =
97              new HashSet<String>( FieldBasedObjectInterpolator.DEFAULT_BLACKLISTED_FIELD_NAMES );
98          blacklistFields.addAll( INTERPOLATION_BLACKLIST );
99  
100         @SuppressWarnings( "unchecked" )
101         final Set<String> blacklistPkgs = FieldBasedObjectInterpolator.DEFAULT_BLACKLISTED_PACKAGE_PREFIXES;
102 
103         final FieldBasedObjectInterpolator objectInterpolator =
104             new FieldBasedObjectInterpolator( blacklistFields, blacklistPkgs );
105         final Interpolator interpolator = buildInterpolator( project, configSource );
106 
107         // TODO: Will this adequately detect cycles between prefixed property references and prefixed project
108         // references??
109         final RecursionInterceptor interceptor =
110             new PrefixAwareRecursionInterceptor( InterpolationConstants.PROJECT_PREFIXES, true );
111 
112         try
113         {
114             objectInterpolator.interpolate( assembly, interpolator, interceptor );
115         }
116         catch ( final InterpolationException e )
117         {
118             throw new AssemblyInterpolationException( "Failed to interpolate assembly with ID: " + assembly.getId()
119                 + ". Reason: " + e.getMessage(), e );
120         }
121         finally
122         {
123             interpolator.clearAnswers();
124         }
125 
126         if ( objectInterpolator.hasWarnings() && getLogger().isDebugEnabled() )
127         {
128             final StringBuilder sb = new StringBuilder();
129 
130             sb.append( "One or more minor errors occurred while interpolating the assembly with ID: " ).append( assembly.getId() ).append( ":\n" );
131 
132             @SuppressWarnings( "unchecked" )
133             final List<ObjectInterpolationWarning> warnings = objectInterpolator.getWarnings();
134             for ( final ObjectInterpolationWarning warning : warnings )
135             {
136                 sb.append( '\n' ).append( warning );
137             }
138 
139             sb.append( "\n\nThese values were SKIPPED, but the assembly process will continue.\n" );
140 
141             getLogger().debug( sb.toString() );
142         }
143 
144         return assembly;
145     }
146 
147     public static Interpolator buildInterpolator( final MavenProject project,
148                                                   final AssemblerConfigurationSource configSource )
149     {
150         final StringSearchInterpolator interpolator = new StringSearchInterpolator();
151         interpolator.setCacheAnswers( true );
152 
153         final MavenSession session = configSource.getMavenSession();
154 
155         if ( session != null )
156         {
157             Properties userProperties = null;
158             try
159             {
160                 userProperties = session.getExecutionProperties();
161             }
162             catch ( final NoSuchMethodError nsmer )
163             {
164                 // OK, so user is using Maven <= 2.0.8. No big deal.
165             }
166 
167             if ( userProperties != null )
168             {
169                 // 4
170                 interpolator.addValueSource( new PropertiesBasedValueSource( userProperties ) );
171             }
172         }
173 
174         interpolator.addValueSource( new PrefixedPropertiesValueSource(
175                                                                         InterpolationConstants.PROJECT_PROPERTIES_PREFIXES,
176                                                                         project.getProperties(), true ) );
177         interpolator.addValueSource( new PrefixedObjectValueSource( InterpolationConstants.PROJECT_PREFIXES, project,
178                                                                     true ) );
179 
180         final Properties settingsProperties = new Properties();
181         if ( configSource.getLocalRepository() != null )
182         {
183             settingsProperties.setProperty( "localRepository", configSource.getLocalRepository().getBasedir() );
184             settingsProperties.setProperty( "settings.localRepository", configSource.getLocalRepository().getBasedir() );
185         }
186         else if ( session != null && session.getSettings() != null )
187         {
188             settingsProperties.setProperty( "localRepository", session.getSettings().getLocalRepository() );
189             settingsProperties.setProperty( "settings.localRepository", configSource.getLocalRepository().getBasedir() );
190         }
191 
192         interpolator.addValueSource( new PropertiesBasedValueSource( settingsProperties ) );
193 
194         Properties commandLineProperties = DefaultAssemblyReader.mergeExecutionPropertiesWithSystemPropertiew( session );
195 
196         // 7
197         interpolator.addValueSource( new PropertiesBasedValueSource( commandLineProperties ) );
198         interpolator.addValueSource( new PrefixedPropertiesValueSource( Collections.singletonList( "env." ),
199                                                                         ENVIRONMENT_VARIABLES, true ) );
200 
201         interpolator.addPostProcessor( new PathTranslatingPostProcessor( project.getBasedir() ) );
202         return interpolator;
203     }
204 
205     @Override
206     protected Logger getLogger()
207     {
208         Logger logger = super.getLogger();
209 
210         if ( logger == null )
211         {
212             logger = new ConsoleLogger( Logger.LEVEL_INFO, "interpolator-internal" );
213 
214             enableLogging( logger );
215         }
216 
217         return logger;
218     }
219 
220     private static final class PathTranslatingPostProcessor
221         implements InterpolationPostProcessor
222     {
223 
224         private final File basedir;
225 
226         public PathTranslatingPostProcessor( final File basedir )
227         {
228             this.basedir = basedir;
229         }
230 
231         public Object execute( final String expression, final Object value )
232         {
233             final String path = String.valueOf( value );
234             return AssemblyFileUtils.makePathRelativeTo( path, basedir );
235         }
236 
237     }
238 }