Development mbed library for MAX32630FTHR

Dependents:   blinky_max32630fthr

Committer:
switches
Date:
Fri Dec 16 16:27:57 2016 +0000
Revision:
3:1198227e6421
Parent:
0:5c4d7b2438d3
Changed ADC scale for MAX32625 platforms to 1.2V full scale to match MAX32630 platforms

Who changed what in which revision?

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