Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
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 import re 00012 from github import Github, GithubException 00013 00014 ROOT = abspath(dirname(dirname(dirname(dirname(__file__))))) 00015 sys.path.insert(0, ROOT) 00016 00017 import examples_lib as lib 00018 from examples_lib import SUPPORTED_TOOLCHAINS 00019 00020 def run_cmd(command, print_warning_on_fail=True): 00021 """ Takes the command specified and runs it in a sub-process, obtaining the return code. 00022 00023 Args: 00024 command - command to run, provided as a list of individual fields which are combined into a 00025 single command before passing to the sub-process call. 00026 return_code - result of the command. 00027 00028 """ 00029 print('[Exec] %s' % ' '.join(command)) 00030 return_code = subprocess.call(command) 00031 00032 if return_code: 00033 print("The command '%s' failed with return code: %s" % (' '.join(command), return_code)) 00034 print("Ignoring and moving on to the next example") 00035 00036 return return_code 00037 00038 def run_cmd_with_output(command, print_warning_on_fail=True): 00039 """ Takes the command specified and runs it in a sub-process, obtaining the return code 00040 and the returned output. 00041 00042 Args: 00043 command - command to run, provided as a list of individual fields which are combined into a 00044 single command before passing to the sub-process call. 00045 return_code - result of the command. 00046 output - the output of the command 00047 00048 """ 00049 print('[Exec] %s' % ' '.join(command)) 00050 returncode = 0 00051 output = None 00052 try: 00053 output = subprocess.check_output(command) 00054 except subprocess.CalledProcessError as e: 00055 print("The command '%s' failed with return code: %s" % (' '.join(command), e.returncode)) 00056 returncode = e.returncode 00057 return returncode, output 00058 00059 def rmtree_readonly(directory): 00060 """ Deletes a readonly directory tree. 00061 00062 Args: 00063 directory - tree to delete 00064 """ 00065 def remove_readonly(func, path, _): 00066 os.chmod(path, stat.S_IWRITE) 00067 func(path) 00068 00069 shutil.rmtree(directory, onerror=remove_readonly) 00070 00071 def find_all_examples(path): 00072 """ Searches the path specified for sub-example folders, ie those containing an 00073 mbed-os.lib file. If found adds the path to the sub-example to a list which is 00074 then returned. 00075 00076 Args: 00077 path - path to search. 00078 examples - (returned) list of paths to example directories. 00079 00080 """ 00081 examples = [] 00082 for root, dirs, files in os.walk(path): 00083 if 'mbed-os.lib' in files: 00084 examples += [root] 00085 00086 return examples 00087 00088 def upgrade_single_example(example, tag, directory, ref): 00089 """ Updates the mbed-os.lib file in the example specified to correspond to the 00090 version specified by the GitHub tag supplied. Also deals with 00091 multiple sub-examples in the GitHub repo, updating them in the same way. 00092 00093 Args: 00094 example - json example object containing the GitHub repo to update. 00095 tag - GitHub tag corresponding to a version of mbed-os to upgrade to. 00096 directory - directory path for the example. 00097 ref - SHA corresponding to the supplied tag 00098 returns - True if the upgrade was successful, False otherwise. 00099 00100 """ 00101 cwd = os.getcwd() 00102 os.chdir(directory) 00103 00104 return_code = False 00105 00106 if os.path.isfile("mbed-os.lib"): 00107 # Rename command will fail on some OS's if the target file already exist, 00108 # so ensure if it does, it is deleted first. 00109 if os.path.isfile("mbed-os.lib_bak"): 00110 os.remove("mbed-os.lib_bak") 00111 00112 os.rename("mbed-os.lib", "mbed-os.lib_bak") 00113 else: 00114 print("!! Error trying to backup mbed-os.lib prior to updating.") 00115 return False 00116 00117 # mbed-os.lib file contains one line with the following format 00118 # e.g. https://github.com/ARMmbed/mbed-os/#0789928ee7f2db08a419fa4a032fffd9bd477aa7 00119 lib_re = re.compile('https://github.com/ARMmbed/mbed-os/#[A-Za-z0-9]+') 00120 updated = False 00121 00122 # Scan through mbed-os.lib line by line 00123 with open('mbed-os.lib_bak', 'r') as ip, open('mbed-os.lib', 'w') as op: 00124 for line in ip: 00125 00126 opline = line 00127 00128 regexp = lib_re.match(line) 00129 if regexp: 00130 opline = 'https://github.com/ARMmbed/mbed-os/#' + ref 00131 updated = True 00132 00133 op.write(opline) 00134 00135 if updated: 00136 # Setup and run the git add command 00137 cmd = ['git', 'add', 'mbed-os.lib'] 00138 return_code = run_cmd(cmd) 00139 00140 os.chdir(cwd) 00141 return not return_code 00142 00143 def prepare_fork(arm_example): 00144 """ Synchronises a cloned fork to ensure it is up to date with the original. 00145 00146 Args: 00147 arm_example - Full GitHub repo path for original example 00148 ret - True if the fork was synchronised successfully, False otherwise 00149 00150 """ 00151 00152 print "In " + os.getcwd() 00153 00154 for cmd in [['git', 'remote', 'add', 'armmbed', arm_example], 00155 ['git', 'fetch', 'armmbed'], 00156 ['git', 'reset', '--hard', 'armmbed/master'], 00157 ['git', 'push', '-f', 'origin']]: 00158 if run_cmd(cmd): 00159 print("preparation of the fork failed!") 00160 return False 00161 return True 00162 00163 00164 def upgrade_example(github, example, tag, user, ref): 00165 """ Clone a fork of the example specified. 00166 Ensures the fork is up to date with the original and then and updates the associated 00167 mbed-os.lib file on that fork to correspond to the version specified by the GitHub tag supplied. 00168 Also deals with multiple sub-examples in the GitHub repo, updating them in the same way. 00169 The updates are pushed to the forked repo. 00170 Finally a PR is raised against the original example repo for the changes. 00171 00172 Args: 00173 github - GitHub instance to allow internal git commands to be run 00174 example - json example object containing the GitHub repo to update. 00175 tag - GitHub tag corresponding to a version of mbed-os to upgrade to. 00176 user - GitHub user name 00177 ref - SHA corresponding to the tag 00178 00179 """ 00180 ret = False 00181 print("\nUpdating example '%s'" % example['name']) 00182 cwd = os.getcwd() 00183 00184 full_repo_name = 'ARMmbed/'+ example['name'] 00185 fork = "https://github.com/" + user + '/' + example['name'] 00186 00187 # Check access to mbed-os repo 00188 try: 00189 repo = github.get_repo(full_repo_name, False) 00190 00191 except: 00192 print("\t\t!! Repo does not exist - skipping\n") 00193 return False 00194 00195 00196 # Clone the forked example repo 00197 clone_cmd = ['git', 'clone', fork] 00198 return_code = run_cmd(clone_cmd) 00199 00200 if not return_code: 00201 00202 # Find all examples 00203 example_directories = find_all_examples(example['name']) 00204 00205 os.chdir(example['name']) 00206 00207 # checkout and synchronise the release-candidate branch 00208 prepare_fork(example['github']) 00209 00210 for example_directory in example_directories: 00211 if not upgrade_single_example(example, tag, os.path.relpath(example_directory, example['name']), ref): 00212 os.chdir(cwd) 00213 return False 00214 00215 # Setup the default commit message 00216 commit_message = 'Updating mbed-os to ' + tag 00217 00218 # Setup and run the commit command 00219 commit_cmd = ['git', 'commit', '-m', commit_message] 00220 return_code = run_cmd(commit_cmd) 00221 if not return_code: 00222 00223 # Setup and run the push command 00224 push_cmd = ['git', 'push', 'origin'] 00225 return_code = run_cmd(push_cmd) 00226 00227 if not return_code: 00228 body = "Please test/merge this PR and then tag Master with " + tag 00229 # Raise a PR from release-candidate to master 00230 user_fork = user + ':master' 00231 try: 00232 pr = repo.create_pull(title='Updating mbed-os to ' + tag, head=user_fork, base='master', body=body) 00233 ret = True 00234 except GithubException as e: 00235 # Default to False 00236 print("Creation of Pull Request from release-candidate to master failed with the following error!") 00237 print e 00238 else: 00239 print("!!! Git push command failed.") 00240 else: 00241 print("!!! Git commit command failed.") 00242 else: 00243 print("!!! Could not clone user fork %s\n" % fork) 00244 00245 00246 os.chdir(cwd) 00247 return ret 00248 00249 def create_work_directory(path): 00250 """ Create a new directory specified in 'path', overwrite if the directory already 00251 exists. 00252 00253 Args: 00254 path - directory path to be created. 00255 00256 """ 00257 if os.path.exists(path): 00258 print("'%s' directory already exists. Deleting..." % path) 00259 rmtree_readonly(path) 00260 00261 os.makedirs(path) 00262 00263 def test_compile(config, tag): 00264 """ For each example repo identified in the config json object, clone, update mbed-os to 00265 the specified tag and then compile for all supported toolchains. 00266 00267 Args: 00268 config - the json object imported from the file. 00269 tag - GitHub tag corresponding to a version of mbed-os to upgrade to. 00270 results - summary of compilation results. 00271 00272 """ 00273 # Create work directories 00274 create_work_directory('test_compile') 00275 00276 # Loop through the examples 00277 results = {} 00278 os.chdir('test_compile') 00279 00280 lib.source_repos(config) 00281 lib.update_mbedos_version(config, tag) 00282 results = lib.compile_repos(config, SUPPORTED_TOOLCHAINS) 00283 os.chdir("..") 00284 00285 return results 00286 00287 00288 def main(arguments): 00289 """ Will update any mbed-os.lib files found in the example list specified by the config file. 00290 If no config file is specified the default 'examples.json' is used. 00291 The update is done by cloning a fork of each example (the fork must be present in the 00292 github account specified by the github user parameter). The fork is searched for any 00293 mbed-os.lib files and each one found is updated with the SHA corresponding to the supplied 00294 github tag. A pull request is then made from the fork to the original example repo. 00295 00296 Args: 00297 tag - tag to update the mbed-os.lib to. E.g. mbed-os-5.3.1 00298 github_token - Pre-authorised token to allow github access 00299 github_user - github username whose account contains the example forks 00300 config_file - optional parameter to specify a list of examples 00301 00302 """ 00303 00304 parser = argparse.ArgumentParser(description=__doc__, 00305 formatter_class=argparse.RawDescriptionHelpFormatter) 00306 parser.add_argument('tag', help="mbed-os tag to which all examples will be updated") 00307 parser.add_argument('-c', '--config_file', help="Path to the configuration file (default is 'examples.json')", default='examples.json') 00308 parser.add_argument('-T', '--github_token', help="GitHub token for secure access") 00309 parser.add_argument('-U', '--github_user', help="GitHub user for forked repos") 00310 00311 args = parser.parse_args(arguments) 00312 00313 cfg = os.path.join(os.path.dirname(__file__), args.config_file) 00314 00315 # Load the config file 00316 config = json.load(open(os.path.join(os.path.dirname(__file__), 00317 args.config_file))) 00318 00319 if not config: 00320 print("Failed to load config file '%s'" % args.config_file) 00321 sys.exit(1) 00322 00323 # Create working directory 00324 create_work_directory('examples') 00325 00326 github = Github(args.github_token) 00327 00328 # Get the github sha corresponding to the specified mbed-os tag 00329 cmd = ['git', 'rev-list', '-1', args.tag] 00330 return_code, ref = run_cmd_with_output(cmd) 00331 00332 if return_code: 00333 print("Could not obtain SHA for tag: %s\n" % args.tag) 00334 sys.exit(1) 00335 00336 # Loop through the examples 00337 failures = [] 00338 successes = [] 00339 results = {} 00340 os.chdir('examples') 00341 00342 for example in config['examples']: 00343 # Determine if this example should be updated and if so update any found 00344 # mbed-os.lib files. 00345 00346 if upgrade_example(github, example, args.tag, args.github_user, ref): 00347 successes += [example['name']] 00348 else: 00349 failures += [example['name']] 00350 00351 os.chdir('../') 00352 00353 # Finish the script and report the results 00354 print(os.linesep + os.linesep +'Finished updating examples!' + os.linesep) 00355 00356 if successes: 00357 print('\nThe following examples updated successfully:') 00358 for success in successes: 00359 print(' - %s' % success) 00360 00361 if failures: 00362 print('\nThe following examples were not updated:') 00363 for fail in failures: 00364 print(' - %s' % fail) 00365 00366 if __name__ == '__main__': 00367 sys.exit(main(sys.argv[1:]))
Generated on Tue Jul 12 2022 11:02:57 by
1.7.2