UNPKG

penguins-eggs

Version:

A remaster system tool, compatible with Almalinux, Alpine, Arch, Debian, Devuan, Fedora, Manjaro, Opensuse, Ubuntu and derivatives

331 lines (330 loc) 14.3 kB
/** * ./src/appimage/dependency-manager.ts * penguins-eggs v.25.11.x / ecmascript 2020 * author: Piero Proietti * email: piero.proietti@gmail.com * license: MIT */ import * as fs from 'fs'; import * as path from 'path'; import Distro from '../classes/distro.js'; import Diversions from '../classes/diversions.js'; import { execSync } from '../lib/utils.js'; const ALPINE_PACKAGES = [ 'alp-conf', 'apk-tools', 'bash', 'cryptsetup', 'curl', 'dosfstools', 'e2fsprogs', 'efibootmgr', 'findutils', 'git', 'grub', 'grub-efi', 'isolinux', 'jq', 'linux-firmware', 'lvm2', 'mtools', 'ncurses', 'nodejs', 'openssl', 'parted', 'procps', 'py3-setuptools', 'rsync', 'sfdisk', 'shadow', 'squashfs-tools', 'syslinux', 'tar', 'xorriso', 'xz', 'zstd' ].join(' '); const META_PACKAGE_NAME = 'penguins-eggs-deps'; const ALPINE_VIRTUAL_PKG = '.penguins-eggs-deps'; // Nota il punto iniziale export class DependencyManager { familyId; appRoot; distro; constructor() { this.distro = new Distro(); this.familyId = this.distro.familyId; // Gestione specifica per Manjaro (che si identifica come archlinux ma richiede tools diversi) if (this.distro.familyId === 'archlinux' && Diversions.isManjaroBased(this.distro.distroLike)) { this.familyId = 'manjaro'; } // Definizione della root per cercare i pacchetti if (process.env.APPDIR) { // In AppImage, i file sono in $APPDIR/distro (o dove li hai configurati) this.appRoot = path.join(process.env.APPDIR, 'distro-packages'); } else { // In sviluppo locale, cerchiamo nella cartella corrente o una di fallback this.appRoot = process.cwd(); } } /** * Installa i distro meta-pacchetti corretti in base alla distribuzione. */ installDistroPackages() { const depsBase = this.appRoot; // CHECK AGGIUNTO: Se è già installato, evitiamo lavoro inutile? // Se vuoi forzare l'installazione sempre, rimuovi questo blocco if. if (this.isInstalled()) { console.log(`[eggs] The meta-packages for ${this.familyId} are already installed.`); return true; } try { switch (this.familyId) { // ========================================== // ALPINE LINUX (Nativo) // ========================================== case 'alpine': { console.log('[eggs] Alpine dependencies configuration (Virtual Package)...'); // --virtual crea un pacchetto fittizio rimuovibile che raggruppa le dipendenze execSync(`apk add --no-cache --virtual ${ALPINE_VIRTUAL_PKG} ${ALPINE_PACKAGES}`, { stdio: 'inherit' }); return true; } // ========================================== // ARCHLINUX // ========================================== case 'archlinux': { const archFile = findPackage(path.join(depsBase, 'arch'), '.zst'); if (archFile) { console.log(`[eggs] Installing the Arch Meta-Package: ${path.basename(archFile)}`); execSync(`pacman -Sy --noconfirm && pacman -U --noconfirm "${archFile}"`, { stdio: 'inherit' }); return true; } break; } // ========================================== // DEBIAN / UBUNTU FAMILY // ========================================== case 'debian': { const debFile = findPackage(path.join(depsBase, 'debian'), '.deb'); if (debFile) { console.log(`[eggs] Installing Debian Meta-Package: ${path.basename(debFile)}`); // Gestione sicura per l'utente _apt copiando in /tmp const tempDebPath = path.join('/tmp', path.basename(debFile)); try { fs.copyFileSync(debFile, tempDebPath); execSync(`apt-get update && apt-get install -y "${tempDebPath}"`, { stdio: 'inherit' }); } finally { // Assicuriamoci di pulire il file temporaneo anche in caso di errore if (fs.existsSync(tempDebPath)) { fs.unlinkSync(tempDebPath); } } return true; } break; } // ========================================== // RHEL / CENTOS / ALMA (RPM Family) // ========================================== case 'el9': { // Cerca file contenente 'el9' const elFile = findPackage(path.join(depsBase, 'rpm'), '.rpm', 'el9'); if (elFile) { console.log(`[eggs] Installing EL9 Meta-Package: ${path.basename(elFile)}`); execSync(`dnf install -y "${elFile}"`, { stdio: 'inherit' }); return true; } break; } // ========================================== // FEDORA (RPM Family) // ========================================== case 'fedora': { // Cerca file contenente 'fc42' o 'fc' dentro la cartella rpm const fedoraFile = findPackage(path.join(depsBase, 'rpm'), '.rpm', 'fc42'); if (fedoraFile) { console.log(`[eggs] Installing Fedora Meta-Package: ${path.basename(fedoraFile)}`); execSync(`dnf install -y "${fedoraFile}"`, { stdio: 'inherit' }); return true; } break; } // ========================================== // MANJARO (Variant: manjaro-tools-iso) // ========================================== case 'manjaro': { const manjaroFile = findPackage(path.join(depsBase, 'manjaro'), '.zst'); if (manjaroFile) { console.log(`[eggs] Installing Manjaro Meta-Package: ${path.basename(manjaroFile)}`); execSync(`pacman -Sy --noconfirm && pacman -U --noconfirm "${manjaroFile}"`, { stdio: 'inherit' }); return true; } break; } // ========================================== // OPENSUSE (RPM Family) // ========================================== case 'opensuse': { const suseFile = findPackage(path.join(depsBase, 'rpm'), '.rpm', 'opensuse'); if (suseFile) { console.log(`[eggs] Installing openSUSE Meta-Package: ${path.basename(suseFile)}`); // --allow-unsigned-rpm è necessario perché i nostri pacchetti non sono firmati con GPG execSync(`zypper install -y --allow-unsigned-rpm "${suseFile}"`, { stdio: 'inherit' }); return true; } break; } default: { console.warn(`[eggs] Distribuzione '${this.familyId}' non supportata dai meta-pacchetti automatici.`); return false; } } } catch (error) { console.error(`[eggs] FATAL ERROR installing dependencies: ${error.message}`); // Rilanciamo l'errore per permettere al chiamante di decidere se uscire o continuare throw error; } // Se siamo qui, non è stato trovato il file specifico console.warn(`[eggs] No meta-package found for ${this.familyId} in ${depsBase}`); return false; } /** * Verifica se i distro-meta-pacchetto sono già installati nel sistema. * @returns true se installati, false altrimenti */ isInstalled() { try { switch (this.familyId) { case 'alpine': { // apk info -e esce con 0 se esiste, 1 se no execSync(`apk info -e ${ALPINE_VIRTUAL_PKG}`, { stdio: 'ignore' }); return true; } case 'archlinux': case 'manjaro': { // pacman -Q esce con 0 se trovato, 1 se no execSync(`pacman -Q ${META_PACKAGE_NAME}`, { stdio: 'ignore' }); return true; } case 'debian': { // dpkg -s verifica lo stato del pacchetto execSync(`dpkg -s ${META_PACKAGE_NAME}`, { stdio: 'ignore' }); return true; } case 'el9': case 'fedora': case 'opensuse': { // rpm -q funziona per tutte le distro RPM execSync(`rpm -q ${META_PACKAGE_NAME}`, { stdio: 'ignore' }); return true; } default: { return false; } } } catch { // Se il comando fallisce (exit code != 0), il pacchetto non è installato return false; } } /** * Reinstalla i distro-meta-pacchetti: Rimuove e poi Installa. * Utile per forzare un aggiornamento delle dipendenze o riparare un'installazione. */ reinstallDistroPackages() { console.log(`[eggs] Reinstallazione distro meta-packages per: ${this.familyId}...`); // Tentiamo la rimozione (ignoriamo errori se non era installato) try { this.removeDistroPackages(); } catch { console.log(`[eggs] No previous versions found or removal not necessary.`); } // Procediamo con l'installazione pulita return this.installDistroPackages(); } /** * Rimuove i distro meta-pacchetti e pulisce le dipendenze. */ removeDistroPackages() { console.log(`[eggs] Removing distro meta-packages for: ${this.familyId}...`); try { switch (this.familyId) { // ========================================== // ALPINE LINUX // ========================================== case 'alpine': { console.log('[eggs] Removing Alpine dependencies...'); execSync(`apk del ${ALPINE_VIRTUAL_PKG}`, { stdio: 'inherit' }); return true; } // ========================================== // ARCHLINUX/MANJARO // ========================================== case 'archlinux': { console.log(`[eggs] Removing package ${META_PACKAGE_NAME} (Arch/Manjaro)...`); // -Rns: Rimuove pacchetto, configurazioni e dipendenze non usate da altri execSync(`pacman -Rns --noconfirm ${META_PACKAGE_NAME}`, { stdio: 'inherit' }); return true; } // ========================================== // DEBIAN / UBUNTU FAMILY // ========================================== case 'debian': { console.log(`[eggs] Removing package ${META_PACKAGE_NAME} (Debian/Devuan/Ubuntu)...`); // Purge rimuove anche i file di configurazione // autoremove pulisce le dipendenze installate dal meta-pacchetto execSync(`apt-get purge -y ${META_PACKAGE_NAME} && apt-get autoremove -y`, { stdio: 'inherit' }); return true; } // ========================================== // RPM FAMILY (EL9 / FEDORA / OPENSUSE) // ========================================== case 'el9': case 'fedora': { console.log(`[eggs] Removing package ${META_PACKAGE_NAME} (RPM/DNF)...`); execSync(`dnf remove -y ${META_PACKAGE_NAME}`, { stdio: 'inherit' }); return true; } case 'opensuse': { console.log(`[eggs] Removing package ${META_PACKAGE_NAME} (Zypper)...`); // -u (--clean-deps) rimuove anche le dipendenze non più necessarie execSync(`zypper rm -y -u ${META_PACKAGE_NAME}`, { stdio: 'inherit' }); return true; } default: { console.warn(`[eggs] Removal not supported automatically for '${this.familyId}'.`); return false; } } } catch (error) { // Spesso la rimozione fallisce semplicemente perché il pacchetto non c'è. // Logghiamo warning invece di errore fatale. console.warn(`[eggs] Warning removing: ${error.message}`); return false; } } } /** * Helper Function (fuori classe, come richiesto) * Cerca un file pacchetto in una directory specifica. */ function findPackage(dir, ext, pattern = '') { try { if (!fs.existsSync(dir)) { // console.warn(`[DependencyManager] Directory non trovata: ${dir}`); return null; } const files = fs.readdirSync(dir); const found = files.find((file) => file.endsWith(ext) && file.includes(pattern)); return found ? path.join(dir, found) : null; } catch (error) { console.error(`[DependencyManager] Error reading directory ${dir}`, error); return null; } }