Backup 1

Committer:
borlanic
Date:
Tue Apr 24 11:45:18 2018 +0000
Revision:
0:02dd72d1d465
BaBoRo_test2 - backup 1

Who changed what in which revision?

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