def evaluate_when( operator_dict, env, cc_dict, context_key, ): """Evaluate the when condition and return bool.""" if 'when' not in operator_dict: return True when_raw = operator_dict['when'] when_condition = False if isinstance(when_raw, str): when_condition = render_variable(env, when_raw, cc_dict, context_key) elif isinstance(when_raw, list): # Evaluate lists as successively evalutated 'and' conditions for i in when_raw: when_condition = render_variable(env, i, cc_dict, context_key) # If anything is false, then break immediately if not when_condition: break operator_dict.pop('when') return when_condition
def prompt_choice_for_config(cc_dict, env, key, options, no_input, context_key): """Prompt user with a set of options to choose from. Each of the possible choices is rendered beforehand. """ rendered_options = [ render_variable(env, raw, cc_dict, context_key) for raw in options ] if no_input: return rendered_options[0] return read_user_choice(key, rendered_options)
def parse_context(context, env, cc_dict, context_key, no_input): """Parse the context and iterate over values. :param dict context: Source for field names and sample values. :param env: Jinja environment to render values with. :param context_key: The key to insert all the outputs under in the context dict. :param no_input: Prompt the user at command line for manual configuration. :param existing_context: A dictionary of values to use during rendering. :return: cc_dict """ for key, raw in context[context_key].items(): if key.startswith(u'_') and not key.startswith('__'): cc_dict[key] = raw continue elif key.startswith('__'): cc_dict[key] = render_variable(env, raw, cc_dict, context_key) continue try: if isinstance(raw, list): # We are dealing with a choice variable val = prompt_choice_for_config(cc_dict, env, key, raw, no_input, context_key) cc_dict[key] = val elif not isinstance(raw, dict): # We are dealing with a regular variable val = render_variable(env, raw, cc_dict, context_key) if not no_input: val = read_user_variable(key, val) cc_dict[key] = val except UndefinedError as err: msg = "Unable to render variable '{}'".format(key) raise UndefinedVariableInTemplate(msg, err, context) # Second pass; handle the dictionaries. for key, raw in context[context_key].items(): if key.startswith('_') and not key.startswith('__'): continue try: if isinstance(raw, dict): # dict parsing logic if 'type' not in raw: val = render_variable(env, raw, cc_dict, context_key) if not no_input: val = read_user_dict(key, val) cc_dict[key] = val else: cc_dict = parse_operator( context, key, dict(cc_dict), no_input=no_input, context_key=context_key, ) except UndefinedError as err: msg = "Unable to render variable '{}'".format(key) raise UndefinedVariableInTemplate(msg, err, context) return cc_dict
def parse_operator( context, key, cc_dict, append_key: bool = False, no_input: bool = False, context_key=None, ): """Parse input dict for loop and when logic and calls hooks. :return: cc_dict """ global post_gen_operator_list if not context_key: context_key = next(iter(context)) env = StrictEnvironment(context=context) logger.debug("Parsing context_key: %s and key: %s" % (context_key, key)) operator_dict = context[context_key][key] when_condition = evaluate_when(operator_dict, env, cc_dict, context_key) if when_condition: # Extract loop if 'loop' in operator_dict: loop_targets = render_variable( env, operator_dict['loop'], cc_dict, context_key ) operator_dict.pop('loop') loop_output = [] for i, l in enumerate(loop_targets): loop_cookiecutter = cc_dict loop_cookiecutter.update({'index': i, 'item': l}) loop_output += [ parse_operator( context, key, loop_cookiecutter, append_key=True, no_input=no_input, ) ] cc_dict.pop('item') cc_dict.pop('index') cc_dict[key] = loop_output return cc_dict if 'block' not in operator_dict['type']: operator_dict = render_variable(env, operator_dict, cc_dict, context_key) # Run the operator if operator_dict['merge'] if 'merge' in operator_dict else False: to_merge, post_gen_operator = run_operator( operator_dict, context, no_input, context_key, cc_dict, env ) cc_dict.update(to_merge) else: cc_dict[key], post_gen_operator = run_operator( operator_dict, context, no_input, context_key, cc_dict, env, key ) if post_gen_operator: post_gen_operator_list.append(post_gen_operator) if append_key: return cc_dict[key] return cc_dict