Skip to content

Commit

Permalink
build: do not rely on gn_helpers in GN build
Browse files Browse the repository at this point in the history
PR-URL: #51439
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
  • Loading branch information
zcbenz authored and marco-ippolito committed Feb 27, 2024
1 parent 5911731 commit 86ac787
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 20 deletions.
2 changes: 1 addition & 1 deletion deps/ngtcp2/unofficial.gni
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# building official binaries.
# Please edit the gyp files if you are making changes to build system.

import("//node/node.gni")
import("../../node.gni")

# The actual configurations are put inside a template in unofficial.gni to
# prevent accidental edits from contributors.
Expand Down
128 changes: 109 additions & 19 deletions tools/gypi_to_gn.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,29 +102,119 @@
from __future__ import absolute_import
from __future__ import print_function
from optparse import OptionParser
import os
import sys


# Look for standalone GN distribution.
def FindGNPath():
for i in os.environ['PATH'].split(os.pathsep):
if i.rstrip(os.sep).endswith('gn'):
return i
return None
# This function is copied from build/gn_helpers.py in Chromium.
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|.
try:
# May already be in the import path.
import gn_helpers
except ImportError:
# Add src/build to import path.
src_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
os.pardir, os.pardir))
sys.path.append(os.path.join(src_dir, 'build'))
if FindGNPath():
sys.path.append(os.path.join(FindGNPath(), 'build'))
import gn_helpers
Raises:
ValueError: |value| cannot be printed to GN.
"""

# Emits all output tokens without intervening whitespaces.
def GenerateTokens(v, level):
if isinstance(v, str):
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, str):
raise ValueError('Dictionary key is not a string.')
if not key or key[0].isdigit() or not key.replace('_', '').isalnum():
raise ValueError('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 ValueError('Unsupported type when printing to GN.')

can_start = lambda tok: tok and tok not in ',}]='
can_end = lambda tok: tok and tok not in ',{[='

# 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

# 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

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


def TranslateToGnChars(s):
for code in s.encode('utf-8'):
if code in (34, 36, 92): # For '"', '$', or '\\'.
yield '\\' + chr(code)
elif 32 <= code < 127:
yield chr(code)
else:
yield '$0x%02X' % code


def LoadPythonDictionary(path):
Expand Down Expand Up @@ -234,7 +324,7 @@ def main():
else:
gn_dict[gn_key] = data[key]

print(gn_helpers.ToGNString(DeduplicateLists(gn_dict)))
print(ToGNString(DeduplicateLists(gn_dict)))

if __name__ == '__main__':
try:
Expand Down

0 comments on commit 86ac787

Please sign in to comment.