UNPKG

penguins-eggs

Version:

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

502 lines (501 loc) 19.4 kB
/** * ./src/commands/tools/repo.ts * penguins-eggs v.25.7.x / ecmascript 2020 * author: Piero Proietti * email: piero.proietti@gmail.com * license: MIT */ import { Command, Flags } from '@oclif/core'; import fs from 'node:fs'; import Distro from '../../classes/distro.js'; import Diversions from '../../classes/diversions.js'; import Utils from '../../classes/utils.js'; import { exec } from '../../lib/utils.js'; const repoUrl = `https://penguins-eggs.net/repos`; // no slash at end const repoKeyUrl = repoUrl + '/KEY.asc'; const repoPath = '/etc/apt/sources.list.d/penguins-repos'; // Base path without extension const repoKeyPath = '/usr/share/keyrings/penguins-repos.gpg'; // Alpine const alpineRepoUrl = repoUrl + '/alpine/'; const alpineKeyName = 'piero.proietti@gmail.com-662b958c'; const alpineKeyUrl = repoUrl + `/alpine/${alpineKeyName}.rsa.pub`; const alpineKeyPath = `/etc/apk/keys/${alpineKeyName}.rsa.pub`; const alpineRepoFile = '/etc/apk/repositories'; // RPM (Fedora/EL) const rpmKeyUrl = repoKeyUrl; const rpmKeyOwner = 'piero.proietti@gmail.com'; // Per cercare e rimuovere la chiave const rpmRepoFilePath = '/etc/yum.repos.d/penguins-eggs.repo'; // Percorso di destinazione const rpmRepoFedoraUrl = repoUrl + '/rpm/fedora/42'; const rpmRepoEl9Url = repoUrl + '/rpm/el9'; // RPM (openSUSE) const opensuseKeyUrl = repoKeyUrl; const opensuseRepoUrl = repoUrl + '/rpm/opensuse/leap'; const opensuseRepoFilePath = '/etc/zypp/repos.d/penguins-eggs.repo'; // NUOVO const opensuseKeyOwner = rpmKeyOwner; // RIUTILIZZA /** * */ export default class Repo extends Command { static description = 'add/remove penguins-repos'; static examples = ['sudo eggs tools repo --add', 'sudo eggs tools repo --remove']; static flags = { add: Flags.boolean({ char: 'a', description: 'add penguins-repos' }), help: Flags.help({ char: 'h' }), nointeractive: Flags.boolean({ char: 'n', description: 'no user interaction' }), remove: Flags.boolean({ char: 'r', description: 'remove penguins-repos' }), verbose: Flags.boolean({ char: 'v', description: 'verbose' }) }; /** * */ async run() { const { flags } = await this.parse(Repo); Utils.titles(this.id + ' ' + this.argv); const { nointeractive } = flags; if (Utils.isRoot()) { const distro = new Distro(); const msgReposAdd = 'Are you sure you want to add https://penguins-eggs.net/repos to your repositories?'; const msgReposRemove = 'Are you sure to remove https://penguins-eggs.net/repos to your repositories?'; switch (distro.familyId) { case 'alpine': { /** * Alpine */ if (flags.add) { Utils.warning(msgReposAdd); if (nointeractive || (await Utils.customConfirm('Select yes to continue'))) { await alpineRepoAdd(); } } else if (flags.remove) { Utils.warning(msgReposRemove); if (nointeractive || (await Utils.customConfirm('Select yes to continue'))) { await alpineRepoRemove(); } } await exec('apk update'); break; } case 'archlinux': { if (flags.add) { Utils.warning(msgReposAdd); if (await Utils.customConfirm('Select yes to continue')) { await archlinuxRepoAdd(distro.distroId); } } else if (flags.remove) { Utils.warning(msgReposRemove); if (await Utils.customConfirm('Select yes to continue')) { await archlinuxRepoRemove(distro.distroId); } } break; } case 'debian': { /** * Debian */ if (flags.add) { Utils.warning(msgReposAdd); if (nointeractive || (await Utils.customConfirm('Select yes to continue'))) { await debianRemove(); if (await debianIs822()) { await debianAdd822(); } else { await debianAdd(); } } } else if (flags.remove) { Utils.warning(msgReposRemove); if (nointeractive || (await Utils.customConfirm('Select yes to continue'))) { await debianRemove(); } await exec('apt-get update'); } break; } case 'fedora': { /** * RPM (Fedora/EL) */ let repoUrl = rpmRepoFedoraUrl; if (distro.distroId !== 'Fedora') { // RHEL9 repoUrl = rpmRepoEl9Url; } if (flags.add) { Utils.warning(msgReposAdd); if (nointeractive || (await Utils.customConfirm('Seleziona sì per continuare...'))) { await rpmRepoAdd(repoUrl, rpmKeyUrl); } } else if (flags.remove) { Utils.warning(msgReposRemove); if (nointeractive || (await Utils.customConfirm('Select yes to continue'))) { await rpmRepoRemove(rpmRepoFilePath, rpmKeyOwner); } } await exec('dnf check-update'); break; } case 'opensuse': { /** * openSUSE */ if (flags.add) { Utils.warning(msgReposAdd); if (nointeractive || (await Utils.customConfirm('Select yes to continue'))) { // Passiamo sia repoUrl che keyUrl await opensuseRepoAdd(opensuseRepoUrl, opensuseKeyUrl); } } else if (flags.remove) { Utils.warning(msgReposRemove); if (nointeractive || (await Utils.customConfirm('Select yes to continue'))) { // RIUTILIZZIAMO la funzione di rimozione di Fedora! await rpmRepoRemove(opensuseRepoFilePath, opensuseKeyOwner); } } // Aggiungiamo un refresh finale await exec('zypper refresh'); break; } default: { /** * All the others */ Utils.warning(`Distro: ${distro.distroId}/${distro.codenameId}, cannot use penguins-eggs.net/repos nor chaotic-aur!`); } } } } } /** * =============================================== * ALPINE * =============================================== */ /** * alpineRepoAdd() */ async function alpineRepoAdd() { console.log('Adding Alpine repository...'); const echo = Utils.setEcho(true); if (fs.existsSync(alpineKeyPath)) { console.log('Chiave già esistente.'); } else { await exec(`curl -fsSL ${alpineKeyUrl} -o ${alpineKeyPath}`, echo); } const repoFileContent = fs.readFileSync(alpineRepoFile, 'utf8'); if (repoFileContent.includes(alpineRepoUrl)) { console.log('La linea del repository è già presente in /etc/apk/repositories.'); } else { fs.appendFileSync(alpineRepoFile, `\n${alpineRepoUrl}\n`); console.log('Repository aggiunto.'); } console.log('Esegui "apk update" per aggiornare i repository.'); } /** * alpineRepoRemove() */ async function alpineRepoRemove() { console.log('Rimozione repository Alpine...'); const echo = Utils.setEcho(true); // Rimuovi chiave if (fs.existsSync(alpineKeyPath)) { await exec(`rm -f ${alpineKeyPath}`, echo); console.log('Chiave del repository rimossa.'); } else { console.log('Chiave del repository non trovata.'); } // Rimuovi da /etc/apk/repositories if (fs.existsSync(alpineRepoFile)) { const content = fs.readFileSync(alpineRepoFile, 'utf8'); if (content.includes(alpineRepoUrl)) { const newLines = content.split('\n').filter((line) => line.trim() !== alpineRepoUrl); fs.writeFileSync(alpineRepoFile, newLines.join('\n')); console.log('Linea del repository rimossa da /etc/apk/repositories.'); } else { console.log('Linea del repository non trovata in /etc/apk/repositories.'); } } console.log('Esegui "apk update" per aggiornare i repository.'); } /** * =============================================== * ARCH * =============================================== */ /** * archlinuxRepoAdd() */ async function archlinuxRepoAdd(distroId = 'Arch') { console.log(`Adding penguins-repos for ${distroId}`); const repoBlockIdentifier = '# penguins-repos'; const repoName = '[penguins-eggs]'; const keyId = 'F6773EA7D2F309BA3E5DE08A45B10F271525403F'; let serverUrl = repoUrl + '/arch'; if (Diversions.isManjaroBased(distroId)) { serverUrl = repoUrl + '/manjaro'; } const pacmanConfPath = '/etc/pacman.conf'; const echo = Utils.setEcho(true); const pacmanConfContent = fs.readFileSync(pacmanConfPath, 'utf8'); if (pacmanConfContent.includes(repoName)) { console.log(`The repository ${repoName} already exists in ${pacmanConfPath}!`); return; } console.log(`Importazione della chiave GPG: ${keyId}...`); await exec(`pacman-key --recv-key ${keyId} --keyserver keyserver.ubuntu.com`, echo); await exec(`pacman-key --lsign-key ${keyId}`, echo); let repoBlock = ``; repoBlock += repoBlockIdentifier + `\n`; repoBlock += `${repoName}\n`; repoBlock += `SigLevel = Optional TrustAll\n`; repoBlock += `Server = ${serverUrl}\n`; fs.appendFileSync(pacmanConfPath, repoBlock); let message = 'Run “sudo pacman -Syyu” to update pacman databases.'; if (Diversions.isManjaroBased(distroId)) { message = 'Run “sudo pamac update --force-refresh" to update pacman databases.'; } console.log('Repository successfully removed!'); console.log(message); } /** * archlinuxRepoRemove() * @param distroId */ async function archlinuxRepoRemove(distroId = 'Arch') { console.log(`Removing penguins-repos for ${distroId}`); const repoBlockIdentifier = '# penguins-repos'; const repoName = '[penguins-eggs]'; let serverUrl = repoUrl + '/arch'; if (Diversions.isManjaroBased(distroId)) { serverUrl = repoUrl + '/manjaro'; } const pacmanConfPath = '/etc/pacman.conf'; let pacmanConfContent = fs.readFileSync(pacmanConfPath, 'utf8'); if (pacmanConfContent.includes(repoName)) { console.log(`Removing repository ${repoName} in progress...`); let repoBlock = ``; repoBlock += repoBlockIdentifier + `\n`; repoBlock += `${repoName}\n`; repoBlock += `SigLevel = Optional TrustAll\n`; repoBlock += `Server = ${serverUrl}\n`; pacmanConfContent = pacmanConfContent.replace(repoBlock, ''); fs.writeFileSync(pacmanConfPath, pacmanConfContent.trim()); let message = 'Run “sudo pacman -Syyu” to update pacman databases.'; if (Diversions.isManjaroBased(distroId)) { message = 'Run “sudo pamac update --force-refresh" to update pacman databases.'; } console.log('Repository successfully removed!'); console.log(message); } else { console.log('The repository was not present in /etc/pacman.conf.'); } } /** * archlinuxAurAdd() */ async function archlinuxAurAdd() { const path = '/var/cache/pacman/pkg/'; const keyring = 'chaotic-keyring.pkg.tar.zst'; const mirrorlist = 'chaotic-mirrorlist.pkg.tar.zst'; const echo = Utils.setEcho(true); if (fs.existsSync(path + keyring) && fs.existsSync(path + mirrorlist)) { console.log('repository Chaotic-AUR, already present!'); await archlinuxAurRemove(); process.exit(); } await exec('pacman-key --recv-key FBA220DFC880C036 --keyserver keyserver.ubuntu.com', echo); await exec('pacman-key --lsign-key FBA220DFC880C036', echo); await exec("pacman -U 'https://cdn-mirror.chaotic.cx/chaotic-aur/chaotic-keyring.pkg.tar.zst' 'https://cdn-mirror.chaotic.cx/chaotic-aur/chaotic-mirrorlist.pkg.tar.zst'", echo); // Append to /etc/pacman.conf const chaoticAppend = '\n[chaotic-aur]\nInclude = /etc/pacman.d/chaotic-mirrorlist\n\n'; fs.appendFileSync('/etc/pacman.conf', chaoticAppend); } /** * archlinuxAurRemove() */ async function archlinuxAurRemove() { const path = '/var/cache/pacman/pkg/'; const keyring = 'chaotic-keyring.pkg.tar.zst'; const mirrorlist = 'chaotic-mirrorlist.pkg.tar.zst'; if (fs.existsSync(path + keyring) && fs.existsSync(path + mirrorlist)) { console.log('to remove chaotic-aur:\n'); console.log(`sudo rm ${path}${keyring}`); console.log(`sudo rm ${path}${mirrorlist}`); console.log(`sudo nano /etc/pacman.conf`); console.log(`remove at the end:`); console.log(`[chaotic-aur]`); console.log(`Include = /etc/pacman.d/chaotic-mirrorlist`); } } /** * =============================================== * DEBIAN * =============================================== */ /** * debianAdd() */ async function debianAdd() { await exec(`curl -fsSL ${repoKeyUrl} | gpg --dearmor -o ${repoKeyPath}`); const content = `deb [signed-by=${repoKeyPath}] ${repoUrl}/deb stable main\n`; fs.writeFileSync(`${repoPath}.list`, content); } /** * debianRemove() */ async function debianRemove() { await exec(`rm -f ${repoKeyPath}`); await exec(`rm -f ${repoPath}*`); } /** * debianIs822() */ async function debianIs822() { let retval = false; const test = `([ -f /etc/apt/sources.list.d/ubuntu.sources ] || [ -f /etc/apt/sources.list.d/debian.sources ]) && echo "1" || echo "0"`; const is822Result = await exec(test, { capture: true, echo: false }); if (is822Result.code === 0 && is822Result.data.trim() === '1') { retval = true; } return retval; } /** * debianAdd822() */ async function debianAdd822() { await exec(`curl -fsSL ${repoKeyUrl} | gpg --dearmor -o ${repoKeyPath}`); let content = ''; content += `Types: deb\n`; content += `URIs: ${repoUrl}/deb\n`; // Correct URI for packages content += `Suites: stable\n`; // It's better to be specific content += `Components: main\n`; content += `Signed-By: ${repoKeyPath}\n`; fs.writeFileSync(`${repoPath}.sources`, content); } /** * =============================================== * Fedora/EL9 * =============================================== */ /** * rpmRepoAdd() * @param repoUrl * @param keyUrl */ /** * rpmRepoAdd() * @param repoUrl * @param keyUrl */ async function rpmRepoAdd(repoUrl, keyUrl) { console.log(`Adding RPM repository for ${repoUrl}...`); const echo = Utils.setEcho(true); // 1. Definisci il contenuto del file .repo const repoContent = ` [penguins-eggs] name=penguins-eggs.net repos baseurl=${repoUrl} enabled=1 gpgcheck=1 gpgkey=${keyUrl} `; // keyUrl (https://penguins-eggs.net/repos/KEY.asc) è già corretto per il campo gpgkey try { // 2. Scrivi il file .repo fs.writeFileSync(rpmRepoFilePath, repoContent.trim()); console.log(`Repository file created at ${rpmRepoFilePath}`); // 3. Importa la chiave GPG nel database RPM // (dnf lo farebbe comunque, ma importarlo è più pulito) await exec(`rpm --import ${keyUrl}`, echo); console.log(`GPG key imported from ${keyUrl}`); // 4. Pulisci la cache per forzare l'aggiornamento await exec('dnf clean metadata', echo); console.log('Repository added. Use "dnf check-update" to refresh.'); } catch (error) { console.error(`Failed to add RPM repository: ${error.message}`); } } /** * rpmRepoRemove() * @param repoFilePath * @param keyOwner */ async function rpmRepoRemove(repoFilePath, keyOwner) { console.log('Removing RPM repo...'); const echo = Utils.setEcho(true); // Rimuovi file .repo if (fs.existsSync(repoFilePath)) { await exec(`rm -f ${repoFilePath}`, echo); console.log(`Removed ${repoFilePath}.`); } else { console.log(`File repository ${repoFilePath} not found.`); } // Rimuovi chiave GPG const findKeyCmd = `rpm -q gpg-pubkey --qf '%{name}-%{version}-%{release} %{summary}\n' | grep '${keyOwner}' | cut -d' ' -f1`; const keyNameResult = await exec(findKeyCmd, { capture: true, echo: false }); if (keyNameResult.code === 0 && keyNameResult.data.trim() !== '') { const keyNames = keyNameResult.data.trim().split('\n'); for (const keyName of keyNames) { if (keyName) { console.log(`Rimozione chiave GPG ${keyName}...`); await exec(`rpm -e ${keyName}`, echo); } } } else { console.log('No GPG key to remove.'); } console.log('Repository removed. Use "dnf check-update" to refresh.'); } /** * =============================================== * Opensuse * =============================================== */ /** * opensuseRepoAdd() * @param repoUrl * @param keyUrl */ async function opensuseRepoAdd(repoUrl, keyUrl) { console.log(`Adding repository openSUSE ${repoUrl}`); const echo = Utils.setEcho(true); // 1. Definisci il contenuto del file .repo const repoContent = ` [penguins-eggs] name=penguins-eggs.net repos baseurl=${repoUrl} enabled=1 gpgcheck=1 repo_gpgcheck=0 gpgkey=${keyUrl} autorefresh=1 `; // gpgcheck=1 -> Controlla i pacchetti RPM (corretto) // repo_gpgcheck=0 -> NON controllare i metadati/repomd.xml (risolve il prompt) try { // 2. Scrivi il file .repo nella directory di zypper fs.writeFileSync(opensuseRepoFilePath, repoContent.trim()); console.log(`Repository file created at ${opensuseRepoFilePath}`); // 3. Importa la chiave GPG nel database RPM (stesso comando di Fedora) await exec(`rpm --import ${keyUrl}`, echo); console.log(`GPG key imported from ${keyUrl}`); console.log('Repository added. Use "zypper refresh" to update.'); } catch (error) { console.error(`Failed to add openSUSE repository: ${error.message}`); } }