/*
* .NET tools :: StyleCop 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.stylecop;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.sonar.api.utils.SonarException;
import org.sonar.dotnet.tools.commons.visualstudio.VisualStudioProject;
import org.sonar.dotnet.tools.commons.visualstudio.VisualStudioSolution;
import com.google.common.collect.Lists;
/**
* Class that generates MSBuild
*/
public class MsBuildFileGenerator {
protected static final String MSBUILD_FILE = "stylecop-msbuild.xml";
private VisualStudioSolution solution;
private File styleCopRuleFile;
private File reportFile;
private File styleCopFolder;
public MsBuildFileGenerator(VisualStudioSolution solution, File styleCopRuleFile, File reportFile, File styleCopFolder) {
this.solution = solution;
this.styleCopRuleFile = styleCopRuleFile;
this.reportFile = reportFile;
this.styleCopFolder = styleCopFolder;
}
/**
* Generates the MSBuild file in the given output folder
*
* @param outputFolder
* the output folder
* @param vsProject
* the VS project that should be analysed. May be NULL, in which case all the projects of the solution will be analysed.
*/
public File generateFile(File outputFolder, VisualStudioProject vsProject) {
File msBuildFile = new File(outputFolder, MSBUILD_FILE);
List<VisualStudioProject> vsProjects = solution.getProjects();
if (vsProject != null) {
vsProjects = Lists.newArrayList(vsProject);
}
FileWriter writer = null;
try {
writer = new FileWriter(msBuildFile);
generateContent(writer, styleCopRuleFile, reportFile, vsProjects);
writer.flush();
} catch (IOException e) {
throw new SonarException("Error while generating the MSBuild file needed to launch StyleCop: " + msBuildFile.getAbsolutePath(), e);
} finally {
IOUtils.closeQuietly(writer);
}
return msBuildFile;
}
protected void generateContent(Writer writer, File styleCopRuleFile, File reportFile, List<VisualStudioProject> vsProjects)
throws IOException {
writer.append("<?xml version=\"1.0\" ?>\n");
writer
.append("<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" DefaultTargets=\"StyleCopLaunch\" ToolsVersion=\"3.5\">\n");
writer.append(" <PropertyGroup>\n");
writer.append(" <ProjectRoot>");
StringEscapeUtils.escapeXml(writer, solution.getSolutionDir().getAbsolutePath());
writer.append("</ProjectRoot>\n");
writer.append(" <StyleCopRoot>");
StringEscapeUtils.escapeXml(writer, styleCopFolder.getAbsolutePath());
writer.append("</StyleCopRoot>\n");
writer.append(" </PropertyGroup>\n");
writer.append(" <UsingTask TaskName=\"StyleCopTask\" AssemblyFile=\"$(StyleCopRoot)\\Microsoft.StyleCop.dll\"></UsingTask>\n");
writer.append(" <ItemGroup>\n");
generateProjectList(writer, vsProjects);
writer.append(" </ItemGroup>\n");
writer.append(" <Target Name=\"StyleCopLaunch\">\n");
writer.append(" <CreateItem Include=\"%(Project.RootDir)%(Project.Directory)**\\*.cs\">\n");
writer.append(" <Output ItemName=\"SourceAnalysisFiles\" TaskParameter=\"Include\"></Output>\n");
writer.append(" </CreateItem>\n");
writer.append(" <StyleCopTask MaxViolationCount=\"-1\" OverrideSettingsFile=\"");
StringEscapeUtils.escapeXml(writer, styleCopRuleFile.getAbsolutePath());
writer.append("\"\n OutputFile=\"");
StringEscapeUtils.escapeXml(writer, reportFile.getAbsolutePath());
writer.append("\"\n TreatErrorsAsWarnings=\"true\" ForceFullAnalysis=\"true\"\n");
writer.append(" SourceFiles=\"@(SourceAnalysisFiles);@(CSFile)\"\n");
writer.append(" ProjectFullPath=\"");
StringEscapeUtils.escapeXml(writer, solution.getSolutionFile().getAbsolutePath());
writer.append("\"></StyleCopTask>\n");
writer.append(" </Target>\n");
writer.append("</Project>");
}
private void generateProjectList(Writer writer, List<VisualStudioProject> vsProjects) throws IOException {
for (VisualStudioProject project : vsProjects) {
if (project.getProjectFile() == null) {
// this is a Web project without ".csproj" file, we need to add a wildcard pattern
writer.append(" <CSFile Include=\"");
StringEscapeUtils.escapeXml(writer, project.getDirectory().getAbsolutePath() + "\\**\\*.cs");
writer.append("\"></CSFile>\n");
} else {
writer.append(" <Project Include=\"");
StringEscapeUtils.escapeXml(writer, project.getProjectFile().getAbsolutePath());
writer.append("\"></Project>\n");
}
}
}
}