diff --git a/src/bundle.ts b/src/bundle.ts index 3f99521..05bacf4 100644 --- a/src/bundle.ts +++ b/src/bundle.ts @@ -3,6 +3,7 @@ import { chmod, lstat, mkdir, + readdir, readlink, stat, symlink, @@ -83,6 +84,11 @@ export abstract class Bundle { */ public readonly path: string; + /** + * Flat bundle. + */ + public readonly flat: boolean; + /** * Projector instance. */ @@ -102,9 +108,11 @@ export abstract class Bundle { * Bundle constructor. * * @param path Output path for the main executable. + * @param flat Flat bundle. */ - constructor(path: string) { + constructor(path: string, flat = false) { this.path = path; + this.flat = flat; } /** @@ -447,6 +455,17 @@ export abstract class Bundle { * Check that output path is valid, else throws. */ protected async _checkOutput() { + if (this.flat) { + const p = dirname(this.path); + if (await fsLstatExists(p)) { + for (const n of await readdir(p)) { + if (!this.isExcludedFile(n)) { + throw new Error(`Output path not empty: ${p}`); + } + } + } + return; + } await Promise.all( [this.path, this.resourcePath('')].map(async p => { if (await fsLstatExists(p)) { @@ -596,6 +615,22 @@ export abstract class Bundle { return dest; } + /** + * Get the projector path. + * + * @returns This path or the nested path. + */ + protected _getProjectorPath() { + return this.flat ? this.path : this._getProjectorPathNested(); + } + + /** + * Get nested projector path. + * + * @returns Output path. + */ + protected abstract _getProjectorPathNested(): string; + /** * Create projector instance for the bundle. * diff --git a/src/bundle/otto.spec.ts b/src/bundle/otto.spec.ts index 21b9a70..6898ef4 100644 --- a/src/bundle/otto.spec.ts +++ b/src/bundle/otto.spec.ts @@ -18,8 +18,8 @@ export async function cleanBundlesDir(...path: string[]) { export class BundleOttoDummy extends BundleOtto { public readonly projector: ProjectorOttoDummy; - constructor(path: string) { - super(path); + constructor(path: string, flat = false) { + super(path, flat); this.projector = this._createProjector(); } @@ -28,13 +28,17 @@ export class BundleOttoDummy extends BundleOtto { return '.exe'; } - protected _createProjector() { + protected _getProjectorPathNested(): string { const {path, extension} = this; const directory = trimExtension(path, extension, true); if (directory === path) { throw new Error(`Output path must end with: ${extension}`); } - return new ProjectorOttoDummy(pathJoin(directory, basename(path))); + return pathJoin(directory, basename(path)); + } + + protected _createProjector() { + return new ProjectorOttoDummy(this._getProjectorPath()); } protected async _writeLauncher() { diff --git a/src/bundle/otto.test.ts b/src/bundle/otto.test.ts index 2d78445..3c08fe9 100644 --- a/src/bundle/otto.test.ts +++ b/src/bundle/otto.test.ts @@ -247,5 +247,17 @@ void describe('bundle/otto', () => { strictEqual((await st('d/a.txt')).isFile(), true); strictEqual((await st('d/b.txt')).isFile(), true); }); + + void it('flat', async () => { + const dir = await getDir('flat'); + const dest = pathJoin(dir, 'application.exe'); + + const b = new BundleOttoDummy(dest, true); + b.projector.skeleton = fixtureFile('dummy.zip'); + b.projector.configFile = fixtureFile('config.ini.crlf.bin'); + await b.write(async p => { + await p.createResourceFile('resource.txt', 'testing123'); + }); + }); }); }); diff --git a/src/bundle/otto.ts b/src/bundle/otto.ts index 500996d..0670491 100644 --- a/src/bundle/otto.ts +++ b/src/bundle/otto.ts @@ -14,16 +14,19 @@ export abstract class BundleOtto extends Bundle { * ProjectorOtto constructor. * * @param path Output path. + * @param flat Flat bundle. */ - constructor(path: string) { - super(path); + constructor(path: string, flat = false) { + super(path, flat); } /** * @inheritdoc */ protected async _close(): Promise { - await this._writeLauncher(); + if (!this.flat) { + await this._writeLauncher(); + } await super._close(); } diff --git a/src/bundle/otto/mac.test.ts b/src/bundle/otto/mac.test.ts index da73d0e..eac56c1 100644 --- a/src/bundle/otto/mac.test.ts +++ b/src/bundle/otto/mac.test.ts @@ -63,6 +63,21 @@ void describe('bundle/otto/mac', () => { ); }); }); + + void it('flat', async () => { + const dir = await getDir('flat'); + const dest = pathJoin(dir, 'application.app'); + + const b = new BundleOttoMac(dest, true); + b.projector.skeleton = await getSkeleton(); + b.projector.configFile = fixtureFile('config.ini.lf.bin'); + await b.write(async b => { + await b.copyResource( + 'movie.dir', + fixtureFile('dir7.dir') + ); + }); + }); }); } }); diff --git a/src/bundle/otto/mac.ts b/src/bundle/otto/mac.ts index 19bc602..8838033 100644 --- a/src/bundle/otto/mac.ts +++ b/src/bundle/otto/mac.ts @@ -22,9 +22,10 @@ export class BundleOttoMac extends BundleOtto { * BundleOttoMac constructor. * * @param path Output path for the main application. + * @param flat Flat bundle. */ - constructor(path: string) { - super(path); + constructor(path: string, flat = false) { + super(path, flat); this.projector = this._createProjector(); } @@ -45,13 +46,19 @@ export class BundleOttoMac extends BundleOtto { return trimExtension(basename(this.path), this.extension, true); } + /** + *@inheritdoc + */ + protected _getProjectorPathNested(): string { + const projName = `${this._getLauncherName()}${this.extension}`; + return pathJoin(this.path, 'Contents', 'Resources', projName); + } + /** * @inheritdoc */ protected _createProjector() { - const projName = `${this._getLauncherName()}${this.extension}`; - const projPath = pathJoin(this.path, 'Contents', 'Resources', projName); - return new ProjectorOttoMac(projPath); + return new ProjectorOttoMac(this._getProjectorPath()); } /** diff --git a/src/bundle/otto/windows.test.ts b/src/bundle/otto/windows.test.ts index 4e97174..4e2eba5 100644 --- a/src/bundle/otto/windows.test.ts +++ b/src/bundle/otto/windows.test.ts @@ -65,6 +65,21 @@ void describe('bundle/otto/windows', () => { ); }); }); + + void it('flat', async () => { + const dir = await getDir('flat'); + const dest = pathJoin(dir, 'application.exe'); + + const b = new BundleOttoWindows(dest, true); + b.projector.skeleton = await getSkeleton(); + b.projector.configFile = fixtureFile('config.ini.crlf.bin'); + await b.write(async b => { + await b.copyResource( + 'movie.dir', + fixtureFile('dir7.dir') + ); + }); + }); }); } }); diff --git a/src/bundle/otto/windows.ts b/src/bundle/otto/windows.ts index f4c95ba..3a9a048 100644 --- a/src/bundle/otto/windows.ts +++ b/src/bundle/otto/windows.ts @@ -19,9 +19,10 @@ export class BundleOttoWindows extends BundleOtto { * BundleOttoWindows constructor. * * @param path Output path for the main application. + * @param flat Flat bundle. */ - constructor(path: string) { - super(path); + constructor(path: string, flat = false) { + super(path, flat); this.projector = this._createProjector(); } @@ -34,15 +35,22 @@ export class BundleOttoWindows extends BundleOtto { } /** - * @inheritdoc + *@inheritdoc */ - protected _createProjector() { + protected _getProjectorPathNested(): string { const {path, extension} = this; const directory = trimExtension(path, extension, true); if (directory === path) { throw new Error(`Output path must end with: ${extension}`); } - return new ProjectorOttoWindows(pathJoin(directory, basename(path))); + return pathJoin(directory, basename(path)); + } + + /** + * @inheritdoc + */ + protected _createProjector() { + return new ProjectorOttoWindows(this._getProjectorPath()); } /**