102102from __future__ import absolute_import
103103from __future__ import print_function
104104from optparse import OptionParser
105- import os
106105import sys
107106
108107
109- # Look for standalone GN distribution.
110- def FindGNPath ():
111- for i in os .environ ['PATH' ].split (os .pathsep ):
112- if i .rstrip (os .sep ).endswith ('gn' ):
113- return i
114- return None
108+ # This function is copied from build/gn_helpers.py in Chromium.
109+ def ToGNString (value , pretty = False ):
110+ """Returns a stringified GN equivalent of a Python value.
115111
112+ Args:
113+ value: The Python value to convert.
114+ pretty: Whether to pretty print. If true, then non-empty lists are rendered
115+ recursively with one item per line, with indents. Otherwise lists are
116+ rendered without new line.
117+ Returns:
118+ The stringified GN equivalent to |value|.
116119
117- try :
118- # May already be in the import path.
119- import gn_helpers
120- except ImportError :
121- # Add src/build to import path.
122- src_dir = os .path .abspath (os .path .join (os .path .dirname (__file__ ),
123- os .pardir , os .pardir ))
124- sys .path .append (os .path .join (src_dir , 'build' ))
125- if FindGNPath ():
126- sys .path .append (os .path .join (FindGNPath (), 'build' ))
127- import gn_helpers
120+ Raises:
121+ ValueError: |value| cannot be printed to GN.
122+ """
123+
124+ # Emits all output tokens without intervening whitespaces.
125+ def GenerateTokens (v , level ):
126+ if isinstance (v , str ):
127+ yield '"' + '' .join (TranslateToGnChars (v )) + '"'
128+
129+ elif isinstance (v , bool ):
130+ yield 'true' if v else 'false'
131+
132+ elif isinstance (v , int ):
133+ yield str (v )
134+
135+ elif isinstance (v , list ):
136+ yield '['
137+ for i , item in enumerate (v ):
138+ if i > 0 :
139+ yield ','
140+ for tok in GenerateTokens (item , level + 1 ):
141+ yield tok
142+ yield ']'
143+
144+ elif isinstance (v , dict ):
145+ if level > 0 :
146+ yield '{'
147+ for key in sorted (v ):
148+ if not isinstance (key , str ):
149+ raise ValueError ('Dictionary key is not a string.' )
150+ if not key or key [0 ].isdigit () or not key .replace ('_' , '' ).isalnum ():
151+ raise ValueError ('Dictionary key is not a valid GN identifier.' )
152+ yield key # No quotations.
153+ yield '='
154+ for tok in GenerateTokens (v [key ], level + 1 ):
155+ yield tok
156+ if level > 0 :
157+ yield '}'
158+
159+ else : # Not supporting float: Add only when needed.
160+ raise ValueError ('Unsupported type when printing to GN.' )
161+
162+ can_start = lambda tok : tok and tok not in ',}]='
163+ can_end = lambda tok : tok and tok not in ',{[='
164+
165+ # Adds whitespaces, trying to keep everything (except dicts) in 1 line.
166+ def PlainGlue (gen ):
167+ prev_tok = None
168+ for i , tok in enumerate (gen ):
169+ if i > 0 :
170+ if can_end (prev_tok ) and can_start (tok ):
171+ yield '\n ' # New dict item.
172+ elif prev_tok == '[' and tok == ']' :
173+ yield ' ' # Special case for [].
174+ elif tok != ',' :
175+ yield ' '
176+ yield tok
177+ prev_tok = tok
178+
179+ # Adds whitespaces so non-empty lists can span multiple lines, with indent.
180+ def PrettyGlue (gen ):
181+ prev_tok = None
182+ level = 0
183+ for i , tok in enumerate (gen ):
184+ if i > 0 :
185+ if can_end (prev_tok ) and can_start (tok ):
186+ yield '\n ' + ' ' * level # New dict item.
187+ elif tok == '=' or prev_tok in '=' :
188+ yield ' ' # Separator before and after '=', on same line.
189+ if tok in ']}' :
190+ level -= 1
191+ # Exclude '[]' and '{}' cases.
192+ if int (prev_tok == '[' ) + int (tok == ']' ) == 1 or \
193+ int (prev_tok == '{' ) + int (tok == '}' ) == 1 :
194+ yield '\n ' + ' ' * level
195+ yield tok
196+ if tok in '[{' :
197+ level += 1
198+ if tok == ',' :
199+ yield '\n ' + ' ' * level
200+ prev_tok = tok
201+
202+ token_gen = GenerateTokens (value , 0 )
203+ ret = '' .join ((PrettyGlue if pretty else PlainGlue )(token_gen ))
204+ # Add terminating '\n' for dict |value| or multi-line output.
205+ if isinstance (value , dict ) or '\n ' in ret :
206+ return ret + '\n '
207+ return ret
208+
209+
210+ def TranslateToGnChars (s ):
211+ for code in s .encode ('utf-8' ):
212+ if code in (34 , 36 , 92 ): # For '"', '$', or '\\'.
213+ yield '\\ ' + chr (code )
214+ elif 32 <= code < 127 :
215+ yield chr (code )
216+ else :
217+ yield '$0x%02X' % code
128218
129219
130220def LoadPythonDictionary (path ):
@@ -234,7 +324,7 @@ def main():
234324 else :
235325 gn_dict [gn_key ] = data [key ]
236326
237- print (gn_helpers . ToGNString (DeduplicateLists (gn_dict )))
327+ print (ToGNString (DeduplicateLists (gn_dict )))
238328
239329if __name__ == '__main__' :
240330 try :
0 commit comments