0
# File Pattern Matching
1
2
File pattern matching utilities provide Ant-style include/exclude pattern support for file discovery, scanning, and filtering operations in build automation and file processing tasks.
3
4
## Capabilities
5
6
### FileNameFinder
7
8
Groovy utility class for finding files using Ant-style patterns with include/exclude support.
9
10
```java { .api }
11
/**
12
* Find files according to a base directory and includes/excludes patterns.
13
* Patterns conform to Ant's fileset pattern conventions.
14
*/
15
public class FileNameFinder implements IFileNameFinder {
16
/** Find files using base directory and include pattern */
17
public List<String> getFileNames(String basedir, String pattern);
18
19
/** Find files using base directory, include pattern, and exclude pattern */
20
public List<String> getFileNames(String basedir, String pattern, String excludesPattern);
21
22
/** Find files using configuration map with named parameters */
23
public List<String> getFileNames(Map args);
24
}
25
26
/**
27
* Interface for file name finding functionality.
28
*/
29
public interface IFileNameFinder {
30
/** Core file finding method with base directory and pattern */
31
List<String> getFileNames(String basedir, String pattern);
32
33
/** Extended file finding with exclude patterns */
34
List<String> getFileNames(String basedir, String pattern, String excludesPattern);
35
36
/** Flexible file finding with named parameters */
37
List<String> getFileNames(Map args);
38
}
39
```
40
41
### FileScanner
42
43
Low-level file scanning utility integrated with Ant's DirectoryScanner functionality.
44
45
```java { .api }
46
/**
47
* Ant-integrated file scanner for pattern-based file discovery.
48
* Provides iterator-style access to matched files.
49
*/
50
public class FileScanner {
51
/** Set the base directory for scanning */
52
public void setDir(File dir);
53
54
/** Get the base directory */
55
public File getDir();
56
57
/** Set include patterns (comma or space separated) */
58
public void setIncludes(String includes);
59
60
/** Get include patterns */
61
public String getIncludes();
62
63
/** Set exclude patterns (comma or space separated) */
64
public void setExcludes(String excludes);
65
66
/** Get exclude patterns */
67
public String getExcludes();
68
69
/** Set whether to follow symbolic links */
70
public void setFollowSymlinks(boolean followSymlinks);
71
72
/** Check if following symbolic links */
73
public boolean isFollowSymlinks();
74
75
/** Set whether to use default excludes (like .svn, .git) */
76
public void setDefaultexcludes(boolean useDefaultExcludes);
77
78
/** Check if using default excludes */
79
public boolean getDefaultexcludes();
80
81
/** Add include pattern */
82
public void addInclude(String pattern);
83
84
/** Add exclude pattern */
85
public void addExclude(String pattern);
86
87
/** Get array of included files */
88
public String[] getIncludedFiles();
89
90
/** Get array of included directories */
91
public String[] getIncludedDirectories();
92
93
/** Scan directory and populate results */
94
public void scan();
95
}
96
```
97
98
### FileIterator
99
100
Iterator interface for traversing files matched by patterns.
101
102
```java { .api }
103
/**
104
* Iterator for traversing files matched by scanning patterns.
105
* Integrates with Java's Iterator pattern for easy file processing.
106
*/
107
public class FileIterator implements java.util.Iterator<File> {
108
/** Check if more files are available */
109
public boolean hasNext();
110
111
/** Get the next file in the iteration */
112
public File next();
113
114
/** Remove current file (operation not supported) */
115
public void remove() throws UnsupportedOperationException;
116
}
117
```
118
119
## Pattern Syntax
120
121
Ant-style patterns support the following wildcards:
122
123
```java { .api }
124
/**
125
* Pattern matching syntax for file selection.
126
*/
127
public interface PatternSyntax {
128
/** Single character wildcard - matches any single character except path separators */
129
String SINGLE_CHAR = "?";
130
131
/** Multi-character wildcard - matches zero or more characters except path separators */
132
String MULTI_CHAR = "*";
133
134
/** Directory wildcard - matches zero or more directories */
135
String DIR_WILDCARD = "**/";
136
137
/** Path separator - platform independent */
138
String PATH_SEP = "/";
139
}
140
```
141
142
### Pattern Examples
143
144
- `*.java` - All Java files in base directory
145
- `**/*.groovy` - All Groovy files in any subdirectory
146
- `src/**/*.java` - All Java files under src directory tree
147
- `**/test/**/*.class` - All class files in any test directory
148
- `**/*Test.java` - All Java files ending with "Test"
149
- `com/example/**` - All files under com/example package structure
150
151
## Usage Examples
152
153
### Basic File Finding
154
```groovy
155
import groovy.util.FileNameFinder
156
157
def finder = new FileNameFinder()
158
159
// Find all Groovy files
160
def groovyFiles = finder.getFileNames("src", "**/*.groovy")
161
groovyFiles.each { file ->
162
println "Found: $file"
163
}
164
165
// Find Java files, excluding test files
166
def javaFiles = finder.getFileNames("src", "**/*.java", "**/*Test.java")
167
println "Found ${javaFiles.size()} non-test Java files"
168
```
169
170
### Map-Based Configuration
171
```groovy
172
def finder = new FileNameFinder()
173
174
// Using named parameters
175
def configFiles = finder.getFileNames(
176
dir: "config",
177
includes: "**/*.properties,**/*.xml",
178
excludes: "**/test/**"
179
)
180
181
// Process configuration files
182
configFiles.each { configFile ->
183
println "Processing config: $configFile"
184
// Load and validate configuration
185
}
186
```
187
188
### Integration with AntBuilder
189
```groovy
190
import groovy.util.AntBuilder
191
import groovy.util.FileNameFinder
192
193
def ant = new AntBuilder()
194
def finder = new FileNameFinder()
195
196
// Find source files to compile
197
def sourceFiles = finder.getFileNames(
198
dir: "src/main/groovy",
199
includes: "**/*.groovy",
200
excludes: "**/internal/**"
201
)
202
203
if (sourceFiles) {
204
println "Compiling ${sourceFiles.size()} source files"
205
206
ant.groovyc(destdir: "build/classes") {
207
sourceFiles.each { sourceFile ->
208
src(file: sourceFile)
209
}
210
}
211
}
212
```
213
214
### File Processing Pipeline
215
```groovy
216
def finder = new FileNameFinder()
217
218
// Find and process different file types
219
def processFiles = { pattern, processor ->
220
def files = finder.getFileNames(".", pattern)
221
files.each { file ->
222
processor(new File(file))
223
}
224
}
225
226
// Process properties files
227
processFiles("**/*.properties") { file ->
228
def props = new Properties()
229
file.withInputStream { props.load(it) }
230
println "$file.name has ${props.size()} properties"
231
}
232
233
// Process XML files
234
processFiles("**/*.xml") { file ->
235
def xml = new XmlSlurper().parse(file)
236
println "$file.name root element: ${xml.name()}"
237
}
238
```
239
240
### Directory Scanner Usage
241
```groovy
242
import org.codehaus.groovy.ant.FileScanner
243
import groovy.util.AntBuilder
244
245
def ant = new AntBuilder()
246
247
// Create scanner through AntBuilder
248
def scanner = ant.fileScanner {
249
fileset(dir: "src") {
250
include(name: "**/*.groovy")
251
include(name: "**/*.java")
252
exclude(name: "**/test/**")
253
exclude(name: "**/*Test.*")
254
}
255
}
256
257
// Iterate through matched files
258
scanner.each { file ->
259
println "Processing: ${file.absolutePath}"
260
261
// Analyze file properties
262
def lines = file.readLines()
263
def size = file.length()
264
println " Lines: ${lines.size()}, Size: ${size} bytes"
265
}
266
```
267
268
### Conditional File Operations
269
```groovy
270
def finder = new FileNameFinder()
271
272
// Find outdated files that need recompilation
273
def sourceFiles = finder.getFileNames("src", "**/*.groovy")
274
def classFiles = finder.getFileNames("build/classes", "**/*.class")
275
276
def outdatedSources = sourceFiles.findAll { srcPath ->
277
def srcFile = new File(srcPath)
278
def classPath = srcPath.replace("src/", "build/classes/")
279
.replace(".groovy", ".class")
280
def classFile = new File(classPath)
281
282
!classFile.exists() || srcFile.lastModified() > classFile.lastModified()
283
}
284
285
if (outdatedSources) {
286
println "Recompiling ${outdatedSources.size()} outdated files"
287
// Trigger compilation
288
} else {
289
println "All files are up to date"
290
}
291
```
292
293
### Archive Content Analysis
294
```groovy
295
import java.util.zip.ZipFile
296
297
def finder = new FileNameFinder()
298
299
// Find all JAR files in dependencies
300
def jarFiles = finder.getFileNames("lib", "**/*.jar")
301
302
jarFiles.each { jarPath ->
303
def jarFile = new ZipFile(jarPath)
304
def entries = jarFile.entries().toList()
305
306
println "Analyzing $jarPath:"
307
println " Total entries: ${entries.size()}"
308
309
// Count different file types
310
def classCount = entries.count { it.name.endsWith('.class') }
311
def resourceCount = entries.count { !it.name.endsWith('.class') && !it.directory }
312
313
println " Classes: $classCount"
314
println " Resources: $resourceCount"
315
316
jarFile.close()
317
}
318
```
319
320
### Build Artifact Management
321
```groovy
322
def finder = new FileNameFinder()
323
324
// Clean up old build artifacts
325
def cleanupOldArtifacts = {
326
def artifactPatterns = [
327
"build/**/*.class",
328
"build/**/*.jar",
329
"dist/**/*.zip",
330
"**/*.tmp"
331
]
332
333
artifactPatterns.each { pattern ->
334
def files = finder.getFileNames(".", pattern)
335
files.each { filePath ->
336
def file = new File(filePath)
337
if (file.exists()) {
338
println "Removing: $filePath"
339
file.delete()
340
}
341
}
342
}
343
}
344
345
// Find test reports for archiving
346
def archiveTestReports = {
347
def reports = finder.getFileNames(
348
dir: "build",
349
includes: "**/TEST-*.xml,**/test-results/**/*.html",
350
excludes: "**/tmp/**"
351
)
352
353
if (reports) {
354
println "Archiving ${reports.size()} test reports"
355
// Create archive with reports
356
}
357
}
358
359
cleanupOldArtifacts()
360
archiveTestReports()
361
```
362
363
### Multi-Project File Discovery
364
```groovy
365
def finder = new FileNameFinder()
366
367
// Find all build files across subprojects
368
def findProjectFiles = { rootDir ->
369
def buildFiles = [:]
370
371
// Find Gradle build files
372
buildFiles.gradle = finder.getFileNames(rootDir, "**/build.gradle")
373
374
// Find Maven POM files
375
buildFiles.maven = finder.getFileNames(rootDir, "**/pom.xml")
376
377
// Find Ant build files
378
buildFiles.ant = finder.getFileNames(rootDir, "**/build.xml")
379
380
return buildFiles
381
}
382
383
def projectFiles = findProjectFiles(".")
384
385
projectFiles.each { buildSystem, files ->
386
if (files) {
387
println "$buildSystem projects found:"
388
files.each { file ->
389
println " $file"
390
}
391
}
392
}
393
```
394
395
## Advanced Pattern Matching
396
397
### Complex Include/Exclude Combinations
398
```groovy
399
def finder = new FileNameFinder()
400
401
// Complex pattern matching for code analysis
402
def analyzeCodebase = {
403
def codeFiles = finder.getFileNames(
404
dir: "src",
405
includes: "**/*.java,**/*.groovy,**/*.scala",
406
excludes: [
407
"**/test/**", // No test files
408
"**/generated/**", // No generated code
409
"**/*\$*.java", // No inner class files
410
"**/package-info.java" // No package info files
411
].join(",")
412
)
413
414
// Categorize by language
415
def byLanguage = codeFiles.groupBy { file ->
416
def ext = file.substring(file.lastIndexOf('.') + 1)
417
return ext
418
}
419
420
byLanguage.each { lang, files ->
421
println "$lang files: ${files.size()}"
422
}
423
424
return codeFiles
425
}
426
427
def codeFiles = analyzeCodebase()
428
```