From db9b5978785c6df8c16d921970ec4f56fcce2648 Mon Sep 17 00:00:00 2001 From: L0m1g Date: Mon, 5 May 2025 16:16:24 +0200 Subject: [PATCH] Add: First packages build --- erminig/cli/govel.py | 15 +++++- erminig/controllers/govel/build.py | 22 +++++--- erminig/core/package.py | 84 ++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 9 deletions(-) diff --git a/erminig/cli/govel.py b/erminig/cli/govel.py index b4dfed5..bad28a4 100644 --- a/erminig/cli/govel.py +++ b/erminig/cli/govel.py @@ -11,7 +11,8 @@ import argparse from pathlib import Path from erminig.core.config import Config from erminig.controllers.govel.pakva import Pakva -from erminig.controllers.govel.build import run_build_function +from erminig.controllers.govel.build import run_build_function, run_pak_function +from erminig.core.package import Package def main(): @@ -33,9 +34,19 @@ def main(): return pakva = Pakva.read(pakva_path) - build_success = run_build_function(pakva.path, pakva.name, pakva.version) + pak_success = False + build_success = run_build_function(pakva.path, pakva.name, pakva.version) if build_success: + pak_success = run_pak_function(pakva.path, pakva.name, pakva.version) + + if pak_success: + tmp_path = f"{Config.BUILD_DIR}/{pakva.name}-{pakva.version}" + pkg = Package(pakva.name, pakva.version, tmp_path) + pkg.generate_manifest() + pkg.write_manifest() + pkg.copy_pakva(pakva.path) + pkg.build_archive() print(f"[GOVEL] Build réussi pour {pakva.name}") else: print(f"[GOVEL] Build échoué pour {pakva.name}") diff --git a/erminig/controllers/govel/build.py b/erminig/controllers/govel/build.py index f45b5c2..a9ac854 100644 --- a/erminig/controllers/govel/build.py +++ b/erminig/controllers/govel/build.py @@ -16,27 +16,26 @@ check_root check_user_exists("pak") -@run_as_user("pak") -def run_build_function(pakva_path, name, version): +def run_pakva_function(pakva_path, name, version, func_name): """ - Exécute la fonction build() du fichier Pakva donné. + Exécute une fonction d’un fichier Pakva donné (ex: build, pak). """ build_root = Config.BUILD_DIR / f"{name}-{version}" src_dir = build_root / "src" tmp_dir = build_root / "tmp" - os.makedirs(src_dir, exist_ok=True) os.makedirs(tmp_dir, exist_ok=True) env = os.environ.copy() env["SRC"] = str(src_dir) env["TMP"] = str(tmp_dir) + try: result = subprocess.run( f""" set -e source "{pakva_path}" - build + {func_name} """, shell=True, check=True, @@ -46,10 +45,19 @@ def run_build_function(pakva_path, name, version): text=True, env=env, ) - print(f"[BUILD] Succès : {pakva_path.name}") + print(f"[{func_name.upper()}] Succès : {pakva_path.name}") print(result.stdout) return True except subprocess.CalledProcessError as e: - print(f"[BUILD] Échec : {pakva_path.name}") + print(f"[{func_name.upper()}] Échec : {pakva_path.name}") print(e.stderr) return False + + +@run_as_user("pak") +def run_build_function(pakva_path, name, version): + return run_pakva_function(pakva_path, name, version, "build") + + +def run_pak_function(pakva_path, name, version): + return run_pakva_function(pakva_path, name, version, "pak") diff --git a/erminig/core/package.py b/erminig/core/package.py index e69de29..4145992 100644 --- a/erminig/core/package.py +++ b/erminig/core/package.py @@ -0,0 +1,84 @@ +import os +import hashlib +import tarfile +import tempfile +import shutil +import pwd +import grp +from pathlib import Path +from erminig.core.config import Config + + +class Package: + def __init__(self, name, version, tmp_dir): + self.name = name + self.version = version + self.tmp_dir = Path(tmp_dir) + self.manifest = [] + + def generate_manifest(self): + install_root = self.tmp_dir / "tmp" + for path in install_root.rglob("*"): + if path.is_file(): + rel_path = Path("/") / path.relative_to(install_root) + stat = path.stat() + md5 = hashlib.md5(path.read_bytes()).hexdigest() + user = pwd.getpwuid(stat.st_uid).pw_name + group = grp.getgrgid(stat.st_gid).gr_name + self.manifest.append( + { + "path": str(rel_path), + "md5": md5, + "mode": oct(stat.st_mode & 0o777), + "user": user, + "group": group, + } + ) + + def write_manifest(self): + manifest_path = self.tmp_dir / "MANIFEST" + with open(manifest_path, "w") as f: + for entry in self.manifest: + f.write( + f"{entry['path']} {entry['md5']} {entry['mode']} {entry['user']} {entry['group']}\n" + ) + + def copy_pakva(self, pakva_path): + dest = self.tmp_dir / "Pakva" + content = Path(pakva_path).read_text() + dest.write_text(content) + + # Dans ta classe Package + + def build_archive(self): + temp_dir = tempfile.mkdtemp() + temp_path = Path(temp_dir) + + # Copie les fichiers Pakva et MANIFEST dans le répertoire temporaire + shutil.copy(self.tmp_dir / "Pakva", temp_path / "Pakva") + shutil.copy(self.tmp_dir / "MANIFEST", temp_path / "MANIFEST") + + # Crée le dossier Files et copie dedans UNIQUEMENT le contenu de $TMP + files_dir = temp_path / "Files" + files_dir.mkdir() + + for item in (self.tmp_dir).iterdir(): + if item.name in ["Pakva", "MANIFEST"]: + continue + install_dir = self.tmp_dir / "tmp" + if install_dir.exists(): + for item in install_dir.iterdir(): + dest = files_dir / item.name + if item.is_dir(): + shutil.copytree(item, dest) + else: + shutil.copy2(item, dest) + # Crée l'archive .bzh sans inclure les dossiers de travail + archive_path = Config.BUILD_DIR / f"{self.name}-{self.version}.bzh" + with tarfile.open(archive_path, "w|xz") as tar: + tar.add(temp_path / "Pakva", arcname="Pakva") + tar.add(temp_path / "MANIFEST", arcname="MANIFEST") + tar.add(files_dir, arcname="Files") + + shutil.rmtree(temp_path) + return archive_path