check_build_warnings.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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\S*\.o',
  23. r'.*error.*\.c\.obj',
  24. r'.*error.*\.cpp\.obj',
  25. r'.*error.*\.cxx\.obj',
  26. r'.*error.*\.cc\.obj',
  27. r'-Werror',
  28. r'error\.d',
  29. r'/.*error\S*.d',
  30. r'reassigning to symbol',
  31. r'changes choice state',
  32. r'crosstool_version_check\.cmake',
  33. r'CryptographyDeprecationWarning',
  34. r'Warning: \d+/\d+ app partitions are too small for binary'
  35. ]
  36. ]
  37. def line_has_warnings(line): # type: (str) -> bool
  38. if not WARNING_REGEX.search(line):
  39. return False
  40. has_warnings = True
  41. for ignored in IGNORE_WARNS:
  42. if re.search(ignored, line):
  43. has_warnings = False
  44. break
  45. return has_warnings
  46. def main(): # type: () -> None
  47. parser = argparse.ArgumentParser(description='ESP-IDF app builder')
  48. parser.add_argument(
  49. '-v',
  50. '--verbose',
  51. action='count',
  52. help='Increase the logging level of the script. Can be specified multiple times.',
  53. )
  54. parser.add_argument(
  55. '--log-file',
  56. type=argparse.FileType('w'),
  57. help='Write the script log to the specified file, instead of stderr',
  58. )
  59. parser.add_argument(
  60. 'build_list',
  61. type=argparse.FileType('r'),
  62. nargs='?',
  63. default=sys.stdin,
  64. help='Name of the file to read the list of builds from. If not specified, read from stdin.',
  65. )
  66. args = parser.parse_args()
  67. setup_logging(args)
  68. build_items = [BuildItem.from_json(line) for line in args.build_list]
  69. if not build_items:
  70. logging.warning('Empty build list')
  71. SystemExit(0)
  72. found_warnings = 0
  73. for build_item in build_items:
  74. if not build_item.build_log_path:
  75. logging.debug('No log file for {}'.format(build_item.work_dir))
  76. continue
  77. with open(build_item.build_log_path, 'r') as log_file:
  78. for line_no, line in enumerate(log_file):
  79. if line_has_warnings(line):
  80. logging.error('Issue in app {}, config {}:'.format(build_item.app_dir, build_item.config_name))
  81. logging.error(line.rstrip('\n'))
  82. logging.error('See {}:{} for details'.format(os.path.basename(build_item.build_log_path),
  83. line_no + 1))
  84. found_warnings += 1
  85. break
  86. if found_warnings:
  87. logging.error('Checked {} builds, found {} warnings'.format(len(build_items), found_warnings))
  88. raise SystemExit(1)
  89. logging.info('No warnings found')
  90. if __name__ == '__main__':
  91. main()