diff --git a/src/mounter.ts b/src/mounter.ts index 00f4959..eb12e5a 100644 --- a/src/mounter.ts +++ b/src/mounter.ts @@ -1,4 +1,4 @@ -import {spawn} from 'node:child_process'; +import {spawn, spawnSync} from 'node:child_process'; import { Plist, @@ -121,7 +121,52 @@ export class Mounter { options: Readonly | null = null, ejectOnShutdown: Readonly | null = null ) { - // Assemble args. + const devices = await this._runAttach(this._argsAttach(file, options)); + const eject = this._createEject(devices, ejectOnShutdown); + return { + devices, + eject + } as IMounterAttachInfo; + } + + /** + * Eject a disk image. + * + * @param file Path to device file or volume mount point. + * @param options Options object. + */ + public async eject( + file: string, + options: Readonly | null = null + ) { + await this._runEject(this._argsEject(file, options)); + } + + /** + * Eject a disk image. + * + * @param file Path to device file or volume mount point. + * @param options Options object. + */ + public ejectSync( + file: string, + options: Readonly | null = null + ) { + // eslint-disable-next-line no-sync + this._runEjectSync(this._argsEject(file, options)); + } + + /** + * Create args for attach. + * + * @param file Path to disk image. + * @param options Options object. + * @returns Argument list. + */ + protected _argsAttach( + file: string, + options: Readonly | null = null + ) { const args = ['attach', '-plist']; if (options) { if (options.readonly) { @@ -132,39 +177,26 @@ export class Mounter { } } args.push(this._fileArg(file)); - - // Run command. - const devices = await this._runAttach(args); - - // Create the eject callback. - const eject = this._createEject(devices, ejectOnShutdown); - - const info: IMounterAttachInfo = { - devices, - eject - }; - return info; + return args; } /** - * Eject a disk image. + * Create args for eject. * * @param file Path to device file or volume mount point. * @param options Options object. + * @returns Argument list. */ - public async eject( + protected _argsEject( file: string, options: Readonly | null = null ) { - // Assemble args. const args = ['eject']; if (options && options.force) { args.push('-force'); } args.push(this._fileArg(file)); - - // Run command. - await this._runEject(args); + return args; } /** @@ -196,12 +228,27 @@ export class Mounter { */ protected async _runEject(args: Readonly) { const proc = spawn(this.hdiutil, args); - const code = await new Promise((resolve, reject) => { + const status = await new Promise((resolve, reject) => { proc.once('exit', resolve); proc.once('error', reject); }); - if (code) { - throw new Error(`Eject failed: hdiutil exit code: ${code}`); + if (status) { + throw new Error(`Eject failed: hdiutil exit code: ${status}`); + } + } + + /** + * Run hdiutil eject command. + * + * @param args CLI args. + */ + protected _runEjectSync(args: Readonly) { + const {status, error} = spawnSync(this.hdiutil, args); + if (error) { + throw error; + } + if (status) { + throw new Error(`Eject failed: hdiutil exit code: ${status}`); } }