penguins-eggs 25.11.21 → 25.12.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/.oclif.manifest.json +53 -41
  2. package/README.md +80 -36
  3. package/README.pdf +21575 -3241
  4. package/addons/eggs/theme/livecd/full.grub.main.cfg +39 -4
  5. package/addons/eggs/theme/livecd/full.isolinux.main.cfg +47 -4
  6. package/bin/run.js +11 -0
  7. package/conf/derivatives.yaml +4 -2
  8. package/conf/exclude.list.d/var.list +11 -6
  9. package/dist/appimage/dependency-manager.d.ts +31 -0
  10. package/dist/appimage/dependency-manager.js +292 -0
  11. package/dist/appimage/first-run-check.js +3 -3
  12. package/dist/bin/run.js +11 -0
  13. package/dist/classes/cli-autologin.js +78 -53
  14. package/dist/classes/compressors.d.ts +7 -10
  15. package/dist/classes/compressors.js +44 -31
  16. package/dist/classes/daddy.js +11 -11
  17. package/dist/classes/distro.js +2 -2
  18. package/dist/classes/diversions.js +2 -3
  19. package/dist/classes/incubation/fisherman-helper/initcpio.d.ts +4 -0
  20. package/dist/classes/incubation/fisherman-helper/initcpio.js +14 -4
  21. package/dist/classes/incubation/fisherman-helper/settings.js +1 -1
  22. package/dist/classes/incubation/fisherman.js +1 -3
  23. package/dist/classes/incubation/incubator.js +1 -1
  24. package/dist/classes/network.d.ts +1 -1
  25. package/dist/classes/ovary.d/create-xdg-autostart.js +1 -1
  26. package/dist/classes/ovary.d/edit-live-fs.d.ts +1 -12
  27. package/dist/classes/ovary.d/edit-live-fs.js +216 -186
  28. package/dist/classes/ovary.d/fertilization.js +1 -1
  29. package/dist/classes/ovary.d/make-dot-disk.js +1 -1
  30. package/dist/classes/ovary.d/produce.js +1 -1
  31. package/dist/classes/ovary.d/user-create-live.d.ts +4 -10
  32. package/dist/classes/ovary.d/user-create-live.js +82 -84
  33. package/dist/classes/ovary.d/users-remove.d.ts +5 -6
  34. package/dist/classes/ovary.d/users-remove.js +61 -31
  35. package/dist/classes/ovary.d/xorriso-command.js +1 -5
  36. package/dist/classes/ovary.d.ts +2 -2
  37. package/dist/classes/ovary.js +2 -2
  38. package/dist/classes/pacman.d/alpine.js +2 -2
  39. package/dist/classes/pacman.d/archlinux.js +2 -2
  40. package/dist/classes/pacman.d/debian.js +2 -3
  41. package/dist/classes/pacman.d/fedora.js +2 -3
  42. package/dist/classes/pacman.d/openmamba.js +2 -3
  43. package/dist/classes/pacman.d/opensuse.js +2 -3
  44. package/dist/classes/pacman.d.ts +21 -12
  45. package/dist/classes/pacman.js +55 -47
  46. package/dist/classes/pve-live.js +1 -1
  47. package/dist/classes/settings.js +1 -1
  48. package/dist/classes/sys-users.d.ts +76 -0
  49. package/dist/classes/sys-users.js +206 -0
  50. package/dist/classes/utils.d/kernel.js +3 -3
  51. package/dist/classes/utils.d.ts +16 -11
  52. package/dist/classes/utils.js +92 -56
  53. package/dist/classes/xdg.js +1 -1
  54. package/dist/classes/yolk.js +2 -4
  55. package/dist/commands/config.js +3 -14
  56. package/dist/commands/cuckoo.js +1 -1
  57. package/dist/commands/export/appimage.js +3 -3
  58. package/dist/commands/export/pkg.js +3 -3
  59. package/dist/commands/export/tarballs.js +3 -3
  60. package/dist/commands/krill.js +1 -1
  61. package/dist/commands/produce.js +9 -4
  62. package/dist/commands/{setup.d.ts → setup/install.d.ts} +1 -5
  63. package/dist/commands/setup/install.js +71 -0
  64. package/dist/commands/setup/purge.d.ts +17 -0
  65. package/dist/commands/setup/purge.js +71 -0
  66. package/dist/commands/tools/yolk.js +1 -1
  67. package/dist/commands/update.d.ts +15 -0
  68. package/dist/commands/update.js +74 -7
  69. package/dist/interfaces/i-exec.d.ts +1 -0
  70. package/dist/krill/classes/prepare.d/location.js +1 -1
  71. package/dist/krill/classes/prepare.d/partitions.js +1 -1
  72. package/dist/krill/classes/prepare.d/users.js +2 -2
  73. package/dist/krill/classes/prepare.js +5 -5
  74. package/dist/krill/classes/sequence.d/add_user.d.ts +3 -15
  75. package/dist/krill/classes/sequence.d/add_user.js +87 -57
  76. package/dist/krill/classes/sequence.d/change_password.d.ts +5 -7
  77. package/dist/krill/classes/sequence.d/change_password.js +25 -10
  78. package/dist/krill/classes/sequence.d/del_live_user.d.ts +5 -7
  79. package/dist/krill/classes/sequence.d/del_live_user.js +39 -25
  80. package/dist/krill/classes/sequence.d/fstab.js +1 -1
  81. package/dist/krill/classes/sequence.d/grubcfg.d.ts +3 -7
  82. package/dist/krill/classes/sequence.d/grubcfg.js +33 -13
  83. package/dist/krill/classes/sequence.d/mkfs.js +1 -2
  84. package/dist/krill/classes/sequence.d/unpackfs.d.ts +2 -4
  85. package/dist/krill/classes/sequence.d/unpackfs.js +8 -5
  86. package/dist/krill/classes/sequence.js +2 -3
  87. package/dist/krill/components/title.js +4 -4
  88. package/dist/krill/lib/select_installation_device.js +1 -1
  89. package/dist/krill/lib/select_replaced_partition.js +1 -1
  90. package/dist/lib/utils.d.ts +51 -19
  91. package/dist/lib/utils.js +225 -39
  92. package/manpages/doc/man/eggs.1.gz +0 -0
  93. package/manpages/doc/man/eggs.html +29 -17
  94. package/package.json +13 -14
  95. package/perrisbrewery/template/dependencies.yaml +1 -0
  96. package/scripts/_eggs +35 -7
  97. package/scripts/boot-encrypted-root.sh +220 -0
  98. package/scripts/eggs.bash +2 -1
  99. package/scripts/mount-encrypted-home.sh +324 -0
  100. package/dist/appimage/prerequisites.d.ts +0 -34
  101. package/dist/appimage/prerequisites.js +0 -350
  102. package/dist/commands/setup.js +0 -90
  103. package/dracut/create-symlink +0 -71
  104. package/dracut/dracut-log.txt +0 -3
  105. package/dracut/export +0 -4
  106. package/dracut/export-dracut-analysis +0 -51
  107. package/dracut/export-dracut-log +0 -2
  108. package/dracut/mkisofs +0 -10
  109. package/dracut/renew-initramfs +0 -17
  110. package/dracut/sbin2bin +0 -10
  111. package/dracut/update-dracut-conf-d +0 -2
  112. package/dracut/update-dracut-modules +0 -62
  113. package/scripts/appimage-build.sh +0 -152
  114. package/scripts/appimage-install.sh +0 -43
