Development mbed library for MAX32630FTHR
Dependents: blinky_max32630fthr
Diff: tools/test/examples/update.py
- Revision:
- 0:5c4d7b2438d3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/test/examples/update.py Fri Nov 11 20:59:50 2016 +0000 @@ -0,0 +1,295 @@ +#!/usr/bin/env python + +import os +from os.path import dirname, abspath, basename +import sys +import argparse +import json +import subprocess +import shutil +import stat + +ROOT = abspath(dirname(dirname(dirname(dirname(__file__))))) +sys.path.insert(0, ROOT) + +import examples_lib as lib +from examples_lib import SUPPORTED_TOOLCHAINS + +def run_cmd(command, print_warning_on_fail=True): + """ Takes the command specified and runs it in a sub-process, obtaining the return code. + + Args: + command - command to run, provided as a list of individual fields which are combined into a + single command before passing to the sub-process call. + return_code - result of the command. + + """ + print('[Exec] %s' % ' '.join(command)) + return_code = subprocess.call(command) + + if return_code: + print("The command '%s' failed with return code: %s" % (' '.join(command), return_code)) + print("Ignoring and moving on to the next example") + + return return_code + + +def rmtree_readonly(directory): + """ Deletes a readonly directory tree. + + Args: + directory - tree to delete + """ + def remove_readonly(func, path, _): + os.chmod(path, stat.S_IWRITE) + func(path) + + shutil.rmtree(directory, onerror=remove_readonly) + +def find_all_examples(path): + """ Searches the path specified for sub-example folders, ie those containing an + mbed-os.lib file. If found adds the path to the sub-example to a list which is + then returned. + + Args: + path - path to search. + examples - (returned) list of paths to example directories. + + """ + examples = [] + for root, dirs, files in os.walk(path): + if 'mbed-os.lib' in files: + examples += [root] + + return examples + +def upgrade_single_example(example, tag, directory): + """ Updates the mbed-os.lib file in the example specified to correspond to the + version specified by the GitHub tag supplied. Also deals with + multiple sub-examples in the GitHub repo, updating them in the same way. + + Args: + example - json example object containing the GitHub repo to update. + tag - GitHub tag corresponding to a version of mbed-os to upgrade to. + directory - directory path for the example. + returns - True if the upgrade was successful, False otherwise. + + """ + print("Upgrading single example at path '%s'" % directory) + cwd = os.getcwd() + os.chdir(directory) + + return_code = None + + # Change directories to the mbed-os library + if not os.path.exists('mbed-os'): + print("'mbed-os' directory not found in the root of '%s'" % directory) + print("Ignoring and moving on to the next example") + os.chdir(cwd) + return False + + os.chdir('mbed-os') + + # Setup and run the update command + update_cmd = ['mbed', 'update', tag] + return_code = run_cmd(update_cmd) + + if return_code: + os.chdir(cwd) + return False + + os.chdir('../') + + # Setup and run the add command + add_cmd = ['git', 'add', 'mbed-os.lib'] + return_code = run_cmd(add_cmd) + + os.chdir(cwd) + return not return_code + +def upgrade_example(example, tag): + """ Clones the example specified from GitHub and updates the associated mbed-os.lib file + to correspond to the version specified by the GitHub tag supplied. Also deals with + multiple sub-examples in the GitHub repo, updating them in the same way. + + Args: + example - json example object containing the GitHub repo to update. + tag - GitHub tag corresponding to a version of mbed-os to upgrade to. + + """ + print("Updating example '%s'" % example['name']) + cwd = os.getcwd() + + # Setup and run the import command + clone_cmd = ['git', 'clone', example['github']] + return_code = run_cmd(clone_cmd) + + if return_code: + return False + + # Find all examples + example_directories = find_all_examples(example['name']) + + os.chdir(example['name']) + + # Setup and run the update command + import_cmd = ['mbed', 'update'] + return_code = run_cmd(import_cmd) + if return_code: + os.chdir(cwd) + return False + + for example_directory in example_directories: + if not upgrade_single_example(example, tag, os.path.relpath(example_directory, example['name'])): + os.chdir(cwd) + return False + + # Setup the default commit message + commit_message = 'Updating mbed-os to {{' + tag +'}}' + + # Setup and run the commit command + commit_cmd = ['git', 'commit', '-m', commit_message] + return_code = run_cmd(commit_cmd) + if return_code: + if return_code == 1: + print("[WARNING] 'git commit' exited with a return code of 1. " + \ + "This usually inidicates that no update was made. Still " + \ + "attempting to create a tag.") + else: + os.chdir(cwd) + return False + + # Setup and run the tag command + tag_cmd = ['git', 'tag', '-a', tag, '-m', tag] + return_code = run_cmd(tag_cmd) + if return_code: + os.chdir(cwd) + return False + + # Setup and run the push command + push_cmd = ['git', 'push', 'origin', 'master'] + return_code = run_cmd(push_cmd) + + if return_code: + os.chdir(cwd) + return False + + push_cmd = ['git', 'push', 'origin', tag] + return_code = run_cmd(push_cmd) + + os.chdir(cwd) + return not return_code + +def create_work_directory(path): + """ Create a new directory specified in 'path', overwrite if the directory already + exists. + + Args: + path - directory path to be created. + + """ + if os.path.exists(path): + print("'%s' directory already exists. Deleting..." % path) + rmtree_readonly(path) + + os.makedirs(path) + +def test_compile(config, tag): + """ For each example repo identified in the config json object, clone, update mbed-os to + the specified tag and then compile for all supported toolchains. + + Args: + config - the json object imported from the file. + tag - GitHub tag corresponding to a version of mbed-os to upgrade to. + results - summary of compilation results. + + """ + # Create work directories + create_work_directory('test_compile') + + # Loop through the examples + results = {} + os.chdir('test_compile') + + lib.source_repos(config) + lib.update_mbedos_version(config, tag) + results = lib.compile_repos(config, SUPPORTED_TOOLCHAINS) + os.chdir("..") + + return results + + +def main(arguments): + + parser = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('tag', help="mbed-os tag to which all examples will be updated") + parser.add_argument('-c', '--config_file', help="Path to the configuration file (default is 'examples.json')", default='examples.json') + + args = parser.parse_args(arguments) + + cfg = os.path.join(os.path.dirname(__file__), args.config_file) + + # Load the config file + config = json.load(open(os.path.join(os.path.dirname(__file__), + args.config_file))) + + if not config: + print("Failed to load config file '%s'" % args.config_file) + sys.exit(1) + + # Create work directories + create_work_directory('examples') + + # Loop through the examples + failures = [] + successes = [] + not_compiled = [] + results = {} + os.chdir('examples') + + results = test_compile(config, args.tag) + lib.print_compilation_summary(results) + + for example in config['examples']: + # Determine if this example should be updated + + # Attempt to update if: + # group of examples passed compilation and + # auto update is set to True + # Note: results fields are [compiled flag, pass flag, successes list, failures list] + if not results[example['name']][0]: + # Example was not compiled + not_compiled += [example['name']] + else: + if results[example['name']][1] and example['auto-update']: + if upgrade_example(example, args.tag): + successes += [example['name']] + else: + failures += [example['name']] + else: + failures += [example['name']] + + os.chdir('../') + + # Finish the script and report the results + print(os.linesep + os.linesep +'Finished updating examples!' + os.linesep) + + if successes: + print('The following examples updated successfully:') + for success in successes: + print(' - %s' % success) + + if failures: + print('\nThe following examples were not updated:') + for fail in failures: + print(' - %s' % fail) + + if not_compiled: + print('The following examples were skipped:') + for example in not_compiled: + print(' - %s' % example) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) \ No newline at end of file