penguins-eggs
Version:
A remaster system tool, compatible with Arch, Debian, Devuan, Ubuntu and others
222 lines (221 loc) • 10.1 kB
JavaScript
/**
* ./src/commands/produce.ts
* penguins-eggs v.10.0.0 / ecmascript 2020
* author: Piero Proietti
* email: piero.proietti@gmail.com
* license: MIT
*/
import { Command, Flags } from '@oclif/core';
import chalk from 'chalk';
import fs from 'node:fs';
import path from 'node:path';
import Compressors from '../classes/compressors.js';
import Ovary from '../classes/ovary.js';
import Utils from '../classes/utils.js';
import Config from './config.js';
// _dirname
const __dirname = path.dirname(new URL(import.meta.url).pathname);
export default class Produce extends Command {
static description = 'produce a live image from your system whithout your data';
static examples = [
'sudo eggs produce # zstd fast compression',
'sudo eggs produce --standard # xz compression',
'sudo eggs produce --max # xz max compression',
'sudo eggs produce --pendrive # zstd compression optimized pendrive',
'sudo eggs produce --clone # clone',
'sudo eggs produce --cryptedclone # crypted clone',
'sudo eggs produce --basename=colibri',
'sudo eggs produce --theme lastos',
'sudo eggs produce --excludes static # you can customize it',
'sudo eggs produce --excludes homes # exclude /home/*',
'sudo eggs produce --excludes home # exclude ~/*'
];
static flags = {
addons: Flags.string({ description: 'addons to be used: adapt, pve, rsupport', multiple: true }),
basename: Flags.string({ description: 'basename' }),
clone: Flags.boolean({ char: 'c', description: 'clone' }),
cryptedclone: Flags.boolean({ char: 'C', description: 'crypted clone' }),
excludes: Flags.string({ description: 'use: static, homes, home', multiple: true }),
help: Flags.help({ char: 'h' }),
kernel: Flags.string({ char: 'k', description: 'kernel version' }),
links: Flags.string({ description: 'desktop links', multiple: true }),
max: Flags.boolean({ char: 'm', description: 'max compression: xz -Xbcj ...' }),
noicon: Flags.boolean({ char: 'N', description: 'no icon eggs on desktop' }),
nointeractive: Flags.boolean({ char: 'n', description: 'no user interaction' }),
pendrive: Flags.boolean({ char: 'p', description: 'optimized for pendrive: zstd -b 1M -Xcompression-level 15' }),
prefix: Flags.string({ char: 'P', description: 'prefix' }),
release: Flags.boolean({ description: 'release: remove penguins-eggs, calamares and dependencies after installation' }),
script: Flags.boolean({ char: 's', description: 'script mode. Generate scripts to manage iso build' }),
standard: Flags.boolean({ char: 'S', description: 'standard compression: xz -b 1M' }),
theme: Flags.string({ description: 'theme for livecd, calamares branding and partitions' }),
unsecure: Flags.boolean({ char: 'u', description: '/root contents are included on live' }),
verbose: Flags.boolean({ char: 'v', description: 'verbose' }),
yolk: Flags.boolean({ char: 'y', description: 'force yolk renew' })
};
async run() {
Utils.titles(this.id + ' ' + this.argv);
const { flags } = await this.parse(Produce);
const pendrive = flags.pendrive === undefined ? null : Number(flags.pendrive);
if (Utils.isRoot()) {
/**
* ADDONS dei vendors
* Fino a 3
*/
const addons = [];
if (flags.addons) {
const { addons } = flags; // array
for (let addon of addons) {
// se non viene specificato il vendor il default è eggs
if (!addon.includes('//')) {
addon = 'eggs/' + addon;
}
const dirAddon = path.resolve(__dirname, `../../addons/${addon}`);
if (!fs.existsSync(dirAddon)) {
console.log(dirAddon);
Utils.warning('addon: ' + chalk.white(addon) + ' not found, terminate!');
process.exit();
}
const vendorAddon = addon.slice(0, Math.max(0, addon.search('/')));
const nameAddon = addon.substring(addon.search('/') + 1, addon.length);
if (nameAddon === 'theme') {
flags.theme = vendorAddon;
}
}
}
// links check
const myLinks = [];
if (flags.links) {
const { links } = flags;
for (const link_ of links) {
if (fs.existsSync(`/usr/share/applications/${link_}.desktop`)) {
myLinks.push(link_);
}
else {
Utils.warning('desktop link: ' + chalk.white('/usr/share/applications/' + link_ + '.desktop') + ' not found!');
}
}
}
/**
* composizione dei flag
*/
// excludes
const excludes = {};
excludes.usr = true;
excludes.var = true;
excludes.static = false;
excludes.homes = false;
excludes.home = false;
if (flags.excludes) {
if (flags.excludes.includes('static')) {
excludes.static = true;
}
if (flags.excludes.includes('homes')) {
excludes.homes = true;
}
if (flags.excludes.includes('home')) {
excludes.home = true;
}
}
let prefix = '';
if (flags.prefix !== undefined) {
prefix = flags.prefix;
}
let basename = ''; // se vuoto viene definito da loadsetting (default nome dell'host)
if (flags.basename !== undefined) {
basename = flags.basename;
}
const compressors = new Compressors();
await compressors.populate();
let compression = compressors.fast();
if (flags.max) {
compression = compressors.max();
}
else if (flags.pendrive) {
compression = compressors.pendrive('15');
}
else if (flags.standard) {
compression = compressors.standard();
}
const { release } = flags;
const { cryptedclone } = flags;
const { clone } = flags;
const { verbose } = flags;
const scriptOnly = flags.script;
const yolkRenew = flags.yolk;
const { nointeractive } = flags;
const { noicon } = flags;
// if clone or cryptedclone unsecure = true
const unsecure = flags.unsecure || clone || cryptedclone;
let { kernel } = flags;
if (kernel === undefined) {
kernel = '';
}
if (kernel !== '') {
if (!fs.existsSync(`/usr/lib/modules/${kernel}`)) {
let kernelModules = `/usr/lib/modules/`;
if (!fs.existsSync(kernelModules)) {
kernelModules = `/lib/modules/`;
}
let kernels = fs.readdirSync(kernelModules);
console.log("modules available:");
for (const k of kernels) {
console.log(`- ${k}`);
}
console.log(`\nNo available modules for kernel version "${kernel}" in /usr/lib/modules/`);
process.exit(1);
}
}
/**
* theme: if not defined will use eggs
*/
let theme = 'eggs';
if (flags.theme !== undefined) {
theme = flags.theme;
if (theme.includes('/')) {
if (theme.endsWith('/')) {
theme = theme.slice(0, Math.max(0, theme.length - 1));
}
}
else {
const wpath = `/home/${await Utils.getPrimaryUser()}/.wardrobe/vendors/`;
theme = wpath + flags.theme;
}
theme = path.resolve(theme);
if (!fs.existsSync(theme + '/theme')) {
console.log('Cannot find theme: ' + theme);
process.exit();
}
}
const i = await Config.thatWeNeed(nointeractive, verbose, cryptedclone);
if ((i.needUpdate || i.configurationInstall || i.configurationRefresh || i.distroTemplate)) {
await Config.install(i, nointeractive, verbose);
}
const myAddons = {};
if (flags.addons != undefined) {
if (flags.addons.includes('adapt')) {
myAddons.adapt = true;
}
if (flags.addons.includes('pve')) {
myAddons.pve = true;
}
if (flags.addons.includes('rsupport')) {
myAddons.rsupport = true;
}
}
Utils.titles(this.id + ' ' + this.argv);
const ovary = new Ovary();
Utils.warning('Produce an egg...');
if (i.calamares) {
let message = "this is a GUI system, calamares is available, but NOT installed\n";
Utils.warning(message);
}
if (await ovary.fertilization(prefix, basename, theme, compression, !nointeractive)) {
await ovary.produce(kernel, clone, cryptedclone, scriptOnly, yolkRenew, release, myAddons, myLinks, excludes, nointeractive, noicon, unsecure, verbose);
ovary.finished(scriptOnly);
}
}
else {
Utils.useRoot(this.id);
}
}
}