From 5277664d16385f35b25f8862c3971988e42dd798 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 8 Mar 2021 17:06:49 +0100 Subject: util: Add function to run commands --- rtems_spec_to_x.py | 25 +++++-------------------- rtemsspec/tests/test_util.py | 20 ++++++++++++++++++-- rtemsspec/util.py | 37 +++++++++++++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/rtems_spec_to_x.py b/rtems_spec_to_x.py index 06653cf4..10ccc787 100755 --- a/rtems_spec_to_x.py +++ b/rtems_spec_to_x.py @@ -25,10 +25,9 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. +import logging import os import string -import subprocess -from typing import List import rtemsspec.applconfig import rtemsspec.build @@ -39,21 +38,6 @@ import rtemsspec.util import rtemsspec.validation -def _run_command(args: List[str], cwd: str) -> int: - task = subprocess.Popen(args, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - cwd=cwd) - assert task.stdout is not None - while True: - line = task.stdout.readline() - if line: - print(line.decode("utf-8").strip()) - elif task.poll() is not None: - break - return task.wait() - - def _run_pre_qualified_only_build(config: dict, item_cache: ItemCache) -> None: files = rtemsspec.build.gather_files(config, item_cache) source_dir = config["source-directory"] @@ -63,11 +47,11 @@ def _run_pre_qualified_only_build(config: dict, item_cache: ItemCache) -> None: content = string.Template(config["config-ini"]).substitute(config) config_ini.write(content) specs = os.path.relpath(os.path.join(source_dir, "spec"), workspace_dir) - _run_command([ + rtemsspec.util.run_command([ "./waf", "configure", "--rtems-specs", specs, "--rtems-top-group", "/build/grp" ], workspace_dir) - _run_command(["./waf"], workspace_dir) + rtemsspec.util.run_command(["./waf"], workspace_dir) def _run_pre_qualified_doxygen(config: dict) -> None: @@ -84,11 +68,12 @@ def _run_pre_qualified_doxygen(config: dict) -> None: content = Template(doxyfile_template.read()).substitute(doxyfile_vars) with open(os.path.join(workspace_dir, "Doxyfile"), "w") as doxyfile: doxyfile.write(content) - _run_command(["doxygen"], workspace_dir) + rtemsspec.util.run_command(["doxygen"], workspace_dir) def main() -> None: """ Generates glossaries of terms according to the configuration. """ + logging.basicConfig(level="DEBUG") config = rtemsspec.util.load_config("config.yml") item_cache = ItemCache(config["spec"]) rtemsspec.glossary.generate(config["glossary"], item_cache) diff --git a/rtemsspec/tests/test_util.py b/rtemsspec/tests/test_util.py index c85e6833..7affd795 100644 --- a/rtemsspec/tests/test_util.py +++ b/rtemsspec/tests/test_util.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-2-Clause """ Unit tests for the rtemsspec.util module. """ -# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# Copyright (C) 2020, 2021 embedded brains GmbH (http://www.embedded-brains.de) # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -25,8 +25,10 @@ # POSSIBILITY OF SUCH DAMAGE. import os +import logging -from rtemsspec.util import copy_files, load_config +from rtemsspec.util import copy_files, load_config, run_command +from rtemsspec.tests.util import get_and_clear_log def test_copy_files(tmpdir): @@ -43,3 +45,17 @@ def test_load_config(): config = load_config(filename) assert config["a"] == "b" assert config["c"] == "d" + + +def test_run(caplog): + caplog.set_level(logging.DEBUG) + status = run_command(["echo", "A"]) + assert status == 0 + assert get_and_clear_log(caplog) == """INFO run in '.': 'echo' 'A' +DEBUG A""" + stdout = [] + status = run_command(["echo", "A"], stdout=stdout) + assert status == 0 + assert stdout[0].strip() == "A" + status = run_command(["sleep", "0.1"]) + assert status == 0 diff --git a/rtemsspec/util.py b/rtemsspec/util.py index d2403cd3..bf07b5fa 100644 --- a/rtemsspec/util.py +++ b/rtemsspec/util.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-2-Clause """ This module provides utility functions. """ -# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# Copyright (C) 2020, 2021 embedded brains GmbH (http://www.embedded-brains.de) # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -24,9 +24,11 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. +import logging import os import shutil -from typing import Any, List +import subprocess +from typing import Any, List, Optional import yaml @@ -63,3 +65,34 @@ def load_config(config_filename: str) -> Any: IncludeLoader.add_constructor("!include", IncludeLoader.include) with open(config_filename, "r") as config_file: return yaml.load(config_file.read(), Loader=IncludeLoader) + + +def run_command(args: List[str], + cwd: str = ".", + stdout: Optional[List[str]] = None, + env=None) -> int: + """ + Runs the command in a subprocess in the working directory and environment. + + Optionally, the standard output of the subprocess is returned. Returns the + exit status of the subprocess. + """ + logging.info("run in '%s': %s", cwd, " ".join(f"'{arg}'" for arg in args)) + task = subprocess.Popen(args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + cwd=cwd, + env=env) + assert task.stdout is not None + while True: + raw_line = task.stdout.readline() + if raw_line: + line = raw_line.decode("utf-8").rstrip() + if stdout is None: + logging.debug("%s", line) + else: + stdout.append(line) + elif task.poll() is not None: + break + return task.wait() -- cgit v1.2.3