Greg Steiert / maxim_dev

Dependents:   sensomed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers project_api.py Source File

project_api.py

00001 """ The new way of doing exports """
00002 import sys
00003 from os.path import join, abspath, dirname, exists
00004 from os.path import basename, relpath, normpath, splitext
00005 from os import makedirs, walk
00006 ROOT = abspath(join(dirname(__file__), ".."))
00007 sys.path.insert(0, ROOT)
00008 import copy
00009 from shutil import rmtree
00010 import zipfile
00011 
00012 from tools.build_api import prepare_toolchain
00013 from tools.build_api import scan_resources
00014 from tools.export import EXPORTERS
00015 from tools.toolchains import Resources
00016 
00017 
00018 def get_exporter_toolchain (ide):
00019     """ Return the exporter class and the toolchain string as a tuple
00020 
00021     Positional arguments:
00022     ide - the ide name of an exporter
00023     """
00024     return EXPORTERS[ide], EXPORTERS[ide].TOOLCHAIN
00025 
00026 
00027 def rewrite_basepath (file_name, resources, export_path, loc):
00028     """ Replace the basepath of filename with export_path
00029 
00030     Positional arguments:
00031     file_name - the absolute path to a file
00032     resources - the resources object that the file came from
00033     export_path - the final destination of the file after export
00034     """
00035     new_f = join(loc, relpath(file_name, resources.file_basepath[file_name]))
00036     resources.file_basepath[join(export_path, new_f)] = export_path
00037     return new_f
00038 
00039 
00040 def subtract_basepath (resources, export_path, loc=""):
00041     """ Rewrite all of the basepaths with the export_path
00042 
00043     Positional arguments:
00044     resources - the resource object to rewrite the basepaths of
00045     export_path - the final destination of the resources with respect to the
00046       generated project files
00047     """
00048     keys = ['s_sources', 'c_sources', 'cpp_sources', 'hex_files',
00049             'objects', 'libraries', 'inc_dirs', 'headers', 'linker_script',
00050             'lib_dirs']
00051     for key in keys:
00052         vals = getattr(resources, key)
00053         if isinstance(vals, set):
00054             vals = list(vals)
00055         if isinstance(vals, list):
00056             new_vals = []
00057             for val in vals:
00058                 new_vals.append(rewrite_basepath(val, resources, export_path,
00059                                                  loc))
00060             if isinstance(getattr(resources, key), set):
00061                 setattr(resources, key, set(new_vals))
00062             else:
00063                 setattr(resources, key, new_vals)
00064         elif vals:
00065             setattr(resources, key, rewrite_basepath(vals, resources,
00066                                                      export_path, loc))
00067 
00068 
00069 def generate_project_files (resources, export_path, target, name, toolchain, ide,
00070                            macros=None):
00071     """Generate the project files for a project
00072 
00073     Positional arguments:
00074     resources - a Resources object containing all of the files needed to build
00075       this project
00076     export_path - location to place project files
00077     name - name of the project
00078     toolchain - a toolchain class that corresponds to the toolchain used by the
00079       IDE or makefile
00080     ide - IDE name to export to
00081 
00082     Optional arguments:
00083     macros - additional macros that should be defined within the exported
00084       project
00085     """
00086     exporter_cls, _ = get_exporter_toolchain(ide)
00087     exporter = exporter_cls(target, export_path, name, toolchain,
00088                             extra_symbols=macros, resources=resources)
00089     exporter.generate()
00090     files = exporter.generated_files
00091     return files, exporter
00092 
00093 
00094 def zip_export (file_name, prefix, resources, project_files, inc_repos):
00095     """Create a zip file from an exported project.
00096 
00097     Positional Parameters:
00098     file_name - the file name of the resulting zip file
00099     prefix - a directory name that will prefix the entire zip file's contents
00100     resources - a resources object with files that must be included in the zip
00101     project_files - a list of extra files to be added to the root of the prefix
00102       directory
00103     """
00104     with zipfile.ZipFile(file_name, "w") as zip_file:
00105         for prj_file in project_files:
00106             zip_file.write(prj_file, join(prefix, basename(prj_file)))
00107         for loc, resource in resources.iteritems():
00108             for res in [resource] + resource.features.values():
00109                 to_zip = (
00110                     res.headers + res.s_sources + res.c_sources +\
00111                     res.cpp_sources + res.libraries + res.hex_files + \
00112                     [res.linker_script] + res.bin_files + res.objects + \
00113                     res.json_files + res.lib_refs + res.lib_builds)
00114                 if inc_repos:
00115                     for directory in res.repo_dirs:
00116                         for root, _, files in walk(directory):
00117                             for repo_file in files:
00118                                 source = join(root, repo_file)
00119                                 to_zip.append(source)
00120                                 res.file_basepath[source] = res.base_path
00121                     to_zip += res.repo_files
00122                 for source in to_zip:
00123                     if source:
00124                         zip_file.write(
00125                             source,
00126                             join(prefix, loc,
00127                                  relpath(source, res.file_basepath[source])))
00128                 for source in res.lib_builds:
00129                     target_dir, _ = splitext(source)
00130                     dest = join(prefix, loc,
00131                                 relpath(target_dir, res.file_basepath[source]),
00132                                 ".bld", "bldrc")
00133                     zip_file.write(source, dest)
00134 
00135 
00136 
00137 def export_project (src_paths, export_path, target, ide,
00138                    libraries_paths=None, linker_script=None, clean=False,
00139                    notify=None, verbose=False, name=None, inc_dirs=None,
00140                    jobs=1, silent=False, extra_verbose=False, config=None,
00141                    macros=None, zip_proj=None, inc_repos=False,
00142                    build_profile=None):
00143     """Generates a project file and creates a zip archive if specified
00144 
00145     Positional Arguments:
00146     src_paths - a list of paths from which to find source files
00147     export_path - a path specifying the location of generated project files
00148     target - the mbed board/mcu for which to generate the executable
00149     ide - the ide for which to generate the project fields
00150 
00151     Keyword Arguments:
00152     libraries_paths - paths to additional libraries
00153     linker_script - path to the linker script for the specified target
00154     clean - removes the export_path if it exists
00155     notify - function is passed all events, and expected to handle notification
00156       of the user, emit the events to a log, etc.
00157     verbose - assigns the notify function to toolchains print_notify_verbose
00158     name - project name
00159     inc_dirs - additional include directories
00160     jobs - number of threads
00161     silent - silent build - no output
00162     extra_verbose - assigns the notify function to toolchains
00163       print_notify_verbose
00164     config - toolchain's config object
00165     macros - User-defined macros
00166     zip_proj - string name of the zip archive you wish to creat (exclude arg
00167      if you do not wish to create an archive
00168     """
00169 
00170     # Convert src_path to a list if needed
00171     if isinstance(src_paths, dict):
00172         paths = sum(src_paths.values(), [])
00173     elif isinstance(src_paths, list):
00174         paths = src_paths[:]
00175     else:
00176         paths = [src_paths]
00177 
00178     # Extend src_paths wit libraries_paths
00179     if libraries_paths is not None:
00180         paths.extend(libraries_paths)
00181 
00182     if not isinstance(src_paths, dict):
00183         src_paths = {"": paths}
00184 
00185     # Export Directory
00186     if exists(export_path) and clean:
00187         rmtree(export_path)
00188     if not exists(export_path):
00189         makedirs(export_path)
00190 
00191     _, toolchain_name = get_exporter_toolchain(ide)
00192 
00193     # Pass all params to the unified prepare_resources()
00194     toolchain = prepare_toolchain(paths, target, toolchain_name,
00195                                   macros=macros, clean=clean, jobs=jobs,
00196                                   notify=notify, silent=silent, verbose=verbose,
00197                                   extra_verbose=extra_verbose, config=config,
00198                                   build_profile=build_profile)
00199     # The first path will give the name to the library
00200     if name is None:
00201         name = basename(normpath(abspath(src_paths[0])))
00202 
00203     # Call unified scan_resources
00204     resource_dict = {loc: scan_resources(path, toolchain, inc_dirs=inc_dirs)
00205                      for loc, path in src_paths.iteritems()}
00206     resources = Resources()
00207     toolchain.build_dir = export_path
00208     config_header = toolchain.get_config_header()
00209     resources.headers.append(config_header)
00210     resources.file_basepath[config_header] = dirname(config_header)
00211 
00212     if zip_proj:
00213         subtract_basepath(resources, export_path)
00214         for loc, res in resource_dict.iteritems():
00215             temp = copy.deepcopy(res)
00216             subtract_basepath(temp, export_path, loc)
00217             resources.add(temp)
00218     else:
00219         for _, res in resource_dict.iteritems():
00220             resources.add(res)
00221 
00222     # Change linker script if specified
00223     if linker_script is not None:
00224         resources.linker_script = linker_script
00225 
00226     files, exporter = generate_project_files(resources, export_path,
00227                                              target, name, toolchain, ide,
00228                                              macros=macros)
00229     files.append(config_header)
00230     if zip_proj:
00231         if isinstance(zip_proj, basestring):
00232             zip_export(join(export_path, zip_proj), name, resource_dict, files, inc_repos)
00233         else:
00234             zip_export(zip_proj, name, resource_dict, files, inc_repos)
00235 
00236     return exporter
00237 
00238 
00239 def print_results (successes, failures, skips=None):
00240     """ Print out the results of an export process
00241 
00242     Positional arguments:
00243     successes - The list of exports that succeeded
00244     failures - The list of exports that failed
00245 
00246     Keyword arguments:
00247     skips - The list of exports that were skipped
00248     """
00249     print
00250     if successes:
00251         print "Successful: "
00252         for success in successes:
00253             print "  * %s" % success
00254     if failures:
00255         print "Failed: "
00256         for failure in failures:
00257             print "  * %s" % failure
00258     if skips:
00259         print "Skipped: "
00260         for skip in skips:
00261             print "  * %s" % skip
00262