| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import copy | 5 import copy |
| 6 import logging | 6 import logging |
| 7 import os | 7 import os |
| 8 | 8 |
| 9 from file_system import FileNotFoundError | 9 from file_system import FileNotFoundError |
| 10 import third_party.json_schema_compiler.json_parse as json_parse | 10 import third_party.json_schema_compiler.json_parse as json_parse |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 def _FormatValue(value): | 43 def _FormatValue(value): |
| 44 """Inserts commas every three digits for integer values. It is magic. | 44 """Inserts commas every three digits for integer values. It is magic. |
| 45 """ | 45 """ |
| 46 s = str(value) | 46 s = str(value) |
| 47 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) | 47 return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1]) |
| 48 | 48 |
| 49 class _JSCModel(object): | 49 class _JSCModel(object): |
| 50 """Uses a Model from the JSON Schema Compiler and generates a dict that | 50 """Uses a Model from the JSON Schema Compiler and generates a dict that |
| 51 a Handlebar template can use for a data source. | 51 a Handlebar template can use for a data source. |
| 52 """ | 52 """ |
| 53 def __init__(self, json, ref_resolver, disable_refs): | 53 def __init__(self, |
| 54 json, |
| 55 ref_resolver, |
| 56 disable_refs, |
| 57 availability_data_source): |
| 54 self._ref_resolver = ref_resolver | 58 self._ref_resolver = ref_resolver |
| 55 self._disable_refs = disable_refs | 59 self._disable_refs = disable_refs |
| 60 self._availability_data_source = availability_data_source |
| 56 clean_json = copy.deepcopy(json) | 61 clean_json = copy.deepcopy(json) |
| 57 if _RemoveNoDocs(clean_json): | 62 if _RemoveNoDocs(clean_json): |
| 58 self._namespace = None | 63 self._namespace = None |
| 59 else: | 64 else: |
| 60 self._namespace = model.Namespace(clean_json, clean_json['namespace']) | 65 self._namespace = model.Namespace(clean_json, clean_json['namespace']) |
| 61 | 66 |
| 62 def _FormatDescription(self, description): | 67 def _FormatDescription(self, description): |
| 63 if self._disable_refs: | 68 if self._disable_refs: |
| 64 return description | 69 return description |
| 65 return self._ref_resolver.ResolveAllLinks(description, | 70 return self._ref_resolver.ResolveAllLinks(description, |
| 66 namespace=self._namespace.name) | 71 namespace=self._namespace.name) |
| 67 | 72 |
| 68 def _GetLink(self, link): | 73 def _GetLink(self, link): |
| 69 if self._disable_refs: | 74 if self._disable_refs: |
| 70 type_name = link.split('.', 1)[-1] | 75 type_name = link.split('.', 1)[-1] |
| 71 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link } | 76 return { 'href': '#type-%s' % type_name, 'text': link, 'name': link } |
| 72 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name) | 77 return self._ref_resolver.SafeGetLink(link, namespace=self._namespace.name) |
| 73 | 78 |
| 74 def ToDict(self): | 79 def ToDict(self): |
| 75 if self._namespace is None: | 80 if self._namespace is None: |
| 76 return {} | 81 return {} |
| 77 return { | 82 return { |
| 78 'name': self._namespace.name, | 83 'name': self._namespace.name, |
| 84 'description': self._namespace.description, |
| 85 'availability': self._GetAvailability(), |
| 79 'types': self._GenerateTypes(self._namespace.types.values()), | 86 'types': self._GenerateTypes(self._namespace.types.values()), |
| 80 'functions': self._GenerateFunctions(self._namespace.functions), | 87 'functions': self._GenerateFunctions(self._namespace.functions), |
| 81 'events': self._GenerateEvents(self._namespace.events), | 88 'events': self._GenerateEvents(self._namespace.events), |
| 82 'properties': self._GenerateProperties(self._namespace.properties) | 89 'properties': self._GenerateProperties(self._namespace.properties) |
| 83 } | 90 } |
| 84 | 91 |
| 92 def _GetAvailability(self): |
| 93 """Finds the earliest version of chrome where an API was available using |
| 94 AvailabilityDataSource. Also [temporarily] creates a string describing the |
| 95 availability depending on its original format. |
| 96 """ |
| 97 availability_string = 'Not Currently Available' |
| 98 availability = self._availability_data_source.FindEarliestAvailability( |
| 99 self._namespace.name) |
| 100 |
| 101 if availability is not None: |
| 102 if availability.isdigit(): |
| 103 availability_string = 'Chrome %s' % availability |
| 104 else: |
| 105 availability_string = ('Chrome %s Channel Only' % |
| 106 availability.capitalize()) |
| 107 return availability_string |
| 108 |
| 85 def _GenerateTypes(self, types): | 109 def _GenerateTypes(self, types): |
| 86 return [self._GenerateType(t) for t in types] | 110 return [self._GenerateType(t) for t in types] |
| 87 | 111 |
| 88 def _GenerateType(self, type_): | 112 def _GenerateType(self, type_): |
| 89 type_dict = { | 113 type_dict = { |
| 90 'name': type_.simple_name, | 114 'name': type_.simple_name, |
| 91 'description': self._FormatDescription(type_.description), | 115 'description': self._FormatDescription(type_.description), |
| 92 'properties': self._GenerateProperties(type_.properties), | 116 'properties': self._GenerateProperties(type_.properties), |
| 93 'functions': self._GenerateFunctions(type_.functions), | 117 'functions': self._GenerateFunctions(type_.functions), |
| 94 'events': self._GenerateEvents(type_.events), | 118 'events': self._GenerateEvents(type_.events), |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 self._samples = samples | 285 self._samples = samples |
| 262 | 286 |
| 263 def get(self, key): | 287 def get(self, key): |
| 264 return self._samples.FilterSamples(key, self._api_name) | 288 return self._samples.FilterSamples(key, self._api_name) |
| 265 | 289 |
| 266 class APIDataSource(object): | 290 class APIDataSource(object): |
| 267 """This class fetches and loads JSON APIs from the FileSystem passed in with | 291 """This class fetches and loads JSON APIs from the FileSystem passed in with |
| 268 |compiled_fs_factory|, so the APIs can be plugged into templates. | 292 |compiled_fs_factory|, so the APIs can be plugged into templates. |
| 269 """ | 293 """ |
| 270 class Factory(object): | 294 class Factory(object): |
| 271 def __init__(self, compiled_fs_factory, base_path): | 295 def __init__(self, |
| 296 compiled_fs_factory, |
| 297 base_path, |
| 298 availability_data_source_factory): |
| 272 def create_compiled_fs(fn, category): | 299 def create_compiled_fs(fn, category): |
| 273 return compiled_fs_factory.Create( | 300 return compiled_fs_factory.Create( |
| 274 fn, APIDataSource, category=category, version=_VERSION) | 301 fn, APIDataSource, category=category, version=_VERSION) |
| 275 | 302 |
| 276 self._permissions_cache = create_compiled_fs(self._LoadPermissions, | 303 self._permissions_cache = create_compiled_fs(self._LoadPermissions, |
| 277 'permissions') | 304 'permissions') |
| 278 | 305 |
| 279 self._json_cache = create_compiled_fs( | 306 self._json_cache = create_compiled_fs( |
| 280 lambda api_name, api: self._LoadJsonAPI(api, False), | 307 lambda api_name, api: self._LoadJsonAPI(api, False), |
| 281 'json') | 308 'json') |
| 282 self._idl_cache = create_compiled_fs( | 309 self._idl_cache = create_compiled_fs( |
| 283 lambda api_name, api: self._LoadIdlAPI(api, False), | 310 lambda api_name, api: self._LoadIdlAPI(api, False), |
| 284 'idl') | 311 'idl') |
| 285 | 312 |
| 286 # These caches are used if an APIDataSource does not want to resolve the | 313 # These caches are used if an APIDataSource does not want to resolve the |
| 287 # $refs in an API. This is needed to prevent infinite recursion in | 314 # $refs in an API. This is needed to prevent infinite recursion in |
| 288 # ReferenceResolver. | 315 # ReferenceResolver. |
| 289 self._json_cache_no_refs = create_compiled_fs( | 316 self._json_cache_no_refs = create_compiled_fs( |
| 290 lambda api_name, api: self._LoadJsonAPI(api, True), | 317 lambda api_name, api: self._LoadJsonAPI(api, True), |
| 291 'json-no-refs') | 318 'json-no-refs') |
| 292 self._idl_cache_no_refs = create_compiled_fs( | 319 self._idl_cache_no_refs = create_compiled_fs( |
| 293 lambda api_name, api: self._LoadIdlAPI(api, True), | 320 lambda api_name, api: self._LoadIdlAPI(api, True), |
| 294 'idl-no-refs') | 321 'idl-no-refs') |
| 295 | 322 |
| 296 self._idl_names_cache = create_compiled_fs(self._GetIDLNames, 'idl-names') | 323 self._idl_names_cache = create_compiled_fs(self._GetIDLNames, 'idl-names') |
| 297 self._names_cache = create_compiled_fs(self._GetAllNames, 'names') | 324 self._names_cache = create_compiled_fs(self._GetAllNames, 'names') |
| 298 | 325 |
| 299 self._base_path = base_path | 326 self._base_path = base_path |
| 300 | 327 self._availability_data_source = availability_data_source_factory.Create() |
| 301 # These must be set later via the SetFooDataSourceFactory methods. | 328 # These must be set later via the SetFooDataSourceFactory methods. |
| 302 self._ref_resolver_factory = None | 329 self._ref_resolver_factory = None |
| 303 self._samples_data_source_factory = None | 330 self._samples_data_source_factory = None |
| 304 | 331 |
| 305 def SetSamplesDataSourceFactory(self, samples_data_source_factory): | 332 def SetSamplesDataSourceFactory(self, samples_data_source_factory): |
| 306 self._samples_data_source_factory = samples_data_source_factory | 333 self._samples_data_source_factory = samples_data_source_factory |
| 307 | 334 |
| 308 def SetReferenceResolverFactory(self, ref_resolver_factory): | 335 def SetReferenceResolverFactory(self, ref_resolver_factory): |
| 309 self._ref_resolver_factory = ref_resolver_factory | 336 self._ref_resolver_factory = ref_resolver_factory |
| 310 | 337 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 336 samples, | 363 samples, |
| 337 disable_refs) | 364 disable_refs) |
| 338 | 365 |
| 339 def _LoadPermissions(self, file_name, json_str): | 366 def _LoadPermissions(self, file_name, json_str): |
| 340 return json_parse.Parse(json_str) | 367 return json_parse.Parse(json_str) |
| 341 | 368 |
| 342 def _LoadJsonAPI(self, api, disable_refs): | 369 def _LoadJsonAPI(self, api, disable_refs): |
| 343 return _JSCModel( | 370 return _JSCModel( |
| 344 json_parse.Parse(api)[0], | 371 json_parse.Parse(api)[0], |
| 345 self._ref_resolver_factory.Create() if not disable_refs else None, | 372 self._ref_resolver_factory.Create() if not disable_refs else None, |
| 346 disable_refs).ToDict() | 373 disable_refs, |
| 374 self._availability_data_source).ToDict() |
| 347 | 375 |
| 348 def _LoadIdlAPI(self, api, disable_refs): | 376 def _LoadIdlAPI(self, api, disable_refs): |
| 349 idl = idl_parser.IDLParser().ParseData(api) | 377 idl = idl_parser.IDLParser().ParseData(api) |
| 350 return _JSCModel( | 378 return _JSCModel( |
| 351 idl_schema.IDLSchema(idl).process()[0], | 379 idl_schema.IDLSchema(idl).process()[0], |
| 352 self._ref_resolver_factory.Create() if not disable_refs else None, | 380 self._ref_resolver_factory.Create() if not disable_refs else None, |
| 353 disable_refs).ToDict() | 381 disable_refs, |
| 382 self._availability_data_source).ToDict() |
| 354 | 383 |
| 355 def _GetIDLNames(self, base_dir, apis): | 384 def _GetIDLNames(self, base_dir, apis): |
| 356 return self._GetExtNames(apis, ['idl']) | 385 return self._GetExtNames(apis, ['idl']) |
| 357 | 386 |
| 358 def _GetAllNames(self, base_dir, apis): | 387 def _GetAllNames(self, base_dir, apis): |
| 359 return self._GetExtNames(apis, ['json', 'idl']) | 388 return self._GetExtNames(apis, ['json', 'idl']) |
| 360 | 389 |
| 361 def _GetExtNames(self, apis, exts): | 390 def _GetExtNames(self, apis, exts): |
| 362 return [model.UnixName(os.path.splitext(api)[0]) for api in apis | 391 return [model.UnixName(os.path.splitext(api)[0]) for api in apis |
| 363 if os.path.splitext(api)[1][1:] in exts] | 392 if os.path.splitext(api)[1][1:] in exts] |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 return feature_data | 452 return feature_data |
| 424 | 453 |
| 425 def _GenerateHandlebarContext(self, handlebar_dict, path): | 454 def _GenerateHandlebarContext(self, handlebar_dict, path): |
| 426 handlebar_dict['permissions'] = self._GetFeatureData(path) | 455 handlebar_dict['permissions'] = self._GetFeatureData(path) |
| 427 handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples) | 456 handlebar_dict['samples'] = _LazySamplesGetter(path, self._samples) |
| 428 return handlebar_dict | 457 return handlebar_dict |
| 429 | 458 |
| 430 def _GetAsSubdirectory(self, name): | 459 def _GetAsSubdirectory(self, name): |
| 431 if name.startswith('experimental_'): | 460 if name.startswith('experimental_'): |
| 432 parts = name[len('experimental_'):].split('_', 1) | 461 parts = name[len('experimental_'):].split('_', 1) |
| 433 parts[1] = 'experimental_%s' % parts[1] | 462 if len(parts) > 1: |
| 434 return '/'.join(parts) | 463 parts[1] = 'experimental_%s' % parts[1] |
| 464 return '/'.join(parts) |
| 465 else: |
| 466 return '%s/%s' % (parts[0], name) |
| 435 return name.replace('_', '/', 1) | 467 return name.replace('_', '/', 1) |
| 436 | 468 |
| 437 def get(self, key): | 469 def _DetermineNamesForGet(self, key): |
| 438 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'): | 470 if key.endswith('.html') or key.endswith('.json') or key.endswith('.idl'): |
| 439 path, ext = os.path.splitext(key) | 471 path, ext = os.path.splitext(key) |
| 440 else: | 472 else: |
| 441 path = key | 473 path = key |
| 442 unix_name = model.UnixName(path) | 474 unix_name = model.UnixName(path) |
| 443 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path) | |
| 444 names = self._names_cache.GetFromFileListing(self._base_path) | 475 names = self._names_cache.GetFromFileListing(self._base_path) |
| 445 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names: | 476 if unix_name not in names and self._GetAsSubdirectory(unix_name) in names: |
| 446 unix_name = self._GetAsSubdirectory(unix_name) | 477 unix_name = self._GetAsSubdirectory(unix_name) |
| 478 return (path, unix_name) |
| 447 | 479 |
| 480 def _DetermineCacheForGet(self, unix_name): |
| 481 idl_names = self._idl_names_cache.GetFromFileListing(self._base_path) |
| 448 if self._disable_refs: | 482 if self._disable_refs: |
| 449 cache, ext = ( | 483 cache, ext = ( |
| 450 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else | 484 (self._idl_cache_no_refs, '.idl') if (unix_name in idl_names) else |
| 451 (self._json_cache_no_refs, '.json')) | 485 (self._json_cache_no_refs, '.json')) |
| 452 else: | 486 else: |
| 453 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else | 487 cache, ext = ((self._idl_cache, '.idl') if (unix_name in idl_names) else |
| 454 (self._json_cache, '.json')) | 488 (self._json_cache, '.json')) |
| 489 return (cache, ext) |
| 490 |
| 491 def get(self, key): |
| 492 path, unix_name = self._DetermineNamesForGet(key) |
| 493 cache, ext = self._DetermineCacheForGet(unix_name) |
| 455 return self._GenerateHandlebarContext( | 494 return self._GenerateHandlebarContext( |
| 456 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)), | 495 cache.GetFromFile('%s/%s%s' % (self._base_path, unix_name, ext)), |
| 457 path) | 496 path) |
| OLD | NEW |