Rtos API example

Committer:
marcozecchini
Date:
Sat Feb 23 12:13:36 2019 +0000
Revision:
0:9fca2b23d0ba
final commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
marcozecchini 0:9fca2b23d0ba 1 """
marcozecchini 0:9fca2b23d0ba 2 mbed SDK
marcozecchini 0:9fca2b23d0ba 3 Copyright (c) 2011-2013 ARM Limited
marcozecchini 0:9fca2b23d0ba 4
marcozecchini 0:9fca2b23d0ba 5 Licensed under the Apache License, Version 2.0 (the "License");
marcozecchini 0:9fca2b23d0ba 6 you may not use this file except in compliance with the License.
marcozecchini 0:9fca2b23d0ba 7 You may obtain a copy of the License at
marcozecchini 0:9fca2b23d0ba 8
marcozecchini 0:9fca2b23d0ba 9 http://www.apache.org/licenses/LICENSE-2.0
marcozecchini 0:9fca2b23d0ba 10
marcozecchini 0:9fca2b23d0ba 11 Unless required by applicable law or agreed to in writing, software
marcozecchini 0:9fca2b23d0ba 12 distributed under the License is distributed on an "AS IS" BASIS,
marcozecchini 0:9fca2b23d0ba 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
marcozecchini 0:9fca2b23d0ba 14 See the License for the specific language governing permissions and
marcozecchini 0:9fca2b23d0ba 15 limitations under the License.
marcozecchini 0:9fca2b23d0ba 16 """
marcozecchini 0:9fca2b23d0ba 17 import sys
marcozecchini 0:9fca2b23d0ba 18 import inspect
marcozecchini 0:9fca2b23d0ba 19 import os
marcozecchini 0:9fca2b23d0ba 20 import argparse
marcozecchini 0:9fca2b23d0ba 21 import math
marcozecchini 0:9fca2b23d0ba 22 from os import listdir, remove, makedirs
marcozecchini 0:9fca2b23d0ba 23 from shutil import copyfile
marcozecchini 0:9fca2b23d0ba 24 from os.path import isdir, join, exists, split, relpath, splitext, abspath
marcozecchini 0:9fca2b23d0ba 25 from os.path import commonprefix, normpath, dirname
marcozecchini 0:9fca2b23d0ba 26 from subprocess import Popen, PIPE, STDOUT, call
marcozecchini 0:9fca2b23d0ba 27 from math import ceil
marcozecchini 0:9fca2b23d0ba 28 import json
marcozecchini 0:9fca2b23d0ba 29 from collections import OrderedDict
marcozecchini 0:9fca2b23d0ba 30 import logging
marcozecchini 0:9fca2b23d0ba 31 from intelhex import IntelHex
marcozecchini 0:9fca2b23d0ba 32
marcozecchini 0:9fca2b23d0ba 33 def remove_if_in(lst, thing):
marcozecchini 0:9fca2b23d0ba 34 if thing in lst:
marcozecchini 0:9fca2b23d0ba 35 lst.remove(thing)
marcozecchini 0:9fca2b23d0ba 36
marcozecchini 0:9fca2b23d0ba 37 def compile_worker(job):
marcozecchini 0:9fca2b23d0ba 38 """Standard task runner used for compiling
marcozecchini 0:9fca2b23d0ba 39
marcozecchini 0:9fca2b23d0ba 40 Positional argumets:
marcozecchini 0:9fca2b23d0ba 41 job - a dict containing a list of commands and the remaining arguments
marcozecchini 0:9fca2b23d0ba 42 to run_cmd
marcozecchini 0:9fca2b23d0ba 43 """
marcozecchini 0:9fca2b23d0ba 44 results = []
marcozecchini 0:9fca2b23d0ba 45 for command in job['commands']:
marcozecchini 0:9fca2b23d0ba 46 try:
marcozecchini 0:9fca2b23d0ba 47 _, _stderr, _rc = run_cmd(command, work_dir=job['work_dir'],
marcozecchini 0:9fca2b23d0ba 48 chroot=job['chroot'])
marcozecchini 0:9fca2b23d0ba 49 except KeyboardInterrupt:
marcozecchini 0:9fca2b23d0ba 50 raise ToolException
marcozecchini 0:9fca2b23d0ba 51
marcozecchini 0:9fca2b23d0ba 52 results.append({
marcozecchini 0:9fca2b23d0ba 53 'code': _rc,
marcozecchini 0:9fca2b23d0ba 54 'output': _stderr,
marcozecchini 0:9fca2b23d0ba 55 'command': command
marcozecchini 0:9fca2b23d0ba 56 })
marcozecchini 0:9fca2b23d0ba 57
marcozecchini 0:9fca2b23d0ba 58 return {
marcozecchini 0:9fca2b23d0ba 59 'source': job['source'],
marcozecchini 0:9fca2b23d0ba 60 'object': job['object'],
marcozecchini 0:9fca2b23d0ba 61 'commands': job['commands'],
marcozecchini 0:9fca2b23d0ba 62 'results': results
marcozecchini 0:9fca2b23d0ba 63 }
marcozecchini 0:9fca2b23d0ba 64
marcozecchini 0:9fca2b23d0ba 65 def cmd(command, check=True, verbose=False, shell=False, cwd=None):
marcozecchini 0:9fca2b23d0ba 66 """A wrapper to run a command as a blocking job"""
marcozecchini 0:9fca2b23d0ba 67 text = command if shell else ' '.join(command)
marcozecchini 0:9fca2b23d0ba 68 if verbose:
marcozecchini 0:9fca2b23d0ba 69 print text
marcozecchini 0:9fca2b23d0ba 70 return_code = call(command, shell=shell, cwd=cwd)
marcozecchini 0:9fca2b23d0ba 71 if check and return_code != 0:
marcozecchini 0:9fca2b23d0ba 72 raise Exception('ERROR %d: "%s"' % (return_code, text))
marcozecchini 0:9fca2b23d0ba 73
marcozecchini 0:9fca2b23d0ba 74
marcozecchini 0:9fca2b23d0ba 75 def run_cmd(command, work_dir=None, chroot=None, redirect=False):
marcozecchini 0:9fca2b23d0ba 76 """Run a command in the forground
marcozecchini 0:9fca2b23d0ba 77
marcozecchini 0:9fca2b23d0ba 78 Positional arguments:
marcozecchini 0:9fca2b23d0ba 79 command - the command to run
marcozecchini 0:9fca2b23d0ba 80
marcozecchini 0:9fca2b23d0ba 81 Keyword arguments:
marcozecchini 0:9fca2b23d0ba 82 work_dir - the working directory to run the command in
marcozecchini 0:9fca2b23d0ba 83 chroot - the chroot to run the command in
marcozecchini 0:9fca2b23d0ba 84 redirect - redirect the stderr to a pipe to be used later
marcozecchini 0:9fca2b23d0ba 85 """
marcozecchini 0:9fca2b23d0ba 86 if chroot:
marcozecchini 0:9fca2b23d0ba 87 # Conventions managed by the web team for the mbed.org build system
marcozecchini 0:9fca2b23d0ba 88 chroot_cmd = [
marcozecchini 0:9fca2b23d0ba 89 '/usr/sbin/chroot', '--userspec=33:33', chroot
marcozecchini 0:9fca2b23d0ba 90 ]
marcozecchini 0:9fca2b23d0ba 91 for element in command:
marcozecchini 0:9fca2b23d0ba 92 chroot_cmd += [element.replace(chroot, '')]
marcozecchini 0:9fca2b23d0ba 93
marcozecchini 0:9fca2b23d0ba 94 logging.debug("Running command %s", ' '.join(chroot_cmd))
marcozecchini 0:9fca2b23d0ba 95 command = chroot_cmd
marcozecchini 0:9fca2b23d0ba 96 work_dir = None
marcozecchini 0:9fca2b23d0ba 97
marcozecchini 0:9fca2b23d0ba 98 try:
marcozecchini 0:9fca2b23d0ba 99 process = Popen(command, stdout=PIPE,
marcozecchini 0:9fca2b23d0ba 100 stderr=STDOUT if redirect else PIPE, cwd=work_dir)
marcozecchini 0:9fca2b23d0ba 101 _stdout, _stderr = process.communicate()
marcozecchini 0:9fca2b23d0ba 102 except OSError:
marcozecchini 0:9fca2b23d0ba 103 print "[OS ERROR] Command: "+(' '.join(command))
marcozecchini 0:9fca2b23d0ba 104 raise
marcozecchini 0:9fca2b23d0ba 105
marcozecchini 0:9fca2b23d0ba 106 return _stdout, _stderr, process.returncode
marcozecchini 0:9fca2b23d0ba 107
marcozecchini 0:9fca2b23d0ba 108
marcozecchini 0:9fca2b23d0ba 109 def run_cmd_ext(command):
marcozecchini 0:9fca2b23d0ba 110 """ A version of run command that checks if the command exists befor running
marcozecchini 0:9fca2b23d0ba 111
marcozecchini 0:9fca2b23d0ba 112 Positional arguments:
marcozecchini 0:9fca2b23d0ba 113 command - the command line you are trying to invoke
marcozecchini 0:9fca2b23d0ba 114 """
marcozecchini 0:9fca2b23d0ba 115 assert is_cmd_valid(command[0])
marcozecchini 0:9fca2b23d0ba 116 process = Popen(command, stdout=PIPE, stderr=PIPE)
marcozecchini 0:9fca2b23d0ba 117 _stdout, _stderr = process.communicate()
marcozecchini 0:9fca2b23d0ba 118 return _stdout, _stderr, process.returncode
marcozecchini 0:9fca2b23d0ba 119
marcozecchini 0:9fca2b23d0ba 120
marcozecchini 0:9fca2b23d0ba 121 def is_cmd_valid(command):
marcozecchini 0:9fca2b23d0ba 122 """ Verify that a command exists and is executable
marcozecchini 0:9fca2b23d0ba 123
marcozecchini 0:9fca2b23d0ba 124 Positional arguments:
marcozecchini 0:9fca2b23d0ba 125 command - the command to check
marcozecchini 0:9fca2b23d0ba 126 """
marcozecchini 0:9fca2b23d0ba 127 caller = get_caller_name()
marcozecchini 0:9fca2b23d0ba 128 cmd_path = find_cmd_abspath(command)
marcozecchini 0:9fca2b23d0ba 129 if not cmd_path:
marcozecchini 0:9fca2b23d0ba 130 error("%s: Command '%s' can't be found" % (caller, command))
marcozecchini 0:9fca2b23d0ba 131 if not is_exec(cmd_path):
marcozecchini 0:9fca2b23d0ba 132 error("%s: Command '%s' resolves to file '%s' which is not executable"
marcozecchini 0:9fca2b23d0ba 133 % (caller, command, cmd_path))
marcozecchini 0:9fca2b23d0ba 134 return True
marcozecchini 0:9fca2b23d0ba 135
marcozecchini 0:9fca2b23d0ba 136
marcozecchini 0:9fca2b23d0ba 137 def is_exec(path):
marcozecchini 0:9fca2b23d0ba 138 """A simple check to verify that a path to an executable exists
marcozecchini 0:9fca2b23d0ba 139
marcozecchini 0:9fca2b23d0ba 140 Positional arguments:
marcozecchini 0:9fca2b23d0ba 141 path - the executable
marcozecchini 0:9fca2b23d0ba 142 """
marcozecchini 0:9fca2b23d0ba 143 return os.access(path, os.X_OK) or os.access(path+'.exe', os.X_OK)
marcozecchini 0:9fca2b23d0ba 144
marcozecchini 0:9fca2b23d0ba 145
marcozecchini 0:9fca2b23d0ba 146 def find_cmd_abspath(command):
marcozecchini 0:9fca2b23d0ba 147 """ Returns the absolute path to a command.
marcozecchini 0:9fca2b23d0ba 148 None is returned if no absolute path was found.
marcozecchini 0:9fca2b23d0ba 149
marcozecchini 0:9fca2b23d0ba 150 Positional arguhments:
marcozecchini 0:9fca2b23d0ba 151 command - the command to find the path of
marcozecchini 0:9fca2b23d0ba 152 """
marcozecchini 0:9fca2b23d0ba 153 if exists(command) or exists(command + '.exe'):
marcozecchini 0:9fca2b23d0ba 154 return os.path.abspath(command)
marcozecchini 0:9fca2b23d0ba 155 if not 'PATH' in os.environ:
marcozecchini 0:9fca2b23d0ba 156 raise Exception("Can't find command path for current platform ('%s')"
marcozecchini 0:9fca2b23d0ba 157 % sys.platform)
marcozecchini 0:9fca2b23d0ba 158 path_env = os.environ['PATH']
marcozecchini 0:9fca2b23d0ba 159 for path in path_env.split(os.pathsep):
marcozecchini 0:9fca2b23d0ba 160 cmd_path = '%s/%s' % (path, command)
marcozecchini 0:9fca2b23d0ba 161 if exists(cmd_path) or exists(cmd_path + '.exe'):
marcozecchini 0:9fca2b23d0ba 162 return cmd_path
marcozecchini 0:9fca2b23d0ba 163
marcozecchini 0:9fca2b23d0ba 164
marcozecchini 0:9fca2b23d0ba 165 def mkdir(path):
marcozecchini 0:9fca2b23d0ba 166 """ a wrapped makedirs that only tries to create a directory if it does not
marcozecchini 0:9fca2b23d0ba 167 exist already
marcozecchini 0:9fca2b23d0ba 168
marcozecchini 0:9fca2b23d0ba 169 Positional arguments:
marcozecchini 0:9fca2b23d0ba 170 path - the path to maybe create
marcozecchini 0:9fca2b23d0ba 171 """
marcozecchini 0:9fca2b23d0ba 172 if not exists(path):
marcozecchini 0:9fca2b23d0ba 173 makedirs(path)
marcozecchini 0:9fca2b23d0ba 174
marcozecchini 0:9fca2b23d0ba 175
marcozecchini 0:9fca2b23d0ba 176 def copy_file(src, dst):
marcozecchini 0:9fca2b23d0ba 177 """ Implement the behaviour of "shutil.copy(src, dst)" without copying the
marcozecchini 0:9fca2b23d0ba 178 permissions (this was causing errors with directories mounted with samba)
marcozecchini 0:9fca2b23d0ba 179
marcozecchini 0:9fca2b23d0ba 180 Positional arguments:
marcozecchini 0:9fca2b23d0ba 181 src - the source of the copy operation
marcozecchini 0:9fca2b23d0ba 182 dst - the destination of the copy operation
marcozecchini 0:9fca2b23d0ba 183 """
marcozecchini 0:9fca2b23d0ba 184 if isdir(dst):
marcozecchini 0:9fca2b23d0ba 185 _, base = split(src)
marcozecchini 0:9fca2b23d0ba 186 dst = join(dst, base)
marcozecchini 0:9fca2b23d0ba 187 copyfile(src, dst)
marcozecchini 0:9fca2b23d0ba 188
marcozecchini 0:9fca2b23d0ba 189
marcozecchini 0:9fca2b23d0ba 190 def delete_dir_files(directory):
marcozecchini 0:9fca2b23d0ba 191 """ A function that does rm -rf
marcozecchini 0:9fca2b23d0ba 192
marcozecchini 0:9fca2b23d0ba 193 Positional arguments:
marcozecchini 0:9fca2b23d0ba 194 directory - the directory to remove
marcozecchini 0:9fca2b23d0ba 195 """
marcozecchini 0:9fca2b23d0ba 196 if not exists(directory):
marcozecchini 0:9fca2b23d0ba 197 return
marcozecchini 0:9fca2b23d0ba 198
marcozecchini 0:9fca2b23d0ba 199 for element in listdir(directory):
marcozecchini 0:9fca2b23d0ba 200 to_remove = join(directory, element)
marcozecchini 0:9fca2b23d0ba 201 if not isdir(to_remove):
marcozecchini 0:9fca2b23d0ba 202 remove(to_remove)
marcozecchini 0:9fca2b23d0ba 203
marcozecchini 0:9fca2b23d0ba 204
marcozecchini 0:9fca2b23d0ba 205 def get_caller_name(steps=2):
marcozecchini 0:9fca2b23d0ba 206 """
marcozecchini 0:9fca2b23d0ba 207 When called inside a function, it returns the name
marcozecchini 0:9fca2b23d0ba 208 of the caller of that function.
marcozecchini 0:9fca2b23d0ba 209
marcozecchini 0:9fca2b23d0ba 210 Keyword arguments:
marcozecchini 0:9fca2b23d0ba 211 steps - the number of steps up the stack the calling function is
marcozecchini 0:9fca2b23d0ba 212 """
marcozecchini 0:9fca2b23d0ba 213 return inspect.stack()[steps][3]
marcozecchini 0:9fca2b23d0ba 214
marcozecchini 0:9fca2b23d0ba 215
marcozecchini 0:9fca2b23d0ba 216 def error(msg):
marcozecchini 0:9fca2b23d0ba 217 """Fatal error, abort hard
marcozecchini 0:9fca2b23d0ba 218
marcozecchini 0:9fca2b23d0ba 219 Positional arguments:
marcozecchini 0:9fca2b23d0ba 220 msg - the message to print before crashing
marcozecchini 0:9fca2b23d0ba 221 """
marcozecchini 0:9fca2b23d0ba 222 print("ERROR: %s" % msg)
marcozecchini 0:9fca2b23d0ba 223 sys.exit(1)
marcozecchini 0:9fca2b23d0ba 224
marcozecchini 0:9fca2b23d0ba 225
marcozecchini 0:9fca2b23d0ba 226 def rel_path(path, base, dot=False):
marcozecchini 0:9fca2b23d0ba 227 """Relative path calculation that optionaly always starts with a dot
marcozecchini 0:9fca2b23d0ba 228
marcozecchini 0:9fca2b23d0ba 229 Positional arguments:
marcozecchini 0:9fca2b23d0ba 230 path - the path to make relative
marcozecchini 0:9fca2b23d0ba 231 base - what to make the path relative to
marcozecchini 0:9fca2b23d0ba 232
marcozecchini 0:9fca2b23d0ba 233 Keyword arguments:
marcozecchini 0:9fca2b23d0ba 234 dot - if True, the path will always start with a './'
marcozecchini 0:9fca2b23d0ba 235 """
marcozecchini 0:9fca2b23d0ba 236 final_path = relpath(path, base)
marcozecchini 0:9fca2b23d0ba 237 if dot and not final_path.startswith('.'):
marcozecchini 0:9fca2b23d0ba 238 final_path = './' + final_path
marcozecchini 0:9fca2b23d0ba 239 return final_path
marcozecchini 0:9fca2b23d0ba 240
marcozecchini 0:9fca2b23d0ba 241
marcozecchini 0:9fca2b23d0ba 242 class ToolException(Exception):
marcozecchini 0:9fca2b23d0ba 243 """A class representing an exception throw by the tools"""
marcozecchini 0:9fca2b23d0ba 244 pass
marcozecchini 0:9fca2b23d0ba 245
marcozecchini 0:9fca2b23d0ba 246 class NotSupportedException(Exception):
marcozecchini 0:9fca2b23d0ba 247 """A class a toolchain not supporting a particular target"""
marcozecchini 0:9fca2b23d0ba 248 pass
marcozecchini 0:9fca2b23d0ba 249
marcozecchini 0:9fca2b23d0ba 250 class InvalidReleaseTargetException(Exception):
marcozecchini 0:9fca2b23d0ba 251 pass
marcozecchini 0:9fca2b23d0ba 252
marcozecchini 0:9fca2b23d0ba 253 def split_path(path):
marcozecchini 0:9fca2b23d0ba 254 """spilt a file name into it's directory name, base name, and extension
marcozecchini 0:9fca2b23d0ba 255
marcozecchini 0:9fca2b23d0ba 256 Positional arguments:
marcozecchini 0:9fca2b23d0ba 257 path - the file name to split
marcozecchini 0:9fca2b23d0ba 258 """
marcozecchini 0:9fca2b23d0ba 259 base, has_ext = split(path)
marcozecchini 0:9fca2b23d0ba 260 name, ext = splitext(has_ext)
marcozecchini 0:9fca2b23d0ba 261 return base, name, ext
marcozecchini 0:9fca2b23d0ba 262
marcozecchini 0:9fca2b23d0ba 263
marcozecchini 0:9fca2b23d0ba 264 def get_path_depth(path):
marcozecchini 0:9fca2b23d0ba 265 """ Given a path, return the number of directory levels present.
marcozecchini 0:9fca2b23d0ba 266 This roughly translates to the number of path separators (os.sep) + 1.
marcozecchini 0:9fca2b23d0ba 267 Ex. Given "path/to/dir", this would return 3
marcozecchini 0:9fca2b23d0ba 268 Special cases: "." and "/" return 0
marcozecchini 0:9fca2b23d0ba 269
marcozecchini 0:9fca2b23d0ba 270 Positional arguments:
marcozecchini 0:9fca2b23d0ba 271 path - the path to calculate the depth of
marcozecchini 0:9fca2b23d0ba 272 """
marcozecchini 0:9fca2b23d0ba 273 normalized_path = normpath(path)
marcozecchini 0:9fca2b23d0ba 274 path_depth = 0
marcozecchini 0:9fca2b23d0ba 275 head, tail = split(normalized_path)
marcozecchini 0:9fca2b23d0ba 276
marcozecchini 0:9fca2b23d0ba 277 while tail and tail != '.':
marcozecchini 0:9fca2b23d0ba 278 path_depth += 1
marcozecchini 0:9fca2b23d0ba 279 head, tail = split(head)
marcozecchini 0:9fca2b23d0ba 280
marcozecchini 0:9fca2b23d0ba 281 return path_depth
marcozecchini 0:9fca2b23d0ba 282
marcozecchini 0:9fca2b23d0ba 283
marcozecchini 0:9fca2b23d0ba 284 def args_error(parser, message):
marcozecchini 0:9fca2b23d0ba 285 """Abort with an error that was generated by the arguments to a CLI program
marcozecchini 0:9fca2b23d0ba 286
marcozecchini 0:9fca2b23d0ba 287 Positional arguments:
marcozecchini 0:9fca2b23d0ba 288 parser - the ArgumentParser object that parsed the command line
marcozecchini 0:9fca2b23d0ba 289 message - what went wrong
marcozecchini 0:9fca2b23d0ba 290 """
marcozecchini 0:9fca2b23d0ba 291 parser.error(message)
marcozecchini 0:9fca2b23d0ba 292 sys.exit(2)
marcozecchini 0:9fca2b23d0ba 293
marcozecchini 0:9fca2b23d0ba 294
marcozecchini 0:9fca2b23d0ba 295 def construct_enum(**enums):
marcozecchini 0:9fca2b23d0ba 296 """ Create your own pseudo-enums
marcozecchini 0:9fca2b23d0ba 297
marcozecchini 0:9fca2b23d0ba 298 Keyword arguments:
marcozecchini 0:9fca2b23d0ba 299 * - a member of the Enum you are creating and it's value
marcozecchini 0:9fca2b23d0ba 300 """
marcozecchini 0:9fca2b23d0ba 301 return type('Enum', (), enums)
marcozecchini 0:9fca2b23d0ba 302
marcozecchini 0:9fca2b23d0ba 303
marcozecchini 0:9fca2b23d0ba 304 def check_required_modules(required_modules, verbose=True):
marcozecchini 0:9fca2b23d0ba 305 """ Function checks for Python modules which should be "importable"
marcozecchini 0:9fca2b23d0ba 306 before test suite can be used.
marcozecchini 0:9fca2b23d0ba 307 @return returns True if all modules are installed already
marcozecchini 0:9fca2b23d0ba 308 """
marcozecchini 0:9fca2b23d0ba 309 import imp
marcozecchini 0:9fca2b23d0ba 310 not_installed_modules = []
marcozecchini 0:9fca2b23d0ba 311 for module_name in required_modules:
marcozecchini 0:9fca2b23d0ba 312 try:
marcozecchini 0:9fca2b23d0ba 313 imp.find_module(module_name)
marcozecchini 0:9fca2b23d0ba 314 except ImportError:
marcozecchini 0:9fca2b23d0ba 315 # We also test against a rare case: module is an egg file
marcozecchini 0:9fca2b23d0ba 316 try:
marcozecchini 0:9fca2b23d0ba 317 __import__(module_name)
marcozecchini 0:9fca2b23d0ba 318 except ImportError as exc:
marcozecchini 0:9fca2b23d0ba 319 not_installed_modules.append(module_name)
marcozecchini 0:9fca2b23d0ba 320 if verbose:
marcozecchini 0:9fca2b23d0ba 321 print "Error: %s" % exc
marcozecchini 0:9fca2b23d0ba 322
marcozecchini 0:9fca2b23d0ba 323 if verbose:
marcozecchini 0:9fca2b23d0ba 324 if not_installed_modules:
marcozecchini 0:9fca2b23d0ba 325 print ("Warning: Module(s) %s not installed. Please install " + \
marcozecchini 0:9fca2b23d0ba 326 "required module(s) before using this script.")\
marcozecchini 0:9fca2b23d0ba 327 % (', '.join(not_installed_modules))
marcozecchini 0:9fca2b23d0ba 328
marcozecchini 0:9fca2b23d0ba 329 if not_installed_modules:
marcozecchini 0:9fca2b23d0ba 330 return False
marcozecchini 0:9fca2b23d0ba 331 else:
marcozecchini 0:9fca2b23d0ba 332 return True
marcozecchini 0:9fca2b23d0ba 333
marcozecchini 0:9fca2b23d0ba 334 def dict_to_ascii(dictionary):
marcozecchini 0:9fca2b23d0ba 335 """ Utility function: traverse a dictionary and change all the strings in
marcozecchini 0:9fca2b23d0ba 336 the dictionary to ASCII from Unicode. Useful when reading ASCII JSON data,
marcozecchini 0:9fca2b23d0ba 337 because the JSON decoder always returns Unicode string. Based on
marcozecchini 0:9fca2b23d0ba 338 http://stackoverflow.com/a/13105359
marcozecchini 0:9fca2b23d0ba 339
marcozecchini 0:9fca2b23d0ba 340 Positional arguments:
marcozecchini 0:9fca2b23d0ba 341 dictionary - The dict that contains some Unicode that should be ASCII
marcozecchini 0:9fca2b23d0ba 342 """
marcozecchini 0:9fca2b23d0ba 343 if isinstance(dictionary, dict):
marcozecchini 0:9fca2b23d0ba 344 return OrderedDict([(dict_to_ascii(key), dict_to_ascii(value))
marcozecchini 0:9fca2b23d0ba 345 for key, value in dictionary.iteritems()])
marcozecchini 0:9fca2b23d0ba 346 elif isinstance(dictionary, list):
marcozecchini 0:9fca2b23d0ba 347 return [dict_to_ascii(element) for element in dictionary]
marcozecchini 0:9fca2b23d0ba 348 elif isinstance(dictionary, unicode):
marcozecchini 0:9fca2b23d0ba 349 return dictionary.encode('ascii')
marcozecchini 0:9fca2b23d0ba 350 else:
marcozecchini 0:9fca2b23d0ba 351 return dictionary
marcozecchini 0:9fca2b23d0ba 352
marcozecchini 0:9fca2b23d0ba 353 def json_file_to_dict(fname):
marcozecchini 0:9fca2b23d0ba 354 """ Read a JSON file and return its Python representation, transforming all
marcozecchini 0:9fca2b23d0ba 355 the strings from Unicode to ASCII. The order of keys in the JSON file is
marcozecchini 0:9fca2b23d0ba 356 preserved.
marcozecchini 0:9fca2b23d0ba 357
marcozecchini 0:9fca2b23d0ba 358 Positional arguments:
marcozecchini 0:9fca2b23d0ba 359 fname - the name of the file to parse
marcozecchini 0:9fca2b23d0ba 360 """
marcozecchini 0:9fca2b23d0ba 361 try:
marcozecchini 0:9fca2b23d0ba 362 with open(fname, "r") as file_obj:
marcozecchini 0:9fca2b23d0ba 363 return dict_to_ascii(json.load(file_obj,
marcozecchini 0:9fca2b23d0ba 364 object_pairs_hook=OrderedDict))
marcozecchini 0:9fca2b23d0ba 365 except (ValueError, IOError):
marcozecchini 0:9fca2b23d0ba 366 sys.stderr.write("Error parsing '%s':\n" % fname)
marcozecchini 0:9fca2b23d0ba 367 raise
marcozecchini 0:9fca2b23d0ba 368
marcozecchini 0:9fca2b23d0ba 369 # Wowza, double closure
marcozecchini 0:9fca2b23d0ba 370 def argparse_type(casedness, prefer_hyphen=False):
marcozecchini 0:9fca2b23d0ba 371 def middle(lst, type_name):
marcozecchini 0:9fca2b23d0ba 372 def parse_type(string):
marcozecchini 0:9fca2b23d0ba 373 """ validate that an argument passed in (as string) is a member of
marcozecchini 0:9fca2b23d0ba 374 the list of possible arguments. Offer a suggestion if the case of
marcozecchini 0:9fca2b23d0ba 375 the string, or the hyphens/underscores do not match the expected
marcozecchini 0:9fca2b23d0ba 376 style of the argument.
marcozecchini 0:9fca2b23d0ba 377 """
marcozecchini 0:9fca2b23d0ba 378 if prefer_hyphen:
marcozecchini 0:9fca2b23d0ba 379 newstring = casedness(string).replace("_", "-")
marcozecchini 0:9fca2b23d0ba 380 else:
marcozecchini 0:9fca2b23d0ba 381 newstring = casedness(string).replace("-", "_")
marcozecchini 0:9fca2b23d0ba 382 if string in lst:
marcozecchini 0:9fca2b23d0ba 383 return string
marcozecchini 0:9fca2b23d0ba 384 elif string not in lst and newstring in lst:
marcozecchini 0:9fca2b23d0ba 385 raise argparse.ArgumentTypeError(
marcozecchini 0:9fca2b23d0ba 386 "{0} is not a supported {1}. Did you mean {2}?".format(
marcozecchini 0:9fca2b23d0ba 387 string, type_name, newstring))
marcozecchini 0:9fca2b23d0ba 388 else:
marcozecchini 0:9fca2b23d0ba 389 raise argparse.ArgumentTypeError(
marcozecchini 0:9fca2b23d0ba 390 "{0} is not a supported {1}. Supported {1}s are:\n{2}".
marcozecchini 0:9fca2b23d0ba 391 format(string, type_name, columnate(lst)))
marcozecchini 0:9fca2b23d0ba 392 return parse_type
marcozecchini 0:9fca2b23d0ba 393 return middle
marcozecchini 0:9fca2b23d0ba 394
marcozecchini 0:9fca2b23d0ba 395 # short cuts for the argparse_type versions
marcozecchini 0:9fca2b23d0ba 396 argparse_uppercase_type = argparse_type(str.upper, False)
marcozecchini 0:9fca2b23d0ba 397 argparse_lowercase_type = argparse_type(str.lower, False)
marcozecchini 0:9fca2b23d0ba 398 argparse_uppercase_hyphen_type = argparse_type(str.upper, True)
marcozecchini 0:9fca2b23d0ba 399 argparse_lowercase_hyphen_type = argparse_type(str.lower, True)
marcozecchini 0:9fca2b23d0ba 400
marcozecchini 0:9fca2b23d0ba 401 def argparse_force_type(case):
marcozecchini 0:9fca2b23d0ba 402 """ validate that an argument passed in (as string) is a member of the list
marcozecchini 0:9fca2b23d0ba 403 of possible arguments after converting it's case.
marcozecchini 0:9fca2b23d0ba 404 """
marcozecchini 0:9fca2b23d0ba 405 def middle(lst, type_name):
marcozecchini 0:9fca2b23d0ba 406 """ The parser type generator"""
marcozecchini 0:9fca2b23d0ba 407 def parse_type(string):
marcozecchini 0:9fca2b23d0ba 408 """ The parser type"""
marcozecchini 0:9fca2b23d0ba 409 for option in lst:
marcozecchini 0:9fca2b23d0ba 410 if case(string) == case(option):
marcozecchini 0:9fca2b23d0ba 411 return option
marcozecchini 0:9fca2b23d0ba 412 raise argparse.ArgumentTypeError(
marcozecchini 0:9fca2b23d0ba 413 "{0} is not a supported {1}. Supported {1}s are:\n{2}".
marcozecchini 0:9fca2b23d0ba 414 format(string, type_name, columnate(lst)))
marcozecchini 0:9fca2b23d0ba 415 return parse_type
marcozecchini 0:9fca2b23d0ba 416 return middle
marcozecchini 0:9fca2b23d0ba 417
marcozecchini 0:9fca2b23d0ba 418 # these two types convert the case of their arguments _before_ validation
marcozecchini 0:9fca2b23d0ba 419 argparse_force_uppercase_type = argparse_force_type(str.upper)
marcozecchini 0:9fca2b23d0ba 420 argparse_force_lowercase_type = argparse_force_type(str.lower)
marcozecchini 0:9fca2b23d0ba 421
marcozecchini 0:9fca2b23d0ba 422 def argparse_many(func):
marcozecchini 0:9fca2b23d0ba 423 """ An argument parser combinator that takes in an argument parser and
marcozecchini 0:9fca2b23d0ba 424 creates a new parser that accepts a comma separated list of the same thing.
marcozecchini 0:9fca2b23d0ba 425 """
marcozecchini 0:9fca2b23d0ba 426 def wrap(string):
marcozecchini 0:9fca2b23d0ba 427 """ The actual parser"""
marcozecchini 0:9fca2b23d0ba 428 return [func(s) for s in string.split(",")]
marcozecchini 0:9fca2b23d0ba 429 return wrap
marcozecchini 0:9fca2b23d0ba 430
marcozecchini 0:9fca2b23d0ba 431 def argparse_filestring_type(string):
marcozecchini 0:9fca2b23d0ba 432 """ An argument parser that verifies that a string passed in corresponds
marcozecchini 0:9fca2b23d0ba 433 to a file"""
marcozecchini 0:9fca2b23d0ba 434 if exists(string):
marcozecchini 0:9fca2b23d0ba 435 return string
marcozecchini 0:9fca2b23d0ba 436 else:
marcozecchini 0:9fca2b23d0ba 437 raise argparse.ArgumentTypeError(
marcozecchini 0:9fca2b23d0ba 438 "{0}"" does not exist in the filesystem.".format(string))
marcozecchini 0:9fca2b23d0ba 439
marcozecchini 0:9fca2b23d0ba 440 def argparse_profile_filestring_type(string):
marcozecchini 0:9fca2b23d0ba 441 """ An argument parser that verifies that a string passed in is either
marcozecchini 0:9fca2b23d0ba 442 absolute path or a file name (expanded to
marcozecchini 0:9fca2b23d0ba 443 mbed-os/tools/profiles/<fname>.json) of a existing file"""
marcozecchini 0:9fca2b23d0ba 444 fpath = join(dirname(__file__), "profiles/{}.json".format(string))
marcozecchini 0:9fca2b23d0ba 445 if exists(string):
marcozecchini 0:9fca2b23d0ba 446 return string
marcozecchini 0:9fca2b23d0ba 447 elif exists(fpath):
marcozecchini 0:9fca2b23d0ba 448 return fpath
marcozecchini 0:9fca2b23d0ba 449 else:
marcozecchini 0:9fca2b23d0ba 450 raise argparse.ArgumentTypeError(
marcozecchini 0:9fca2b23d0ba 451 "{0} does not exist in the filesystem.".format(string))
marcozecchini 0:9fca2b23d0ba 452
marcozecchini 0:9fca2b23d0ba 453 def columnate(strings, separator=", ", chars=80):
marcozecchini 0:9fca2b23d0ba 454 """ render a list of strings as a in a bunch of columns
marcozecchini 0:9fca2b23d0ba 455
marcozecchini 0:9fca2b23d0ba 456 Positional arguments:
marcozecchini 0:9fca2b23d0ba 457 strings - the strings to columnate
marcozecchini 0:9fca2b23d0ba 458
marcozecchini 0:9fca2b23d0ba 459 Keyword arguments;
marcozecchini 0:9fca2b23d0ba 460 separator - the separation between the columns
marcozecchini 0:9fca2b23d0ba 461 chars - the maximum with of a row
marcozecchini 0:9fca2b23d0ba 462 """
marcozecchini 0:9fca2b23d0ba 463 col_width = max(len(s) for s in strings)
marcozecchini 0:9fca2b23d0ba 464 total_width = col_width + len(separator)
marcozecchini 0:9fca2b23d0ba 465 columns = math.floor(chars / total_width)
marcozecchini 0:9fca2b23d0ba 466 output = ""
marcozecchini 0:9fca2b23d0ba 467 for i, string in zip(range(len(strings)), strings):
marcozecchini 0:9fca2b23d0ba 468 append = string
marcozecchini 0:9fca2b23d0ba 469 if i != len(strings) - 1:
marcozecchini 0:9fca2b23d0ba 470 append += separator
marcozecchini 0:9fca2b23d0ba 471 if i % columns == columns - 1:
marcozecchini 0:9fca2b23d0ba 472 append += "\n"
marcozecchini 0:9fca2b23d0ba 473 else:
marcozecchini 0:9fca2b23d0ba 474 append = append.ljust(total_width)
marcozecchini 0:9fca2b23d0ba 475 output += append
marcozecchini 0:9fca2b23d0ba 476 return output
marcozecchini 0:9fca2b23d0ba 477
marcozecchini 0:9fca2b23d0ba 478 def argparse_dir_not_parent(other):
marcozecchini 0:9fca2b23d0ba 479 """fail if argument provided is a parent of the specified directory"""
marcozecchini 0:9fca2b23d0ba 480 def parse_type(not_parent):
marcozecchini 0:9fca2b23d0ba 481 """The parser type"""
marcozecchini 0:9fca2b23d0ba 482 abs_other = abspath(other)
marcozecchini 0:9fca2b23d0ba 483 abs_not_parent = abspath(not_parent)
marcozecchini 0:9fca2b23d0ba 484 if abs_not_parent == commonprefix([abs_not_parent, abs_other]):
marcozecchini 0:9fca2b23d0ba 485 raise argparse.ArgumentTypeError(
marcozecchini 0:9fca2b23d0ba 486 "{0} may not be a parent directory of {1}".format(
marcozecchini 0:9fca2b23d0ba 487 not_parent, other))
marcozecchini 0:9fca2b23d0ba 488 else:
marcozecchini 0:9fca2b23d0ba 489 return not_parent
marcozecchini 0:9fca2b23d0ba 490 return parse_type
marcozecchini 0:9fca2b23d0ba 491
marcozecchini 0:9fca2b23d0ba 492 def argparse_deprecate(replacement_message):
marcozecchini 0:9fca2b23d0ba 493 """fail if argument is provided with deprecation warning"""
marcozecchini 0:9fca2b23d0ba 494 def parse_type(_):
marcozecchini 0:9fca2b23d0ba 495 """The parser type"""
marcozecchini 0:9fca2b23d0ba 496 raise argparse.ArgumentTypeError("Deprecated." + replacement_message)
marcozecchini 0:9fca2b23d0ba 497 return parse_type
marcozecchini 0:9fca2b23d0ba 498
marcozecchini 0:9fca2b23d0ba 499 def print_large_string(large_string):
marcozecchini 0:9fca2b23d0ba 500 """ Breaks a string up into smaller pieces before print them
marcozecchini 0:9fca2b23d0ba 501
marcozecchini 0:9fca2b23d0ba 502 This is a limitation within Windows, as detailed here:
marcozecchini 0:9fca2b23d0ba 503 https://bugs.python.org/issue11395
marcozecchini 0:9fca2b23d0ba 504
marcozecchini 0:9fca2b23d0ba 505 Positional arguments:
marcozecchini 0:9fca2b23d0ba 506 large_string - the large string to print
marcozecchini 0:9fca2b23d0ba 507 """
marcozecchini 0:9fca2b23d0ba 508 string_limit = 1000
marcozecchini 0:9fca2b23d0ba 509 large_string_len = len(large_string)
marcozecchini 0:9fca2b23d0ba 510 num_parts = int(ceil(float(large_string_len) / float(string_limit)))
marcozecchini 0:9fca2b23d0ba 511 for string_part in range(num_parts):
marcozecchini 0:9fca2b23d0ba 512 start_index = string_part * string_limit
marcozecchini 0:9fca2b23d0ba 513 if string_part == num_parts - 1:
marcozecchini 0:9fca2b23d0ba 514 sys.stdout.write(large_string[start_index:])
marcozecchini 0:9fca2b23d0ba 515 else:
marcozecchini 0:9fca2b23d0ba 516 sys.stdout.write(large_string[start_index:
marcozecchini 0:9fca2b23d0ba 517 start_index + string_limit])
marcozecchini 0:9fca2b23d0ba 518 sys.stdout.write("\n")
marcozecchini 0:9fca2b23d0ba 519
marcozecchini 0:9fca2b23d0ba 520 def intelhex_offset(filename, offset):
marcozecchini 0:9fca2b23d0ba 521 """Load a hex or bin file at a particular offset"""
marcozecchini 0:9fca2b23d0ba 522 _, inteltype = splitext(filename)
marcozecchini 0:9fca2b23d0ba 523 ih = IntelHex()
marcozecchini 0:9fca2b23d0ba 524 if inteltype == ".bin":
marcozecchini 0:9fca2b23d0ba 525 ih.loadbin(filename, offset=offset)
marcozecchini 0:9fca2b23d0ba 526 elif inteltype == ".hex":
marcozecchini 0:9fca2b23d0ba 527 ih.loadhex(filename)
marcozecchini 0:9fca2b23d0ba 528 else:
marcozecchini 0:9fca2b23d0ba 529 raise ToolException("File %s does not have a known binary file type"
marcozecchini 0:9fca2b23d0ba 530 % filename)
marcozecchini 0:9fca2b23d0ba 531 return ih