Clone of official tools

Committer:
theotherjimmy
Date:
Tue Sep 25 13:43:09 2018 -0500
Revision:
43:2a7da56ebd24
Parent:
40:7d3fa6b99b2b
Release 5.10.0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
The Other Jimmy 31:8ea194f6145b 1 """The generic interface for all exporters.
screamer 0:66f3b5499f7f 2 """
The Other Jimmy 31:8ea194f6145b 3 # mbed SDK
The Other Jimmy 31:8ea194f6145b 4 # Copyright (c) 2011-2016 ARM Limited
The Other Jimmy 31:8ea194f6145b 5 #
The Other Jimmy 31:8ea194f6145b 6 # Licensed under the Apache License, Version 2.0 (the "License");
The Other Jimmy 31:8ea194f6145b 7 # you may not use this file except in compliance with the License.
The Other Jimmy 31:8ea194f6145b 8 # You may obtain a copy of the License at
The Other Jimmy 31:8ea194f6145b 9 #
The Other Jimmy 31:8ea194f6145b 10 # http://www.apache.org/licenses/LICENSE-2.0
The Other Jimmy 31:8ea194f6145b 11 #
The Other Jimmy 31:8ea194f6145b 12 # Unless required by applicable law or agreed to in writing, software
The Other Jimmy 31:8ea194f6145b 13 # distributed under the License is distributed on an "AS IS" BASIS,
The Other Jimmy 31:8ea194f6145b 14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
The Other Jimmy 31:8ea194f6145b 15 # See the License for the specific language governing permissions and
The Other Jimmy 31:8ea194f6145b 16 # limitations under the License.
screamer 0:66f3b5499f7f 17
theotherjimmy 43:2a7da56ebd24 18 from __future__ import print_function, division, absolute_import
theotherjimmy 43:2a7da56ebd24 19
The Other Jimmy 36:96847d42f010 20 import sys
theotherjimmy 43:2a7da56ebd24 21 from os.path import join, abspath, dirname, exists, isfile
The Other Jimmy 36:96847d42f010 22 from os.path import basename, relpath, normpath, splitext
The Other Jimmy 36:96847d42f010 23 from os import makedirs, walk
The Other Jimmy 36:96847d42f010 24 import copy
The Other Jimmy 36:96847d42f010 25 from shutil import rmtree, copyfile
The Other Jimmy 36:96847d42f010 26 import zipfile
The Other Jimmy 36:96847d42f010 27
theotherjimmy 43:2a7da56ebd24 28 from ..resources import Resources, FileType, FileRef
theotherjimmy 43:2a7da56ebd24 29 from ..config import ALLOWED_FEATURES
theotherjimmy 43:2a7da56ebd24 30 from ..build_api import prepare_toolchain
theotherjimmy 43:2a7da56ebd24 31 from ..targets import TARGET_NAMES
theotherjimmy 43:2a7da56ebd24 32 from . import (lpcxpresso, ds5_5, iar, makefile, embitz, coide, kds, simplicity,
theotherjimmy 43:2a7da56ebd24 33 atmelstudio, mcuxpresso, sw4stm32, e2studio, zip, cmsis, uvision,
theotherjimmy 43:2a7da56ebd24 34 cdt, vscode, gnuarmeclipse, qtcreator, cmake, nb, cces, codeblocks)
screamer 0:66f3b5499f7f 35
screamer 0:66f3b5499f7f 36 EXPORTERS = {
theotherjimmy 43:2a7da56ebd24 37 u'uvision6': uvision.UvisionArmc6,
theotherjimmy 43:2a7da56ebd24 38 u'uvision5': uvision.UvisionArmc5,
theotherjimmy 43:2a7da56ebd24 39 u'make_gcc_arm': makefile.GccArm,
theotherjimmy 43:2a7da56ebd24 40 u'make_armc5': makefile.Armc5,
theotherjimmy 43:2a7da56ebd24 41 u'make_armc6': makefile.Armc6,
theotherjimmy 43:2a7da56ebd24 42 u'make_iar': makefile.IAR,
theotherjimmy 43:2a7da56ebd24 43 u'ds5_5': ds5_5.DS5_5,
theotherjimmy 43:2a7da56ebd24 44 u'iar': iar.IAR,
theotherjimmy 43:2a7da56ebd24 45 u'embitz' : embitz.EmBitz,
theotherjimmy 43:2a7da56ebd24 46 u'sw4stm32' : sw4stm32.Sw4STM32,
theotherjimmy 43:2a7da56ebd24 47 u'e2studio' : e2studio.E2Studio,
theotherjimmy 43:2a7da56ebd24 48 u'eclipse_gcc_arm' : cdt.EclipseGcc,
theotherjimmy 43:2a7da56ebd24 49 u'eclipse_iar' : cdt.EclipseIAR,
theotherjimmy 43:2a7da56ebd24 50 u'eclipse_armc5' : cdt.EclipseArmc5,
theotherjimmy 43:2a7da56ebd24 51 u'gnuarmeclipse': gnuarmeclipse.GNUARMEclipse,
theotherjimmy 43:2a7da56ebd24 52 u'mcuxpresso': mcuxpresso.MCUXpresso,
theotherjimmy 43:2a7da56ebd24 53 u'netbeans': nb.GNUARMNetbeans,
theotherjimmy 43:2a7da56ebd24 54 u'qtcreator': qtcreator.QtCreator,
theotherjimmy 43:2a7da56ebd24 55 u'vscode_gcc_arm' : vscode.VSCodeGcc,
theotherjimmy 43:2a7da56ebd24 56 u'vscode_iar' : vscode.VSCodeIAR,
theotherjimmy 43:2a7da56ebd24 57 u'vscode_armc5' : vscode.VSCodeArmc5,
theotherjimmy 43:2a7da56ebd24 58 u'cmake_gcc_arm': cmake.GccArm,
theotherjimmy 43:2a7da56ebd24 59 u'cces' : cces.CCES,
theotherjimmy 43:2a7da56ebd24 60 u'codeblocks': codeblocks.CodeBlocks
screamer 0:66f3b5499f7f 61 }
screamer 0:66f3b5499f7f 62
screamer 0:66f3b5499f7f 63 ERROR_MESSAGE_UNSUPPORTED_TOOLCHAIN = """
screamer 0:66f3b5499f7f 64 Sorry, the target %s is not currently supported on the %s toolchain.
screamer 0:66f3b5499f7f 65 Please refer to <a href='/handbook/Exporting-to-offline-toolchains' target='_blank'>Exporting to offline toolchains</a> for more information.
screamer 0:66f3b5499f7f 66 """
screamer 0:66f3b5499f7f 67
screamer 0:66f3b5499f7f 68 ERROR_MESSAGE_NOT_EXPORT_LIBS = """
screamer 0:66f3b5499f7f 69 To export this project please <a href='http://mbed.org/compiler/?import=http://mbed.org/users/mbed_official/code/mbed-export/k&mode=lib' target='_blank'>import the export version of the mbed library</a>.
screamer 0:66f3b5499f7f 70 """
screamer 0:66f3b5499f7f 71
The Other Jimmy 36:96847d42f010 72 def mcu_ide_list():
The Other Jimmy 36:96847d42f010 73 """Shows list of exportable ides
The Other Jimmy 36:96847d42f010 74
The Other Jimmy 36:96847d42f010 75 """
The Other Jimmy 36:96847d42f010 76 supported_ides = sorted(EXPORTERS.keys())
The Other Jimmy 36:96847d42f010 77 return "\n".join(supported_ides)
The Other Jimmy 36:96847d42f010 78
The Other Jimmy 36:96847d42f010 79
The Other Jimmy 31:8ea194f6145b 80 def mcu_ide_matrix(verbose_html=False):
The Other Jimmy 31:8ea194f6145b 81 """Shows target map using prettytable
screamer 0:66f3b5499f7f 82
The Other Jimmy 31:8ea194f6145b 83 Keyword argumets:
The Other Jimmy 31:8ea194f6145b 84 verbose_html - print the matrix in html format
screamer 0:66f3b5499f7f 85 """
The Other Jimmy 31:8ea194f6145b 86 supported_ides = sorted(EXPORTERS.keys())
The Other Jimmy 31:8ea194f6145b 87 # Only use it in this function so building works without extra modules
The Other Jimmy 31:8ea194f6145b 88 from prettytable import PrettyTable, ALL
screamer 0:66f3b5499f7f 89
screamer 0:66f3b5499f7f 90 # All tests status table print
The Other Jimmy 31:8ea194f6145b 91 table_printer = PrettyTable(["Platform"] + supported_ides)
screamer 0:66f3b5499f7f 92 # Align table
The Other Jimmy 31:8ea194f6145b 93 for col in supported_ides:
The Other Jimmy 31:8ea194f6145b 94 table_printer.align[col] = "c"
The Other Jimmy 31:8ea194f6145b 95 table_printer.align["Platform"] = "l"
screamer 0:66f3b5499f7f 96
screamer 0:66f3b5499f7f 97 perm_counter = 0
screamer 0:66f3b5499f7f 98 for target in sorted(TARGET_NAMES):
screamer 0:66f3b5499f7f 99 row = [target] # First column is platform name
screamer 0:66f3b5499f7f 100 for ide in supported_ides:
screamer 0:66f3b5499f7f 101 text = "-"
theotherjimmy 40:7d3fa6b99b2b 102 if EXPORTERS[ide].is_target_supported(target):
screamer 0:66f3b5499f7f 103 if verbose_html:
screamer 0:66f3b5499f7f 104 text = "&#10003;"
screamer 0:66f3b5499f7f 105 else:
screamer 0:66f3b5499f7f 106 text = "x"
screamer 0:66f3b5499f7f 107 perm_counter += 1
screamer 0:66f3b5499f7f 108 row.append(text)
The Other Jimmy 31:8ea194f6145b 109 table_printer.add_row(row)
screamer 0:66f3b5499f7f 110
The Other Jimmy 31:8ea194f6145b 111 table_printer.border = True
The Other Jimmy 31:8ea194f6145b 112 table_printer.vrules = ALL
The Other Jimmy 31:8ea194f6145b 113 table_printer.hrules = ALL
screamer 0:66f3b5499f7f 114 # creates a html page in a shorter format suitable for readme.md
The Other Jimmy 31:8ea194f6145b 115 if verbose_html:
The Other Jimmy 31:8ea194f6145b 116 result = table_printer.get_html_string()
The Other Jimmy 31:8ea194f6145b 117 else:
The Other Jimmy 31:8ea194f6145b 118 result = table_printer.get_string()
screamer 0:66f3b5499f7f 119 result += "\n"
screamer 0:66f3b5499f7f 120 result += "Total IDEs: %d\n"% (len(supported_ides))
The Other Jimmy 31:8ea194f6145b 121 if verbose_html:
The Other Jimmy 31:8ea194f6145b 122 result += "<br>"
The Other Jimmy 31:8ea194f6145b 123 result += "Total platforms: %d\n"% (len(TARGET_NAMES))
The Other Jimmy 31:8ea194f6145b 124 if verbose_html:
The Other Jimmy 31:8ea194f6145b 125 result += "<br>"
screamer 0:66f3b5499f7f 126 result += "Total permutations: %d"% (perm_counter)
The Other Jimmy 31:8ea194f6145b 127 if verbose_html:
The Other Jimmy 31:8ea194f6145b 128 result = result.replace("&amp;", "&")
screamer 0:66f3b5499f7f 129 return result
The Other Jimmy 36:96847d42f010 130
The Other Jimmy 36:96847d42f010 131
The Other Jimmy 36:96847d42f010 132 def get_exporter_toolchain(ide):
The Other Jimmy 36:96847d42f010 133 """ Return the exporter class and the toolchain string as a tuple
The Other Jimmy 36:96847d42f010 134
The Other Jimmy 36:96847d42f010 135 Positional arguments:
The Other Jimmy 36:96847d42f010 136 ide - the ide name of an exporter
The Other Jimmy 36:96847d42f010 137 """
The Other Jimmy 36:96847d42f010 138 return EXPORTERS[ide], EXPORTERS[ide].TOOLCHAIN
The Other Jimmy 36:96847d42f010 139
The Other Jimmy 36:96847d42f010 140
The Other Jimmy 36:96847d42f010 141 def generate_project_files(resources, export_path, target, name, toolchain, ide,
The Other Jimmy 36:96847d42f010 142 macros=None):
The Other Jimmy 36:96847d42f010 143 """Generate the project files for a project
The Other Jimmy 36:96847d42f010 144
The Other Jimmy 36:96847d42f010 145 Positional arguments:
The Other Jimmy 36:96847d42f010 146 resources - a Resources object containing all of the files needed to build
The Other Jimmy 36:96847d42f010 147 this project
The Other Jimmy 36:96847d42f010 148 export_path - location to place project files
The Other Jimmy 36:96847d42f010 149 name - name of the project
The Other Jimmy 36:96847d42f010 150 toolchain - a toolchain class that corresponds to the toolchain used by the
The Other Jimmy 36:96847d42f010 151 IDE or makefile
The Other Jimmy 36:96847d42f010 152 ide - IDE name to export to
The Other Jimmy 36:96847d42f010 153
The Other Jimmy 36:96847d42f010 154 Optional arguments:
The Other Jimmy 36:96847d42f010 155 macros - additional macros that should be defined within the exported
The Other Jimmy 36:96847d42f010 156 project
The Other Jimmy 36:96847d42f010 157 """
The Other Jimmy 36:96847d42f010 158 exporter_cls, _ = get_exporter_toolchain(ide)
The Other Jimmy 36:96847d42f010 159 exporter = exporter_cls(target, export_path, name, toolchain,
The Other Jimmy 36:96847d42f010 160 extra_symbols=macros, resources=resources)
The Other Jimmy 36:96847d42f010 161 exporter.generate()
The Other Jimmy 36:96847d42f010 162 files = exporter.generated_files
The Other Jimmy 36:96847d42f010 163 return files, exporter
The Other Jimmy 36:96847d42f010 164
The Other Jimmy 36:96847d42f010 165
theotherjimmy 43:2a7da56ebd24 166 def _inner_zip_export(resources, prj_files, inc_repos):
theotherjimmy 43:2a7da56ebd24 167 to_zip = sum((resources.get_file_refs(ftype) for ftype
theotherjimmy 43:2a7da56ebd24 168 in Resources.ALL_FILE_TYPES),
theotherjimmy 43:2a7da56ebd24 169 [])
theotherjimmy 43:2a7da56ebd24 170 to_zip.extend(FileRef(basename(pfile), pfile) for pfile in prj_files)
theotherjimmy 43:2a7da56ebd24 171 for dest, source in resources.get_file_refs(FileType.BLD_REF):
theotherjimmy 43:2a7da56ebd24 172 target_dir, _ = splitext(dest)
theotherjimmy 43:2a7da56ebd24 173 dest = join(target_dir, ".bld", "bldrc")
theotherjimmy 43:2a7da56ebd24 174 to_zip.append(FileRef(dest, source))
theotherjimmy 43:2a7da56ebd24 175 if inc_repos:
theotherjimmy 43:2a7da56ebd24 176 for dest, source in resources.get_file_refs(FileType.REPO_DIRS):
theotherjimmy 43:2a7da56ebd24 177 for root, _, files in walk(source):
theotherjimmy 43:2a7da56ebd24 178 for repo_file in files:
theotherjimmy 43:2a7da56ebd24 179 file_source = join(root, repo_file)
theotherjimmy 43:2a7da56ebd24 180 file_dest = join(dest, relpath(file_source, source))
theotherjimmy 43:2a7da56ebd24 181 to_zip.append(FileRef(file_dest, file_source))
theotherjimmy 43:2a7da56ebd24 182 return to_zip
theotherjimmy 43:2a7da56ebd24 183
theotherjimmy 43:2a7da56ebd24 184 def zip_export(file_name, prefix, resources, project_files, inc_repos, notify):
The Other Jimmy 36:96847d42f010 185 """Create a zip file from an exported project.
The Other Jimmy 36:96847d42f010 186
The Other Jimmy 36:96847d42f010 187 Positional Parameters:
The Other Jimmy 36:96847d42f010 188 file_name - the file name of the resulting zip file
The Other Jimmy 36:96847d42f010 189 prefix - a directory name that will prefix the entire zip file's contents
The Other Jimmy 36:96847d42f010 190 resources - a resources object with files that must be included in the zip
The Other Jimmy 36:96847d42f010 191 project_files - a list of extra files to be added to the root of the prefix
The Other Jimmy 36:96847d42f010 192 directory
The Other Jimmy 36:96847d42f010 193 """
theotherjimmy 43:2a7da56ebd24 194 to_zip_list = sorted(set(_inner_zip_export(
theotherjimmy 43:2a7da56ebd24 195 resources, project_files, inc_repos)))
theotherjimmy 43:2a7da56ebd24 196 total_files = len(to_zip_list)
theotherjimmy 43:2a7da56ebd24 197 zipped = 0
The Other Jimmy 36:96847d42f010 198 with zipfile.ZipFile(file_name, "w") as zip_file:
theotherjimmy 43:2a7da56ebd24 199 for dest, source in to_zip_list:
theotherjimmy 43:2a7da56ebd24 200 if source and isfile(source):
theotherjimmy 43:2a7da56ebd24 201 zip_file.write(source, join(prefix, dest))
theotherjimmy 43:2a7da56ebd24 202 zipped += 1
theotherjimmy 43:2a7da56ebd24 203 notify.progress("Zipping", source,
theotherjimmy 43:2a7da56ebd24 204 100 * (zipped / total_files))
theotherjimmy 43:2a7da56ebd24 205 else:
theotherjimmy 43:2a7da56ebd24 206 zipped += 1
The Other Jimmy 36:96847d42f010 207
The Other Jimmy 36:96847d42f010 208
The Other Jimmy 36:96847d42f010 209 def export_project(src_paths, export_path, target, ide, libraries_paths=None,
theotherjimmy 43:2a7da56ebd24 210 linker_script=None, notify=None, name=None, inc_dirs=None,
theotherjimmy 43:2a7da56ebd24 211 jobs=1, config=None, macros=None, zip_proj=None,
theotherjimmy 43:2a7da56ebd24 212 inc_repos=False, build_profile=None, app_config=None,
theotherjimmy 43:2a7da56ebd24 213 ignore=None):
The Other Jimmy 36:96847d42f010 214 """Generates a project file and creates a zip archive if specified
The Other Jimmy 36:96847d42f010 215
The Other Jimmy 36:96847d42f010 216 Positional Arguments:
The Other Jimmy 36:96847d42f010 217 src_paths - a list of paths from which to find source files
The Other Jimmy 36:96847d42f010 218 export_path - a path specifying the location of generated project files
The Other Jimmy 36:96847d42f010 219 target - the mbed board/mcu for which to generate the executable
The Other Jimmy 36:96847d42f010 220 ide - the ide for which to generate the project fields
The Other Jimmy 36:96847d42f010 221
The Other Jimmy 36:96847d42f010 222 Keyword Arguments:
The Other Jimmy 36:96847d42f010 223 libraries_paths - paths to additional libraries
The Other Jimmy 36:96847d42f010 224 linker_script - path to the linker script for the specified target
The Other Jimmy 36:96847d42f010 225 notify - function is passed all events, and expected to handle notification
The Other Jimmy 36:96847d42f010 226 of the user, emit the events to a log, etc.
The Other Jimmy 36:96847d42f010 227 name - project name
The Other Jimmy 36:96847d42f010 228 inc_dirs - additional include directories
The Other Jimmy 36:96847d42f010 229 jobs - number of threads
The Other Jimmy 36:96847d42f010 230 config - toolchain's config object
The Other Jimmy 36:96847d42f010 231 macros - User-defined macros
The Other Jimmy 36:96847d42f010 232 zip_proj - string name of the zip archive you wish to creat (exclude arg
The Other Jimmy 36:96847d42f010 233 if you do not wish to create an archive
theotherjimmy 43:2a7da56ebd24 234 ignore - list of paths to add to mbedignore
The Other Jimmy 36:96847d42f010 235 """
The Other Jimmy 36:96847d42f010 236
The Other Jimmy 36:96847d42f010 237 # Convert src_path to a list if needed
The Other Jimmy 36:96847d42f010 238 if isinstance(src_paths, dict):
The Other Jimmy 36:96847d42f010 239 paths = sum(src_paths.values(), [])
The Other Jimmy 36:96847d42f010 240 elif isinstance(src_paths, list):
The Other Jimmy 36:96847d42f010 241 paths = src_paths[:]
The Other Jimmy 36:96847d42f010 242 else:
The Other Jimmy 36:96847d42f010 243 paths = [src_paths]
The Other Jimmy 36:96847d42f010 244
The Other Jimmy 36:96847d42f010 245 # Extend src_paths wit libraries_paths
The Other Jimmy 36:96847d42f010 246 if libraries_paths is not None:
The Other Jimmy 36:96847d42f010 247 paths.extend(libraries_paths)
The Other Jimmy 36:96847d42f010 248
The Other Jimmy 36:96847d42f010 249 if not isinstance(src_paths, dict):
The Other Jimmy 36:96847d42f010 250 src_paths = {"": paths}
The Other Jimmy 36:96847d42f010 251
The Other Jimmy 36:96847d42f010 252 # Export Directory
The Other Jimmy 36:96847d42f010 253 if not exists(export_path):
The Other Jimmy 36:96847d42f010 254 makedirs(export_path)
The Other Jimmy 36:96847d42f010 255
The Other Jimmy 36:96847d42f010 256 _, toolchain_name = get_exporter_toolchain(ide)
The Other Jimmy 36:96847d42f010 257
The Other Jimmy 36:96847d42f010 258 # Pass all params to the unified prepare_resources()
The Other Jimmy 36:96847d42f010 259 toolchain = prepare_toolchain(
The Other Jimmy 36:96847d42f010 260 paths, "", target, toolchain_name, macros=macros, jobs=jobs,
theotherjimmy 43:2a7da56ebd24 261 notify=notify, config=config, build_profile=build_profile,
theotherjimmy 43:2a7da56ebd24 262 app_config=app_config, ignore=ignore)
theotherjimmy 43:2a7da56ebd24 263
theotherjimmy 40:7d3fa6b99b2b 264 toolchain.RESPONSE_FILES = False
The Other Jimmy 36:96847d42f010 265 if name is None:
The Other Jimmy 36:96847d42f010 266 name = basename(normpath(abspath(src_paths[0])))
The Other Jimmy 36:96847d42f010 267
theotherjimmy 43:2a7da56ebd24 268 resources = Resources(notify, collect_ignores=True)
theotherjimmy 43:2a7da56ebd24 269 resources.add_toolchain_labels(toolchain)
theotherjimmy 43:2a7da56ebd24 270 for loc, path in src_paths.items():
theotherjimmy 43:2a7da56ebd24 271 for p in path:
theotherjimmy 43:2a7da56ebd24 272 resources.add_directory(p, into_path=loc)
The Other Jimmy 36:96847d42f010 273 toolchain.build_dir = export_path
theotherjimmy 43:2a7da56ebd24 274 toolchain.config.load_resources(resources)
theotherjimmy 43:2a7da56ebd24 275 toolchain.set_config_data(toolchain.config.get_config_data())
The Other Jimmy 36:96847d42f010 276 config_header = toolchain.get_config_header()
theotherjimmy 43:2a7da56ebd24 277 resources.add_file_ref(FileType.HEADER, basename(config_header), config_header)
The Other Jimmy 36:96847d42f010 278
The Other Jimmy 36:96847d42f010 279 # Change linker script if specified
The Other Jimmy 36:96847d42f010 280 if linker_script is not None:
The Other Jimmy 36:96847d42f010 281 resources.linker_script = linker_script
The Other Jimmy 36:96847d42f010 282
The Other Jimmy 36:96847d42f010 283 files, exporter = generate_project_files(resources, export_path,
The Other Jimmy 36:96847d42f010 284 target, name, toolchain, ide,
The Other Jimmy 36:96847d42f010 285 macros=macros)
The Other Jimmy 36:96847d42f010 286 if zip_proj:
theotherjimmy 43:2a7da56ebd24 287 resources.add_features(ALLOWED_FEATURES)
The Other Jimmy 36:96847d42f010 288 if isinstance(zip_proj, basestring):
theotherjimmy 43:2a7da56ebd24 289 zip_export(join(export_path, zip_proj), name, resources,
theotherjimmy 43:2a7da56ebd24 290 files + list(exporter.static_files), inc_repos, notify)
The Other Jimmy 36:96847d42f010 291 else:
theotherjimmy 43:2a7da56ebd24 292 zip_export(zip_proj, name, resources,
theotherjimmy 43:2a7da56ebd24 293 files + list(exporter.static_files), inc_repos, notify)
The Other Jimmy 36:96847d42f010 294 else:
theotherjimmy 40:7d3fa6b99b2b 295 for static_file in exporter.static_files:
theotherjimmy 40:7d3fa6b99b2b 296 if not exists(join(export_path, basename(static_file))):
theotherjimmy 40:7d3fa6b99b2b 297 copyfile(static_file, join(export_path, basename(static_file)))
The Other Jimmy 36:96847d42f010 298
The Other Jimmy 36:96847d42f010 299 return exporter