Source code for tbot.machine.linux.special

# tbot, Embedded Automation Tool
# Copyright (C) 2018  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 typing
import abc
import shlex
from tbot import machine
from tbot.machine import linux  # noqa: F401

H = typing.TypeVar("H", bound="linux.LinuxMachine")


class Special(abc.ABC, typing.Generic[H]):
    """Base class for special characters."""

    @abc.abstractmethod
    def resolve_string(self, host: H) -> str:
        """Return the string representation of this special character."""
        pass


[docs]class Raw(Special): """Raw unescaped string.""" __slots__ = ("text",) def __init__(self, text: str) -> None: """ Create a new unescaped string. **Example**:: m.exec0(linux.Raw('FOOBAR="${USER}@$(hostname):${PWD}"')) :param str text: The raw string """ self.text = text def resolve_string(self, _: H) -> str: """Return the string representation of this special character.""" return self.text
[docs]class F(Special[H]): """Format string.""" __slots__ = ("fmt", "args", "quote") def __init__( self, fmt: str, *args: "typing.Union[str, linux.Path[H], Special[H]]", quote: bool = True, ) -> None: """ Create a format string. **Example**:: m.exec0("export", linux.F("PATH={}:{}", p1, linux.Env("PATH"), quote=False)) All normal python formatters are supported. :param str fmt: Format string :param args: Format arguments. Can be tbot paths as well. :param bool quote: Whether to escape the resulting string. """ self.fmt = fmt self.args = args self.quote = quote def resolve_string(self, host: H) -> str: """Return the string representation of this special character.""" def validate(arg: typing.Union[str, linux.Path[H], Special[H]]) -> str: if isinstance(arg, str): return arg elif isinstance(arg, Special): return arg.resolve_string(host) elif isinstance(arg, linux.Path): if arg.host is not host: raise machine.WrongHostException(host, arg) string = arg._local_str() # If quoting is off, we should still quote paths if not self.quote: return shlex.quote(string) else: return string else: raise TypeError(f"{arg!r} is not a supported argument type!") args = list(map(validate, self.args)) string = self.fmt.format(*args) if self.quote: return shlex.quote(string) else: return string
[docs]class Env(Special): """Expand an environment variable or shell variable.""" __slots__ = ("name",) def __init__(self, name: str) -> None: """ Create a new environment variable accessor. **Example**:: m.exec0(linux.Env("CC"), "-c", m.workdir / "main.c") :param str name: Name of the env var. """ self.name = name def resolve_string(self, _: H) -> str: """Return the string representation of this special character.""" return f"${{{self.name}}}"
class _Static(Special): __slots__ = ("string",) def __init__(self, string: str) -> None: self.string = string def resolve_string(self, _: H) -> str: """Return the string representation of this special character.""" return self.string AndThen = _Static("&&") Background = _Static("&") OrElse = _Static("||") Pipe = _Static("|") Then = _Static(";")