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