37
37
reports as reports_helper , statistics as report_statistics
38
38
from codechecker_report_converter .report .hash import HashType , \
39
39
get_report_path_hash
40
+ from codechecker_report_converter .report .parser .base import AnalyzerInfo
40
41
41
42
from codechecker_client import client as libclient
42
43
from codechecker_client import product
@@ -404,10 +405,12 @@ def parse_analyzer_result_files(
404
405
""" Get reports from the given analyzer result files. """
405
406
analyzer_result_file_reports : AnalyzerResultFileReports = defaultdict (list )
406
407
407
- for file_path , reports in zip (
408
+ for idx , ( file_path , reports ) in enumerate ( zip (
408
409
analyzer_result_files , zip_iter (
409
410
functools .partial (get_reports , checker_labels = checker_labels ),
410
- analyzer_result_files )):
411
+ analyzer_result_files ))):
412
+ LOG .debug (f"[{ idx } /{ len (analyzer_result_files )} ] "
413
+ f"Parsed '{ file_path } ' ..." )
411
414
analyzer_result_file_reports [file_path ] = reports
412
415
413
416
return analyzer_result_file_reports
@@ -421,8 +424,12 @@ def assemble_zip(inputs,
421
424
"""Collect and compress report and source files, together with files
422
425
contanining analysis related information into a zip file which
423
426
will be sent to the server.
427
+
428
+ For each report directory, we create a uniqued zipped directory. Each
429
+ report directory to store could have been made with different
430
+ configurations, so we can't merge them all into a single zip.
424
431
"""
425
- files_to_compress = set ( )
432
+ files_to_compress : Dict [ str , set ] = defaultdict ( set )
426
433
analyzer_result_file_paths = []
427
434
stats = StorageZipStatistics ()
428
435
@@ -431,21 +438,24 @@ def assemble_zip(inputs,
431
438
432
439
metadata_file_path = os .path .join (dir_path , 'metadata.json' )
433
440
if os .path .exists (metadata_file_path ):
434
- files_to_compress .add (metadata_file_path )
441
+ files_to_compress [os .path .dirname (metadata_file_path )] \
442
+ .add (metadata_file_path )
435
443
436
444
skip_file_path = os .path .join (dir_path , 'skip_file' )
437
445
if os .path .exists (skip_file_path ):
438
446
with open (skip_file_path , 'r' ) as f :
439
447
LOG .info ("Found skip file %s with the following content:\n %s" ,
440
448
skip_file_path , f .read ())
441
449
442
- files_to_compress .add (skip_file_path )
450
+ files_to_compress [os .path .dirname (skip_file_path )] \
451
+ .add (skip_file_path )
443
452
444
453
review_status_file_path = os .path .join (dir_path , 'review_status.yaml' )
445
454
if os .path .exists (review_status_file_path ):
446
- files_to_compress .add (review_status_file_path )
455
+ files_to_compress [os .path .dirname (review_status_file_path )]\
456
+ .add (review_status_file_path )
447
457
448
- LOG .debug ("Processing report files ..." )
458
+ LOG .debug (f "Processing { len ( analyzer_result_file_paths ) } report files ..." )
449
459
450
460
with MultiProcessPool () as executor :
451
461
analyzer_result_file_reports = parse_analyzer_result_files (
@@ -456,24 +466,43 @@ def assemble_zip(inputs,
456
466
changed_files = set ()
457
467
file_paths = set ()
458
468
file_report_positions : FileReportPositions = defaultdict (set )
459
- unique_reports = set ()
469
+ unique_reports : Dict [str , Dict [str , List [Report ]]] = defaultdict (dict )
470
+
471
+ unique_report_hashes = set ()
460
472
for file_path , reports in analyzer_result_file_reports .items ():
461
- files_to_compress .add (file_path )
462
473
stats .num_of_analyzer_result_files += 1
463
474
464
475
for report in reports :
465
476
if report .changed_files :
466
477
changed_files .update (report .changed_files )
467
478
continue
468
- # Need to calculate unique reoirt count to determine report limit
479
+ # Unique all bug reports per report directory; also, count how many
480
+ # reports we want to store at once to check for the report store
481
+ # limit.
469
482
report_path_hash = get_report_path_hash (report )
470
- if report_path_hash not in unique_reports :
471
- unique_reports .add (report_path_hash )
483
+ if report_path_hash not in unique_report_hashes :
484
+ unique_report_hashes .add (report_path_hash )
485
+ unique_reports [os .path .dirname (file_path )]\
486
+ .setdefault (report .analyzer_name , []) \
487
+ .append (report )
472
488
stats .add_report (report )
473
489
474
490
file_paths .update (report .original_files )
475
491
file_report_positions [report .file .original_path ].add (report .line )
476
492
493
+ files_to_delete = []
494
+ for dirname , analyzer_reports in unique_reports .items ():
495
+ for analyzer_name , reports in analyzer_reports .items ():
496
+ if not analyzer_name :
497
+ analyzer_name = 'unknown'
498
+ _ , tmpfile = tempfile .mkstemp (f'-{ analyzer_name } .plist' )
499
+
500
+ report_file .create (tmpfile , reports , checker_labels ,
501
+ AnalyzerInfo (analyzer_name ))
502
+ LOG .debug (f"Stored '{ analyzer_name } ' unique reports in { tmpfile } ." )
503
+ files_to_compress [dirname ].add (tmpfile )
504
+ files_to_delete .append (tmpfile )
505
+
477
506
if changed_files :
478
507
reports_helper .dump_changed_files (changed_files )
479
508
sys .exit (1 )
@@ -529,15 +558,17 @@ def assemble_zip(inputs,
529
558
LOG .info ("Building report zip file..." )
530
559
with zipfile .ZipFile (zip_file , 'a' , allowZip64 = True ) as zipf :
531
560
# Add the files to the zip which will be sent to the server.
532
- for file_path in files_to_compress :
533
- _ , file_name = os .path .split (file_path )
534
561
535
- # Create a unique report directory name.
536
- report_dir_name = hashlib . md5 ( os . path . dirname (
537
- file_path ). encode ( 'utf-8' )). hexdigest ( )
562
+ for dirname , files in files_to_compress . items ():
563
+ for file_path in files :
564
+ _ , file_name = os . path . split ( file_path )
538
565
539
- zip_target = os .path .join ('reports' , report_dir_name , file_name )
540
- zipf .write (file_path , zip_target )
566
+ # Create a unique report directory name.
567
+ report_dir_name = \
568
+ hashlib .md5 (dirname .encode ('utf-8' )).hexdigest ()
569
+ zip_target = \
570
+ os .path .join ('reports' , report_dir_name , file_name )
571
+ zipf .write (file_path , zip_target )
541
572
542
573
collected_file_paths = set ()
543
574
for f , h in file_to_hash .items ():
@@ -611,6 +642,10 @@ def assemble_zip(inputs,
611
642
LOG .info ("Compressing report zip file done (%s / %s)." ,
612
643
sizeof_fmt (zip_size ), sizeof_fmt (compressed_zip_size ))
613
644
645
+ # We are responsible for deleting these.
646
+ for file in files_to_delete :
647
+ os .remove (file )
648
+
614
649
615
650
def should_be_zipped (input_file : str , input_files : Iterable [str ]) -> bool :
616
651
"""
0 commit comments