Source code for waves._build

"""Internal API module implementing the ``build`` subcommand behavior.

Should raise ``RuntimeError`` or a derived class of :class:`waves.exceptions.WAVESError` to allow the CLI implementation
to convert stack-trace/exceptions into STDERR message and non-zero exit codes.
"""

import sys
import typing
import pathlib
import argparse

from waves import _settings
from waves import _utilities


_exclude_from_namespace = set(globals().keys())


[docs] def get_parser() -> argparse.ArgumentParser: """Return a 'no-help' parser for the build subcommand :return: parser """ parser = argparse.ArgumentParser(add_help=False) parser.add_argument( "TARGET", nargs="+", help=f"SCons target(s)", ) parser.add_argument( "-m", "--max-iterations", type=int, default=5, help="Maximum number of SCons command iterations (default: %(default)s)", ) directory_group = parser.add_mutually_exclusive_group() directory_group.add_argument( "--working-directory", type=str, default=None, help=argparse.SUPPRESS, ) directory_group.add_argument( "-g", "--git-clone-directory", type=str, default=None, # fmt: off help="Perform a full local git clone operation to the specified directory before executing the scons " "command, ``git clone --no-hardlinks ${PWD} ${GIT_CLONE_DIRECTORY}`` (default: %(default)s)", # fmt: on ) return parser
[docs] def main( targets: list, scons_args: typing.Optional[list] = None, max_iterations: int = 5, working_directory: typing.Union[str, pathlib.Path, None] = None, git_clone_directory: typing.Union[str, pathlib.Path, None] = None, ) -> None: """Submit an iterative SCons command SCons command is re-submitted until SCons reports that the target 'is up to date.' or the iteration count is reached. :param targets: list of SCons targets (positional arguments) :param scons_args: list of SCons arguments :param max_iterations: Maximum number of iterations before the iterative loop is terminated :param working_directory: Change the SCons command working directory :param git_clone_directory: Destination directory for a Git clone operation """ if not scons_args: scons_args = [] if not targets: raise RuntimeError("At least one target must be provided") if git_clone_directory: current_directory = pathlib.Path().cwd().resolve() git_clone_directory = pathlib.Path(git_clone_directory).resolve() git_clone_directory.mkdir(parents=True, exist_ok=True) working_directory = str(git_clone_directory) command = ["git", "clone", "--no-hardlinks", str(current_directory), working_directory] git_clone_return_code, git_clone_stdout = _utilities.tee_subprocess(command) if git_clone_return_code != 0: raise RuntimeError(f"command '{' '.join(command)}' failed") stop_trigger = "is up to date." scons_command = [_settings._scons_command] scons_command.extend(scons_args) command = scons_command + targets scons_stdout = "Go boat" trigger_count = 0 count = 0 while trigger_count < len(targets): count += 1 if count > max_iterations: raise RuntimeError( f"Exceeded maximum iterations '{max_iterations}' before finding '{stop_trigger}' " "for every target" ) print( f"\n{_settings._project_name_short.lower()} build iteration {count}: '{' '.join(command)}'\n", file=sys.stdout, ) scons_return_code, scons_stdout = _utilities.tee_subprocess(command, cwd=working_directory) if scons_return_code != 0: raise RuntimeError(f"command '{' '.join(command)}' failed") trigger_count = scons_stdout.count(stop_trigger)
# Limit help() and 'from module import *' behavior to the module's public API _module_objects = set(globals().keys()) - _exclude_from_namespace __all__ = [name for name in _module_objects if not name.startswith("_")]