def test_shell(self): assert evaluate_expression("$(echo foobar)", self.names) == (True, "foobar") assert evaluate_expression("$(test -d /thoushaltnotexist)", self.names) == (False, '') assert evaluate_expression("$(false)", self.names) == (False, '') assert evaluate_expression("$(true)", self.names) == (True, '') assert re.match(".*/foo/bar$", evaluate_expression("$(cd foo; cd bar; pwd; cd ../..)", self.names)[1])
def test_in(self): assert evaluate_expression('$nonempty in "foobar"', self.names) == (True, "foo") assert evaluate_expression('$nonempty2 in "foobar"', self.names) == (True, "bar") assert evaluate_expression('$empty in "foobar"', self.names) == (True, "") assert evaluate_expression('$nonempty in "FOOBAR"', self.names) == (False, "foo")
def test_shell(self): assert evaluate_expression("$(echo foobar)", self.names) == (True, "foobar") assert evaluate_expression("$(test -d /thoushaltnotexist)", self.names) == (False, '') assert evaluate_expression("$(false)", self.names) == (False, '') assert evaluate_expression("$(true)", self.names) == (True, '') assert re.match( ".*/foo/bar$", evaluate_expression("$(cd foo; cd bar; pwd; cd ../..)", self.names)[1])
def _assign_variable(self, variable, comm, kwargs): """Assigns *result* of expression to variable. If there are two variables separated by comma, the first gets assigned *logical result* and the second the *result*. The variable is then put into kwargs (overwriting original value, if already there). Note, that unlike other methods, this method has to accept kwargs, not **kwargs. Even if comm has *logical result* == False, output is still stored and this method doesn't fail. Args: variable: variable (or two variables separated by ",") to assign to comm: either another variable or command to run """ comma_count = variable.count(',') if comma_count > 1: raise exceptions.YamlSyntaxError( 'Max two variables allowed on left side.') res1, res2 = evaluate_expression(comm, kwargs) if comma_count == 1: var1, var2 = map(lambda v: self._get_var_name(v), variable.split(',')) kwargs[var1] = res1 else: var2 = self._get_var_name(variable) kwargs[var2] = res2
def _get_section_from_condition(self, if_section, else_section=None, **kwargs): """Returns section that should be used from given if/else sections by evaluating given condition. Args: if_section - section with if clause else_section - section that *may* be else clause (just next section after if_section, this method will check if it really is else); possibly None if not present Returns: tuple (<0 or 1>, <True or False>, section), where - the first member says whether we're going to "if" section (0) or else section (1) - the second member says whether we should skip next section during further evaluation (True or False - either we have else to skip, or we don't) - the third member is the appropriate section to run or None if there is only "if" clause and condition evaluates to False """ # check if else section is really else skip = True if else_section is not None and else_section[ 0] == 'else' else False if evaluate_expression(if_section[0][2:].strip(), kwargs)[0]: return (0, skip, if_section[1]) else: return (1, skip, else_section[1]) if skip else (1, skip, None)
def _get_section_from_condition(self, if_section, else_section=None, **kwargs): """Returns section that should be used from given if/else sections by evaluating given condition. Args: if_section - section with if clause else_section - section that *may* be else clause (just next section after if_section, this method will check if it really is else); possibly None if not present Returns: tuple (<0 or 1>, <True or False>, section), where - the first member says whether we're going to "if" section (0) or else section (1) - the second member says whether we should skip next section during further evaluation (True or False - either we have else to skip, or we don't) - the third member is the appropriate section to run or None if there is only "if" clause and condition evaluates to False """ # check if else section is really else skip = True if else_section is not None and else_section[0] == 'else' else False if evaluate_expression(if_section[0][2:].strip(), kwargs)[0]: return (0, skip, if_section[1]) else: return (1, skip, else_section[1]) if skip else (1, skip, None)
def _assign_variable(self, variable, comm, kwargs): """Assigns *result* of expression to variable. If there are two variables separated by comma, the first gets assigned *logical result* and the second the *result*. The variable is then put into kwargs (overwriting original value, if already there). Note, that unlike other methods, this method has to accept kwargs, not **kwargs. Even if comm has *logical result* == False, output is still stored and this method doesn't fail. Args: variable: variable (or two variables separated by ",") to assign to comm: either another variable or command to run """ comma_count = variable.count(',') if comma_count > 1: raise exceptions.YamlSyntaxError('Max two variables allowed on left side.') res1, res2 = evaluate_expression(comm, kwargs) if comma_count == 1: var1, var2 = map(lambda v: self._get_var_name(v), variable.split(',')) kwargs[var1] = res1 else: var2 = self._get_var_name(variable) kwargs[var2] = res2
def test_complex_expression(self): assert evaluate_expression( 'defined $empty or $empty and \ $(echo -e foo bar "and also baz") or "else $nonempty"', self.names) == (True, 'else foo')
def test_variable_substitution(self): assert evaluate_expression('"$nonempty"', self.names) == (True, "foo") assert evaluate_expression('"$empty"', self.names) == (False, "") assert evaluate_expression('"$true"', self.names) == (True, "True")
def test_literal(self): assert evaluate_expression('"foobar"', self.names) == (True, "foobar") assert evaluate_expression('""', self.names) == (False, "")
def test_complex_expression(self): assert evaluate_expression('defined $empty or $empty and \ $(echo -e foo bar "and also baz") or "else $nonempty"', self.names) == (True, 'else foo')
def test_not(self): assert evaluate_expression("not $true", self.names) == (False, "") assert evaluate_expression("not $false", self.names) == (True, "") assert evaluate_expression("not $nonempty", self.names) == (False, "foo") assert evaluate_expression("not $empty", self.names) == (True, "")
def test_and(self): # XXX or should this be (True, "") or (True, "True") assert evaluate_expression("$true and $true", self.names) == (True, "") assert evaluate_expression("$true and $false", self.names) == (False, "") assert evaluate_expression("$false and $true", self.names) == (False, "") assert evaluate_expression("$false and $false", self.names) == (False, "") assert evaluate_expression("$nonempty and $nonempty2", self.names) == (True, "bar") assert evaluate_expression("$nonempty2 and $nonempty", self.names) == (True, "foo") assert evaluate_expression("$nonempty and $empty", self.names) == (False, "") assert evaluate_expression("$empty and $nonempty", self.names) == (False, "") assert evaluate_expression("$nonempty and $true", self.names) == (True, "") assert evaluate_expression("$true and $nonempty", self.names) == (True, "") assert evaluate_expression("$empty and $true", self.names) == (False, "") assert evaluate_expression("$true and $empty", self.names) == (False, "") assert evaluate_expression("$empty and $empty", self.names) == (False, "") assert evaluate_expression("$true and $nonempty and $nonempty2", self.names) == (True, "") assert evaluate_expression("$true and $nonempty and $empty", self.names) == (False, "")
def _run_one_section(self, section, kwargs): skip_else = False for i, command_dict in enumerate(section): if self.stop_flag: break for comm_type, comm in command_dict.items(): if comm_type.startswith('call'): # calling workflow: # 1) get proper run section (either from self or from snippet) # 2) if running snippet, add its files to kwargs['__files__'] # 3) actually run # 4) if running snippet, pop its files from kwargs['__files__'] sect = self._get_section_from_call(comm, 'run') if sect is None: logger.warning('Couldn\'t find section to run: {0}.'.format(comm)) continue if self._is_snippet_call(comm, **kwargs): # we're calling a snippet => add files and template_dir to kwargs snippet = yaml_snippet_loader.YamlSnippetLoader.get_snippet_by_name(comm.split('.')[0]) if '__files__' not in kwargs: kwargs['__files__'] = [] kwargs['__template_dir__'] = [] kwargs['__files__'].append(snippet.get_files_section()) kwargs['__template_dir__'].append(snippet.get_template_dir()) self._run_one_section(sect, copy.deepcopy(kwargs)) if self._is_snippet_call(comm, **kwargs): kwargs['__files__'].pop() kwargs['__template_dir__'].pop() elif comm_type.startswith('$'): # intentionally pass kwargs as dict, not as keywords try: self._assign_variable(comm_type, comm, kwargs) except exceptions.YamlSyntaxError as e: logger.error(e) raise e elif 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 = self._get_section_from_condition((comm_type, comm), possible_else, **kwargs) if to_run: # run with original kwargs, so that they might be changed for code after this if self._run_one_section(to_run, kwargs) elif comm_type == 'else': if not skip_else: logger.warning('Yaml error: encountered "else" with no associated "if", skipping.') skip_else = False elif comm_type.startswith('for'): # syntax: "for $i in $x: <section> or "for $i in cl_command: <section>" try: control_var, expression = self._parse_for(comm_type) except exceptions.YamlSyntaxError as e: logger.error(e) raise e try: eval_expression = evaluate_expression() except exceptions.YamlSyntaxError as e: logger.log(e) raise e for i in eval_expression: kwargs[control_var] = i self._run_one_section(comm, kwargs) elif comm_type.startswith('scl'): if '__scls__' not in kwargs: kwargs['__scls__'] = [] # list of lists of scl names kwargs['__scls__'].append(comm_type.split()[1:]) self._run_one_section(comm, kwargs) kwargs['__scls__'].pop() else: files = kwargs['__files__'][-1] if kwargs.get('__files__', None) else self._files template_dir = kwargs['__template_dir__'][-1] if kwargs.get('__template_dir__', None) else self.template_dir run_command(comm_type, CommandFormatter.format(comm_type, comm, template_dir, files, **kwargs), **kwargs)
def test_variable(self): assert evaluate_expression("$true", self.names) == (True, "") assert evaluate_expression("$false", self.names) == (False, "") assert evaluate_expression("$nonempty", self.names) == (True, "foo") assert evaluate_expression("$empty", self.names) == (False, "")
def test_defined(self): assert evaluate_expression("defined $nonempty", self.names) == (True, "foo") assert evaluate_expression("defined $empty", self.names) == (True, "") assert evaluate_expression("defined $notdefined", self.names) == (False, "")
def test_or(self): assert evaluate_expression("$true or $true", self.names) == (True, "") assert evaluate_expression("$true or $false", self.names) == (True, "") assert evaluate_expression("$false or $true", self.names) == (True, "") assert evaluate_expression("$false or $false", self.names) == (False, "") assert evaluate_expression("$nonempty or $nonempty2", self.names) == (True, "foo") assert evaluate_expression("$nonempty2 or $nonempty", self.names) == (True, "bar") assert evaluate_expression("$nonempty or $empty", self.names) == (True, "foo") assert evaluate_expression("$empty or $nonempty", self.names) == (True, "foo") assert evaluate_expression("$nonempty or $true", self.names) == (True, "foo") assert evaluate_expression("$true or $nonempty", self.names) == (True, "foo") assert evaluate_expression("$empty or $true", self.names) == (True, "") assert evaluate_expression("$true or $empty", self.names) == (True, "") assert evaluate_expression("$empty or $empty", self.names) == (False, "") assert evaluate_expression("$true or $nonempty or $nonempty2", self.names) == (True, "foo") assert evaluate_expression("$false or $nonempty or $empty", self.names) == (True, "foo")
def _run_one_section(self, section, kwargs): skip_else = False for i, command_dict in enumerate(section): if self.stop_flag: break for comm_type, comm in command_dict.items(): if comm_type.startswith('call'): # calling workflow: # 1) get proper run section (either from self or from snippet) # 2) if running snippet, add its files to kwargs['__files__'] # 3) actually run # 4) if running snippet, pop its files from kwargs['__files__'] sect = self._get_section_from_call(comm, 'run') if sect is None: logger.warning( 'Couldn\'t find section to run: {0}.'.format(comm)) continue if self._is_snippet_call(comm, **kwargs): # we're calling a snippet => add files and template_dir to kwargs snippet = yaml_snippet_loader.YamlSnippetLoader.get_snippet_by_name( comm.split('.')[0]) if '__files__' not in kwargs: kwargs['__files__'] = [] kwargs['__template_dir__'] = [] kwargs['__files__'].append(snippet.get_files_section()) kwargs['__template_dir__'].append( snippet.get_template_dir()) self._run_one_section(sect, copy.deepcopy(kwargs)) if self._is_snippet_call(comm, **kwargs): kwargs['__files__'].pop() kwargs['__template_dir__'].pop() elif comm_type.startswith('$'): # intentionally pass kwargs as dict, not as keywords try: self._assign_variable(comm_type, comm, kwargs) except exceptions.YamlSyntaxError as e: logger.error(e) raise e elif 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 = self._get_section_from_condition( (comm_type, comm), possible_else, **kwargs) if to_run: # run with original kwargs, so that they might be changed for code after this if self._run_one_section(to_run, kwargs) elif comm_type == 'else': if not skip_else: logger.warning( 'Yaml error: encountered "else" with no associated "if", skipping.' ) skip_else = False elif comm_type.startswith('for'): # syntax: "for $i in $x: <section> or "for $i in cl_command: <section>" try: control_var, expression = self._parse_for(comm_type) except exceptions.YamlSyntaxError as e: logger.error(e) raise e try: eval_expression = evaluate_expression() except exceptions.YamlSyntaxError as e: logger.log(e) raise e for i in eval_expression: kwargs[control_var] = i self._run_one_section(comm, kwargs) elif comm_type.startswith('scl'): if '__scls__' not in kwargs: kwargs['__scls__'] = [] # list of lists of scl names kwargs['__scls__'].append(comm_type.split()[1:]) self._run_one_section(comm, kwargs) kwargs['__scls__'].pop() else: files = kwargs['__files__'][-1] if kwargs.get( '__files__', None) else self._files template_dir = kwargs['__template_dir__'][-1] if kwargs.get( '__template_dir__', None) else self.template_dir run_command( comm_type, CommandFormatter.format(comm_type, comm, template_dir, files, **kwargs), **kwargs)