penguins-eggs
Version:
A remaster system tool, compatible with Almalinux, Alpine, Arch, Debian, Devuan, Fedora, Manjaro, Opensuse, Ubuntu and derivatives
446 lines (445 loc) • 17.8 kB
JavaScript
/**
* ./src/classes/incubation/incubator.ts
* penguins-eggs v.25.7.x / ecmascript 2020
* author: Piero Proietti
* email: piero.proietti@gmail.com
* license: MIT
*/
// pjson
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
// partition
import yaml from 'js-yaml';
import fs from 'node:fs';
import path from 'node:path';
const pjson = require('../../../package.json');
import { shx } from '../../lib/utils.js';
import Pacman from '../pacman.js';
import Utils from '../utils.js';
import { branding } from './branding.js';
import { customizePartitions } from './customize/customize-partitions.js';
// incubator.d
import { Alpine } from './incubator.d/alpine.js';
import { Archlinux } from './incubator.d/archlinux.js';
import { Buster } from './incubator.d/buster.js';
import { Fedora } from './incubator.d/fedora.js';
import { Manjaro } from './incubator.d/manjaro.js';
import { Noble } from './incubator.d/noble.js';
import { Openmamba } from './incubator.d/openmamba.js';
import { Opensuse } from './incubator.d/opensuse.js';
import { Trixie } from './incubator.d/trixie.js';
import { installer } from './installer.js';
// _dirname
const __dirname = path.dirname(new URL(import.meta.url).pathname);
/**
*
*/
export default class Incubator {
distro;
installer = {};
isClone;
remix;
theme;
user_opt;
verbose = false;
/**
*
* @param remix
* @param distro
* @param verbose
*/
constructor(remix, distro, user_opt = 'live', theme = 'eggs', isClone = false, verbose = false) {
this.installer = installer();
this.remix = remix;
this.distro = distro;
this.user_opt = user_opt;
this.theme = theme;
this.verbose = verbose;
this.remix.branding = theme;
this.isClone = isClone;
// branding è solo il basename
this.remix.branding = path.basename(theme);
}
/**
* config
*/
async config(release = false) {
const verbose = true;
const echo = Utils.setEcho(verbose);
Utils.warning(`creating ${installer().name} configuration files on ${installer().configRoot}`);
this.createInstallerDirs();
this.createBranding();
const { distroUniqueId } = this.distro;
try {
/**
* Alpine
*/
switch (distroUniqueId) {
case 'alpine': {
const alpine = new Alpine(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await alpine.create();
/**
* Archlinux
*/
break;
}
case 'archlinux': {
const archlinux = new Archlinux(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await archlinux.create();
/**
* Manjaro ex rolling
*/
break;
}
case 'beowulf': {
const beowulf = new Buster(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await beowulf.create();
break;
}
case 'bookworm': {
const bookworm = new Buster(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await bookworm.create();
break;
}
case 'bullseye': {
const bullseye = new Buster(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await bullseye.create();
break;
}
case 'buster': {
const buster = new Buster(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await buster.create();
break;
}
case 'chimaera': {
const chimaera = new Buster(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await chimaera.create();
break;
}
case 'daedalus': {
const daedalus = new Buster(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await daedalus.create();
break;
}
case 'devel': {
const devel = new Noble(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await devel.create();
break;
}
case 'excalibur': {
const excalibur = new Trixie(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await excalibur.create();
/**
* fedora
*/
break;
}
case 'fedora': {
const fedora = new Fedora(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await fedora.create();
/**
* openmamba
*/
break;
}
case 'focal': {
const focal = new Noble(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await focal.create();
break;
}
case 'forky': {
const forky = new Trixie(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await forky.create();
/**
* Devuan
*/
break;
}
case 'jammy': {
const jammy = new Noble(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await jammy.create();
break;
}
case 'manjaro': {
const manjaro = new Manjaro(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await manjaro.create();
/**
* Debian
*/
break;
}
case 'noble': {
const noble = new Noble(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await noble.create();
break;
}
case 'openmamba': {
const mamba = new Openmamba(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await mamba.create();
/**
* opensuse
*/
break;
}
case 'opensuse': {
const suse = new Opensuse(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await suse.create();
/**
* Ubuntu
*/
break;
}
case 'trixie': {
const trixie = new Trixie(this.installer, this.remix, this.distro, this.user_opt, release, this.theme, this.isClone, this.verbose);
await trixie.create();
break;
}
// No default
}
}
catch (error) {
console.error('--- ERRORE FATALE CATTURATO ---');
console.error("L'esecuzione si è interrotta durante la creazione della configurazione specifica per la distro.");
console.error(error);
process.exit(1);
}
if (Pacman.calamaresExists()) {
await customizePartitions();
}
Utils.warning(`cleanup ${installer().name} configuration files`);
await this.cleanupConfiguration();
}
/**
* Rewrite modules
*/
async cleanupConfiguration() {
// modules
const elements = fs.readdirSync(this.installer.modules);
elements.sort();
for (const elem of elements) {
const file = path.join(this.installer.modules, elem);
const fileContent = fs.readFileSync(file, 'utf8');
const yamlContent = yaml.load(fileContent);
let destContent = `# ${elem} on ${this.distro.distroId}, penguins-eggs ${pjson.version}\n`;
destContent += '---\n';
destContent += yaml.dump(yamlContent);
fs.writeFileSync(file, destContent, 'utf8');
}
// settings
const file = path.join(this.installer.configRoot, 'settings.conf');
const fileContent = fs.readFileSync(file, 'utf8');
const yamlContent = yaml.load(fileContent);
let destContent = `# settings.conf on ${this.distro.distroId} penguins-eggs ${pjson.version}\n`;
destContent += '---\n';
destContent += yaml.dump(yamlContent);
fs.writeFileSync(file, destContent, 'utf8');
}
/**
*
*/
createBranding() {
const dir = path.join(this.installer.configRoot, 'branding', this.remix.branding);
if (!fs.existsSync(dir)) {
shx.exec(`mkdir ${dir} -p`);
}
const file = path.join(dir, 'branding.desc');
let destContent = `# branding.desc on ${this.distro.distroId} penguins-eggs ${pjson.version}\n`;
destContent += '---\n';
destContent += branding(this.remix, this.distro, this.theme, this.verbose);
write(file, destContent, this.verbose);
}
/**
*
*/
createInstallerDirs() {
if (this.installer.name !== 'calamares') {
// Remove krill configuration and multiarc if present
try {
shx.exec('rm ' + this.installer.configRoot + ' -rf');
}
catch (error) {
console.log('error: ' + error + ' removing ' + this.installer.configRoot + ' -rf');
}
try {
shx.exec('rm ' + this.installer.multiarch + ' -rf');
}
catch (error) {
console.log('error: ' + error + ' removing ' + this.installer.multiarch + ' -rf');
}
}
// rootConfiguration krill/calamares
if (!fs.existsSync(this.installer.configRoot)) {
try {
fs.mkdirSync(this.installer.configRoot);
}
catch (error) {
console.log('error: ' + error + ' creating ' + this.installer.configRoot);
}
}
if (!fs.existsSync(path.join(this.installer.configRoot, 'branding'))) {
try {
fs.mkdirSync(path.join(this.installer.configRoot, 'branding'));
}
catch (error) {
console.log('error: ' + error + ' creating ' + path.join(this.installer.configRoot, 'branding'));
}
}
if (!fs.existsSync(path.join(this.installer.configRoot, 'branding/eggs'))) {
try {
fs.mkdirSync(path.join(this.installer.configRoot, 'branding/eggs'));
}
catch (error) {
console.log('error: ' + error + ' creating ' + path.join(this.installer.configRoot, 'branding/eggs'));
}
}
if (!fs.existsSync(path.join(this.installer.configRoot, 'modules'))) {
try {
fs.mkdirSync(path.join(this.installer.configRoot, 'modules'));
}
catch (error) {
console.log('error: ' + error + ' creating ' + path.join(this.installer.configRoot, 'modules'));
}
}
if (!fs.existsSync(this.installer.multiarch)) {
try {
fs.mkdirSync(this.installer.multiarch);
}
catch (error) {
console.log('error: ' + error + ' creating ' + this.installer.multiarch);
}
}
if (!fs.existsSync(this.installer.multiarchModules)) {
try {
fs.mkdirSync(this.installer.multiarchModules);
}
catch (error) {
console.log('error: ' + error + ' creating ' + this.installer.multiarchModules);
}
}
/**
* themes krill/calamares
*/
let calamaresBranding = path.resolve(__dirname, `../../../addons/eggs/theme/calamares/branding`);
if (this.theme.includes('/')) {
calamaresBranding = `${this.theme}/theme/calamares/branding`;
}
// console.log(`calamaresBranding: ${calamaresBranding}`)
if (fs.existsSync(calamaresBranding)) {
if (!fs.existsSync(path.join(this.installer.configRoot, `branding/${this.remix.branding}`))) {
try {
fs.mkdirSync(path.join(this.installer.configRoot, `branding/${this.remix.branding}`));
}
catch (error) {
console.log('error: ' + error + ' creating ' + path.join(this.installer.configRoot, `branding/${this.remix.branding}`));
}
}
// patch quirinux
shx.cp('-r', path.join(calamaresBranding, '*'), path.join(this.installer.configRoot, `branding/${this.remix.branding}`));
}
else {
console.log(calamaresBranding);
console.log(`${calamaresBranding} branding not found!`);
process.exit();
}
/**
* install-system.png
*/
let calamaresIcon = path.resolve(__dirname, `../../../addons/${this.remix.branding}/theme/artwork/install-system.png`);
if (this.theme.includes('/')) {
calamaresIcon = `${this.theme}/theme/artwork/install-system.png`;
}
if (Pacman.calamaresExists()) {
if (fs.existsSync(calamaresIcon)) {
shx.cp(calamaresIcon, '/usr/share/icons/');
}
else {
console.log(`${calamaresIcon} icon not found!`);
process.exit();
}
}
/**
* install-system.desktop
*/
let calamaresLauncher = path.resolve(__dirname, `../../../addons/${this.remix.branding}/theme/applications/install-system.desktop`);
if (this.theme.includes('/')) {
calamaresLauncher = `${this.theme}/theme/applications/install-system.desktop`;
}
if (fs.existsSync(calamaresLauncher)) {
shx.cp(calamaresLauncher, '/usr/share/applications/');
}
else {
console.log(`${calamaresLauncher} launcher not found!`);
process.exit();
}
/**
* install-system.sh
*/
{
const sourceScript = path.resolve(__dirname, '../../../assets/calamares/install-system.sh');
const targetScript = '/usr/bin/install-system.sh';
fs.copyFileSync(sourceScript, targetScript);
fs.chmodSync(targetScript, 0o755);
fs.chownSync(targetScript, 0, 0);
}
this.sudoers();
}
/**
* soluzione tampone from Glenn
*/
sudoers() {
const live = this.user_opt;
if (!live)
return;
const sudoersPath = '/etc/sudoers.d/99-eggs-calamares';
const sudoersDir = '/etc/sudoers.d'; // O usa path.dirname(sudoersPath)
// FIX: Crea la directory se non esiste
if (!fs.existsSync(sudoersDir)) {
try {
fs.mkdirSync(sudoersDir, { mode: 0o755, recursive: true });
}
catch (error) {
console.error(`Error creating ${sudoersDir}:`, error);
}
}
// Nota il SETENV: prima di NOPASSWD
const content = `${live} ALL=(ALL) SETENV: NOPASSWD: /usr/bin/calamares\n`;
try {
fs.writeFileSync(sudoersPath, content, { encoding: 'utf8', mode: 0o440 });
fs.chownSync(sudoersPath, 0, 0);
}
catch (error) {
console.error(error);
}
}
/**
* soluzione tampone from Glenn
*
*/
sudoersToRemove() {
const live = this.user_opt;
if (!live)
return;
const sudoersPath = '/etc/sudoers.d/99-eggs-calamares';
// Nota il SETENV: prima di NOPASSWD
const content = `${live} ALL=(ALL) SETENV: NOPASSWD: /usr/bin/calamares\n`;
try {
fs.writeFileSync(sudoersPath, content, { encoding: 'utf8', mode: 0o440 });
fs.chownSync(sudoersPath, 0, 0);
}
catch (error) {
console.error(error);
}
}
}
/**
*
* @param file
* @param content
* @param verbose
*/
function write(file, content, verbose = false) {
if (verbose) {
console.log(`calamares: create ${file}`);
}
fs.writeFileSync(file, content, 'utf8');
}