blob: fd8b295fda183d58883a1352579339baa2525e9a [file] [log] [blame]
package com.intellij.codeInspection.ex;
import com.intellij.codeInspection.InspectionApplication;
import com.intellij.codeInspection.InspectionsReportConverter;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.io.URLUtil;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.net.URL;
import java.util.List;
import java.util.Map;
/**
* @author Roman.Chernyatchik
*/
public class PlainTextFormatter implements InspectionsReportConverter {
public static final String NAME = "plain";
private static final String FILE_ELEMENT = "file";
private static final String LINE_ELEMENT = "line";
private static final String PROBLEM_ELEMENT = "problem";
private static final String DESCRIPTION_ELEMENT = "description";
private static final String PROBLEM_CLASS_ELEMENT = "problem_class";
private static final String SEVERITY_ATTRIBUTE = "severity";
@Override
public String getFormatName() {
return NAME;
}
@Override
public boolean useTmpDirForRawData() {
return true;
}
@Override
public void convert(@NotNull final String rawDataDirectoryPath,
@Nullable final String outputPath,
@NotNull final Map<String, Tools> tools,
@NotNull final List<File> inspectionsResults) throws ConversionException {
final SAXTransformerFactory transformerFactory = (SAXTransformerFactory)TransformerFactory.newInstance();
final URL descrExtractorXsltUrl = getClass().getResource("description-text.xsl");
final Source xslSource;
final Transformer transformer;
try {
xslSource = new StreamSource(URLUtil.openStream(descrExtractorXsltUrl));
transformer = transformerFactory.newTransformer(xslSource);
}
catch (IOException e) {
throw new ConversionException("Cannot find inspection descriptions converter.");
}
catch (TransformerConfigurationException e) {
throw new ConversionException("Fail to load inspection descriptions converter.");
}
// write to file/stdout:
final Writer w;
if (outputPath != null) {
final File outputFile = new File(outputPath);
try {
w = new FileWriter(outputFile);
}
catch (IOException e) {
throw new ConversionException("Cannot edit file: " + outputFile.getPath());
}
}
else {
w = new PrintWriter(System.out);
}
try {
for (File inspectionData : inspectionsResults) {
if (inspectionData.isDirectory()) {
warn("Folder isn't expected here: " + inspectionData.getName());
continue;
}
final String fileNameWithoutExt = FileUtil.getNameWithoutExtension(inspectionData);
if (InspectionApplication.DESCRIPTIONS.equals(fileNameWithoutExt)) {
continue;
}
InspectionToolWrapper toolWrapper = tools.get(fileNameWithoutExt).getTool();
// Tool name and group
w.append(getToolPresentableName(toolWrapper)).append("\n");
// Description is HTML based, need to be converted in plain text
writeInspectionDescription(w, toolWrapper, transformer);
// separator before file list
w.append("\n");
// parse xml and output results
final SAXBuilder builder = new SAXBuilder();
try {
final Document doc = builder.build(inspectionData);
final Element root = doc.getRootElement();
final List problems = root.getChildren(PROBLEM_ELEMENT);
// let's count max file path & line_number length to align problem descriptions
final int maxFileColonLineLength = getMaxFileColonLineNumLength(inspectionData, toolWrapper, problems);
for (Object problem : problems) {
// Format:
// file_path:line_num [severity] problem description
final Element fileElement = ((Element)problem).getChild(FILE_ELEMENT);
final String filePath = getPath(fileElement);
// skip suppressed results
if (resultsIgnored(inspectionData, toolWrapper)) {
continue;
}
final Element lineElement = ((Element)problem).getChild(LINE_ELEMENT);
final Element problemDescrElement = ((Element)problem).getChild(DESCRIPTION_ELEMENT);
final String severity = ((Element)problem).getChild(PROBLEM_CLASS_ELEMENT).getAttributeValue(SEVERITY_ATTRIBUTE);
final String fileLineNum = lineElement.getText();
w.append(" ").append(filePath).append(':').append(fileLineNum);
// align descriptions
for (int i = maxFileColonLineLength - 1 - filePath.length() - fileLineNum.length() + 4; i >= 0; i--) {
w.append(' ');
}
w.append("[").append(severity).append("] ");
w.append(problemDescrElement.getText()).append('\n');
}
}
catch (JDOMException e) {
throw new ConversionException("Unknown results format, file = " + inspectionData.getPath() + ". Error: " + e.getMessage());
}
// separator between neighbour inspections
w.append("\n");
}
}
catch (IOException e) {
throw new ConversionException("Cannot write inspection results: " + e.getMessage());
} finally {
if (w != null) {
try {
w.close();
}
catch (IOException e) {
warn("Cannot save inspection results: " + e.getMessage());
}
}
}
}
private int getMaxFileColonLineNumLength(@NotNull final File inspectionResultData,
@NotNull final InspectionToolWrapper toolWrapper,
@NotNull final List problems) {
int maxFileColonLineLength = 0;
for (Object problem : problems) {
final Element fileElement = ((Element)problem).getChild(FILE_ELEMENT);
final Element lineElement = ((Element)problem).getChild(LINE_ELEMENT);
final String filePath = getPath(fileElement);
// skip suppressed results
if (resultsIgnored(inspectionResultData, toolWrapper)) {
continue;
}
maxFileColonLineLength = Math.max(maxFileColonLineLength, filePath.length() + 1 + lineElement.getText().length());
}
return maxFileColonLineLength;
}
private void warn(String msg) {
System.err.println(msg);
}
private boolean resultsIgnored(@NotNull final File file,
@NotNull final InspectionToolWrapper toolWrapper) {
// TODO: check according to config
return false;
}
@NotNull
protected String getPath(@NotNull final Element fileElement) {
return fileElement.getText().replace("file://$PROJECT_DIR$", ".");
}
protected void writeInspectionDescription(@NotNull final Writer w,
@NotNull final InspectionToolWrapper toolWrapper,
@NotNull final Transformer transformer)
throws IOException, ConversionException {
final StringWriter descrWriter = new StringWriter();
String descr = toolWrapper.loadDescription();
if (descr == null) {
return;
}
// convert line ends to xml form
descr = descr.replace("<br>", "<br/>");
try {
transformer.transform(new StreamSource(new StringReader(descr)), new StreamResult(descrWriter));
}
catch (TransformerException e) {
// Not critical problem, just inspection error cannot be loaded
warn("ERROR: Cannot load description for inspection: " + getToolPresentableName(toolWrapper) + ".\n Error message: " + e.getMessage());
return;
}
final String trimmedDesc = descrWriter.toString().trim();
final String[] descLines = StringUtil.splitByLines(trimmedDesc);
if (descLines.length > 0) {
for (String descLine : descLines) {
w.append(" ").append(descLine.trim()).append("\n");
}
}
}
@NotNull
protected String getToolPresentableName(@NotNull final InspectionToolWrapper toolWrapper) throws IOException {
final StringBuilder buff = new StringBuilder();
// inspection name
buff.append(toolWrapper.getDisplayName()).append(" (");
// group name
final String[] groupPath = toolWrapper.getGroupPath();
for (int i = 0, groupPathLength = groupPath.length; i < groupPathLength; i++) {
if (i != 0) {
buff.append(" | ");
}
buff.append(groupPath[i]);
}
buff.append(")");
return buff.toString();
}
}