CasperSecurity

Current Path : /lib/python3/dist-packages/uaclient/cli/
Upload File :
Current File : //lib/python3/dist-packages/uaclient/cli/formatter.py

import abc
import os
import re
import sys
import textwrap
from enum import Enum
from typing import Any, Dict, List, Optional  # noqa: F401

from uaclient.config import UAConfig
from uaclient.messages import TxtColor

COLOR_FORMATTING_PATTERN = r"\033\[.*?m"
LINK_START_PATTERN = r"\033]8;;.+?\033\\+"
LINK_END = "\033]8;;\033\\"
UTF8_ALTERNATIVES = {
    "—": "-",
    "✘": "x",
    "✔": "*",
}  # type: Dict[str, str]


class ContentAlignment(Enum):
    LEFT = "l"
    RIGHT = "r"


# Class attributes and methods so we don't need singletons or globals for this
class ProOutputFormatterConfig:
    use_utf8 = True
    use_color = True

    # Initializing the class after the import is useful for unit testing
    @classmethod
    def init(cls, cfg: UAConfig):
        cls.use_utf8 = (
            sys.stdout.encoding is not None
            and "UTF-8" in sys.stdout.encoding.upper()
        )

        cls.use_color = sys.stdout.isatty() and os.getenv("NO_COLOR") is None

    @classmethod
    def disable_color(cls) -> None:
        cls.use_color = False


ProOutputFormatterConfig.init(cfg=UAConfig())


def create_link(text: str, url: str) -> str:
    return "\033]8;;{url}\033\\{text}\033]8;;\033\\".format(url=url, text=text)


def real_len(text: str) -> int:
    # ignore colors if existing
    result = re.sub(COLOR_FORMATTING_PATTERN, "", text)
    # Ignore link control characters and metadata
    result = re.sub(LINK_START_PATTERN, "", result)
    result = result.replace(LINK_END, "")

    return len(result)


def _get_default_length():
    if sys.stdout.isatty():
        return os.get_terminal_size().columns
    # If you're not in a tty, we don't care about string length
    # If you have a thousand characters line, well, wow
    return 999


def process_formatter_config(text: str) -> str:
    output = text
    if not ProOutputFormatterConfig.use_color:
        output = re.sub(COLOR_FORMATTING_PATTERN, "", text)

    if not ProOutputFormatterConfig.use_utf8:
        for char, alternative in UTF8_ALTERNATIVES.items():
            output = output.replace(char, alternative)
        output = output.encode("ascii", "ignore").decode()

    if not sys.stdout.isatty():
        output = re.sub(LINK_START_PATTERN, "", output)
        output = output.replace(LINK_END, "")

    return output


# We can't rely on textwrap because of the real_len function
# Textwrap is using a magic regex instead
def wrap_text(text: str, max_width: int) -> List[str]:
    if real_len(text) <= max_width:
        return [text]

    words = text.split()
    wrapped_lines = []
    current_line = ""

    for word in words:
        if real_len(current_line) + real_len(word) >= max_width:
            wrapped_lines.append(current_line.strip())
            current_line = word
        else:
            current_line += " " + word

    if current_line:
        wrapped_lines.append(current_line.strip())

    return wrapped_lines


class ProOutputFormatter(abc.ABC):
    @abc.abstractmethod
    def to_string(self, line_length: Optional[int] = None) -> str:
        pass

    def __str__(self):
        return self.to_string()


