001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2014 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * SonarQube is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * SonarQube is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public License
017     * along with this program; if not, write to the Free Software Foundation,
018     * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019     */
020    package org.sonar.batch.scan2;
021    
022    import org.apache.commons.io.FileUtils;
023    import org.apache.commons.io.IOUtils;
024    import org.slf4j.Logger;
025    import org.slf4j.LoggerFactory;
026    import org.sonar.api.batch.bootstrap.ProjectDefinition;
027    import org.sonar.api.batch.fs.FileSystem;
028    import org.sonar.api.batch.fs.InputFile;
029    import org.sonar.api.batch.sensor.issue.Issue;
030    import org.sonar.api.batch.sensor.measure.Measure;
031    import org.sonar.api.config.Settings;
032    import org.sonar.api.utils.ZipUtils;
033    import org.sonar.api.utils.text.JsonWriter;
034    
035    import java.io.File;
036    import java.io.FileWriter;
037    import java.io.IOException;
038    import java.util.Properties;
039    
040    public final class AnalysisPublisher {
041    
042      private static final Logger LOG = LoggerFactory.getLogger(AnalysisPublisher.class);
043      private final Settings settings;
044      private final FileSystem fs;
045      private final AnalyzerMeasureCache measureCache;
046      private final ProjectDefinition def;
047      private final AnalyzerIssueCache issueCache;
048    
049      public AnalysisPublisher(ProjectDefinition def, Settings settings, FileSystem fs,
050        AnalyzerMeasureCache measureCache,
051        AnalyzerIssueCache analyzerIssueCache) {
052        this.def = def;
053        this.settings = settings;
054        this.fs = fs;
055        this.measureCache = measureCache;
056        this.issueCache = analyzerIssueCache;
057      }
058    
059      public void execute() {
060        if (settings.getBoolean("sonar.skipPublish")) {
061          LOG.debug("Publishing of results is skipped");
062          return;
063        }
064        File exportDir = prepareExportDir();
065    
066        exportAnalysisProperties(exportDir);
067    
068        exportSourceFiles(exportDir);
069    
070        exportMeasures(exportDir);
071    
072        exportIssues(exportDir);
073    
074        createZip(exportDir);
075    
076      }
077    
078      private void createZip(File exportDir) {
079        File exportZip = new File(fs.workDir(), def.getKey() + "-export.zip");
080        try {
081          ZipUtils.zipDir(exportDir, exportZip);
082          FileUtils.deleteDirectory(exportDir);
083        } catch (IOException e) {
084          throw unableToExport(e);
085        }
086        LOG.info("Results packaged in " + exportZip);
087      }
088    
089      private IllegalStateException unableToExport(IOException e) {
090        return new IllegalStateException("Unable to export result of analyzis", e);
091      }
092    
093      private void exportIssues(File exportDir) {
094        File issuesFile = new File(exportDir, "issues.json");
095        FileWriter issueWriter = null;
096        try {
097          issueWriter = new FileWriter(issuesFile);
098          JsonWriter jsonWriter = JsonWriter.of(issueWriter);
099          jsonWriter
100            .beginObject().name("issues")
101            .beginArray();
102          for (Issue issue : issueCache.byModule(def.getKey())) {
103            jsonWriter.beginObject()
104              .prop("repository", issue.ruleKey().repository())
105              .prop("rule", issue.ruleKey().rule());
106            if (issue.inputPath() != null) {
107              jsonWriter.prop("path", issue.inputPath().relativePath());
108            }
109            jsonWriter.prop("message", issue.message())
110              .prop("effortToFix", issue.effortToFix())
111              .prop("line", issue.line())
112              .prop("severity", issue.severity())
113              .endObject();
114          }
115          jsonWriter.endArray()
116            .endObject()
117            .close();
118        } catch (IOException e) {
119          throw unableToExport(e);
120        } finally {
121          IOUtils.closeQuietly(issueWriter);
122        }
123      }
124    
125      private void exportMeasures(File exportDir) {
126        File measuresFile = new File(exportDir, "measures.json");
127        FileWriter measureWriter = null;
128        try {
129          measureWriter = new FileWriter(measuresFile);
130          JsonWriter jsonWriter = JsonWriter.of(measureWriter);
131          jsonWriter
132            .beginObject().name("measures")
133            .beginArray();
134          for (Measure<?> measure : measureCache.byModule(def.getKey())) {
135            jsonWriter.beginObject()
136              .prop("metricKey", measure.metric().key());
137            InputFile inputFile = measure.inputFile();
138            if (inputFile != null) {
139              jsonWriter.prop("filePath", inputFile.relativePath());
140            }
141            jsonWriter.prop("value", String.valueOf(measure.value()))
142              .endObject();
143          }
144          jsonWriter.endArray()
145            .endObject()
146            .close();
147        } catch (IOException e) {
148          throw unableToExport(e);
149        } finally {
150          IOUtils.closeQuietly(measureWriter);
151        }
152      }
153    
154      private void exportSourceFiles(File exportDir) {
155        File sourceDir = new File(exportDir, "sources");
156        for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) {
157          File dest = new File(sourceDir, inputFile.relativePath());
158          try {
159            FileUtils.copyFile(inputFile.file(), dest);
160          } catch (IOException e) {
161            throw unableToExport(e);
162          }
163        }
164      }
165    
166      private void exportAnalysisProperties(File exportDir) {
167        File propsFile = new File(exportDir, "analysis.properties");
168        Properties props = new Properties();
169        props.putAll(settings.getProperties());
170        FileWriter writer = null;
171        try {
172          writer = new FileWriter(propsFile);
173          props.store(writer, "SonarQube batch");
174        } catch (IOException e) {
175          throw unableToExport(e);
176        } finally {
177          IOUtils.closeQuietly(writer);
178        }
179      }
180    
181      private File prepareExportDir() {
182        File exportDir = new File(fs.workDir(), "export");
183        try {
184          if (exportDir.exists()) {
185            FileUtils.forceDelete(exportDir);
186          }
187          FileUtils.forceMkdir(exportDir);
188        } catch (IOException e) {
189          throw unableToExport(e);
190        }
191        return exportDir;
192      }
193    }