mbed-os for GR-LYCHEE
Dependents: mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more
tools/check_release.py@0:f782d9c66c49, 2018-02-02 (annotated)
- Committer:
- dkato
- Date:
- Fri Feb 02 05:42:23 2018 +0000
- Revision:
- 0:f782d9c66c49
mbed-os for GR-LYCHEE
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
dkato | 0:f782d9c66c49 | 1 | # Script to check a new mbed 2 release by compiling a set of specified test apps |
dkato | 0:f782d9c66c49 | 2 | # for all currently supported platforms. Each test app must include an mbed library. |
dkato | 0:f782d9c66c49 | 3 | # This can either be the pre-compiled version 'mbed' or the source version 'mbed-dev'. |
dkato | 0:f782d9c66c49 | 4 | # |
dkato | 0:f782d9c66c49 | 5 | # Setup: |
dkato | 0:f782d9c66c49 | 6 | # 1. Set up your global .hgrc file |
dkato | 0:f782d9c66c49 | 7 | # |
dkato | 0:f782d9c66c49 | 8 | # If you don't already have a .hgrc file in your $HOME directory, create one there. |
dkato | 0:f782d9c66c49 | 9 | # Then add the following section: |
dkato | 0:f782d9c66c49 | 10 | # |
dkato | 0:f782d9c66c49 | 11 | # [auth] |
dkato | 0:f782d9c66c49 | 12 | # x.prefix = * |
dkato | 0:f782d9c66c49 | 13 | # x.username = <put your mbed org username here> |
dkato | 0:f782d9c66c49 | 14 | # x.password = <put your mbed org password here> |
dkato | 0:f782d9c66c49 | 15 | # |
dkato | 0:f782d9c66c49 | 16 | # This has 2 purposes, the first means you don't get prompted for your password |
dkato | 0:f782d9c66c49 | 17 | # whenever you run hg commands on the commandline. The second is that this script |
dkato | 0:f782d9c66c49 | 18 | # reads these details in order to fully automate the Mercurial commands. |
dkato | 0:f782d9c66c49 | 19 | # |
dkato | 0:f782d9c66c49 | 20 | # Edit "check_release.json". This has the following structure: |
dkato | 0:f782d9c66c49 | 21 | #{ |
dkato | 0:f782d9c66c49 | 22 | # "config" : { |
dkato | 0:f782d9c66c49 | 23 | # "mbed_repo_path" : "C:/Users/annbri01/Work/Mercurial" |
dkato | 0:f782d9c66c49 | 24 | # }, |
dkato | 0:f782d9c66c49 | 25 | # "test_list" : [ |
dkato | 0:f782d9c66c49 | 26 | # { |
dkato | 0:f782d9c66c49 | 27 | # "name" : "test_compile_mbed_lib", |
dkato | 0:f782d9c66c49 | 28 | # "lib" : "mbed" |
dkato | 0:f782d9c66c49 | 29 | # }, |
dkato | 0:f782d9c66c49 | 30 | # { |
dkato | 0:f782d9c66c49 | 31 | # "name" : "test_compile_mbed_dev", |
dkato | 0:f782d9c66c49 | 32 | # "lib" : "mbed-dev" |
dkato | 0:f782d9c66c49 | 33 | # } |
dkato | 0:f782d9c66c49 | 34 | # ], |
dkato | 0:f782d9c66c49 | 35 | # "target_list" : [] |
dkato | 0:f782d9c66c49 | 36 | #} |
dkato | 0:f782d9c66c49 | 37 | # |
dkato | 0:f782d9c66c49 | 38 | # The mbed_repo_path field should be changed to point to where your local |
dkato | 0:f782d9c66c49 | 39 | # working directory is for Mercurial repositories. |
dkato | 0:f782d9c66c49 | 40 | # For each test app you wish to run, add an entry to the test list. The example |
dkato | 0:f782d9c66c49 | 41 | # above has 2 test apps |
dkato | 0:f782d9c66c49 | 42 | # "test_compile_mbed_lib" and "test_compile_mbed_dev" |
dkato | 0:f782d9c66c49 | 43 | # The lib field in each says which type of mbed 2 library the app contains. |
dkato | 0:f782d9c66c49 | 44 | # These test apps MUST be available as repos in the user's online Mercurial area. |
dkato | 0:f782d9c66c49 | 45 | # The target_list allows the user to override the set of targets/platforms used |
dkato | 0:f782d9c66c49 | 46 | # for the compilation. |
dkato | 0:f782d9c66c49 | 47 | # E.g to just compile for 2 targets, K64F and K22F : |
dkato | 0:f782d9c66c49 | 48 | # "target_list" : ["K64F", "K22F"] |
dkato | 0:f782d9c66c49 | 49 | # |
dkato | 0:f782d9c66c49 | 50 | # Run the script from the mbed-os directory as follows: |
dkato | 0:f782d9c66c49 | 51 | # > python tools/check_release.py |
dkato | 0:f782d9c66c49 | 52 | # |
dkato | 0:f782d9c66c49 | 53 | # It will look for local clones of the test app repos. If they don't exist |
dkato | 0:f782d9c66c49 | 54 | # it will clone them. It will then read the latest versions of mbed and mbed-dev |
dkato | 0:f782d9c66c49 | 55 | # (an assumption is made that both of these are already cloned in your Mercurial area). |
dkato | 0:f782d9c66c49 | 56 | # The lib files within the test apps are then updated to the corresponding version in |
dkato | 0:f782d9c66c49 | 57 | # the associated lib itself. The test apps are then committed and pushed back to the users |
dkato | 0:f782d9c66c49 | 58 | # fork. |
dkato | 0:f782d9c66c49 | 59 | # The test apps will then be compiled for all supported targets and a % result output at |
dkato | 0:f782d9c66c49 | 60 | # the end. |
dkato | 0:f782d9c66c49 | 61 | # |
dkato | 0:f782d9c66c49 | 62 | # Uses the online compiler API at https://mbed.org/handbook/Compile-API |
dkato | 0:f782d9c66c49 | 63 | # Based on the example from https://mbed.org/teams/mbed/code/mbed-API-helper/ |
dkato | 0:f782d9c66c49 | 64 | |
dkato | 0:f782d9c66c49 | 65 | |
dkato | 0:f782d9c66c49 | 66 | import os, getpass, sys, json, time, requests, logging |
dkato | 0:f782d9c66c49 | 67 | from os.path import dirname, abspath, basename, join |
dkato | 0:f782d9c66c49 | 68 | import argparse |
dkato | 0:f782d9c66c49 | 69 | import subprocess |
dkato | 0:f782d9c66c49 | 70 | import re |
dkato | 0:f782d9c66c49 | 71 | import hglib |
dkato | 0:f782d9c66c49 | 72 | import argparse |
dkato | 0:f782d9c66c49 | 73 | |
dkato | 0:f782d9c66c49 | 74 | # Be sure that the tools directory is in the search path |
dkato | 0:f782d9c66c49 | 75 | ROOT = abspath(join(dirname(__file__), "..")) |
dkato | 0:f782d9c66c49 | 76 | sys.path.insert(0, ROOT) |
dkato | 0:f782d9c66c49 | 77 | |
dkato | 0:f782d9c66c49 | 78 | from tools.build_api import get_mbed_official_release |
dkato | 0:f782d9c66c49 | 79 | |
dkato | 0:f782d9c66c49 | 80 | OFFICIAL_MBED_LIBRARY_BUILD = get_mbed_official_release('2') |
dkato | 0:f782d9c66c49 | 81 | |
dkato | 0:f782d9c66c49 | 82 | def get_compilation_failure(messages): |
dkato | 0:f782d9c66c49 | 83 | """ Reads the json formatted 'messages' and checks for compilation errors. |
dkato | 0:f782d9c66c49 | 84 | If there is a genuine compilation error then there should be a new |
dkato | 0:f782d9c66c49 | 85 | message containing a severity field = Error and an accompanying message |
dkato | 0:f782d9c66c49 | 86 | with the compile error text. Any other combination is considered an |
dkato | 0:f782d9c66c49 | 87 | internal compile engine failure |
dkato | 0:f782d9c66c49 | 88 | Args: |
dkato | 0:f782d9c66c49 | 89 | messages - json formatted text returned by the online compiler API. |
dkato | 0:f782d9c66c49 | 90 | |
dkato | 0:f782d9c66c49 | 91 | Returns: |
dkato | 0:f782d9c66c49 | 92 | Either "Error" or "Internal" to indicate an actual compilation error or an |
dkato | 0:f782d9c66c49 | 93 | internal IDE API fault. |
dkato | 0:f782d9c66c49 | 94 | |
dkato | 0:f782d9c66c49 | 95 | """ |
dkato | 0:f782d9c66c49 | 96 | for m in messages: |
dkato | 0:f782d9c66c49 | 97 | # Get message text if it exists |
dkato | 0:f782d9c66c49 | 98 | try: |
dkato | 0:f782d9c66c49 | 99 | message = m['message'] |
dkato | 0:f782d9c66c49 | 100 | message = message + "\n" |
dkato | 0:f782d9c66c49 | 101 | except KeyError: |
dkato | 0:f782d9c66c49 | 102 | # Skip this message as it has no 'message' field |
dkato | 0:f782d9c66c49 | 103 | continue |
dkato | 0:f782d9c66c49 | 104 | |
dkato | 0:f782d9c66c49 | 105 | # Get type of message text |
dkato | 0:f782d9c66c49 | 106 | try: |
dkato | 0:f782d9c66c49 | 107 | msg_type = m['type'] |
dkato | 0:f782d9c66c49 | 108 | except KeyError: |
dkato | 0:f782d9c66c49 | 109 | # Skip this message as it has no 'type' field |
dkato | 0:f782d9c66c49 | 110 | continue |
dkato | 0:f782d9c66c49 | 111 | |
dkato | 0:f782d9c66c49 | 112 | if msg_type == 'error' or msg_type == 'tool_error': |
dkato | 0:f782d9c66c49 | 113 | rel_log.error(message) |
dkato | 0:f782d9c66c49 | 114 | return "Error" |
dkato | 0:f782d9c66c49 | 115 | else: |
dkato | 0:f782d9c66c49 | 116 | rel_log.debug(message) |
dkato | 0:f782d9c66c49 | 117 | |
dkato | 0:f782d9c66c49 | 118 | return "Internal" |
dkato | 0:f782d9c66c49 | 119 | |
dkato | 0:f782d9c66c49 | 120 | def invoke_api(payload, url, auth, polls, begin="start/"): |
dkato | 0:f782d9c66c49 | 121 | """ Sends an API command request to the online IDE. Waits for a task completed |
dkato | 0:f782d9c66c49 | 122 | response before returning the results. |
dkato | 0:f782d9c66c49 | 123 | |
dkato | 0:f782d9c66c49 | 124 | Args: |
dkato | 0:f782d9c66c49 | 125 | payload - Configuration parameters to be passed to the API |
dkato | 0:f782d9c66c49 | 126 | url - THe URL for the online compiler API |
dkato | 0:f782d9c66c49 | 127 | auth - Tuple containing authentication credentials |
dkato | 0:f782d9c66c49 | 128 | polls - Number of times to poll for results |
dkato | 0:f782d9c66c49 | 129 | begin - Default value = "start/", start command to be appended to URL |
dkato | 0:f782d9c66c49 | 130 | |
dkato | 0:f782d9c66c49 | 131 | Returns: |
dkato | 0:f782d9c66c49 | 132 | result - True/False indicating the success/failure of the compilation |
dkato | 0:f782d9c66c49 | 133 | fail_type - the failure text if the compilation failed, else None |
dkato | 0:f782d9c66c49 | 134 | """ |
dkato | 0:f782d9c66c49 | 135 | |
dkato | 0:f782d9c66c49 | 136 | # send task to api |
dkato | 0:f782d9c66c49 | 137 | rel_log.debug(url + begin + "| data: " + str(payload)) |
dkato | 0:f782d9c66c49 | 138 | r = requests.post(url + begin, data=payload, auth=auth) |
dkato | 0:f782d9c66c49 | 139 | rel_log.debug(r.request.body) |
dkato | 0:f782d9c66c49 | 140 | |
dkato | 0:f782d9c66c49 | 141 | if r.status_code != 200: |
dkato | 0:f782d9c66c49 | 142 | rel_log.error("HTTP code %d reported.", r.status_code) |
dkato | 0:f782d9c66c49 | 143 | return False, "Internal" |
dkato | 0:f782d9c66c49 | 144 | |
dkato | 0:f782d9c66c49 | 145 | response = r.json() |
dkato | 0:f782d9c66c49 | 146 | rel_log.debug(response) |
dkato | 0:f782d9c66c49 | 147 | uuid = response['result']['data']['task_id'] |
dkato | 0:f782d9c66c49 | 148 | rel_log.debug("Task accepted and given ID: %s", uuid) |
dkato | 0:f782d9c66c49 | 149 | result = False |
dkato | 0:f782d9c66c49 | 150 | fail_type = None |
dkato | 0:f782d9c66c49 | 151 | |
dkato | 0:f782d9c66c49 | 152 | # It currently seems to take the onlide IDE API ~30s to process the compile |
dkato | 0:f782d9c66c49 | 153 | # request and provide a response. Set the poll time to half that in case it |
dkato | 0:f782d9c66c49 | 154 | # does manage to compile quicker. |
dkato | 0:f782d9c66c49 | 155 | poll_delay = 15 |
dkato | 0:f782d9c66c49 | 156 | rel_log.debug("Running with a poll for response delay of: %ss", poll_delay) |
dkato | 0:f782d9c66c49 | 157 | |
dkato | 0:f782d9c66c49 | 158 | # poll for output |
dkato | 0:f782d9c66c49 | 159 | for check in range(polls): |
dkato | 0:f782d9c66c49 | 160 | time.sleep(poll_delay) |
dkato | 0:f782d9c66c49 | 161 | |
dkato | 0:f782d9c66c49 | 162 | try: |
dkato | 0:f782d9c66c49 | 163 | r = requests.get(url + "output/%s" % uuid, auth=auth) |
dkato | 0:f782d9c66c49 | 164 | |
dkato | 0:f782d9c66c49 | 165 | except ConnectionError: |
dkato | 0:f782d9c66c49 | 166 | return "Internal" |
dkato | 0:f782d9c66c49 | 167 | |
dkato | 0:f782d9c66c49 | 168 | response = r.json() |
dkato | 0:f782d9c66c49 | 169 | |
dkato | 0:f782d9c66c49 | 170 | data = response['result']['data'] |
dkato | 0:f782d9c66c49 | 171 | if data['task_complete']: |
dkato | 0:f782d9c66c49 | 172 | # Task completed. Now determine the result. Should be one of : |
dkato | 0:f782d9c66c49 | 173 | # 1) Successful compilation |
dkato | 0:f782d9c66c49 | 174 | # 2) Failed compilation with an error message |
dkato | 0:f782d9c66c49 | 175 | # 3) Internal failure of the online compiler |
dkato | 0:f782d9c66c49 | 176 | result = bool(data['compilation_success']) |
dkato | 0:f782d9c66c49 | 177 | if result: |
dkato | 0:f782d9c66c49 | 178 | rel_log.info("COMPILATION SUCCESSFUL\n") |
dkato | 0:f782d9c66c49 | 179 | else: |
dkato | 0:f782d9c66c49 | 180 | # Did this fail due to a genuine compilation error or a failue of |
dkato | 0:f782d9c66c49 | 181 | # the api itself ? |
dkato | 0:f782d9c66c49 | 182 | rel_log.info("COMPILATION FAILURE\n") |
dkato | 0:f782d9c66c49 | 183 | fail_type = get_compilation_failure(data['new_messages']) |
dkato | 0:f782d9c66c49 | 184 | break |
dkato | 0:f782d9c66c49 | 185 | else: |
dkato | 0:f782d9c66c49 | 186 | rel_log.info("COMPILATION FAILURE\n") |
dkato | 0:f782d9c66c49 | 187 | |
dkato | 0:f782d9c66c49 | 188 | if not result and fail_type == None: |
dkato | 0:f782d9c66c49 | 189 | fail_type = "Internal" |
dkato | 0:f782d9c66c49 | 190 | |
dkato | 0:f782d9c66c49 | 191 | return result, fail_type |
dkato | 0:f782d9c66c49 | 192 | |
dkato | 0:f782d9c66c49 | 193 | |
dkato | 0:f782d9c66c49 | 194 | def build_repo(target, program, user, pw, polls=25, |
dkato | 0:f782d9c66c49 | 195 | url="https://developer.mbed.org/api/v2/tasks/compiler/"): |
dkato | 0:f782d9c66c49 | 196 | """ Wrapper for sending an API command request to the online IDE. Sends a |
dkato | 0:f782d9c66c49 | 197 | build request. |
dkato | 0:f782d9c66c49 | 198 | |
dkato | 0:f782d9c66c49 | 199 | Args: |
dkato | 0:f782d9c66c49 | 200 | target - Target to be built |
dkato | 0:f782d9c66c49 | 201 | program - Test program to build |
dkato | 0:f782d9c66c49 | 202 | user - mbed username |
dkato | 0:f782d9c66c49 | 203 | pw - mbed password |
dkato | 0:f782d9c66c49 | 204 | polls - Number of times to poll for results |
dkato | 0:f782d9c66c49 | 205 | url - THe URL for the online compiler API |
dkato | 0:f782d9c66c49 | 206 | |
dkato | 0:f782d9c66c49 | 207 | Returns: |
dkato | 0:f782d9c66c49 | 208 | result - True/False indicating the success/failure of the compilation |
dkato | 0:f782d9c66c49 | 209 | fail_type - the failure text if the compilation failed, else None |
dkato | 0:f782d9c66c49 | 210 | """ |
dkato | 0:f782d9c66c49 | 211 | payload = {'clean':True, 'target':target, 'program':program} |
dkato | 0:f782d9c66c49 | 212 | auth = (user, pw) |
dkato | 0:f782d9c66c49 | 213 | return invoke_api(payload, url, auth, polls) |
dkato | 0:f782d9c66c49 | 214 | |
dkato | 0:f782d9c66c49 | 215 | def run_cmd(command, exit_on_failure=False): |
dkato | 0:f782d9c66c49 | 216 | """ Passes a command to the system and returns a True/False result once the |
dkato | 0:f782d9c66c49 | 217 | command has been executed, indicating success/failure. Commands are passed |
dkato | 0:f782d9c66c49 | 218 | as a list of tokens. |
dkato | 0:f782d9c66c49 | 219 | E.g. The command 'git remote -v' would be passed in as ['git', 'remote', '-v'] |
dkato | 0:f782d9c66c49 | 220 | |
dkato | 0:f782d9c66c49 | 221 | Args: |
dkato | 0:f782d9c66c49 | 222 | command - system command as a list of tokens |
dkato | 0:f782d9c66c49 | 223 | exit_on_failure - If True exit the program on failure (default = False) |
dkato | 0:f782d9c66c49 | 224 | |
dkato | 0:f782d9c66c49 | 225 | Returns: |
dkato | 0:f782d9c66c49 | 226 | result - True/False indicating the success/failure of the command |
dkato | 0:f782d9c66c49 | 227 | """ |
dkato | 0:f782d9c66c49 | 228 | rel_log.debug('[Exec] %s', ' '.join(command)) |
dkato | 0:f782d9c66c49 | 229 | return_code = subprocess.call(command, shell=True) |
dkato | 0:f782d9c66c49 | 230 | |
dkato | 0:f782d9c66c49 | 231 | if return_code: |
dkato | 0:f782d9c66c49 | 232 | rel_log.warning("The command '%s' failed with return code: %s", |
dkato | 0:f782d9c66c49 | 233 | (' '.join(command), return_code)) |
dkato | 0:f782d9c66c49 | 234 | if exit_on_failure: |
dkato | 0:f782d9c66c49 | 235 | sys.exit(1) |
dkato | 0:f782d9c66c49 | 236 | |
dkato | 0:f782d9c66c49 | 237 | return return_code |
dkato | 0:f782d9c66c49 | 238 | |
dkato | 0:f782d9c66c49 | 239 | def run_cmd_with_output(command, exit_on_failure=False): |
dkato | 0:f782d9c66c49 | 240 | """ Passes a command to the system and returns a True/False result once the |
dkato | 0:f782d9c66c49 | 241 | command has been executed, indicating success/failure. If the command was |
dkato | 0:f782d9c66c49 | 242 | successful then the output from the command is returned to the caller. |
dkato | 0:f782d9c66c49 | 243 | Commands are passed as a list of tokens. |
dkato | 0:f782d9c66c49 | 244 | E.g. The command 'git remote -v' would be passed in as ['git', 'remote', '-v'] |
dkato | 0:f782d9c66c49 | 245 | |
dkato | 0:f782d9c66c49 | 246 | Args: |
dkato | 0:f782d9c66c49 | 247 | command - system command as a list of tokens |
dkato | 0:f782d9c66c49 | 248 | exit_on_failure - If True exit the program on failure (default = False) |
dkato | 0:f782d9c66c49 | 249 | |
dkato | 0:f782d9c66c49 | 250 | Returns: |
dkato | 0:f782d9c66c49 | 251 | result - True/False indicating the success/failure of the command |
dkato | 0:f782d9c66c49 | 252 | output - The output of the command if it was successful, else empty string |
dkato | 0:f782d9c66c49 | 253 | """ |
dkato | 0:f782d9c66c49 | 254 | rel_log.debug('[Exec] %s', ' '.join(command)) |
dkato | 0:f782d9c66c49 | 255 | returncode = 0 |
dkato | 0:f782d9c66c49 | 256 | output = "" |
dkato | 0:f782d9c66c49 | 257 | try: |
dkato | 0:f782d9c66c49 | 258 | output = subprocess.check_output(command, shell=True) |
dkato | 0:f782d9c66c49 | 259 | except subprocess.CalledProcessError as e: |
dkato | 0:f782d9c66c49 | 260 | rel_log.warning("The command '%s' failed with return code: %s", |
dkato | 0:f782d9c66c49 | 261 | (' '.join(command), e.returncode)) |
dkato | 0:f782d9c66c49 | 262 | returncode = e.returncode |
dkato | 0:f782d9c66c49 | 263 | if exit_on_failure: |
dkato | 0:f782d9c66c49 | 264 | sys.exit(1) |
dkato | 0:f782d9c66c49 | 265 | return returncode, output |
dkato | 0:f782d9c66c49 | 266 | |
dkato | 0:f782d9c66c49 | 267 | def upgrade_test_repo(test, user, library, ref, repo_path): |
dkato | 0:f782d9c66c49 | 268 | """ Upgrades a local version of a test repo to the latest version of its |
dkato | 0:f782d9c66c49 | 269 | embedded library. |
dkato | 0:f782d9c66c49 | 270 | If the test repo is not present in the user area specified in the json |
dkato | 0:f782d9c66c49 | 271 | config file, then it will first be cloned. |
dkato | 0:f782d9c66c49 | 272 | Args: |
dkato | 0:f782d9c66c49 | 273 | test - Mercurial test repo name |
dkato | 0:f782d9c66c49 | 274 | user - Mercurial user name |
dkato | 0:f782d9c66c49 | 275 | library - library name |
dkato | 0:f782d9c66c49 | 276 | ref - SHA corresponding to the latest version of the library |
dkato | 0:f782d9c66c49 | 277 | repo_path - path to the user's repo area |
dkato | 0:f782d9c66c49 | 278 | |
dkato | 0:f782d9c66c49 | 279 | Returns: |
dkato | 0:f782d9c66c49 | 280 | updated - True if library was updated, False otherwise |
dkato | 0:f782d9c66c49 | 281 | """ |
dkato | 0:f782d9c66c49 | 282 | rel_log.info("Updating test repo: '%s' to SHA: %s", test, ref) |
dkato | 0:f782d9c66c49 | 283 | cwd = os.getcwd() |
dkato | 0:f782d9c66c49 | 284 | |
dkato | 0:f782d9c66c49 | 285 | repo = "https://" + user + '@developer.mbed.org/users/' + user + '/code/' + test |
dkato | 0:f782d9c66c49 | 286 | |
dkato | 0:f782d9c66c49 | 287 | # Clone the repo if it doesn't already exist |
dkato | 0:f782d9c66c49 | 288 | path = abspath(repo_path + '/' + test) |
dkato | 0:f782d9c66c49 | 289 | if not os.path.exists(path): |
dkato | 0:f782d9c66c49 | 290 | rel_log.info("Test repo doesn't exist, cloning...") |
dkato | 0:f782d9c66c49 | 291 | os.chdir(abspath(repo_path)) |
dkato | 0:f782d9c66c49 | 292 | clone_cmd = ['hg', 'clone', repo] |
dkato | 0:f782d9c66c49 | 293 | run_cmd(clone_cmd, exit_on_failure=True) |
dkato | 0:f782d9c66c49 | 294 | |
dkato | 0:f782d9c66c49 | 295 | os.chdir(path) |
dkato | 0:f782d9c66c49 | 296 | |
dkato | 0:f782d9c66c49 | 297 | client = hglib.open(path) |
dkato | 0:f782d9c66c49 | 298 | |
dkato | 0:f782d9c66c49 | 299 | lib_file = library + '.lib' |
dkato | 0:f782d9c66c49 | 300 | if os.path.isfile(lib_file): |
dkato | 0:f782d9c66c49 | 301 | # Rename command will fail on some OS's if the target file already exist, |
dkato | 0:f782d9c66c49 | 302 | # so ensure if it does, it is deleted first. |
dkato | 0:f782d9c66c49 | 303 | bak_file = library + '_bak' |
dkato | 0:f782d9c66c49 | 304 | if os.path.isfile(bak_file): |
dkato | 0:f782d9c66c49 | 305 | os.remove(bak_file) |
dkato | 0:f782d9c66c49 | 306 | |
dkato | 0:f782d9c66c49 | 307 | os.rename(lib_file, bak_file) |
dkato | 0:f782d9c66c49 | 308 | else: |
dkato | 0:f782d9c66c49 | 309 | rel_log.error("Failure to backup lib file prior to updating.") |
dkato | 0:f782d9c66c49 | 310 | return False |
dkato | 0:f782d9c66c49 | 311 | |
dkato | 0:f782d9c66c49 | 312 | # mbed 2 style lib file contains one line with the following format |
dkato | 0:f782d9c66c49 | 313 | # e.g. https://developer.mbed.org/users/<user>/code/mbed-dev/#156823d33999 |
dkato | 0:f782d9c66c49 | 314 | exp = 'https://developer.mbed.org/users/' + user + '/code/' + library + '/#[A-Za-z0-9]+' |
dkato | 0:f782d9c66c49 | 315 | lib_re = re.compile(exp) |
dkato | 0:f782d9c66c49 | 316 | updated = False |
dkato | 0:f782d9c66c49 | 317 | |
dkato | 0:f782d9c66c49 | 318 | # Scan through mbed-os.lib line by line, looking for lib version and update |
dkato | 0:f782d9c66c49 | 319 | # it if found |
dkato | 0:f782d9c66c49 | 320 | with open(bak_file, 'r') as ip, open(lib_file, 'w') as op: |
dkato | 0:f782d9c66c49 | 321 | for line in ip: |
dkato | 0:f782d9c66c49 | 322 | |
dkato | 0:f782d9c66c49 | 323 | opline = line |
dkato | 0:f782d9c66c49 | 324 | |
dkato | 0:f782d9c66c49 | 325 | regexp = lib_re.match(line) |
dkato | 0:f782d9c66c49 | 326 | if regexp: |
dkato | 0:f782d9c66c49 | 327 | opline = 'https://developer.mbed.org/users/' + user + '/code/' + library + '/#' + ref |
dkato | 0:f782d9c66c49 | 328 | updated = True |
dkato | 0:f782d9c66c49 | 329 | |
dkato | 0:f782d9c66c49 | 330 | op.write(opline) |
dkato | 0:f782d9c66c49 | 331 | |
dkato | 0:f782d9c66c49 | 332 | if updated: |
dkato | 0:f782d9c66c49 | 333 | |
dkato | 0:f782d9c66c49 | 334 | # Setup the default commit message |
dkato | 0:f782d9c66c49 | 335 | commit_message = '"Updating ' + library + ' to ' + ref + '"' |
dkato | 0:f782d9c66c49 | 336 | |
dkato | 0:f782d9c66c49 | 337 | # Setup and run the commit command. Need to use the rawcommand in the hglib |
dkato | 0:f782d9c66c49 | 338 | # for this in order to pass the string value to the -m option. run_cmd using |
dkato | 0:f782d9c66c49 | 339 | # subprocess does not like this syntax. |
dkato | 0:f782d9c66c49 | 340 | try: |
dkato | 0:f782d9c66c49 | 341 | client.rawcommand(['commit','-m '+commit_message, lib_file]) |
dkato | 0:f782d9c66c49 | 342 | |
dkato | 0:f782d9c66c49 | 343 | cmd = ['hg', 'push', '-f', repo] |
dkato | 0:f782d9c66c49 | 344 | run_cmd(cmd, exit_on_failure=True) |
dkato | 0:f782d9c66c49 | 345 | |
dkato | 0:f782d9c66c49 | 346 | except: |
dkato | 0:f782d9c66c49 | 347 | rel_log.info("Lib file already up to date and thus nothing to commit") |
dkato | 0:f782d9c66c49 | 348 | |
dkato | 0:f782d9c66c49 | 349 | os.chdir(cwd) |
dkato | 0:f782d9c66c49 | 350 | return updated |
dkato | 0:f782d9c66c49 | 351 | |
dkato | 0:f782d9c66c49 | 352 | def get_sha(repo_path, library): |
dkato | 0:f782d9c66c49 | 353 | """ Gets the latest SHA for the library specified. The library is assumed to be |
dkato | 0:f782d9c66c49 | 354 | located at the repo_path. If a SHA cannot be obtained this script will exit. |
dkato | 0:f782d9c66c49 | 355 | |
dkato | 0:f782d9c66c49 | 356 | Args: |
dkato | 0:f782d9c66c49 | 357 | library - library name |
dkato | 0:f782d9c66c49 | 358 | repo_path - path to the user's repo area |
dkato | 0:f782d9c66c49 | 359 | |
dkato | 0:f782d9c66c49 | 360 | Returns: |
dkato | 0:f782d9c66c49 | 361 | sha - last commit SHA |
dkato | 0:f782d9c66c49 | 362 | """ |
dkato | 0:f782d9c66c49 | 363 | cwd = os.getcwd() |
dkato | 0:f782d9c66c49 | 364 | sha = None |
dkato | 0:f782d9c66c49 | 365 | os.chdir(abspath(repo_path + '/' + library)) |
dkato | 0:f782d9c66c49 | 366 | |
dkato | 0:f782d9c66c49 | 367 | cmd = ['hg', 'log', '-l', '1'] |
dkato | 0:f782d9c66c49 | 368 | ret, output = run_cmd_with_output(cmd, exit_on_failure=True) |
dkato | 0:f782d9c66c49 | 369 | |
dkato | 0:f782d9c66c49 | 370 | # Output should contain a 4 line string of the form: |
dkato | 0:f782d9c66c49 | 371 | # changeset: 135:176b8275d35d |
dkato | 0:f782d9c66c49 | 372 | # tag: tip |
dkato | 0:f782d9c66c49 | 373 | # user: <> |
dkato | 0:f782d9c66c49 | 374 | # date: Thu Feb 02 16:02:30 2017 +0000 |
dkato | 0:f782d9c66c49 | 375 | # summary: Release 135 of the mbed library |
dkato | 0:f782d9c66c49 | 376 | # All we want is the changeset string after version number |
dkato | 0:f782d9c66c49 | 377 | |
dkato | 0:f782d9c66c49 | 378 | lines = output.split('\n') |
dkato | 0:f782d9c66c49 | 379 | fields = lines[0].split(':') |
dkato | 0:f782d9c66c49 | 380 | sha = fields[2] |
dkato | 0:f782d9c66c49 | 381 | |
dkato | 0:f782d9c66c49 | 382 | os.chdir(cwd) |
dkato | 0:f782d9c66c49 | 383 | return sha |
dkato | 0:f782d9c66c49 | 384 | |
dkato | 0:f782d9c66c49 | 385 | def get_latest_library_versions(repo_path): |
dkato | 0:f782d9c66c49 | 386 | """ Returns the latest library versions (SHAs) for 'mbed' and 'mbed-dev'. |
dkato | 0:f782d9c66c49 | 387 | If the SHAs cannot be obtained this script will exit. |
dkato | 0:f782d9c66c49 | 388 | |
dkato | 0:f782d9c66c49 | 389 | Args: |
dkato | 0:f782d9c66c49 | 390 | repo_path - path to the user's repo area |
dkato | 0:f782d9c66c49 | 391 | |
dkato | 0:f782d9c66c49 | 392 | Returns: |
dkato | 0:f782d9c66c49 | 393 | mbed - last commit SHA for mbed library |
dkato | 0:f782d9c66c49 | 394 | mbed_dev - last commit SHA for mbed_dev library |
dkato | 0:f782d9c66c49 | 395 | |
dkato | 0:f782d9c66c49 | 396 | """ |
dkato | 0:f782d9c66c49 | 397 | |
dkato | 0:f782d9c66c49 | 398 | mbed = get_sha(repo_path, 'mbed') |
dkato | 0:f782d9c66c49 | 399 | mbed_dev = get_sha(repo_path, 'mbed-dev') |
dkato | 0:f782d9c66c49 | 400 | |
dkato | 0:f782d9c66c49 | 401 | return mbed, mbed_dev |
dkato | 0:f782d9c66c49 | 402 | |
dkato | 0:f782d9c66c49 | 403 | def log_results(lst, title): |
dkato | 0:f782d9c66c49 | 404 | if len(lst) == 0: |
dkato | 0:f782d9c66c49 | 405 | rel_log.info("%s - None", title) |
dkato | 0:f782d9c66c49 | 406 | else: |
dkato | 0:f782d9c66c49 | 407 | for entry in lst: |
dkato | 0:f782d9c66c49 | 408 | rel_log.info("%s - Test: %s, Target: %s", title, entry[0], entry[1]) |
dkato | 0:f782d9c66c49 | 409 | |
dkato | 0:f782d9c66c49 | 410 | |
dkato | 0:f782d9c66c49 | 411 | if __name__ == '__main__': |
dkato | 0:f782d9c66c49 | 412 | |
dkato | 0:f782d9c66c49 | 413 | parser = argparse.ArgumentParser(description=__doc__, |
dkato | 0:f782d9c66c49 | 414 | formatter_class=argparse.RawDescriptionHelpFormatter) |
dkato | 0:f782d9c66c49 | 415 | parser.add_argument('-l', '--log-level', |
dkato | 0:f782d9c66c49 | 416 | help="Level for providing logging output", |
dkato | 0:f782d9c66c49 | 417 | default='INFO') |
dkato | 0:f782d9c66c49 | 418 | args = parser.parse_args() |
dkato | 0:f782d9c66c49 | 419 | |
dkato | 0:f782d9c66c49 | 420 | default = getattr(logging, 'INFO') |
dkato | 0:f782d9c66c49 | 421 | level = getattr(logging, args.log_level.upper(), default) |
dkato | 0:f782d9c66c49 | 422 | |
dkato | 0:f782d9c66c49 | 423 | # Set logging level |
dkato | 0:f782d9c66c49 | 424 | logging.basicConfig(level=level) |
dkato | 0:f782d9c66c49 | 425 | rel_log = logging.getLogger("check-release") |
dkato | 0:f782d9c66c49 | 426 | |
dkato | 0:f782d9c66c49 | 427 | # Read configuration data |
dkato | 0:f782d9c66c49 | 428 | with open(os.path.join(os.path.dirname(__file__), "check_release.json")) as config: |
dkato | 0:f782d9c66c49 | 429 | json_data = json.load(config) |
dkato | 0:f782d9c66c49 | 430 | |
dkato | 0:f782d9c66c49 | 431 | supported_targets = [] |
dkato | 0:f782d9c66c49 | 432 | |
dkato | 0:f782d9c66c49 | 433 | if len(json_data["target_list"]) > 0: |
dkato | 0:f782d9c66c49 | 434 | # Compile user supplied subset of targets |
dkato | 0:f782d9c66c49 | 435 | supported_targets = json_data["target_list"] |
dkato | 0:f782d9c66c49 | 436 | else: |
dkato | 0:f782d9c66c49 | 437 | # Get a list of the officially supported mbed-os 2 targets |
dkato | 0:f782d9c66c49 | 438 | for tgt in OFFICIAL_MBED_LIBRARY_BUILD: |
dkato | 0:f782d9c66c49 | 439 | supported_targets.append(tgt[0]) |
dkato | 0:f782d9c66c49 | 440 | |
dkato | 0:f782d9c66c49 | 441 | ignore_list = [] |
dkato | 0:f782d9c66c49 | 442 | |
dkato | 0:f782d9c66c49 | 443 | if len(json_data["ignore_list"]) > 0: |
dkato | 0:f782d9c66c49 | 444 | # List of tuples of (test, target) to be ignored in this test |
dkato | 0:f782d9c66c49 | 445 | ignore_list = json_data["ignore_list"] |
dkato | 0:f782d9c66c49 | 446 | |
dkato | 0:f782d9c66c49 | 447 | config = json_data["config"] |
dkato | 0:f782d9c66c49 | 448 | test_list = json_data["test_list"] |
dkato | 0:f782d9c66c49 | 449 | repo_path = config["mbed_repo_path"] |
dkato | 0:f782d9c66c49 | 450 | tests = [] |
dkato | 0:f782d9c66c49 | 451 | |
dkato | 0:f782d9c66c49 | 452 | # get username |
dkato | 0:f782d9c66c49 | 453 | cmd = ['hg', 'config', 'auth.x.username'] |
dkato | 0:f782d9c66c49 | 454 | ret, output = run_cmd_with_output(cmd, exit_on_failure=True) |
dkato | 0:f782d9c66c49 | 455 | output = output.split('\n') |
dkato | 0:f782d9c66c49 | 456 | user = output[0] |
dkato | 0:f782d9c66c49 | 457 | |
dkato | 0:f782d9c66c49 | 458 | # get password |
dkato | 0:f782d9c66c49 | 459 | cmd = ['hg', 'config', 'auth.x.password'] |
dkato | 0:f782d9c66c49 | 460 | ret, output = run_cmd_with_output(cmd, exit_on_failure=True) |
dkato | 0:f782d9c66c49 | 461 | output = output.split('\n') |
dkato | 0:f782d9c66c49 | 462 | password = output[0] |
dkato | 0:f782d9c66c49 | 463 | |
dkato | 0:f782d9c66c49 | 464 | mbed, mbed_dev = get_latest_library_versions(repo_path) |
dkato | 0:f782d9c66c49 | 465 | |
dkato | 0:f782d9c66c49 | 466 | if not mbed or not mbed_dev: |
dkato | 0:f782d9c66c49 | 467 | rel_log.error("Could not obtain latest versions of library files!!") |
dkato | 0:f782d9c66c49 | 468 | exit(1) |
dkato | 0:f782d9c66c49 | 469 | |
dkato | 0:f782d9c66c49 | 470 | rel_log.info("Latest mbed lib version = %s", mbed) |
dkato | 0:f782d9c66c49 | 471 | rel_log.info("Latest mbed-dev lib version = %s", mbed_dev) |
dkato | 0:f782d9c66c49 | 472 | |
dkato | 0:f782d9c66c49 | 473 | # First update test repos to latest versions of their embedded libraries |
dkato | 0:f782d9c66c49 | 474 | for test in test_list: |
dkato | 0:f782d9c66c49 | 475 | tests.append(test['name']) |
dkato | 0:f782d9c66c49 | 476 | upgrade_test_repo(test['name'], user, test['lib'], |
dkato | 0:f782d9c66c49 | 477 | mbed if test['lib'] == "mbed" else mbed_dev, |
dkato | 0:f782d9c66c49 | 478 | repo_path) |
dkato | 0:f782d9c66c49 | 479 | |
dkato | 0:f782d9c66c49 | 480 | total = len(supported_targets) * len(tests) |
dkato | 0:f782d9c66c49 | 481 | current = 0 |
dkato | 0:f782d9c66c49 | 482 | retries = 10 |
dkato | 0:f782d9c66c49 | 483 | passes = 0 |
dkato | 0:f782d9c66c49 | 484 | failures = [] |
dkato | 0:f782d9c66c49 | 485 | skipped = [] |
dkato | 0:f782d9c66c49 | 486 | |
dkato | 0:f782d9c66c49 | 487 | # Compile each test for each supported target |
dkato | 0:f782d9c66c49 | 488 | for test in tests: |
dkato | 0:f782d9c66c49 | 489 | for target in supported_targets: |
dkato | 0:f782d9c66c49 | 490 | |
dkato | 0:f782d9c66c49 | 491 | combo = [test, target] |
dkato | 0:f782d9c66c49 | 492 | |
dkato | 0:f782d9c66c49 | 493 | if combo in ignore_list: |
dkato | 0:f782d9c66c49 | 494 | rel_log.info("SKIPPING TEST: %s, TARGET: %s", test, target) |
dkato | 0:f782d9c66c49 | 495 | total -= 1 |
dkato | 0:f782d9c66c49 | 496 | skipped.append(combo) |
dkato | 0:f782d9c66c49 | 497 | continue |
dkato | 0:f782d9c66c49 | 498 | |
dkato | 0:f782d9c66c49 | 499 | current += 1 |
dkato | 0:f782d9c66c49 | 500 | for retry in range(0, retries): |
dkato | 0:f782d9c66c49 | 501 | rel_log.info("COMPILING (%d/%d): TEST %s, TARGET: %s , attempt %u\n", current, total, test, target, retry) |
dkato | 0:f782d9c66c49 | 502 | result, mesg = build_repo(target, test, user, password) |
dkato | 0:f782d9c66c49 | 503 | if not result: |
dkato | 0:f782d9c66c49 | 504 | if mesg == 'Internal': |
dkato | 0:f782d9c66c49 | 505 | # Internal compiler error thus retry |
dkato | 0:f782d9c66c49 | 506 | continue |
dkato | 0:f782d9c66c49 | 507 | else: |
dkato | 0:f782d9c66c49 | 508 | # Actual error thus move on to next compilation |
dkato | 0:f782d9c66c49 | 509 | failures.append(combo) |
dkato | 0:f782d9c66c49 | 510 | break |
dkato | 0:f782d9c66c49 | 511 | |
dkato | 0:f782d9c66c49 | 512 | passes += (int)(result) |
dkato | 0:f782d9c66c49 | 513 | break |
dkato | 0:f782d9c66c49 | 514 | else: |
dkato | 0:f782d9c66c49 | 515 | rel_log.error("Compilation failed due to internal errors.") |
dkato | 0:f782d9c66c49 | 516 | rel_log.error("Skipping test/target combination.") |
dkato | 0:f782d9c66c49 | 517 | total -= 1 |
dkato | 0:f782d9c66c49 | 518 | skipped.append(combo) |
dkato | 0:f782d9c66c49 | 519 | |
dkato | 0:f782d9c66c49 | 520 | rel_log.info(" SUMMARY OF COMPILATION RESULTS") |
dkato | 0:f782d9c66c49 | 521 | rel_log.info(" ------------------------------") |
dkato | 0:f782d9c66c49 | 522 | rel_log.info(" NUMBER OF TEST APPS: %d, NUMBER OF TARGETS: %d", |
dkato | 0:f782d9c66c49 | 523 | len(tests), len(supported_targets)) |
dkato | 0:f782d9c66c49 | 524 | log_results(failures, " FAILED") |
dkato | 0:f782d9c66c49 | 525 | log_results(skipped, " SKIPPED") |
dkato | 0:f782d9c66c49 | 526 | |
dkato | 0:f782d9c66c49 | 527 | # Output a % pass rate, indicate a failure if not 100% successful |
dkato | 0:f782d9c66c49 | 528 | pass_rate = (float(passes) / float(total)) * 100.0 |
dkato | 0:f782d9c66c49 | 529 | rel_log.info(" PASS RATE %.1f %%\n", pass_rate) |
dkato | 0:f782d9c66c49 | 530 | sys.exit(not (pass_rate == 100)) |