USB: add generic usb-keyboard device driver (EXPERIMENTAL)
[bertos.git] / wizard / BProject.py
1 #!/usr/bin/env python
2 # encoding: utf-8
3 #
4 # This file is part of BeRTOS.
5 #
6 # Bertos is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 #
20 # As a special exception, you may use this file as part of a free software
21 # library without restriction.  Specifically, if other files instantiate
22 # templates or use macros or inline functions from this file, or you compile
23 # this file and link it with other files to produce an executable, this
24 # file does not by itself cause the resulting executable to be covered by
25 # the GNU General Public License.  This exception does not however
26 # invalidate any other reasons why the executable file might be covered by
27 # the GNU General Public License.
28 #
29 # Copyright 2008 Develer S.r.l. (http://www.develer.com/)
30 #
31 #
32 # Author: Lorenzo Berni <duplo@develer.com>
33 #
34
35 import os
36 import fnmatch
37 import copy
38 import pickle
39 import shutil
40 import copytree
41
42 import DefineException
43
44 from LoadException import VersionException, ToolchainException
45
46 import const
47
48 from bertos_utils import (
49                             # Utility functions
50                             isBertosDir, getTagSet, getInfos, updateConfigurationValues,
51                             loadConfigurationInfos, loadDefineLists, loadModuleDefinition,
52                             getCommentList, sub,
53
54                             # Project creation functions
55                             projectFileGenerator, versionFileGenerator, loadPlugin,
56                             mergeSources,
57
58                             # Custom exceptions
59                             ParseError, SupportedException
60                         )
61 import bertos_utils
62
63 from compatibility import updateProject
64
65 class BProject(object):
66     """
67     Simple class for store and retrieve project informations.
68     """
69
70     def __init__(self, project_file="", info_dict={}):
71         self.infos = {}
72         self._cached_queries = {}
73         self.edit = False
74         if project_file:
75             self.edit = True
76             self.loadBertosProject(project_file, info_dict)
77
78     #--- Load methods (methods that loads data into project) ------------------#
79
80     def loadBertosProject(self, project_file, info_dict):
81         project_dir = os.path.dirname(project_file)
82         project_data = pickle.loads(open(project_file, "r").read())
83         updateProject(project_data)
84         # If PROJECT_NAME is not defined it use the directory name as PROJECT_NAME
85         # NOTE: this can throw an Exception if the user has changed the directory containing the project
86         self.infos["PROJECT_NAME"] = project_data.get("PROJECT_NAME", os.path.basename(project_dir))
87         self.infos["PROJECT_PATH"] = os.path.dirname(project_file)
88         project_src_path = os.path.join(project_dir, project_data.get("PROJECT_SRC_PATH", project_data["PROJECT_NAME"]))
89         if project_src_path:
90             self.infos["PROJECT_SRC_PATH"] = project_src_path
91
92         else:
93             # In projects created with older versions of the Wizard this metadata doesn't exist
94             self.infos["PROJECT_SRC_PATH"] = os.path.join(self.infos["PROJECT_PATH"], self.infos["PROJECT_NAME"])
95         self.infos["PROJECT_HW_PATH"] = os.path.join(self.infos["PROJECT_PATH"], project_data.get("PROJECT_HW_PATH", self.infos["PROJECT_PATH"]))
96
97         linked_sources_path = project_data["BERTOS_PATH"]
98         sources_abspath = os.path.abspath(os.path.join(project_dir, linked_sources_path))
99         project_data["BERTOS_PATH"] = sources_abspath
100
101         self._loadBertosSourceStuff(project_data["BERTOS_PATH"], info_dict.get("BERTOS_PATH", None))
102
103         self.infos["PRESET"] = project_data.get("PRESET", False)
104
105         # For those projects that don't have a VERSION file create a dummy one.
106         if not isBertosDir(project_dir) and not self.is_preset:
107             version_file = open(os.path.join(const.DATA_DIR, "vtemplates/VERSION"), "r").read()
108             open(os.path.join(project_dir, "VERSION"), "w").write(version_file.replace("$version", "").strip())
109
110         self.loadSourceTree()
111         self._loadCpuStuff(project_data["CPU_NAME"], project_data["SELECTED_FREQ"])
112         self._loadToolchainStuff(project_data["TOOLCHAIN"], info_dict.get("TOOLCHAIN", None))
113         self.infos["OUTPUT"] = project_data["OUTPUT"]
114         self.loadModuleData(True)
115         self.setEnabledModules(project_data["ENABLED_MODULES"])
116
117     def _loadBertosSourceStuff(self, sources_path, forced_version=None):
118         if forced_version:
119             sources_path = forced_version
120         if os.path.exists(sources_path):
121             self.infos["BERTOS_PATH"] = sources_path
122         else:
123             raise VersionException(self)
124
125     def _loadCpuStuff(self, cpu_name, cpu_frequency):
126         self.infos["CPU_NAME"] = cpu_name
127         cpu_info = self.getCpuInfos()
128         for cpu in cpu_info:
129             if cpu["CPU_NAME"] == cpu_name:
130                 self.infos["CPU_INFOS"] = cpu
131                 break
132         tag_list = getTagSet(cpu_info)
133         # Create, fill and store the dict with the tags
134         tag_dict = {}
135         for element in tag_list:
136             tag_dict[element] = False
137         infos = self.info("CPU_INFOS")
138         for tag in tag_dict:
139             if tag in infos["CPU_TAGS"] + [infos["CPU_NAME"], infos["TOOLCHAIN"]]:
140                 tag_dict[tag] = True
141             else:
142                 tag_dict[tag] = False
143         self.infos["ALL_CPU_TAGS"] = tag_dict
144         self.infos["SELECTED_FREQ"] = cpu_frequency
145
146     def _loadToolchainStuff(self, toolchain, forced_toolchain=None):
147         toolchain = toolchain
148         if forced_toolchain:
149             toolchain = forced_toolchain
150         if os.path.exists(toolchain["path"]):
151             self.infos["TOOLCHAIN"] = toolchain
152         else:
153             raise ToolchainException(self)
154
155     def loadProjectFromPreset(self, preset):
156         """
157         Load a project from a preset.
158         NOTE: this is a stub.
159         """
160         project_file = os.path.join(preset, "project.bertos")
161         project_data = pickle.loads(open(project_file, "r").read())
162         self.loadSourceTree()
163         self._loadCpuStuff(project_data["CPU_NAME"], project_data["SELECTED_FREQ"])
164
165         # NOTE: this is a HACK!!!
166         # TODO: find a better way to reuse loadModuleData
167         preset_project_name = project_data.get("PROJECT_NAME", os.path.basename(preset))
168         preset_prj_src_path = os.path.join(preset, project_data.get("PROJECT_SRC_PATH", os.path.join(preset, preset_project_name)))
169         preset_prj_hw_path = os.path.join(preset, project_data.get("PROJECT_HW_PATH", preset))
170
171         old_project_name = self.infos["PROJECT_NAME"]
172         old_project_path = self.infos["PROJECT_PATH"]
173         old_project_src_path = self.infos["PROJECT_SRC_PATH"]
174         old_project_hw_path = self.infos["PROJECT_HW_PATH"]
175
176         self.infos["PROJECT_NAME"] = preset_project_name
177         self.infos["PROJECT_PATH"] = preset
178         self.infos["PROJECT_SRC_PATH"] = preset_prj_src_path
179         self.infos["PROJECT_HW_PATH"] = preset_prj_hw_path
180
181         self.loadModuleData(True)
182         self.setEnabledModules(project_data["ENABLED_MODULES"])
183
184         self.infos["PROJECT_NAME"] = old_project_name
185         self.infos["PROJECT_PATH"] = old_project_path
186         self.infos["PROJECT_SRC_PATH"] = old_project_src_path
187         self.infos["PROJECT_HW_PATH"] = old_project_hw_path
188         # End of the ugly HACK!
189
190         self.infos["PRESET_NAME"] = preset_project_name
191         self.infos["PRESET_PATH"] = preset
192         self.infos["PRESET_SRC_PATH"] = preset_prj_src_path
193         self.infos["PRESET_HW_PATH"] = preset_prj_hw_path
194
195     def loadProjectPresets(self):
196         """
197         Load the default presets (into the const.PREDEFINED_BOARDS_DIR).
198         """
199         # NOTE: this method does nothing (for now).
200         preset_path = os.path.join(self.infos["BERTOS_PATH"], const.PREDEFINED_BOARDS_DIR)
201         preset_tree = {"children": []}
202         if os.path.exists(preset_path):
203             preset_tree = self._loadProjectPresetTree(preset_path)
204         self.infos["PRESET_TREE"] = preset_tree
205
206     def _loadProjectPresetTree(self, path):
207         _tree = {}
208         _tree["info"] = self._loadPresetInfo(os.path.join(path, const.PREDEFINED_BOARD_SPEC_FILE))
209         _tree["info"]["filename"] = os.path.basename(path)
210         _tree["info"]["path"] = path
211         _tree["children"] = {}
212         entries = set(os.listdir(path))
213         for entry in entries:
214             _path = os.path.join(path, entry)
215             if os.path.isdir(_path):
216                 sub_entries = set(os.listdir(_path))
217                 if const.PREDEFINED_BOARD_SPEC_FILE in sub_entries:
218                     _tree["children"][_path] = self._loadProjectPresetTree(_path)
219         # Add into the info dict the dir type (dir/project)
220         if _tree["children"]:
221             _tree["info"]["type"] = "dir"
222         else:
223             _tree["info"]["type"] = "project"
224         return _tree
225
226     def _loadPresetInfo(self, preset_spec_file):
227         D = {}
228         try:
229             execfile(preset_spec_file, {}, D)
230         except IOError, e:
231             pass
232         return D
233
234     def loadModuleData(self, edit=False):
235         module_info_dict = {}
236         list_info_dict = {}
237         configuration_info_dict = {}
238         file_dict = {}
239         for filename, path in self.findDefinitions("*.h") + self.findDefinitions("*.c") + self.findDefinitions("*.s") + self.findDefinitions("*.S"):
240             comment_list = getCommentList(open(path + "/" + filename, "r").read())
241             if len(comment_list) > 0:
242                 module_info = {}
243                 configuration_info = {}
244                 try:
245                     to_be_parsed, module_dict = loadModuleDefinition(comment_list[0])
246                 except ParseError, err:
247                     raise DefineException.ModuleDefineException(os.path.join(path, filename), err.line_number, err.line)
248                 for module, information in module_dict.items():
249                     if "depends" not in information:
250                         information["depends"] = ()
251                     information["depends"] += (filename.split(".")[0],)
252                     information["category"] = os.path.basename(path)
253
254                     # Hack to remove 'bertos/' from the configuration file path.
255                     #
256                     # The new module information format substitute paths like 'bertos/cfg/config_file.h'
257                     # with the relative path into the bertos directory ('cfg/config_file.h')
258                     information["configuration"] = information["configuration"].replace("bertos/", "")
259                     information["hw"] = [hw.replace("bertos/", "") for hw in information["hw"]]
260
261                     if "configuration" in information and len(information["configuration"]):
262                         configuration = module_dict[module]["configuration"]
263                         try:
264                             cfg_file_path = os.path.join(self.bertos_srcdir, configuration)
265                             configuration_info[configuration] = loadConfigurationInfos(cfg_file_path)
266                         except ParseError, err:
267                             raise DefineException.ConfigurationDefineException(cfg_file_path, err.line_number, err.line)
268                         if edit:
269                             try:
270                                 path = self.infos["PROJECT_SRC_PATH"]
271                                 cfg_file_path = os.path.join(path, configuration)
272                                 configuration_info[configuration] = updateConfigurationValues(configuration_info[configuration], loadConfigurationInfos(cfg_file_path))
273                             except ParseError, err:
274                                 raise DefineException.ConfigurationDefineException(cfg_file_path, err.line_number, err.line)
275                             except IOError, err:
276                                 # The wizard can't find the file, use the default configuration
277                                 pass
278                 module_info_dict.update(module_dict)
279                 configuration_info_dict.update(configuration_info)
280                 if to_be_parsed:
281                     try:
282                         list_dict = loadDefineLists(comment_list[1:])
283                         list_info_dict.update(list_dict)
284                     except ParseError, err:
285                         raise DefineException.EnumDefineException(os.path.join(path, filename), err.line_number, err.line)
286         for tag in self.infos["CPU_INFOS"]["CPU_TAGS"]:
287             for filename, path in self.findDefinitions("*_" + tag + ".h"):
288                 comment_list = getCommentList(open(path + "/" + filename, "r").read())
289                 list_info_dict.update(loadDefineLists(comment_list))
290         self.infos["MODULES"] = module_info_dict
291         self.infos["LISTS"] = list_info_dict
292         self.infos["CONFIGURATIONS"] = configuration_info_dict
293         self.infos["FILES"] = file_dict
294
295     def loadSourceTree(self):
296         """
297         Index BeRTOS source and load it in memory.
298         """
299         # Index only the BERTOS_PATH/bertos content
300         bertos_sources_dir = os.path.join(self.info("BERTOS_PATH"), "bertos")
301         file_dict = {}
302         if os.path.exists(bertos_sources_dir):
303             for element in os.walk(bertos_sources_dir):
304                 for f in element[2]:
305                     file_dict[f] = file_dict.get(f, []) + [element[0]]
306         self.infos["FILE_DICT"] = file_dict
307
308     def reloadCpuInfo(self):
309         for cpu_info in self.getCpuInfos():
310             if cpu_info["CPU_NAME"] == self.infos["CPU_NAME"]:
311                 self.infos["CPU_INFOS"] = cpu_info
312
313     #-------------------------------------------------------------------------#
314
315     def createBertosProject(self):
316         # NOTE: Temporary hack.
317         if self.edit:
318             self._editBertosProject()
319         else:
320             if not self.from_preset:
321                 self._newCustomBertosProject()
322             else:
323                 self._newBertosProjectFromPreset()
324
325     def _newBertosProject(self):
326         for directory in (self.maindir, self.srcdir, self.prjdir, self.cfgdir, self.hwdir):
327             self._createDirectory(directory)
328         # Write the project file
329         self._writeProjectFile(os.path.join(self.maindir, "project.bertos"))
330         # VERSION file
331         self._writeVersionFile(os.path.join(self.maindir, "VERSION"))
332         # Destination makefile
333         self._writeMakefile()
334         # Copy the sources
335         self._copySources(self.bertos_maindir, self.srcdir)
336         # Set properly the autoenabled parameters
337         self._setupAutoenabledParameters()
338         # Copy all the configuration files
339         self._writeCfgFiles(self.bertos_srcdir, self.cfgdir)
340         # Destination wizard mk file
341         self._writeWizardMkFile()
342
343     def _newCustomBertosProject(self):
344         # Create/write/copy the common things
345         self._newBertosProject()
346         # Copy the clean hw files
347         self._createDirectory(self.hwdir)
348         # Copy all the hw files
349         self._writeHwFiles(self.bertos_srcdir, self.hwdir)
350         # Destination user mk file
351         self._writeUserMkFile()
352         # Destination main.c file
353         self._writeMainFile(self.prjdir + "/main.c")
354         # Create project files for selected plugins
355         self._createProjectFiles()
356
357     def _newBertosProjectFromPreset(self):
358         # Create/write/copy the common things
359         self._newBertosProject()
360
361         # Copy all the files and dirs except cfg/hw/*.mk
362         self._writeCustomSrcFiles()
363
364         # Copy the hw files
365         self._writeAllPresetHwFiles(self.src_hwdir, self.hwdir)
366
367         # Copyt the new *_user.mk file
368         self._writeUserMkFileFromPreset()
369
370         # Create project files for selected plugins
371         self._createProjectFiles()
372
373     def _editBertosProject(self):
374         # Write the project file
375         self._writeProjectFile(os.path.join(self.maindir, "project.bertos"))
376         if not self.is_preset:
377             # Generate this files only if the project isn't a preset
378             # VERSION file
379             self._writeVersionFile(os.path.join(self.maindir, "VERSION"))
380             # Destination makefile
381             self._writeMakefile()
382             # Merge sources
383             self._mergeSources(self.bertos_maindir, self.srcdir, self.old_srcdir)
384             # Copy all the hw files
385             self._writeHwFiles(self.bertos_srcdir, self.hwdir)
386             # Destination wizard mk file
387             self._writeWizardMkFile()
388         # Set properly the autoenabled parameters
389         self._setupAutoenabledParameters()
390         # Copy all the configuration files
391         self._writeCfgFiles(self.bertos_srcdir, self.cfgdir)
392         if not self.is_preset:
393             # Create project files for selected plugins only if the project isn't a preset
394             self._createProjectFiles()
395
396     def _createProjectFiles(self):
397         # Files for selected plugins
398         relevants_files = {}
399         for plugin in self.infos["OUTPUT"]:
400             module = loadPlugin(plugin)
401             relevants_files[plugin] = module.createProject(self)
402         self.infos["RELEVANT_FILES"] = relevants_files
403
404     def _writeVersionFile(self, filename):
405         if not self.edit or self.old_srcdir:
406             version_file = open(os.path.join(const.DATA_DIR, "vtemplates/VERSION"), "r").read()
407             open(filename, "w").write(versionFileGenerator(self, version_file))
408
409     def _writeProjectFile(self, filename):
410         f = open(filename, "w")
411         f.write(projectFileGenerator(self))
412         f.close()
413
414     def _writeMakefile(self):
415         bertos_utils.makefileGenerator(self)
416
417     def _writeUserMkFile(self):
418         bertos_utils.userMkGenerator(self)
419
420     def _writeUserMkFileFromPreset(self):
421         bertos_utils.userMkGeneratorFromPreset(self)
422
423     def _writeWizardMkFile(self):
424         bertos_utils.mkGenerator(self)
425
426     def _writeMainFile(self, filename):
427         main = open(os.path.join(const.DATA_DIR, "srctemplates/main.c"), "r").read()
428         open(filename, "w").write(main)
429
430     def _writeHwFiles(self, source_dir, destination_dir):
431         for module, information in self.infos["MODULES"].items():
432             for hwfile in information["hw"]:
433                 if hwfile == "":
434                     continue
435                 string = open(source_dir + "/" + hwfile, "r").read()
436                 hwfile_path = destination_dir + "/" + os.path.basename(hwfile)
437                 if not self.edit or not os.path.exists(hwfile_path):
438                     # If not in editing mode it copies all the hw files. If in
439                     # editing mode it copies only the files that don't exist yet
440                     open(os.path.join(destination_dir,os.path.basename(hwfile)), "w").write(string)
441
442     def _writeAllPresetHwFiles(self, source_dir, destination_dir):
443         """
444         Copy all but directories contained into the preset hw directory.
445         It's needed because some presets need custom hw files not defined with
446         Wizard directives into modules...
447         """
448         source_dir = os.path.join(source_dir, "hw")
449         for f in os.listdir(source_dir):
450             abspath = os.path.join(source_dir, f)
451             if not os.path.isdir(abspath):
452                 # Exlude directories from the copy!
453                 hw_file = open(os.path.join(source_dir, f), 'r').read()
454                 open(os.path.join(destination_dir, f), 'w').write(hw_file)
455
456     def _writeCfgFiles(self, source_dir, destination_dir):
457         for configuration, information in self.infos["CONFIGURATIONS"].items():
458             string = open(source_dir + "/" + configuration, "r").read()
459             for start, parameter in information["paramlist"]:
460                 infos = information[parameter]
461                 value = infos["value"]
462                 if "unsigned" in infos["informations"] and infos["informations"]["unsigned"]:
463                     value += "U"
464                 if "long" in infos["informations"] and infos["informations"]["long"]:
465                     value += "L"
466                 string = sub(string, parameter, value)
467             f = open(os.path.join(destination_dir, os.path.basename(configuration)), "w")
468             f.write(string)
469             f.close()
470
471     def _writeCustomSrcFiles(self):
472         origin = self.infos["PRESET_SRC_PATH"]
473         # Files to be ignored (all project files, cfg dir, wizard mk file, all global ignored dirs)
474         project_related_stuff = (
475             "cfg",
476             "hw",
477             self.infos["PRESET_NAME"] + ".mk",
478             self.infos["PRESET_NAME"] + "_user.mk",
479             "project.bertos",
480             self.infos["PRESET_NAME"] + ".project",
481             self.infos["PRESET_NAME"] + ".workspace",
482         ) + const.IGNORE_LIST
483         for element in os.listdir(origin):
484             if element not in project_related_stuff:
485                 full_path = os.path.join(origin, element)
486                 if os.path.isdir(full_path):
487                     copytree.copytree(full_path, os.path.join(self.prjdir, element), ignore_list=const.IGNORE_LIST)
488                 else:
489                     shutil.copy(full_path, self.prjdir)
490
491     def _setupAutoenabledParameters(self):
492         for module, information in self.infos["MODULES"].items():
493             if "configuration" in information and information["configuration"] != "":
494                 configurations = self.infos["CONFIGURATIONS"]
495                 configuration = configurations[information["configuration"]]
496                 for start, parameter in configuration["paramlist"]:
497                     if "type" in configuration[parameter]["informations"] and configuration[parameter]["informations"]["type"] == "autoenabled":
498                         configuration[parameter]["value"] = "1" if information["enabled"] else "0"
499                 self.infos["CONFIGURATIONS"] = configurations
500
501     # Project related properties
502     @property
503     def maindir(self):
504         return self.infos.get("PROJECT_PATH", None)
505
506     @property
507     def srcdir(self):
508         if self.maindir:
509             return os.path.join(self.maindir, "bertos")
510         else:
511             return None
512
513     @property
514     def prjdir(self):
515         return self.infos.get("PROJECT_SRC_PATH", None)
516
517     @property
518     def hwdir(self):
519         if self.prjdir:
520             return os.path.join(self.prjdir, "hw")
521         else:
522             return None
523
524     @property
525     def cfgdir(self):
526         if self.prjdir:
527             return os.path.join(self.prjdir, "cfg")
528         else:
529             return None
530
531     @property
532     def old_srcdir(self):
533         return self.infos.get("OLD_BERTOS_PATH", None)
534
535     # BeRTOS sources related properties
536     @property
537     def bertos_maindir(self):
538         return self.infos.get("BERTOS_PATH", None)
539
540     @property
541     def bertos_srcdir(self):
542         if self.bertos_maindir:
543             return os.path.join(self.bertos_maindir, "bertos")
544         else:
545             return None
546
547     @property
548     def src_hwdir(self):
549         if self.from_preset:
550             return os.path.join(self.infos["PRESET_PATH"], self.infos["PRESET_HW_PATH"])
551         else:
552             return self.bertos_maindir
553
554     @property
555     def from_preset(self):
556         return self.infos.get("PROJECT_FROM_PRESET", False)
557
558     @property
559     def is_preset(self):
560         return self.infos.get("PRESET", False)
561
562     def _createDirectory(self, directory):
563         if not directory:
564             return
565         if os.path.isdir(directory):
566             shutil.rmtree(directory, True)
567         os.makedirs(directory)
568
569     def _copySources(self, origin, destination):
570         # If not in editing mode it copies all the bertos sources in the /bertos subdirectory of the project
571         shutil.rmtree(destination, True)
572         copytree.copytree(origin + "/bertos", destination, ignore_list=const.IGNORE_LIST)
573
574     def _mergeSources(self, origin, destination, old_sources_dir):
575         if old_sources_dir:
576             mergeSources(destination, origin, old_sources_dir)
577
578     def setInfo(self, key, value):
579         """
580         Store the given value with the name key.
581         """
582         self.infos[key] = value
583
584     def info(self, key, default=None):
585         """
586         Retrieve the value associated with the name key.
587         """
588         if key in self.infos:
589             return copy.deepcopy(self.infos[key])
590         return default
591
592     def getCpuInfos(self):
593         cpuInfos = []
594         for definition in self.findDefinitions(const.CPU_DEFINITION):
595             cpuInfos.append(getInfos(definition))
596         return cpuInfos
597
598     def searchFiles(self, filename):
599         file_dict = self.infos["FILE_DICT"]
600         return [(filename, dirname) for dirname in file_dict.get(filename, [])]
601
602     def findDefinitions(self, ftype):
603         # Maintain a cache for every scanned BERTOS_PATH
604         definitions_dict = self._cached_queries.get(self.infos["BERTOS_PATH"], {})
605         definitions = definitions_dict.get(ftype, None)
606         if definitions is not None:
607             return definitions
608         file_dict = self.infos["FILE_DICT"]
609         definitions = []
610         for filename in file_dict:
611             if fnmatch.fnmatch(filename, ftype):
612                 definitions += [(filename, dirname) for dirname in file_dict.get(filename, [])]
613
614         # If no cache for the current BERTOS_PATH create an empty one
615         if not definitions_dict:
616             self._cached_queries[self.infos["BERTOS_PATH"]] = {}
617         # Fill the empty cache with the result
618         self._cached_queries[self.infos["BERTOS_PATH"]][ftype] = definitions
619         return definitions
620
621     def setEnabledModules(self, enabled_modules):
622         modules = self.infos["MODULES"]
623         files = {}
624         for module, information in modules.items():
625             information["enabled"] = module in enabled_modules
626             if information["enabled"]:
627                 for dependency in information["depends"]:
628                     if not dependency in modules:
629                         files[dependency] = files.get(dependency, 0) + 1
630         self.infos["MODULES"] = modules
631         self.infos["FILES"] = files
632
633     def __repr__(self):
634         return "<BProject:instance %d>%s" %(id(self), repr(self.infos))