Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 3006780

Browse files
authored
Update gn_helpers.py from upstream (#493)
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.
1 parent ed767ed commit 3006780

File tree

3 files changed

+120
-26
lines changed

3 files changed

+120
-26
lines changed

build/config/win/visual_studio_version.gni

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ declare_args() {
2424

2525
if (visual_studio_path == "") {
2626
_toolchain_data =
27-
exec_script("../../vs_toolchain.py", [ "get_toolchain_dir" ], "scope")
27+
exec_script("//build/vs_toolchain.py", [ "get_toolchain_dir" ], "scope")
2828
visual_studio_path = _toolchain_data.vs_path
2929
windows_sdk_path = _toolchain_data.sdk_path
3030
visual_studio_version = _toolchain_data.vs_version

build/gn_helpers.py

Lines changed: 118 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,132 @@
22
# Use of this source code is governed by a BSD-style license that can be
33
# found in the LICENSE file.
44

5+
import sys
6+
57
"""Helper functions useful when writing scripts that are run from GN's
68
exec_script function."""
79

8-
class GNException(Exception):
10+
class GNError(Exception):
911
pass
1012

1113

12-
def ToGNString(value, allow_dicts = True):
13-
"""Prints the given value to stdout.
14+
# Computes ASCII code of an element of encoded Python 2 str / Python 3 bytes.
15+
_Ord = ord if sys.version_info.major < 3 else lambda c: c
16+
17+
18+
def _TranslateToGnChars(s):
19+
for decoded_ch in s.encode('utf-8'): # str in Python 2, bytes in Python 3.
20+
code = _Ord(decoded_ch) # int
21+
if code in (34, 36, 92): # For '"', '$', or '\\'.
22+
yield '\\' + chr(code)
23+
elif 32 <= code < 127:
24+
yield chr(code)
25+
else:
26+
yield '$0x%02X' % code
27+
28+
29+
def ToGNString(value, pretty=False):
30+
"""Returns a stringified GN equivalent of a Python value.
31+
32+
Args:
33+
value: The Python value to convert.
34+
pretty: Whether to pretty print. If true, then non-empty lists are rendered
35+
recursively with one item per line, with indents. Otherwise lists are
36+
rendered without new line.
37+
Returns:
38+
The stringified GN equivalent to |value|.
39+
40+
Raises:
41+
GNError: |value| cannot be printed to GN.
42+
"""
43+
44+
if sys.version_info.major < 3:
45+
basestring_compat = basestring
46+
else:
47+
basestring_compat = str
48+
49+
# Emits all output tokens without intervening whitespaces.
50+
def GenerateTokens(v, level):
51+
if isinstance(v, basestring_compat):
52+
yield '"' + ''.join(_TranslateToGnChars(v)) + '"'
53+
54+
elif isinstance(v, bool):
55+
yield 'true' if v else 'false'
56+
57+
elif isinstance(v, int):
58+
yield str(v)
59+
60+
elif isinstance(v, list):
61+
yield '['
62+
for i, item in enumerate(v):
63+
if i > 0:
64+
yield ','
65+
for tok in GenerateTokens(item, level + 1):
66+
yield tok
67+
yield ']'
68+
69+
elif isinstance(v, dict):
70+
if level > 0:
71+
yield '{'
72+
for key in sorted(v):
73+
if not isinstance(key, basestring_compat):
74+
raise GNError('Dictionary key is not a string.')
75+
if not key or key[0].isdigit() or not key.replace('_', '').isalnum():
76+
raise GNError('Dictionary key is not a valid GN identifier.')
77+
yield key # No quotations.
78+
yield '='
79+
for tok in GenerateTokens(v[key], level + 1):
80+
yield tok
81+
if level > 0:
82+
yield '}'
83+
84+
else: # Not supporting float: Add only when needed.
85+
raise GNError('Unsupported type when printing to GN.')
1486

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

23-
if isinstance(value, list):
24-
return '[ %s ]' % ', '.join(ToGNString(v) for v in value)
90+
# Adds whitespaces, trying to keep everything (except dicts) in 1 line.
91+
def PlainGlue(gen):
92+
prev_tok = None
93+
for i, tok in enumerate(gen):
94+
if i > 0:
95+
if can_end(prev_tok) and can_start(tok):
96+
yield '\n' # New dict item.
97+
elif prev_tok == '[' and tok == ']':
98+
yield ' ' # Special case for [].
99+
elif tok != ',':
100+
yield ' '
101+
yield tok
102+
prev_tok = tok
25103

26-
if isinstance(value, dict):
27-
if not allow_dicts:
28-
raise GNException("Attempting to recursively print a dictionary.")
29-
result = ""
30-
for key in value:
31-
if not isinstance(key, str):
32-
raise GNException("Dictionary key is not a string.")
33-
result += "%s = %s\n" % (key, ToGNString(value[key], False))
34-
return result
104+
# Adds whitespaces so non-empty lists can span multiple lines, with indent.
105+
def PrettyGlue(gen):
106+
prev_tok = None
107+
level = 0
108+
for i, tok in enumerate(gen):
109+
if i > 0:
110+
if can_end(prev_tok) and can_start(tok):
111+
yield '\n' + ' ' * level # New dict item.
112+
elif tok == '=' or prev_tok in '=':
113+
yield ' ' # Separator before and after '=', on same line.
114+
if tok in ']}':
115+
level -= 1
116+
# Exclude '[]' and '{}' cases.
117+
if int(prev_tok == '[') + int(tok == ']') == 1 or \
118+
int(prev_tok == '{') + int(tok == '}') == 1:
119+
yield '\n' + ' ' * level
120+
yield tok
121+
if tok in '[{':
122+
level += 1
123+
if tok == ',':
124+
yield '\n' + ' ' * level
125+
prev_tok = tok
35126

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

39-
raise GNException("Unsupported type %s (value %s) when printing to GN." % (type(value), value))

build/toolchain/win/BUILD.gn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ if (current_toolchain == default_toolchain) {
5656
} else {
5757
configuration = "Release"
5858
}
59-
exec_script("../../vs_toolchain.py",
59+
exec_script("//build/vs_toolchain.py",
6060
[
6161
"copy_dlls",
6262
rebase_path(root_build_dir),

0 commit comments

Comments
 (0)