gn_helper.py 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. # Copyright 2024 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. """This provides an easy way to access args.gn."""
  5. import os
  6. import re
  7. import sys
  8. def _find_root(output_dir):
  9. curdir = output_dir
  10. while True:
  11. if os.path.exists(os.path.join(curdir, ".gn")):
  12. return curdir
  13. nextdir = os.path.join(curdir, "..")
  14. if os.path.abspath(curdir) == os.path.abspath(nextdir):
  15. raise Exception(
  16. 'Could not find checkout in any parent of the current path.')
  17. curdir = nextdir
  18. def _gn_lines(output_dir, path):
  19. """
  20. Generator function that returns args.gn lines one at a time, following
  21. import directives as needed.
  22. """
  23. import_re = re.compile(r'\s*import\("(.*)"\)')
  24. with open(path, encoding="utf-8") as f:
  25. for line in f:
  26. match = import_re.match(line)
  27. if match:
  28. raw_import_path = match.groups()[0]
  29. if raw_import_path[:2] == "//":
  30. import_path = os.path.normpath(
  31. os.path.join(_find_root(output_dir),
  32. raw_import_path[2:]))
  33. elif raw_import_path.startswith('/'):
  34. # GN uses "/"-prefix as absolute path,
  35. # https://gn.googlesource.com/gn/+/main/docs/reference.md#labels
  36. # e.g.
  37. # /usr/local/foo:bar
  38. # /C:/Program Files/MyLibs:bar
  39. # but Win32's absolute path doesn't have "/"-prefix.
  40. if sys.platform.startswith('win32'):
  41. import_path = raw_import_path[1:]
  42. else:
  43. import_path = raw_import_path
  44. if not os.path.isabs(import_path):
  45. raise Exception('Wrong absolute path for import %s' %
  46. raw_import_path)
  47. else:
  48. if os.path.isabs(raw_import_path):
  49. raise Execption(
  50. 'Absolute path "%s" should start with "/" in GN' %
  51. raw_import_path)
  52. import_path = os.path.normpath(
  53. os.path.join(os.path.dirname(path), raw_import_path))
  54. yield from _gn_lines(output_dir, import_path)
  55. else:
  56. yield line
  57. def _path(output_dir):
  58. return os.path.join(output_dir, "args.gn")
  59. def exists(output_dir):
  60. """Checks args.gn exists in output_dir."""
  61. return os.path.exists(_path(output_dir))
  62. def lines(output_dir):
  63. """Generator of args.gn lines. comment is removed."""
  64. if not exists(output_dir):
  65. return
  66. for line in _gn_lines(output_dir, _path(output_dir)):
  67. line_without_comment = line.split("#")[0]
  68. yield line_without_comment
  69. _gn_arg_pattern = re.compile(r"(^|\s*)([^=\s]*)\s*=\s*(\S*)\s*$")
  70. def args(output_dir):
  71. """Generator of args.gn's key,value pair."""
  72. for line in lines(output_dir):
  73. m = _gn_arg_pattern.match(line)
  74. if not m:
  75. continue
  76. yield (m.group(2), m.group(3))