mbed-os for GR-LYCHEE

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

Committer:
dkato
Date:
Fri Feb 02 05:42:23 2018 +0000
Revision:
0:f782d9c66c49
mbed-os for GR-LYCHEE

Who changed what in which revision?

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