mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:28:02 +00:00
f26e522f84
BUG= R=alanknight@google.com Review URL: https://codereview.chromium.org/1987073002 .
343 lines
11 KiB
Python
Executable file
343 lines
11 KiB
Python
Executable file
#!/usr/bin/python
|
|
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
# for details. All rights reserved. Use of this source code is governed by a
|
|
# BSD-style license that can be found in the LICENSE file.
|
|
|
|
"""Module to manage IDL files."""
|
|
|
|
import copy
|
|
import pickle
|
|
import logging
|
|
import os
|
|
import os.path
|
|
import shutil
|
|
import idlnode
|
|
import idlrenderer
|
|
from generator import IsDartCollectionType, IsPureInterface
|
|
|
|
_logger = logging.getLogger('database')
|
|
|
|
|
|
class Database(object):
|
|
"""The Database class manages a collection of IDL files stored
|
|
inside a directory.
|
|
|
|
Each IDL is describing a single interface. The IDL files are written in the
|
|
FremontCut syntax, which is derived from the Web IDL syntax and includes
|
|
annotations.
|
|
|
|
Database operations include adding, updating and removing IDL files.
|
|
"""
|
|
|
|
def __init__(self, root_dir):
|
|
"""Initializes a Database over a given directory.
|
|
|
|
Args:
|
|
root_dir -- a directory. If directory does not exist, it will
|
|
be created.
|
|
"""
|
|
self._root_dir = root_dir
|
|
if not os.path.exists(root_dir):
|
|
_logger.debug('creating root directory %s' % root_dir)
|
|
os.makedirs(root_dir)
|
|
self._all_interfaces = {}
|
|
self._interfaces_to_delete = []
|
|
self._enums = {}
|
|
self._all_dictionaries = {}
|
|
# TODO(terry): Hack to remember all typedef unions.
|
|
self._all_type_defs = {}
|
|
|
|
def Clone(self):
|
|
new_database = Database(self._root_dir)
|
|
new_database._all_interfaces = copy.deepcopy(self._all_interfaces)
|
|
new_database._interfaces_to_delete = copy.deepcopy(
|
|
self._interfaces_to_delete)
|
|
new_database._enums = copy.deepcopy(self._enums)
|
|
new_database._all_dictionaries = copy.deepcopy(self._all_dictionaries)
|
|
new_database._all_type_defs = copy.deepcopy(self._all_type_defs)
|
|
|
|
return new_database
|
|
|
|
def Delete(self):
|
|
"""Deletes the database by deleting its directory"""
|
|
if os.path.exists(self._root_dir):
|
|
shutil.rmtree(self._root_dir)
|
|
# reset in-memory constructs
|
|
self._all_interfaces = {}
|
|
|
|
def _ScanForInterfaces(self):
|
|
"""Iteratores over the database files and lists all interface names.
|
|
|
|
Return:
|
|
A list of interface names.
|
|
"""
|
|
res = []
|
|
|
|
def Visitor(_, dirname, names):
|
|
for name in names:
|
|
if os.path.isfile(os.path.join(dirname, name)):
|
|
root, ext = os.path.splitext(name)
|
|
if ext == '.idl':
|
|
res.append(root)
|
|
|
|
os.path.walk(self._root_dir, Visitor, None)
|
|
return res
|
|
|
|
def _FilePath(self, interface_name):
|
|
"""Calculates the file path that a given interface should
|
|
be saved to.
|
|
|
|
Args:
|
|
interface_name -- the name of the interface.
|
|
"""
|
|
return os.path.join(self._root_dir, '%s.idl' % interface_name)
|
|
|
|
def _LoadInterfaceFile(self, interface_name):
|
|
"""Loads an interface from the database.
|
|
|
|
Returns:
|
|
An IDLInterface instance or None if the interface is not found.
|
|
Args:
|
|
interface_name -- the name of the interface.
|
|
"""
|
|
file_name = self._FilePath(interface_name)
|
|
_logger.info('loading %s' % file_name)
|
|
if not os.path.exists(file_name):
|
|
return None
|
|
|
|
f = open(file_name, 'r')
|
|
content = f.read()
|
|
f.close()
|
|
|
|
# Parse file:
|
|
idl_file = idlnode.IDLFile(self._idlparser.parse(content), file_name)
|
|
|
|
if not idl_file.interfaces:
|
|
raise RuntimeError('No interface found in %s' % file_name)
|
|
elif len(idl_file.interfaces) > 1:
|
|
raise RuntimeError('Expected one interface in %s' % file_name)
|
|
|
|
interface = idl_file.interfaces[0]
|
|
self._all_interfaces[interface_name] = interface
|
|
return interface
|
|
|
|
def Load(self):
|
|
"""Loads all interfaces into memory.
|
|
"""
|
|
# FIXME: Speed this up by multi-threading.
|
|
for (interface_name) in self._ScanForInterfaces():
|
|
self._LoadInterfaceFile(interface_name)
|
|
self.Cache()
|
|
|
|
def Cache(self):
|
|
"""Serialize the database using pickle for faster startup in the future
|
|
"""
|
|
output_file = open(os.path.join(self._root_dir, 'cache.pickle'), 'wb')
|
|
pickle.dump(self._all_interfaces, output_file)
|
|
pickle.dump(self._interfaces_to_delete, output_file)
|
|
|
|
def LoadFromCache(self):
|
|
"""Deserialize the database using pickle for fast startup
|
|
"""
|
|
input_file_name = os.path.join(self._root_dir, 'cache.pickle')
|
|
if not os.path.isfile(input_file_name):
|
|
self.Load()
|
|
return
|
|
input_file = open(input_file_name, 'rb')
|
|
self._all_interfaces = pickle.load(input_file)
|
|
self._interfaces_to_delete = pickle.load(input_file)
|
|
input_file.close()
|
|
|
|
def Save(self):
|
|
"""Saves all in-memory interfaces into files."""
|
|
for interface in self._all_interfaces.values():
|
|
self._SaveInterfaceFile(interface)
|
|
for interface_name in self._interfaces_to_delete:
|
|
self._DeleteInterfaceFile(interface_name)
|
|
|
|
def _SaveInterfaceFile(self, interface):
|
|
"""Saves an interface into the database.
|
|
|
|
Args:
|
|
interface -- an IDLInterface instance.
|
|
"""
|
|
|
|
interface_name = interface.id
|
|
|
|
# Actual saving
|
|
file_path = self._FilePath(interface_name)
|
|
_logger.debug('writing %s' % file_path)
|
|
|
|
dir_name = os.path.dirname(file_path)
|
|
if not os.path.exists(dir_name):
|
|
_logger.debug('creating directory %s' % dir_name)
|
|
os.mkdir(dir_name)
|
|
|
|
# Render the IDLInterface object into text.
|
|
text = idlrenderer.render(interface)
|
|
|
|
f = open(file_path, 'w')
|
|
f.write(text)
|
|
f.close()
|
|
|
|
def HasInterface(self, interface_name):
|
|
"""Returns True if the interface is in memory"""
|
|
return interface_name in self._all_interfaces
|
|
|
|
def GetInterface(self, interface_name):
|
|
"""Returns an IDLInterface corresponding to the interface_name
|
|
from memory.
|
|
|
|
Args:
|
|
interface_name -- the name of the interface.
|
|
"""
|
|
if interface_name not in self._all_interfaces:
|
|
raise RuntimeError('Interface %s is not loaded' % interface_name)
|
|
return self._all_interfaces[interface_name]
|
|
|
|
def AddInterface(self, interface):
|
|
"""Returns an IDLInterface corresponding to the interface_name
|
|
from memory.
|
|
|
|
Args:
|
|
interface -- the name of the interface.
|
|
"""
|
|
interface_name = interface.id
|
|
if interface_name in self._all_interfaces:
|
|
raise RuntimeError('Interface %s already exists' % interface_name)
|
|
self._all_interfaces[interface_name] = interface
|
|
|
|
def GetInterfaces(self):
|
|
"""Returns a list of all loaded interfaces."""
|
|
res = []
|
|
for _, interface in sorted(self._all_interfaces.items()):
|
|
res.append(interface)
|
|
return res
|
|
|
|
def DeleteInterface(self, interface_name):
|
|
"""Deletes an interface from the database. File is deleted when
|
|
Save() is called.
|
|
|
|
Args:
|
|
interface_name -- the name of the interface.
|
|
"""
|
|
if interface_name not in self._all_interfaces:
|
|
raise RuntimeError('Interface %s not found' % interface_name)
|
|
self._interfaces_to_delete.append(interface_name)
|
|
del self._all_interfaces[interface_name]
|
|
|
|
def _DeleteInterfaceFile(self, interface_name):
|
|
"""Actual file deletion"""
|
|
file_path = self._FilePath(interface_name)
|
|
if os.path.exists(file_path):
|
|
_logger.debug('deleting %s' % file_path)
|
|
os.remove(file_path)
|
|
|
|
def Hierarchy(self, interface):
|
|
yield interface
|
|
for parent in interface.parents:
|
|
parent_name = parent.type.id
|
|
if not self.HasInterface(parent.type.id):
|
|
continue
|
|
for parent_interface in self.Hierarchy(self.GetInterface(parent.type.id)):
|
|
yield parent_interface
|
|
|
|
def HasEnum(self, enum_name):
|
|
return enum_name in self._enums
|
|
|
|
def GetEnum(self, enum_name):
|
|
return self._enums[enum_name]
|
|
|
|
def AddEnum(self, enum):
|
|
self._enums[enum.id] = enum
|
|
|
|
def HasDictionary(self, dictionary_name):
|
|
"""Returns True if the dictionary is in memory"""
|
|
return dictionary_name in self._all_dictionaries
|
|
|
|
def GetDictionary(self, dictionary_name):
|
|
"""Returns an IDLDictionary corresponding to the dictionary_name
|
|
from memory.
|
|
|
|
Args:
|
|
dictionary_name -- the name of the dictionary.
|
|
"""
|
|
if dictionary_name not in self._all_dictionaries:
|
|
raise RuntimeError('Dictionary %s is not loaded' % dictionary_name)
|
|
return self._all_dictionaries[dictionary_name]
|
|
|
|
def AddDictionary(self, dictionary):
|
|
"""Returns an IDLDictionary corresponding to the dictionary_name
|
|
from memory.
|
|
|
|
Args:
|
|
dictionary -- the name of the dictionary.
|
|
"""
|
|
dictionary_name = dictionary.id
|
|
if dictionary_name in self._all_dictionaries:
|
|
raise RuntimeError('Dictionary %s already exists' % dictionary_name)
|
|
self._all_dictionaries[dictionary_name] = dictionary
|
|
|
|
def GetDictionaries(self):
|
|
"""Returns a list of all loaded dictionaries."""
|
|
res = []
|
|
for _, dictionary in sorted(self._all_dictionaries.items()):
|
|
res.append(dictionary)
|
|
return res
|
|
|
|
def HasTypeDef(self, type_def_name):
|
|
"""Returns True if the typedef is in memory"""
|
|
return type_def_name in self._all_type_defs
|
|
|
|
def GetTypeDef(self, type_def_name):
|
|
"""Returns an IDLTypeDef corresponding to the type_def_name
|
|
from memory.
|
|
|
|
Args:
|
|
type_def_name -- the name of the typedef.
|
|
"""
|
|
if type_def_name not in self._all_type_defs:
|
|
raise RuntimeError('Typedef %s is not loaded' % type_def_name)
|
|
return self._all_type_defs[type_def_name]
|
|
|
|
def AddTypeDef(self, type_def):
|
|
"""Add only a typedef that a unions they map to any (no type)."""
|
|
type_def_name = type_def.id
|
|
if type_def_name in self._all_type_defs:
|
|
raise RuntimeError('Typedef %s already exists' % type_def_name)
|
|
self._all_type_defs[type_def_name] = type_def
|
|
print ' Added typedef %s' % type_def_name
|
|
|
|
def TransitiveSecondaryParents(self, interface, propagate_event_target):
|
|
"""Returns a list of all non-primary parents.
|
|
|
|
The list contains the interface objects for interfaces defined in the
|
|
database, and the name for undefined interfaces.
|
|
"""
|
|
def walk(parents, walk_result):
|
|
for parent in parents:
|
|
parent_name = parent.type.id
|
|
if IsDartCollectionType(parent_name):
|
|
if not(parent_name in walk_result):
|
|
walk_result.append(parent_name)
|
|
continue
|
|
if self.HasInterface(parent_name):
|
|
parent_interface = self.GetInterface(parent_name)
|
|
if not(parent_interface in walk_result):
|
|
# Interface has multi-inherited don't add interfaces more than once
|
|
# to our parent result list.
|
|
walk_result.append(parent_interface)
|
|
walk(parent_interface.parents, walk_result)
|
|
return walk_result
|
|
|
|
result = []
|
|
if interface.parents:
|
|
parent = interface.parents[0]
|
|
if (IsPureInterface(parent.type.id, self) or
|
|
(propagate_event_target and parent.type.id == 'EventTarget')):
|
|
result = walk(interface.parents, [])
|
|
else:
|
|
result = walk(interface.parents[1:], [])
|
|
|
|
return result
|
|
|