run_sonar.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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 += [
  66. '-Dsonar.projectBaseDir=' + sources_dir,
  67. '-Dsonar.cxx.coverage.reportPath=' + opts.gcov_report_path,
  68. ]
  69. if opts.classes_jar_paths:
  70. classes_dir = os.path.abspath('cls')
  71. os.mkdir(classes_dir)
  72. for classes_jar_path in opts.classes_jar_paths:
  73. extract_zip_file(classes_jar_path, classes_dir)
  74. base_props_args.append('-Dsonar.java.binaries=' + classes_dir)
  75. if opts.java_coverage_merged_tar:
  76. jacoco_report_path = os.path.abspath('jacoco.exec')
  77. with open(jacoco_report_path, 'w') as dest:
  78. with tarfile.open(opts.java_coverage_merged_tar) as tar:
  79. for src in tar:
  80. extracted = tar.extractfile(src)
  81. if extracted is not None:
  82. shutil.copyfileobj(extracted, dest)
  83. base_props_args += ['-Dsonar.core.codeCoveragePlugin=jacoco', '-Dsonar.jacoco.reportPath=' + jacoco_report_path]
  84. java_args = ['-{}'.format(i) for i in opts.java_args] + [
  85. '-Djava.net.preferIPv6Addresses=true',
  86. '-Djava.net.preferIPv4Addresses=false',
  87. ]
  88. sonar_cmd = (
  89. [
  90. opts.java_binary_path,
  91. ]
  92. + java_args
  93. + [
  94. '-classpath',
  95. opts.sonar_scanner_jar_path,
  96. ]
  97. + base_props_args
  98. + props_args
  99. + [opts.sonar_scanner_main_class, '-X']
  100. )
  101. p = sp.Popen(sonar_cmd, stdout=sp.PIPE, stderr=sp.STDOUT)
  102. out, _ = p.communicate()
  103. sys.stderr.write(out)
  104. with open(opts.log_path, 'a') as f:
  105. f.write(out)
  106. sys.exit(p.returncode)
  107. if __name__ == '__main__':
  108. opts, args = parse_args()
  109. props_args = ['-D' + arg for arg in args]
  110. main(opts, props_args)