diff --git a/src/erminig/common/__init__.py b/src/erminig/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/erminig/common/pakfile.py b/src/erminig/common/pakfile.py new file mode 100644 index 0000000..96881ad --- /dev/null +++ b/src/erminig/common/pakfile.py @@ -0,0 +1,182 @@ +# +# Erminig - Librairie Pakfile +# Copyright (C) 2025 L0m1g +# Sous licence DOUARN - Voir le fichier LICENCE pour les détails +# +# Ce fichier fait partie du projet Erminig. +# Libre comme l’air, stable comme un menhir, et salé comme le beurre. +# + +import os +import toml + +class Pakfile: + """ + Représente un fichier de description de paquet (pakfile.toml) + dans le système de gestion de paquets Erminig. + + Cette classe offre les opérations essentielles pour manipuler, + vérifier et modifier les pakfiles. + """ + + BASE_PATH = "/var/govel" + + def __init__(self, package: str): + """ + Initialise la gestion du pakfile pour un paquet donné. + + :param package: Nom du paquet + """ + self.package = package + self.data = {} + + def _load(self): + """ + Charge le contenu du pakfile en mémoire + Appelé automatiquement à l'initialisation si le fichier existe + """ + package_dir, pakfile_path = self._get_paths(package) + if not os.path.exists(pakfile_path): + raise FileNotFoundError(f"Pakfile introuvable pour {self.package} dans {pakfile_path}") + + with open(pakfile_path, "r", encoding="utf-8") as f: + self.data = toml.load(f) + + def _get_paths(self, package: str) -> tuple[str, str]: + """ + Retourne le chemin du dossier du paquet et du pakfile associé. + """ + package_dir = f"{self.BASE_PATH}/{package}" + pakfile_path = f"{package_dir}/pakfile.toml" + return package_dir, pakfile_path + + def new(self, package: str): + """ + Crée un nouveau pakfile avec un squelette de base prêt à être édité. + Soulève une erreur si le pakfile existe déjà. + """ + package_dir, pakfile_path = self._get_paths(package) + + if os.path.exists(pakfile_path): + raise FileExistsError(f"Le pakfile existe déjà pour {package}") + + data = { + "header": { + "copyright": "Copyright (C) 2025 L0m1g", + "license": "Sous licence DOUARN - Voir le fichier LICENCE pour les détails", + "author": "L0m1g", + "maintainer": "L0m1g", + "description": "Description à compléter" + }, + "name": package, + "ver": "", + "rev": 1, + "src": [], + "build": "# Ajouter les commandes de construction ici", + "check": "# Ajouter les commandes check ou équivalentes ici", + "install": "# Ajouter les commandes d’installation ici" + } + + os.makedirs(package_dir, exist_ok=True) + + with open(pakfile_path, "w", encoding="utf-8") as f: + toml.dump(data, f) + + def set(self, key: str, value): + """ + Définit une valeur dans le pakfile et sauvegarde immédiatement + """ + self.data[key] = value + self._save() + + def _save(self): + """ + Ecrit le contenu actuel de self.data dans le pakfile correspondant + Créé le répertoire s'il n'existe pas. + """ + package_dir, pakfile_path = self._get_paths(self.package) + + os.makedirs(package_dir, exist_ok=True) + with open(pakfile_path, "w", encoding="utf-8") as f: + toml.dump(self.data, f) + + def get(self, key: str): + """ + Récupère la valeur d'une clé dans le pakfile + Redirige vers de getters spécifiques + + :param key: Clé à récupérer + :return: Valeur associée ou None + """ + match key: + case "name" | "ver" | "rev": + return self._get(key) + case "src" | "deps" | "bdeps": + return self._get_list(key) + case _: + return None + + def _get(self, key: str) -> str | None: + """ + Getter générique pour les chaines + """ + return self.data.get(key) + + def _get_list(self, key: str) -> list[str]: + """ + Getter spécifique aux listes + """ + return self.data.get(key,[]) + + def delete(self, package: str) -> bool: + """ + Supprime un paquet non installé et son répertoire associé. + + :param package: Nom du paquet à supprimer + :return: True si la suppression a réussi, False sinon + """ + package_dir, pakfile_path = self._get_paths(package) + + if not os.path.exists(package_dir): + print(f"Le paquet '{package}' n'existe pas. Rien à supprimer.") + return False + + try: + # On vire tout le répertoire et son contenu + for root, dirs, files in os.walk(package_dir, topdown=False): + for file in files: + os.remove(os.path.join(root, file)) + for dir in dirs: + os.rmdir(os.path.join(root, dir)) + os.rmdir(package_dir) + + print(f"Paquet '{package}' supprimé avec succès.") + return True + + except Exception as e: + print(f"Erreur lors de la suppression de '{package}': {e}") + return False + + def check(self): + """ + Vérifie la validité de la structure du pakfile. + Contrôle la présence et la cohérence des clés obligatoires. + Ne vérifie PAS la disponibilité des sources ou la qualité du code, juste la structure. + """ + required_keys = {"name", "ver", "rev", "src"} + optional_keys = {"deps", "bdeps", "build", "make", "install"} + + all_keys = set(self.data.keys()) + unknown_keys = all_keys - required_keys - optional_keys + + missing_keys = required_keys - all_keys + + if missing_keys: + print(f"Clés manquantes dans {self.package}: {', '.join(missing_keys)}") + return False + + if unknown_keys: + print(f"Clés inconnues dans {self.package}: {', '.join(unknown_keys)}") + return False + + return True