diff --git a/README.md b/README.md index a5f3f88..9c58eb5 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,9 @@ import {ProjectorWindows} from '@shockpkg/dir-projector'; const projector = new ProjectorWindows('projector-windows/application.exe'); +// Required skeleton. +projector.skeleton = 'skeleton.zip'; + // Optional custom icon. projector.iconFile = 'icon.ico'; @@ -70,7 +73,7 @@ projector.nestXtrasConfiguration = true; // Optionally fix Shockwave 3D Xtra InstalledDisplayDrivers reading. projector.patchShockwave3dInstalledDisplayDriversSize = true; -await projector.withFile('skeleton.zip', 'config.ini'); +await projector.withFile('config.ini'); ``` ### Mac App @@ -80,6 +83,9 @@ import {ProjectorMacApp} from '@shockpkg/dir-projector'; const projector = new ProjectorMacApp('projector-macapp/application.app'); +// Required skeleton. +projector.skeleton = 'skeleton.zip'; + // Optional custom icon. projector.iconFile = 'icon.icns'; @@ -118,7 +124,7 @@ projector.nestXtrasContents = true; // Optionally use Intel-only skeleton. // projector.intel = true; -await projector.withFile('skeleton.dmg', 'config.ini'); +await projector.withFile('config.ini'); ``` ## Bundle @@ -131,11 +137,9 @@ import {BundleWindows} from '@shockpkg/dir-projector'; const bundle = new BundleWindows('bundle-windows/application.exe'); // Use projector property to set options. -bundle.projector.includeXtras = { - '': null -}; +bundle.projector.skeleton = 'skeleton.zip'; -await bundle.withFile('skeleton.zip', 'config.ini', async b => { +await bundle.withFile('config.ini', async b => { // Add resources in callback. await b.copyResource('movie.dir', 'movie.dir'); }); @@ -149,11 +153,9 @@ import {BundleMacApp} from '@shockpkg/dir-projector'; const bundle = new BundleMacApp('bundle-macapp/application.app'); // Use projector property to set options. -bundle.projector.includeXtras = { - '': null -}; +bundle.projector.skeleton = 'skeleton.zip'; -await bundle.withFile('skeleton.dmg', 'config.ini', async b => { +await bundle.withFile('config.ini', async b => { // Add resources in callback. await b.copyResource('movie.dir', 'movie.dir'); }); diff --git a/src/bundle.test.ts b/src/bundle.test.ts index e19686b..e9206c8 100644 --- a/src/bundle.test.ts +++ b/src/bundle.test.ts @@ -62,11 +62,9 @@ void describe('bundle', () => { const dir = await getDir('simple'); const dest = pathJoin(dir, 'application.exe'); - const p = new BundleDummy(dest); - await p.withFile( - fixtureFile('dummy.exe'), - fixtureFile('config.ini.crlf.bin') - ); + const b = new BundleDummy(dest); + b.projector.skeleton = fixtureFile('dummy.zip'); + await b.withFile(fixtureFile('config.ini.crlf.bin')); }); void it('resources', async () => { @@ -109,48 +107,45 @@ void describe('bundle', () => { await utimes(resources, dateA, dateA); - const p = new BundleDummy(dest); - await p.withFile( - fixtureFile('dummy.exe'), - fixtureFile('config.ini.crlf.bin'), - async p => { - await p.copyResource('resources0', resources); - - await p.copyResource('resources1', resources, { - atimeCopy: true, - mtimeCopy: true, - executableCopy: true - }); - - await p.copyResource('resources2/a.txt', resourcesA, { + const b = new BundleDummy(dest); + b.projector.skeleton = fixtureFile('dummy.zip'); + await b.withFile(fixtureFile('config.ini.crlf.bin'), async p => { + await p.copyResource('resources0', resources); + + await p.copyResource('resources1', resources, { + atimeCopy: true, + mtimeCopy: true, + executableCopy: true + }); + + await p.copyResource('resources2/a.txt', resourcesA, { + atime: dateB, + mtime: dateB, + executable: true + }); + await p.copyResource('resources2/d/b.txt', resourcesB, { + atime: dateB, + mtime: dateB, + executable: false + }); + + if (supportsSymlinks) { + await p.copyResource('resources2/l1.txt', resourcesL1, { atime: dateB, mtime: dateB, executable: true }); - await p.copyResource('resources2/d/b.txt', resourcesB, { + await p.copyResource('resources2/l2.txt', resourcesL2, { atime: dateB, mtime: dateB, executable: false }); - - if (supportsSymlinks) { - await p.copyResource('resources2/l1.txt', resourcesL1, { - atime: dateB, - mtime: dateB, - executable: true - }); - await p.copyResource('resources2/l2.txt', resourcesL2, { - atime: dateB, - mtime: dateB, - executable: false - }); - } } - ); + }); await rm(resources, {recursive: true, force: true}); - const st = async (path: string) => lstat(p.resourcePath(path)); + const st = async (path: string) => lstat(b.resourcePath(path)); const res0 = await st('resources0'); notEqual(res0.atime.getFullYear(), 2001); @@ -255,23 +250,20 @@ void describe('bundle', () => { await mkdir(dirname(resourcesA), {recursive: true}); await writeFile(resourcesA, 'alpha'); - const p = new BundleDummy(dest); - await p.withFile( - fixtureFile('dummy.exe'), - fixtureFile('config.ini.crlf.bin'), - async p => { - await p.createResourceFile('d/b.txt', 'beta'); + const b = new BundleDummy(dest); + b.projector.skeleton = fixtureFile('dummy.zip'); + await b.withFile(fixtureFile('config.ini.crlf.bin'), async p => { + await p.createResourceFile('d/b.txt', 'beta'); - // Merge contents at root of resources. - await p.copyResource('.', resources, { - merge: true - }); - } - ); + // Merge contents at root of resources. + await p.copyResource('.', resources, { + merge: true + }); + }); await rm(resources, {recursive: true, force: true}); - const st = async (path: string) => lstat(p.resourcePath(path)); + const st = async (path: string) => lstat(b.resourcePath(path)); strictEqual((await st('d/a.txt')).isFile(), true); strictEqual((await st('d/b.txt')).isFile(), true); diff --git a/src/bundle.ts b/src/bundle.ts index 8042cb3..4650373 100644 --- a/src/bundle.ts +++ b/src/bundle.ts @@ -135,28 +135,26 @@ export abstract class Bundle { /** * Open output with file. * - * @param player Player path. * @param configFile Config file. */ - public async openFile(player: string, configFile: string | null) { + public async openFile(configFile: string | null) { const configData = configFile ? await readFile(configFile) : null; - await this.openData(player, configData); + await this.openData(configData); } /** * Open output with data. * - * @param player Player path. * @param configData Config data. */ - public async openData(player: string, configData: Readonly | null) { + public async openData(configData: Readonly | null) { if (this._isOpen) { throw new Error('Already open'); } await this._checkOutput(); this._closeQueue.clear(); - await this._openData(player, configData); + await this._openData(configData); this._isOpen = true; } @@ -180,35 +178,31 @@ export abstract class Bundle { * Write out projector with player and file. * Has a callback to write out the resources. * - * @param player Player path. * @param configFile Config file. * @param func Async function. * @returns Return value of the async function. */ public async withFile( - player: string, configFile: string | null, func: ((self: this) => Promise) | null = null ) { const configData = configFile ? await readFile(configFile) : null; - return this.withData(player, configData, func); + return this.withData(configData, func); } /** * Write out projector with player and data. * Has a callback to write out the resources. * - * @param player Player path. * @param configData Config data. * @param func Async function. * @returns Return value of the async function. */ public async withData( - player: string, configData: Readonly | null, func: ((self: this) => Promise) | null = null ) { - await this.openData(player, configData); + await this.openData(configData); try { return func ? await func.call(this, this) : null; } finally { @@ -588,14 +582,10 @@ export abstract class Bundle { /** * Open output with data. * - * @param player Player path. * @param configData Config data. */ - protected async _openData( - player: string, - configData: Readonly | null - ) { - await this.projector.withData(player, configData); + protected async _openData(configData: Readonly | null) { + await this.projector.withData(configData); } /** diff --git a/src/bundle/mac/app.test.ts b/src/bundle/mac/app.test.ts index e79e9db..9201787 100644 --- a/src/bundle/mac/app.test.ts +++ b/src/bundle/mac/app.test.ts @@ -26,8 +26,8 @@ void describe('bundle/mac/app', () => { const dest = pathJoin(dir, 'application.app'); const b = new BundleMacApp(dest); + b.projector.skeleton = await getSkeleton(); await b.withFile( - await getSkeleton(), fixtureFile('config.ini.lf.bin'), async b => { await b.copyResource( @@ -44,6 +44,7 @@ void describe('bundle/mac/app', () => { const b = new BundleMacApp(dest); const p = b.projector; + p.skeleton = await getSkeleton(); p.lingoFile = fixtureFile('lingo.ini.lf.bin'); p.splashImageFile = fixtureFile('splash.pict'); p.iconFile = fixtureFile('icon.icns'); @@ -57,7 +58,6 @@ void describe('bundle/mac/app', () => { '': null }; await b.withFile( - await getSkeleton(), fixtureFile('config.ini.lf.bin'), async b => { await b.copyResource( diff --git a/src/bundle/windows.test.ts b/src/bundle/windows.test.ts index b2aa445..87fddfe 100644 --- a/src/bundle/windows.test.ts +++ b/src/bundle/windows.test.ts @@ -30,8 +30,8 @@ void describe('bundle/windows', () => { const dest = pathJoin(dir, 'application.exe'); const b = new BundleWindows(dest); + b.projector.skeleton = await getSkeleton(); await b.withFile( - await getSkeleton(), fixtureFile('config.ini.crlf.bin'), async b => { await b.copyResource( @@ -48,6 +48,7 @@ void describe('bundle/windows', () => { const b = new BundleWindows(dest); const p = b.projector; + p.skeleton = await getSkeleton(); p.lingoFile = fixtureFile('lingo.ini.crlf.bin'); p.splashImageFile = fixtureFile('splash.bmp'); p.nestXtrasConfiguration = true; @@ -60,7 +61,6 @@ void describe('bundle/windows', () => { p.iconFile = fixtureFile('icon.ico'); p.versionStrings = versionStrings; await b.withFile( - await getSkeleton(), fixtureFile('config.ini.crlf.bin'), async b => { await b.copyResource( diff --git a/src/projector.test.ts b/src/projector.test.ts index 47fa260..2f54e08 100644 --- a/src/projector.test.ts +++ b/src/projector.test.ts @@ -14,7 +14,8 @@ void describe('projector', () => { const dest = pathJoin(dir, 'application.exe'); const p = new ProjectorDummy(dest); - await p.withFile('dummy', fixtureFile('config.ini.crlf.bin')); + p.skeleton = 'dummy'; + await p.withFile(fixtureFile('config.ini.crlf.bin')); await copyFile(fixtureFile('dir7.dir'), pathJoin(dir, 'movie.dir')); }); @@ -24,8 +25,9 @@ void describe('projector', () => { const dest = pathJoin(dir, 'application.exe'); const p = new ProjectorDummy(dest); + p.skeleton = 'dummy'; p.lingoFile = fixtureFile('lingo.ini.crlf.bin'); - await p.withFile('dummy', fixtureFile('config.ini.crlf.bin')); + await p.withFile(fixtureFile('config.ini.crlf.bin')); await copyFile(fixtureFile('dir7.dir'), pathJoin(dir, 'movie.dir')); }); @@ -35,8 +37,9 @@ void describe('projector', () => { const dest = pathJoin(dir, 'application.exe'); const p = new ProjectorDummy(dest); + p.skeleton = 'dummy'; p.splashImageFile = fixtureFile('splash.bmp'); - await p.withFile('dummy', fixtureFile('config.ini.crlf.bin')); + await p.withFile(fixtureFile('config.ini.crlf.bin')); await copyFile(fixtureFile('dir7.dir'), pathJoin(dir, 'movie.dir')); }); @@ -46,9 +49,10 @@ void describe('projector', () => { const dest = pathJoin(dir, 'application.exe'); const p = new ProjectorDummy(dest); + p.skeleton = 'dummy'; p.lingoFile = fixtureFile('lingo.ini.crlf.bin'); p.splashImageFile = fixtureFile('splash.bmp'); - await p.withFile('dummy', fixtureFile('config.ini.crlf.bin')); + await p.withFile(fixtureFile('config.ini.crlf.bin')); await copyFile(fixtureFile('dir7.dir'), pathJoin(dir, 'movie.dir')); }); diff --git a/src/projector.ts b/src/projector.ts index 56b080c..6bbb985 100644 --- a/src/projector.ts +++ b/src/projector.ts @@ -80,6 +80,11 @@ export abstract class Projector { */ public nobrowse = false; + /** + * Skeleton path. + */ + public skeleton: string | null = null; + /** * Output path. */ @@ -287,24 +292,25 @@ export abstract class Projector { /** * Write out projector with skeleton and config file. * - * @param skeleton Skeleton path. * @param configFile Config file. */ - public async withFile(skeleton: string, configFile: string | null) { - const configData = configFile ? await readFile(configFile) : null; - await this.withData(skeleton, configData); + public async withFile(configFile: string | null) { + await this.withData(configFile ? await readFile(configFile) : null); } /** * Write out projector with skeleton and config data. * - * @param skeleton Skeleton path. * @param configData Config data. */ public async withData( - skeleton: string, configData: Readonly | string | Readonly | null ) { + const {skeleton} = this; + if (!skeleton) { + throw new Error('No projector skeleton configured'); + } + await this._checkOutput(); await this._writeSkeleton(skeleton); await this._modifySkeleton(); diff --git a/src/projector/mac/app.test.ts b/src/projector/mac/app.test.ts index 3c7099f..ca8fa88 100644 --- a/src/projector/mac/app.test.ts +++ b/src/projector/mac/app.test.ts @@ -26,10 +26,8 @@ void describe('projector/mac/app', () => { const dest = pathJoin(dir, 'application.app'); const p = new ProjectorMacApp(dest); - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.lf.bin') - ); + p.skeleton = await getSkeleton(); + await p.withFile(fixtureFile('config.ini.lf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -42,14 +40,12 @@ void describe('projector/mac/app', () => { const dest = pathJoin(dir, 'application.app'); const p = new ProjectorMacApp(dest); + p.skeleton = await getSkeleton(); p.includeXtras = { // eslint-disable-next-line @typescript-eslint/naming-convention '': null }; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.lf.bin') - ); + await p.withFile(fixtureFile('config.ini.lf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -62,15 +58,13 @@ void describe('projector/mac/app', () => { const dest = pathJoin(dir, 'application.app'); const p = new ProjectorMacApp(dest); + p.skeleton = await getSkeleton(); p.includeXtras = { Scripting: null, // eslint-disable-next-line @typescript-eslint/naming-convention 'GIF Agent.xtra': null }; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.lf.bin') - ); + await p.withFile(fixtureFile('config.ini.lf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -83,15 +77,13 @@ void describe('projector/mac/app', () => { const dest = pathJoin(dir, 'application.app'); const p = new ProjectorMacApp(dest); + p.skeleton = await getSkeleton(); p.includeXtras = { Scripting: 'Scripting RENAMED', // eslint-disable-next-line @typescript-eslint/naming-convention 'GIF Agent.xtra': 'GIF Agent RENAMED.xtra' }; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.lf.bin') - ); + await p.withFile(fixtureFile('config.ini.lf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -104,11 +96,9 @@ void describe('projector/mac/app', () => { const dest = pathJoin(dir, 'application.app'); const p = new ProjectorMacApp(dest); + p.skeleton = await getSkeleton(); p.shockwave = true; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.lf.bin') - ); + await p.withFile(fixtureFile('config.ini.lf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -121,15 +111,13 @@ void describe('projector/mac/app', () => { const dest = pathJoin(dir, 'application.app'); const p = new ProjectorMacApp(dest); + p.skeleton = await getSkeleton(); p.nestXtrasConfiguration = true; p.includeXtras = { // eslint-disable-next-line @typescript-eslint/naming-convention '': null }; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.lf.bin') - ); + await p.withFile(fixtureFile('config.ini.lf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -143,15 +131,13 @@ void describe('projector/mac/app', () => { const dest = pathJoin(dir, 'application.app'); const p = new ProjectorMacApp(dest); + p.skeleton = await getSkeleton(); p.nestXtrasContents = true; p.includeXtras = { // eslint-disable-next-line @typescript-eslint/naming-convention '': null }; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.lf.bin') - ); + await p.withFile(fixtureFile('config.ini.lf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -166,11 +152,9 @@ void describe('projector/mac/app', () => { const dest = pathJoin(dir, 'application.app'); const p = new ProjectorMacApp(dest); + p.skeleton = await getSkeleton(); p.intel = true; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.lf.bin') - ); + await p.withFile(fixtureFile('config.ini.lf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -184,6 +168,7 @@ void describe('projector/mac/app', () => { const dest = pathJoin(dir, 'application.app'); const p = new ProjectorMacApp(dest); + p.skeleton = await getSkeleton(); p.lingoFile = fixtureFile('lingo.ini.lf.bin'); p.splashImageFile = fixtureFile('splash.pict'); p.iconFile = fixtureFile('icon.icns'); @@ -196,10 +181,7 @@ void describe('projector/mac/app', () => { // eslint-disable-next-line @typescript-eslint/naming-convention '': null }; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.lf.bin') - ); + await p.withFile(fixtureFile('config.ini.lf.bin')); await copyFile( fixtureFile('dir7.dir'), diff --git a/src/projector/windows.test.ts b/src/projector/windows.test.ts index 236a349..dd7758b 100644 --- a/src/projector/windows.test.ts +++ b/src/projector/windows.test.ts @@ -30,10 +30,8 @@ void describe('projector/windows', () => { const dest = pathJoin(dir, 'application.exe'); const p = new ProjectorWindows(dest); - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.crlf.bin') - ); + p.skeleton = await getSkeleton(); + await p.withFile(fixtureFile('config.ini.crlf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -46,16 +44,14 @@ void describe('projector/windows', () => { const dest = pathJoin(dir, 'application.exe'); const p = new ProjectorWindows(dest); + p.skeleton = await getSkeleton(); p.includeXtras = { // eslint-disable-next-line @typescript-eslint/naming-convention '': null }; p.patchShockwave3dInstalledDisplayDriversSize = patchShockwave3dInstalledDisplayDriversSize; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.crlf.bin') - ); + await p.withFile(fixtureFile('config.ini.crlf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -68,6 +64,7 @@ void describe('projector/windows', () => { const dest = pathJoin(dir, 'application.exe'); const p = new ProjectorWindows(dest); + p.skeleton = await getSkeleton(); p.includeXtras = { Scripting: null, // eslint-disable-next-line @typescript-eslint/naming-convention @@ -75,10 +72,7 @@ void describe('projector/windows', () => { // eslint-disable-next-line @typescript-eslint/naming-convention 'GIF Agent.x32': null }; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.crlf.bin') - ); + await p.withFile(fixtureFile('config.ini.crlf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -91,6 +85,7 @@ void describe('projector/windows', () => { const dest = pathJoin(dir, 'application.exe'); const p = new ProjectorWindows(dest); + p.skeleton = await getSkeleton(); p.includeXtras = { Scripting: 'Scripting RENAMED', // eslint-disable-next-line @typescript-eslint/naming-convention @@ -98,10 +93,7 @@ void describe('projector/windows', () => { // eslint-disable-next-line @typescript-eslint/naming-convention 'GIF Agent.x32': 'GIF Agent RENAMED.x32' }; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.crlf.bin') - ); + await p.withFile(fixtureFile('config.ini.crlf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -114,11 +106,9 @@ void describe('projector/windows', () => { const dest = pathJoin(dir, 'application.exe'); const p = new ProjectorWindows(dest); + p.skeleton = await getSkeleton(); p.shockwave = true; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.crlf.bin') - ); + await p.withFile(fixtureFile('config.ini.crlf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -131,6 +121,7 @@ void describe('projector/windows', () => { const dest = pathJoin(dir, 'application.exe'); const p = new ProjectorWindows(dest); + p.skeleton = await getSkeleton(); p.nestXtrasConfiguration = true; p.includeXtras = { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -138,10 +129,7 @@ void describe('projector/windows', () => { }; p.patchShockwave3dInstalledDisplayDriversSize = patchShockwave3dInstalledDisplayDriversSize; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.crlf.bin') - ); + await p.withFile(fixtureFile('config.ini.crlf.bin')); await copyFile( fixtureFile('dir7.dir'), @@ -154,6 +142,7 @@ void describe('projector/windows', () => { const dest = pathJoin(dir, 'application.exe'); const p = new ProjectorWindows(dest); + p.skeleton = await getSkeleton(); p.lingoFile = fixtureFile('lingo.ini.crlf.bin'); p.splashImageFile = fixtureFile('splash.bmp'); p.nestXtrasConfiguration = true; @@ -165,10 +154,7 @@ void describe('projector/windows', () => { patchShockwave3dInstalledDisplayDriversSize; p.iconFile = fixtureFile('icon.ico'); p.versionStrings = versionStrings; - await p.withFile( - await getSkeleton(), - fixtureFile('config.ini.crlf.bin') - ); + await p.withFile(fixtureFile('config.ini.crlf.bin')); await copyFile( fixtureFile('dir7.dir'),