mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
103 lines
3.0 KiB
Python
103 lines
3.0 KiB
Python
#
|
|
# This file is distributed under the MIT License. See LICENSE.md for details.
|
|
#
|
|
|
|
import importlib.util
|
|
import logging
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Sequence
|
|
|
|
import click
|
|
|
|
from . import initialize_pypeline
|
|
from .cli.utils import EagerParsedPath, LazyGroup
|
|
|
|
logger = logging.getLogger("pypeline")
|
|
logger.setLevel(logging.DEBUG)
|
|
logger.addHandler(logging.StreamHandler(sys.stderr))
|
|
|
|
|
|
def import_pipebox(module_path: str, is_complete: bool) -> object:
|
|
"""Import a module from a path. This is used to import the pipebox file.
|
|
Args:
|
|
env (dict[str, str]): The environment variables.
|
|
module_path (str): The path to the module.
|
|
is_complete (bool): If True, raise an error if the module is not found.
|
|
"""
|
|
# Absolute path to the module
|
|
module_abspath = Path(module_path).resolve()
|
|
if not module_abspath.exists():
|
|
# This is a small trick to allow generating the module auto-complete
|
|
# without having a pipebox file
|
|
if is_complete:
|
|
return object()
|
|
logger.error(
|
|
(
|
|
"Pipebox file `%s` does not exist. Either set it using the "
|
|
"PIPEBOX env var, or pass the --pipebox option."
|
|
),
|
|
module_abspath,
|
|
)
|
|
sys.exit(1)
|
|
# We guess that the module name is the file name without the extension
|
|
module_name: str = module_abspath.stem
|
|
# Dynamic import of the pipebox module
|
|
spec = importlib.util.spec_from_file_location(module_name, str(module_abspath))
|
|
if spec is None:
|
|
if is_complete:
|
|
return object()
|
|
logger.error("Could not load module `%s` from `%s`", module_name, module_abspath)
|
|
sys.exit(1)
|
|
module = importlib.util.module_from_spec(spec)
|
|
if spec.loader is None:
|
|
if is_complete:
|
|
return object()
|
|
logger.error("Could not load module `%s` from `%s`", module_name, module_abspath)
|
|
sys.exit(1)
|
|
# Execute the module to load it
|
|
spec.loader.exec_module(module)
|
|
# Initialize the pypeline as we just imported the pipebox
|
|
initialize_pypeline()
|
|
return module
|
|
|
|
|
|
@click.group(
|
|
cls=LazyGroup,
|
|
lazy_subcommands={
|
|
"pipeline": "revng.pypeline.cli.pipeline:pipeline",
|
|
"project": "revng.pypeline.cli.project:project",
|
|
},
|
|
)
|
|
@click.option(
|
|
"--pipebox",
|
|
type=EagerParsedPath(
|
|
name="pipebox",
|
|
parser=lambda path: import_pipebox(path, "_PYPE_COMPLETE" in os.environ),
|
|
),
|
|
help=(
|
|
"Path to the pipebox file. Defaults to the `PIPEBOX` environment "
|
|
"variable, then 'pipebox.py'."
|
|
),
|
|
default=os.environ.get("PIPEBOX", "pipebox.py"),
|
|
expose_value=False,
|
|
)
|
|
def cli():
|
|
pass
|
|
|
|
|
|
def main(args: Sequence[str]) -> None:
|
|
# pylint: disable=E1120 no-value-for-parameter
|
|
# This is ok as click will pass the pipebox argument automatically
|
|
cli(args=args)
|
|
|
|
|
|
def run():
|
|
"""Run the pipeline from the command line using the shell environment."""
|
|
main(sys.argv[1:])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run()
|