Greg Steiert / pegasus_dev

Dependents:   blinky_max32630fthr

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers update.py Source File

update.py

00001 #!/usr/bin/env python
00002 
00003 import os
00004 from os.path import dirname, abspath, basename
00005 import sys
00006 import argparse
00007 import json
00008 import subprocess
00009 import shutil
00010 import stat
00011 
00012 ROOT = abspath(dirname(dirname(dirname(dirname(__file__)))))
00013 sys.path.insert(0, ROOT)
00014 
00015 import examples_lib as lib
00016 from examples_lib import SUPPORTED_TOOLCHAINS
00017 
00018 def run_cmd(command, print_warning_on_fail=True):
00019     """ Takes the command specified and runs it in a sub-process, obtaining the return code.
00020         
00021     Args:
00022     command - command to run, provided as a list of individual fields which are combined into a 
00023               single command before passing to the sub-process call.
00024     return_code - result of the command.
00025 
00026     """
00027     print('[Exec] %s' % ' '.join(command))
00028     return_code = subprocess.call(command)
00029     
00030     if return_code:
00031         print("The command '%s' failed with return code: %s" % (' '.join(command), return_code))
00032         print("Ignoring and moving on to the next example")
00033     
00034     return return_code
00035     
00036 
00037 def rmtree_readonly(directory):
00038     """ Deletes a readonly directory tree.
00039         
00040     Args:
00041     directory - tree to delete
00042     """
00043     def remove_readonly(func, path, _):
00044         os.chmod(path, stat.S_IWRITE)
00045         func(path)
00046 
00047     shutil.rmtree(directory, onerror=remove_readonly)
00048 
00049 def find_all_examples(path):
00050     """ Searches the path specified for sub-example folders, ie those containing an
00051         mbed-os.lib file. If found adds the path to the sub-example to a list which is 
00052         then returned.
00053         
00054     Args:
00055     path - path to search.
00056     examples - (returned) list of paths to example directories.
00057 
00058     """
00059     examples = []
00060     for root, dirs, files in os.walk(path):
00061         if 'mbed-os.lib' in files:
00062             examples += [root]
00063     
00064     return examples
00065 
00066 def upgrade_single_example(example, tag, directory):
00067     """ Updates the mbed-os.lib file in the example specified to correspond to the 
00068         version specified by the GitHub tag supplied. Also deals with 
00069         multiple sub-examples in the GitHub repo, updating them in the same way.
00070         
00071     Args:
00072     example - json example object containing the GitHub repo to update.
00073     tag - GitHub tag corresponding to a version of mbed-os to upgrade to.
00074     directory - directory path for the example.
00075     returns - True if the upgrade was successful, False otherwise.
00076     
00077     """
00078     print("Upgrading single example at path '%s'" % directory)
00079     cwd = os.getcwd()
00080     os.chdir(directory)
00081     
00082     return_code = None
00083     
00084     # Change directories to the mbed-os library
00085     if not os.path.exists('mbed-os'):
00086         print("'mbed-os' directory not found in the root of '%s'" % directory)
00087         print("Ignoring and moving on to the next example")
00088         os.chdir(cwd)
00089         return False
00090     
00091     os.chdir('mbed-os')
00092     
00093     # Setup and run the update command
00094     update_cmd = ['mbed', 'update', tag]
00095     return_code = run_cmd(update_cmd)
00096     
00097     if return_code:
00098         os.chdir(cwd)
00099         return False
00100     
00101     os.chdir('../')
00102     
00103     # Setup and run the add command
00104     add_cmd = ['git', 'add', 'mbed-os.lib']
00105     return_code = run_cmd(add_cmd)
00106     
00107     os.chdir(cwd)
00108     return not return_code
00109 
00110 def upgrade_example(example, tag):
00111     """ Clones the example specified from GitHub and updates the associated mbed-os.lib file
00112         to correspond to the version specified by the GitHub tag supplied. Also deals with 
00113         multiple sub-examples in the GitHub repo, updating them in the same way.
00114         
00115     Args:
00116     example - json example object containing the GitHub repo to update.
00117     tag - GitHub tag corresponding to a version of mbed-os to upgrade to.
00118     
00119     """
00120     print("Updating example '%s'" % example['name'])
00121     cwd = os.getcwd()
00122     
00123     # Setup and run the import command
00124     clone_cmd = ['git', 'clone', example['github']]
00125     return_code = run_cmd(clone_cmd)
00126     
00127     if return_code:
00128         return False
00129     
00130     # Find all examples
00131     example_directories = find_all_examples(example['name'])
00132     
00133     os.chdir(example['name'])
00134     
00135     # Setup and run the update command
00136     import_cmd = ['mbed', 'update']
00137     return_code = run_cmd(import_cmd)
00138     if return_code:
00139         os.chdir(cwd)
00140         return False
00141     
00142     for example_directory in example_directories:
00143         if not upgrade_single_example(example, tag, os.path.relpath(example_directory, example['name'])):
00144             os.chdir(cwd)
00145             return False
00146         
00147     # Setup the default commit message
00148     commit_message = 'Updating mbed-os to {{' + tag +'}}'
00149             
00150     # Setup and run the commit command
00151     commit_cmd = ['git', 'commit', '-m', commit_message]
00152     return_code = run_cmd(commit_cmd)
00153     if return_code:
00154         if return_code == 1:
00155             print("[WARNING] 'git commit' exited with a return code of 1. " + \
00156             "This usually inidicates that no update was made. Still " + \
00157             "attempting to create a tag.")
00158         else:
00159             os.chdir(cwd)
00160             return False
00161     
00162     # Setup and run the tag command
00163     tag_cmd = ['git', 'tag', '-a', tag, '-m', tag]
00164     return_code = run_cmd(tag_cmd)
00165     if return_code:
00166         os.chdir(cwd)
00167         return False
00168     
00169     # Setup and run the push command
00170     push_cmd = ['git', 'push', 'origin', 'master']
00171     return_code = run_cmd(push_cmd)
00172     
00173     if return_code:
00174         os.chdir(cwd)
00175         return False
00176         
00177     push_cmd = ['git', 'push', 'origin', tag]
00178     return_code = run_cmd(push_cmd)
00179     
00180     os.chdir(cwd)
00181     return not return_code
00182 
00183 def create_work_directory(path):
00184     """ Create a new directory specified in 'path', overwrite if the directory already 
00185         exists.
00186         
00187     Args:
00188     path - directory path to be created. 
00189     
00190     """
00191     if os.path.exists(path):
00192         print("'%s' directory already exists. Deleting..." % path)
00193         rmtree_readonly(path)
00194     
00195     os.makedirs(path)
00196 
00197 def test_compile(config, tag):
00198     """ For each example repo identified in the config json object, clone, update mbed-os to
00199         the specified tag and then compile for all supported toolchains.
00200         
00201     Args:
00202     config - the json object imported from the file. 
00203     tag - GitHub tag corresponding to a version of mbed-os to upgrade to.
00204     results - summary of compilation results. 
00205     
00206     """
00207     # Create work directories
00208     create_work_directory('test_compile')
00209     
00210     # Loop through the examples
00211     results = {}
00212     os.chdir('test_compile')
00213 
00214     lib.source_repos(config)    
00215     lib.update_mbedos_version(config, tag)
00216     results = lib.compile_repos(config, SUPPORTED_TOOLCHAINS)
00217     os.chdir("..")
00218 
00219     return results
00220     
00221 
00222 def main(arguments):
00223 
00224     parser = argparse.ArgumentParser(description=__doc__,
00225                                      formatter_class=argparse.RawDescriptionHelpFormatter)
00226     parser.add_argument('tag', help="mbed-os tag to which all examples will be updated")
00227     parser.add_argument('-c', '--config_file', help="Path to the configuration file (default is 'examples.json')", default='examples.json')
00228     
00229     args = parser.parse_args(arguments)
00230 
00231     cfg = os.path.join(os.path.dirname(__file__), args.config_file)
00232     
00233     # Load the config file
00234     config = json.load(open(os.path.join(os.path.dirname(__file__),
00235                              args.config_file)))
00236     
00237     if not config:
00238         print("Failed to load config file '%s'" % args.config_file)
00239         sys.exit(1)
00240     
00241     # Create work directories
00242     create_work_directory('examples')
00243     
00244     # Loop through the examples
00245     failures = []
00246     successes = []
00247     not_compiled = []
00248     results = {}
00249     os.chdir('examples')
00250 
00251     results = test_compile(config, args.tag)
00252     lib.print_compilation_summary(results)
00253     
00254     for example in config['examples']:
00255         # Determine if this example should be updated
00256 
00257         # Attempt to update if:
00258         #   group of examples passed compilation and
00259         #   auto update is set to True
00260         # Note: results fields are [compiled flag, pass flag, successes list, failures list]
00261         if not results[example['name']][0]:
00262             # Example was not compiled
00263             not_compiled += [example['name']]
00264         else:
00265             if results[example['name']][1] and example['auto-update']: 
00266                 if upgrade_example(example, args.tag):
00267                     successes += [example['name']]
00268                 else:
00269                     failures += [example['name']]
00270             else:    
00271                 failures += [example['name']]
00272     
00273     os.chdir('../')
00274     
00275     # Finish the script and report the results
00276     print(os.linesep + os.linesep +'Finished updating examples!' + os.linesep)
00277     
00278     if successes:
00279         print('The following examples updated successfully:')
00280         for success in successes:
00281             print('    - %s' % success)
00282     
00283     if failures:
00284         print('\nThe following examples were not updated:')
00285         for fail in failures:
00286             print('    - %s' % fail)
00287 
00288     if not_compiled:
00289         print('The following examples were skipped:')
00290         for example in not_compiled:
00291             print('    - %s' % example)
00292 
00293 
00294 if __name__ == '__main__':
00295     sys.exit(main(sys.argv[1:]))