Skip to content

Commit 4818983

Browse files
Added support for uploading lcov generated info file
1 parent f189814 commit 4818983

1 file changed

Lines changed: 96 additions & 44 deletions

File tree

cpp_coveralls/coverage.py

Lines changed: 96 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ def create_args(params):
7070
default=None, metavar='FILE')
7171
parser.add_argument('--follow-symlinks', action='store_true',
7272
help='Follow symlinks (default off)')
73+
parser.add_argument('-l', '--lcov-file', metavar='FILE',
74+
help='Upload lcov generated info file')
7375

7476
return parser.parse_args(params)
7577

@@ -278,6 +280,31 @@ def parse_gcov_file(fobj, filename):
278280
coverage.append(int(cov_num))
279281
return coverage
280282

283+
def parse_lcov_file_info(args, filepath, line_iter, line_coverage_re, file_end_string):
284+
""" Parse the file content in lcov info file
285+
"""
286+
coverage = []
287+
lines_covered = []
288+
while True:
289+
try:
290+
line = line_iter.next()
291+
if line != "end_of_record":
292+
line_coverage_match = line_coverage_re.match(line)
293+
if line_coverage_match:
294+
line_no = line_coverage_match.group(1)
295+
cov_count = int(line_coverage_match.group(2))
296+
lines_covered.append((line_no, cov_count))
297+
else:
298+
break
299+
except StopIteration:
300+
break
301+
302+
num_code_lines = len([line.rstrip('\n') for line in open(filepath, 'r')])
303+
coverage = [None] * num_code_lines
304+
for line_covered in lines_covered:
305+
coverage[int(line_covered[0]) - 1] = line_covered[1]
306+
307+
return coverage
281308

