124 lines
3.0 KiB
TypeScript
124 lines
3.0 KiB
TypeScript
/**
|
|
* ISO Packer
|
|
* Repacks a directory into a bootable ISO using xorriso
|
|
*/
|
|
|
|
import { log } from '../logging.ts';
|
|
|
|
export class IsoPacker {
|
|
/**
|
|
* Pack a directory into an ISO
|
|
*/
|
|
async pack(sourceDir: string, outputIso: string, volumeLabel?: string): Promise<void> {
|
|
log.info(`Creating ISO from ${sourceDir}...`);
|
|
|
|
const label = volumeLabel || 'UBUNTU_CUSTOM';
|
|
|
|
// Use xorriso to create a bootable ISO
|
|
const command = new Deno.Command('xorriso', {
|
|
args: [
|
|
'-as',
|
|
'mkisofs',
|
|
'-r',
|
|
'-V',
|
|
label,
|
|
'-o',
|
|
outputIso,
|
|
'-J',
|
|
'-joliet-long',
|
|
'-cache-inodes',
|
|
'-isohybrid-mbr',
|
|
'/usr/lib/ISOLINUX/isohdpfx.bin',
|
|
'-b',
|
|
'isolinux/isolinux.bin',
|
|
'-c',
|
|
'isolinux/boot.cat',
|
|
'-boot-load-size',
|
|
'4',
|
|
'-boot-info-table',
|
|
'-no-emul-boot',
|
|
'-eltorito-alt-boot',
|
|
'-e',
|
|
'boot/grub/efi.img',
|
|
'-no-emul-boot',
|
|
'-isohybrid-gpt-basdat',
|
|
sourceDir,
|
|
],
|
|
stdout: 'piped',
|
|
stderr: 'piped',
|
|
});
|
|
|
|
const process = command.spawn();
|
|
const { code, stderr } = await process.output();
|
|
|
|
if (code !== 0) {
|
|
const errorText = new TextDecoder().decode(stderr);
|
|
throw new Error(`Failed to create ISO: ${errorText}`);
|
|
}
|
|
|
|
log.success(`ISO created successfully at ${outputIso}`);
|
|
|
|
// Make it hybrid bootable (USB compatible)
|
|
await this.makeIsohybrid(outputIso);
|
|
}
|
|
|
|
/**
|
|
* Make the ISO hybrid bootable (USB-compatible)
|
|
*/
|
|
private async makeIsohybrid(isoPath: string): Promise<void> {
|
|
try {
|
|
log.info('Making ISO hybrid bootable...');
|
|
|
|
const command = new Deno.Command('isohybrid', {
|
|
args: ['--uefi', isoPath],
|
|
stdout: 'piped',
|
|
stderr: 'piped',
|
|
});
|
|
|
|
const { code } = await command.output();
|
|
|
|
if (code === 0) {
|
|
log.success('ISO is now USB-bootable');
|
|
} else {
|
|
log.warn('isohybrid failed, ISO may not be USB-bootable');
|
|
}
|
|
} catch (err: unknown) {
|
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
log.warn(`isohybrid not available: ${errorMessage}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if required tools are installed
|
|
*/
|
|
async checkDependencies(): Promise<boolean> {
|
|
try {
|
|
const xorrisoCmd = new Deno.Command('xorriso', {
|
|
args: ['--version'],
|
|
stdout: 'null',
|
|
stderr: 'null',
|
|
});
|
|
|
|
const { code } = await xorrisoCmd.output();
|
|
return code === 0;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ensure dependencies are installed
|
|
*/
|
|
async ensureDependencies(): Promise<void> {
|
|
const hasXorriso = await this.checkDependencies();
|
|
|
|
if (!hasXorriso) {
|
|
log.error('xorriso is not installed!');
|
|
log.info('Install xorriso:');
|
|
log.info(' Ubuntu/Debian: sudo apt install xorriso syslinux-utils');
|
|
log.info(' macOS: brew install xorriso syslinux');
|
|
throw new Error('Missing dependency: xorriso');
|
|
}
|
|
}
|
|
}
|