Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion src/unixTerminal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,37 @@ const FIXTURES_PATH = path.normalize(path.join(__dirname, '..', 'fixtures', 'utf
if (process.platform !== 'win32') {
// Dynamic require to avoid loading pty.node on Windows
// eslint-disable-next-line @typescript-eslint/naming-convention
const { UnixTerminal } = require('./unixTerminal') as { UnixTerminal: typeof UnixTerminalType };
const { UnixTerminal, resolveSpawnHelperPath } = require('./unixTerminal') as { UnixTerminal: typeof UnixTerminalType; resolveSpawnHelperPath: (nativeDir: string, moduleDir: string) => string };

describe('resolveSpawnHelperPath', () => {
it('rewrites a packed asar path to its unpacked form', () => {
const helperPath = resolveSpawnHelperPath(
'/Example.app/Contents/Resources/app.asar/node_modules/node-pty/build/Release',
'/Example.app/Contents/Resources/app.asar/node_modules/node-pty/lib');
assert.strictEqual(helperPath, '/Example.app/Contents/Resources/app.asar.unpacked/node_modules/node-pty/build/Release/spawn-helper');
});

it('does not double-rewrite an already-unpacked asar path', () => {
const helperPath = resolveSpawnHelperPath(
'/Example.app/Contents/Resources/app.asar.unpacked/node_modules/node-pty/build/Release',
'/Example.app/Contents/Resources/app.asar.unpacked/node_modules/node-pty/lib');
assert.strictEqual(helperPath, '/Example.app/Contents/Resources/app.asar.unpacked/node_modules/node-pty/build/Release/spawn-helper');
});

it('rewrites a packed node_modules.asar path to its unpacked form', () => {
const helperPath = resolveSpawnHelperPath(
'/app/node_modules.asar/node-pty/build/Release',
'/app/node_modules.asar/node-pty/lib');
assert.strictEqual(helperPath, '/app/node_modules.asar.unpacked/node-pty/build/Release/spawn-helper');
});

it('does not double-rewrite an already-unpacked node_modules.asar path', () => {
const helperPath = resolveSpawnHelperPath(
'/app/node_modules.asar.unpacked/node-pty/build/Release',
'/app/node_modules.asar.unpacked/node-pty/lib');
assert.strictEqual(helperPath, '/app/node_modules.asar.unpacked/node-pty/build/Release/spawn-helper');
});
});

describe('UnixTerminal', () => {
describe('Constructor', () => {
Expand Down
30 changes: 26 additions & 4 deletions src/unixTerminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,32 @@ import { assign, loadNativeModule } from './utils';

const native = loadNativeModule('pty');
const pty: IUnixNative = native.module;
let helperPath = native.dir + '/spawn-helper';
helperPath = path.resolve(__dirname, helperPath);
helperPath = helperPath.replace('app.asar', 'app.asar.unpacked');
helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked');

/**
* Resolve the absolute path of the platform spawn helper binary.
*
* @param nativeDir - the directory that holds the compiled native module.
* @param moduleDir - the directory of this module (resolves relative dirs).
* @returns the absolute spawn-helper path.
*/
export function resolveSpawnHelperPath(nativeDir: string, moduleDir: string): string {
let helperPath = path.resolve(moduleDir, nativeDir + '/spawn-helper');
// String.prototype.replace matches the first occurrence, so when helperPath
// already contains 'app.asar.unpacked' (e.g. node-pty is installed under an
// unpacked asar directory) the substring 'app.asar' matches the prefix of
// 'app.asar.unpacked' and produces 'app.asar.unpacked.unpacked' — a path
// that does not exist on disk. Skip each rewrite when the unpacked variant
// is already present.
if (helperPath.indexOf('app.asar.unpacked') === -1) {
helperPath = helperPath.replace('app.asar', 'app.asar.unpacked');
}
if (helperPath.indexOf('node_modules.asar.unpacked') === -1) {
helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked');
}
return helperPath;
}

const helperPath = resolveSpawnHelperPath(native.dir, __dirname);

const DEFAULT_FILE = 'sh';
const DEFAULT_NAME = 'xterm';
Expand Down