@@ -1,10 +1,7 @@
1
1
  /**
2
2
  * ./src/krill/modules/grubcfg.ts
3
3
  * penguins-eggs v.25.7.x / ecmascript 2020
4
- * author: Piero Proietti
5
- * email: piero.proietti@gmail.com
6
- * license: MIT
7
- * https://stackoverflow.com/questions/23876782/how-do-i-split-a-typescript-class-into-multiple-files
4
+ * * REFACTORED: Adds SELinux permissive mode for RHEL family
8
5
  */
9
6
  import fs from 'node:fs';
10
7
  import Utils from '../../../classes/utils.js';
@@ -12,24 +9,47 @@ import { InstallationMode } from '../krill_enums.js';
12
9
  /**
13
10
  * grubcfg
14
11
  * - open /etc/default/grub
15
- * - find GRUB_CMDLINE_LINUX_DEFAULT=
16
- * - replace with GRUB_CMDLINE_LINUX_DEFAULT=
17
- * 's/GRUB_CMDLINE_LINUX_DEFAULT=.*$/GRUB_CMDLINE_LINUX_DEFAULT=/g'
12
+ * - handle BTRFS/LUKS settings
13
+ * - inject enforcing=0 for Fedora/RHEL to allow autorelabel on first boot
18
14
  */
