Package hudson.plugins.analysis.core

Source Code of hudson.plugins.analysis.core.FilesParser

package hudson.plugins.analysis.core;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;

import hudson.FilePath;
import hudson.FilePath.FileCallable;

import hudson.plugins.analysis.Messages;
import hudson.plugins.analysis.util.FileFinder;
import hudson.plugins.analysis.util.ModuleDetector;
import hudson.plugins.analysis.util.NullModuleDetector;
import hudson.plugins.analysis.util.PluginLogger;
import hudson.plugins.analysis.util.StringPluginLogger;
import hudson.plugins.analysis.util.model.FileAnnotation;

import hudson.remoting.VirtualChannel;

/**
* Parses files that match the specified pattern and creates a corresponding
* {@link ParserResult} with a collection of annotations.
*
* @author Ulli Hafner
*/
public class FilesParser implements FileCallable<ParserResult> {
    private static final long serialVersionUID = -6415863872891783891L;

    /** Logs into a string. @since 1.20 */
    @edu.umd.cs.findbugs.annotations.SuppressWarnings("Se")
    private transient StringPluginLogger stringLogger;

    /** Ant file-set pattern to scan for. */
    private final String filePattern;
    /** Parser to be used to process the workspace files. */
    private final AnnotationParser parser;
    /** Determines whether this build uses maven. */
    private final boolean isMavenBuild;
    /** The predefined module name, might be empty. */
    private final String moduleName;
    /** Determines whether module names should be derived from Maven or Ant. */
    private boolean shouldDetectModules = true;

    private final String pluginId;

    private final boolean canResolveRelativePaths;

    private FilesParser(final String filePattern, final AnnotationParser parser,
            final boolean isMavenBuild, final String moduleName) {
        this.filePattern = filePattern;
        this.parser = parser;
        this.isMavenBuild = isMavenBuild;
        this.moduleName = moduleName;
        pluginId = "[ANALYSIS] ";
        canResolveRelativePaths = true;
    }

    private FilesParser(final String pluginId, final String filePattern,
            final AnnotationParser parser, final boolean shouldDetectModules,
            final boolean isMavenBuild, final String moduleName,
            final boolean canResolveRelativePaths) {
        this.pluginId = pluginId;
        this.filePattern = filePattern;
        this.parser = parser;
        this.isMavenBuild = isMavenBuild;
        this.moduleName = moduleName;
        this.shouldDetectModules = shouldDetectModules;
        this.canResolveRelativePaths = canResolveRelativePaths;
    }

    /**
     * Creates a new instance of {@link FilesParser}. Since no file pattern is
     * given, this parser assumes that it is invoked on a file rather than on a
     * directory.
     *
     * @param pluginId
     *            the ID of the plug-in that uses this parser
     * @param parser
     *            the parser to apply on the found files
     * @param moduleName
     *            the name of the module to use for all files
     */
    public FilesParser(final String pluginId, final AnnotationParser parser, final String moduleName) {
        this(pluginId, "", parser, true, true, moduleName, true);
    }

    /**
     * Creates a new instance of {@link FilesParser}.
     *
     * @param pluginId
     *            the ID of the plug-in that uses this parser
     * @param filePattern
     *            ant file-set pattern to scan for files to parse
     * @param parser
     *            the parser to apply on the found files
     * @param moduleName
     *            the name of the module to use for all files
     */
    public FilesParser(final String pluginId, final String filePattern,
            final AnnotationParser parser, final String moduleName) {
        this(pluginId, filePattern, parser, true, true, moduleName, true);
    }

    /**
     * Creates a new instance of {@link FilesParser}.
     *
     * @param pluginId
     *            the ID of the plug-in that uses this parser
     * @param filePattern
     *            ant file-set pattern to scan for files to parse
     * @param parser
     *            the parser to apply on the found files
     * @param shouldDetectModules
     *            determines whether modules should be detected from pom.xml or
     *            build.xml files
     * @param isMavenBuild
     *            determines whether this build uses maven
     */
    public FilesParser(final String pluginId, final String filePattern,
            final AnnotationParser parser, final boolean shouldDetectModules,
            final boolean isMavenBuild) {
        this(pluginId, filePattern, parser, shouldDetectModules, isMavenBuild, true);
    }