class Table(ProOutputFormatter):
    SEPARATOR = " " * 2

    def __init__(
        self,
        headers: Optional[List[str]] = None,
        rows: Optional[List[List[str]]] = None,
        alignment: Optional[List[ContentAlignment]] = None,
    ):
        self.headers = headers if headers is not None else []
        self.rows = rows if rows is not None else []
        self.column_sizes = self._get_column_sizes()
        self.alignment = (
            alignment
            if alignment is not None
            else [ContentAlignment.LEFT] * len(self.column_sizes)
        )
        if len(self.alignment) != len(self.column_sizes):
            raise ValueError(
                "'alignment' list should have length {}".format(
                    len(self.column_sizes)
                )
            )
        self.last_column_size = self.column_sizes[-1]

    @staticmethod
    def ljust(string: str, total_length: int) -> str:
        str_length = real_len(string)
        if str_length >= total_length:
            return string
        return string + " " * (total_length - str_length)

    @staticmethod
    def rjust(string: str, total_length: int) -> str:
        str_length = real_len(string)
        if str_length >= total_length:
            return string
        return " " * (total_length - str_length) + string

    def _get_column_sizes(self) -> List[int]:
        if not self.headers and not self.rows:
            raise ValueError(
                "Empty table not supported. Please provide headers or rows."
            )

        if self.rows and any(len(item) == 0 for item in self.rows):
            raise ValueError(
                "Empty row not supported. Please provide content for each row."
            )

        all_content = []
        if self.headers:
            all_content.append(self.headers)
        if self.rows:
            all_content.extend(self.rows)

        expected_length = len(all_content[0])
        if not all(len(item) == expected_length for item in all_content):
            raise ValueError(
                "Mixed lengths in table content. "
                "Please provide headers / rows of the same length."
            )

        column_sizes = []
        for i in range(len(all_content[0])):
            column_sizes.append(
                max(real_len(str(item[i])) for item in all_content)
            )

        return column_sizes

    def to_string(self, line_length: Optional[int] = None) -> str:
        if line_length is None:
            line_length = _get_default_length()

        rows = self.rows
        if self._get_line_length() > line_length:
            rows = self.wrap_last_column(line_length)
        output = ""
        if self.headers:
            output += (
                TxtColor.BOLD
                + self._fill_row(self.headers)
                + TxtColor.ENDC
                + "\n"
            )
        for row in rows:
            output += self._fill_row(row)
            output += "\n"

        return process_formatter_config(output)

    def _get_line_length(self) -> int:
        return sum(self.column_sizes) + (len(self.column_sizes) - 1) * len(
            self.SEPARATOR
        )

    def wrap_last_column(self, max_length: int) -> List[List[str]]:
        self.last_column_size = max_length - (
            sum(self.column_sizes[:-1])
            + (len(self.column_sizes) - 1) * len(self.SEPARATOR)
        )
        new_rows = []
        for row in self.rows:
            if len(row[-1]) <= self.last_column_size:
                new_rows.append(row)
            else:
                wrapped_last_column = wrap_text(row[-1], self.last_column_size)
                new_rows.append(row[:-1] + [wrapped_last_column[0]])
                for extra_line in wrapped_last_column[1:]:
                    new_row = [" "] * (len(self.column_sizes) - 1) + [
                        extra_line
                    ]
                    new_rows.append(new_row)
        return new_rows

    def _fill_row(self, row: List[str]) -> str:
        output = ""
        for i in range(len(row) - 1):
            if self.alignment[i] == ContentAlignment.LEFT:
                output += (
                    self.ljust(row[i], self.column_sizes[i]) + self.SEPARATOR
                )
            elif self.alignment[i] == ContentAlignment.RIGHT:
                output += (
                    self.rjust(row[i], self.column_sizes[i]) + self.SEPARATOR
                )
        if self.alignment[-1] == ContentAlignment.LEFT:
            output += row[-1]
        elif self.alignment[-1] == ContentAlignment.RIGHT:
            output += self.rjust(row[-1], self.last_column_size)
        return output


class Block(ProOutputFormatter):
    INDENT_SIZE = 4
    INDENT_CHAR = " "

    def __init__(
        self,
        title: Optional[str] = None,
        content: Optional[List[Any]] = None,
    ):
        self.title = title
        self.content = content if content is not None else []

    def to_string(self, line_length: Optional[int] = None) -> str:
        if line_length is None:
            line_length = _get_default_length()

        line_length -= self.INDENT_SIZE

        output = ""

        if self.title:
            output += (
                TxtColor.BOLD
                + TxtColor.DISABLEGREY
                + self.title
                + TxtColor.ENDC
                + "\n"
            )

        for item in self.content:
            if isinstance(item, ProOutputFormatter):
                item_str = item.to_string(line_length=line_length)
            else:
                item_str = "\n".join(wrap_text(str(item), line_length)) + "\n"

            output += textwrap.indent(
                item_str, self.INDENT_CHAR * self.INDENT_SIZE
            )

        return process_formatter_config(output)
Hacker Blog, Shell İndir, Sql İnjection, XSS Attacks, LFI Attacks, Social Hacking, Exploit Bot, Proxy Tools, Web Shell, PHP Shell, Alfa Shell İndir, Hacking Training Set, DDoS Script, Denial Of Service, Botnet, RFI Attacks, Encryption
Telegram @BIBIL_0DAY