Untitled

mail@pastecode.io avatar
unknown
plain_text
21 days ago
6.1 kB
4
Indexable
Never
from enum import Enum
from enum import auto as autovalue
from pathlib import Path
from typing import Union
from kcolors.refs import BOLD, GREEN, RED
from doc.help import *
import os
import re
import pwd

ROOT_DIR = os.path.dirname(os.path.abspath(__file__))  # This is your Project Root
APP_NAME = f"sbackup"

# TODO: Ver como se comportan accesable_path y get_path_perms en
#       windows.

class Action(Enum):
    Create = autovalue()
    Restore = autovalue()
    ShowHelpLeave = autovalue()


class NormalExit(Exception):
    """Excepción usada para detener el programa con un código de salida 0."""

    pass


class NotAbsolutePath(Exception):
    pass


class NotParentAccess(Exception):
    pass


class NotPathAccess(Exception):
    pass



PathStr = Union[Path, str]
Number = Union[int, float]


def show_help():
    """Muestra el mensaje de ayuda"""
    print(HELP)


def get_executor():
    """Retorna el nombre del usuario que ejecuta el programa"""
    # return os.getlogin()
    uid = os.getuid()
    username = pwd.getpwuid(uid).pw_name
    return username


def is_integer(value) -> bool:
    """Valida que un valor sea instancia de un int pero excluye a bool.
    Esta función sirve para evitar confusiones a la hora de validar enteros."""
    return isinstance(value, int) and not isinstance(value, bool)


def validate_gname(gname: str):
    """Esta función retorna una cadena con un mensaje de error descriptivo acerca
    de por qué un nombre de grupo es inválido.

    Si el grupo no es inválido entonces se retornará una cadena vacia.

    Función usada por:
        _read_target_groups de Parameters
        _validate_gname de GroupSettings
        _validate_gname de UserSettings
    """

    e = ""

    if re.match(r"^[-_]", gname):
        first = gname[0]
        e += "los nombres de los grupos no pueden empezar por guiones o barrabajas"
        e += f" '{BGRAY}_-{END}' pero '{BGRAY}{gname}{END}' empieza por"
        e += f" '{BGRAY}{first}{END}'"

    elif re.search(r"\d$", gname):
        e += "los nombres de los grupos no pueden terminar en digitos pero el"
        e += f" grupo '{BGRAY}{gname}{END}' termina en digitos."

    elif re.search(r"[^a-zA-Z0-9-_]", gname):
        invalid_chars = re.findall(r"[^a-zA-Z0-9-_]", gname)
        invalid_chars_str = f"".join(f"{char}" for char in invalid_chars)
        invalid_chars_str = f"{BGRAY}{invalid_chars_str}{END}"
        e += "los nombres de los grupos solo pueden contener letras, guiones,"
        e += f" números o barras bajas pero el grupo '{BGRAY}{gname}{END}'"
        e += f" contiene los siguientes carácteres inválidos:"
        e += f" {invalid_chars_str}"

    return e


def accesable_path(path: Path, do_raise: bool = False):
    """Esta función retornará None si tenemos los permisos necesarios para leer
    los detalles de un path y en caso contrario retornará un objeto descriptivo
    de una clase derivada de Excepción.

        NotParentAccess: no se puede acceder a alguno de sus parents
            -> el usuario no tiene los permisos r/x o ambos en alguno de sus parents

        NotPathAccess: no se puede acceder a los detalles del path
            -> el usuario no tiene el permiso de r en el file/dir
    """

    uname = get_executor()

    if not os.access(path.parent, os.R_OK | os.X_OK):
        m = f"Se ha producido un error de acceso al tratar de acceder a los"
        m += f" detalles de '{BGRAY}{path}{END}' debido a que"
        m += f" '{BGRAY}{uname}{END}' no tiene los permisos necesarios de"
        m += f" ({GREEN}lectura{END}{BOLD}/{END}{RED}acceso{END})"
        m += f" en alguno/s de sus directorios padres."
        if do_raise:
            raise NotParentAccess(m)
        return NotParentAccess(m)

    if not os.access(path, os.R_OK):
        m = f"Se ha producido un error al tratar de acceder a los detalles de"
        m += f" '{BGRAY}{path}{END}' debido a '{BGRAY}{uname}{END}' no tiene el"
        m += " permiso necesario de lectura sobre el."
        if do_raise:
            raise NotPathAccess(m)
        return NotPathAccess(m)


def get_path_perms(path: Path, do_raise: bool = False) -> Union[Exception, str]:
    """Función que retorna los detalles de un path absoluto.

    'dr-x'   dir  | read |    -    | access
    '.rw-'   file | read | writing |   -

    [!] Esta función debe recibir un path absoluto, si no lo recibe lanzará una
    excepción con el fin de avisar al programador.

    Excepciones que puede retornar:
        NotParentAccess: no se puede acceder a alguno de sus parents.
            -> el usuario no tiene los permisos r/x o ambos en alguno de sus parents

        NotPathAccess: no se puede acceder a los detalles del path.
            -> el usuario no tiene el permiso de r en el file/dir

        FileNotFoundError: el fichero/directorio no existe.

    Si la función no ha retornado una excepción puedes averiguar los detalles:
        if 'd' in perms:  # si es un directorio
        if '.' in perms:  # si es un fichero
        if 'r' in perms:  # si hay permiso de lectura

    """
    if not path.is_absolute():
        raise NotAbsolutePath(
            f"[DEV] Has pasado un path no absoluto a get_path_perms:"
            f" '{BGRAY}{path}{END}'"
        )

    # 1. Si no podemos acceder al fichero retornamos una excepción con el motivo
    #   nota: si do_raise es true accesable_path lanzará la excepción.
    exc = accesable_path(path, do_raise)
    if isinstance(exc, Exception):
        return exc

    # 2. Si el fichero no existe retornamos FileNotFound
    if not path.exists():
        m = f"El path '{BGRAY}{path}{END}' no existe"
        if do_raise:
            raise FileNotFoundError(m)
        return FileNotFoundError(m)


    # 3. Apuntamos el tipo de fichero
    perms = "d" if path.is_dir() else "."

    # 4. Apuntamos los permisos
    r = os.access(path, os.R_OK)
    w = os.access(path, os.W_OK)
    x = os.access(path, os.X_OK)
    perms += "r" if r else "-"
    perms += "w" if w else "-"
    perms += "x" if x else "-"

    return perms
Leave a Comment