/*
* .NET tools :: Gendarme Runner
* 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.gendarme;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.utils.command.Command;
import org.sonar.dotnet.tools.commons.utils.FileFinder;
import org.sonar.dotnet.tools.commons.visualstudio.VisualStudioProject;
import org.sonar.dotnet.tools.commons.visualstudio.VisualStudioSolution;
import com.google.common.collect.Lists;
/**
* Class used to build the command line to run Gendarme.
*/
public final class GendarmeCommandBuilder {
private static final Logger LOG = LoggerFactory.getLogger(GendarmeCommandBuilder.class);
private VisualStudioSolution solution;
private VisualStudioProject vsProject;
private File gendarmeExecutable;
private File silverlightFolder;
private String gendarmeConfidence = "normal+";
private String gendarmeSeverity = "all";
private File gendarmeConfigFile;
private File gendarmeReportFile;
private String buildConfigurations = "Debug";
private String[] assembliesToScan = new String[] {};
private GendarmeCommandBuilder() {
}
/**
* Constructs a {@link GendarmeCommandBuilder} object for the given Visual Studio solution.
*
* @param solution
* the solution to analyse
* @param project
* the VS project to analyse
*
* @return a Gendarme builder for this solution
*/
public static GendarmeCommandBuilder createBuilder(VisualStudioSolution solution, VisualStudioProject project) {
GendarmeCommandBuilder builder = new GendarmeCommandBuilder();
builder.solution = solution;
builder.vsProject = project;
return builder;
}
/**
* Sets the executable
*
* @param gendarmeExecutable
* the executable
* @return the current builder
*/
public GendarmeCommandBuilder setExecutable(File gendarmeExecutable) {
this.gendarmeExecutable = gendarmeExecutable;
return this;
}
/**
* Sets the configuration file to use
*
* @param gendarmeConfigFile
* the config file
* @return the current builder
*/
public GendarmeCommandBuilder setConfigFile(File gendarmeConfigFile) {
this.gendarmeConfigFile = gendarmeConfigFile;
return this;
}
/**
* Sets the report file to generate
*
* @param reportFile
* the report file
* @return the current builder
*/
public GendarmeCommandBuilder setReportFile(File reportFile) {
this.gendarmeReportFile = reportFile;
return this;
}
/**
* Sets the Silverlight folder where is located the
* Silverlight version of mscorlib.
*
* @param silverlightFolder
* the Silverlight folder
* @return the current builder
*/
public GendarmeCommandBuilder setSilverlightFolder(File silverlightFolder) {
this.silverlightFolder = silverlightFolder;
return this;
}
/**
* Sets the Gendarme confidence level. By default "normal+" if nothing is specified.
*
* @param gendarmeConfidence
* the confidence level
* @return the current builder
*/
public GendarmeCommandBuilder setConfidence(String gendarmeConfidence) {
this.gendarmeConfidence = gendarmeConfidence;
return this;
}
/**
* Sets the Gendarme severity level. By default "all" if nothing is specified.
*
* @param gendarmeSeverity
* the severity level
* @return the current builder
*/
public GendarmeCommandBuilder setSeverity(String gendarmeSeverity) {
this.gendarmeSeverity = gendarmeSeverity;
return this;
}
/**
* Sets the build configurations. By default, it is "Debug".
*
* @param buildConfigurations
* the build configurations
* @return the current builder
*/
public GendarmeCommandBuilder setBuildConfigurations(String buildConfigurations) {
this.buildConfigurations = buildConfigurations;
return this;
}
/**
* Sets the assemblies to scan if the information should not be taken from the VS configuration files.
*
* @param assembliesToScan
* the assemblies to scan
* @return the current builder
*/
public GendarmeCommandBuilder setAssembliesToScan(String... assembliesToScan) {
this.assembliesToScan = assembliesToScan;
return this;
}
protected String getBuildConfigurations() {
return buildConfigurations;
}
/**
* Transforms this command object into a Command object that can be passed to the CommandExecutor.
*
* @return the Command object that represents the command to launch.
*/
public Command toCommand() throws GendarmeException {
Collection<File> assemblyToScanFiles = findAssembliesToScan();
validate(assemblyToScanFiles);
LOG.debug("- Gendarme program : " + gendarmeExecutable);
Command command = Command.create(gendarmeExecutable.getAbsolutePath());
LOG.debug("- Config file : " + gendarmeConfigFile);
command.addArgument("--config");
command.addArgument(gendarmeConfigFile.getAbsolutePath());
LOG.debug("- Report file : " + gendarmeReportFile);
command.addArgument("--xml");
command.addArgument(gendarmeReportFile.getAbsolutePath());
LOG.debug("- Quiet output");
command.addArgument("--quiet");
LOG.debug("- Confidence : " + gendarmeConfidence);
command.addArgument("--confidence");
command.addArgument(gendarmeConfidence);
LOG.debug("- Severity : all");
command.addArgument("--severity");
command.addArgument(gendarmeSeverity);
LOG.debug("- Scanned assemblies :");
for (File checkedAssembly : assemblyToScanFiles) {
LOG.debug(" o " + checkedAssembly);
command.addArgument(checkedAssembly.getAbsolutePath());
}
if (vsProject != null && vsProject.isSilverlightProject()) {
copySilverlightAssembly();
}
return command;
}
protected void copySilverlightAssembly() throws GendarmeException {
File silverlightAssembly = new File(silverlightFolder, "mscorlib.dll");
if (silverlightAssembly == null || !silverlightAssembly.isFile()) {
throw new GendarmeException("Could not find Silverlight Mscorlib.dll assembly. Please check your settings.");
}
File destinationDirectory = vsProject.getArtifactDirectory(buildConfigurations);
if (destinationDirectory == null) {
throw new GendarmeException("Impossible to copy Silverlight Mscorlib.dll as there is no existing artifact "
+ "directory for the build configuration: " + buildConfigurations);
}
try {
LOG.debug("Copy Silverlight Mscorlib.dll file ");
FileUtils.copyFileToDirectory(silverlightAssembly, destinationDirectory);
} catch (IOException e) {
throw new GendarmeException("Cannot copy Silverlight 'mscorlib.dll' file to " + destinationDirectory, e);
}
}
private Collection<File> findAssembliesToScan() {
final Collection<File> assemblyFiles;
if (assembliesToScan.length == 0) {
LOG.debug("No assembly specified: will look into 'csproj' files to find which should be analyzed.");
assemblyFiles = Lists.newArrayList();
addProjectAssembly(assemblyFiles, vsProject);
} else {
// Some assemblies have been specified: let's analyze them
assemblyFiles = FileFinder.findFiles(solution, vsProject, assembliesToScan);
}
return assemblyFiles;
}
private void addProjectAssembly(Collection<File> assemblyFileList, VisualStudioProject visualStudioProject) {
Set<File> assemblies = visualStudioProject.getGeneratedAssemblies(buildConfigurations);
for (File assembly : assemblies) {
if (assembly != null && assembly.isFile()) {
LOG.debug(" - Found {}", assembly.getAbsolutePath());
assemblyFileList.add(assembly);
}
}
}
protected void validate(Collection<File> assemblyToScanFiles) {
if (gendarmeConfigFile == null || !gendarmeConfigFile.exists()) {
throw new IllegalStateException("The Gendarme configuration file does not exist.");
}
if (assemblyToScanFiles.isEmpty()) {
throw new IllegalStateException("No assembly to scan. Please check your project's Gendarme plugin configuration.");
}
}
}