beforeEach(() => { const PROCESS_PATH = nuclideUri.join( __dirname, 'fixtures/dummy-service/dummyioserver.py', ); const OPTS = { cwd: nuclideUri.dirname(PROCESS_PATH), stdio: 'pipe', detached: false, }; const serviceRegistry = new ServiceRegistry( [], [ { name: 'dummy', definition: nuclideUri.join( __dirname, 'fixtures/dummy-service/DummyService.js', ), implementation: nuclideUri.join( __dirname, 'fixtures/dummy-service/DummyService.js', ), preserveFunctionNames: true, }, ], ); const processStream = spawn('python', [PROCESS_PATH], OPTS) // For the sake of our tests, simulate creating the process asynchronously. .subscribeOn(Scheduler.async); server = new RpcProcess('Dummy IO Server', serviceRegistry, processStream); });
async function createHackProcess( fileCache: FileCache, configDir: string, ): Promise<HackProcess> { const command = await getHackCommand(); if (command === '') { throw new Error("Couldn't find Hack command"); } logger.info(`Creating new hack connection for ${configDir}: ${command}`); logger.info(`Current PATH: ${maybeToString(process.env.PATH)}`); try { await runCommand(command, ['start', configDir], { isExitError: ({exitCode}) => !(exitCode === 0 || exitCode === HACK_SERVER_ALREADY_EXISTS_EXIT_CODE), }).toPromise(); } catch (err) { if (err.exitCode != null) { throw new Error( `Hack server start failed with code: ${String(err.exitCode)}`, ); } throw new Error(`Hack server failed with error: ${err.message}`); } const processStream = spawn(command, ['ide', configDir]); const hackProcess = new HackProcess( fileCache, `HackProcess-${configDir}`, processStream, configDir, ); // If the process exits unexpectedly, create a new one immediately. const startTime = Date.now(); hackProcess.observeExitMessage().subscribe(message => { // Dispose the process by removing it from the cache. if (processes.has(fileCache)) { processes.get(fileCache).delete(configDir); } if ( message != null && message.exitCode === HACK_IDE_NEW_CLIENT_CONNECTED_EXIT_CODE ) { logger.info('Not reconnecting Hack process--another client connected'); return; } // If the process exited too quickly (possibly due to a crash), don't get // stuck in a loop creating and crashing it. const processUptimeMs = Date.now() - startTime; if (processUptimeMs < 1000) { logger.error('Hack process exited in <1s; not reconnecting'); return; } logger.info(`Reconnecting with new HackProcess for ${configDir}`); processes.get(fileCache).get(configDir); }); return hackProcess; }
function getOutputLines(command, args, opts) { return spawn(command, args, opts).switchMap(proc => { return getOutputStream(proc).reduce((acc, result) => { if (result.kind === 'stdout') { acc.push(result.data.trimRight()); } return acc; }, []); }); }