gn_helpers: Add support for imported args files.
The libassistant build calls gn_helpers to read the out dir's args.gn file (while it's being invoked by ninja, mind you!) and passes its contents through gn_helpers, applies a filtering, then creates a sub build dir (within the original build dir) using its modified set of GN args. This is problematic since crbug.com/937821 is trying to transition CrOS bots to using import() lines in their args file, which breaks libassistant's build. This fixes that by adding import support to gn_helpers. Bug: 937821 Change-Id: I790bc27368611f31b63a0135c0e5919f35b21e6e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2107709 Reviewed-by: Takuto Ikuta <tikuta@chromium.org> Commit-Queue: Ben Pastene <bpastene@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#752503} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 00156a211ee71ca14e6dcb1084b88b9ad92944e9
This commit is contained in:
Родитель
39e7b36992
Коммит
d079f3a5d1
|
@ -19,9 +19,14 @@ To use in a random python file in the build:
|
|||
Where the sequence of parameters to join is the relative path from your source
|
||||
file to the build directory."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
IMPORT_RE = re.compile(r'^import\("//(\S+)"\)')
|
||||
|
||||
|
||||
class GNException(Exception):
|
||||
pass
|
||||
|
||||
|
@ -170,6 +175,31 @@ class GNValueParser(object):
|
|||
def IsDone(self):
|
||||
return self.cur == len(self.input)
|
||||
|
||||
def ReplaceImports(self):
|
||||
"""Replaces import(...) lines with the contents of the imports.
|
||||
|
||||
Recurses on itself until there are no imports remaining, in the case of
|
||||
nested imports.
|
||||
"""
|
||||
lines = self.input.splitlines()
|
||||
if not any(line.startswith('import(') for line in lines):
|
||||
return
|
||||
for line in lines:
|
||||
if not line.startswith('import('):
|
||||
continue
|
||||
regex_match = IMPORT_RE.match(line)
|
||||
if not regex_match:
|
||||
raise GNException('Not a valid import string: %s' % line)
|
||||
import_path = os.path.join(
|
||||
os.path.dirname(__file__), os.pardir, regex_match.group(1))
|
||||
with open(import_path) as f:
|
||||
imported_args = f.read()
|
||||
self.input = self.input.replace(line, imported_args)
|
||||
# Call ourselves again if we've just replaced an import() with additional
|
||||
# imports.
|
||||
self.ReplaceImports()
|
||||
|
||||
|
||||
def ConsumeWhitespace(self):
|
||||
while not self.IsDone() and self.input[self.cur] in ' \t\n':
|
||||
self.cur += 1
|
||||
|
@ -218,6 +248,7 @@ class GNValueParser(object):
|
|||
"""
|
||||
d = {}
|
||||
|
||||
self.ReplaceImports()
|
||||
self.ConsumeWhitespace()
|
||||
self.ConsumeComment()
|
||||
while not self.IsDone():
|
||||
|
|
|
@ -2,9 +2,13 @@
|
|||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import gn_helpers
|
||||
import mock
|
||||
import textwrap
|
||||
import unittest
|
||||
|
||||
import gn_helpers
|
||||
|
||||
|
||||
class UnitTest(unittest.TestCase):
|
||||
def test_ToGNString(self):
|
||||
self.assertEqual(
|
||||
|
@ -122,5 +126,58 @@ class UnitTest(unittest.TestCase):
|
|||
self.assertEqual(gn_helpers.FromGNArgs('foo_=true'),
|
||||
{'foo_': True})
|
||||
|
||||
def test_ReplaceImports(self):
|
||||
# Should be a no-op on args inputs without any imports.
|
||||
parser = gn_helpers.GNValueParser(
|
||||
textwrap.dedent("""
|
||||
some_arg1 = "val1"
|
||||
some_arg2 = "val2"
|
||||
"""))
|
||||
parser.ReplaceImports()
|
||||
self.assertEquals(
|
||||
parser.input,
|
||||
textwrap.dedent("""
|
||||
some_arg1 = "val1"
|
||||
some_arg2 = "val2"
|
||||
"""))
|
||||
|
||||
# A single "import(...)" line should be replaced with the contents of the
|
||||
# file being imported.
|
||||
parser = gn_helpers.GNValueParser(
|
||||
textwrap.dedent("""
|
||||
some_arg1 = "val1"
|
||||
import("//some/args/file.gni")
|
||||
some_arg2 = "val2"
|
||||
"""))
|
||||
fake_import = 'some_imported_arg = "imported_val"'
|
||||
with mock.patch('__builtin__.open', mock.mock_open(read_data=fake_import)):
|
||||
parser.ReplaceImports()
|
||||
self.assertEquals(
|
||||
parser.input,
|
||||
textwrap.dedent("""
|
||||
some_arg1 = "val1"
|
||||
some_imported_arg = "imported_val"
|
||||
some_arg2 = "val2"
|
||||
"""))
|
||||
|
||||
# No trailing parenthesis should raise an exception.
|
||||
with self.assertRaises(gn_helpers.GNException):
|
||||
parser = gn_helpers.GNValueParser(
|
||||
textwrap.dedent('import("//some/args/file.gni"'))
|
||||
parser.ReplaceImports()
|
||||
|
||||
# No double quotes should raise an exception.
|
||||
with self.assertRaises(gn_helpers.GNException):
|
||||
parser = gn_helpers.GNValueParser(
|
||||
textwrap.dedent('import(//some/args/file.gni)'))
|
||||
parser.ReplaceImports()
|
||||
|
||||
# A path that's not source absolute should raise an exception.
|
||||
with self.assertRaises(gn_helpers.GNException):
|
||||
parser = gn_helpers.GNValueParser(
|
||||
textwrap.dedent('import("some/relative/args/file.gni")'))
|
||||
parser.ReplaceImports()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
Загрузка…
Ссылка в новой задаче