19
15
  export default async function grubcfg() {
20
16
  const file = `${this.installTarget}/etc/default/grub`;
17
+ if (!fs.existsSync(file)) {
18
+ console.warn(`Warning: ${file} not found. Skipping GRUB config.`);
19
+ return;
20
+ }
21
21
  let content = '';
22
22
  const grubs = fs.readFileSync(file, 'utf8').split('\n');
23
+ // Cache per la verifica della famiglia
24
+ const isRhelFamily = ['fedora', 'rhel', 'centos', 'almalinux', 'rocky'].includes(this.distro.familyId);
23
25
  for (let i = 0; i < grubs.length; i++) {
24
- // RESUME
25
- if (grubs[i].includes('GRUB_CMDLINE_LINUX_DEFAULT=')) {
26
+ let line = grubs[i];
27
+ // 1. LOGICA ESISTENTE (BTRFS / LUKS)
28
+ // Questa logica riscrive completamente la riga DEFAULT se necessario
29
+ if (line.trim().startsWith('GRUB_CMDLINE_LINUX_DEFAULT=')) {
26
30
  if (this.partitions.filesystemType === 'btrfs') {
27
- // userSwapChoice != SwapChoice.File) {
28
- // grubs[i] = this.partitions.installationMode === InstallationMode.Luks ? `GRUB_CMDLINE_LINUX_DEFAULT="resume=UUID=${Utils.uuid(this.devices.swap.name)}"` : `GRUB_CMDLINE_LINUX_DEFAULT="quiet splash resume=UUID=${Utils.uuid(this.devices.swap.name)}"`
29
- grubs[i] = this.partitions.installationMode === InstallationMode.Luks ? `GRUB_CMDLINE_LINUX_DEFAULT="resume=UUID=${Utils.uuid(this.devices.swap.name)}"` : `GRUB_CMDLINE_LINUX_DEFAULT="quiet splash rootflags=subvol=@"`;
31
+ const uuid = Utils.uuid(this.devices.swap.name);
32
+ if (this.partitions.installationMode === InstallationMode.Luks) {
33
+ line = `GRUB_CMDLINE_LINUX_DEFAULT="resume=UUID=${uuid}"`;
34
+ }
35
+ else {
36
+ line = `GRUB_CMDLINE_LINUX_DEFAULT="quiet splash rootflags=subvol=@"`;
37
+ }
38
+ }
39
+ }
40
+ // 2. LOGICA SELINUX (RHEL/FEDORA)
41
+ // Applichiamo la modifica sia se la riga è stata appena toccata, sia se è originale.
42
+ // Fedora usa spesso anche GRUB_CMDLINE_LINUX (senza DEFAULT), quindi controlliamo entrambe.
43
+ if (isRhelFamily) {
44
+ if (line.trim().startsWith('GRUB_CMDLINE_LINUX_DEFAULT=') || line.trim().startsWith('GRUB_CMDLINE_LINUX=')) {
45
+ // Se non c'è già il parametro, lo iniettiamo subito dopo la prima virgoletta
46
+ if (!line.includes('enforcing=0')) {
47
+ line = line.replace('="', '="enforcing=0 ');
48
+ console.log(`- GRUB: injected enforcing=0 into ${line.split('=')[0]}`);
49
+ }
30
50
  }
31
51
  }
32
- content += grubs[i] + '\n';
52
+ content += line + '\n';
33
53
  }
34
54
  fs.writeFileSync(file, content, 'utf-8');
35
55
  }
@@ -6,8 +6,7 @@
6
6
  * license: MIT
7
7
  * https://stackoverflow.com/questions/23876782/how-do-i-split-a-typescript-class-into-multiple-files
8
8
  */
9
- import { exec } from '../../../lib/utils.js';
10
- import shx from "shelljs";
9
+ import { exec, shx } from '../../../lib/utils.js';
11
10
  import { InstallationMode, SwapChoice } from '../krill_enums.js';
12
11
  /**
13
12
  * mkfs
@@ -1,13 +1,11 @@
1
1
  /**
2
2
  * ./src/krill/modules/unpackfs.ts
3
3
  * penguins-eggs v.25.7.x / ecmascript 2020
4
- * author: Piero Proietti
5
- * email: piero.proietti@gmail.com
6
- * license: MIT
7
- * https://stackoverflow.com/questions/23876782/how-do-i-split-a-typescript-class-into-multiple-files
4
+ * * CLEANED: Just unpacks. SELinux is handled via autorelabel on first boot.
8
5
  */
9
6
  import Sequence from '../../classes/sequence.js';
10
7
  /**
11
8
  * unpackfs
9
+ * Scompatta il filesystem (senza tentare fix SELinux costosi qui)
12
10
  */
13
11
  export default function unpackfs(this: Sequence): Promise<void>;
@@ -1,21 +1,24 @@
1
1
  /**
2
2
  * ./src/krill/modules/unpackfs.ts
3
3
  * penguins-eggs v.25.7.x / ecmascript 2020
4
- * author: Piero Proietti
5
- * email: piero.proietti@gmail.com
6
- * license: MIT
7
- * https://stackoverflow.com/questions/23876782/how-do-i-split-a-typescript-class-into-multiple-files
4
+ * * CLEANED: Just unpacks. SELinux is handled via autorelabel on first boot.
8
5
  */
9
6
  import Utils from '../../../classes/utils.js';
10
7
  import { exec } from '../../../lib/utils.js';
11
8
  import path from 'path';
12
9
  /**
13
10
  * unpackfs
11
+ * Scompatta il filesystem (senza tentare fix SELinux costosi qui)
14
12
  */
15
13
  export default async function unpackfs() {
16
14
  const squafsPath = path.join(this.distro.liveMediumPath, this.distro.squashfs);
15
+ // -d: destination
16
+ // -f: force (overwrite)
17
17
  const cmd = `unsquashfs -d ${this.installTarget} -f ${squafsPath} ${this.toNull}`;
18
- const echoYes = Utils.setEcho(true);
18
+ // Usiamo echo false per evitare di intasare il log con migliaia di file
19
19
  const echoNo = Utils.setEcho(false);
20
+ console.log('Unpacking filesystem (this may take a while)...');
21
+ // Esecuzione
20
22
  await exec(cmd, echoNo);
23
+ console.log('Filesystem unpacked successfully.');
21
24
  }
@@ -19,7 +19,7 @@ import Distro from '../../classes/distro.js';
19
19
  import Pacman from '../../classes/pacman.js';
20
20
  import Utils from '../../classes/utils.js';
21
21
  import Xdg from '../../classes/xdg.js';
22
- import { exec } from '../../lib/utils.js';
22
+ import { exec, spawnSync } from '../../lib/utils.js';
23
23
  // Import all modules (unchanged)
24
24
  import partition from './sequence.d/partition.js';
25
25
  import biosStandard from './sequence.d/partition.d/bios_standard.js';
@@ -51,7 +51,6 @@ import hostname from './sequence.d/hostname.js';
51
51
  import CFS from './cfs.js';
52
52
  import Title from '../components/title.js';
53
53
  import cliCursor from 'cli-cursor';
54
- import { spawnSync } from 'child_process';
55
54
  /**
56
55
  * Main Sequence class - Simple Refactoring
57
56
  */
@@ -339,7 +338,7 @@ export default class Sequence {
339
338
  await sleep(5000);
340
339
  }
341
340
  else {
342
- spawnSync('read _ ', { shell: true, stdio: [0, 1, 2] });
341
+ spawnSync('read _ ', [], { shell: true, stdio: [0, 1, 2] });
343
342
  }
344
343
  await exec(cmd, { echo: false });
345
344
  }
