run_sonar.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import os
  2. import sys
  3. import zipfile
  4. import tarfile
  5. import subprocess as sp
  6. import optparse
  7. import shutil
  8. import xml.etree.ElementTree as et
  9. def parse_args():
  10. parser = optparse.OptionParser()
  11. parser.add_option(
  12. '--classes-jar-path',
  13. dest='classes_jar_paths',
  14. action='append',
  15. default=[],
  16. )
  17. parser.add_option('--sources-jar-path')
  18. parser.add_option('--sonar-scanner-jar-path')
  19. parser.add_option('--sonar-scanner-main-class')
  20. parser.add_option('--java-coverage-merged-tar')
  21. parser.add_option('--java-binary-path')
  22. parser.add_option('--log-path')
  23. parser.add_option('--gcov-report-path')
  24. parser.add_option('--source-root')
  25. parser.add_option('--java-args', action='append', default=[])
  26. return parser.parse_args()
  27. def extract_zip_file(zip_file_path, dest_dir):
  28. with zipfile.ZipFile(zip_file_path) as arch:
  29. arch.extractall(dest_dir)
  30. def get_source_real_path(source_root, path):
  31. parts = os.path.normpath(path).split(os.path.sep)
  32. for i in xrange(len(parts)):
  33. if os.path.exists(os.path.join(source_root, *parts[i:])):
  34. return os.path.join(*parts[i:])
  35. return None
  36. def collect_cpp_sources(report, source_root, destination):
  37. sources = set()
  38. with open(report) as f:
  39. root = et.fromstring(f.read())
  40. for f in root.findall('.//class[@filename]'):
  41. real_filename = get_source_real_path(source_root, f.attrib['filename'])
  42. if real_filename:
  43. f.attrib['filename'] = real_filename
  44. sources.add(real_filename)
  45. with open(report, 'w') as f:
  46. pref = '''<?xml version="1.0" ?>
  47. <!DOCTYPE coverage
  48. SYSTEM 'http://cobertura.sourceforge.net/xml/coverage-03.dtd'>\n'''
  49. f.write(pref + et.tostring(root, encoding='utf-8') + '\n\n')
  50. for src in sources:
  51. dst = os.path.join(destination, src)
  52. src = os.path.join(source_root, src)
  53. if os.path.isfile(src):
  54. if not os.path.exists(os.path.dirname(dst)):
  55. os.makedirs(os.path.dirname(dst))
  56. os.link(src, dst)
  57. def main(opts, props_args):
  58. sources_dir = os.path.abspath('src')
  59. base_props_args = ['-Dsonar.sources=' + sources_dir]
  60. os.mkdir(sources_dir)
  61. if opts.sources_jar_path:
  62. extract_zip_file(opts.sources_jar_path, sources_dir)
  63. if opts.gcov_report_path:
  64. collect_cpp_sources(opts.gcov_report_path, opts.source_root, sources_dir)
  65. base_props_args += ['-Dsonar.projectBaseDir=' + sources_dir, '-Dsonar.cxx.coverage.reportPath=' + opts.gcov_report_path]
  66. if opts.classes_jar_paths:
  67. classes_dir = os.path.abspath('cls')
  68. os.mkdir(classes_dir)
  69. for classes_jar_path in opts.classes_jar_paths:
  70. extract_zip_file(classes_jar_path, classes_dir)
  71. base_props_args.append('-Dsonar.java.binaries=' + classes_dir)
  72. if opts.java_coverage_merged_tar:
  73. jacoco_report_path = os.path.abspath('jacoco.exec')
  74. with open(jacoco_report_path, 'w') as dest:
  75. with tarfile.open(opts.java_coverage_merged_tar) as tar:
  76. for src in tar:
  77. extracted = tar.extractfile(src)
  78. if extracted is not None:
  79. shutil.copyfileobj(extracted, dest)
  80. base_props_args += [
  81. '-Dsonar.core.codeCoveragePlugin=jacoco',
  82. '-Dsonar.jacoco.reportPath=' + jacoco_report_path
  83. ]
  84. java_args = ['-{}'.format(i) for i in opts.java_args] + ['-Djava.net.preferIPv6Addresses=true', '-Djava.net.preferIPv4Addresses=false']
  85. sonar_cmd = [
  86. opts.java_binary_path,
  87. ] + java_args + [
  88. '-classpath',
  89. opts.sonar_scanner_jar_path,
  90. ] + base_props_args + props_args + [opts.sonar_scanner_main_class, '-X']
  91. p = sp.Popen(sonar_cmd, stdout=sp.PIPE, stderr=sp.STDOUT)
  92. out, _ = p.communicate()
  93. sys.stderr.write(out)
  94. with open(opts.log_path, 'a') as f:
  95. f.write(out)
  96. sys.exit(p.returncode)
  97. if __name__ == '__main__':
  98. opts, args = parse_args()
  99. props_args = ['-D' + arg for arg in args]
  100. main(opts, props_args)