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.model.Resource;
24  import org.apache.maven.project.MavenProject;
25  import org.codehaus.plexus.logging.AbstractLogEnabled;
26  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
27  import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
28  import org.codehaus.plexus.util.FileUtils;
29  import org.codehaus.plexus.util.PathTool;
30  import org.codehaus.plexus.util.ReaderFactory;
31  import org.codehaus.plexus.util.Scanner;
32  import org.codehaus.plexus.util.StringUtils;
33  import org.sonatype.plexus.build.incremental.BuildContext;
34  
35  import java.io.File;
36  import java.io.IOException;
37  import java.util.ArrayList;
38  import java.util.Arrays;
39  import java.util.List;
40  
41  /**
42   * @author Olivier Lamy
43   * @plexus.component role="org.apache.maven.shared.filtering.MavenResourcesFiltering"
44   * role-hint="default"
45   */
46  public class DefaultMavenResourcesFiltering
47      extends AbstractLogEnabled
48      implements MavenResourcesFiltering, Initializable
49  {
50  
51      private static final String[] EMPTY_STRING_ARRAY = { };
52  
53      private static final String[] DEFAULT_INCLUDES = { "**/**" };
54  
55      private List<String> defaultNonFilteredFileExtensions;
56  
57      /**
58       * @plexus.requirement
59       */
60      private BuildContext buildContext;
61  
62      // ------------------------------------------------
63      //  Plexus lifecycle
64      // ------------------------------------------------
65      public void initialize()
66          throws InitializationException
67      {
68          // jpg,jpeg,gif,bmp,png
69          this.defaultNonFilteredFileExtensions = new ArrayList<String>( 5 );
70          this.defaultNonFilteredFileExtensions.add( "jpg" );
71          this.defaultNonFilteredFileExtensions.add( "jpeg" );
72          this.defaultNonFilteredFileExtensions.add( "gif" );
73          this.defaultNonFilteredFileExtensions.add( "bmp" );
74          this.defaultNonFilteredFileExtensions.add( "png" );
75      }
76  
77  
78      /**
79       * @plexus.requirement role-hint="default"
80       */
81      private MavenFileFilter mavenFileFilter;
82  
83      public void filterResources( List<Resource> resources, File outputDirectory, MavenProject mavenProject,
84                                   String encoding, List<String> fileFilters, List<String> nonFilteredFileExtensions,
85                                   MavenSession mavenSession )
86          throws MavenFilteringException
87      {
88          MavenResourcesExecution mavenResourcesExecution =
89              new MavenResourcesExecution( resources, outputDirectory, mavenProject, encoding, fileFilters,
90                                           nonFilteredFileExtensions, mavenSession );
91          mavenResourcesExecution.setUseDefaultFilterWrappers( true );
92  //        mavenResourcesExecution.setEscapeWindowsPaths( false );
93  
94          filterResources( mavenResourcesExecution );
95      }
96  
97      public void filterResources( List<Resource> resources, File outputDirectory, String encoding,
98                                   List<FileUtils.FilterWrapper> filterWrappers, File resourcesBaseDirectory,
99                                   List<String> nonFilteredFileExtensions )
100         throws MavenFilteringException
101     {
102         MavenResourcesExecution mavenResourcesExecution =
103             new MavenResourcesExecution( resources, outputDirectory, encoding, filterWrappers, resourcesBaseDirectory,
104                                          nonFilteredFileExtensions );
105         filterResources( mavenResourcesExecution );
106     }
107 
108 
109     public boolean filteredFileExtension( String fileName, List<String> userNonFilteredFileExtensions )
110     {
111         List<String> nonFilteredFileExtensions = new ArrayList<String>( getDefaultNonFilteredFileExtensions() );
112         if ( userNonFilteredFileExtensions != null )
113         {
114             nonFilteredFileExtensions.addAll( userNonFilteredFileExtensions );
115         }
116         boolean filteredFileExtension =
117             !nonFilteredFileExtensions.contains( StringUtils.lowerCase( FileUtils.extension( fileName ) ) );
118         if ( getLogger().isDebugEnabled() )
119         {
120             getLogger().debug(
121                 "file " + fileName + " has a" + ( filteredFileExtension ? " " : " non " ) + "filtered file extension" );
122         }
123         return filteredFileExtension;
124     }
125 
126     public List<String> getDefaultNonFilteredFileExtensions()
127     {
128         if ( this.defaultNonFilteredFileExtensions == null )
129         {
130             this.defaultNonFilteredFileExtensions = new ArrayList<String>();
131         }
132         return this.defaultNonFilteredFileExtensions;
133     }
134 
135     public void filterResources( MavenResourcesExecution mavenResourcesExecution )
136         throws MavenFilteringException
137     {
138         if ( mavenResourcesExecution == null )
139         {
140             throw new MavenFilteringException( "mavenResourcesExecution cannot be null" );
141         }
142 
143         if ( mavenResourcesExecution.getResources() == null )
144         {
145             getLogger().info( "No resources configured skip copying/filtering" );
146             return;
147         }
148 
149         if ( mavenResourcesExecution.getOutputDirectory() == null )
150         {
151             throw new MavenFilteringException( "outputDirectory cannot be null" );
152         }
153 
154         if ( mavenResourcesExecution.isUseDefaultFilterWrappers() )
155         {
156             List<FileUtils.FilterWrapper> filterWrappers = new ArrayList<FileUtils.FilterWrapper>();
157             if ( mavenResourcesExecution.getFilterWrappers() != null )
158             {
159                 filterWrappers.addAll( mavenResourcesExecution.getFilterWrappers() );
160             }
161             filterWrappers.addAll( mavenFileFilter.getDefaultFilterWrappers( mavenResourcesExecution ) );
162             mavenResourcesExecution.setFilterWrappers( filterWrappers );
163         }
164 
165         if ( mavenResourcesExecution.getEncoding() == null || mavenResourcesExecution.getEncoding().length() < 1 )
166         {
167             getLogger().warn( "Using platform encoding (" + ReaderFactory.FILE_ENCODING
168                                   + " actually) to copy filtered resources, i.e. build is platform dependent!" );
169         }
170         else
171         {
172             getLogger().info(
173                 "Using '" + mavenResourcesExecution.getEncoding() + "' encoding to copy filtered resources." );
174         }
175 
176         for ( Resource resource : mavenResourcesExecution.getResources() )
177         {
178 
179             if ( getLogger().isDebugEnabled() )
180             {
181                 String ls = System.getProperty( "line.separator" );
182                 StringBuffer debugMessage =
183                     new StringBuffer( "resource with targetPath " + resource.getTargetPath() ).append( ls );
184                 debugMessage.append( "directory " + resource.getDirectory() ).append( ls );
185                 debugMessage.append( "excludes " + ( resource.getExcludes() == null
186                     ? " empty "
187                     : resource.getExcludes().toString() ) ).append( ls );
188                 debugMessage.append(
189                     "includes " + ( resource.getIncludes() == null ? " empty " : resource.getIncludes().toString() ) );
190                 getLogger().debug( debugMessage.toString() );
191             }
192 
193             String targetPath = resource.getTargetPath();
194 
195             File resourceDirectory = new File( resource.getDirectory() );
196 
197             if ( !resourceDirectory.isAbsolute() )
198             {
199                 resourceDirectory =
200                     new File( mavenResourcesExecution.getResourcesBaseDirectory(), resourceDirectory.getPath() );
201             }
202 
203             if ( !resourceDirectory.exists() )
204             {
205                 getLogger().info( "skip non existing resourceDirectory " + resourceDirectory.getPath() );
206                 continue;
207             }
208 
209             // this part is required in case the user specified "../something" as destination
210             // see MNG-1345
211             File outputDirectory = mavenResourcesExecution.getOutputDirectory();
212             boolean outputExists = outputDirectory.exists();
213             if ( !outputExists && !outputDirectory.mkdirs() )
214             {
215                 throw new MavenFilteringException( "Cannot create resource output directory: " + outputDirectory );
216             }
217 
218             boolean ignoreDelta = !outputExists || buildContext.hasDelta( mavenResourcesExecution.getFileFilters() )
219                 || buildContext.hasDelta( getRelativeOutputDirectory( mavenResourcesExecution ) );
220             getLogger().debug( "ignoreDelta " + ignoreDelta );
221             Scanner scanner = buildContext.newScanner( resourceDirectory, ignoreDelta );
222 
223             setupScanner( resource, scanner );
224 
225             scanner.scan();
226 
227             if ( mavenResourcesExecution.isIncludeEmptyDirs() )
228             {
229                 try
230                 {
231                     File targetDirectory =
232                         targetPath == null ? outputDirectory : new File( outputDirectory, targetPath );
233                     copyDirectoryLayout( resourceDirectory, targetDirectory, scanner );
234                 }
235                 catch ( IOException e )
236                 {
237                     throw new MavenFilteringException(
238                         "Cannot copy directory structure from " + resourceDirectory.getPath() + " to "
239                             + outputDirectory.getPath() );
240                 }
241             }
242 
243             List<String> includedFiles = Arrays.asList( scanner.getIncludedFiles() );
244 
245             getLogger().info(
246                 "Copying " + includedFiles.size() + " resource" + ( includedFiles.size() > 1 ? "s" : "" ) + (
247                     targetPath == null ? "" : " to " + targetPath ) );
248 
249             for ( String name : includedFiles )
250             {
251 
252                 File source = new File( resourceDirectory, name );
253 
254                 //File destinationFile = new File( outputDirectory, destination );
255 
256                 File destinationFile = getDestinationFile( outputDirectory, targetPath, name );
257 
258                 boolean filteredExt =
259                     filteredFileExtension( source.getName(), mavenResourcesExecution.getNonFilteredFileExtensions() );
260 
261                 mavenFileFilter.copyFile( source, destinationFile, resource.isFiltering() && filteredExt,
262                                           mavenResourcesExecution.getFilterWrappers(),
263                                           mavenResourcesExecution.getEncoding(),
264                                           mavenResourcesExecution.isOverwrite() );
265             }
266 
267             // deal with deleted source files
268 
269             scanner = buildContext.newDeleteScanner( resourceDirectory );
270 
271             setupScanner( resource, scanner );
272 
273             scanner.scan();
274 
275             List<String> deletedFiles = Arrays.asList( scanner.getIncludedFiles() );
276 
277             for ( String name : deletedFiles )
278             {
279                 File destinationFile = getDestinationFile( outputDirectory, targetPath, name );
280 
281                 destinationFile.delete();
282 
283                 buildContext.refresh( destinationFile );
284             }
285 
286         }
287 
288     }
289 
290     private File getDestinationFile( File outputDirectory, String targetPath, String name )
291     {
292         String destination = name;
293 
294         if ( targetPath != null )
295         {
296             destination = targetPath + "/" + name;
297         }
298 
299         File destinationFile = new File( destination );
300         if ( !destinationFile.isAbsolute() )
301         {
302             destinationFile = new File( outputDirectory, destination );
303         }
304 
305         if ( !destinationFile.getParentFile().exists() )
306         {
307             destinationFile.getParentFile().mkdirs();
308         }
309         return destinationFile;
310     }
311 
312     private String[] setupScanner( Resource resource, Scanner scanner )
313     {
314         String[] includes = null;
315         if ( resource.getIncludes() != null && !resource.getIncludes().isEmpty() )
316         {
317             includes = (String[]) resource.getIncludes().toArray( EMPTY_STRING_ARRAY );
318         }
319         else
320         {
321             includes = DEFAULT_INCLUDES;
322         }
323         scanner.setIncludes( includes );
324 
325         String[] excludes = null;
326         if ( resource.getExcludes() != null && !resource.getExcludes().isEmpty() )
327         {
328             excludes = (String[]) resource.getExcludes().toArray( EMPTY_STRING_ARRAY );
329             scanner.setExcludes( excludes );
330         }
331 
332         scanner.addDefaultExcludes();
333         return includes;
334     }
335 
336     private void copyDirectoryLayout( File sourceDirectory, File destinationDirectory, Scanner scanner )
337         throws IOException
338     {
339         if ( sourceDirectory == null )
340         {
341             throw new IOException( "source directory can't be null." );
342         }
343 
344         if ( destinationDirectory == null )
345         {
346             throw new IOException( "destination directory can't be null." );
347         }
348 
349         if ( sourceDirectory.equals( destinationDirectory ) )
350         {
351             throw new IOException( "source and destination are the same directory." );
352         }
353 
354         if ( !sourceDirectory.exists() )
355         {
356             throw new IOException( "Source directory doesn't exists (" + sourceDirectory.getAbsolutePath() + ")." );
357         }
358 
359         List<String> includedDirectories = Arrays.asList( scanner.getIncludedDirectories() );
360 
361         for ( String name : includedDirectories )
362         {
363             File source = new File( sourceDirectory, name );
364 
365             if ( source.equals( sourceDirectory ) )
366             {
367                 continue;
368             }
369 
370             File destination = new File( destinationDirectory, name );
371             destination.mkdirs();
372         }
373     }
374 
375     private String getRelativeOutputDirectory( MavenResourcesExecution execution )
376     {
377         String relOutDir = execution.getOutputDirectory().getAbsolutePath();
378 
379         if ( execution.getMavenProject() != null && execution.getMavenProject().getBasedir() != null )
380         {
381             String basedir = execution.getMavenProject().getBasedir().getAbsolutePath();
382             relOutDir = PathTool.getRelativeFilePath( basedir, relOutDir );
383             if ( relOutDir == null )
384             {
385                 relOutDir = execution.getOutputDirectory().getPath();
386             }
387             else
388             {
389                 relOutDir = relOutDir.replace( '\\', '/' );
390             }
391         }
392 
393         return relOutDir;
394     }
395 
396 }