[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/exkson/ceph-devstack/main/ceph_devstack/exec.py [Back]  [Original]

import asyncio
from asyncio.subprocess import SubprocessStreamProtocol
import functools
import os
import pathlib
import subprocess

from typing import Dict, List, Optional

from ceph_devstack import logger, VERBOSE


class LoggingStreamProtocol(asyncio.subprocess.SubprocessStreamProtocol):
    def __init__(self, limit, loop, log_level):
        self.log_level = log_level
        super().__init__(limit=limit, loop=loop)

    def pipe_data_received(self, fd, data):
        logger.log(
            self.log_level,
            (data.decode() if isinstance(data, bytes) else str(data)).rstrip("\n"),
        )
        super().pipe_data_received(fd, data)


class Command:
    def __init__(
        self,
        args: List[str],
        cwd: Optional[pathlib.Path] = None,
        env: Optional[Dict] = None,
        stream_output: bool = False,
    ):
        self.args = args
        self.env = os.environ | (env or {})
        self.kwargs: Dict = {
            "stdout": asyncio.subprocess.PIPE,
            "stderr": asyncio.subprocess.PIPE,
        }
        if cwd:
            self.kwargs.update(cwd=cwd)
        self.stream_output = stream_output

    def _make_log_msg(self) -> str:
        msg = "> " + " ".join(self.args)
        if (cwd := str(self.kwargs.get("cwd", "."))) != ".":
            msg = f"{msg} cwd='{cwd}'"
        return msg

    def run(self) -> subprocess.Popen:
        logger.log(VERBOSE, self._make_log_msg())
        proc = subprocess.Popen(
            args=self.args,
            env=self.env,
            **self.kwargs,
        )
        proc.wait()
        return proc

    async def arun(self) -> asyncio.subprocess.Process:
        logger.log(VERBOSE, self._make_log_msg())
        loop = asyncio.get_running_loop()
        protocol_factory: functools.partial[SubprocessStreamProtocol]
        if self.stream_output:
            protocol_factory = functools.partial(
                LoggingStreamProtocol,
                limit=2**16,
                loop=loop,
                log_level=VERBOSE,
            )
        else:
            protocol_factory = functools.partial(
                asyncio.subprocess.SubprocessStreamProtocol,
                limit=2**16,
                loop=loop,
            )
        transport, protocol = await loop.subprocess_exec(
            protocol_factory,
            *self.args,
            env=self.env,
            **self.kwargs,
        )
        return asyncio.subprocess.Process(
            transport,
            protocol,
            loop,
        )

    def __str__(self):
        return " ".join(self.args)

Web Proxy Viewer  |  New URL  |  Original Page