33import os
44import re
55import collections
6+ from copy import deepcopy
67
78SPLIT_START = '>>>>>>>'
89SPLIT_END = '<<<<<<<'
2223
2324CONFIG_DIR = '~/.google-service-cli'
2425
26+ POD_TYPES = set (('boolean' , 'integer' , 'number' , 'uint32' , 'double' , 'float' , 'int32' , 'int64' , 'uint64' , 'string' ))
27+
2528re_splitters = re .compile (r"%s ([\w\-\.]+)\n(.*?)\n%s" % (SPLIT_START , SPLIT_END ), re .MULTILINE | re .DOTALL )
2629
2730MethodContext = collections .namedtuple ('MethodContext' , ['m' , 'response_schema' , 'params' , 'request_value' ,
2831 'media_params' ,'required_props' , 'optional_props' ,
2932 'part_prop' ])
3033
34+ CTYPE_POD = 'pod'
35+ CTYPE_ARRAY = 'list'
36+ CTYPE_MAP = 'map'
37+ SchemaEntry = collections .namedtuple ('SchemaEntry' , ['container_type' , 'actual_property' , 'property' ])
38+
3139def new_method_context (resource , method , c ):
3240 m = c .fqan_map [util .to_fqan (c .rtc_map [resource ], resource , method )]
3341 response_schema = util .method_response (c , m )
@@ -46,6 +54,7 @@ def pretty(n):
4654def is_request_value_property (mc , p ):
4755 return mc .request_value and mc .request_value .id == p .get (util .TREF )
4856
57+
4958# transform name to be a suitable subcommand
5059def mangle_subcommand (name ):
5160 return util .camel_to_under (name ).replace ('_' , '-' ).replace ('.' , '-' )
@@ -55,12 +64,86 @@ def mangle_subcommand(name):
5564def subcommand_md_filename (resource , method ):
5665 return mangle_subcommand (resource ) + '_' + mangle_subcommand (method ) + '.md'
5766
67+
5868def docopt_mode (protocols ):
5969 mode = '|' .join (protocols )
6070 if len (protocols ) > 1 :
6171 mode = '(%s)' % mode
6272 return mode
6373
74+
75+ # Return schema' with fields dict: { 'field1' : SchemaField(...), 'SubSchema': schema' }
76+ def to_cli_schema (c , schema ):
77+ res = deepcopy (schema )
78+ fd = dict ()
79+ res ['fields' ] = fd
80+
81+ # util.nested_type_name
82+ properties = schema .get ('properties' , dict ())
83+ if not properties and 'variant' in schema and 'map' in schema .variant :
84+ for e in schema .variant .map :
85+ assert util .TREF in e
86+ properties [e .type_value ] = e
87+ # end handle enumerations
88+
89+ for pn , p in properties .iteritems ():
90+ def set_nested_schema (ns ):
91+ if ns .fields :
92+ fd [pn ] = ns
93+ # end utility
94+
95+ def dup_property ():
96+ pc = deepcopy (p )
97+ if 'type' in pc and pc .type == 'string' and 'Count' in pn :
98+ pc .type = 'int64'
99+ return pc
100+ # end
101+
102+ if util .TREF in p :
103+ if p [util .TREF ] != schema .id : # prevent recursion (in case of self-referential schemas)
104+ set_nested_schema (to_cli_schema (c , c .schemas [p [util .TREF ]]))
105+ elif p .type == 'array' and 'items' in p and 'type' in p .get ('items' ) and p .get ('items' ).type in POD_TYPES :
106+ pc = dup_property ()
107+ fd [pn ] = SchemaEntry (CTYPE_ARRAY , pc .get ('items' ), pc )
108+ elif p .type == 'object' :
109+ if util .is_map_prop (p ):
110+ if 'type' in p .additionalProperties and p .additionalProperties .type in POD_TYPES :
111+ pc = dup_property ()
112+ fd [pn ] = SchemaEntry (CTYPE_MAP , pc .additionalProperties , pc )
113+ else :
114+ set_nested_schema (to_cli_schema (c , c .schemas [util .nested_type_name (schema .id , pn )]))
115+ elif p .type in POD_TYPES :
116+ pc = dup_property ()
117+ fd [pn ] = SchemaEntry (CTYPE_POD , pc , pc )
118+ # end handle property type
119+ # end
120+
121+ return res
122+
123+
124+ # Convert the given cli-schema (result from to_cli_schema(schema)) to a yaml-like string. It's suitable for
125+ # documentation only
126+ def cli_schema_to_yaml (schema , prefix = '' ):
127+ if not prefix :
128+ o = '%s%s:\n ' % (prefix , util .unique_type_name (schema .id ))
129+ else :
130+ o = ''
131+ prefix += ' '
132+ for fn , f in schema .fields .iteritems ():
133+ o += '%s%s:' % (prefix , mangle_subcommand (fn ))
134+ if not isinstance (f , SchemaEntry ):
135+ o += '\n ' + cli_schema_to_yaml (f , prefix )
136+ else :
137+ t = f .actual_property .type
138+ if f .container_type == CTYPE_ARRAY :
139+ t = '[%s]' % t
140+ elif f .container_type == CTYPE_MAP :
141+ t = '{ string: %s }' % t
142+ o += ' %s\n ' % t
143+ # end for each field
144+ return o
145+
146+
64147# split the result along split segments
65148def process_template_result (r , output_file ):
66149 found = False
@@ -74,7 +157,7 @@ def process_template_result(r, output_file):
74157 for m in re_splitters .finditer (r ):
75158 found = True
76159 fh = open (os .path .join (dir , m .group (1 )), 'wb' )
77- fh .write (m .group (2 ))
160+ fh .write (m .group (2 ). encode ( 'UTF-8' ) )
78161 fh .close ()
79162 # end for each match
80163
0 commit comments