View Javadoc

1   package org.apache.maven.shared.filtering;
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 org.apache.maven.execution.MavenSession;
23  import org.apache.maven.project.MavenProject;
24  import org.apache.maven.settings.Settings;
25  import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
26  import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
27  import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
28  import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
29  import org.codehaus.plexus.interpolation.RecursionInterceptor;
30  import org.codehaus.plexus.interpolation.SimpleRecursionInterceptor;
31  import org.codehaus.plexus.interpolation.SingleResponseValueSource;
32  import org.codehaus.plexus.interpolation.ValueSource;
33  import org.codehaus.plexus.interpolation.multi.MultiDelimiterStringSearchInterpolator;
34  import org.codehaus.plexus.logging.AbstractLogEnabled;
35  import org.codehaus.plexus.util.FileUtils;
36  import org.codehaus.plexus.util.StringUtils;
37  import org.sonatype.plexus.build.incremental.BuildContext;
38  
39  import java.io.File;
40  import java.io.IOException;
41  import java.io.Reader;
42  import java.util.ArrayList;
43  import java.util.Collections;
44  import java.util.Iterator;
45  import java.util.LinkedHashSet;
46  import java.util.List;
47  import java.util.Properties;
48  
49  /**
50   * @author Olivier Lamy
51   *
52   * @plexus.component role="org.apache.maven.shared.filtering.MavenFileFilter"
53   * role-hint="default"
54   */
55  public class DefaultMavenFileFilter
56      extends AbstractLogEnabled
57      implements MavenFileFilter
58  {
59  
60      /**
61       * @plexus.requirement
62       */
63      private BuildContext buildContext;
64  
65      public void copyFile( File from, File to, boolean filtering, MavenProject mavenProject, List<String> filters,
66                            boolean escapedBackslashesInFilePath, String encoding, MavenSession mavenSession )
67          throws MavenFilteringException
68      {
69          MavenResourcesExecution mre = new MavenResourcesExecution();
70          mre.setMavenProject( mavenProject );
71          mre.setFileFilters( filters );
72          mre.setEscapeWindowsPaths( escapedBackslashesInFilePath );
73          mre.setMavenSession( mavenSession );
74          mre.setInjectProjectBuildFilters( true );
75  
76          List<FileUtils.FilterWrapper> filterWrappers = getDefaultFilterWrappers( mre );
77          copyFile( from, to, filtering, filterWrappers, encoding );
78      }
79  
80  
81      public void copyFile( MavenFileFilterRequest mavenFileFilterRequest )
82          throws MavenFilteringException
83      {
84          List filterWrappers = getDefaultFilterWrappers( mavenFileFilterRequest );
85  
86          copyFile( mavenFileFilterRequest.getFrom(), mavenFileFilterRequest.getTo(),
87                    mavenFileFilterRequest.isFiltering(), filterWrappers, mavenFileFilterRequest.getEncoding() );
88      }
89  
90  
91      public void copyFile( File from, File to, boolean filtering, List<FileUtils.FilterWrapper> filterWrappers,
92                            String encoding )
93          throws MavenFilteringException
94      {
95          // overwrite forced to false to preserve backward comp
96          copyFile( from, to, filtering, filterWrappers, encoding, false );
97      }
98  
99  
100     public void copyFile( File from, File to, boolean filtering, List<FileUtils.FilterWrapper> filterWrappers,
101                           String encoding, boolean overwrite )
102         throws MavenFilteringException
103     {
104         try
105         {
106             if ( filtering )
107             {
108                 if ( getLogger().isDebugEnabled() )
109                 {
110                     getLogger().debug( "filtering " + from.getPath() + " to " + to.getPath() );
111                 }
112                 FileUtils.FilterWrapper[] wrappers = (FileUtils.FilterWrapper[]) filterWrappers.toArray(
113                     new FileUtils.FilterWrapper[filterWrappers.size()] );
114                 FileUtils.copyFile( from, to, encoding, wrappers );
115             }
116             else
117             {
118                 if ( getLogger().isDebugEnabled() )
119                 {
120                     getLogger().debug( "copy " + from.getPath() + " to " + to.getPath() );
121                 }
122                 FileUtils.copyFile( from, to, encoding, new FileUtils.FilterWrapper[0], overwrite );
123             }
124 
125             buildContext.refresh( to );
126         }
127         catch ( IOException e )
128         {
129             throw new MavenFilteringException( e.getMessage(), e );
130         }
131 
132     }
133 
134     /**
135      * @see org.apache.maven.shared.filtering.MavenFileFilter#getDefaultFilterWrappers(org.apache.maven.project.MavenProject, java.util.List, boolean, org.apache.maven.execution.MavenSession)
136      * @deprecated
137      */
138     public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final MavenProject mavenProject,
139                                                                    List<String> filters,
140                                                                    final boolean escapedBackslashesInFilePath,
141                                                                    MavenSession mavenSession )
142         throws MavenFilteringException
143     {
144         return getDefaultFilterWrappers( mavenProject, filters, escapedBackslashesInFilePath, mavenSession, null );
145     }
146 
147 
148     public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final MavenProject mavenProject, List<String> filters,
149                                                                    final boolean escapedBackslashesInFilePath,
150                                                                    MavenSession mavenSession,
151                                                                    MavenResourcesExecution mavenResourcesExecution )
152         throws MavenFilteringException
153     {
154 
155         MavenResourcesExecution mre =
156             mavenResourcesExecution == null ? new MavenResourcesExecution() : mavenResourcesExecution.copyOf();
157 
158         mre.setMavenProject( mavenProject );
159         mre.setMavenSession( mavenSession );
160         mre.setFilters( filters );
161         mre.setEscapedBackslashesInFilePath( escapedBackslashesInFilePath );
162 
163         return getDefaultFilterWrappers( mre );
164 
165     }
166 
167     public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final AbstractMavenFilteringRequest req )
168         throws MavenFilteringException
169     {
170         // backup values
171         boolean supportMultiLineFiltering = req.isSupportMultiLineFiltering();
172 
173         // compensate for null parameter value.
174         final AbstractMavenFilteringRequest request = req == null ? new MavenFileFilterRequest() : req;
175 
176         request.setSupportMultiLineFiltering( supportMultiLineFiltering );
177 
178         // Here we build some properties which will be used to read some properties files
179         // to interpolate the expression ${ } in this properties file
180 
181         // Take a copy of filterProperties to ensure that evaluated filterTokens are not propagated
182         // to subsequent filter files. Note: this replicates current behaviour and seems to make sense.
183 
184         final Properties baseProps = new Properties();
185 
186         // Project properties
187         if ( request.getMavenProject() != null )
188         {
189             baseProps.putAll( request.getMavenProject().getProperties() == null
190                                   ? Collections.emptyMap()
191                                   : request.getMavenProject().getProperties() );
192         }
193         // TODO this is NPE free but do we consider this as normal
194         // or do we have to throw an MavenFilteringException with mavenSession cannot be null
195         if ( request.getMavenSession() != null )
196         {
197             // execution properties wins
198             baseProps.putAll( request.getMavenSession().getExecutionProperties() );
199         }
200 
201         // now we build properties to use for resources interpolation
202 
203         final Properties filterProperties = new Properties();
204 
205         loadProperties( filterProperties, request.getFileFilters(), baseProps );
206         if ( filterProperties.size() < 1 )
207         {
208             filterProperties.putAll( baseProps );
209         }
210 
211         if ( request.getMavenProject() != null )
212         {
213             if ( request.isInjectProjectBuildFilters() )
214             {
215                 List<String> buildFilters = new ArrayList( request.getMavenProject().getBuild().getFilters() );
216                 buildFilters.removeAll( request.getFileFilters() );
217 
218                 loadProperties( filterProperties, buildFilters, baseProps );
219             }
220 
221             // Project properties
222             filterProperties.putAll( request.getMavenProject().getProperties() == null
223                                          ? Collections.emptyMap()
224                                          : request.getMavenProject().getProperties() );
225         }
226         if ( request.getMavenSession() != null )
227         {
228             // execution properties wins
229             filterProperties.putAll( request.getMavenSession().getExecutionProperties() );
230         }
231 
232         if ( request.getAdditionalProperties() != null )
233         {
234             // additional properties wins
235             filterProperties.putAll( request.getAdditionalProperties() );
236         }
237 
238         List<FileUtils.FilterWrapper> defaultFilterWrappers = request == null
239             ? new ArrayList<FileUtils.FilterWrapper>( 1 )
240             : new ArrayList<FileUtils.FilterWrapper>( request.getDelimiters().size() + 1 );
241 
242         if ( getLogger().isDebugEnabled() )
243         {
244             getLogger().debug( "properties used " + filterProperties );
245         }
246 
247         final ValueSource propertiesValueSource = new PropertiesBasedValueSource( filterProperties );
248 
249         if ( request != null )
250         {
251             FileUtils.FilterWrapper wrapper =
252                 new Wrapper( request.getDelimiters(), request.getMavenProject(), request.getMavenSession(),
253                              propertiesValueSource, request.getProjectStartExpressions(), request.getEscapeString(),
254                              request.isEscapeWindowsPaths(), request.isSupportMultiLineFiltering() );
255 
256             defaultFilterWrappers.add( wrapper );
257         }
258 
259         return defaultFilterWrappers;
260     }
261 
262     /**
263      * protected only for testing reason !
264      */
265     protected void loadProperties( Properties filterProperties, List<String> propertiesFilePaths, Properties baseProps )
266         throws MavenFilteringException
267     {
268         if ( propertiesFilePaths != null )
269         {
270             Properties workProperties = new Properties();
271             workProperties.putAll( baseProps );
272 
273             for ( Iterator iterator = propertiesFilePaths.iterator(); iterator.hasNext(); )
274             {
275                 String filterFile = (String) iterator.next();
276                 if ( StringUtils.isEmpty( filterFile ) )
277                 {
278                     // skip empty file name
279                     continue;
280                 }
281                 try
282                 {
283                     // TODO new File should be new File(mavenProject.getBasedir(), filterfile ) ?
284                     Properties properties = PropertyUtils.loadPropertyFile( new File( filterFile ), workProperties );
285                     filterProperties.putAll( properties );
286                     workProperties.putAll( properties );
287                 }
288                 catch ( IOException e )
289                 {
290                     throw new MavenFilteringException( "Error loading property file '" + filterFile + "'", e );
291                 }
292             }
293         }
294     }
295 
296     private static final class Wrapper
297         extends FileUtils.FilterWrapper
298     {
299 
300         private LinkedHashSet<String> delimiters;
301 
302         private MavenProject project;
303 
304         private ValueSource propertiesValueSource;
305 
306         private List<String> projectStartExpressions;
307 
308         private String escapeString;
309 
310         private boolean escapeWindowsPaths;
311 
312         private final MavenSession mavenSession;
313 
314         private boolean supportMultiLineFiltering;
315 
316         Wrapper( LinkedHashSet<String> delimiters, MavenProject project, MavenSession mavenSession,
317                  ValueSource propertiesValueSource, List<String> projectStartExpressions, String escapeString,
318                  boolean escapeWindowsPaths, boolean supportMultiLineFiltering )
319         {
320             super();
321             this.delimiters = delimiters;
322             this.project = project;
323             this.mavenSession = mavenSession;
324             this.propertiesValueSource = propertiesValueSource;
325             this.projectStartExpressions = projectStartExpressions;
326             this.escapeString = escapeString;
327             this.escapeWindowsPaths = escapeWindowsPaths;
328             this.supportMultiLineFiltering = supportMultiLineFiltering;
329         }
330 
331         public Reader getReader( Reader reader )
332         {
333             MultiDelimiterStringSearchInterpolator interpolator = new MultiDelimiterStringSearchInterpolator();
334             interpolator.setDelimiterSpecs( delimiters );
335 
336             RecursionInterceptor ri = null;
337             if ( projectStartExpressions != null && !projectStartExpressions.isEmpty() )
338             {
339                 ri = new PrefixAwareRecursionInterceptor( projectStartExpressions, true );
340             }
341             else
342             {
343                 ri = new SimpleRecursionInterceptor();
344             }
345 
346             interpolator.addValueSource( propertiesValueSource );
347 
348             if ( project != null )
349             {
350                 interpolator.addValueSource( new PrefixedObjectValueSource( projectStartExpressions, project, true ) );
351             }
352 
353             if ( mavenSession != null )
354             {
355                 interpolator.addValueSource( new PrefixedObjectValueSource( "session", mavenSession ) );
356 
357                 final Settings settings = mavenSession.getSettings();
358                 if ( settings != null )
359                 {
360                     interpolator.addValueSource( new PrefixedObjectValueSource( "settings", settings ) );
361                     interpolator.addValueSource(
362                         new SingleResponseValueSource( "localRepository", settings.getLocalRepository() ) );
363                 }
364             }
365 
366             interpolator.setEscapeString( escapeString );
367 
368             if ( escapeWindowsPaths )
369             {
370                 interpolator.addPostProcessor( new InterpolationPostProcessor()
371                 {
372                     public Object execute( String expression, Object value )
373                     {
374                         if ( value instanceof String )
375                         {
376                             return FilteringUtils.escapeWindowsPath( (String) value );
377                         }
378 
379                         return value;
380                     }
381                 } );
382             }
383 
384             MultiDelimiterInterpolatorFilterReaderLineEnding filterReader =
385                 new MultiDelimiterInterpolatorFilterReaderLineEnding( reader, interpolator, supportMultiLineFiltering );
386             filterReader.setRecursionInterceptor( ri );
387             filterReader.setDelimiterSpecs( delimiters );
388 
389             filterReader.setInterpolateWithPrefixPattern( false );
390             filterReader.setEscapeString( escapeString );
391 
392             return filterReader;
393         }
394 
395     }
396 
397 }