| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/python | |
| 2 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
| 3 # for details. All rights reserved. Use of this source code is governed by a | |
| 4 # BSD-style license that can be found in the LICENSE file. | |
| 5 | |
| 6 """Module to manage IDL files.""" | |
| 7 | |
| 8 import copy | |
| 9 import pickle | |
| 10 import logging | |
| 11 import os | |
| 12 import os.path | |
| 13 import shutil | |
| 14 import idlnode | |
| 15 import idlparser | |
| 16 import idlrenderer | |
| 17 | |
| 18 _logger = logging.getLogger('database') | |
| 19 | |
| 20 | |
| 21 class Database(object): | |
| 22 """The Database class manages a collection of IDL files stored | |
| 23 inside a directory. | |
| 24 | |
| 25 Each IDL is describing a single interface. The IDL files are written in the | |
| 26 FremontCut syntax, which is derived from the Web IDL syntax and includes | |
| 27 annotations. | |
| 28 | |
| 29 Database operations include adding, updating and removing IDL files. | |
| 30 """ | |
| 31 | |
| 32 def __init__(self, root_dir): | |
| 33 """Initializes a Database over a given directory. | |
| 34 | |
| 35 Args: | |
| 36 root_dir -- a directory. If directory does not exist, it will | |
| 37 be created. | |
| 38 """ | |
| 39 self._root_dir = root_dir | |
| 40 if not os.path.exists(root_dir): | |
| 41 _logger.debug('creating root directory %s' % root_dir) | |
| 42 os.makedirs(root_dir) | |
| 43 self._all_interfaces = {} | |
| 44 self._interfaces_to_delete = [] | |
| 45 self._idlparser = idlparser.IDLParser(idlparser.FREMONTCUT_SYNTAX) | |
| 46 | |
| 47 def Clone(self): | |
| 48 new_database = Database(self._root_dir) | |
| 49 new_database._all_interfaces = copy.deepcopy(self._all_interfaces) | |
| 50 new_database._interfaces_to_delete = copy.deepcopy( | |
| 51 self._interfaces_to_delete) | |
| 52 return new_database | |
| 53 | |
| 54 def Delete(self): | |
| 55 """Deletes the database by deleting its directory""" | |
| 56 if os.path.exists(self._root_dir): | |
| 57 shutil.rmtree(self._root_dir) | |
| 58 # reset in-memory constructs | |
| 59 self._all_interfaces = {} | |
| 60 | |
| 61 def _ScanForInterfaces(self): | |
| 62 """Iteratores over the database files and lists all interface names. | |
| 63 | |
| 64 Return: | |
| 65 A list of interface names. | |
| 66 """ | |
| 67 res = [] | |
| 68 | |
| 69 def Visitor(_, dirname, names): | |
| 70 for name in names: | |
| 71 if os.path.isfile(os.path.join(dirname, name)): | |
| 72 root, ext = os.path.splitext(name) | |
| 73 if ext == '.idl': | |
| 74 res.append(root) | |
| 75 | |
| 76 os.path.walk(self._root_dir, Visitor, None) | |
| 77 return res | |
| 78 | |
| 79 def _FilePath(self, interface_name): | |
| 80 """Calculates the file path that a given interface should | |
| 81 be saved to. | |
| 82 | |
| 83 Args: | |
| 84 interface_name -- the name of the interface. | |
| 85 """ | |
| 86 return os.path.join(self._root_dir, '%s.idl' % interface_name) | |
| 87 | |
| 88 def _LoadInterfaceFile(self, interface_name): | |
| 89 """Loads an interface from the database. | |
| 90 | |
| 91 Returns: | |
| 92 An IDLInterface instance or None if the interface is not found. | |
| 93 Args: | |
| 94 interface_name -- the name of the interface. | |
| 95 """ | |
| 96 file_name = self._FilePath(interface_name) | |
| 97 _logger.info('loading %s' % file_name) | |
| 98 if not os.path.exists(file_name): | |
| 99 return None | |
| 100 | |
| 101 f = open(file_name, 'r') | |
| 102 content = f.read() | |
| 103 f.close() | |
| 104 | |
| 105 # Parse file: | |
| 106 idl_file = idlnode.IDLFile(self._idlparser.parse(content), file_name) | |
| 107 | |
| 108 if not idl_file.interfaces: | |
| 109 raise RuntimeError('No interface found in %s' % file_name) | |
| 110 elif len(idl_file.interfaces) > 1: | |
| 111 raise RuntimeError('Expected one interface in %s' % file_name) | |
| 112 | |
| 113 interface = idl_file.interfaces[0] | |
| 114 self._all_interfaces[interface_name] = interface | |
| 115 return interface | |
| 116 | |
| 117 def Load(self): | |
| 118 """Loads all interfaces into memory. | |
| 119 """ | |
| 120 # FIXME: Speed this up by multi-threading. | |
| 121 for (interface_name) in self._ScanForInterfaces(): | |
| 122 self._LoadInterfaceFile(interface_name) | |
| 123 self.Cache() | |
| 124 | |
| 125 def Cache(self): | |
| 126 """Serialize the database using pickle for faster startup in the future | |
| 127 """ | |
| 128 output_file = open(os.path.join(self._root_dir, 'cache.pickle'), 'wb') | |
| 129 pickle.dump(self._all_interfaces, output_file) | |
| 130 pickle.dump(self._interfaces_to_delete, output_file) | |
| 131 | |
| 132 def LoadFromCache(self): | |
| 133 """Deserialize the database using pickle for fast startup | |
| 134 """ | |
| 135 input_file_name = os.path.join(self._root_dir, 'cache.pickle') | |
| 136 if not os.path.isfile(input_file_name): | |
| 137 self.Load() | |
| 138 return | |
| 139 input_file = open(input_file_name, 'rb') | |
| 140 self._all_interfaces = pickle.load(input_file) | |
| 141 self._interfaces_to_delete = pickle.load(input_file) | |
| 142 input_file.close() | |
| 143 | |
| 144 def Save(self): | |
| 145 """Saves all in-memory interfaces into files.""" | |
| 146 for interface in self._all_interfaces.values(): | |
| 147 self._SaveInterfaceFile(interface) | |
| 148 for interface_name in self._interfaces_to_delete: | |
| 149 self._DeleteInterfaceFile(interface_name) | |
| 150 | |
| 151 def _SaveInterfaceFile(self, interface): | |
| 152 """Saves an interface into the database. | |
| 153 | |
| 154 Args: | |
| 155 interface -- an IDLInterface instance. | |
| 156 """ | |
| 157 | |
| 158 interface_name = interface.id | |
| 159 | |
| 160 # Actual saving | |
| 161 file_path = self._FilePath(interface_name) | |
| 162 _logger.debug('writing %s' % file_path) | |
| 163 | |
| 164 dir_name = os.path.dirname(file_path) | |
| 165 if not os.path.exists(dir_name): | |
| 166 _logger.debug('creating directory %s' % dir_name) | |
| 167 os.mkdir(dir_name) | |
| 168 | |
| 169 # Render the IDLInterface object into text. | |
| 170 text = idlrenderer.render(interface) | |
| 171 | |
| 172 f = open(file_path, 'w') | |
| 173 f.write(text) | |
| 174 f.close() | |
| 175 | |
| 176 def HasInterface(self, interface_name): | |
| 177 """Returns True if the interface is in memory""" | |
| 178 return interface_name in self._all_interfaces | |
| 179 | |
| 180 def GetInterface(self, interface_name): | |
| 181 """Returns an IDLInterface corresponding to the interface_name | |
| 182 from memory. | |
| 183 | |
| 184 Args: | |
| 185 interface_name -- the name of the interface. | |
| 186 """ | |
| 187 if interface_name not in self._all_interfaces: | |
| 188 raise RuntimeError('Interface %s is not loaded' % interface_name) | |
| 189 return self._all_interfaces[interface_name] | |
| 190 | |
| 191 def AddInterface(self, interface): | |
| 192 """Returns an IDLInterface corresponding to the interface_name | |
| 193 from memory. | |
| 194 | |
| 195 Args: | |
| 196 interface -- the name of the interface. | |
| 197 """ | |
| 198 interface_name = interface.id | |
| 199 if interface_name in self._all_interfaces: | |
| 200 raise RuntimeError('Interface %s already exists' % interface_name) | |
| 201 self._all_interfaces[interface_name] = interface | |
| 202 | |
| 203 def GetInterfaces(self): | |
| 204 """Returns a list of all loaded interfaces.""" | |
| 205 res = [] | |
| 206 for _, interface in sorted(self._all_interfaces.items()): | |
| 207 res.append(interface) | |
| 208 return res | |
| 209 | |
| 210 def DeleteInterface(self, interface_name): | |
| 211 """Deletes an interface from the database. File is deleted when | |
| 212 Save() is called. | |
| 213 | |
| 214 Args: | |
| 215 interface_name -- the name of the interface. | |
| 216 """ | |
| 217 if interface_name not in self._all_interfaces: | |
| 218 raise RuntimeError('Interface %s not found' % interface_name) | |
| 219 self._interfaces_to_delete.append(interface_name) | |
| 220 del self._all_interfaces[interface_name] | |
| 221 | |
| 222 def _DeleteInterfaceFile(self, interface_name): | |
| 223 """Actual file deletion""" | |
| 224 file_path = self._FilePath(interface_name) | |
| 225 if os.path.exists(file_path): | |
| 226 _logger.debug('deleting %s' % file_path) | |
| 227 os.remove(file_path) | |
| 228 | |
| 229 def Hierarchy(self, interface): | |
| 230 yield interface | |
| 231 for parent in interface.parents: | |
| 232 parent_name = parent.type.id | |
| 233 if not self.HasInterface(parent.type.id): | |
| 234 continue | |
| 235 for parent_interface in self.Hierarchy(self.GetInterface(parent.type.id)): | |
| 236 yield parent_interface | |
| OLD | NEW |