282309
def combine_reports(original, new):
283310
"""Combines two gcov reports for a file into one by adding the number of hits on each line
@@ -299,7 +326,6 @@ def combine_reports(original, new):
299326
report['coverage'] = coverage
300327
return report
301328

302-
303329
def collect_non_report_files(args, discovered_files):
304330
"""Collects the source files that have no coverage reports.
305331
"""
@@ -344,54 +370,80 @@ def collect(args):
344370
discovered_files = set()
345371
src_files = {}
346372
abs_root = os.path.abspath(args.root)
347-
for root, dirs, files in os.walk(args.root, followlinks=args.follow_symlinks):
348-
dirs[:] = filter_dirs(root, dirs, excl_paths)
349-
350-
root_is_libtool_dir = is_libtool_dir(root)
351-
for filepath in files:
352-
if os.path.splitext(filepath)[1] == '.gcov':
353-
gcov_path = os.path.join(os.path.join(root, filepath))
354-
with open(gcov_path, mode='rb') as fobj:
355-
source_file_line = fobj.readline().decode('utf-8', 'replace')
356-
source_file_path = source_file_line.split(':')[-1].strip()
357-
if not os.path.isabs(source_file_path):
358-
if args.build_root:
359-
source_file_path = os.path.join(
360-
args.build_root, source_file_path)
361-
elif root_is_libtool_dir:
362-
source_file_path = os.path.abspath(
363-
libtool_source_file_path(
364-
root, source_file_path))
365-
else:
366-
if not source_file_path.startswith(os.path.pardir + os.path.sep) and \
367-
os.path.dirname(source_file_path):
368-
the_root = abs_root
369-
else:
370-
the_root = root
371-
source_file_path = os.path.abspath(
372-
os.path.join(the_root, source_file_path))
373-
src_path = os.path.relpath(source_file_path, abs_root)
374-
if src_path.startswith(os.path.pardir + os.path.sep):
375-
continue
376-
if is_excluded_path(args, source_file_path):
377-
continue
378-
373+
if args.lcov_file:
374+
info_lines = [line.rstrip('\n') for line in open(args.lcov_file, 'r')]
375+
line_iter = iter(info_lines)
376+
new_file_re = re.compile('SF:(.*)')
377+
line_coverage_re = re.compile('DA:(\d+),(\d+)');
378+
while True:
379+
try:
380+
line = line_iter.next()
381+
new_file_match = new_file_re.match(line)
382+
if new_file_match:
379383
src_report = {}
380-
src_report['name'] = posix_path(src_path)
381-
discovered_files.add(src_path)
382-
with io.open(source_file_path, mode='rb') as src_file:
384+
filepath = new_file_match.group(1)
385+
if args.build_root:
386+
filepath = os.path.relpath(filepath, args.build_root)
387+
abs_filepath = os.path.join(abs_root, filepath)
388+
src_report['name'] = unicode(posix_path(filepath))
389+
with io.open(abs_filepath, mode='rb') as src_file:
383390
src_report['source_digest'] = hashlib.md5(src_file.read()).hexdigest()
384-
385-
src_report['coverage'] = parse_gcov_file(fobj, gcov_path)
386-
if src_path in src_files:
387-
src_files[src_path] = combine_reports(src_files[src_path], src_report)
388-
else:
389-
src_files[src_path] = src_report
391+
src_report['coverage'] = parse_lcov_file_info(abs_filepath, line_iter, line_coverage_re, "end_of_record")
392+
src_files[filepath] = src_report
393+
elif line != "TN:":
394+
print "invalid info file"
395+
except StopIteration:
396+
break
397+
else:
398+
for root, dirs, files in os.walk(args.root, followlinks=args.follow_symlinks):
399+
dirs[:] = filter_dirs(root, dirs, excl_paths)
400+
401+
root_is_libtool_dir = is_libtool_dir(root)
402+
for filepath in files:
403+
if os.path.splitext(filepath)[1] == '.gcov':
404+
gcov_path = os.path.join(os.path.join(root, filepath))
405+
with open(gcov_path, mode='rb') as fobj:
406+
source_file_line = fobj.readline().decode('utf-8', 'replace')
407+
source_file_path = source_file_line.split(':')[-1].strip()
408+
if not os.path.isabs(source_file_path):
409+
if args.build_root:
410+
source_file_path = os.path.join(
411+
args.build_root, source_file_path)
412+
elif root_is_libtool_dir:
413+
source_file_path = os.path.abspath(
414+
libtool_source_file_path(
415+
root, source_file_path))
416+
else:
417+
if not source_file_path.startswith(os.path.pardir + os.path.sep) and \
418+
os.path.dirname(source_file_path):
419+
the_root = abs_root
420+
else:
421+
the_root = root
422+
source_file_path = os.path.abspath(
423+
os.path.join(the_root, source_file_path))
424+
src_path = os.path.relpath(source_file_path, abs_root)
425+
if src_path.startswith(os.path.pardir + os.path.sep):
426+
continue
427+
if is_excluded_path(args, source_file_path):
428+
continue
429+
430+
src_report = {}
431+
src_report['name'] = posix_path(src_path)
432+
discovered_files.add(src_path)
433+
with io.open(source_file_path, mode='rb') as src_file:
434+
src_report['source_digest'] = hashlib.md5(src_file.read()).hexdigest()
435+
436+
src_report['coverage'] = parse_gcov_file(fobj, gcov_path)
437+
if src_path in src_files:
438+
src_files[src_path] = combine_reports(src_files[src_path], src_report)
439+
else:
440+
src_files[src_path] = src_report
390441

391442
report['source_files'] = list(src_files.values())
392443
# Also collects the source files that have no coverage reports.
393-
report['source_files'].extend(
394-
collect_non_report_files(args, discovered_files))
444+
if not args.lcov_file:
445+
report['source_files'].extend(
446+
collect_non_report_files(args, discovered_files))
395447

396448
# Use the root directory to get information on the Git repository
397449
report['git'] = gitrepo.gitrepo(abs_root)

0 commit comments

Comments
 (0)