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