Source code for wfcommons.wfbench.translator.makeflow
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2024-2025 The WfCommons Team.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
import pathlib
import shutil
from logging import Logger
from typing import Optional, Union
from .abstract_translator import Translator
from ...common import Workflow
this_dir = pathlib.Path(__file__).resolve().parent
[docs]
class MakeflowTranslator(Translator):
"""
A WfFormat parser for creating Makeflow workflow applications.
:param workflow: Workflow benchmark object or path to the workflow benchmark JSON instance.
:type workflow: Union[Workflow, pathlib.Path],
:param logger: The logger where to log information/warning or errors (optional).
:type logger: Logger
"""
def __init__(self,
workflow: Union[Workflow, pathlib.Path],
logger: Optional[Logger] = None) -> None:
"""Create an object of the translator."""
super().__init__(workflow, logger)
self._script = ""
[docs]
def translate(self, output_folder: pathlib.Path) -> None:
"""
Translate a workflow benchmark description (WfFormat) into an actual workflow application.
:param output_folder: The path to the folder in which the workflow benchmark will be generated.
:type output_folder: pathlib.Path
"""
# Generate code
self._generate_code()
# write benchmark files
output_folder.mkdir(parents=True)
with open(output_folder.joinpath("workflow.makeflow"), "w") as fp:
fp.write(self._script)
# additional files
self._copy_binary_files(output_folder)
self._generate_input_files(output_folder)
# README file
self._write_readme_file(output_folder)
[docs]
def _generate_code(self):
"""
Generate the Makeflow code
:return: the code
:rtype: str
"""
self._script = "# Makeflow workflow specification\n\n"
for task_name, task in self.workflow.tasks.items():
make_clause = ""
# output files
for output_file in task.output_files:
make_clause += f"data/{output_file.file_id} "
make_clause += ": "
# input files
for input_file in task.input_files:
make_clause += f"data/{input_file.file_id} "
make_clause += "\n"
# Command
make_clause += "\t"
make_clause += task.program + " "
input_spec = "\"["
for file in task.input_files:
input_spec += f"\\\\\"data/{file.file_id}\\\\\","
input_spec = input_spec[:-1] + "]\""
output_spec = "\"{"
for file in task.output_files:
output_spec += f"\\\\\"data/{file.file_id}\\\\\":{str(file.size)},"
output_spec = output_spec[:-1] + "}\""
args = []
for a in task.args:
if "--output-files" in a:
args.append(f"--output-files {output_spec}")
elif "--input-files" in a:
args.append(f"--input-files {input_spec}")
else:
args.append(a)
args = " ".join(f"{a}" for a in args)
make_clause += args + "\n"
self._script += make_clause + "\n\n"
return
[docs]
def _write_readme_file(self, output_folder: pathlib.Path) -> None:
"""
Write the README file.
:param output_folder: The path of the output folder.
:type output_folder: pathlib.Path
"""
readme_file_path = output_folder.joinpath("README")
with open(readme_file_path, "w") as out:
out.write(f"In directory {str(output_folder)}:\n")
out.write(f" - The Makeflow input file: workflow.makeflow\n")
out.write(f" - Run the workflow: makeflow workflow.makeflow\n")