check_build_warnings.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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 argparse
  9. import logging
  10. import os
  11. import re
  12. import sys
  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'(?:error|warning)[^\w]', 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.warning('Empty build list')
  67. SystemExit(0)
  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()