/* * Sonar C# Plugin :: StyleCop * 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.plugins.csharp.stylecop; import java.io.File; import java.io.FileWriter; import java.io.IOException; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.DependsUpon; import org.sonar.api.batch.SensorContext; import org.sonar.api.profiles.RulesProfile; import org.sonar.api.resources.Project; import org.sonar.api.resources.ProjectFileSystem; import org.sonar.api.utils.SonarException; import org.sonar.dotnet.tools.commons.utils.FileFinder; import org.sonar.dotnet.tools.stylecop.StyleCopCommandBuilder; import org.sonar.dotnet.tools.stylecop.StyleCopException; import org.sonar.dotnet.tools.stylecop.StyleCopRunner; import org.sonar.plugins.csharp.api.CSharpConfiguration; import org.sonar.plugins.csharp.api.CSharpConstants; import org.sonar.plugins.csharp.api.MicrosoftWindowsEnvironment; import org.sonar.plugins.csharp.api.sensor.AbstractRegularCSharpSensor; import org.sonar.plugins.csharp.stylecop.profiles.StyleCopProfileExporter; /** * Collects the StyleCop reporting into sonar. */ @DependsUpon(CSharpConstants.CSHARP_CORE_EXECUTED) public class StyleCopSensor extends AbstractRegularCSharpSensor { private static final Logger LOG = LoggerFactory.getLogger(StyleCopSensor.class); private ProjectFileSystem fileSystem; private RulesProfile rulesProfile; private StyleCopProfileExporter profileExporter; private StyleCopResultParser styleCopResultParser; private CSharpConfiguration configuration; private String executionMode; /** * Constructs a {@link StyleCopSensor}. * * @param fileSystem * @param ruleFinder * @param styleCopRunner * @param profileExporter * @param rulesProfile */ public StyleCopSensor(ProjectFileSystem fileSystem, RulesProfile rulesProfile, StyleCopProfileExporter profileExporter, StyleCopResultParser styleCopResultParser, CSharpConfiguration configuration, MicrosoftWindowsEnvironment microsoftWindowsEnvironment) { super(microsoftWindowsEnvironment); this.fileSystem = fileSystem; this.rulesProfile = rulesProfile; this.profileExporter = profileExporter; this.styleCopResultParser = styleCopResultParser; this.configuration = configuration; this.executionMode = configuration.getString(StyleCopConstants.MODE, ""); } /** * {@inheritDoc} */ public boolean shouldExecuteOnProject(Project project) { boolean skipMode = StyleCopConstants.MODE_SKIP.equalsIgnoreCase(executionMode); if (skipMode) { LOG.info("StyleCop plugin won't execute as it is set to 'skip' mode."); } return super.shouldExecuteOnProject(project) && !skipMode; } /** * {@inheritDoc} */ public void analyse(Project project, SensorContext context) { if (rulesProfile.getActiveRulesByRepository(StyleCopConstants.REPOSITORY_KEY).isEmpty()) { LOG.warn("/!\\ SKIP StyleCop analysis: no rule defined for StyleCop in the \"{}\" profil.", rulesProfile.getName()); return; } styleCopResultParser.setEncoding(fileSystem.getSourceCharset()); final File reportFile; File sonarDir = fileSystem.getSonarWorkingDirectory(); if (StyleCopConstants.MODE_REUSE_REPORT.equalsIgnoreCase(executionMode)) { String reportPath = configuration.getString(StyleCopConstants.REPORTS_PATH_KEY, StyleCopConstants.STYLECOP_REPORT_XML); reportFile = FileFinder.browse(sonarDir, reportPath); } else { // prepare config file for StyleCop File styleCopConfigFile = generateConfigurationFile(); // run StyleCop try { File tempDir = new File(getMicrosoftWindowsEnvironment().getCurrentSolution().getSolutionDir(), getMicrosoftWindowsEnvironment() .getWorkingDirectory()); StyleCopRunner runner = StyleCopRunner.create( configuration.getString(StyleCopConstants.INSTALL_DIR_KEY, StyleCopConstants.INSTALL_DIR_DEFVALUE), getMicrosoftWindowsEnvironment().getDotnetSdkDirectory().getAbsolutePath(), tempDir.getAbsolutePath()); launchStyleCop(project, runner, styleCopConfigFile); } catch (StyleCopException e) { throw new SonarException("StyleCop execution failed.", e); } reportFile = new File(sonarDir, StyleCopConstants.STYLECOP_REPORT_XML); } // and analyse results analyseResults(reportFile); } protected void launchStyleCop(Project project, StyleCopRunner runner, File styleCopConfigFile) throws StyleCopException { StyleCopCommandBuilder builder = runner.createCommandBuilder(getMicrosoftWindowsEnvironment().getCurrentSolution(), getVSProject(project)); builder.setConfigFile(styleCopConfigFile); builder.setReportFile(new File(fileSystem.getSonarWorkingDirectory(), StyleCopConstants.STYLECOP_REPORT_XML)); runner.execute(builder, configuration.getInt(StyleCopConstants.TIMEOUT_MINUTES_KEY, StyleCopConstants.TIMEOUT_MINUTES_DEFVALUE)); } protected File generateConfigurationFile() { File configFile = new File(fileSystem.getSonarWorkingDirectory(), StyleCopConstants.STYLECOP_RULES_FILE); FileWriter writer = null; try { writer = new FileWriter(configFile); profileExporter.exportProfile(rulesProfile, writer); writer.flush(); } catch (IOException e) { throw new SonarException("Error while generating the StyleCop configuration file by exporting the Sonar rules.", e); } finally { IOUtils.closeQuietly(writer); } return configFile; } private void analyseResults(File reportFile) { if (reportFile.exists()) { LOG.debug("StyleCop report found at location {}", reportFile); styleCopResultParser.parse(reportFile); } else { LOG.warn("No StyleCop report found for path {}", reportFile); } } }