1 19 20 package org.netbeans.modules.junit.output.antutils; 21 22 import java.io.File ; 23 import java.util.ArrayList ; 24 import java.util.Arrays ; 25 import java.util.Collection ; 26 import java.util.Collections ; 27 import java.util.Iterator ; 28 import java.util.List ; 29 import java.util.StringTokenizer ; 30 import java.util.regex.Matcher ; 31 import java.util.regex.Pattern ; 32 import org.netbeans.modules.junit.output.antutils.FileSetScanner.AntPattern.PatternPartType; 33 import org.netbeans.modules.junit.output.antutils.FileUtils; 34 35 39 class FileSetScanner { 40 41 42 private static final String [] DEFAULT_EXCLUDES = new String [] { 43 "**/*~", "**/#*#", "**/.#*", "**/%*%", "**/._*", "**/CVS", "**/CVS/**", "**/.cvsignore", "**/SCCS", "**/SCCS/**", "**/vssver.scc", "**/.svn", "**/.svn/**", "**/.DS_Store" }; 58 59 60 private static final String [] EMPTY_STRING_ARR = new String [0]; 61 62 63 private final FileSet fileSet; 64 65 66 private File baseDir; 67 68 private boolean caseSensitive; 69 70 private boolean followSymlinks; 71 72 private AntPattern[] includePatterns; 73 74 private AntPattern[] excludePatterns; 75 76 78 static Collection <File > listFiles(FileSet fileSet) { 79 return new FileSetScanner(fileSet).getMatchingFiles(); 80 } 81 82 84 FileSetScanner(FileSet fileSet) { 85 this.fileSet = fileSet; 86 } 87 88 90 Collection <File > getMatchingFiles() { 91 File file = fileSet.getFile(); 92 93 if (file != null) { 94 file = FileUtils.resolveFile(fileSet.getBaseDir(), file.getName()); 95 if (file.exists()) { 96 return Collections.singleton(file); 97 } else { 98 return Collections.emptyList(); 99 } 100 } 101 102 this.baseDir = fileSet.getBaseDir(); 103 this.caseSensitive = fileSet.isCaseSensitive(); 104 this.followSymlinks = fileSet.isFollowSymlinks(); 105 preparePatterns(); 106 findMatchingFiles(); 107 return matchingFiles; 108 } 109 110 111 private Collection <File > matchingFiles; 112 113 115 private void findMatchingFiles() { 116 matchingFiles = new ArrayList <File >(32); 117 findMatchingFiles(baseDir, createPatternTests(includePatterns, 118 excludePatterns)); 119 } 120 121 123 private void findMatchingFiles( 124 final File directory, 125 final Collection <PatternTest> patternTests) { 126 127 final File [] children = directory.listFiles(); 128 for (File child : children) { 129 final boolean isFile = child.isFile(); 130 final boolean isDir = child.isDirectory(); 131 if (!isFile && !isDir) { 132 continue; } 135 136 Collection <PatternTest> childTests; 137 138 childTests = isDir ? new ArrayList <PatternTest>(patternTests.size()) 139 : null; 140 boolean matches = checkFileAgainstPatterns(child, 141 patternTests, 142 childTests); 143 if (matches) { 144 if (isFile) { 145 matchingFiles.add(child); 146 } else { 147 findMatchingFiles(child, childTests); 148 } 149 } 150 } 151 } 152 153 155 private boolean checkFileAgainstPatterns( 156 final File file, 157 final Collection <PatternTest> tests, 158 final Collection <PatternTest> childrenTests) { 159 160 assert !tests.isEmpty(); 161 assert tests.iterator().next().includePattern; 162 163 final boolean isDir = childrenTests != null; 164 final boolean isFile = !isDir; 165 166 boolean matches = false; 167 for (PatternTest patternTest : tests) { 168 final AntPattern pattern = patternTest.pattern; 169 final boolean isIncludePattern = patternTest.includePattern; 170 final int partIndex = patternTest.patternPartIndex; 171 final PatternPartType partType = 172 pattern.patternPartTypes[partIndex]; 173 final boolean isLastPart = pattern.isLastPart(partIndex); 174 175 188 189 if (isIncludePattern && isLastPart 190 && partType == PatternPartType.DOUBLE_STAR) { 191 192 193 198 matches = true; 199 childrenTests.add(patternTest); 200 continue; 201 } 202 203 if (isFile && (!isLastPart || (matches && isIncludePattern))) { 204 205 continue; 206 } 207 if (isDir && isLastPart 208 && (partType != PatternPartType.DOUBLE_STAR)) { 209 210 continue; 211 } 212 213 final boolean nameMatches = 214 (partType == PatternPartType.DOUBLE_STAR) 215 || isMatchingFile(file, pattern, partIndex); 216 if (!nameMatches) { 217 218 continue; 219 } 220 221 if (!isLastPart) { 222 223 assert isDir; 225 if (isIncludePattern) { 226 matches = true; 227 } 228 229 int nextPartIndex = partIndex + 1; 230 PatternPartType nextPartType = 231 pattern.patternPartTypes[nextPartIndex]; 232 if (partType != PatternPartType.DOUBLE_STAR 233 && nextPartType == PatternPartType.DOUBLE_STAR 234 && pattern.isLastPart(nextPartIndex)) { 235 239 if (isIncludePattern) { 240 246 childrenTests.clear(); 247 childrenTests.add(new PatternTest(pattern, 248 isIncludePattern, 249 nextPartIndex)); 250 255 } else { 256 260 matches = false; 261 break; 262 } 263 } else { 264 childrenTests.add(new PatternTest(pattern, 265 isIncludePattern, 266 partIndex + 1)); 267 if (partType == PatternPartType.DOUBLE_STAR) { 268 childrenTests.add(patternTest); 269 } 270 } 271 } else { 272 273 if (isIncludePattern) { 274 assert !isDir; 276 matches = true; 277 } else { 278 matches = false; 279 break; 280 } 281 } 282 } 283 return matches; 284 } 285 286 288 private boolean isMatchingFile(final File file, 289 final AntPattern pattern, 290 final int partIndex) { 291 assert file.isDirectory() || file.isFile(); 292 293 final String name = file.getName(); 294 final PatternPartType patternType = pattern.patternPartTypes[partIndex]; 295 296 assert patternType == PatternPartType.PLAIN 297 || patternType == PatternPartType.REGEXP; 298 299 if (patternType == PatternPartType.PLAIN) { 300 final String fileNamePattern = pattern.patternParts[partIndex]; 301 return caseSensitive 302 ? name.equals(fileNamePattern) 303 : name.equalsIgnoreCase(fileNamePattern); 304 } else { 305 Pattern patternPartMatcher = 306 pattern.getPatternPartMatcher(partIndex, caseSensitive); 307 assert pattern.patternPartMatchers[partIndex] != null; 308 return pattern.patternPartMatchers[partIndex].matcher(name) 309 .matches(); 310 } 311 } 312 313 315 private static Collection <PatternTest> createPatternTests( 316 final AntPattern[] includePatterns, 317 final AntPattern[] excludePatterns) { 318 Collection <PatternTest> result = 319 new ArrayList <PatternTest>(includePatterns.length 320 + excludePatterns.length); 321 326 for (AntPattern pattern : includePatterns) { 327 if (pattern.patternPartTypes[0] == PatternPartType.DOUBLE_STAR) { 328 if (pattern.isLastPart(0)) { 329 333 result.clear(); 334 result.add(new PatternTest(pattern, true, 0)); 335 break; 336 } else { 337 result.add(new PatternTest(pattern, true, 1)); 338 } 339 } 340 result.add(new PatternTest(pattern, true, 0)); 341 } 342 for (AntPattern pattern : excludePatterns) { 343 if (pattern.patternPartTypes[0] == PatternPartType.DOUBLE_STAR) { 344 if (pattern.isLastPart(0)) { 345 350 return Collections.emptyList(); 351 } else { 352 result.add(new PatternTest(pattern, false, 1)); 353 } 354 } 355 result.add(new PatternTest(pattern, false, 0)); 356 } 357 return result; 358 } 359 360 377 private void preparePatterns() { 378 Collection <String > patterns; 379 380 381 patterns = fileSet.getIncludePatterns(); 382 if (patterns.isEmpty()) { 383 patterns = Collections.singletonList("**"); } 385 includePatterns = parsePatternStrings(patterns); 386 387 388 patterns = fileSet.getExcludesPatterns(); 389 if (fileSet.isDefaultExcludes()) { 390 Collection <String > defExcludes = Arrays.asList(DEFAULT_EXCLUDES); 391 if (patterns.isEmpty()) { 392 patterns = defExcludes; 393 } else { 394 patterns.addAll(defExcludes); 395 } 396 } 397 excludePatterns = parsePatternStrings(patterns); 398 } 399 400 408 private AntPattern[] parsePatternStrings( 409 Collection <String > patternStrings) { 410 final AntPattern[] patterns = new AntPattern[patternStrings.size()]; 411 final Iterator <String > it = patternStrings.iterator(); 412 for (int i = 0; i < patterns.length; i++) { 413 patterns[i] = parsePatternString(it.next()); 414 } 415 return patterns; 416 } 417 418 426 AntPattern parsePatternString(String patternString) { 427 if ((patternString.length() != 0) 428 && (patternString.charAt(0) == File.separatorChar)) { 429 assert false : "corner case - not implemented"; } 431 432 List <String > tokens = new ArrayList <String >(6); 433 boolean lastWasDoubleStar = false; 434 int tokenStart = 0; 435 String token; 436 int slashIndex = patternString.indexOf(File.separatorChar); 437 while (slashIndex != -1) { 438 token = patternString.substring(tokenStart, slashIndex); 439 440 boolean isDoubleStar = token.equals("**"); if (!(isDoubleStar && lastWasDoubleStar)) { 442 tokens.add(patternString.substring(tokenStart, slashIndex)); 443 } 444 lastWasDoubleStar = isDoubleStar; 445 446 tokenStart = slashIndex + 1; 447 slashIndex = patternString.indexOf(File.separatorChar, 448 tokenStart); 449 } 450 if (tokenStart == patternString.length()) { token = "**"; } else { 453 token = patternString.substring(tokenStart); 454 } 455 if (!(lastWasDoubleStar && token.equals("**"))) { tokens.add(token); 457 } 458 459 String [] patternParts = new String [tokens.size()]; 460 tokens.toArray(patternParts); 461 return new AntPattern(patternParts); 462 } 463 464 465 468 static final class PatternTest { 469 final AntPattern pattern; 470 final boolean includePattern; 471 int patternPartIndex; 472 PatternTest(AntPattern pattern, boolean includePattern, int index) { 473 this.pattern = pattern; 474 this.includePattern = includePattern; 475 this.patternPartIndex = index; 476 } 477 } 478 479 482 static final class AntPattern { 483 private static final int CASE_SENSITIVE_FLAGS = 0; 484 private static final int CASE_INSENSITIVE_FLAGS = 485 Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE; 486 enum PatternPartType { 487 DOUBLE_STAR, 488 REGEXP, 489 PLAIN 490 } 491 final String [] patternParts; 492 final PatternPartType[] patternPartTypes; 493 private final Pattern [] patternPartMatchers; 494 AntPattern(String [] patternParts) { 495 if (patternParts == null) { 496 throw new IllegalArgumentException ( 497 "patternParts: null"); } 499 500 this.patternParts = patternParts; 501 502 patternPartTypes = new PatternPartType[patternParts.length]; 503 patternPartMatchers = new Pattern [patternParts.length]; 504 for (int i = 0; i < patternParts.length; i++) { 505 final String pattern = patternParts[i]; 506 PatternPartType patternPartType; 507 if (pattern.equals("**")) { patternPartType = PatternPartType.DOUBLE_STAR; 509 } else if (pattern.indexOf('*') != -1 510 || pattern.indexOf('?') != -1) { 511 patternPartType = PatternPartType.REGEXP; 512 } else { 513 patternPartType = PatternPartType.PLAIN; 514 } 515 patternPartTypes[i] = patternPartType; 516 } 517 } 518 Pattern getPatternPartMatcher(final int partIndex, 519 final boolean caseSensitive) { 520 Pattern matcher = patternPartMatchers[partIndex]; 521 if (matcher == null) { 522 matcher = Pattern.compile( 523 makeJdkPattern(patternParts[partIndex]), 524 caseSensitive ? CASE_SENSITIVE_FLAGS 525 : CASE_INSENSITIVE_FLAGS); 526 patternPartMatchers[partIndex] = matcher; 527 } 528 return matcher; 529 } 530 538 static String makeJdkPattern(String antRegexp) { 539 StringBuilder buf = new StringBuilder (antRegexp.length() + 16); 540 StringTokenizer tokenizer = 541 new StringTokenizer (antRegexp, "*?", true); while (tokenizer.hasMoreTokens()) { 543 String token = tokenizer.nextToken(); 544 if (token.length() == 0) { 545 continue; 546 } 547 if (token.equals("?")) { buf.append(token); 549 } else if (token.equals("*")) { buf.append(".*"); } else { 552 buf.append(quote(token)); 553 } 554 } 555 return buf.toString(); 556 } 557 566 static String quote(String str) { 567 final String SPECIAL_CHARS = "\\.[](){}+^$|?*"; StringBuilder buf = null; 569 char[] chars = str.toCharArray(); 570 for (int i = 0; i < chars.length; i++) { 571 char c = chars[i]; 572 if (SPECIAL_CHARS.indexOf(c) != -1) { 573 if (buf == null) { 574 buf = new StringBuilder (str.length() + 10); 575 buf.append(str.substring(0, i)); 576 } 577 buf.append('\\'); 578 } 579 if (buf != null) { 580 buf.append(c); 581 } 582 } 583 return buf != null ? buf.toString() : str; 584 } 585 boolean isLastPart(int index) { 586 return index == (patternParts.length - 1); 587 } 588 @Override 589 public boolean equals(Object object) { 590 return (object != null) 591 && (object.getClass() == AntPattern.class) 592 && Arrays.equals(patternParts, 593 ((AntPattern) object).patternParts); 594 } 595 @Override 596 public String toString() { 597 String patternsString; 598 if (patternParts.length == 0) { 599 patternsString = "[]"; } else { 601 StringBuilder buf = new StringBuilder (256); 602 buf.append('['); 603 buf.append(patternParts[0]); 604 for (int i = 1; i < patternParts.length; i++) { 605 buf.append(',').append(patternParts[i]); 606 } 607 buf.append(']'); 608 patternsString = buf.toString(); 609 } 610 return super.toString() + patternsString; 611 } 612 } 613 614 } 615 | Popular Tags |