    /**
     * Creates a new instance of {@link FilesParser}.
     *
     * @param pluginId
     *            the ID of the plug-in that uses this parser
     * @param filePattern
     *            ant file-set pattern to scan for files to parse
     * @param parser
     *            the parser to apply on the found files
     * @param shouldDetectModules
     *            determines whether modules should be detected from pom.xml or
     *            build.xml files
     * @param isMavenBuild
     *            determines whether this build uses maven
     * @param canResolveRelativePaths
     *            determines whether relative paths in warnings should be
     *            resolved using a time expensive operation that scans the whole
     *            workspace for matching files.
     */
    public FilesParser(final String pluginId, final String filePattern,
            final AnnotationParser parser, final boolean shouldDetectModules,
            final boolean isMavenBuild, final boolean canResolveRelativePaths) {
        this(pluginId, filePattern, parser, shouldDetectModules, isMavenBuild, StringUtils.EMPTY,
                canResolveRelativePaths);
    }

    /**
     * Logs the specified message.
     *
     * @param message
     *            the message
     */
    protected void log(final String message) {
        if (stringLogger == null) {
            stringLogger = new StringPluginLogger(pluginId);
        }
        stringLogger.log(message);
    }

    /**
     * Creates a formatted message in singular or plural form.
     *
     * @param count
     *            the number of occurrences
     * @param message
     *            the message containing the format in singular form
     * @return
     *            the message in singular or plural form depending on the count,
     *            or an empty string if the count is 0 and no format is specified
     */
    protected String plural(final int count, String message) {
        if (count == 0 && !message.contains("%")) {
            return "";
        }

        if (count != 1) {
            message += "s";
        }

        return String.format(message, count);
    }

    @Override
    public ParserResult invoke(final File workspace, final VirtualChannel channel)
            throws IOException {
        ParserResult result = new ParserResult(new FilePath(workspace), canResolveRelativePaths);
        try {
            if (StringUtils.isBlank(filePattern)) {
                parseSingleFile(workspace, result);
            }
            else {
                parserCollectionOfFiles(workspace, result);
            }
        }
        catch (InterruptedException exception) {
            log("Parsing has been canceled.");
        }

        if (stringLogger != null) {
            result.setLog(stringLogger.toString());
        }

        for (FileAnnotation annotation : result.getAnnotations()) {
            annotation.setPathName(workspace.getAbsolutePath());
        }
        return result;
    }

    private void parserCollectionOfFiles(final File workspace, final ParserResult result) throws InterruptedException {
        log("Finding all files that match the pattern " + filePattern);
        String[] fileNames = new FileFinder(filePattern).find(workspace);

        if (fileNames.length == 0) {
            if (isMavenBuild) {
                log("No files found in " + workspace.getAbsolutePath() + " for pattern: " + filePattern);
            }
            else {
                result.addErrorMessage(Messages.FilesParser_Error_NoFiles());
            }
        }
        else {
            log("Parsing " + plural(fileNames.length, "%d file") + " in " + workspace.getAbsolutePath());
            parseFiles(workspace, fileNames, result);
        }
    }

    private void parseSingleFile(final File workspace, final ParserResult result) throws InterruptedException {
        String[] fileNames = new String[] {workspace.getAbsolutePath()};
        log("Parsing file " + workspace.getAbsolutePath());
        parseFiles(workspace, fileNames, result);
    }

    /**
     * Parses the specified collection of files and appends the results to the
     * provided container.
     *
     * @param workspace
     *            the workspace root
     * @param fileNames
     *            the names of the file to parse
     * @param result
     *            the result of the parsing
     * @throws InterruptedException
     *             if the user cancels the parsing
     */
    private void parseFiles(final File workspace, final String[] fileNames,
            final ParserResult result) throws InterruptedException {
        ModuleDetector detector = createModuleDetector(workspace);

        for (String fileName : fileNames) {
            File file = new File(fileName);

            if (!file.isAbsolute()) {
                file = new File(workspace, fileName);
            }

            String module = getModuleName(detector, file);

            if (!file.canRead()) {
                String message = Messages.FilesParser_Error_NoPermission(module, file);
                log(message);
                result.addErrorMessage(module, message);
                continue;
            }
            if (file.length() <= 0) {
                String message = Messages.FilesParser_Error_EmptyFile(module, file);
                log(message);
                result.addErrorMessage(module, message);
                continue;
            }

            parseFile(file, module, result);

            result.addModule(module);
        }
    }

    private ModuleDetector createModuleDetector(final File workspace) {
        if (shouldDetectModules) {
            return new ModuleDetector(workspace);
        }
        else {
            return new NullModuleDetector();
        }
    }

    private String getModuleName(final ModuleDetector detector, final File file) {
        String module;
        if (StringUtils.isBlank(moduleName)) {
            module = detector.guessModuleName(file.getAbsolutePath());
        }
        else {
            module = moduleName;
        }
        return module;
    }

