package hudson.plugins.tasks.parser;
import hudson.FilePath;
import hudson.FilePath.FileCallable;
import hudson.plugins.analysis.util.ContextHashCode;
import hudson.plugins.analysis.util.EncodingValidator;
import hudson.plugins.analysis.util.ModuleDetector;
import hudson.plugins.analysis.util.PackageDetectors;
import hudson.remoting.VirtualChannel;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collection;
import org.apache.commons.lang.StringUtils;
import org.apache.tools.ant.types.FileSet;
/**
* Scans the workspace and records the found tasks. Each file is then
* classified, i.e., a module and package is guessed and assigned.
*
* @author Ulli Hafner
*/
public class WorkspaceScanner implements FileCallable<TasksParserResult> {
/** Generated ID. */
private static final long serialVersionUID = -4355362392102020724L;
/** Ant file-set pattern to define the files to scan. */
private final String filePattern;
/** Ant file-set pattern to define the files to exclude from scan. */
private final String excludeFilePattern;
/** The maven module. If <code>null</code>, then the scanner tries to guess it (freestyle project). */
private String moduleName;
/** Tag identifiers indicating high priority. */
private final String high;
/** Tag identifiers indicating normal priority. */
private final String normal;
/** Tag identifiers indicating low priority. */
private final String low;
/** Tag identifiers indicating case sensitive parsing. */
private final boolean ignoreCase;
/** Prefix of path. */
private String prefix;
/** The default encoding to be used when reading and parsing files. */
private final String defaultEncoding;
/**
* Creates a new instance of <code>WorkspaceScanner</code>.
*
* @param filePattern
* ant file-set pattern to scan for files
* @param excludeFilePattern
* ant file-set pattern to exclude from scan
* @param defaultEncoding
* the default encoding to be used when reading and parsing files
* @param high
* tag identifiers indicating high priority
* @param normal
* tag identifiers indicating normal priority
* @param low
* tag identifiers indicating low priority
* @param ignoreCase
* if case should be ignored during matching
*/
public WorkspaceScanner(final String filePattern, final String excludeFilePattern, final String defaultEncoding,
final String high, final String normal, final String low, final boolean ignoreCase) {
this.filePattern = filePattern;
this.excludeFilePattern = excludeFilePattern;
this.defaultEncoding = defaultEncoding;
this.high = high;
this.normal = normal;
this.low = low;
this.ignoreCase = ignoreCase;
}
/**
* Creates a new instance of <code>WorkspaceScanner</code>.
*
* @param filePattern
* ant file-set pattern to scan for files
* @param excludeFilePattern
* ant file-set pattern to exclude from scan
* @param defaultEncoding
* the default encoding to be used when reading and parsing files
* @param high
* tag identifiers indicating high priority
* @param normal
* tag identifiers indicating normal priority
* @param low
* tag identifiers indicating low priority
* @param caseSensitive
* determines whether the scanner should work case sensitive
* @param moduleName
* the maven module name
*/
// CHECKSTYLE:OFF
public WorkspaceScanner(final String filePattern, final String excludeFilePattern, final String defaultEncoding,
final String high, final String normal, final String low, final boolean caseSensitive,
final String moduleName) {
this(filePattern, excludeFilePattern, defaultEncoding, high, normal, low, caseSensitive);
this.moduleName = moduleName;
}
// CHECKSTYLE:ON
/**
* Sets the prefix to the specified value.
*
* @param prefix the value to set
*/
public void setPrefix(final String prefix) {
this.prefix = prefix + "/";
}
/**
* Returns the prefix.
*
* @return the prefix
*/
public String getPrefix() {
return StringUtils.defaultIfEmpty(prefix, StringUtils.EMPTY);
}
/** {@inheritDoc} */
public TasksParserResult invoke(final File workspace, final VirtualChannel channel) throws IOException {
String[] files = findFiles(workspace);
TaskScanner taskScanner = new TaskScanner(high, normal, low, ignoreCase);
TasksParserResult javaProject = new TasksParserResult(files.length);
ModuleDetector moduleDetector = new ModuleDetector(workspace);
for (String fileName : files) {
File originalFile = new File(workspace, fileName);
Collection<Task> tasks = taskScanner.scan(new InputStreamReader(new FilePath(originalFile).read(),
EncodingValidator.defaultCharset(defaultEncoding)));
if (!tasks.isEmpty()) {
String unixName = fileName.replace('\\', '/');
String packageName = PackageDetectors.detectPackage(unixName, new FilePath(originalFile).read());
String guessedModule = moduleDetector.guessModuleName(originalFile.getAbsolutePath());
String actualModule = StringUtils.defaultIfEmpty(moduleName, guessedModule);
for (Task task : tasks) {
task.setFileName(originalFile.getAbsolutePath());
task.setPackageName(packageName);
task.setModuleName(actualModule);
task.setPathName(workspace.getPath());
ContextHashCode hashCode = new ContextHashCode();
task.setContextHashCode(hashCode.create(originalFile.getAbsolutePath(), task.getPrimaryLineNumber(), defaultEncoding));
}
javaProject.addAnnotations(tasks);
}
}
return javaProject;
}
/**
* Returns an array with the filenames of the files that have been found in
* the workspace.
*
* @param workspaceRoot
* root directory of the workspace
* @return the filenames of the FindBugs files
*/
private String[] findFiles(final File workspaceRoot) {
FileSet fileSet = new FileSet();
org.apache.tools.ant.Project project = new org.apache.tools.ant.Project();
fileSet.setProject(project);
fileSet.setDir(workspaceRoot);
fileSet.setIncludes(filePattern);
if (StringUtils.isNotBlank(excludeFilePattern)) {
fileSet.setExcludes(excludeFilePattern);
}
return fileSet.getDirectoryScanner(project).getIncludedFiles();
}
}