Diff: tools/test/examples/examples_lib.py
- Revision:
- 0:0e018d759a2a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/test/examples/examples_lib.py Tue Nov 08 18:27:11 2016 +0000
@@ -0,0 +1,314 @@
+""" Import and bulid a bunch of example programs
+
+ This library includes functions that are shared between the examples.py and
+ the update.py modules.
+
+ """
+import os
+from os.path import dirname, abspath, basename
+import os.path
+import sys
+import subprocess
+from shutil import rmtree
+
+ROOT = abspath(dirname(dirname(dirname(dirname(__file__)))))
+sys.path.insert(0, ROOT)
+
+from tools.build_api import get_mbed_official_release
+from tools.targets import TARGET_MAP
+from tools.export import EXPORTERS
+
+SUPPORTED_TOOLCHAINS = ["ARM", "IAR", "GCC_ARM"]
+SUPPORTED_IDES = ["iar", "uvision", "make_gcc_arm", "make_iar", "make_armc5"]
+
+def print_list(lst):
+ """Prints to screen the contents of a list
+
+ Args:
+ lst - a list of any type, to be displayed
+
+ """
+ if lst:
+ for thing in lst:
+ print("# %s" % thing)
+
+def print_summary(results, export=False):
+ """Prints to screen the results of compiling/exporting combinations of example programs,
+ targets and compile toolchains/IDEs.
+
+ Args:
+ results - results of the compilation stage. See compile_repos() and export_repos()
+ for details of the format.
+
+ """
+
+ print("#"*80)
+ print("# Examples compilation summary")
+ print("#"*80)
+ print("#")
+ print("# Passed example combinations")
+ print("#")
+ for key, val in results.iteritems():
+ print_list(val[2])
+
+ second_result = "Failed example combinations" if not export else \
+ "Failed export example combinations"
+
+ print("#")
+ print("# %s"%second_result)
+ print("#")
+ for key, val in results.iteritems():
+ print_list(val[3])
+
+ if export:
+ print("#")
+ print("# Failed build example combinations")
+ print("#")
+ for key, val in results.iteritems():
+ print_list(val[4])
+
+ print("#")
+ print("#"*80)
+
+
+def target_cross_toolchain(allowed_toolchains,
+ features=[], targets=[]):
+ """Generate pairs of target and toolchains
+
+ Args:
+ allowed_toolchains - a list of all possible toolchains
+
+ Kwargs:
+ features - the features that must be in the features array of a
+ target
+ targets - a list of available targets
+ """
+ if len(targets) == 0:
+ targets=TARGET_MAP.keys()
+
+ for target, toolchains in get_mbed_official_release("5"):
+ for toolchain in toolchains:
+ if (toolchain in allowed_toolchains and
+ target in targets and
+ all(feature in TARGET_MAP[target].features
+ for feature in features)):
+ yield target, toolchain
+
+
+def target_cross_ide(allowed_ides,
+ features=[], targets=[]):
+ """Generate pairs of target and ides
+
+ Args:
+ allowed_ides - a list of all possible IDEs
+
+ Kwargs:
+ features - the features that must be in the features array of a
+ target
+ targets - a list of available targets
+ """
+ if len(targets) == 0:
+ targets=TARGET_MAP.keys()
+
+ for target, toolchains in get_mbed_official_release("5"):
+ for ide in allowed_ides:
+ if (EXPORTERS[ide].TOOLCHAIN in toolchains and
+ target in EXPORTERS[ide].TARGETS and
+ target in targets and
+ all(feature in TARGET_MAP[target].features
+ for feature in features)):
+ yield target, ide
+
+
+def get_repo_list(example):
+ """ Returns a list of all the repos associated with the specific example in the json
+ config file.
+ If there are repos listed under the mbed section then these will be returned as a
+ list. If not then the github single repo with be returned.
+ NOTE: This does not currently deal with multiple examples underneath a github
+ sourced exampe repo.
+
+ Args:
+ example - Example for which the repo list is requested
+ repos - The list of repos contained within that example in the json file
+
+ """
+ repos = []
+ if len(example['mbed']) > 0:
+ for repo in example['mbed']:
+ repos.append(repo)
+ else:
+ repos.append(example['github'])
+ return repos
+
+def source_repos(config):
+ """ Clones each of the repos associated with the specific examples name from the
+ json config file. Note if there is already a clone of the repo then it will first
+ be removed to ensure a clean, up to date cloning.
+ Args:
+ config - the json object imported from the file.
+
+ """
+ print("\nImporting example repos....\n")
+ for example in config['examples']:
+ for repo in get_repo_list(example):
+ name = basename(repo)
+ if os.path.exists(name):
+ print("'%s' example directory already exists. Deleting..." % name)
+ rmtree(name)
+
+ subprocess.call(["mbed-cli", "import", repo])
+
+def get_num_failures(results, export=False):
+ """ Returns the number of failed compilations from the results summary
+ Args:
+ results - results summary of the compilation stage. See compile_repos() for
+ details of the format.
+ num_failures
+
+ """
+ num_failures = 0
+
+ for key, val in results.iteritems():
+ num_failures = num_failures + len(val[3])
+ if export:
+ num_failures += len(val[4])
+
+ return num_failures
+
+
+def export_repos(config, ides):
+ def print_message(message, name):
+ print(message+ " %s"%name)
+ sys.stdout.flush()
+
+ results = {}
+ print("\nExporting example repos....\n")
+ for example in config['examples']:
+ export_failures = []
+ build_failures = []
+ successes = []
+ exported = True
+ pass_status = True
+ if example['export']:
+ for repo in get_repo_list(example):
+ example_project_name = basename(repo)
+ os.chdir(example_project_name)
+ # Check that the target, IDE, and features combinations are valid and return a
+ # list of valid combinations to work through
+ for target, ide in target_cross_ide(ides,
+ example['features'],
+ example['targets']):
+ example_name = "{} {} {}".format(example_project_name, target,
+ ide)
+ def status(message):
+ print(message + " %s" % example_name)
+ sys.stdout.flush()
+
+ status("Exporting")
+ proc = subprocess.Popen(["mbed-cli", "export", "-i", ide,
+ "-m", target])
+ proc.wait()
+ if proc.returncode:
+ export_failures.append(example_name)
+ status("FAILURE exporting")
+ else:
+ status("SUCCESS exporting")
+ status("Building")
+ if EXPORTERS[ide].build(example_project_name):
+ status("FAILURE building")
+ build_failures.append(example_name)
+ else:
+ status("SUCCESS building")
+ successes.append(example_name)
+ os.chdir("..")
+
+ if len(build_failures+export_failures) > 0:
+ pass_status= False
+ else:
+ exported = False
+
+ results[example['name']] = [exported, pass_status, successes, export_failures, build_failures]
+
+ return results
+
+
+def compile_repos(config, toolchains):
+ """Compiles combinations of example programs, targets and compile chains.
+
+ The results are returned in a [key: value] dictionary format:
+ Where key = The example name from the json config file
+ value = a list containing: pass_status, successes, and failures
+
+ where pass_status = The overall pass status for the compilation of the full
+ set of example programs comprising the example suite.
+ True if all examples pass, false otherwise
+ successes = list of passing examples.
+ failures = list of failing examples.
+
+ Both successes and failures contain the example name, target and compile chain
+
+ Args:
+ config - the json object imported from the file.
+ toolchains - List of toolchains to compile for.
+ results - results of the compilation stage.
+
+ """
+ results = {}
+ print("\nCompiling example repos....\n")
+ for example in config['examples']:
+ failures = []
+ successes = []
+ compiled = True
+ pass_status = True
+ if example['compile']:
+ if len(example['toolchains']) > 0:
+ toolchains = example['toolchains']
+
+ for repo in get_repo_list(example):
+ os.chdir(basename(repo))
+
+ # Check that the target, toolchain and features combinations are valid and return a
+ # list of valid combinations to work through
+ for target, toolchain in target_cross_toolchain(toolchains,
+ example['features'], example['targets']):
+ proc = subprocess.Popen(["mbed-cli", "compile", "-t", toolchain,
+ "-m", target, "--silent"])
+ proc.wait()
+ example_summary = "{} {} {}".format(basename(repo), target, toolchain)
+ if proc.returncode:
+ failures.append(example_summary)
+ else:
+ successes.append(example_summary)
+ os.chdir("..")
+
+ # If there are any compilation failures for the example 'set' then the overall status is fail.
+ if len(failures) > 0:
+ pass_status = False
+ else:
+ compiled = False
+
+ results[example['name']] = [compiled, pass_status, successes, failures]
+
+ return results
+
+
+def update_mbedos_version(config, tag):
+ """ For each example repo identified in the config json object, update the version of
+ mbed-os to that specified by the supplied GitHub tag. This function assumes that each
+ example repo has already been cloned.
+
+ Args:
+ config - the json object imported from the file.
+ tag - GitHub tag corresponding to a version of mbed-os to upgrade to.
+
+ """
+ print("Updating mbed-os in examples to version %s\n" % tag)
+ for example in config['examples']:
+ for repo in get_repo_list(example):
+ update_dir = basename(repo) + "/mbed-os"
+ print("\nChanging dir to %s\n" % update_dir)
+ os.chdir(update_dir)
+ subprocess.call(["mbed-cli", "update", tag, "--clean"])
+ os.chdir("../..")
+