    /**
     * Parses the specified file and stores all found annotations. If the file
     * could not be parsed then an error message is appended to the result.
     *
     * @param file
     *            the file to parse
     * @param module
     *            the associated module
     * @param result
     *            the result of the parser
     * @throws InterruptedException
     *             if the user cancels the parsing
     */
    private void parseFile(final File file, final String module, final ParserResult result)
            throws InterruptedException {
        try {
            Collection<FileAnnotation> annotations = parser.parse(file, module);
            int duplicateCount = annotations.size() - result.addAnnotations(annotations);
            int moduleCount = StringUtils.isBlank(module) ? 0 : 1;

            log("Successfully parsed file " + file + plural(moduleCount, " of module " + module) + " with "
                    + plural(result.getNumberOfAnnotations(), "%d unique warning")
                    + plural(duplicateCount, " and %d duplicate") + ".");
        }
        catch (InvocationTargetException exception) {
            String errorMessage = Messages.FilesParser_Error_Exception(file)
                    + "\n\n"
                    + ExceptionUtils.getStackTrace((Throwable)ObjectUtils.defaultIfNull(
                            exception.getCause(), exception));
            result.addErrorMessage(module, errorMessage);

            log(errorMessage);
        }
    }

    /**
     * Creates a new instance of {@link FilesParser}.
     *
     * @param logger
     *            the logger
     * @param filePattern
     *            ant file-set pattern to scan for files to parse
     * @param parser
     *            the parser to apply on the found files
     * @param isMavenBuild
     *            determines whether this build uses maven
     * @deprecated Use
     *             {@link #FilesParser(String, String, AnnotationParser, boolean, boolean)}
     */
    @Deprecated
    @SuppressWarnings("PMD")
    public FilesParser(final PluginLogger logger, final String filePattern,
            final AnnotationParser parser, final boolean isMavenBuild) {
        this(filePattern, parser, isMavenBuild, StringUtils.EMPTY);
    }

    /**
     * Creates a new instance of {@link FilesParser}. Assumes that this is a
     * Maven build with the specified module name.
     *
     * @param logger
     *            the logger
     * @param filePattern
     *            ant file-set pattern to scan for files to parse
     * @param parser
     *            the parser to apply on the found files
     * @param moduleName
     *            the name of the module to use for all files
     * @deprecated Use
     *             {@link #FilesParser(String, String, AnnotationParser, boolean, boolean)}
     */
    @Deprecated
    @SuppressWarnings("PMD")
    public FilesParser(final PluginLogger logger, final String filePattern,
            final AnnotationParser parser, final String moduleName) {
        this(filePattern, parser, true, moduleName);
    }

    /**
     * Creates a new instance of {@link FilesParser}. Assumes that this is a
     * Maven build with the specified module name.
     *
     * @param logger
     *            the logger
     * @param filePattern
     *            ant file-set pattern to scan for files to parse
     * @param parser
     *            the parser to apply on the found files
     * @deprecated Use
     *             {@link #FilesParser(String, String, AnnotationParser, boolean, boolean)}
     */
    @Deprecated
    @SuppressWarnings("PMD")
    public FilesParser(final PluginLogger logger, final String filePattern,
            final AnnotationParser parser) {
        this(filePattern, parser, true, StringUtils.EMPTY);

        shouldDetectModules = false;
    }

    /**
     * Creates a new instance of {@link FilesParser}.
     *
     * @param logger
     *            the logger
     * @param filePattern
     *            ant file-set pattern to scan for files to parse
     * @param parser
     *            the parser to apply on the found files
     * @param moduleName
     *            the name of the module to use for all files
     * @deprecated Use
     *             {@link #FilesParser(String, String, AnnotationParser, boolean, boolean)}
     */
    @Deprecated
    @SuppressWarnings("PMD")
    public FilesParser(final StringPluginLogger logger, final String filePattern,
            final AnnotationParser parser, final String moduleName) {
        this(filePattern, parser, true, moduleName);
    }

    /**
     * Creates a new instance of {@link FilesParser}.
     *
     * @param logger
     *            the logger
     * @param filePattern
     *            ant file-set pattern to scan for files to parse
     * @param parser
     *            the parser to apply on the found files
     * @param shouldDetectModules
     *            determines whether modules should be detected from pom.xml or
     *            build.xml files
     * @param isMavenBuild
     *            determines whether this build uses maven
     * @deprecated Use
     *             {@link #FilesParser(String, String, AnnotationParser, boolean, boolean)}
     */
    @Deprecated
    @SuppressWarnings("PMD")
    public FilesParser(final StringPluginLogger logger, final String filePattern,
            final AnnotationParser parser, final boolean shouldDetectModules,
            final boolean isMavenBuild) {
        this(filePattern, parser, isMavenBuild, StringUtils.EMPTY);
    }
}
TOP

Related Classes of hudson.plugins.analysis.core.FilesParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.