Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: components/policy/tools/generate_policy_source.py

Issue 205923004: Add regex support in policy schema (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@json-schema-regex
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 '''python %prog [options] platform chromium_os_flag template 6 '''python %prog [options] platform chromium_os_flag template
7 7
8 platform specifies which platform source is being generated for 8 platform specifies which platform source is being generated for
9 and can be one of (win, mac, linux) 9 and can be one of (win, mac, linux)
10 chromium_os_flag should be 1 if this is a Chromium OS build 10 chromium_os_flag should be 1 if this is a Chromium OS build
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 'boolean': None, 277 'boolean': None,
278 'integer': None, 278 'integer': None,
279 'null': None, 279 'null': None,
280 'number': None, 280 'number': None,
281 'string': None, 281 'string': None,
282 } 282 }
283 self.stringlist_type = None 283 self.stringlist_type = None
284 self.ranges = {} 284 self.ranges = {}
285 285
286 def GetString(self, s): 286 def GetString(self, s):
287 return self.shared_strings[s] if s in self.shared_strings else '"%s"' % s 287 if s in self.shared_strings:
288 return self.shared_strings[s]
289 # Generate JSON escaped string, which is slightly different from desired
290 # C/C++ escaped string.
291 return json.dumps(s)
288 292
289 def AppendSchema(self, type, extra, comment=''): 293 def AppendSchema(self, type, extra, comment=''):
290 index = len(self.schema_nodes) 294 index = len(self.schema_nodes)
291 self.schema_nodes.append((type, extra, comment)) 295 self.schema_nodes.append((type, extra, comment))
292 return index 296 return index
293 297
294 def AppendRestriction(self, first, second): 298 def AppendRestriction(self, first, second):
295 r = (str(first), str(second)) 299 r = (str(first), str(second))
296 if not r in self.ranges: 300 if not r in self.ranges:
297 self.ranges[r] = len(self.restriction_nodes) 301 self.ranges[r] = len(self.restriction_nodes)
(...skipping 10 matching lines...) Expand all
308 312
309 def GetStringList(self): 313 def GetStringList(self):
310 if self.stringlist_type == None: 314 if self.stringlist_type == None:
311 self.stringlist_type = self.AppendSchema( 315 self.stringlist_type = self.AppendSchema(
312 'TYPE_LIST', 316 'TYPE_LIST',
313 self.GetSimpleType('string'), 317 self.GetSimpleType('string'),
314 'simple type: stringlist') 318 'simple type: stringlist')
315 return self.stringlist_type 319 return self.stringlist_type
316 320
317 def SchemaHaveRestriction(self, schema): 321 def SchemaHaveRestriction(self, schema):
318 return 'minimum' in schema or 'maximum' in schema or 'enum' in schema 322 return any(keyword in schema for keyword in
323 ['minimum', 'maximum', 'enum', 'pattern'])
319 324
320 def IsConsecutiveInterval(self, seq): 325 def IsConsecutiveInterval(self, seq):
321 sortedSeq = sorted(seq) 326 sortedSeq = sorted(seq)
322 return all(sortedSeq[i] + 1 == sortedSeq[i + 1] 327 return all(sortedSeq[i] + 1 == sortedSeq[i + 1]
323 for i in xrange(len(sortedSeq) - 1)) 328 for i in xrange(len(sortedSeq) - 1))
324 329
325 def GetEnumIntegerType(self, schema, name): 330 def GetEnumIntegerType(self, schema, name):
326 assert all(type(x) == int for x in schema['enum']) 331 assert all(type(x) == int for x in schema['enum'])
327 possible_values = schema['enum'] 332 possible_values = schema['enum']
328 if self.IsConsecutiveInterval(possible_values): 333 if self.IsConsecutiveInterval(possible_values):
(...skipping 19 matching lines...) Expand all
348 def GetEnumType(self, schema, name): 353 def GetEnumType(self, schema, name):
349 if len(schema['enum']) == 0: 354 if len(schema['enum']) == 0:
350 raise RuntimeError('Empty enumeration in %s' % name) 355 raise RuntimeError('Empty enumeration in %s' % name)
351 elif schema['type'] == 'integer': 356 elif schema['type'] == 'integer':
352 return self.GetEnumIntegerType(schema, name) 357 return self.GetEnumIntegerType(schema, name)
353 elif schema['type'] == 'string': 358 elif schema['type'] == 'string':
354 return self.GetEnumStringType(schema, name) 359 return self.GetEnumStringType(schema, name)
355 else: 360 else:
356 raise RuntimeError('Unknown enumeration type in %s' % name) 361 raise RuntimeError('Unknown enumeration type in %s' % name)
357 362
363 def GetPatternType(self, schema, name):
364 if schema['type'] != 'string':
365 raise RuntimeError('Unknown pattern type in %s' % name)
366 pattern = schema['pattern']
367 # Try to compile the pattern to validate it, note that the syntax used
368 # here might be slightly different from re2.
Joao da Silva 2014/03/21 12:58:12 Leave a TODO to use a python wrapper for re2 here
binjin 2014/03/27 17:57:47 Done.
369 re.compile(pattern)
370 index = len(self.string_enums);
371 self.string_enums.append(pattern);
372 return self.AppendSchema('TYPE_STRING',
373 self.AppendRestriction(index, index),
374 'string with pattern restriction: %s' % name);
375
358 def GetRangedType(self, schema, name): 376 def GetRangedType(self, schema, name):
359 if schema['type'] != 'integer': 377 if schema['type'] != 'integer':
360 raise RuntimeError('Unknown ranged type in %s' % name) 378 raise RuntimeError('Unknown ranged type in %s' % name)
361 min_value_set, max_value_set = False, False 379 min_value_set, max_value_set = False, False
362 if 'minimum' in schema: 380 if 'minimum' in schema:
363 min_value = int(schema['minimum']) 381 min_value = int(schema['minimum'])
364 min_value_set = True 382 min_value_set = True
365 if 'maximum' in schema: 383 if 'maximum' in schema:
366 max_value = int(schema['minimum']) 384 max_value = int(schema['minimum'])
367 max_value_set = True 385 max_value_set = True
(...skipping 10 matching lines...) Expand all
378 """Generates the structs for the given schema. 396 """Generates the structs for the given schema.
379 397
380 |schema|: a valid JSON schema in a dictionary. 398 |schema|: a valid JSON schema in a dictionary.
381 |name|: the name of the current node, for the generated comments.""" 399 |name|: the name of the current node, for the generated comments."""
382 if schema['type'] in self.simple_types: 400 if schema['type'] in self.simple_types:
383 if not self.SchemaHaveRestriction(schema): 401 if not self.SchemaHaveRestriction(schema):
384 # Simple types use shared nodes. 402 # Simple types use shared nodes.
385 return self.GetSimpleType(schema['type']) 403 return self.GetSimpleType(schema['type'])
386 elif 'enum' in schema: 404 elif 'enum' in schema:
387 return self.GetEnumType(schema, name) 405 return self.GetEnumType(schema, name)
406 elif 'pattern' in schema:
407 return self.GetPatternType(schema, name)
388 else: 408 else:
389 return self.GetRangedType(schema, name) 409 return self.GetRangedType(schema, name)
390 410
391 if schema['type'] == 'array': 411 if schema['type'] == 'array':
392 # Special case for lists of strings, which is a common policy type. 412 # Special case for lists of strings, which is a common policy type.
393 if schema['items']['type'] == 'string': 413 if schema['items']['type'] == 'string':
394 return self.GetStringList() 414 return self.GetStringList()
395 return self.AppendSchema( 415 return self.AppendSchema(
396 'TYPE_LIST', 416 'TYPE_LIST',
397 self.Generate(schema['items'], 'items of ' + name)) 417 self.Generate(schema['items'], 'items of ' + name))
398 elif schema['type'] == 'object': 418 elif schema['type'] == 'object':
399 # Reserve an index first, so that dictionaries come before their 419 # Reserve an index first, so that dictionaries come before their
400 # properties. This makes sure that the root node is the first in the 420 # properties. This makes sure that the root node is the first in the
401 # SchemaNodes array. 421 # SchemaNodes array.
402 index = self.AppendSchema('TYPE_DICTIONARY', -1) 422 index = self.AppendSchema('TYPE_DICTIONARY', -1)
403 423
404 if 'additionalProperties' in schema: 424 if 'additionalProperties' in schema:
405 additionalProperties = self.Generate( 425 additionalProperties = self.Generate(
406 schema['additionalProperties'], 426 schema['additionalProperties'],
407 'additionalProperties of ' + name) 427 'additionalProperties of ' + name)
408 else: 428 else:
409 additionalProperties = -1 429 additionalProperties = -1
410 430
411 # Properties must be sorted by name, for the binary search lookup. 431 # Properties must be sorted by name, for the binary search lookup.
412 # Note that |properties| must be evaluated immediately, so that all the 432 # Note that |properties| must be evaluated immediately, so that all the
413 # recursive calls to Generate() append the necessary child nodes; if 433 # recursive calls to Generate() append the necessary child nodes; if
414 # |properties| were a generator then this wouldn't work. 434 # |properties| were a generator then this wouldn't work.
415 sorted_properties = sorted(schema.get('properties', {}).items()) 435 sorted_properties = sorted(schema.get('properties', {}).items())
416 properties = [ (self.GetString(key), self.Generate(schema, key)) 436 properties = [ (self.GetString(key), self.Generate(subschema, key))
417 for key, schema in sorted_properties ] 437 for key, subschema in sorted_properties ]
418 begin = len(self.property_nodes) 438 begin = len(self.property_nodes)
419 self.property_nodes += properties 439 self.property_nodes += properties
420 end = len(self.property_nodes) 440 end = len(self.property_nodes)
441
442 for pattern, subschema in schema.get('patternProperties', {}).items():
443 self.property_nodes.append((self.GetString(pattern),
Joao da Silva 2014/03/21 12:58:12 appending one by one and making recursive calls to
binjin 2014/03/27 17:57:47 Done.
444 self.Generate(subschema, pattern)));
445 pattern_end = len(self.property_nodes)
446
421 if index == 0: 447 if index == 0:
422 self.root_properties_begin = begin 448 self.root_properties_begin = begin
423 self.root_properties_end = end 449 self.root_properties_end = end
424 450
425 extra = len(self.properties_nodes) 451 extra = len(self.properties_nodes)
426 self.properties_nodes.append((begin, end, additionalProperties, name)) 452 self.properties_nodes.append((begin, end, pattern_end,
453 additionalProperties, name))
427 454
428 # Set the right data at |index| now. 455 # Set the right data at |index| now.
429 self.schema_nodes[index] = ('TYPE_DICTIONARY', extra, name) 456 self.schema_nodes[index] = ('TYPE_DICTIONARY', extra, name)
430 return index 457 return index
431 else: 458 else:
432 assert False 459 assert False
433 460
434 def Write(self, f): 461 def Write(self, f):
435 """Writes the generated structs to the given file. 462 """Writes the generated structs to the given file.
436 463
437 |f| an open file to write to.""" 464 |f| an open file to write to."""
438 f.write('const internal::SchemaNode kSchemas[] = {\n' 465 f.write('const internal::SchemaNode kSchemas[] = {\n'
439 '// Type Extra\n') 466 '// Type Extra\n')
440 for type, extra, comment in self.schema_nodes: 467 for type, extra, comment in self.schema_nodes:
441 type += ',' 468 type += ','
442 f.write(' { base::Value::%-18s %3d }, // %s\n' % (type, extra, comment)) 469 f.write(' { base::Value::%-18s %3d }, // %s\n' % (type, extra, comment))
443 f.write('};\n\n') 470 f.write('};\n\n')
444 471
445 if self.property_nodes: 472 if self.property_nodes:
446 f.write('const internal::PropertyNode kPropertyNodes[] = {\n' 473 f.write('const internal::PropertyNode kPropertyNodes[] = {\n'
447 '// Property #Schema\n') 474 '// Property #Schema\n')
448 for key, schema in self.property_nodes: 475 for key, schema in self.property_nodes:
449 key += ',' 476 key += ','
450 f.write(' { %-50s %6d },\n' % (key, schema)) 477 f.write(' { %-50s %6d },\n' % (key, schema))
451 f.write('};\n\n') 478 f.write('};\n\n')
452 479
453 if self.properties_nodes: 480 if self.properties_nodes:
454 f.write('const internal::PropertiesNode kProperties[] = {\n' 481 f.write('const internal::PropertiesNode kProperties[] = {\n'
455 '// Begin End Additional Properties\n') 482 '// Begin End PatternEnd Additional Properties\n')
456 for node in self.properties_nodes: 483 for node in self.properties_nodes:
457 f.write(' { %5d, %5d, %5d }, // %s\n' % node) 484 f.write(' { %5d, %5d, %10d, %5d }, // %s\n' % node)
458 f.write('};\n\n') 485 f.write('};\n\n')
459 486
460 if self.restriction_nodes: 487 if self.restriction_nodes:
461 f.write('const internal::RestrictionNode kRestrictionNodes[] = {\n') 488 f.write('const internal::RestrictionNode kRestrictionNodes[] = {\n')
462 f.write('// FIRST, SECOND\n') 489 f.write('// FIRST, SECOND\n')
463 for first, second in self.restriction_nodes: 490 for first, second in self.restriction_nodes:
464 f.write(' {{ %-8s %4s}},\n' % (first + ',', second)) 491 f.write(' {{ %-8s %4s}},\n' % (first + ',', second))
465 f.write('};\n\n') 492 f.write('};\n\n')
466 493
467 if self.int_enums: 494 if self.int_enums:
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
839 def _WriteCloudPolicyDecoder(policies, os, f): 866 def _WriteCloudPolicyDecoder(policies, os, f):
840 f.write(CPP_HEAD) 867 f.write(CPP_HEAD)
841 for policy in policies: 868 for policy in policies:
842 if policy.is_supported and not policy.is_device_only: 869 if policy.is_supported and not policy.is_device_only:
843 _WritePolicyCode(f, policy) 870 _WritePolicyCode(f, policy)
844 f.write(CPP_FOOT) 871 f.write(CPP_FOOT)
845 872
846 873
847 if __name__ == '__main__': 874 if __name__ == '__main__':
848 sys.exit(main()) 875 sys.exit(main())
OLDNEW
« components/policy/core/common/schema_internal.h ('K') | « components/policy/policy_common.gypi ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698