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