Brian Daniels / mbed-tools

Fork of mbed-tools by Morpheus

Committer:
screamer
Date:
Wed Mar 30 16:23:44 2016 +0000
Revision:
0:4a2e5f0422d6
Child:
2:5f044fef8f98
Initial revision

Who changed what in which revision?

UserRevisionLine numberNew contents of line
screamer 0:4a2e5f0422d6 1 """Just a template for subclassing"""
screamer 0:4a2e5f0422d6 2 import uuid, shutil, os, logging, fnmatch
screamer 0:4a2e5f0422d6 3 from os import walk, remove
screamer 0:4a2e5f0422d6 4 from os.path import join, dirname, isdir, split
screamer 0:4a2e5f0422d6 5 from copy import copy
screamer 0:4a2e5f0422d6 6 from jinja2 import Template, FileSystemLoader
screamer 0:4a2e5f0422d6 7 from jinja2.environment import Environment
screamer 0:4a2e5f0422d6 8 from contextlib import closing
screamer 0:4a2e5f0422d6 9 from zipfile import ZipFile, ZIP_DEFLATED
screamer 0:4a2e5f0422d6 10
screamer 0:4a2e5f0422d6 11 from workspace_tools.utils import mkdir
screamer 0:4a2e5f0422d6 12 from workspace_tools.toolchains import TOOLCHAIN_CLASSES
screamer 0:4a2e5f0422d6 13 from workspace_tools.targets import TARGET_MAP
screamer 0:4a2e5f0422d6 14
screamer 0:4a2e5f0422d6 15 from project_generator.generate import Generator
screamer 0:4a2e5f0422d6 16 from project_generator.project import Project
screamer 0:4a2e5f0422d6 17 from project_generator.settings import ProjectSettings
screamer 0:4a2e5f0422d6 18
screamer 0:4a2e5f0422d6 19 class OldLibrariesException(Exception): pass
screamer 0:4a2e5f0422d6 20
screamer 0:4a2e5f0422d6 21 class Exporter(object):
screamer 0:4a2e5f0422d6 22 TEMPLATE_DIR = dirname(__file__)
screamer 0:4a2e5f0422d6 23 DOT_IN_RELATIVE_PATH = False
screamer 0:4a2e5f0422d6 24
screamer 0:4a2e5f0422d6 25 def __init__(self, target, inputDir, program_name, build_url_resolver, extra_symbols=None):
screamer 0:4a2e5f0422d6 26 self.inputDir = inputDir
screamer 0:4a2e5f0422d6 27 self.target = target
screamer 0:4a2e5f0422d6 28 self.program_name = program_name
screamer 0:4a2e5f0422d6 29 self.toolchain = TOOLCHAIN_CLASSES[self.get_toolchain()](TARGET_MAP[target])
screamer 0:4a2e5f0422d6 30 self.build_url_resolver = build_url_resolver
screamer 0:4a2e5f0422d6 31 jinja_loader = FileSystemLoader(os.path.dirname(os.path.abspath(__file__)))
screamer 0:4a2e5f0422d6 32 self.jinja_environment = Environment(loader=jinja_loader)
screamer 0:4a2e5f0422d6 33 self.extra_symbols = extra_symbols
screamer 0:4a2e5f0422d6 34
screamer 0:4a2e5f0422d6 35 def get_toolchain(self):
screamer 0:4a2e5f0422d6 36 return self.TOOLCHAIN
screamer 0:4a2e5f0422d6 37
screamer 0:4a2e5f0422d6 38 def __scan_and_copy(self, src_path, trg_path):
screamer 0:4a2e5f0422d6 39 resources = self.toolchain.scan_resources(src_path)
screamer 0:4a2e5f0422d6 40
screamer 0:4a2e5f0422d6 41 for r_type in ['headers', 's_sources', 'c_sources', 'cpp_sources',
screamer 0:4a2e5f0422d6 42 'objects', 'libraries', 'linker_script',
screamer 0:4a2e5f0422d6 43 'lib_builds', 'lib_refs', 'repo_files', 'hex_files', 'bin_files']:
screamer 0:4a2e5f0422d6 44 r = getattr(resources, r_type)
screamer 0:4a2e5f0422d6 45 if r:
screamer 0:4a2e5f0422d6 46 self.toolchain.copy_files(r, trg_path, rel_path=src_path)
screamer 0:4a2e5f0422d6 47 return resources
screamer 0:4a2e5f0422d6 48
screamer 0:4a2e5f0422d6 49 def progen_get_project_data(self):
screamer 0:4a2e5f0422d6 50 """ Get ProGen project data """
screamer 0:4a2e5f0422d6 51 # provide default data, some tools don't require any additional
screamer 0:4a2e5f0422d6 52 # tool specific settings
screamer 0:4a2e5f0422d6 53 sources = []
screamer 0:4a2e5f0422d6 54 for r_type in ['c_sources', 'cpp_sources', 's_sources']:
screamer 0:4a2e5f0422d6 55 for file in getattr(self.resources, r_type):
screamer 0:4a2e5f0422d6 56 sources.append(file)
screamer 0:4a2e5f0422d6 57
screamer 0:4a2e5f0422d6 58 project_data = {
screamer 0:4a2e5f0422d6 59 'common': {
screamer 0:4a2e5f0422d6 60 'sources': {
screamer 0:4a2e5f0422d6 61 'Source Files': sources + self.resources.hex_files +
screamer 0:4a2e5f0422d6 62 self.resources.objects + self.resources.libraries,
screamer 0:4a2e5f0422d6 63 },
screamer 0:4a2e5f0422d6 64 'includes': {
screamer 0:4a2e5f0422d6 65 'Include Files': self.resources.headers,
screamer 0:4a2e5f0422d6 66 },
screamer 0:4a2e5f0422d6 67 'target': [TARGET_MAP[self.target].progen['target']],
screamer 0:4a2e5f0422d6 68 'macros': self.get_symbols(),
screamer 0:4a2e5f0422d6 69 'export_dir': [self.inputDir],
screamer 0:4a2e5f0422d6 70 'linker_file': [self.resources.linker_script],
screamer 0:4a2e5f0422d6 71 }
screamer 0:4a2e5f0422d6 72 }
screamer 0:4a2e5f0422d6 73 return project_data
screamer 0:4a2e5f0422d6 74
screamer 0:4a2e5f0422d6 75 def progen_gen_file(self, tool_name, project_data):
screamer 0:4a2e5f0422d6 76 """" Generate project using ProGen Project API """
screamer 0:4a2e5f0422d6 77 settings = ProjectSettings()
screamer 0:4a2e5f0422d6 78 project = Project(self.program_name, [project_data], settings)
screamer 0:4a2e5f0422d6 79 # TODO: Fix this, the inc_dirs are not valid (our scripts copy files), therefore progen
screamer 0:4a2e5f0422d6 80 # thinks it is not dict but a file, and adds them to workspace.
screamer 0:4a2e5f0422d6 81 project.project['common']['include_paths'] = self.resources.inc_dirs
screamer 0:4a2e5f0422d6 82 project.generate(tool_name, copied=True)
screamer 0:4a2e5f0422d6 83
screamer 0:4a2e5f0422d6 84 def __scan_all(self, path):
screamer 0:4a2e5f0422d6 85 resources = []
screamer 0:4a2e5f0422d6 86
screamer 0:4a2e5f0422d6 87 for root, dirs, files in walk(path):
screamer 0:4a2e5f0422d6 88 for d in copy(dirs):
screamer 0:4a2e5f0422d6 89 if d == '.' or d == '..':
screamer 0:4a2e5f0422d6 90 dirs.remove(d)
screamer 0:4a2e5f0422d6 91
screamer 0:4a2e5f0422d6 92 for file in files:
screamer 0:4a2e5f0422d6 93 file_path = join(root, file)
screamer 0:4a2e5f0422d6 94 resources.append(file_path)
screamer 0:4a2e5f0422d6 95
screamer 0:4a2e5f0422d6 96 return resources
screamer 0:4a2e5f0422d6 97
screamer 0:4a2e5f0422d6 98 def scan_and_copy_resources(self, prj_path, trg_path):
screamer 0:4a2e5f0422d6 99 # Copy only the file for the required target and toolchain
screamer 0:4a2e5f0422d6 100 lib_builds = []
screamer 0:4a2e5f0422d6 101 for src in ['lib', 'src']:
screamer 0:4a2e5f0422d6 102 resources = self.__scan_and_copy(join(prj_path, src), trg_path)
screamer 0:4a2e5f0422d6 103 lib_builds.extend(resources.lib_builds)
screamer 0:4a2e5f0422d6 104
screamer 0:4a2e5f0422d6 105 # The repository files
screamer 0:4a2e5f0422d6 106 for repo_dir in resources.repo_dirs:
screamer 0:4a2e5f0422d6 107 repo_files = self.__scan_all(repo_dir)
screamer 0:4a2e5f0422d6 108 self.toolchain.copy_files(repo_files, trg_path, rel_path=join(prj_path, src))
screamer 0:4a2e5f0422d6 109
screamer 0:4a2e5f0422d6 110 # The libraries builds
screamer 0:4a2e5f0422d6 111 for bld in lib_builds:
screamer 0:4a2e5f0422d6 112 build_url = open(bld).read().strip()
screamer 0:4a2e5f0422d6 113 lib_data = self.build_url_resolver(build_url)
screamer 0:4a2e5f0422d6 114 lib_path = lib_data['path'].rstrip('\\/')
screamer 0:4a2e5f0422d6 115 self.__scan_and_copy(lib_path, join(trg_path, lib_data['name']))
screamer 0:4a2e5f0422d6 116
screamer 0:4a2e5f0422d6 117 # Create .hg dir in mbed build dir so it's ignored when versioning
screamer 0:4a2e5f0422d6 118 hgdir = join(trg_path, lib_data['name'], '.hg')
screamer 0:4a2e5f0422d6 119 mkdir(hgdir)
screamer 0:4a2e5f0422d6 120 fhandle = file(join(hgdir, 'keep.me'), 'a')
screamer 0:4a2e5f0422d6 121 fhandle.close()
screamer 0:4a2e5f0422d6 122
screamer 0:4a2e5f0422d6 123 # Final scan of the actual exported resources
screamer 0:4a2e5f0422d6 124 self.resources = self.toolchain.scan_resources(trg_path)
screamer 0:4a2e5f0422d6 125 self.resources.relative_to(trg_path, self.DOT_IN_RELATIVE_PATH)
screamer 0:4a2e5f0422d6 126 # Check the existence of a binary build of the mbed library for the desired target
screamer 0:4a2e5f0422d6 127 # This prevents exporting the mbed libraries from source
screamer 0:4a2e5f0422d6 128 # if not self.toolchain.mbed_libs:
screamer 0:4a2e5f0422d6 129 # raise OldLibrariesException()
screamer 0:4a2e5f0422d6 130
screamer 0:4a2e5f0422d6 131 def gen_file(self, template_file, data, target_file):
screamer 0:4a2e5f0422d6 132 template_path = join(Exporter.TEMPLATE_DIR, template_file)
screamer 0:4a2e5f0422d6 133 template = self.jinja_environment.get_template(template_file)
screamer 0:4a2e5f0422d6 134 target_text = template.render(data)
screamer 0:4a2e5f0422d6 135
screamer 0:4a2e5f0422d6 136 target_path = join(self.inputDir, target_file)
screamer 0:4a2e5f0422d6 137 logging.debug("Generating: %s" % target_path)
screamer 0:4a2e5f0422d6 138 open(target_path, "w").write(target_text)
screamer 0:4a2e5f0422d6 139
screamer 0:4a2e5f0422d6 140 def get_symbols(self, add_extra_symbols=True):
screamer 0:4a2e5f0422d6 141 """ This function returns symbols which must be exported.
screamer 0:4a2e5f0422d6 142 Please add / overwrite symbols in each exporter separately
screamer 0:4a2e5f0422d6 143 """
screamer 0:4a2e5f0422d6 144 symbols = self.toolchain.get_symbols()
screamer 0:4a2e5f0422d6 145 # We have extra symbols from e.g. libraries, we want to have them also added to export
screamer 0:4a2e5f0422d6 146 if add_extra_symbols:
screamer 0:4a2e5f0422d6 147 if self.extra_symbols is not None:
screamer 0:4a2e5f0422d6 148 symbols.extend(self.extra_symbols)
screamer 0:4a2e5f0422d6 149 return symbols
screamer 0:4a2e5f0422d6 150
screamer 0:4a2e5f0422d6 151 def zip_working_directory_and_clean_up(tempdirectory=None, destination=None, program_name=None, clean=True):
screamer 0:4a2e5f0422d6 152 uid = str(uuid.uuid4())
screamer 0:4a2e5f0422d6 153 zipfilename = '%s.zip'%uid
screamer 0:4a2e5f0422d6 154
screamer 0:4a2e5f0422d6 155 logging.debug("Zipping up %s to %s" % (tempdirectory, join(destination, zipfilename)))
screamer 0:4a2e5f0422d6 156 # make zip
screamer 0:4a2e5f0422d6 157 def zipdir(basedir, archivename):
screamer 0:4a2e5f0422d6 158 assert isdir(basedir)
screamer 0:4a2e5f0422d6 159 fakeroot = program_name + '/'
screamer 0:4a2e5f0422d6 160 with closing(ZipFile(archivename, "w", ZIP_DEFLATED)) as z:
screamer 0:4a2e5f0422d6 161 for root, _, files in os.walk(basedir):
screamer 0:4a2e5f0422d6 162 # NOTE: ignore empty directories
screamer 0:4a2e5f0422d6 163 for fn in files:
screamer 0:4a2e5f0422d6 164 absfn = join(root, fn)
screamer 0:4a2e5f0422d6 165 zfn = fakeroot + '/' + absfn[len(basedir)+len(os.sep):]
screamer 0:4a2e5f0422d6 166 z.write(absfn, zfn)
screamer 0:4a2e5f0422d6 167
screamer 0:4a2e5f0422d6 168 zipdir(tempdirectory, join(destination, zipfilename))
screamer 0:4a2e5f0422d6 169
screamer 0:4a2e5f0422d6 170 if clean:
screamer 0:4a2e5f0422d6 171 shutil.rmtree(tempdirectory)
screamer 0:4a2e5f0422d6 172
screamer 0:4a2e5f0422d6 173 return join(destination, zipfilename)