Source code for libdebug.utils.libcontext
#
# This file is part of libdebug Python library (https://github.com/libdebug/libdebug).
# Copyright (c) 2023-2024 Gabriele Digregorio, Roberto Alessandro Bertolini. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for details.
#
from __future__ import annotations
import sys
from contextlib import contextmanager
from copy import deepcopy
from libdebug.liblog import liblog
[docs]
class LibContext:
    """A class that holds the global context of the library."""
    _instance = None
    def __new__(cls: type):
        """Create a new instance of the class if it does not exist yet.
        Returns:
            LibContext: the instance of the class.
        """
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._initialized = False
        return cls._instance
    def __init__(self: LibContext) -> None:
        """Initializes the context."""
        if self._initialized:
            return
        self._sym_lvl = 3
        self._debugger_logger = "INFO"
        self._pipe_logger = "INFO"
        self._general_logger = "INFO"
        # Adjust log levels based on command-line arguments
        if len(sys.argv) > 1:
            if "debugger" in sys.argv:
                liblog.debugger_logger.setLevel("DEBUG")
                self._debugger_logger = "DEBUG"
            elif "pipe" in sys.argv:
                liblog.pipe_logger.setLevel("DEBUG")
                self._pipe_logger = "DEBUG"
            elif "dbg" in sys.argv:
                self._set_debug_level_for_all()
                self._debugger_logger = "DEBUG"
                self._pipe_logger = "DEBUG"
                self._general_logger = "DEBUG"
        self._initialized = True
        self._arch = "amd64"
        self._terminal = []
    def _set_debug_level_for_all(self: LibContext) -> None:
        """Set the debug level for all the loggers to DEBUG."""
        for logger in [
            liblog.general_logger,
            liblog.debugger_logger,
            liblog.pipe_logger,
        ]:
            logger.setLevel("DEBUG")
    @property
    def sym_lvl(self: LibContext) -> int:
        """Property getter for sym_lvl.
        Returns:
            _sym_lvl (int): the current symbol level.
        """
        return self._sym_lvl
    @sym_lvl.setter
    def sym_lvl(self: LibContext, value: int) -> None:
        """Property setter for sym_lvl, ensuring it's between 0 and 5."""
        if 0 <= value <= 5:
            self._sym_lvl = value
        else:
            raise ValueError("sym_lvl must be between 0 and 5")
    @property
    def debugger_logger(self: LibContext) -> str:
        """Property getter for debugger_logger.
        Returns:
            _debugger_logger (str): the current debugger logger level.
        """
        return self._debugger_logger
    @debugger_logger.setter
    def debugger_logger(self: LibContext, value: str) -> None:
        """Property setter for debugger_logger, ensuring it's a valid logging level."""
        if value in ["DEBUG", "INFO"]:
            self._debugger_logger = value
            liblog.debugger_logger.setLevel(value)
        else:
            raise ValueError("debugger_logger must be a valid logging level")
    @property
    def pipe_logger(self: LibContext) -> str:
        """Property getter for pipe_logger.
        Returns:
            _pipe_logger (str): the current pipe logger level.
        """
        return self._pipe_logger
    @pipe_logger.setter
    def pipe_logger(self: LibContext, value: str) -> None:
        """Property setter for pipe_logger, ensuring it's a valid logging level."""
        if value in ["DEBUG", "INFO"]:
            self._pipe_logger = value
            liblog.pipe_logger.setLevel(value)
        else:
            raise ValueError("pipe_logger must be a valid logging level")
    @property
    def general_logger(self: LibContext) -> str:
        """Property getter for general_logger.
        Returns:
            _general_logger (str): the current general logger level.
        """
        return self._general_logger
    @general_logger.setter
    def general_logger(self: LibContext, value: str) -> None:
        """Property setter for general_logger, ensuring it's a valid logging level."""
        if value in ["DEBUG", "INFO"]:
            self._general_logger = value
            liblog.general_logger.setLevel(value)
        else:
            raise ValueError("general_logger must be a valid logging level")
    @property
    def arch(self: LibContext) -> str:
        """Property getter for architecture.
        Returns:
            _arch (str): the current architecture.
        """
        return self._arch
    @arch.setter
    def arch(self: LibContext, value: str) -> None:
        """Property setter for arch, ensuring it's a valid architecture."""
        if value in ["amd64"]:
            self._arch = value
        else:
            raise RuntimeError("The specified architecture is not supported")
    @property
    def terminal(self: LibContext) -> list[str]:
        """Property getter for terminal.
        Returns:
            _terminal (str): the current terminal.
        """
        return self._terminal
    @terminal.setter
    def terminal(self: LibContext, value: list[str] | str) -> None:
        """Property setter for terminal, ensuring it's a valid terminal."""
        if isinstance(value, str):
            value = [value]
        self._terminal = value
[docs]
    def update(self: LibContext, **kwargs: ...) -> None:
        """Update the context with the given values."""
        for key, value in kwargs.items():
            if hasattr(self, key):
                setattr(self, key, value) 
[docs]
    @contextmanager
    def tmp(self: LibContext, **kwargs: ...) -> ...:
        """Context manager that temporarily changes the library context. Use "with" statement."""
        # Make a deep copy of the current state
        old_context = deepcopy(self.__dict__)
        self.update(**kwargs)
        try:
            yield
        finally:
            # Restore the original state
            self.__dict__.update(old_context)
            liblog.debugger_logger.setLevel(self.debugger_logger)
            liblog.pipe_logger.setLevel(self.pipe_logger) 
 
# Global context instance
libcontext = LibContext()