...

Text file src/github.com/emissary-ingress/emissary/v3/python/kat/utils.py

Documentation: github.com/emissary-ingress/emissary/v3/python/kat

     1import re
     2import subprocess
     3import time
     4
     5_quote_pos = re.compile("(?=[^-0-9a-zA-Z_./\n])")
     6
     7
     8def quote(arg):
     9    r"""
    10    >>> quote('\t')
    11    '\\\t'
    12    >>> quote('foo bar')
    13    'foo\\ bar'
    14    """
    15
    16    # This is the logic emacs uses
    17    if arg:
    18        return _quote_pos.sub("\\\\", arg).replace("\n", "'\n'")
    19    else:
    20        return "''"
    21
    22
    23class ShellCommand:
    24    def __init__(self, *args, **kwargs) -> None:
    25        self.verbose = kwargs.pop("verbose", False)
    26
    27        for arg in "stdout", "stderr":
    28            if arg not in kwargs:
    29                kwargs[arg] = subprocess.PIPE
    30
    31        self.cmdline = " ".join([quote(x) for x in args])
    32
    33        if self.verbose:
    34            print(f"---- running: {self.cmdline}")
    35
    36        self.proc = subprocess.run(args, **kwargs)
    37
    38    def status(self) -> bool:
    39        try:
    40            self.proc.check_returncode()
    41            return True
    42        except Exception as e:
    43            return False
    44
    45    def check(self, what: str) -> bool:
    46        if self.status():
    47            return True
    48        else:
    49            print(f"==== COMMAND FAILED: {what}")
    50            print(f"---- command line: {self.cmdline}")
    51            if self.stdout:
    52                print("---- stdout ----")
    53                print(self.stdout)
    54                print("---- end stdout ----")
    55            if self.stderr:
    56                print("---- stderr ----")
    57                print(self.stderr)
    58                print("---- end stderr ----")
    59
    60            return False
    61
    62    @property
    63    def stdout(self) -> str:
    64        return self.proc.stdout.decode("utf-8")
    65
    66    @property
    67    def stderr(self) -> str:
    68        return self.proc.stderr.decode("utf-8")
    69
    70    @classmethod
    71    def run_with_retry(cls, what: str, *args, **kwargs) -> bool:
    72        try_count = 0
    73        retries = kwargs.pop("retries", 3)
    74        sleep_seconds = kwargs.pop("sleep_seconds", 5)
    75        while try_count < retries:
    76            if try_count > 0:
    77                print(f"Sleeping for {sleep_seconds} before retrying command")
    78                time.sleep(sleep_seconds)
    79            if cls.run(what, *args, **kwargs):
    80                return True
    81            try_count += 1
    82        return False
    83
    84    @classmethod
    85    def run(cls, what: str, *args, **kwargs) -> bool:
    86        return ShellCommand(*args, **kwargs).check(what)

View as plain text