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 |