| # Copyright 2024 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """This provides an easy way to access args.gn.""" |
| |
| import os |
| import re |
| import sys |
| |
| |
| def _find_root(output_dir): |
| curdir = output_dir |
| while True: |
| if os.path.exists(os.path.join(curdir, ".gn")): |
| return curdir |
| nextdir = os.path.join(curdir, "..") |
| if os.path.abspath(curdir) == os.path.abspath(nextdir): |
| raise Exception( |
| 'Could not find checkout in any parent of the current path.') |
| curdir = nextdir |
| |
| |
| def _gn_lines(output_dir, path): |
| """ |
| Generator function that returns args.gn lines one at a time, following |
| import directives as needed. |
| """ |
| import_re = re.compile(r'\s*import\("(.*)"\)') |
| with open(path, encoding="utf-8") as f: |
| for line in f: |
| match = import_re.match(line) |
| if match: |
| raw_import_path = match.groups()[0] |
| if raw_import_path[:2] == "//": |
| import_path = os.path.normpath( |
| os.path.join(_find_root(output_dir), |
| raw_import_path[2:])) |
| elif raw_import_path.startswith('/'): |
| # GN uses "/"-prefix as absolute path, |
| # https://gn.googlesource.com/gn/+/main/docs/reference.md#labels |
| # e.g. |
| # /usr/local/foo:bar |
| # /C:/Program Files/MyLibs:bar |
| # but Win32's absolute path doesn't have "/"-prefix. |
| if sys.platform.startswith('win32'): |
| import_path = raw_import_path[1:] |
| else: |
| import_path = raw_import_path |
| if not os.path.isabs(import_path): |
| raise Exception('Wrong absolute path for import %s' % |
| raw_import_path) |
| else: |
| if os.path.isabs(raw_import_path): |
| raise Execption( |
| 'Absolute path "%s" should start with "/" in GN' % |
| raw_import_path) |
| import_path = os.path.normpath( |
| os.path.join(os.path.dirname(path), raw_import_path)) |
| yield from _gn_lines(output_dir, import_path) |
| else: |
| yield line |
| |
| |
| def _path(output_dir): |
| return os.path.join(output_dir, "args.gn") |
| |
| |
| def exists(output_dir): |
| """Checks args.gn exists in output_dir.""" |
| return os.path.exists(_path(output_dir)) |
| |
| |
| def lines(output_dir): |
| """Generator of args.gn lines. comment is removed.""" |
| if not exists(output_dir): |
| return |
| for line in _gn_lines(output_dir, _path(output_dir)): |
| line_without_comment = line.split("#")[0] |
| yield line_without_comment |
| |
| |
| _gn_arg_pattern = re.compile(r"(^|\s*)([^=\s]*)\s*=\s*(\S*)\s*$") |
| |
| |
| def args(output_dir): |
| """Generator of args.gn's key,value pair.""" |
| for line in lines(output_dir): |
| m = _gn_arg_pattern.match(line) |
| if not m: |
| continue |
| yield (m.group(2), m.group(3)) |