@@ -14,14 +14,14 @@ const require = createRequire(import.meta.url);
14
14
  const pjson = require('../../../package.json');
15
15
  export default function Title({ title = "", version = "" }) {
16
16
  let type = "";
17
- if (Utils.isAppImage()) {
18
- type = "AppImage:";
17
+ if (!Utils.isAppImage()) {
18
+ type = " native";
19
19
  }
20
20
  if (title === "")
21
21
  title = `${pjson.name}`;
22
- let green = ` ${type} ${title}`.padEnd(25, " ");
22
+ let green = ` ${title}`.padEnd(25, " ");
23
23
  let white = ` Perri's brewery edition `.padEnd(25, " ");
24
- let red = ` v${pjson.version} `.padStart(25, " ");
24
+ let red = ` v${pjson.version}${type} `.padStart(25, " ");
25
25
  return (React.createElement(React.Fragment, null,
26
26
  React.createElement(Box, { flexDirection: "column" },
27
27
  React.createElement(Box, null),
@@ -6,7 +6,7 @@
6
6
  * license: MIT
7
7
  */
8
8
  import inquirer from 'inquirer';
9
- import shx from 'shelljs';
9
+ import { shx } from '../../lib/utils.js';
10
10
  export default async function selectInstallationDevice() {
11
11
  const drives = shx.exec('lsblk |grep disk|cut -f 1 "-d "', { silent: true }).stdout.trim().split('\n');
12
12
  const raid = shx.exec('lsblk -l | grep raid | cut -f 1 "-d "', { silent: true }).stdout.trim().split('\n');
@@ -6,7 +6,7 @@
6
6
  * license: MIT
7
7
  */
8
8
  import inquirer from 'inquirer';
9
- import shx from 'shelljs';
9
+ import { shx } from '../../lib/utils.js';
10
10
  export default async function selectReplacedPartition() {
11
11
  const partitions = shx.exec('lsblk -l -o NAME,TYPE | grep part | cut -d" " -f1', { silent: true }).stdout.trim().split('\n');
12
12
  let partitionsList = [];
@@ -5,31 +5,63 @@
5
5
  * email: piero.proietti@gmail.com
6
6
  * license: MIT
7
7
  */
8
+ import { SpawnOptions, SpawnSyncOptions, SpawnSyncReturns, ChildProcess } from 'child_process';
9
+ import { IExec } from '../interfaces/index.js';
10
+ interface ShellExecResult {
11
+ code: number;
12
+ stdout: string;
13
+ stderr: string;
14
+ }
15
+ interface ExecSyncOptions {
16
+ echo?: boolean;
17
+ ignore?: boolean;
18
+ stdio?: 'pipe' | 'ignore' | 'inherit';
19
+ }
8
20
  /**
9
- * Executes shell command as it would happen in BASH script
10
- * @param {string} command
11
- * @param {Object} [options] Object with options.
12
- * echo: true, to echo command passed.
13
- * ignore: true to ignore stdout
14
- * capture: true, to capture and return stdout.
15
- *
16
- * @returns {Promise<{code: number, data: string | undefined, error: Object}>}
17
- *
18
- * https://github.com/oclif/core/issues/453#issuecomment-1200778612
19
- * codespool:
20
- * You could wrap spawn in a promise, listen to exit event, and resolve when it happens. That should play nicely with oclif/core.
21
- * We are using it here:
22
- * https://github.com/AstarNetwork/swanky-cli/blob/master/src/commands/compile/index.ts
21
+ * spawnSync (WRAPPER INTELLIGENTE)
22
+ * Supporta:
23
+ * 1. (command, args, options)
24
+ * 2. (command, options) -> args diventa []
25
+ * Pulisce automaticamente l'ambiente.
23
26
  */
24
- import { IExec } from '../interfaces/index.js';
27
+ export declare function spawnSync(command: string, arg2?: string[] | SpawnSyncOptions, arg3?: SpawnSyncOptions): SpawnSyncReturns<string | Buffer>;
28
+ /**
29
+ * spawn (WRAPPER INTELLIGENTE)
30
+ * Supporta:
31
+ * 1. (command, args, options)
32
+ * 2. (command, options) -> args diventa []
33
+ * Pulisce automaticamente l'ambiente.
34
+ */
35
+ export declare function spawn(command: string, arg2?: readonly string[] | SpawnOptions, arg3?: SpawnOptions): ChildProcess;
36
+ /**
37
+ * shx
38
+ * Sostituto drop-in per shelljs che usa API native e ambiente pulito.
39
+ */
40
+ export declare const shx: {
41
+ sed: (flag: string, regex: string | RegExp, replacement: string, file: string) => void;
42
+ touch: (file: string) => void;
43
+ cp: (arg1: string, arg2: string, arg3?: string) => void;
44
+ rm: (arg1: string, arg2?: string) => void;
45
+ mkdir: (arg1: string, arg2?: string) => void;
46
+ mv: (src: string, dest: string) => void;
47
+ chmod: (mode: string | number, file: string) => void;
48
+ test: (flag: string, pathToCheck: string) => boolean;
49
+ which: (cmd: string) => string | null;
50
+ ln: (flag: string, target: string, link: string) => void;
51
+ exec: (command: string, options?: {
52
+ silent?: boolean;
53
+ }) => ShellExecResult;
54
+ };
55
+ /**
56
+ * execSync
57
+ */
58
+ export declare function execSync(command: string, options?: ExecSyncOptions): string | null;
25
59
  /**
26
- *
27
- * @param command
28
- * @param param1
29
- * @returns
60
+ * exec (Async)
30
61
  */
31
62
  export declare function exec(command: string, { echo, ignore, capture }?: {
32
63
  echo?: boolean | undefined;
33
64
  ignore?: boolean | undefined;
34
65
  capture?: boolean | undefined;
35
66
  }): Promise<IExec>;
67
+ export {};
package/dist/lib/utils.js CHANGED
@@ -5,53 +5,239 @@
5
5
  * email: piero.proietti@gmail.com
6
6
  * license: MIT
7
7
  */
8
- import { spawn } from 'child_process';
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ // Importiamo con alias per poter wrappare
11
+ import { spawn as nodeSpawn, spawnSync as nodeSpawnSync } from 'child_process';
9
12
  /**
10
- *
11
- * @param command
12
- * @param param1
13
- * @returns
13
+ * Pulizia AppImage
14
+ * Variabili d'ambiente da rimuovere per evitare conflitti quando si eseguono
15
+ * comandi di sistema dall'interno di una AppImage.
16
+ */
17
+ const APPIMAGE_ENV_BLACKLIST = [
18
+ 'LD_LIBRARY_PATH', 'LD_PRELOAD', 'PYTHONPATH', 'PERLLIB',
19
+ 'GSETTINGS_SCHEMA_DIR', 'QT_PLUGIN_PATH', 'XDG_DATA_DIRS',
20
+ 'LIBRARY_PATH', 'PKG_CONFIG_PATH', 'GIO_MODULE_DIR', 'APPIMAGE', 'APPDIR'
21
+ ];
22
+ /**
23
+ * Ottiene un ambiente pulito dalle variabili AppImage
24
+ * @returns Oggetto process.env sanificato
25
+ */
26
+ function getCleanEnv() {
27
+ const env = { ...process.env };
28
+ if (process.env.APPIMAGE) {
29
+ APPIMAGE_ENV_BLACKLIST.forEach((key) => delete env[key]);
30
+ }
31
+ return env;
32
+ }
33
+ /**
34
+ * spawnSync (WRAPPER INTELLIGENTE)
35
+ * Supporta:
36
+ * 1. (command, args, options)
37
+ * 2. (command, options) -> args diventa []
38
+ * Pulisce automaticamente l'ambiente.
39
+ */
40
+ export function spawnSync(command, arg2, arg3) {
41
+ let args = [];
42
+ let options = {};
43
+ // Rilevamento argomenti (Polimorfismo)
44
+ if (Array.isArray(arg2)) {
45
+ args = arg2;
46
+ options = arg3 || {};
47
+ }
48
+ else if (arg2 && typeof arg2 === 'object') {
49
+ // TypeScript fix: cast esplicito per evitare errori di tipo union
50
+ options = arg2;
51
+ }
52
+ const env = getCleanEnv();
53
+ const finalEnv = { ...env, ...(options.env || {}) };
54
+ return nodeSpawnSync(command, args, {
55
+ ...options,
56
+ env: finalEnv
57
+ });
58
+ }
59
+ /**
60
+ * spawn (WRAPPER INTELLIGENTE)
61
+ * Supporta:
62
+ * 1. (command, args, options)
63
+ * 2. (command, options) -> args diventa []
64
+ * Pulisce automaticamente l'ambiente.
65
+ */
66
+ export function spawn(command, arg2, arg3) {
67
+ let args = [];
68
+ let options = {};
69
+ // Rilevamento argomenti (Polimorfismo)
70
+ if (Array.isArray(arg2)) {
71
+ args = arg2;
72
+ options = arg3 || {};
73
+ }
74
+ else if (arg2 && typeof arg2 === 'object') {
75
+ // TypeScript fix: cast esplicito
76
+ options = arg2;
77
+ }
78
+ const env = getCleanEnv();
79
+ const finalEnv = { ...env, ...(options.env || {}) };
80
+ return nodeSpawn(command, args, {
81
+ ...options,
82
+ env: finalEnv
83
+ });
84
+ }
85
+ /**
86
+ * shx
87
+ * Sostituto drop-in per shelljs che usa API native e ambiente pulito.
88
+ */
89
+ export const shx = {
90
+ sed: (flag, regex, replacement, file) => {
91
+ if (!fs.existsSync(file))
92
+ return;
93
+ const content = fs.readFileSync(file, 'utf8');
94
+ const searchRegex = typeof regex === 'string' ? new RegExp(regex, 'g') : regex;
95
+ const newContent = content.replace(searchRegex, replacement);
96
+ fs.writeFileSync(file, newContent, 'utf8');
97
+ },
98
+ touch: (file) => {
99
+ const time = new Date();
100
+ try {
101
+ fs.utimesSync(file, time, time);
102
+ }
103
+ catch (err) {
104
+ fs.closeSync(fs.openSync(file, 'w'));
105
+ }
106
+ },
107
+ cp: (arg1, arg2, arg3) => {
108
+ const src = arg3 ? arg2 : arg1;
109
+ const dest = arg3 ? arg3 : arg2;
110
+ // --- GESTIONE WILDCARD (*) ---
111
+ if (src.endsWith('*')) {
112
+ const srcDir = path.dirname(src);
113
+ if (!fs.existsSync(srcDir))
114
+ return;
115
+ if (!fs.existsSync(dest))
116
+ fs.mkdirSync(dest, { recursive: true });
117
+ const items = fs.readdirSync(srcDir);
118
+ items.forEach(item => {
119
+ const s = path.join(srcDir, item);
120
+ const d = path.join(dest, item);
121
+ fs.cpSync(s, d, { recursive: true, force: true });
122
+ });
123
+ return;
124
+ }
125
+ // ----------------------------
126
+ let finalDest = dest;
127
+ if (fs.existsSync(dest) && fs.statSync(dest).isDirectory()) {
128
+ finalDest = path.join(dest, path.basename(src));
129
+ }
130
+ if (fs.existsSync(src)) {
131
+ fs.cpSync(src, finalDest, { recursive: true, force: true });
132
+ }
133
+ },
134
+ rm: (arg1, arg2) => {
135
+ const target = arg2 ? arg2 : arg1;
136
+ fs.rmSync(target, { recursive: true, force: true });
137
+ },
138
+ mkdir: (arg1, arg2) => {
139
+ const dir = arg2 ? arg2 : arg1;
140
+ fs.mkdirSync(dir, { recursive: true });
141
+ },
142
+ mv: (src, dest) => {
143
+ if (!fs.existsSync(src))
144
+ return;
145
+ fs.renameSync(src, dest);
146
+ },
147
+ chmod: (mode, file) => {
148
+ if (!fs.existsSync(file))
149
+ return;
150
+ let finalMode = mode;
151
+ if (mode === '+x')
152
+ finalMode = 0o755;
153
+ if (typeof mode === 'string' && !isNaN(parseInt(mode, 8))) {
154
+ finalMode = parseInt(mode, 8);
155
+ }
156
+ fs.chmodSync(file, finalMode);
157
+ },
158
+ test: (flag, pathToCheck) => {
159
+ try {
160
+ const stats = fs.statSync(pathToCheck);
161
+ if (flag === '-f')
162
+ return stats.isFile();
163
+ if (flag === '-d')
164
+ return stats.isDirectory();
165
+ return true; // -e
166
+ }
167
+ catch (e) {
168
+ return false;
169
+ }
170
+ },
171
+ which: (cmd) => {
172
+ const result = shx.exec(`command -v ${cmd}`, { silent: true });
173
+ return result.code === 0 ? result.stdout.trim() : null;
174
+ },
175
+ ln: (flag, target, link) => {
176
+ if (fs.existsSync(link) || fs.lstatSync(link, { throwIfNoEntry: false })) {
177
+ fs.rmSync(link, { force: true });
178
+ }
179
+ fs.symlinkSync(target, link);
180
+ },
181
+ exec: (command, options = {}) => {
182
+ const env = getCleanEnv();
183
+ const spawnOpts = {
184
+ stdio: options.silent ? 'pipe' : 'inherit',
185
+ env: env,
186
+ shell: '/bin/bash',
187
+ encoding: 'utf-8'
188
+ };
189
+ // Usiamo nodeSpawnSync perché calcoliamo l'env qui sopra
190
+ const result = nodeSpawnSync(command, [], spawnOpts);
191
+ return {
192
+ code: result.status ?? 1,
193
+ stdout: result.stdout ? result.stdout.toString() : '',
194
+ stderr: result.stderr ? result.stderr.toString() : ''
195
+ };
196
+ }
197
+ };
198
+ /**
199
+ * execSync
200
+ */
201
+ export function execSync(command, options = {}) {
202
+ const { echo = false, ignore = false, stdio } = options;
203
+ if (echo)
204
+ console.log(command);
205
+ const isSilent = ignore || stdio === 'ignore';
206
+ const result = shx.exec(command, { silent: isSilent });
207
+ if (result.code !== 0) {
208
+ throw new Error(`Command failed: ${command}\nExit Code: ${result.code}\nStderr: ${result.stderr}`);
209
+ }
210
+ return result.stdout.trim();
211
+ }
212
+ /**
213
+ * exec (Async)
14
214
  */
15
215
  export async function exec(command, { echo = false, ignore = false, capture = false } = {}) {
16
216
  return new Promise((resolve, reject) => {
17
- if (echo) {
217
+ if (echo)
18
218
  console.log(command);
19
- }
20
- // Opzioni di base per spawn
21
- const spawnOptions = {
22
- stdio: ignore ? 'ignore' : capture ? 'pipe' : 'inherit'
23
- };
24
- // AppImage Detected
25
- if (process.env.APPIMAGE) {
26
- // Clona l'ambiente attuale
27
- const env = { ...process.env };
28
- // 1. Rimuovi le variabili che causano conflitti di librerie (Kernel Panic)
29
- delete env.LD_LIBRARY_PATH;
30
- delete env.LD_PRELOAD;
31
- delete env.GSETTINGS_SCHEMA_DIR;
32
- delete env.PYTHONPATH;
33
- delete env.MANPATH;
34
- // 2. FORZA IL PATH DI SISTEMA
35
- env.PATH = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin';
36
- // Applica l'ambiente pulito alle opzioni di spawn
37
- spawnOptions.env = env;
38
- // (Opzionale) Debug visivo per essere sicuri che stia funzionando
39
- if (echo) {
40
- console.log(' [AppImage Detected] Environment sanitized for system command.');
41
- }
42
- }
43
- const child = spawn('bash', ['-c', command], spawnOptions);
219
+ const env = getCleanEnv();
220
+ // Usiamo nodeSpawn direttamente qui per coerenza
221
+ const child = nodeSpawn(command, [], {
222
+ stdio: ignore ? 'ignore' : (capture ? 'pipe' : 'inherit'),
223
+ env: env,
224
+ shell: '/bin/bash'
225
+ });
44
226
  let stdout = '';
45
- if (capture) {
46
- child.stdout?.on('data', (data) => {
47
- stdout += data;
48
- });
49
- }
227
+ let stderr = '';
228
+ if (capture && child.stdout)
229
+ child.stdout.on('data', d => stdout += d.toString());
230
+ if (capture && child.stderr)
231
+ child.stderr.on('data', d => stderr += d.toString());
50
232
  child.on('error', (error) => {
51
- reject({ code: 1, error });
233
+ reject({ code: 1, error, stderr });
52
234
  });
53
- child.on('exit', (code) => {
54
- resolve({ code, data: stdout });
235
+ child.on('close', (code) => {
236
+ resolve({
237
+ code: code || 0,
238
+ data: stdout.trim(),
239
+ error: code !== 0 ? stderr.trim() : undefined
240
+ });
55
241
  });
56
242
  });
57
243
  }
Binary file
@@ -6,12 +6,12 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
7
  </head>
8
8
  <body>
9
- <h1>eggs(1) -- the reproductive system of penguins: eggs v25.11.21</h1>
9
+ <h1>eggs(1) -- the reproductive system of penguins: eggs v25.12.7</h1>
10
10
  <h1>SYNOPSIS</h1>
11
11
  <p>eggs is a console utility, in active development, who let you to remaster your system and redistribuite it as live ISO image.</p>
12
12
  <h1>INSTALL</h1>
13
13
  <p>penguins-eggs as an AppImage, it can be installed on all supported distributions. Download it from https://github.com/pieroproietti/penguins-eggs/releases, then run the following commands:</p>
14
- <pre><code>$ chmod +x penguins-eggs_25.11.21-1_amd64-x86_64.AppImage
14
+ <pre><code>$ chmod +x penguins-eggs_25.12.7-1_amd64-x86_64.AppImage
15
15
  $ sudo mv /usr/local/bin
16
16
  $ sudo eggs setup
17
17
  </code></pre>
@@ -19,30 +19,30 @@ $ sudo eggs setup
19
19
  <pre><code>$ doas apk add penguins-eggs@testing
20
20
  </code></pre>
21
21
  <p>AlmaLinux/RockyLinux</p>
22
- <pre><code>$ sudo dnf install ./penguins-eggs_25.11.21-1_amd64-1rocky9.5..x86_64.rpm
22
+ <pre><code>$ sudo dnf install ./penguins-eggs_25.12.7-1_amd64-1rocky9.5..x86_64.rpm
23
23
 
24
24
  </code></pre>
25
25
  <p>Arch</p>
26
26
  <pre><code>$ sudo pacman -S penguins-eggs
27
- $ sudo pacman -U penguins-eggs_25.11.21-1_amd64-1-x86_64.pkg.tar.zst
27
+ $ sudo pacman -U penguins-eggs_25.12.7-1_amd64-1-x86_64.pkg.tar.zst
28
28
  </code></pre>
29
29
  <p>Debian/Devuan/Ubuntu</p>
30
30
  <pre><code>$ sudo apt install penguins-eggs
31
- $ sudo dpkg -i penguins-eggs_25.11.21-1_amd64.deb
31
+ $ sudo dpkg -i penguins-eggs_25.12.7-1_amd64.deb
32
32
  </code></pre>
33
33
  <p>Fedora</p>
34
- <pre><code>$ sudo dnf install ./penguins-eggs_25.11.21-1_amd64-1fedora.x86_64.rpm
34
+ <pre><code>$ sudo dnf install ./penguins-eggs_25.12.7-1_amd64-1fedora.x86_64.rpm
35
35
  </code></pre>
36
36
  <p>Manjaro</p>
37
37
  <pre><code>$ sudo pamac install penguins-eggs
38
38
  </code></pre>
39
39
  <p>OpenMamba</p>
40
- <pre><code>$ sudo dnf install ./penguins-eggs_25.11.21-1_amd64-1mamba.x86_64.rpm
40
+ <pre><code>$ sudo dnf install ./penguins-eggs_25.12.7-1_amd64-1mamba.x86_64.rpm
41
41
  </code></pre>
42
42
  <h1>USAGE</h1>
43
43
  <pre><code>$ eggs (-v|--version|version)
44
44
 
45
- penguins-eggs/25.11.21
45
+ penguins-eggs/25.12.7
46
46
  $ eggs --help [COMMAND]
47
47
 
48
48
  USAGE
@@ -79,7 +79,8 @@ sudo eggs dad
79
79
  <li><a href="#eggs-love"><code>eggs love</code></a></li>
80
80
  <li><a href="#eggs-mom"><code>eggs mom</code></a></li>
81
81
  <li><a href="#eggs-produce"><code>eggs produce</code></a></li>
82
- <li><a href="#eggs-setup"><code>eggs setup</code></a></li>
82
+ <li><a href="#eggs-setup-install"><code>eggs setup install</code></a></li>
83
+ <li><a href="#eggs-setup-purge"><code>eggs setup purge</code></a></li>
83
84
  <li><a href="#eggs-status"><code>eggs status</code></a></li>
84
85
  <li><a href="#eggs-tools-clean"><code>eggs tools clean</code></a></li>
85
86
  <li><a href="#eggs-tools-repo"><code>eggs tools repo</code></a></li>
@@ -444,24 +445,35 @@ EXAMPLES
444
445
 
445
446
  sudo eggs produce --basename=colibri
446
447
  </code></pre>
447
- <h2><code>eggs setup</code></h2>
448
+ <h2><code>eggs setup install</code></h2>
448
449
  <p>Automatically check and install system prerequisites</p>
449
450
  <pre><code>USAGE
450
- $ eggs setup [-c] [-f]
451
+ $ eggs setup install
451
452
 
452
- FLAGS
453
- -c, --check check status only, do not install
454
- -f, --force force installation even if already installed
453
+ DESCRIPTION
454
+ Automatically check and install system prerequisites
455
+
456
+ EXAMPLES
457
+ $ eggs setup # this help
458
+
459
+ sudo eggs setup install # install native dependencies, autocomplete, man, etc
460
+
461
+ sudo eggs setup purge # purge all configurations, autocomplete, man, etc installed from penguins-eggs AppImage
462
+ </code></pre>
463
+ <h2><code>eggs setup purge</code></h2>
464
+ <p>Automatically check and install system prerequisites</p>
465
+ <pre><code>USAGE
466
+ $ eggs setup purge
455
467
 
456
468
  DESCRIPTION
457
469
  Automatically check and install system prerequisites
458
470
 
459
471
  EXAMPLES
460
- sudo eggs setup # install prerequisites
472
+ $ eggs setup # this help
461
473
 
462
- sudo eggs setup --check # check prerequisites presence
474
+ sudo eggs setup install # install native dependencies, autocomplete, man, etc
463
475
 
464
- sudo eggs setup --force # force prerequisites install
476
+ sudo eggs setup purge # purge all configurations, autocomplete, man, etc installed from penguins-eggs AppImage
465
477
  </code></pre>
466
478
  <h2><code>eggs status</code></h2>
467
479
  <p>informations about eggs status</p>