def build(name, ask=True, **kwargs): """ Build the malicious mote to its target hardware. :param name: experiment name (or absolute path to experiment) :param ask: ask confirmation :param path: expanded path of the experiment (dynamically filled in through 'command' decorator with 'expand' """ def is_device_present(): with settings(hide(*HIDDEN_ALL), warn_only=True): return local( "if [ -c /dev/ttyUSB0 ]; then echo 'ok'; else echo 'nok'; fi", capture=True) == 'ok' console = kwargs.get('console') counter, interval = 0.0, 0.5 while not is_device_present(): sleep(interval) counter += interval if counter % 5 == 0: logger.warning("Waiting for mote to be detected...") elif counter >= 120: logger.error( "Something failed with the mote ; check that it mounts to /dev/ttyUSB0" ) return remake(name, build=True, ** kwargs) if console is None else console.do_remake( name, build=True, **kwargs)
def get_constants_and_replacements(blocks): """ This function retrieves the constants and replacements corresponding to the building blocks provided in input. :param blocks: input building blocks :return: corresponding constants and replacements to be made in ContikiRPL files """ available_blocks = get_building_blocks() constants, replacements = {}, {} for block in blocks: for key, value in available_blocks[block].items(): # e.g. {"RPL_CONF_MIN_HOPRANKINC": 128} will be collected in constants if key.upper() == key and not (key.endswith('.c') or key.endswith('.h')): if key in constants.keys(): logger.warning( " > Building-block '{}': '{}' is already set to {}". format(block, key, value)) else: constants[key] = value # else, it is a replacement in a file, e.g. {"rpl-icmp6.c": ["dag->version", "dag->version++"]} else: if key in replacements.keys() and value[0] in [ srcl for srcl, dstl in replacements.values() ]: logger.warning( " > Building-block '{}': line '{}' is already replaced in {}" .format(block, value[0], key)) else: replacements[key] = value return constants, replacements
def get_parameter(dictionary, section, key, condition, reason=None, default=None): """ This function checks and returns a validated value for the given parameter. :param dictionary: dictionary of parameters :param section: section in the dictionary :param key: key of the related parameter :param condition: validation condition :param reason: message to be displayed in case of test failure :param default: default value to be used in last resort :return: validated parameter """ silent = dictionary.pop('silent', False) param = (dictionary.get(section) or {}).get(key) or DEFAULTS.get(key) if param is None and default is not None: param = default if isinstance(condition, list) and isinstance(param, list): buffer = [] for p in param: if not condition[0](p): if not silent: logger.warning("Parameter [{} -> {}] '{}' does not exist (removed)" .format(section, key, p)) else: buffer.append(p) return buffer else: if not condition(param): if not silent: logger.warning("Parameter [{} -> {}] {} (set to default: {})" .format(section, key, reason, DEFAULTS[key])) param = DEFAULTS[key] return param
def get_constants_and_replacements(blocks): """ This function retrieves the constants and replacements corresponding to the building blocks provided in input. :param blocks: input building blocks :return: corresponding constants and replacements to be made in ContikiRPL files """ available_blocks = get_building_blocks() constants, replacements = {}, {} for block in blocks: for key, value in available_blocks[block].items(): # e.g. {"RPL_CONF_MIN_HOPRANKINC": 128} will be collected in constants if key.upper() == key and not (key.endswith('.c') or key.endswith('.h')): if key in constants.keys(): logger.warning(" > Building-block '{}': '{}' is already set to {}".format(block, key, value)) else: constants[key] = value # else, it is a replacement in a file, e.g. {"rpl-icmp6.c": ["dag->version", "dag->version++"]} else: if key in replacements.keys() and value[0] in [srcl for srcl, dstl in replacements.values()]: logger.warning(" > Building-block '{}': line '{}' is already replaced in {}" .format(block, value[0], key)) else: replacements[key] = value return constants, replacements
def get_parameter(dictionary, section, key, condition, reason=None, default=None): """ This function checks and returns a validated value for the given parameter. :param dictionary: dictionary of parameters :param section: section in the dictionary :param key: key of the related parameter :param condition: validation condition :param reason: message to be displayed in case of test failure :param default: default value to be used in last resort :return: validated parameter """ silent = dictionary.pop('silent', False) param = (dictionary.get(section) or {}).get(key) or DEFAULTS.get(key) if param is None and default is not None: param = default if isinstance(condition, list) and isinstance(param, list): buffer = [] for p in param: if not condition[0](p): if not silent: logger.warning("Parameter [{} -> {}] '{}' does not exist (removed)" .format(section, key, p)) else: buffer.append(p) return buffer else: if not condition(param): if not silent: logger.warning("Parameter [{} -> {}] {} (set to default: {})" .format(section, key, reason, DEFAULTS[key])) param = DEFAULTS[key] return param
def setup(silent=False, **kwargs): """ Setup the framework. """ recompile = False # install Cooja modifications if not check_cooja(COOJA_FOLDER): logger.debug(" > Installing Cooja add-ons...") # modify Cooja.java and adapt build.xml and ~/.cooja.user.properties modify_cooja(COOJA_FOLDER) update_cooja_build(COOJA_FOLDER) update_cooja_user_properties() recompile = True # install VisualizerScreenshot plugin in Cooja visualizer = join(COOJA_FOLDER, 'apps', 'visualizer_screenshot') if not exists(visualizer): logger.debug(" > Installing VisualizerScreenshot Cooja plugin...") copy_folder('src/visualizer_screenshot', visualizer) recompile = True # recompile Cooja for making the changes take effect if recompile: with lcd(COOJA_FOLDER): logger.debug(" > Recompiling Cooja...") with settings(warn_only=True): local("ant clean") local("ant jar") else: logger.debug(" > Cooja is up-to-date") # install imagemagick with hide(*HIDDEN_ALL): imagemagick_apt_output = local('apt-cache policy imagemagick', capture=True) if 'Unable to locate package' in imagemagick_apt_output: logger.debug(" > Installing imagemagick package...") sudo("apt-get install imagemagick -y &") else: logger.debug(" > Imagemagick is installed") # install msp430 (GCC) upgrade with hide(*HIDDEN_ALL): msp430_version_output = local('msp430-gcc --version', capture=True) if 'msp430-gcc (GCC) 4.7.0 20120322' not in msp430_version_output: txt = "In order to extend msp430x memory support, it is necessary to upgrade msp430-gcc.\n" \ "Would you like to upgrade it now ? (yes|no) [default: no] " answer = std_input(txt, 'yellow') if answer == "yes": logger.debug(" > Upgrading msp430-gcc from version 4.6.3 to 4.7.0...") logger.warning("If you encounter problems with this upgrade, please refer to:\n" "https://github.com/contiki-os/contiki/wiki/MSP430X") with lcd('src/'): logger.warning(" > Upgrade now starts, this may take up to 30 minutes...") sudo('./upgrade-msp430.sh') sudo('rm -r tmp/') local('export PATH=/usr/local/msp430/bin:$PATH') register_new_path_in_profile() else: logger.warning("Upgrade of library msp430-gcc aborted") logger.warning("You may experience problems of mote memory size at compilation") else: logger.debug(" > Library msp430-gcc is up-to-date (version 4.7.0)")
def graceful_exit(self): """ Exit handler for terminating the process pool gracefully. """ if 'PENDING' in [x['status'] for x in self.tasklist.values()]: logger.info(" > Waiting for opened processes to finish...") logger.warning("Hit CTRL+C a second time to force process termination.") try: self.pool.close() self.pool.join() except KeyboardInterrupt: logger.info(" > Terminating opened processes...") for task_obj in self.tasklist.keys(): try: task_obj.task.get(1) except TimeoutError: pass self.pool.terminate() self.pool.join()
def get_experiments(exp_file, silent=False): """ This function retrieves the dictionary of experiments with their parameters from a JSON campaign file. :param exp_file: input JSON simulation campaign file :param silent: specify whether an eventual error is to be raised or not :return: dictionary with the parsed experiments and their parameters """ if dirname(exp_file) == '': exp_file = join(EXPERIMENT_FOLDER, exp_file) exp_file = expanduser(exp_file) if not exp_file.endswith(".json"): exp_file += ".json" if not exists(exp_file): logger.critical("Simulation campaign JSON file does not exist !") logger.warning("Make sure you've generated a JSON simulation campaign file by using 'prepare' fabric command.") return return is_valid_commented_json(exp_file, return_json=True, logger=logger if not silent else None) or {}
def get_experiments(exp_file, silent=False): """ This function retrieves the dictionary of experiments with their parameters from a JSON campaign file. :param exp_file: input JSON simulation campaign file :param silent: specify whether an eventual error is to be raised or not :return: dictionary with the parsed experiments and their parameters """ if dirname(exp_file) == '': exp_file = join(EXPERIMENT_FOLDER, exp_file) exp_file = expanduser(exp_file) if not exp_file.endswith(".json"): exp_file += ".json" if not exists(exp_file): logger.critical("Simulation campaign JSON file does not exist !") logger.warning("Make sure you've generated a JSON simulation campaign file by using 'prepare' fabric command.") return return is_valid_commented_json(exp_file, return_json=True, logger=logger if not silent else None) or {}
def get_experiments(exp_file): """ This function retrieves the dictionary of experiments with their parameters from a JSON campaign file. :param exp_file: input JSON simulation campaign file :return: dictionary with the parsed experiments and their parameters """ if dirname(exp_file) == '': exp_file = join(EXPERIMENT_FOLDER, exp_file) exp_file = expanduser(exp_file) if not exp_file.endswith(".json"): exp_file += ".json" if not exists(exp_file): logger.critical("Simulation campaign JSON file does not exist !") logger.warning( "Make sure you've generated a JSON simulation campaign file by using 'prepare' fabric command." ) return with open(exp_file) as f: experiments = loads(jsmin(f.read())) return experiments
def graceful_exit(self): """ Exit handler for terminating the process pool gracefully. """ if 'PENDING' in [x['status'] for x in self.tasklist.values()]: logger.info(" > Waiting for opened processes to finish...") logger.warning( "Hit CTRL+C a second time to force process termination.") try: for task_obj in self.tasklist.keys(): # see: http://stackoverflow.com/questions/1408356/keyboard-interrupts-with-pythons-multiprocessing-pool # "The KeyboardInterrupt exception won't be delivered until wait() returns, and it never returns, # so the interrupt never happens. KeyboardInterrupt should almost certainly interrupt a condition # wait. Note that this doesn't happen if a timeout is specified; cond.wait(1) will receive the # interrupt immediately. So, a workaround is to specify a timeout." task_obj.task.get(999999) self.pool.close() #self.pool.join() except KeyboardInterrupt: logger.info(" > Terminating opened processes...") for task_obj in self.tasklist.keys(): task_obj.kill() self.pool.terminate() self.pool.join() if not self.already_running: os.remove(PIDFILE)
def wrapper(*args, **kwargs): """ This is the wrapper for the 'command' decorator, handling the following execution flow : - It first determines if this command is used with a console - In case of console, it performs a lexical analysis - Anyway, it performs a signature checking - It handles 'expand' parameter - It then handles 'exists' and 'not_exists' (in this order) - It finally selects the right behavior using 'behavior' """ # specific argument existence check through the 'not_exists' and 'exists' attributes def get_ask(): if attrs['on_boolean'] in kwargs.keys(): return kwargs[attrs['on_boolean']] try: param = sig.parameters[attrs['on_boolean']] try: return args[list(sig.parameters.values()).index(param)] except ( IndexError, ValueError ): # occurs if 'ask' was not specified in the arguments ; # in this case, take the default value from the signature return param.default except KeyError: # occurs if no 'ask' parameter is in the signature return False # log message formatting with specified arguments from 'args' or 'kwargs' def log_msg(lvl, msg): if kwargs.get('silent'): return if isinstance(msg, tuple): values = [] for a in msg[1:]: try: values.append(args[list( sig.parameters.keys()).index(a)]) except KeyError: value = kwargs.get(a) if value is not None: values.append(value) getattr(logger, lvl)(msg[0].format(*values)) else: getattr(logger, lvl)(msg) console = args[0] if len(args) > 0 and isinstance(args[0], Cmd) else None if console is not None: kwargs['console'] = console # lexical analysis if len(args) > 1 and console is not None: line = args[1] kwargs_tmp = {k: v for k, v in kwargs.items()} args, kwargs = lexer.analyze(line) if args is None and kwargs is None: print( console.badcmd_msg.format( "Invalid", '{} {}'.format(f.__name__, line))) return kwargs.update(kwargs_tmp) # bad signature check sig = signature(f) args = () if args == ( '', ) else args # occurs in case of Cmd ; an empty 'line' can be passed if a # command is called without any argument # - first, exclude variable arguments and keyword-arguments no_var_args = [ p for p in list(sig.parameters.values()) if not str(p).startswith('*') ] # - then, retrieve arguments without default values no_def_args = [p for p in no_var_args if p.default is not p.empty] # - now, if less input arguments are provided than the number of arguments without default value, # display an error if len(args) < len(no_var_args) - len(no_def_args): logger.critical("Bad input arguments !") logger.info( "This command has the following signature: {}{}".format( f.__name__, str(sig).replace(', **kwargs', ''))) logger.info( "Please check the documentation for more information.") return # expand a specified argument to a path if hasattr(f, 'expand'): arg, attrs = f.expand arg_idx = list(sig.parameters.keys()).index(arg) try: expanded = expanduser(join(attrs['into'], args[arg_idx])) except IndexError: # occurs when arg_idx out of range of args, meaning that the argument to be # expanded was not provided return # if an extension was provided and the file path does not end with it, just append it if attrs.get('ext') and not expanded.endswith("." + attrs['ext']): expanded += "." + attrs['ext'] # the expanded argument must not be saved to a new argument name, just replace its old value if attrs.get('new_arg') is None: args = tuple([ a if i != arg_idx else expanded for i, a in enumerate(args) ]) # otherwise, create the new argument if the name is not used yet elif attrs['new_arg'] not in list(sig.parameters.keys()): kwargs[attrs['new_arg']] = expanded if attrs.get( 'apply') is None else attrs['apply'](expanded) # when no 'path' kwarg is set, it must be added based on the direcotory name of the expanded arg if 'path' not in kwargs.keys(): kwargs['path'] = dirname(expanded) # if next commands require sudo, prompt now for privilege elevation if getattr(f, 'requires_sudo', False): system('sudo ls > /dev/null') # check for existence (or not) and ask for a confirmation to continue if required for fattr in ['exists', 'not_exists']: if hasattr(f, fattr): arg, attrs = getattr(f, fattr) try: arg_val = args[list(sig.parameters.keys()).index(arg)] except ValueError: arg_val = kwargs[arg] if (fattr == 'exists' and exists(arg_val)) or (fattr == 'not_exists' and not exists(arg_val)): if 'loglvl' in attrs.keys() and 'msg' in attrs.keys(): log_msg(attrs['loglvl'], attrs['msg']) if attrs.get('loglvl') in ('error', 'critical') or \ ((attrs.get('loglvl') in ('warning', 'info') or fattr == 'exists') and get_ask() and attrs.get('confirm') is not None and not std_input(attrs['confirm'], 'yellow') == 'yes'): return # run the command and catch exception if any if console is not None and len(args) > 0: console.clean_tasks() pending_tasks = { i['name']: str(o) for o, i in console.tasklist.items() if i['status'] == 'PENDING' } if args[0] not in pending_tasks.keys(): if hasattr(f, 'start_msg'): log_msg('info', f.start_msg) kwargs['task'] = f.__name__.lstrip('_') f.behavior( console, f.__base__ if f.behavior is MultiprocessedCommand else f, args[0], kwargs.get('path')).run(*args, **kwargs) else: logger.warning( "A task is still pending on this experiment ({})". format(pending_tasks[args[0]])) else: if hasattr(f, 'start_msg'): log_msg('info', f.start_msg) f(*args, **kwargs)
def wrapper(*args, **kwargs): """ This is the wrapper for the 'command' decorator, handling the following execution flow : - It first determines if this command is used with a console - In case of console, it performs a lexical analysis - Anyway, it performs a signature checking - It handles 'expand' parameter - It then handles 'exists' and 'not_exists' (in this order) - It finally selects the right behavior using 'behavior' """ # specific argument existence check through the 'not_exists' and 'exists' attributes def get_ask(): if attrs['on_boolean'] in kwargs.keys(): return kwargs[attrs['on_boolean']] try: param = sig.parameters[attrs['on_boolean']] try: return args[list(sig.parameters.values()).index(param)] except (IndexError, ValueError): # occurs if 'ask' was not specified in the arguments ; # in this case, take the default value from the signature return param.default except KeyError: # occurs if no 'ask' parameter is in the signature return False # log message formatting with specified arguments from 'args' or 'kwargs' def log_msg(lvl, msg): if kwargs.get('silent'): return if isinstance(msg, tuple): values = [] for a in msg[1:]: try: values.append(args[list(sig.parameters.keys()).index(a)]) except KeyError: value = kwargs.get(a) if value is not None: values.append(value) getattr(logger, lvl)(msg[0].format(*values)) else: getattr(logger, lvl)(msg) console = args[0] if len(args) > 0 and isinstance(args[0], Cmd) else None if console is not None: kwargs['console'] = console # lexical analysis if len(args) > 1 and console is not None: line = args[1] kwargs_tmp = {k: v for k, v in kwargs.items()} args, kwargs = lexer.analyze(line) if args is None and kwargs is None: print(console.badcmd_msg.format("Invalid", '{} {}'.format(f.__name__, line))) return kwargs.update(kwargs_tmp) # bad signature check sig = signature(f) args = () if args == ('',) else args # occurs in case of Cmd ; an empty 'line' can be passed if a # command is called without any argument # - first, exclude variable arguments and keyword-arguments no_var_args = [p for p in list(sig.parameters.values()) if not str(p).startswith('*')] # - then, retrieve arguments without default values no_def_args = [p for p in no_var_args if p.default is not p.empty] # - now, if less input arguments are provided than the number of arguments without default value, # display an error if len(args) < len(no_var_args) - len(no_def_args): logger.critical("Bad input arguments !") logger.info("This command has the following signature: {}{}" .format(f.__name__, str(sig).replace(', **kwargs', ''))) logger.info("Please check the documentation for more information.") return # expand a specified argument to a path if hasattr(f, 'expand'): arg, attrs = f.expand arg_idx = list(sig.parameters.keys()).index(arg) try: expanded = expanduser(join(attrs['into'], args[arg_idx])) except IndexError: # occurs when arg_idx out of range of args, meaning that the argument to be # expanded was not provided return if attrs.get('ext') and not expanded.endswith("." + attrs['ext']): expanded += "." + attrs['ext'] if attrs.get('new_arg') is None: args = tuple([a if i != arg_idx else expanded for i, a in enumerate(args)]) elif attrs['new_arg'] not in list(sig.parameters.keys()): kwargs[attrs['new_arg']] = expanded if attrs.get('apply') is None else attrs['apply'](expanded) # check for existence (or not) and ask for a confirmation to continue if required for fattr in ['exists', 'not_exists']: if hasattr(f, fattr): arg, attrs = getattr(f, fattr) try: arg_val = args[list(sig.parameters.keys()).index(arg)] except ValueError: arg_val = kwargs[arg] if (fattr == 'exists' and exists(arg_val)) or (fattr == 'not_exists' and not exists(arg_val)): if 'loglvl' in attrs.keys() and 'msg' in attrs.keys(): log_msg(attrs['loglvl'], attrs['msg']) if attrs.get('loglvl') in ('error', 'critical') or \ ((attrs.get('loglvl') in ('warning', 'info') or fattr == 'exists') and get_ask() and attrs.get('confirm') is not None and not std_input(attrs['confirm'], 'yellow') == 'yes'): return # run the command and catch exception if any if console is not None and len(args) > 0: console.clean_tasks() pending_tasks = {i['name']: str(o) for o, i in console.tasklist.items() if i['status'] == 'PENDING'} if args[0] not in pending_tasks.keys(): if hasattr(f, 'start_msg'): log_msg('info', f.start_msg) f.behavior(console, f.__base__ if f.behavior is MultiprocessedCommand else f, args[0]) \ .run(*args, **kwargs) else: logger.warning("A task is still pending on this experiment ({})".format(pending_tasks[args[0]])) else: if hasattr(f, 'start_msg'): log_msg('info', f.start_msg) f(*args, **kwargs)
def setup(silent=False, **kwargs): """ Setup the framework. """ recompile = False # adapt IPv6 debug mode modify_ipv6_debug(CONTIKI_FOLDER) # install Cooja modifications if not check_cooja(COOJA_FOLDER): logger.debug(" > Installing Cooja add-ons...") # modify Cooja.java and adapt build.xml and ~/.cooja.user.properties modify_cooja(COOJA_FOLDER) update_cooja_build(COOJA_FOLDER) update_cooja_user_properties() recompile = True # install VisualizerScreenshot plugin in Cooja visualizer = join(COOJA_FOLDER, 'apps', 'visualizer_screenshot') if not exists(visualizer): logger.debug(" > Installing VisualizerScreenshot Cooja plugin...") copy_folder('src/visualizer_screenshot', visualizer) recompile = True # recompile Cooja for making the changes take effect if recompile: with lcd(CONTIKI_FOLDER): local('git submodule update --init') with lcd(COOJA_FOLDER): logger.debug(" > Recompiling Cooja...") with hide(*HIDDEN_ALL): for cmd in ["clean", "jar"]: output = local("ant {}".format(cmd), capture=True) info, error = False, False for line in output.split('\n'): if line.strip() == "": info, error = False, False elif line.startswith("BUILD"): info, error = "SUCCESSFUL" in line, "FAILED" in line if info or error: getattr( logger, "debug" if info else "error" if error else "warn")(line) else: logger.debug(" > Cooja is up-to-date") # install imagemagick with hide(*HIDDEN_ALL): imagemagick_apt_output = local('apt-cache policy imagemagick', capture=True) if 'Unable to locate package' in imagemagick_apt_output: logger.debug(" > Installing imagemagick package...") local('sudo apt-get install imagemagick -y &') else: logger.debug(" > Imagemagick is installed") # install msp430 (GCC) upgrade with hide(*HIDDEN_ALL): msp430_version_output = local('msp430-gcc --version', capture=True) if 'msp430-gcc (GCC) 4.7.0 20120322' not in msp430_version_output: txt = "In order to extend msp430x memory support, it is necessary to upgrade msp430-gcc.\n" \ "Would you like to upgrade it now ? (yes|no) [default: no] " if silent or std_input(txt, 'yellow') == "yes": logger.debug( " > Upgrading msp430-gcc from version 4.6.3 to 4.7.0...") logger.warning( "If you encounter problems with this upgrade, please refer to:\n" "https://github.com/contiki-os/contiki/wiki/MSP430X") with lcd('src/'): logger.warning( " > Upgrade now starts, this may take up to 30 minutes...") local('sudo ./upgrade-msp430.sh') local('sudo rm -r tmp/') local('export PATH=/usr/local/msp430/bin:$PATH') register_new_path_in_profile() else: logger.warning("Upgrade of library msp430-gcc aborted") logger.warning( "You may experience problems of mote memory size at compilation" ) else: logger.debug(" > Library msp430-gcc is up-to-date (version 4.7.0)") # create a new desktop shortcut for the framework desktop = expanduser('~/Desktop') shortcut = join(desktop, 'rpl-attacks-framework.desktop') if not exists(desktop): makedirs(desktop) if not exists(shortcut): with hide(*HIDDEN_ALL): local('sudo cp {} /usr/share/icons/hicolor/scalable/apps/'.format( join(FRAMEWORK_FOLDER, 'src/rpla-icon.svg'))) local('sudo gtk-update-icon-cache /usr/share/icons/hicolor') with open(shortcut, 'w+') as f: f.write(SHORTCUT.format(path=FRAMEWORK_FOLDER)) chmod(shortcut, int('775', 8)) logger.debug(" > Desktop shortcut created") else: logger.debug(" > Desktop shortcut already exists")
def setup(silent=False, **kwargs): """ Setup the framework. """ recompile = False # install Cooja modifications if not check_cooja(COOJA_FOLDER): logger.debug(" > Installing Cooja add-ons...") # modify Cooja.java and adapt build.xml and ~/.cooja.user.properties modify_cooja(COOJA_FOLDER) update_cooja_build(COOJA_FOLDER) update_cooja_user_properties() recompile = True # install VisualizerScreenshot plugin in Cooja visualizer = join(COOJA_FOLDER, 'apps', 'visualizer_screenshot') if not exists(visualizer): logger.debug(" > Installing VisualizerScreenshot Cooja plugin...") copy_folder('src/visualizer_screenshot', visualizer) recompile = True # recompile Cooja for making the changes take effect if recompile: with lcd(COOJA_FOLDER): logger.debug(" > Recompiling Cooja...") with settings(warn_only=True): local("ant clean") local("ant jar") else: logger.debug(" > Cooja is up-to-date") # install imagemagick with hide(*HIDDEN_ALL): imagemagick_apt_output = local('apt-cache policy imagemagick', capture=True) if 'Unable to locate package' in imagemagick_apt_output: logger.debug(" > Installing imagemagick package...") sudo("apt-get install imagemagick -y &") else: logger.debug(" > Imagemagick is installed") # install msp430 (GCC) upgrade with hide(*HIDDEN_ALL): msp430_version_output = local('msp430-gcc --version', capture=True) if 'msp430-gcc (GCC) 4.7.0 20120322' not in msp430_version_output: txt = "In order to extend msp430x memory support, it is necessary to upgrade msp430-gcc.\n" \ "Would you like to upgrade it now ? (yes|no) [default: no] " answer = std_input(txt, 'yellow') if answer == "yes": logger.debug( " > Upgrading msp430-gcc from version 4.6.3 to 4.7.0...") logger.warning( "If you encounter problems with this upgrade, please refer to:\n" "https://github.com/contiki-os/contiki/wiki/MSP430X") with lcd('src/'): logger.warning( " > Upgrade now starts, this may take up to 30 minutes...") sudo('./upgrade-msp430.sh') sudo('rm -r tmp/') local('export PATH=/usr/local/msp430/bin:$PATH') register_new_path_in_profile() else: logger.warning("Upgrade of library msp430-gcc aborted") logger.warning( "You may experience problems of mote memory size at compilation" ) else: logger.debug(" > Library msp430-gcc is up-to-date (version 4.7.0)")