diff --git a/Testsuite/test/post_process_ctest_results.py b/Testsuite/test/post_process_ctest_results.py index 6da4d7de21c1..45ea579532bc 100644 --- a/Testsuite/test/post_process_ctest_results.py +++ b/Testsuite/test/post_process_ctest_results.py @@ -1,75 +1,169 @@ import sys -import io import re import os +import collections +import logging +from itertools import islice -report_file=sys.argv[1] -report_name=sys.argv[2] -global_report_name=sys.argv[3] -rx=re.compile('(.*Configuring (examples|demo|test)*( in )*(test\/|examples\/|demo\/)*)((?!done)\w+)') -rx_demo=re.compile('.*in demo\/') -rx_examples=re.compile('.*in examples\/') - - -#open the Installation report -#For each NAME, check if NAME is a directory. If not, create one, create a -#text report, and write everything that is in the report until the next NAME -#in it. Then, add 'NAME r' in the global report. This should allow to get all -#the NOTICE and other info explaining why the configuration is skipped. - -name="" -is_writing=False -is_ignored=False -global_report=open(global_report_name, "a+") -with open(report_file, "rt") as test_report: - for myline in test_report: - m=rx.match(myline) - - if is_writing: - if m: - is_writing=False - test_report.close() - if is_ignored: - print("{label} {result}".format(label=name, result='r'), file=global_report) - is_ignored=False - else: - test_report.write(myline) - if not is_writing: - if m: - name=m.group(0).replace(m.group(1), "") - if rx_demo.match(myline): - name="{str}_Demo".format(str=name) - elif rx_examples.match(myline): - name="{str}_Examples".format(str=name) - elif name == "libCGAL": - name="libCGAL_shared" - elif name == "libCGAL_Core": - name="libCGALCore_shared" - elif name == "libCGAL_ImageIO": - name="libCGALimageIO_shared" - elif name == "libCGAL_Qt6": - name="libCGALQt6_shared" - if name=="incomplete": - is_writing=False - is_ignored=False - continue - else: - if not os.path.isdir(name): - is_ignored=True - os.mkdir(name) - test_report=open("{dir}/{file}".format(dir=name, file=report_name), "w+") - print(""" -{scm_branch} -""" .format(scm_branch=open("{}/../../../../../.scm-branch".format(os.getcwd()), 'r').read()),file=test_report) - else: - is_ignored=False - test_report=open("{dir}/{file}".format(dir=name, file=report_name), "a+") - test_report.write(" --- CMake Results: --- \n\n") - is_writing=True -if is_writing: - is_writing=False - test_report.close() - if is_ignored: - print("{label} {result}".format(label=name, result='r'), file=global_report) - is_ignored=False -global_report.close() +CONFIG_REGEX = re.compile( + r"(.*Configuring (examples|demo|test) *in *(test/|examples/|demo/))((?!done)\w+)" +) +DEMO_REGEX = re.compile(r".*in demo/") +EXAMPLES_REGEX = re.compile(r'.*in examples/') +SEPARATOR = "------------------------------------------------------------------" + +def find_third_separator(contents): + """Find the position of the third separator line in the contents. + If there are less than 3 separators, then return the position where the third separator + should be inserted. + """ + separator_positions = ( + i for i, line in enumerate(contents) if line.strip() == SEPARATOR + ) + return next(islice(separator_positions, 2, None), len(contents) + 2) + +def last(iterator): + """Return the last item of an iterator or None if empty.""" + return collections.deque(iterator, maxlen=1).pop() + +def find_last(contents, query_string): + """Find the number of the last line matching the query string.""" + position, _ = last(filter(lambda x: x[1].strip() == query_string, enumerate(contents))) + return position + +def read_file_lines(file_path): + """Read the lines of a file and return them as a list.""" + try: + with open(file_path, "r", encoding="utf-8") as file: + return file.readlines() + except IOError as e: + print(f"Error opening file {file_path}: {e}") + return [] + +def write_file_lines(file_path, contents): + """Write the contents to a file. The contents should be a list of strings.""" + try: + with open(file_path, "w", encoding="utf-8") as file: + file.write("".join(contents)) + except IOError as e: + print(f"Error writing to file {file_path}: {e}") + +def mark_package_as_missing_requirements(global_report_file_name, name): + """Mark a package as missing requirements in the global report file.""" + try: + with open(global_report_file_name, "a+", encoding="utf-8") as global_report: + print(f"{name} r", file=global_report) + except IOError as e: + print(f"Error opening global report file {global_report_file_name}: {e}") + +def handle_end_of_package(package_name, report_file_name, lines_to_write): + """Handle the end of a package by inserting the lines to write into the report file.""" + if not lines_to_write: + return + + file_path = f"{package_name}/{report_file_name}" + contents = read_file_lines(file_path) + position = find_third_separator(contents) + + if not any(re.search("- CMake Results .*", content) for content in contents): + lines_to_write.insert(0, f""" +{SEPARATOR} +- CMake Results for {package_name} +{SEPARATOR} + +""") + contents[position:position] = lines_to_write + + write_file_lines(file_path, contents) + + +SCM_BRANCH_FILE_CONTENT = read_file_lines(f"{os.getcwd()}/../../../../../.scm-branch") + +def handle_new_package__is_ignored(name, report_file_name, cmake_logs): + """Handle new package creation or update logs if package already exists.""" + if not os.path.isdir(name): + os.mkdir(name) + write_file_lines(f"{name}/{report_file_name}", SCM_BRANCH_FILE_CONTENT) + return True + else: + file_path = f"{name}/{report_file_name}" + contents = read_file_lines(file_path) + position = find_third_separator(contents) + + if not any(re.search("- CMake Logs .*", content) for content in contents): + contents.insert( + position - 1, + SEPARATOR + "\n- CMake Logs from Installation \n" + SEPARATOR + "\n\n", + ) + for log in cmake_logs: + contents.insert(position, log) + position += 1 + + write_file_lines(file_path, contents) + return False + +def retrieve_cmake_logs(file_path): + """Retrieve the CMake logs from a file and return them as a list.""" + logging.debug("Opening file %s", file_path) + contents = read_file_lines(file_path) + + position_begin = 1 + find_last(contents, SEPARATOR) + position_end = 1 + find_last(contents, "== Generating build files for tests ==") + + cmake_logs = contents[position_begin:position_end] + + logging.debug("CMake log beginning is at line %d", position_begin) + logging.debug("CMake log end is at line %d", position_end) + logging.debug("Length of contents is %d", len(contents)) + logging.debug("Length of installation CMake logs is %d", len(cmake_logs)) + logging.debug("Installation CMake logs are %s", "".join(cmake_logs)) + return cmake_logs + +def main(): + """Main function that processes the input report file and performs necessary operations.""" + input_report_file_name = sys.argv[1] + report_file_name = sys.argv[2] + global_report_file_name = sys.argv[3] + + cmake_logs = retrieve_cmake_logs(f"Installation/{report_file_name}") + + package_name = "" + lines_to_write = [] + + for line in read_file_lines(input_report_file_name): + + line_matches_new_package = CONFIG_REGEX.match(line) + if package_name and line_matches_new_package: + handle_end_of_package(package_name, report_file_name, lines_to_write) + lines_to_write = [] + package_name = "" + + if line_matches_new_package: + logging.debug("Found new package %s", line_matches_new_package.group(0)) + logging.debug(" group 1 %s", line_matches_new_package.group(1)) + new_package_name = line_matches_new_package.group(0).replace( + line_matches_new_package.group(1), "" + ) + logging.debug("Setting package name to %s", new_package_name) + package_name = new_package_name + if DEMO_REGEX.match(line): + package_name = f"{package_name}_Demo" + elif EXAMPLES_REGEX.match(line): + package_name = f"{package_name}_Examples" + + if package_name == "incomplete": + package_name = "" + continue + else: + is_ignored = handle_new_package__is_ignored( + package_name, report_file_name, cmake_logs + ) + logging.debug("Is package %s ignored? %s", package_name, is_ignored) + if is_ignored: + mark_package_as_missing_requirements(global_report_file_name, package_name) + + if package_name and not line_matches_new_package and line.strip() != "": + lines_to_write.append(line) + +if __name__ == "__main__": + main()