@ -12,15 +12,22 @@ from __future__ import unicode_literals
import codecs
import codecs
import csv
import csv
import datetime
import itertools
import itertools
import json
import json
import operator
import operator
import os
import os
import re
import shutil
import shutil
import sys
import sys
import tempfile
import tempfile
import xml . etree . ElementTree as ET
import xml . etree . ElementTree as ET
try :
from lxml import etree
except ImportError :
etree = None
from . import colorize , config , source , utils
from . import colorize , config , source , utils
@ -82,6 +89,7 @@ JSON_INDEX_HASH = 'hash'
JSON_INDEX_KIND = ' kind '
JSON_INDEX_KIND = ' kind '
JSON_INDEX_LINE = ' line '
JSON_INDEX_LINE = ' line '
JSON_INDEX_PROCEDURE = ' procedure '
JSON_INDEX_PROCEDURE = ' procedure '
JSON_INDEX_PROCEDURE_ID = ' procedure_id '
JSON_INDEX_QUALIFIER = ' qualifier '
JSON_INDEX_QUALIFIER = ' qualifier '
JSON_INDEX_QUALIFIER_TAGS = ' qualifier_tags '
JSON_INDEX_QUALIFIER_TAGS = ' qualifier_tags '
JSON_INDEX_SEVERITY = ' file '
JSON_INDEX_SEVERITY = ' file '
@ -103,6 +111,7 @@ JSON_INDEX_ISL_ENUM = 'enum'
QUALIFIER_TAGS = ' qualifier_tags '
QUALIFIER_TAGS = ' qualifier_tags '
BUCKET_TAGS = ' bucket '
BUCKET_TAGS = ' bucket '
ISSUE_TYPES_URL = ' http://fbinfer.com/docs/infer-issue-types.html# '
def clean_csv ( args , csv_report ) :
def clean_csv ( args , csv_report ) :
@ -252,15 +261,19 @@ def _is_user_visible(report):
kind in [ ISSUE_KIND_ERROR , ISSUE_KIND_WARNING ] )
kind in [ ISSUE_KIND_ERROR , ISSUE_KIND_WARNING ] )
def print_and_save_errors ( json_report , bugs_out ):
def print_and_save_errors ( json_report , bugs_out , xml_out ):
errors = utils . load_json_from_path ( json_report )
errors = utils . load_json_from_path ( json_report )
errors = filter ( _is_user_visible , errors )
errors = filter ( _is_user_visible , errors )
utils . stdout ( ' \n ' + _text_of_report_list ( errors ) )
utils . stdout ( ' \n ' + _text_of_report_list ( errors ) )
plain_out = _text_of_report_list ( errors ,
formatter = colorize . PLAIN_FORMATTER )
with codecs . open ( bugs_out , ' w ' ,
with codecs . open ( bugs_out , ' w ' ,
encoding = config . LOCALE , errors = ' replace ' ) as file_out :
encoding = config . LOCALE , errors = ' replace ' ) as file_out :
plain_out = _text_of_report_list ( errors ,
formatter = colorize . PLAIN_FORMATTER )
file_out . write ( plain_out )
file_out . write ( plain_out )
if xml_out is not None :
with codecs . open ( xml_out , ' w ' ,
encoding = config . LOCALE , errors = ' replace ' ) as file_out :
file_out . write ( _pmd_xml_of_issues ( errors ) )
def merge_reports_from_paths ( report_paths ) :
def merge_reports_from_paths ( report_paths ) :
@ -270,6 +283,48 @@ def merge_reports_from_paths(report_paths):
return _sort_and_uniq_rows ( json_data )
return _sort_and_uniq_rows ( json_data )
def _pmd_xml_of_issues ( issues ) :
if etree is None :
print ( ' ERROR: " etree " Python package not found. ' )
print ( ' ERROR: You need to install it to use Infer with --pmd-xml ' )
sys . exit ( 1 )
root = etree . Element ( ' pmd ' )
root . attrib [ ' version ' ] = ' 5.4.1 '
root . attrib [ ' date ' ] = datetime . datetime . now ( ) . isoformat ( )
for issue in issues :
fully_qualifed_method_name = re . search ( ' (.*) \ (.* ' ,
issue [ JSON_INDEX_PROCEDURE_ID ] )
class_name = ' '
package = ' '
if fully_qualifed_method_name is not None :
# probably Java
info = fully_qualifed_method_name . groups ( ) [ 0 ] . split ( ' . ' )
class_name = info [ - 2 : - 1 ] [ 0 ]
method = info [ - 1 ]
package = ' . ' . join ( info [ 0 : - 2 ] )
else :
method = issue [ JSON_INDEX_PROCEDURE ]
file_node = etree . Element ( ' file ' )
file_node . attrib [ ' name ' ] = issue [ JSON_INDEX_FILENAME ]
violation = etree . Element ( ' violation ' )
violation . attrib [ ' begincolumn ' ] = ' 0 '
violation . attrib [ ' beginline ' ] = str ( issue [ JSON_INDEX_LINE ] )
violation . attrib [ ' endcolumn ' ] = ' 0 '
violation . attrib [ ' endline ' ] = str ( issue [ JSON_INDEX_LINE ] + 1 )
violation . attrib [ ' class ' ] = class_name
violation . attrib [ ' method ' ] = method
violation . attrib [ ' package ' ] = package
violation . attrib [ ' priority ' ] = ' 1 '
violation . attrib [ ' rule ' ] = issue [ JSON_INDEX_TYPE ]
violation . attrib [ ' ruleset ' ] = ' Infer Rules '
violation . attrib [ ' externalinfourl ' ] = (
ISSUE_TYPES_URL + issue [ JSON_INDEX_TYPE ] )
violation . text = issue [ JSON_INDEX_QUALIFIER ]
file_node . append ( violation )
root . append ( file_node )
return etree . tostring ( root , pretty_print = True , encoding = config . LOCALE )
def _sort_and_uniq_rows ( l ) :
def _sort_and_uniq_rows ( l ) :
key = operator . itemgetter ( JSON_INDEX_FILENAME ,
key = operator . itemgetter ( JSON_INDEX_FILENAME ,
JSON_INDEX_LINE ,
JSON_INDEX_LINE ,