Esempio n. 1
0
    def run(self, context):
        src = self.getarg('src', context)
        dst = self.getarg('dst', context)
        self.log_info(f'Render {src} --> {dst}')

        # The template search path:
        #   1. .
        #   2. ./templates
        #   3. <ocwd>
        #   4. <ocwd>/templates
        # where <ocwd> is the original working directory at the time when the
        # se script was called
        search_path = ['.', 'templates']
        if '_se_cmd_cwd' in context:
            search_path.extend([
                context['_se_cmd_cwd'],
                os.path.join(context['_se_cmd_cwd'], 'templates')
            ])
        self.log_debug(f'Search path for template: {search_path}')

        loader = jinja2.FileSystemLoader(search_path)
        environment = jinja2.Environment(loader=loader)
        for name, function in j2filters().items():
            environment.filters[name] = function
        template = environment.get_template(src)
        output_text = j2render(template.render(context), context)

        with open(dst, 'w') as output_file:
            output_file.write(f'{output_text}\n')
Esempio n. 2
0
    def run(self, context):
        src = self.getarg("src", context)
        dst = Path(self.getarg("dst", context))
        self.log_info(f"Jinja2 render: {src} --> {dst}")

        # Prepare the Jinja render environment with the proper search path
        search_path = (
            Path("."),
            Path(".") / "templates",
            Path(context["se"]["cli"]["cwd"]),
            Path(context["se"]["cli"]["cwd"]) / "templates",
        )
        self.log_debug(f"Template search path: {tuple(map(str, search_path))}")
        j2loader = jinja2.FileSystemLoader(search_path)
        j2env = jinja2.Environment(loader=j2loader)
        for name, function in j2filters().items():
            j2env.filters[name] = function

        output = j2render(j2env.get_template(src).render(context), context)
        with dst.open(mode="w") as f:
            f.write(output + "\n")

        if self.getarg("executable", context, default=False):
            umask = os.umask(0)
            os.umask(umask)
            dst.chmod(dst.stat().st_mode
                      | (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) & ~umask)
Esempio n. 3
0
 def when(self, context):
     try:
         return self._when is None or j2render(
             self._when, context, boolean=True)
     except ScriptEngineParseJinjaError:
         self.log_error("Error while parsing (Jinja2) invalid when clause "
                        f'"{self._when}" with context "{context}"')
         raise ScriptEngineJobParseError
Esempio n. 4
0
 def loop(self, context):
     loop_iter = j2render(self._loop_iter, context)
     if isinstance(loop_iter, str):
         try:
             loop_iter = ast.literal_eval(loop_iter)
         except SyntaxError:
             raise ScriptEngineParseError(
                 'Syntax error while evaluating loop expression '
                 f'"{loop_iter}" in job with id {self.id}')
     return self._loop_var, loop_iter
Esempio n. 5
0
    def run(self, context):

        # No recursive job submission by default: check if we're already in a job
        if is_batch_job() and not self.getarg('submit_from_batch_job',
                                              default=False):
            self.log_debug(
                f'{self.__class__.__name__} task from within a batch '
                'job and "submit_from_batch_job" is not set or false: '
                'not submitting new job')
            return

        # Append all opts,args that should go to the submit command to a list
        opt_args = []
        for opt, arg in self.__dict__.items():
            if opt in ('scripts',
                       'submit_from_batch_job') or opt.startswith('_'):
                continue
            opt_args.append(f'--{opt}')
            if arg:
                opt_args.append(j2render(arg, context))

        # Build the submit command line
        submit_cmd = [_SUBMIT_CMD]
        submit_cmd.extend(map(str, opt_args))
        scripts = self.getarg('scripts', default=None)
        if scripts:
            submit_cmd.append('se')
            submit_cmd.extend(
                map(str, scripts if isinstance(scripts, list) else [scripts]))
        else:
            # If no scripts were given, use the original SE command line
            submit_cmd.extend(sys.argv)
        self.log_debug(f'Command line for submitting job: {submit_cmd}')

        # Run submit command, with handling of errors
        try:
            subprocess.run(submit_cmd, check=True)
        except subprocess.CalledProcessError as e:
            self.log_error(f'Submit command returns error: {e}')
            raise ScriptEngineTaskRunError
        else:
            self.log_info(
                'Requesting stop after submitting batch job to SLURM')
            raise ScriptEngineStopException
Esempio n. 6
0
 def loop_spec(self, context):
     try:
         iter = j2render(self._loop, context)
     except ScriptEngineParseJinjaError:
         self.log_error(
             "Error while parsing (Jinja2) invalid loop expression "
             f'"{self._loop}" with context "{context}"')
         raise ScriptEngineJobParseError
     if isinstance(iter, str):
         try:
             iter = ast.literal_eval(iter or "None")
         except (SyntaxError, ValueError):
             self.log_error(
                 "Error while evaluating (AST) invalid loop expression "
                 f'"{iter}" with context "{context}"')
             raise ScriptEngineJobParseError
     if isinstance(iter, dict):
         iter = iter.items()
         vars = self._loop_vars or ("key", "value")
     else:
         vars = self._loop_vars or ("item", )
     return iter, vars
Esempio n. 7
0
 def loop(self, context):
     if self._loop:
         iter, vars = self.loop_spec(context)
         if iter:
             for items in iter:
                 parsed_items = tuple(
                     j2render(i, context)
                     for i in _listy(items, type_=tuple))
                 vars_tuple = _listy(vars, type_=tuple)
                 if len(vars_tuple) == 1 and len(parsed_items) > 1:
                     # If only one loop variable is given and items is listy,
                     # assign the whole list to the variable (see #59)
                     yield {vars_tuple[0]: parsed_items}
                 else:
                     # Otherwise, map (zip) loop vars with items
                     # Note that extra vars or items are ignored!
                     yield dict(zip(vars_tuple, parsed_items))
         else:
             self.log_warning(
                 "Null loop after parsing loop descriptor, job is not run!")
             raise StopIteration
     else:
         yield {}
Esempio n. 8
0
 def when(self, context):
     return (self._when is None
             or j2render(self._when, context, boolean=True))