Source code for tbot.machine.linux.special

# tbot, Embedded Automation Tool
# Copyright (C) 2019  Harald Seiler
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

import abc
import shlex
import typing

import tbot.error
from . import linux_shell, path  # noqa: F401

H = typing.TypeVar("H", bound="linux_shell.LinuxShell")


class Special(typing.Generic[H]):
    __slots__ = ()

    @abc.abstractmethod
    def _to_string(self, host: H) -> str:
        raise tbot.error.AbstractMethodError()


[docs]class Raw(Special[H]): __slots__ = ("string",) def __init__(self, string: str) -> None: self.string = string def _to_string(self, _: H) -> str: return self.string
class _Stdio(Special[H]): __slots__ = ("file",) _both = False @property @abc.abstractmethod def _redir_token(self) -> str: raise tbot.error.AbstractMethodError() def __init__(self, file: path.Path[H]) -> None: self.file = file def _to_string(self, h: H) -> str: # The order of the redirects is important! First, redirect stdout to a # file and then redirect stderr to stdout. If this is switched around, # stderr will go to old stdout, before it was redirected (that is, the # terminal). result = self._redir_token + shlex.quote(self.file.at_host(h)) if self._both: result += " 2>&1" return result
[docs]class RedirStdout(_Stdio[H]): _redir_token = ">"
[docs]class RedirStderr(_Stdio[H]): _redir_token = "2>"
[docs]class RedirBoth(_Stdio[H]): _redir_token = ">" _both = True
[docs]class RedirStdin(_Stdio[H]): _redir_token = "<"
[docs]class AppendStdout(_Stdio[H]): _redir_token = ">>"
[docs]class AppendStderr(_Stdio[H]): _redir_token = "2>>"
[docs]class AppendBoth(_Stdio[H]): _redir_token = ">>" _both = True
class _Background(Special[H]): def __init__( self, *, stdout: typing.Optional[path.Path[H]] = None, stderr: typing.Optional[path.Path[H]] = None, ) -> None: self.stdout = stdout self.stderr = stderr def __call__( self, *, stdout: typing.Optional[path.Path[H]] = None, stderr: typing.Optional[path.Path[H]] = None, ) -> "_Background": return _Background(stdout=stdout, stderr=stderr) def _to_string(self, h: H) -> str: if self.stdout is not None and self.stderr is not None: if self.stdout == self.stderr: return f"1>{shlex.quote(self.stdout.at_host(h))} 2>&1 &" else: return f"1>{shlex.quote(self.stdout.at_host(h))} 2>{shlex.quote(self.stderr.at_host(h))} &" elif self.stderr is not None: return f"1>/dev/null 2>{shlex.quote(self.stderr.at_host(h))} &" elif self.stdout is not None: return f"2>/dev/null 1>{shlex.quote(self.stdout.at_host(h))} &" else: return "1>/dev/null 2>&1 &" class _Static(Special): __slots__ = ("string",) def __init__(self, string: str) -> None: self.string = string def _to_string(self, _: H) -> str: return self.string AndThen = _Static("&&") Background: _Background = _Background() OrElse = _Static("||") Pipe = _Static("|") Then = _Static(";")