Skip to content

Commit

Permalink
Update gn_helpers.py from upstream (flutter#493)
Browse files Browse the repository at this point in the history
Updates our ToGNString implementation to match the Chromium version at
version 4e21091c52ffc65be4df7839cc2e86575237e968 of the upstream repo
https://chromium.googlesource.com/chromium/src/+/refs/heads/main/build/gn_helpers.py

Also switches to absolute (buildroot relative) paths for invocations of
vs_toolchain.py.
  • Loading branch information
cbracken authored Jul 30, 2021
1 parent ed767ed commit 3006780
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 26 deletions.
2 changes: 1 addition & 1 deletion build/config/win/visual_studio_version.gni
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ declare_args() {

if (visual_studio_path == "") {
_toolchain_data =
exec_script("../../vs_toolchain.py", [ "get_toolchain_dir" ], "scope")
exec_script("//build/vs_toolchain.py", [ "get_toolchain_dir" ], "scope")
visual_studio_path = _toolchain_data.vs_path
windows_sdk_path = _toolchain_data.sdk_path
visual_studio_version = _toolchain_data.vs_version
Expand Down
142 changes: 118 additions & 24 deletions build/gn_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,132 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import sys

"""Helper functions useful when writing scripts that are run from GN's
exec_script function."""

class GNException(Exception):
class GNError(Exception):
pass


def ToGNString(value, allow_dicts = True):
"""Prints the given value to stdout.
# Computes ASCII code of an element of encoded Python 2 str / Python 3 bytes.
_Ord = ord if sys.version_info.major < 3 else lambda c: c


def _TranslateToGnChars(s):
for decoded_ch in s.encode('utf-8'): # str in Python 2, bytes in Python 3.
code = _Ord(decoded_ch) # int
if code in (34, 36, 92): # For '"', '$', or '\\'.
yield '\\' + chr(code)
elif 32 <= code < 127:
yield chr(code)
else:
yield '$0x%02X' % code


def ToGNString(value, pretty=False):
"""Returns a stringified GN equivalent of a Python value.
Args:
value: The Python value to convert.
pretty: Whether to pretty print. If true, then non-empty lists are rendered
recursively with one item per line, with indents. Otherwise lists are
rendered without new line.
Returns:
The stringified GN equivalent to |value|.
Raises:
GNError: |value| cannot be printed to GN.
"""

if sys.version_info.major < 3:
basestring_compat = basestring
else:
basestring_compat = str

# Emits all output tokens without intervening whitespaces.
def GenerateTokens(v, level):
if isinstance(v, basestring_compat):
yield '"' + ''.join(_TranslateToGnChars(v)) + '"'

elif isinstance(v, bool):
yield 'true' if v else 'false'

elif isinstance(v, int):
yield str(v)

elif isinstance(v, list):
yield '['
for i, item in enumerate(v):
if i > 0:
yield ','
for tok in GenerateTokens(item, level + 1):
yield tok
yield ']'

elif isinstance(v, dict):
if level > 0:
yield '{'
for key in sorted(v):
if not isinstance(key, basestring_compat):
raise GNError('Dictionary key is not a string.')
if not key or key[0].isdigit() or not key.replace('_', '').isalnum():
raise GNError('Dictionary key is not a valid GN identifier.')
yield key # No quotations.
yield '='
for tok in GenerateTokens(v[key], level + 1):
yield tok
if level > 0:
yield '}'

else: # Not supporting float: Add only when needed.
raise GNError('Unsupported type when printing to GN.')

allow_dicts indicates if this function will allow converting dictionaries
to GN scopes. This is only possible at the top level, you can't nest a
GN scope in a list, so this should be set to False for recursive calls."""
if isinstance(value, str) or isinstance(value, str):
if value.find('\n') >= 0:
raise GNException("Trying to print a string with a newline in it.")
return '"' + value.replace('"', '\\"') + '"'
can_start = lambda tok: tok and tok not in ',}]='
can_end = lambda tok: tok and tok not in ',{[='

if isinstance(value, list):
return '[ %s ]' % ', '.join(ToGNString(v) for v in value)
# Adds whitespaces, trying to keep everything (except dicts) in 1 line.
def PlainGlue(gen):
prev_tok = None
for i, tok in enumerate(gen):
if i > 0:
if can_end(prev_tok) and can_start(tok):
yield '\n' # New dict item.
elif prev_tok == '[' and tok == ']':
yield ' ' # Special case for [].
elif tok != ',':
yield ' '
yield tok
prev_tok = tok

if isinstance(value, dict):
if not allow_dicts:
raise GNException("Attempting to recursively print a dictionary.")
result = ""
for key in value:
if not isinstance(key, str):
raise GNException("Dictionary key is not a string.")
result += "%s = %s\n" % (key, ToGNString(value[key], False))
return result
# Adds whitespaces so non-empty lists can span multiple lines, with indent.
def PrettyGlue(gen):
prev_tok = None
level = 0
for i, tok in enumerate(gen):
if i > 0:
if can_end(prev_tok) and can_start(tok):
yield '\n' + ' ' * level # New dict item.
elif tok == '=' or prev_tok in '=':
yield ' ' # Separator before and after '=', on same line.
if tok in ']}':
level -= 1
# Exclude '[]' and '{}' cases.
if int(prev_tok == '[') + int(tok == ']') == 1 or \
int(prev_tok == '{') + int(tok == '}') == 1:
yield '\n' + ' ' * level
yield tok
if tok in '[{':
level += 1
if tok == ',':
yield '\n' + ' ' * level
prev_tok = tok

if isinstance(value, int):
return str(value)
token_gen = GenerateTokens(value, 0)
ret = ''.join((PrettyGlue if pretty else PlainGlue)(token_gen))
# Add terminating '\n' for dict |value| or multi-line output.
if isinstance(value, dict) or '\n' in ret:
return ret + '\n'
return ret

raise GNException("Unsupported type %s (value %s) when printing to GN." % (type(value), value))
2 changes: 1 addition & 1 deletion build/toolchain/win/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ if (current_toolchain == default_toolchain) {
} else {
configuration = "Release"
}
exec_script("../../vs_toolchain.py",
exec_script("//build/vs_toolchain.py",
[
"copy_dlls",
rebase_path(root_build_dir),
Expand Down

0 comments on commit 3006780

Please sign in to comment.