init

Dependencies:   mbed

Committer:
Nathan Yonkee
Date:
Fri Mar 02 07:12:37 2018 -0700
Revision:
9:d58e77ebd769
add mbed-os library

Who changed what in which revision?

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