def run(self): if os.path.isfile(self.kwargs['package']): old_level = logger.getEffectiveLevel() logger.setLevel(logging.ERROR) try: d = dapi.Dap(self.kwargs['package']) if not dapi.DapChecker.check(d): raise exceptions.ExecutionException( 'This DAP is not valid, info can\'t be displayed.') finally: logger.setLevel(old_level) logger.infolines( dapicli.format_local_dap(d, full=self.kwargs.get('full', False))) elif self.kwargs.get('installed'): try: logger.infolines( dapicli.format_installed_dap(self.kwargs['package'], full=self.kwargs.get( 'full', False))) except exceptions.DapiError as e: logger.error(utils.exc_as_decoded_string(e)) raise exceptions.ExecutionException( utils.exc_as_decoded_string(e)) else: try: logger.infolines( dapicli.format_dap_from_dapi(self.kwargs['package'], full=self.kwargs.get( 'full', False))) except exceptions.DapiError as e: logger.error(utils.exc_as_decoded_string(e)) raise exceptions.ExecutionException( utils.exc_as_decoded_string(e))
def save_configuration_file(self): """ Save all configuration into file Only if config file does not yet exist or configuration was changed """ if os.path.exists(self.config_file) and not self.config_changed: return dirname = os.path.dirname(self.config_file) try: if not os.path.exists(dirname): os.makedirs(dirname) except (OSError, IOError) as e: self.logger.warning( "Could not make directory for configuration file: {0}".format( utils.exc_as_decoded_string(e))) return try: with open(self.config_file, 'w') as file: csvwriter = csv.writer(file, delimiter='=', escapechar='\\', lineterminator='\n', quoting=csv.QUOTE_NONE) for key, value in self.config_dict.items(): csvwriter.writerow([key, value]) self.config_changed = False except (OSError, IOError) as e: self.logger.warning("Could not save configuration file: {0}".\ format(utils.exc_as_decoded_string(e)))
def save_configuration_file(self): """ Save all configuration into file Only if config file does not yet exist or configuration was changed """ if os.path.exists(self.config_file) and not self.config_changed: return dirname = os.path.dirname(self.config_file) try: if not os.path.exists(dirname): os.makedirs(dirname) except (OSError, IOError) as e: self.logger.warning("Could not make directory for configuration file: {0}". format(utils.exc_as_decoded_string(e))) return try: with open(self.config_file, 'w') as file: csvwriter = csv.writer(file, delimiter='=', escapechar='\\', lineterminator='\n', quoting=csv.QUOTE_NONE) for key, value in self.config_dict.items(): csvwriter.writerow([key, value]) self.config_changed = False except (OSError, IOError) as e: self.logger.warning("Could not save configuration file: {0}".\ format(utils.exc_as_decoded_string(e)))
def run(self): pkgs = exs = [] try: pkgs = self.kwargs['package'] except KeyError: pkgs = dapicli.get_installed_daps() if pkgs: logger.info('Updating all DAP packages ...') else: logger.info('No installed DAP packages found, nothing to update.') for pkg in pkgs: logger.info('Updating DAP {pkg} ...'.format(pkg=pkg)) try: updated = dapicli.install_dap(pkg, update=True, update_allpaths=self.kwargs['allpaths'], force=self.kwargs['force']) if updated: logger.info('DAP {pkg} successfully updated.'.format(pkg=pkg)) else: logger.info('DAP {pkg} is already up to date.'.format(pkg=pkg)) except exceptions.DapiError as e: exs.append(utils.exc_as_decoded_string(e)) logger.error(utils.exc_as_decoded_string(e)) if exs: raise exceptions.ExecutionException('; '.join(exs))
def run(self): pkgs = exs = [] try: pkgs = self.kwargs['package'] except KeyError: pkgs = dapicli.get_installed_daps() if pkgs: logger.info('Updating all DAP packages ...') else: logger.info( 'No installed DAP packages found, nothing to update.') for pkg in pkgs: logger.info('Updating DAP {pkg} ...'.format(pkg=pkg)) try: updated = dapicli.install_dap( pkg, update=True, update_allpaths=self.kwargs['allpaths'], force=self.kwargs['force']) if updated: logger.info( 'DAP {pkg} successfully updated.'.format(pkg=pkg)) else: logger.info( 'DAP {pkg} is already up to date.'.format(pkg=pkg)) except exceptions.DapiError as e: exs.append(utils.exc_as_decoded_string(e)) logger.error(utils.exc_as_decoded_string(e)) if exs: raise exceptions.ExecutionException('; '.join(exs))
def run(self): if os.path.isfile(self.kwargs['package']): old_level = logger.getEffectiveLevel() logger.setLevel(logging.ERROR) try: d = dapi.Dap(self.kwargs['package']) if not dapi.DapChecker.check(d): raise exceptions.ExecutionException( 'This DAP is not valid, info can\'t be displayed.') finally: logger.setLevel(old_level) dapicli.print_local_dap(d, full=self.kwargs.get('full', False)) elif self.kwargs.get('installed'): try: dapicli.print_installed_dap(self.kwargs['package'], full=self.kwargs.get('full', False)) except exceptions.DapiError as e: logger.error(utils.exc_as_decoded_string(e)) raise exceptions.ExecutionException(utils.exc_as_decoded_string(e)) else: try: dapicli.print_dap_from_dapi(self.kwargs['package'], full=self.kwargs.get('full', False)) except exceptions.DapiError as e: logger.error(utils.exc_as_decoded_string(e)) raise exceptions.ExecutionException(utils.exc_as_decoded_string(e))
def resolve(cls, *args): logger.info('Resolving RPM dependencies with DNF...') import dnf import hawkey base = dnf.Base() base.conf.cachedir = tempfile.mkdtemp() base.conf.substitutions['releasever'] = platform.linux_distribution( )[1] base.read_all_repos() base.fill_sack(load_system_repo=True, load_available_repos=True) for pkg in (str(arg) for arg in args): if pkg.startswith('@'): base.group_install(pkg[1:]) else: try: res = base.sack.query().available().filter( provides=pkg).run() base.install(str(res[0])) except (hawkey.QueryException, IndexError): msg = 'Package not found: {pkg}'.format(pkg=pkg) raise exceptions.DependencyException(msg) try: base.resolve() except dnf.exceptions.Error as e: raise exceptions.DependencyException( 'Error resolving RPM dependencies with DNF: {0}'.format( utils.exc_as_decoded_string(e))) logger.debug('Installing/Updating:') to_install = [] for pkg in base.transaction.install_set: to_install.append(str(pkg)) logger.debug(str(pkg)) return to_install
def resolve(cls, *args): logger.info('Resolving RPM dependencies with DNF...') import dnf import hawkey base = dnf.Base() base.conf.cachedir = tempfile.mkdtemp() base.conf.substitutions['releasever'] = platform.linux_distribution()[1] base.read_all_repos() base.fill_sack(load_system_repo=True, load_available_repos=True) for pkg in (str(arg) for arg in args): if pkg.startswith('@'): base.group_install(pkg[1:]) else: try: res = base.sack.query().available().filter(provides=pkg).run() base.install(str(res[0])) except (hawkey.QueryException, IndexError): msg = 'Package not found: {pkg}'.format(pkg=pkg) raise exceptions.DependencyException(msg) try: base.resolve() except dnf.exceptions.Error as e: raise exceptions.DependencyException('Error resolving RPM dependencies with DNF: {0}'. format(utils.exc_as_decoded_string(e))) logger.debug('Installing/Updating:') to_install = [] for pkg in base.transaction.install_set: to_install.append(str(pkg)) logger.debug(str(pkg)) return to_install
def run_gui(): """ Function for running DevAssistant GUI """ try: from gi.repository import Gtk except ImportError as ie: pass except RuntimeError as e: sys.stderr.write(GUI_MESSAGE) sys.stderr.write("%s: %r" % (e.__class__.__name__, utils.exc_as_decoded_string(e))) sys.stderr.flush() sys.exit(1) if not os.environ.get('DISPLAY'): sys.stderr.write("%s %s" % (GUI_MESSAGE, GUI_MESSAGE_DISPLAY)) sys.stderr.flush() sys.exit(1) parser = argparse.ArgumentParser(description='Run DevAssistant GUI.') utils.add_no_cache_argument(parser) # now we only have "--no-cache" argument, which we don't actually need to remember, # see add_no_cache_argument help; so we only run parse_args to determine if # the invocation was correct parser.parse_args() settings.USE_CACHE = False if '--no-cache' in sys.argv else True from devassistant.gui import main_window main_window.MainWindow()
def resolve(cls, *args): logger.info('Resolving RPM dependencies ...') import yum y = yum.YumBase() y.setCacheDir(tempfile.mkdtemp()) for pkg in args: if pkg.startswith('@'): y.selectGroup(pkg[1:]) else: try: y.install(y.returnPackageByDep(pkg)) except yum.Errors.YumBaseError: msg = 'Package not found: {pkg}'.format(pkg=pkg) raise exceptions.DependencyException(msg) try: y.resolveDeps() except yum.Errors.PackageSackError as e: # Resolution of Issue 154 raise exceptions.DependencyException('Error resolving RPM dependencies: {0}'. format(utils.exc_as_decoded_string(e))) logger.debug('Installing/Updating:') to_install = [] for pkg in y.tsInfo.getMembers(): to_install.append(pkg.po.ui_envra) logger.debug(pkg.po.ui_envra) return to_install
def resolve(cls, *args): logger.info('Resolving RPM dependencies ...') import yum y = yum.YumBase() y.setCacheDir(tempfile.mkdtemp()) for pkg in args: if pkg.startswith('@'): y.selectGroup(pkg[1:]) else: try: y.install(y.returnPackageByDep(pkg)) except yum.Errors.YumBaseError: msg = 'Package not found: {pkg}'.format(pkg=pkg) raise exceptions.DependencyException(msg) try: y.resolveDeps() except yum.Errors.PackageSackError as e: # Resolution of Issue 154 raise exceptions.DependencyException( 'Error resolving RPM dependencies: {0}'.format( utils.exc_as_decoded_string(e))) logger.debug('Installing/Updating:') to_install = [] for pkg in y.tsInfo.getMembers(): to_install.append(pkg.po.ui_envra) logger.debug(pkg.po.ui_envra) return to_install
def run(self): newargs = {} newargs['q'] = ' '.join(self.kwargs['query']) newargs['noassistants'] = self.kwargs['noassistants'] newargs['unstable'] = self.kwargs['unstable'] newargs['notactive'] = self.kwargs['deactivated'] newargs['minimal_rank'] = self.kwargs['minrank'] newargs['minimal_rank_count'] = self.kwargs['mincount'] if not self.kwargs['allplatforms']: newargs['platform'] = utils.get_distro_name() try: dapicli.print_search(**newargs) except exceptions.DapiError as e: logger.error(utils.exc_as_decoded_string(e)) raise exceptions.ExecutionException(utils.exc_as_decoded_string(e))
def load_configuration_file(self): """ Load all configuration from file """ if not os.path.exists(self.config_file): return try: with open(self.config_file, 'r') as file: csvreader = csv.reader(file, delimiter='=', escapechar='\\', quoting=csv.QUOTE_NONE) for line in csvreader: if len(line) == 2: key, value = line self.config_dict[key] = value else: self.config_dict = dict() self.logger.warning( "Malformed configuration file {0}, ignoring it.". format(self.config_file)) return except (OSError, IOError) as e: self.logger.warning("Could not load configuration file: {0}".\ format(utils.exc_as_decoded_string(e)))
def run(self): newargs = {} newargs['q'] = ' '.join(self.kwargs['query']) newargs['noassistants'] = self.kwargs['noassistants'] newargs['unstable'] = self.kwargs['unstable'] newargs['notactive'] = self.kwargs['deactivated'] newargs['minimal_rank'] = self.kwargs['minrank'] newargs['minimal_rank_count'] = self.kwargs['mincount'] if not self.kwargs['allplatforms']: newargs['platform'] = utils.get_distro_name() try: logger.infolines(dapicli.format_search(**newargs)) except exceptions.DapiError as e: logger.error(utils.exc_as_decoded_string(e)) raise exceptions.ExecutionException(utils.exc_as_decoded_string(e))
def run(self): exs = [] for pkg in self.kwargs['package']: logger.info('Installing DAP {pkg} ...'.format(pkg=pkg)) if os.path.isfile(pkg): method = dapicli.install_dap_from_path else: method = dapicli.install_dap try: pkgs = method(pkg, force=self.kwargs['force'], nodeps=self.kwargs['nodeps'], reinstall=self.kwargs['reinstall']) logger.info('Successfully installed DAPs {pkgs}'.format(pkgs=' '.join(pkgs))) except exceptions.DapiError as e: exs.append(utils.exc_as_decoded_string(e)) logger.error(utils.exc_as_decoded_string(e)) if exs: raise exceptions.ExecutionException('; '.join(exs))
def run(self): exs = [] uninstalled = [] for pkg in self.kwargs['package']: if pkg in uninstalled: logger.info('DAP {pkg} already uninstalled'.format(pkg=pkg)) continue logger.info('Uninstalling DAP {pkg} ...'.format(pkg=pkg)) try: done = dapicli.uninstall_dap(pkg, confirm=self.kwargs['force'], allpaths=self.kwargs['allpaths']) if done: logger.info('DAPs {pkgs} successfully uninstalled'.format(pkgs=' '.join(done))) uninstalled += done except exceptions.DapiError as e: exs.append(utils.exc_as_decoded_string(e)) logger.error(utils.exc_as_decoded_string(e)) if exs: raise exceptions.ExecutionException('; '.join(exs))
def run(self): exs = [] for pkg in self.kwargs['package']: logger.info('Installing DAP {pkg} ...'.format(pkg=pkg)) if os.path.isfile(pkg): method = dapicli.install_dap_from_path else: method = dapicli.install_dap try: pkgs = method(pkg, force=self.kwargs['force'], nodeps=self.kwargs['nodeps'], reinstall=self.kwargs['reinstall'], __ui__=self.kwargs['__ui__']) logger.info('Successfully installed DAPs {pkgs}'.format( pkgs=' '.join(pkgs))) except exceptions.DapiError as e: exs.append(utils.exc_as_decoded_string(e)) logger.error(utils.exc_as_decoded_string(e)) if exs: raise exceptions.ExecutionException('; '.join(exs))
def run(self): exs = [] uninstalled = [] for pkg in self.kwargs['package']: if pkg in uninstalled: logger.info('DAP {pkg} already uninstalled'.format(pkg=pkg)) continue logger.info('Uninstalling DAP {pkg} ...'.format(pkg=pkg)) try: done = dapicli.uninstall_dap(pkg, confirm=self.kwargs['force'], allpaths=self.kwargs['allpaths'], __ui__=self.kwargs['__ui__']) if done: logger.info('DAPs {pkgs} successfully uninstalled'.format( pkgs=' '.join(done))) uninstalled += done except exceptions.DapiError as e: exs.append(utils.exc_as_decoded_string(e)) logger.error(utils.exc_as_decoded_string(e)) if exs: raise exceptions.ExecutionException('; '.join(exs))
def run(cls, **kwargs): error = False old_level = logger.getEffectiveLevel() for pkg in kwargs['package']: try: if kwargs['nowarnings']: logger.setLevel(logging.ERROR) d = dapi.Dap(pkg) if not dapi.DapChecker.check(d, network=kwargs['network']): error = True except (exceptions.DapFileError, exceptions.DapMetaError) as e: logger.error(utils.exc_as_decoded_string(e)) error = True logger.setLevel(old_level) if error: raise exceptions.ExecutionException('One or more packages are not sane')
def check_yamls(cls, dap): '''Check that all assistants and snippets are valid. Return list of DapProblems.''' problems = list() for yaml in dap.assistants_and_snippets: path = yaml + '.yaml' parsed_yaml = YamlLoader.load_yaml_by_path(dap._get_file(path, prepend=True)) if parsed_yaml: try: yaml_checker.check(path, parsed_yaml) except YamlError as e: problems.append(DapProblem(exc_as_decoded_string(e), level=logging.ERROR)) else: problems.append(DapProblem('Empty YAML ' + path, level=logging.WARNING)) return problems
def is_pkg_installed(cls, dep): """Is a package managed by this manager installed?""" import paludis env = paludis.EnvironmentFactory.instance.create('') installed = env.fetch_repository('installed') try: pkg = paludis.parse_user_package_dep_spec(dep, env, paludis.UserPackageDepSpecOptions()) # TODO Compare package version! r = [] for i in installed.package_ids(str(pkg.package), []): r.append(str(i)) logger.debug('Checking is installed: {0} -> {1}'.format(pkg, repr(r))) return r except paludis.BaseException as e: msg = 'Dependency specification is invalid [{0}]: {1}'.\ format(dep, utils.exc_as_decoded_string(e)) raise exceptions.DependencyException(msg)
def is_pkg_installed(cls, dep): """Is a package managed by this manager installed?""" import paludis env = paludis.EnvironmentFactory.instance.create('') installed = env.fetch_repository('installed') try: pkg = paludis.parse_user_package_dep_spec( dep, env, paludis.UserPackageDepSpecOptions()) # TODO Compare package version! r = [] for i in installed.package_ids(str(pkg.package), []): r.append(str(i)) logger.debug('Checking is installed: {0} -> {1}'.format( pkg, repr(r))) return r except paludis.BaseException as e: msg = 'Dependency specification is invalid [{0}]: {1}'.\ format(dep, utils.exc_as_decoded_string(e)) raise exceptions.DependencyException(msg)
def run(self): error = False old_level = logger.getEffectiveLevel() for pkg in self.kwargs['package']: try: if self.kwargs['nowarnings']: logger.setLevel(logging.ERROR) d = dapi.Dap(pkg) if not dapi.DapChecker.check( d, network=self.kwargs['network'], yamls=not self.kwargs['noyamlcheck']): error = True except (exceptions.DapFileError, exceptions.DapMetaError) as e: logger.error(utils.exc_as_decoded_string(e)) error = True logger.setLevel(old_level) if error: raise exceptions.ExecutionException( 'One or more packages are not sane')
def load_configuration_file(self): """ Load all configuration from file """ if not os.path.exists(self.config_file): return try: with open(self.config_file, 'r') as file: csvreader = csv.reader(file, delimiter='=', escapechar='\\', quoting=csv.QUOTE_NONE) for line in csvreader: if len(line) == 2: key, value = line self.config_dict[key] = value else: self.config_dict = dict() self.logger.warning("Malformed configuration file {0}, ignoring it.". format(self.config_file)) return except (OSError, IOError) as e: self.logger.warning("Could not load configuration file: {0}".\ format(utils.exc_as_decoded_string(e)))
def check_yamls(cls, dap): '''Check that all assistants and snippets are valid. Return list of DapProblems.''' problems = list() for yaml in dap.assistants_and_snippets: path = yaml + '.yaml' parsed_yaml = YamlLoader.load_yaml_by_path( dap._get_file(path, prepend=True)) if parsed_yaml: try: yaml_checker.check(path, parsed_yaml) except YamlError as e: problems.append( DapProblem(exc_as_decoded_string(e), level=logging.ERROR)) else: problems.append( DapProblem('Empty YAML ' + path, level=logging.WARNING)) return problems
def run_gui(): """ Function for running DevAssistant GUI """ try: from gi.repository import Gtk except ImportError as ie: pass except RuntimeError as e: sys.stderr.write(GUI_MESSAGE) sys.stderr.write( "%s: %r" % (e.__class__.__name__, utils.exc_as_decoded_string(e))) sys.stderr.flush() sys.exit(1) if not os.environ.get('DISPLAY'): sys.stderr.write("%s %s" % (GUI_MESSAGE, GUI_MESSAGE_DISPLAY)) sys.stderr.flush() sys.exit(1) # For GNOME 3 icon: # because this is invoked as da-gui and the desktop file is called devassistant try: from gi.repository import GLib GLib.set_prgname(PRGNAME) except ImportError: pass parser = argparse.ArgumentParser(description='Run DevAssistant GUI.') utils.add_no_cache_argument(parser) # now we only have "--no-cache" argument, which we don't actually need to remember, # see add_no_cache_argument help; so we only run parse_args to determine if # the invocation was correct parser.parse_args() settings.USE_CACHE = False if '--no-cache' in sys.argv else True from devassistant.gui import main_window main_window.MainWindow()
def run(cls, **kwargs): try: dapicli.print_search(' '.join(kwargs['query'])) except Exception as e: logger.error(utils.exc_as_decoded_string(e)) raise exceptions.ExecutionException(utils.exc_as_decoded_string(e))
def _log_if_not_logged(self, err): if not getattr(err, 'already_logged', False): # this is here primarily because of log_ command, that logs the message itself logger.error(utils.exc_as_decoded_string(err)) return err
def eval_exec_section(section, kwargs, runner=None): skip_else = False retval = (False, '') if isinstance(section, six.string_types): return evaluate_expression(section, kwargs) for i, command_dict in enumerate(section): if getattr(runner, 'stop_flag', False): break for comm_type, comm in command_dict.items(): if comm_type.startswith('if'): possible_else = None if len(section) > i + 1: # do we have "else" clause? possible_else = list(section[i + 1].items())[0] _, skip_else, to_run = get_section_from_condition( (comm_type, comm), possible_else, kwargs) # run with original kwargs, so that they might be changed for code after this if to_run: retval = run_section(to_run, kwargs, runner=runner) elif comm_type == 'else': if not skip_else: msg = 'Yaml error: encountered "else" with no associated "if", skipping.' raise exceptions.YamlSyntaxError(msg) skip_else = False elif comm_type.startswith('for '): # syntax: "for $i in $x: <section> or "for $i in cl_command: <section>" control_vars, eval_expression = get_for_control_var_and_eval_expr( comm_type, kwargs) for i in eval_expression: if len(control_vars) == 2: kwargs[control_vars[0]] = i[0] kwargs[control_vars[1]] = i[1] else: kwargs[control_vars[0]] = i retval = run_section(comm, kwargs, runner=runner) elif comm_type.startswith('$'): # commands that can have exec flag appended follow if comm_type.endswith( '~'): # on exec flag, eval comm as exec section comm_ret = eval_exec_section(comm, kwargs, runner) else: # with no exec flag, eval comm as input section comm_ret = eval_literal_section(comm, kwargs, runner) retval = assign_variable(comm_type, *comm_ret, kwargs=kwargs) elif comm_type.startswith('catch '): was_exc_var, exc_var = get_catch_vars(comm_type) try: run_section(comm, kwargs, runner=runner) kwargs[was_exc_var] = False kwargs[exc_var] = '' except exceptions.ExecutionException as ex: kwargs[was_exc_var] = True kwargs[exc_var] = utils.exc_as_decoded_string(ex) retval = kwargs[was_exc_var], kwargs[exc_var] else: retval = Command(comm_type, comm, kwargs=kwargs).run() if not isinstance(retval, (list, tuple)) or len(retval) != 2: raise exceptions.RunException( 'Bad return value of last command ({ct}: {c}): {r}'.format( ct=comm_type, c=comm, r=retval)) assign_last_result(kwargs, *retval) return retval
def eval_exec_section(section, kwargs, runner=None): skip_else = False retval = (False, '') if isinstance(section, six.string_types): return evaluate_expression(section, kwargs) for i, command_dict in enumerate(section): if getattr(runner, 'stop_flag', False): break for comm_type, comm in command_dict.items(): if comm_type.startswith('if'): possible_else = None if len(section) > i + 1: # do we have "else" clause? possible_else = list(section[i + 1].items())[0] _, skip_else, to_run = get_section_from_condition((comm_type, comm), possible_else, kwargs) # run with original kwargs, so that they might be changed for code after this if to_run: retval = run_section(to_run, kwargs, runner=runner) elif comm_type == 'else': if not skip_else: msg = 'Yaml error: encountered "else" with no associated "if", skipping.' raise exceptions.YamlSyntaxError(msg) skip_else = False elif comm_type.startswith('for '): # syntax: "for $i in $x: <section> or "for $i in cl_command: <section>" control_vars, eval_expression = get_for_control_var_and_eval_expr(comm_type, kwargs) for i in eval_expression: if len(control_vars) == 2: kwargs[control_vars[0]] = i[0] kwargs[control_vars[1]] = i[1] else: kwargs[control_vars[0]] = i retval = run_section(comm, kwargs, runner=runner) elif comm_type.startswith('$'): # commands that can have exec flag appended follow if comm_type.endswith('~'): # on exec flag, eval comm as exec section comm_ret = eval_exec_section(comm, kwargs, runner) else: # with no exec flag, eval comm as input section comm_ret = eval_literal_section(comm, kwargs, runner) retval = assign_variable(comm_type, *comm_ret, kwargs=kwargs) elif comm_type.startswith('catch '): was_exc_var, exc_var = get_catch_vars(comm_type) try: run_section(comm, kwargs, runner=runner) kwargs[was_exc_var] = False kwargs[exc_var] = '' except exceptions.ExecutionException as ex: kwargs[was_exc_var] = True kwargs[exc_var] = utils.exc_as_decoded_string(ex) retval = kwargs[was_exc_var], kwargs[exc_var] else: retval = Command(comm_type, comm, kwargs=kwargs).run() if not isinstance(retval, (list, tuple)) or len(retval) != 2: raise exceptions.RunException('Bad return value of last command ({ct}: {c}): {r}'. format(ct=comm_type, c=comm, r=retval)) assign_last_result(kwargs, *retval) return retval