From bd7acd91ca6e16554c38287d140fdce2543f99b7 Mon Sep 17 00:00:00 2001 From: Christopher Spinrath <christopher.spinrath@univ-grenoble-alpes.fr> Date: Wed, 30 Apr 2025 16:53:23 +0200 Subject: [PATCH] Add experimental exp2sh converter The converter is not feature complete! --- exp2sh.py | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ run-exp.py | 20 +++++++++++ 2 files changed, 118 insertions(+) create mode 100755 exp2sh.py diff --git a/exp2sh.py b/exp2sh.py new file mode 100755 index 0000000..d9a3164 --- /dev/null +++ b/exp2sh.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 + +import importlib +import pathlib + +import click +import structlog + +exprunner = importlib.import_module('run-exp') + + +# logger = structlog.get_logger() +def drop_log_msgs(*_1, **_2): + raise structlog.DropEvent + + +structlog.configure(processors = [drop_log_msgs]) + + +def print_stmt(stmt, indent): + print(f"{" " * indent}{stmt}", flush = True) + + +def translate_var_init(variable, variable_map, indent): + sh_var_name = variable_map[variable.name].strip("$") # remove leading $ + + if isinstance(variable, exprunner.SimpleVariable): + values = variable.evaluate(variable_map) + if len(values) == 1: + print_stmt(f"{sh_var_name}=\"{values[0]}\"", indent) + return False + else: + print() + print_stmt(f"for {sh_var_name} in {" ".join(f"\"{v}\"" for v in values)}", indent) + print_stmt("do", indent) + return True + + if isinstance(variable, exprunner.RangeVariable): + print() + print_stmt(f"for {sh_var_name} in $(seq {variable.lower} {variable.step} {variable.upper})", indent) + print_stmt("do", indent) + return True + + if isinstance(variable, exprunner.FileVariable): + directory_str = variable.directory_str.format(**variable_map) + print() + print_stmt(f"for {sh_var_name} in {directory_str}/*", indent) + print_stmt("do", indent) + if variable.basename_only: + print_stmt(f"{sh_var_name}=$(basename ${sh_var_name})", indent + 1) + return True + + return False + + +@click.command() +@click.argument("config_file", type = click.Path( + exists = True, file_okay = True, dir_okay = False, readable = True, path_type = pathlib.Path)) +@click.option("--global-timeout", type = click.IntRange(1), default = 7200) +@click.option("--dry-run", is_flag = True) +def main(config_file, global_timeout, dry_run): + c = exprunner.Config.from_file(config_file) + + print("#!/usr/bin/env bash") + print() + + print("# WARNING: This script ignoes 'if-(not)-variable' conditions!") + print() + + # we precompute all variable values to be able to abort early in case of a problem, + # for instance, if a file does not exist + variable_map = {v.name: f"${v.name.upper().replace('-', '_')}" for v in c.variables} + indent = 0 + + num_for_loops = 0 + for variable in c.variables: + if translate_var_init(variable, variable_map, indent): + num_for_loops += 1 + indent += 1 + + print() + print_stmt(f"for EXP_RUNNER_REPETITION in $(seq 0 {c.repetitions})", indent) + print_stmt("do", indent) + + for task in c.tasks: + print_stmt(f"# {task.name}", indent + 1) + print(" " * (indent + 1), flush = True, end = '') + if dry_run: + print("echo ", flush = True, end = '') + task.run({k: f"\\{v}" for k, v in variable_map.items()}, global_timeout, True) + + for _ in range(num_for_loops + 1): + print_stmt("done", indent) + indent -= 1 + + +if __name__ == "__main__": + main() diff --git a/run-exp.py b/run-exp.py index 9b1a1b0..4d62126 100755 --- a/run-exp.py +++ b/run-exp.py @@ -54,6 +54,18 @@ class RangeVariable(SimpleVariable): def __init__(self, name, lower, upper, step): super().__init__(name, list(range(lower, upper + 1, step))) + @property + def lower(self): + return self._lower + + @property + def upper(self): + return self._upper + + @property + def step(self): + return self._step + class FileVariable(Variable): def __init__(self, name, directory_str, basename_only): @@ -61,6 +73,14 @@ class FileVariable(Variable): self._directory_str = directory_str self._basename_only = basename_only + @property + def directory_str(self): + return self._directory_str + + @property + def basename_only(self): + return self._basename_only + def evaluate(self, variable_mapping): directory = pathlib.Path(self._directory_str.format(**variable_mapping)) directory = directory.expanduser() -- GitLab