Brian Daniels / mbed-tools

Fork of mbed-tools by Morpheus

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers exporters.py Source File

exporters.py

00001 """Just a template for subclassing"""
00002 import uuid, shutil, os, logging, fnmatch
00003 from os import walk, remove
00004 from os.path import join, dirname, isdir, split
00005 from copy import copy
00006 from jinja2 import Template, FileSystemLoader
00007 from jinja2.environment import Environment
00008 from contextlib import closing
00009 from zipfile import ZipFile, ZIP_DEFLATED
00010 
00011 from tools.utils import mkdir
00012 from tools.toolchains import TOOLCHAIN_CLASSES
00013 from tools.targets import TARGET_MAP
00014 
00015 from project_generator.generate import Generator
00016 from project_generator.project import Project
00017 from project_generator.settings import ProjectSettings
00018 
00019 class OldLibrariesException(Exception): pass
00020 
00021 class Exporter(object):
00022     TEMPLATE_DIR = dirname(__file__)
00023     DOT_IN_RELATIVE_PATH = False
00024 
00025     def __init__(self, target, inputDir, program_name, build_url_resolver, extra_symbols=None):
00026         self.inputDir = inputDir
00027         self.target = target
00028         self.program_name = program_name
00029         self.toolchain = TOOLCHAIN_CLASSES[self.get_toolchain()](TARGET_MAP[target])
00030         self.build_url_resolver = build_url_resolver
00031         jinja_loader = FileSystemLoader(os.path.dirname(os.path.abspath(__file__)))
00032         self.jinja_environment = Environment(loader=jinja_loader)
00033         self.extra_symbols = extra_symbols
00034 
00035     def get_toolchain(self):
00036         return self.TOOLCHAIN
00037 
00038     def __scan_and_copy(self, src_path, trg_path):
00039         resources = self.toolchain.scan_resources(src_path)
00040 
00041         for r_type in ['headers', 's_sources', 'c_sources', 'cpp_sources',
00042             'objects', 'libraries', 'linker_script',
00043             'lib_builds', 'lib_refs', 'repo_files', 'hex_files', 'bin_files']:
00044             r = getattr(resources, r_type)
00045             if r:
00046                 self.toolchain.copy_files(r, trg_path, rel_path=src_path)
00047         return resources
00048 
00049     def progen_get_project_data(self):
00050         """ Get ProGen project data  """
00051         # provide default data, some tools don't require any additional
00052         # tool specific settings
00053         sources = []
00054         for r_type in ['c_sources', 'cpp_sources', 's_sources']:
00055             for file in getattr(self.resources, r_type):
00056                 sources.append(file)
00057 
00058         project_data = {
00059             'common': {
00060                 'sources': { 
00061                     'Source Files': sources + self.resources.hex_files +
00062                         self.resources.objects + self.resources.libraries,
00063                 },
00064                 'includes':  { 
00065                     'Include Files': self.resources.headers,
00066                 },
00067                 'target': [TARGET_MAP[self.target].progen['target']],
00068                 'macros': self.get_symbols(),
00069                 'export_dir': [self.inputDir],
00070                 'linker_file': [self.resources.linker_script],
00071             }
00072         }
00073         return project_data
00074 
00075     def progen_gen_file(self, tool_name, project_data):
00076         """" Generate project using ProGen Project API """
00077         settings = ProjectSettings()
00078         project = Project(self.program_name, [project_data], settings)
00079         # TODO: Fix this, the inc_dirs are not valid (our scripts copy files), therefore progen
00080         # thinks it is not dict but a file, and adds them to workspace.
00081         project.project['common']['include_paths'] = self.resources.inc_dirs
00082         project.generate(tool_name, copied=True)
00083 
00084     def __scan_all(self, path):
00085         resources = []
00086 
00087         for root, dirs, files in walk(path):
00088             for d in copy(dirs):
00089                 if d == '.' or d == '..':
00090                     dirs.remove(d)
00091 
00092             for file in files:
00093                 file_path = join(root, file)
00094                 resources.append(file_path)
00095 
00096         return resources
00097 
00098     def scan_and_copy_resources(self, prj_path, trg_path):
00099         # Copy only the file for the required target and toolchain
00100         lib_builds = []
00101         for src in ['lib', 'src']:
00102             resources = self.__scan_and_copy(join(prj_path, src), trg_path)
00103             lib_builds.extend(resources.lib_builds)
00104 
00105             # The repository files
00106             for repo_dir in resources.repo_dirs:
00107                 repo_files = self.__scan_all(repo_dir)
00108                 self.toolchain.copy_files(repo_files, trg_path, rel_path=join(prj_path, src))
00109 
00110         # The libraries builds
00111         for bld in lib_builds:
00112             build_url = open(bld).read().strip()
00113             lib_data = self.build_url_resolver(build_url)
00114             lib_path = lib_data['path'].rstrip('\\/')
00115             self.__scan_and_copy(lib_path, join(trg_path, lib_data['name']))
00116 
00117             # Create .hg dir in mbed build dir so it's ignored when versioning
00118             hgdir = join(trg_path, lib_data['name'], '.hg')
00119             mkdir(hgdir)
00120             fhandle = file(join(hgdir, 'keep.me'), 'a')
00121             fhandle.close()
00122 
00123         # Final scan of the actual exported resources
00124         self.resources = self.toolchain.scan_resources(trg_path)
00125         self.resources.relative_to(trg_path, self.DOT_IN_RELATIVE_PATH)
00126         # Check the existence of a binary build of the mbed library for the desired target
00127         # This prevents exporting the mbed libraries from source
00128         # if not self.toolchain.mbed_libs:
00129         #    raise OldLibrariesException()
00130 
00131     def gen_file(self, template_file, data, target_file):
00132         template_path = join(Exporter.TEMPLATE_DIR, template_file)
00133         template = self.jinja_environment.get_template(template_file)
00134         target_text = template.render(data)
00135 
00136         target_path = join(self.inputDir, target_file)
00137         logging.debug("Generating: %s" % target_path)
00138         open(target_path, "w").write(target_text)
00139 
00140     def get_symbols(self, add_extra_symbols=True):
00141         """ This function returns symbols which must be exported.
00142             Please add / overwrite symbols in each exporter separately
00143         """
00144         symbols = self.toolchain.get_symbols()
00145         # We have extra symbols from e.g. libraries, we want to have them also added to export
00146         if add_extra_symbols:
00147             if self.extra_symbols is not None:
00148                 symbols.extend(self.extra_symbols)
00149         return symbols
00150 
00151 def zip_working_directory_and_clean_up(tempdirectory=None, destination=None, program_name=None, clean=True):
00152     uid = str(uuid.uuid4())
00153     zipfilename = '%s.zip'%uid
00154 
00155     logging.debug("Zipping up %s to %s" % (tempdirectory,  join(destination, zipfilename)))
00156     # make zip
00157     def zipdir(basedir, archivename):
00158         assert isdir(basedir)
00159         fakeroot = program_name + '/'
00160         with closing(ZipFile(archivename, "w", ZIP_DEFLATED)) as z:
00161             for root, _, files in os.walk(basedir):
00162                 # NOTE: ignore empty directories
00163                 for fn in files:
00164                     absfn = join(root, fn)
00165                     zfn = fakeroot + '/' +  absfn[len(basedir)+len(os.sep):]
00166                     z.write(absfn, zfn)
00167 
00168     zipdir(tempdirectory, join(destination, zipfilename))
00169 
00170     if clean:
00171         shutil.rmtree(tempdirectory)
00172 
00173     return join(destination, zipfilename)