Flutter Engine
The Flutter Engine
database.py
Go to the documentation of this file.
1#!/usr/bin/env python3
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"""Module to manage IDL files."""
6
7import copy
8import pickle
9import logging
10import os
11import os.path
12import shutil
13import idlnode
14import idlrenderer
15from generator import IsDartCollectionType, IsPureInterface
16
17_logger = logging.getLogger('database')
18
19
20class Database(object):
21 """The Database class manages a collection of IDL files stored
22 inside a directory.
23
24 Each IDL is describing a single interface. The IDL files are written in the
25 FremontCut syntax, which is derived from the Web IDL syntax and includes
26 annotations.
27
28 Database operations include adding, updating and removing IDL files.
29 """
30
31 def __init__(self, root_dir):
32 """Initializes a Database over a given directory.
33
34 Args:
35 root_dir -- a directory. If directory does not exist, it will
36 be created.
37 """
38 self._root_dir = root_dir
39 if not os.path.exists(root_dir):
40 _logger.debug('creating root directory %s' % root_dir)
41 os.makedirs(root_dir)
42 self._all_interfaces = {}
43 self._interfaces_to_delete = []
44 self._enums = {}
45 self._all_dictionaries = {}
46 # TODO(terry): Hack to remember all typedef unions.
47 self._all_type_defs = {}
48
49 def Clone(self):
50 new_database = Database(self._root_dir)
51 new_database._all_interfaces = copy.deepcopy(self._all_interfaces)
52 new_database._interfaces_to_delete = copy.deepcopy(
54 new_database._enums = copy.deepcopy(self._enums)
55 new_database._all_dictionaries = copy.deepcopy(self._all_dictionaries)
56 new_database._all_type_defs = copy.deepcopy(self._all_type_defs)
57
58 return new_database
59
60 def Delete(self):
61 """Deletes the database by deleting its directory"""
62 if os.path.exists(self._root_dir):
63 shutil.rmtree(self._root_dir)
64 # reset in-memory constructs
65 self._all_interfaces = {}
66
67 def _ScanForInterfaces(self):
68 """Iterates over the database files and lists all interface names.
69
70 Return:
71 A list of interface names.
72 """
73 res = []
74
75 def Visitor(_, dirname, names):
76 for name in names:
77 if os.path.isfile(os.path.join(dirname, name)):
78 root, ext = os.path.splitext(name)
79 if ext == '.idl':
80 res.append(root)
81
82 os.path.walk(self._root_dir, Visitor, None)
83 return res
84
85 def _FilePath(self, interface_name):
86 """Calculates the file path that a given interface should
87 be saved to.
88
89 Args:
90 interface_name -- the name of the interface.
91 """
92 return os.path.join(self._root_dir, '%s.idl' % interface_name)
93
94 def _LoadInterfaceFile(self, interface_name):
95 """Loads an interface from the database.
96
97 Returns:
98 An IDLInterface instance or None if the interface is not found.
99 Args:
100 interface_name -- the name of the interface.
101 """
102 file_name = self._FilePath(interface_name)
103 _logger.info('loading %s' % file_name)
104 if not os.path.exists(file_name):
105 return None
106
107 f = open(file_name, 'r')
108 content = f.read()
109 f.close()
110
111 # Parse file:
112 idl_file = idlnode.IDLFile(self._idlparser.parse(content), file_name)
113
114 if not idl_file.interfaces:
115 raise RuntimeError('No interface found in %s' % file_name)
116 elif len(idl_file.interfaces) > 1:
117 raise RuntimeError('Expected one interface in %s' % file_name)
118
119 interface = idl_file.interfaces[0]
120 self._all_interfaces[interface_name] = interface
121 return interface
122
123 def Load(self):
124 """Loads all interfaces into memory.
125 """
126 # FIXME: Speed this up by multi-threading.
127 for (interface_name) in self._ScanForInterfaces():
128 self._LoadInterfaceFile(interface_name)
129 self.Cache()
130
131 def Cache(self):
132 """Serialize the database using pickle for faster startup in the future
133 """
134 output_file = open(os.path.join(self._root_dir, 'cache.pickle'), 'wb')
135 pickle.dump(self._all_interfaces, output_file)
136 pickle.dump(self._interfaces_to_delete, output_file)
137
138 def LoadFromCache(self):
139 """Deserialize the database using pickle for fast startup
140 """
141 input_file_name = os.path.join(self._root_dir, 'cache.pickle')
142 if not os.path.isfile(input_file_name):
143 self.Load()
144 return
145 input_file = open(input_file_name, 'rb')
146 self._all_interfaces = pickle.load(input_file)
147 self._interfaces_to_delete = pickle.load(input_file)
148 input_file.close()
149
150 def Save(self):
151 """Saves all in-memory interfaces into files."""
152 for interface in list(self._all_interfaces.values()):
153 self._SaveInterfaceFile(interface)
154 for interface_name in self._interfaces_to_delete:
155 self._DeleteInterfaceFile(interface_name)
156
157 def _SaveInterfaceFile(self, interface):
158 """Saves an interface into the database.
159
160 Args:
161 interface -- an IDLInterface instance.
162 """
163
164 interface_name = interface.id
165
166 # Actual saving
167 file_path = self._FilePath(interface_name)
168 _logger.debug('writing %s' % file_path)
169
170 dir_name = os.path.dirname(file_path)
171 if not os.path.exists(dir_name):
172 _logger.debug('creating directory %s' % dir_name)
173 os.mkdir(dir_name)
174
175 # Render the IDLInterface object into text.
176 text = idlrenderer.render(interface)
177
178 f = open(file_path, 'w')
179 f.write(text)
180 f.close()
181
182 def HasInterface(self, interface_name):
183 """Returns True if the interface is in memory"""
184 return interface_name in self._all_interfaces
185
186 def GetInterface(self, interface_name):
187 """Returns an IDLInterface corresponding to the interface_name
188 from memory.
189
190 Args:
191 interface_name -- the name of the interface.
192 """
193 if interface_name not in self._all_interfaces:
194 raise RuntimeError('Interface %s is not loaded' % interface_name)
195 return self._all_interfaces[interface_name]
196
197 def AddInterface(self, interface):
198 """Returns an IDLInterface corresponding to the interface_name
199 from memory.
200
201 Args:
202 interface -- the name of the interface.
203 """
204 interface_name = interface.id
205 if interface_name in self._all_interfaces:
206 raise RuntimeError('Interface %s already exists' % interface_name)
207 self._all_interfaces[interface_name] = interface
208
209 def GetInterfaces(self):
210 """Returns a list of all loaded interfaces."""
211 res = []
212 for _, interface in sorted(self._all_interfaces.items()):
213 res.append(interface)
214 return res
215
216 def DeleteInterface(self, interface_name):
217 """Deletes an interface from the database. File is deleted when
218 Save() is called.
219
220 Args:
221 interface_name -- the name of the interface.
222 """
223 if interface_name not in self._all_interfaces:
224 raise RuntimeError('Interface %s not found' % interface_name)
225 self._interfaces_to_delete.append(interface_name)
226 del self._all_interfaces[interface_name]
227
228 def _DeleteInterfaceFile(self, interface_name):
229 """Actual file deletion"""
230 file_path = self._FilePath(interface_name)
231 if os.path.exists(file_path):
232 _logger.debug('deleting %s' % file_path)
233 os.remove(file_path)
234
235 def Hierarchy(self, interface):
236 yield interface
237 for parent in interface.parents:
238 parent_name = parent.type.id
239 if not self.HasInterface(parent.type.id):
240 continue
241 for parent_interface in self.Hierarchy(
242 self.GetInterface(parent.type.id)):
243 yield parent_interface
244
245 def HasEnum(self, enum_name):
246 return enum_name in self._enums
247
248 def GetEnum(self, enum_name):
249 return self._enums[enum_name]
250
251 def AddEnum(self, enum):
252 self._enums[enum.id] = enum
253
254 def HasDictionary(self, dictionary_name):
255 """Returns True if the dictionary is in memory"""
256 return dictionary_name in self._all_dictionaries
257
258 def GetDictionary(self, dictionary_name):
259 """Returns an IDLDictionary corresponding to the dictionary_name
260 from memory.
261
262 Args:
263 dictionary_name -- the name of the dictionary.
264 """
265 if dictionary_name not in self._all_dictionaries:
266 raise RuntimeError('Dictionary %s is not loaded' % dictionary_name)
267 return self._all_dictionaries[dictionary_name]
268
269 def AddDictionary(self, dictionary):
270 """Returns an IDLDictionary corresponding to the dictionary_name
271 from memory.
272
273 Args:
274 dictionary -- the name of the dictionary.
275 """
276 dictionary_name = dictionary.id
277 if dictionary_name in self._all_dictionaries:
278 raise RuntimeError('Dictionary %s already exists' % dictionary_name)
279 self._all_dictionaries[dictionary_name] = dictionary
280
282 """Returns a list of all loaded dictionaries."""
283 res = []
284 for _, dictionary in sorted(self._all_dictionaries.items()):
285 res.append(dictionary)
286 return res
287
288 def HasTypeDef(self, type_def_name):
289 """Returns True if the typedef is in memory"""
290 return type_def_name in self._all_type_defs
291
292 def GetTypeDef(self, type_def_name):
293 """Returns an IDLTypeDef corresponding to the type_def_name
294 from memory.
295
296 Args:
297 type_def_name -- the name of the typedef.
298 """
299 if type_def_name not in self._all_type_defs:
300 raise RuntimeError('Typedef %s is not loaded' % type_def_name)
301 return self._all_type_defs[type_def_name]
302
303 def AddTypeDef(self, type_def):
304 """Add only a typedef that a unions they map to any (no type)."""
305 type_def_name = type_def.id
306 if type_def_name in self._all_type_defs:
307 raise RuntimeError('Typedef %s already exists' % type_def_name)
308 self._all_type_defs[type_def_name] = type_def
309 print(' Added typedef %s' % type_def_name)
310
311 def TransitiveSecondaryParents(self, interface, propagate_event_target):
312 """Returns a list of all non-primary parents.
313
314 The list contains the interface objects for interfaces defined in the
315 database, and the name for undefined interfaces.
316 """
317
318 def walk(parents, walk_result):
319 for parent in parents:
320 parent_name = parent.type.id
321 if IsDartCollectionType(parent_name):
322 if not (parent_name in walk_result):
323 walk_result.append(parent_name)
324 continue
325 if self.HasInterface(parent_name):
326 parent_interface = self.GetInterface(parent_name)
327 if not (parent_interface in walk_result):
328 # Interface has multi-inherited don't add interfaces more than once
329 # to our parent result list.
330 walk_result.append(parent_interface)
331 walk(parent_interface.parents, walk_result)
332 return walk_result
333
334 result = []
335 if interface.parents:
336 parent = interface.parents[0]
337 if (IsPureInterface(parent.type.id, self) or
338 (propagate_event_target and parent.type.id == 'EventTarget')):
339 result = walk(interface.parents, [])
340 else:
341 result = walk(interface.parents[1:], [])
342
343 return result
def GetTypeDef(self, type_def_name)
Definition: database.py:292
def AddEnum(self, enum)
Definition: database.py:251
def AddTypeDef(self, type_def)
Definition: database.py:303
def DeleteInterface(self, interface_name)
Definition: database.py:216
def TransitiveSecondaryParents(self, interface, propagate_event_target)
Definition: database.py:311
def GetEnum(self, enum_name)
Definition: database.py:248
def _FilePath(self, interface_name)
Definition: database.py:85
def GetInterface(self, interface_name)
Definition: database.py:186
def __init__(self, root_dir)
Definition: database.py:31
def AddDictionary(self, dictionary)
Definition: database.py:269
def HasEnum(self, enum_name)
Definition: database.py:245
def _LoadInterfaceFile(self, interface_name)
Definition: database.py:94
def _DeleteInterfaceFile(self, interface_name)
Definition: database.py:228
def HasDictionary(self, dictionary_name)
Definition: database.py:254
def AddInterface(self, interface)
Definition: database.py:197
def _ScanForInterfaces(self)
Definition: database.py:67
def _SaveInterfaceFile(self, interface)
Definition: database.py:157
def HasInterface(self, interface_name)
Definition: database.py:182
def GetDictionary(self, dictionary_name)
Definition: database.py:258
def Hierarchy(self, interface)
Definition: database.py:235
def HasTypeDef(self, type_def_name)
Definition: database.py:288
static void append(char **dst, size_t *count, const char *src, size_t n)
Definition: editor.cpp:211
Visitor(Ts...) -> Visitor< Ts... >
def parse(repo_root, recipes_cfg_path)
Definition: recipes.py:56
def print(*args, **kwargs)
Definition: run_tests.py:49