Add progress dialog when loading existing projects.
[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
387         # Destination wizard mk file (it seems that this file need to be
388         # rewritten also if the project is a preset)...
389         self._writeWizardMkFile()
390
391         # Set properly the autoenabled parameters
392         self._setupAutoenabledParameters()
393         # Copy all the configuration files
394         self._writeCfgFiles(self.bertos_srcdir, self.cfgdir)
395         if not self.is_preset:
396             # Create project files for selected plugins only if the project isn't a preset
397             self._createProjectFiles()
398
399     def _createProjectFiles(self):
400         # Files for selected plugins
401         relevants_files = {}
402         for plugin in self.infos["OUTPUT"]:
403             module = loadPlugin(plugin)
404             relevants_files[plugin] = module.createProject(self)
405         self.infos["RELEVANT_FILES"] = relevants_files
406
407     def _writeVersionFile(self, filename):
408         if not self.edit or self.old_srcdir:
409             version_file = open(os.path.join(const.DATA_DIR, "vtemplates/VERSION"), "r").read()
410             open(filename, "w").write(versionFileGenerator(self, version_file))
411
412     def _writeProjectFile(self, filename):
413         f = open(filename, "w")
414         f.write(projectFileGenerator(self))
415         f.close()
416
417     def _writeMakefile(self):
418         bertos_utils.makefileGenerator(self)
419
420     def _writeUserMkFile(self):
421         bertos_utils.userMkGenerator(self)
422
423     def _writeUserMkFileFromPreset(self):
424         bertos_utils.userMkGeneratorFromPreset(self)
425
426     def _writeWizardMkFile(self):
427         bertos_utils.mkGenerator(self)
428
429     def _writeMainFile(self, filename):
430         main = open(os.path.join(const.DATA_DIR, "srctemplates/main.c"), "r").read()
431         open(filename, "w").write(main)
432
433     def _writeHwFiles(self, source_dir, destination_dir):
434         for module, information in self.infos["MODULES"].items():
435             for hwfile in information["hw"]:
436                 if hwfile == "":
437                     continue
438                 string = open(source_dir + "/" + hwfile, "r").read()
439                 hwfile_path = destination_dir + "/" + os.path.basename(hwfile)
440                 if not self.edit or not os.path.exists(hwfile_path):
441                     # If not in editing mode it copies all the hw files. If in
442                     # editing mode it copies only the files that don't exist yet
443                     open(os.path.join(destination_dir,os.path.basename(hwfile)), "w").write(string)
444
445     def _writeAllPresetHwFiles(self, source_dir, destination_dir):
446         """
447         Copy all but directories contained into the preset hw directory.
448         It's needed because some presets need custom hw files not defined with
449         Wizard directives into modules...
450         """
451         source_dir = os.path.join(source_dir, "hw")
452         for f in os.listdir(source_dir):
453             abspath = os.path.join(source_dir, f)
454             if not os.path.isdir(abspath):
455                 # Exlude directories from the copy!
456                 hw_file = open(os.path.join(source_dir, f), 'r').read()
457                 open(os.path.join(destination_dir, f), 'w').write(hw_file)
458
459     def _writeCfgFiles(self, source_dir, destination_dir):
460         for configuration, information in self.infos["CONFIGURATIONS"].items():
461             string = open(source_dir + "/" + configuration, "r").read()
462             for start, parameter in information["paramlist"]:
463                 infos = information[parameter]
464                 value = infos["value"]
465                 if "unsigned" in infos["informations"] and infos["informations"]["unsigned"]:
466                     value += "U"
467                 if "long" in infos["informations"] and infos["informations"]["long"]:
468                     value += "L"
469                 string = sub(string, parameter, value)
470             f = open(os.path.join(destination_dir, os.path.basename(configuration)), "w")
471             f.write(string)
472             f.close()
473
474     def _writeCustomSrcFiles(self):
475         origin = self.infos["PRESET_SRC_PATH"]
476         # Files to be ignored (all project files, cfg dir, wizard mk file, all global ignored dirs)
477         project_related_stuff = (
478             "cfg",
479             "hw",
480             self.infos["PRESET_NAME"] + ".mk",
481             self.infos["PRESET_NAME"] + "_user.mk",
482             "project.bertos",
483             self.infos["PRESET_NAME"] + ".project",
484             self.infos["PRESET_NAME"] + ".workspace",
485         ) + const.IGNORE_LIST
486         for element in os.listdir(origin):
487             if element not in project_related_stuff:
488                 full_path = os.path.join(origin, element)
489                 if os.path.isdir(full_path):
490                     copytree.copytree(full_path, os.path.join(self.prjdir, element), ignore_list=const.IGNORE_LIST)
491                 else:
492                     shutil.copy(full_path, self.prjdir)
493
494     def _setupAutoenabledParameters(self):
495         for module, information in self.infos["MODULES"].items():
496             if "configuration" in information and information["configuration"] != "":
497                 configurations = self.infos["CONFIGURATIONS"]
498                 configuration = configurations[information["configuration"]]
499                 for start, parameter in configuration["paramlist"]:
500                     if "type" in configuration[parameter]["informations"] and configuration[parameter]["informations"]["type"] == "autoenabled":
501                         configuration[parameter]["value"] = "1" if information["enabled"] else "0"
502                 self.infos["CONFIGURATIONS"] = configurations
503
504     # Project related properties
505     @property
506     def maindir(self):
507         return self.infos.get("PROJECT_PATH", None)
508
509     @property
510     def srcdir(self):
511         if self.maindir:
512             return os.path.join(self.maindir, "bertos")
513         else:
514             return None
515
516     @property
517     def prjdir(self):
518         return self.infos.get("PROJECT_SRC_PATH", None)
519
520     @property
521     def hwdir(self):
522         if self.prjdir:
523             return os.path.join(self.prjdir, "hw")
524         else:
525             return None
526
527     @property
528     def cfgdir(self):
529         if self.prjdir:
530             return os.path.join(self.prjdir, "cfg")
531         else:
532             return None
533
534     @property
535     def old_srcdir(self):
536         return self.infos.get("OLD_BERTOS_PATH", None)
537
538     # BeRTOS sources related properties
539     @property
540     def bertos_maindir(self):
541         return self.infos.get("BERTOS_PATH", None)
542
543     @property
544     def bertos_srcdir(self):
545         if self.bertos_maindir:
546             return os.path.join(self.bertos_maindir, "bertos")
547         else:
548             return None
549
550     @property
551     def src_hwdir(self):
552         if self.from_preset:
553             return os.path.join(self.infos["PRESET_PATH"], self.infos["PRESET_HW_PATH"])
554         else:
555             return self.bertos_maindir
556
557     @property
558     def from_preset(self):
559         return self.infos.get("PROJECT_FROM_PRESET", False)
560
561     @property
562     def is_preset(self):
563         return self.infos.get("PRESET", False)
564
565     def _createDirectory(self, directory):
566         if not directory:
567             return
568         if os.path.isdir(directory):
569             shutil.rmtree(directory, True)
570         os.makedirs(directory)
571
572     def _copySources(self, origin, destination):
573         # If not in editing mode it copies all the bertos sources in the /bertos subdirectory of the project
574         shutil.rmtree(destination, True)
575         copytree.copytree(origin + "/bertos", destination, ignore_list=const.IGNORE_LIST)
576
577     def _mergeSources(self, origin, destination, old_sources_dir):
578         if old_sources_dir:
579             mergeSources(destination, origin, old_sources_dir)
580
581     def setInfo(self, key, value):
582         """
583         Store the given value with the name key.
584         """
585         self.infos[key] = value
586
587     def info(self, key, default=None):
588         """
589         Retrieve the value associated with the name key.
590         """
591         if key in self.infos:
592             return copy.deepcopy(self.infos[key])
593         return default
594
595     def getCpuInfos(self):
596         cpuInfos = []
597         for definition in self.findDefinitions(const.CPU_DEFINITION):
598             cpuInfos.append(getInfos(definition))
599         return cpuInfos
600
601     def searchFiles(self, filename):
602         file_dict = self.infos["FILE_DICT"]
603         return [(filename, dirname) for dirname in file_dict.get(filename, [])]
604
605     def findDefinitions(self, ftype):
606         # Maintain a cache for every scanned BERTOS_PATH
607         definitions_dict = self._cached_queries.get(self.infos["BERTOS_PATH"], {})
608         definitions = definitions_dict.get(ftype, None)
609         if definitions is not None:
610             return definitions
611         file_dict = self.infos["FILE_DICT"]
612         definitions = []
613         for filename in file_dict:
614             if fnmatch.fnmatch(filename, ftype):
615                 definitions += [(filename, dirname) for dirname in file_dict.get(filename, [])]
616
617         # If no cache for the current BERTOS_PATH create an empty one
618         if not definitions_dict:
619             self._cached_queries[self.infos["BERTOS_PATH"]] = {}
620         # Fill the empty cache with the result
621         self._cached_queries[self.infos["BERTOS_PATH"]][ftype] = definitions
622         return definitions
623
624     def setEnabledModules(self, enabled_modules):
625         modules = self.infos["MODULES"]
626         files = {}
627         for module, information in modules.items():
628             information["enabled"] = module in enabled_modules
629             if information["enabled"]:
630                 for dependency in information["depends"]:
631                     if not dependency in modules:
632                         files[dependency] = files.get(dependency, 0) + 1
633         self.infos["MODULES"] = modules
634         self.infos["FILES"] = files
635
636     def __repr__(self):
637         return "<BProject:instance %d>%s" %(id(self), repr(self.infos))