org.sonar.dotnet.tools.commons.utils.FileFinder.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.dotnet.tools.commons.utils.FileFinder.java

Source

/*
 * .NET tools :: Commons
 * Copyright (C) 2010 Jose Chillan, Alexandre Victoor and SonarSource
 * dev@sonar.codehaus.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
 */
package org.sonar.dotnet.tools.commons.utils;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.utils.WildcardPattern;
import org.sonar.dotnet.tools.commons.visualstudio.VisualStudioProject;
import org.sonar.dotnet.tools.commons.visualstudio.VisualStudioSolution;

/**
 * Helper class to easily find files using ant style patterns, relative or absolute paths.
 * $(SolutionDir) can be used to specify the folder where the visual studio sln file is located.
 * "../" can be used to climb in the folder tree.
 * Absolute and relative paths are both supported.
 * 
 * @author Alexandre Victoor
 * 
 */
public final class FileFinder {

    private static final String SOLUTION_DIR_KEY = "$(SolutionDir)/";
    private static final String PARENT_DIRECTORY = "../";
    private static final Logger LOG = LoggerFactory.getLogger(FileFinder.class);

    private FileFinder() {
    }

    /**
     * Find files that match the given patterns
     * 
     * @param currentSolution
     *          The VS solution being analyzed by sonar
     * @param currentProject
     *          The VS project being analyzed
     * @param patterns
     *          A list of paths or ant style patterns delimited by a comma or a semi-comma
     * @return The files found on the filesystem
     */
    public static Collection<File> findFiles(VisualStudioSolution currentSolution,
            VisualStudioProject currentProject, String patterns) {
        String[] patternArray = StringUtils.split(patterns, ",;");
        return findFiles(currentSolution, currentProject, patternArray);
    }

    /**
     * Find directories that match the given patterns
     * 
     * @param currentSolution
     *          The VS solution being analyzed by sonar
     * @param currentProject
     *          The VS project being analyzed
     * @param patternArray
     *          A list of paths or ant style patterns
     * @return The directories found on the filesystem
     */
    public static Collection<File> findDirectories(VisualStudioSolution currentSolution,
            VisualStudioProject currentProject, String... patternArray) {
        Collection<File> files = findFiles(currentSolution, currentProject, patternArray);
        Collection<File> directories = new ArrayList<File>();
        for (File file : files) {
            if (file.isDirectory()) {
                directories.add(file);
            }
        }
        return directories;
    }

    /**
     * Find files that match the given patterns
     * 
     * @param currentSolution
     *          The VS solution being analyzed by sonar
     * @param currentProject
     *          The VS project being analyzed
     * @param patternArray
     *          A list of paths or ant style patterns
     * @return The files found on the filesystem
     */
    @SuppressWarnings("unchecked")
    public static Collection<File> findFiles(VisualStudioSolution currentSolution,
            VisualStudioProject currentProject, String... patternArray) {

        if (patternArray == null || patternArray.length == 0) {
            return Collections.EMPTY_LIST;
        }

        Set<File> result = new HashSet<File>();
        for (String pattern : patternArray) {
            String currentPattern = convertSlash(pattern);
            File workDir = currentProject.getDirectory();
            if (StringUtils.startsWith(pattern, SOLUTION_DIR_KEY)) {
                workDir = currentSolution.getSolutionDir();
                currentPattern = StringUtils.substringAfter(currentPattern, SOLUTION_DIR_KEY);
            }
            while (StringUtils.startsWith(currentPattern, PARENT_DIRECTORY)) {
                workDir = workDir.getParentFile();
                currentPattern = StringUtils.substringAfter(currentPattern, PARENT_DIRECTORY);
            }
            if (StringUtils.contains(currentPattern, '*')) {
                String prefix = StringUtils.substringBefore(currentPattern, "*");
                if (StringUtils.contains(prefix, '/')) {
                    workDir = browse(workDir, prefix);
                    currentPattern = "*" + StringUtils.substringAfter(currentPattern, "*");
                }
                IOFileFilter externalFilter = new PatternFilter(workDir, currentPattern);
                listFiles(result, workDir, externalFilter);

            } else {
                result.add(browse(workDir, currentPattern));
            }
        }

        if (LOG.isDebugEnabled()) {
            if (result.isEmpty()) {
                LOG.warn("No file found using pattern(s) " + StringUtils.join(patternArray, ','));
            } else {
                LOG.debug("The following files have been found using pattern(s) "
                        + StringUtils.join(patternArray, ',') + "\n" + StringUtils.join(result, "\n  "));
            }
        }

        return result;
    }

    public static File browse(File workDir, String path) {
        if (StringUtils.isEmpty(path)) {
            return workDir;
        }
        File file = new File(path);
        if (!file.exists() || !file.isAbsolute()) {
            File currentWorkDir = workDir;
            String currentPath = path;
            while (StringUtils.startsWith(currentPath, PARENT_DIRECTORY)) {
                currentWorkDir = currentWorkDir.getParentFile();
                currentPath = StringUtils.substringAfter(currentPath, PARENT_DIRECTORY);
            }
            file = new File(currentWorkDir, currentPath);
        }

        return file;
    }

    private static void listFiles(Collection<File> files, File directory, IOFileFilter filter) {
        if (!directory.exists() || directory.isFile()) {
            return;
        }

        File[] found = directory.listFiles((FileFilter) filter);
        if (found != null) {
            files.addAll(Arrays.asList(found));
        }
        File[] subDirectories = directory.listFiles((FileFilter) DirectoryFileFilter.INSTANCE);
        for (File subDirectory : subDirectories) {
            listFiles(files, subDirectory, filter);
        }
    }

    private static String convertSlash(String path) {
        return StringUtils.replaceChars(path, '\\', '/');
    }

    private static class PatternFilter implements IOFileFilter {

        private final WildcardPattern pattern;

        public PatternFilter(File workDir, String pattern) {
            String absolutePathPattern = workDir.getAbsolutePath() + "/" + pattern;
            absolutePathPattern = convertSlash(absolutePathPattern);
            this.pattern = WildcardPattern.create(absolutePathPattern);
        }

        public boolean accept(File paramFile) {
            String absolutePath = paramFile.getAbsolutePath();
            final String path = absolutePath;
            return pattern.match(convertSlash(path));
        }

        public boolean accept(File dir, String name) {
            return accept(new File(dir, name));
        }

    }

}