001 package net.sourceforge.pmd.util;
002
003 import java.io.File;
004 import java.io.FilenameFilter;
005 import java.io.IOException;
006 import java.util.ArrayList;
007 import java.util.Collections;
008 import java.util.Enumeration;
009 import java.util.List;
010 import java.util.zip.ZipEntry;
011 import java.util.zip.ZipFile;
012
013 import net.sourceforge.pmd.util.datasource.DataSource;
014 import net.sourceforge.pmd.util.datasource.FileDataSource;
015 import net.sourceforge.pmd.util.datasource.ZipDataSource;
016 import net.sourceforge.pmd.util.filter.AndFilter;
017 import net.sourceforge.pmd.util.filter.Filter;
018 import net.sourceforge.pmd.util.filter.Filters;
019 import net.sourceforge.pmd.util.filter.OrFilter;
020
021 /**
022 * This is a utility class for working with Files.
023 */
024 public final class FileUtil {
025
026 private FileUtil() {}
027
028 /**
029 * Helper method to get a filename without its extension
030 * @param fileName String
031 * @return String
032 */
033 public static String getFileNameWithoutExtension(String fileName) {
034 String name = fileName;
035
036 int index = fileName.lastIndexOf('.');
037 if (index != -1) {
038 name = fileName.substring(0, index);
039 }
040
041 return name;
042 }
043
044 /**
045 * Collects a list of DataSources using a comma separated list of input file
046 * locations to process. If a file location is a directory, the directory
047 * hierarchy will be traversed to look for files. If a file location is a
048 * ZIP or Jar the archive will be scanned looking for files. If a file
049 * location is a file, it will be used. For each located file, a
050 * FilenameFilter is used to decide whether to return a DataSource.
051 *
052 * @param fileLocations A comma-separated list of file locations.
053 * @param filenameFilter The FilenameFilter to apply to files.
054 * @return A list of DataSources, one for each file collected.
055 */
056 public static List<DataSource> collectFiles(String fileLocations, FilenameFilter filenameFilter) {
057 List<DataSource> dataSources = new ArrayList<DataSource>();
058 for (String fileLocation : fileLocations.split(",")) {
059 collect(dataSources, fileLocation, filenameFilter);
060 }
061 return dataSources;
062 }
063
064 private static List<DataSource> collect(List<DataSource> dataSources, String fileLocation,
065 FilenameFilter filenameFilter) {
066 File file = new File(fileLocation);
067 if (!file.exists()) {
068 throw new RuntimeException("File " + file.getName() + " doesn't exist");
069 }
070 if (!file.isDirectory()) {
071 if (fileLocation.endsWith(".zip") || fileLocation.endsWith(".jar")) {
072 ZipFile zipFile;
073 try {
074 zipFile = new ZipFile(fileLocation);
075 Enumeration<? extends ZipEntry> e = zipFile.entries();
076 while (e.hasMoreElements()) {
077 ZipEntry zipEntry = e.nextElement();
078 if (filenameFilter.accept(null, zipEntry.getName())) {
079 dataSources.add(new ZipDataSource(zipFile, zipEntry));
080 }
081 }
082 } catch (IOException ze) {
083 throw new RuntimeException("Archive file " + file.getName() + " can't be opened");
084 }
085 } else {
086 dataSources.add(new FileDataSource(file));
087 }
088 } else {
089 // Match files, or directories which are not excluded.
090 // FUTURE Make the excluded directories be some configurable option
091 Filter<File> filter = new OrFilter<File>(Filters.toFileFilter(filenameFilter), new AndFilter<File>(Filters
092 .getDirectoryFilter(), Filters.toNormalizedFileFilter(Filters.buildRegexFilterExcludeOverInclude(
093 null, Collections.singletonList("SCCS")))));
094 FileFinder finder = new FileFinder();
095 List<File> files = finder.findFilesFrom(file.getAbsolutePath(), Filters.toFilenameFilter(filter), true);
096 for (File f : files) {
097 dataSources.add(new FileDataSource(f));
098 }
099 }
100 return dataSources;
101 }
102 }
|