utils.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. # Copyright 2022 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. """ A collection of commonly used functions across depot_tools.
  5. """
  6. import codecs
  7. import logging
  8. import os
  9. import re
  10. import subprocess
  11. def depot_tools_version():
  12. depot_tools_root = os.path.dirname(os.path.abspath(__file__))
  13. try:
  14. commit_hash = subprocess.check_output(['git', 'rev-parse', 'HEAD'],
  15. cwd=depot_tools_root).decode(
  16. 'utf-8', 'ignore')
  17. return 'git-%s' % commit_hash
  18. except Exception:
  19. pass
  20. # git check failed, let's check last modification of frequently checked file
  21. try:
  22. mtime = os.path.getmtime(
  23. os.path.join(depot_tools_root, 'infra', 'config', 'recipes.cfg'))
  24. return 'recipes.cfg-%d' % (mtime)
  25. except Exception:
  26. return 'unknown'
  27. def normpath(path):
  28. '''Version of os.path.normpath that also changes backward slashes to
  29. forward slashes when not running on Windows.
  30. '''
  31. # This is safe to always do because the Windows version of os.path.normpath
  32. # will replace forward slashes with backward slashes.
  33. path = path.replace(os.sep, '/')
  34. return os.path.normpath(path)
  35. def ListRelevantFilesInSourceCheckout(files, root, match_re, exclude_re):
  36. """Finds all files that apply to a given set of source files, e.g. PRESUBMIT.
  37. If inherit-review-settings-ok is present right under root, looks for matches
  38. in directories enclosing root.
  39. Args:
  40. files: An iterable container containing file paths.
  41. root: Path where to stop searching.
  42. match_re: regex to match filename
  43. exclude_re: regex to exclude filename
  44. Return:
  45. List of absolute paths of the existing PRESUBMIT.py scripts.
  46. """
  47. files = [normpath(os.path.join(root, f)) for f in files]
  48. # List all the individual directories containing files.
  49. directories = {os.path.dirname(f) for f in files}
  50. # Ignore root if inherit-review-settings-ok is present.
  51. if os.path.isfile(os.path.join(root, 'inherit-review-settings-ok')):
  52. root = None
  53. # Collect all unique directories that may contain PRESUBMIT.py.
  54. candidates = set()
  55. for directory in directories:
  56. while True:
  57. if directory in candidates:
  58. break
  59. candidates.add(directory)
  60. if directory == root:
  61. break
  62. parent_dir = os.path.dirname(directory)
  63. if parent_dir == directory:
  64. # We hit the system root directory.
  65. break
  66. directory = parent_dir
  67. # Look for PRESUBMIT.py in all candidate directories.
  68. results = []
  69. for directory in sorted(list(candidates)):
  70. try:
  71. for f in os.listdir(directory):
  72. p = os.path.join(directory, f)
  73. if os.path.isfile(p) and re.match(match_re,
  74. f) and not re.match(exclude_re, f):
  75. results.append(p)
  76. except OSError:
  77. pass
  78. logging.debug('Presubmit files: %s', ','.join(results))
  79. return results
  80. def FileRead(filename, mode='rbU'):
  81. # mode is ignored now; we always return unicode strings.
  82. with open(filename, mode='rb') as f:
  83. s = f.read()
  84. try:
  85. return s.decode('utf-8', 'replace')
  86. except (UnicodeDecodeError, AttributeError):
  87. return s
  88. def FileWrite(filename, content, mode='w', encoding='utf-8'):
  89. with codecs.open(filename, mode=mode, encoding=encoding) as f:
  90. f.write(content)