check_build_warnings.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. #
  4. # CI script to check build logs for warnings.
  5. # Reads the list of builds, in the format produced by find_apps.py or build_apps.py, and finds warnings in the
  6. # log files for every build.
  7. # Exits with a non-zero exit code if any warning is found.
  8. import os
  9. import sys
  10. import argparse
  11. import logging
  12. import re
  13. try:
  14. from find_build_apps import BuildItem, setup_logging
  15. except ImportError:
  16. sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
  17. from find_build_apps import BuildItem, setup_logging
  18. WARNING_REGEX = re.compile(r"^\s*(?:error|warning)", re.MULTILINE | re.IGNORECASE)
  19. IGNORE_WARNS = [
  20. re.compile(r_str) for r_str in [
  21. r"library/error\.o",
  22. r".*error.*\.c\.obj",
  23. r"-Werror",
  24. r"error\.d",
  25. r"reassigning to symbol",
  26. r"changes choice state",
  27. r"crosstool_version_check\.cmake",
  28. r"CryptographyDeprecationWarning",
  29. r"Python 3 versions older than 3.6 are not supported.",
  30. r"Support for Python 2 is deprecated and will be removed in future versions.",
  31. ]
  32. ]
  33. def line_has_warnings(line): # type: (str) -> bool
  34. if not WARNING_REGEX.search(line):
  35. return False
  36. has_warnings = True
  37. for ignored in IGNORE_WARNS:
  38. if re.search(ignored, line):
  39. has_warnings = False
  40. break
  41. return has_warnings
  42. def main():
  43. parser = argparse.ArgumentParser(description="ESP-IDF app builder")
  44. parser.add_argument(
  45. "-v",
  46. "--verbose",
  47. action="count",
  48. help="Increase the logging level of the script. Can be specified multiple times.",
  49. )
  50. parser.add_argument(
  51. "--log-file",
  52. type=argparse.FileType("w"),
  53. help="Write the script log to the specified file, instead of stderr",
  54. )
  55. parser.add_argument(
  56. "build_list",
  57. type=argparse.FileType("r"),
  58. nargs="?",
  59. default=sys.stdin,
  60. help="Name of the file to read the list of builds from. If not specified, read from stdin.",
  61. )
  62. args = parser.parse_args()
  63. setup_logging(args)
  64. build_items = [BuildItem.from_json(line) for line in args.build_list]
  65. if not build_items:
  66. logging.error("Empty build list!")
  67. raise SystemExit(1)
  68. found_warnings = 0
  69. for build_item in build_items:
  70. if not build_item.build_log_path:
  71. logging.debug("No log file for {}".format(build_item.work_dir))
  72. continue
  73. with open(build_item.build_log_path, "r") as log_file:
  74. for line_no, line in enumerate(log_file):
  75. if line_has_warnings(line):
  76. logging.error("Issue in app {}, config {}:".format(build_item.app_dir, build_item.config_name))
  77. logging.error(line.rstrip("\n"))
  78. logging.error("See {}:{} for details".format(os.path.basename(build_item.build_log_path),
  79. line_no + 1))
  80. found_warnings += 1
  81. break
  82. if found_warnings:
  83. logging.error("Checked {} builds, found {} warnings".format(len(build_items), found_warnings))
  84. raise SystemExit(1)
  85. logging.info("No warnings found")
  86. if __name__ == "__main__":
  87. main()