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
JavaScript
/**
* ./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}`);
}
}