11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ciconst { 31cb0ef41Sopenharmony_ci ArrayPrototypeFilter, 41cb0ef41Sopenharmony_ci ArrayPrototypeForEach, 51cb0ef41Sopenharmony_ci ArrayPrototypeJoin, 61cb0ef41Sopenharmony_ci ArrayPrototypeMap, 71cb0ef41Sopenharmony_ci ArrayPrototypePushApply, 81cb0ef41Sopenharmony_ci ArrayPrototypeSlice, 91cb0ef41Sopenharmony_ci StringPrototypeStartsWith, 101cb0ef41Sopenharmony_ci} = primordials; 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ciconst { 131cb0ef41Sopenharmony_ci prepareMainThreadExecution, 141cb0ef41Sopenharmony_ci markBootstrapComplete, 151cb0ef41Sopenharmony_ci} = require('internal/process/pre_execution'); 161cb0ef41Sopenharmony_ciconst { triggerUncaughtException } = internalBinding('errors'); 171cb0ef41Sopenharmony_ciconst { getOptionValue } = require('internal/options'); 181cb0ef41Sopenharmony_ciconst { emitExperimentalWarning } = require('internal/util'); 191cb0ef41Sopenharmony_ciconst { FilesWatcher } = require('internal/watch_mode/files_watcher'); 201cb0ef41Sopenharmony_ciconst { green, blue, red, white, clear } = require('internal/util/colors'); 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ciconst { spawn } = require('child_process'); 231cb0ef41Sopenharmony_ciconst { inspect } = require('util'); 241cb0ef41Sopenharmony_ciconst { setTimeout, clearTimeout } = require('timers'); 251cb0ef41Sopenharmony_ciconst { resolve } = require('path'); 261cb0ef41Sopenharmony_ciconst { once, on } = require('events'); 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ciprepareMainThreadExecution(false, false); 301cb0ef41Sopenharmony_cimarkBootstrapComplete(); 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_ci// TODO(MoLow): Make kill signal configurable 331cb0ef41Sopenharmony_ciconst kKillSignal = 'SIGTERM'; 341cb0ef41Sopenharmony_ciconst kShouldFilterModules = getOptionValue('--watch-path').length === 0; 351cb0ef41Sopenharmony_ciconst kWatchedPaths = ArrayPrototypeMap(getOptionValue('--watch-path'), (path) => resolve(path)); 361cb0ef41Sopenharmony_ciconst kPreserveOutput = getOptionValue('--watch-preserve-output'); 371cb0ef41Sopenharmony_ciconst kCommand = ArrayPrototypeSlice(process.argv, 1); 381cb0ef41Sopenharmony_ciconst kCommandStr = inspect(ArrayPrototypeJoin(kCommand, ' ')); 391cb0ef41Sopenharmony_ciconst args = ArrayPrototypeFilter(process.execArgv, (arg, i, arr) => 401cb0ef41Sopenharmony_ci !StringPrototypeStartsWith(arg, '--watch-path') && 411cb0ef41Sopenharmony_ci (!arr[i - 1] || !StringPrototypeStartsWith(arr[i - 1], '--watch-path')) && 421cb0ef41Sopenharmony_ci arg !== '--watch' && arg !== '--watch-preserve-output'); 431cb0ef41Sopenharmony_ciArrayPrototypePushApply(args, kCommand); 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ciconst watcher = new FilesWatcher({ debounce: 200, mode: kShouldFilterModules ? 'filter' : 'all' }); 461cb0ef41Sopenharmony_ciArrayPrototypeForEach(kWatchedPaths, (p) => watcher.watchPath(p)); 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_cilet graceTimer; 491cb0ef41Sopenharmony_cilet child; 501cb0ef41Sopenharmony_cilet exited; 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_cifunction start() { 531cb0ef41Sopenharmony_ci exited = false; 541cb0ef41Sopenharmony_ci const stdio = kShouldFilterModules ? ['inherit', 'inherit', 'inherit', 'ipc'] : 'inherit'; 551cb0ef41Sopenharmony_ci child = spawn(process.execPath, args, { stdio, env: { ...process.env, WATCH_REPORT_DEPENDENCIES: '1' } }); 561cb0ef41Sopenharmony_ci watcher.watchChildProcessModules(child); 571cb0ef41Sopenharmony_ci child.once('exit', (code) => { 581cb0ef41Sopenharmony_ci exited = true; 591cb0ef41Sopenharmony_ci if (code === 0) { 601cb0ef41Sopenharmony_ci process.stdout.write(`${blue}Completed running ${kCommandStr}${white}\n`); 611cb0ef41Sopenharmony_ci } else { 621cb0ef41Sopenharmony_ci process.stdout.write(`${red}Failed running ${kCommandStr}${white}\n`); 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci }); 651cb0ef41Sopenharmony_ci} 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ciasync function killAndWait(signal = kKillSignal, force = false) { 681cb0ef41Sopenharmony_ci child?.removeAllListeners(); 691cb0ef41Sopenharmony_ci if (!child) { 701cb0ef41Sopenharmony_ci return; 711cb0ef41Sopenharmony_ci } 721cb0ef41Sopenharmony_ci if ((child.killed || exited) && !force) { 731cb0ef41Sopenharmony_ci return; 741cb0ef41Sopenharmony_ci } 751cb0ef41Sopenharmony_ci const onExit = once(child, 'exit'); 761cb0ef41Sopenharmony_ci child.kill(signal); 771cb0ef41Sopenharmony_ci const { 0: exitCode } = await onExit; 781cb0ef41Sopenharmony_ci return exitCode; 791cb0ef41Sopenharmony_ci} 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_cifunction reportGracefulTermination() { 821cb0ef41Sopenharmony_ci // Log if process takes more than 500ms to stop. 831cb0ef41Sopenharmony_ci let reported = false; 841cb0ef41Sopenharmony_ci clearTimeout(graceTimer); 851cb0ef41Sopenharmony_ci graceTimer = setTimeout(() => { 861cb0ef41Sopenharmony_ci reported = true; 871cb0ef41Sopenharmony_ci process.stdout.write(`${blue}Waiting for graceful termination...${white}\n`); 881cb0ef41Sopenharmony_ci }, 500).unref(); 891cb0ef41Sopenharmony_ci return () => { 901cb0ef41Sopenharmony_ci clearTimeout(graceTimer); 911cb0ef41Sopenharmony_ci if (reported) { 921cb0ef41Sopenharmony_ci process.stdout.write(`${clear}${green}Gracefully restarted ${kCommandStr}${white}\n`); 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci }; 951cb0ef41Sopenharmony_ci} 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ciasync function stop() { 981cb0ef41Sopenharmony_ci watcher.clearFileFilters(); 991cb0ef41Sopenharmony_ci const clearGraceReport = reportGracefulTermination(); 1001cb0ef41Sopenharmony_ci await killAndWait(); 1011cb0ef41Sopenharmony_ci clearGraceReport(); 1021cb0ef41Sopenharmony_ci} 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ciasync function restart() { 1051cb0ef41Sopenharmony_ci if (!kPreserveOutput) process.stdout.write(clear); 1061cb0ef41Sopenharmony_ci process.stdout.write(`${green}Restarting ${kCommandStr}${white}\n`); 1071cb0ef41Sopenharmony_ci await stop(); 1081cb0ef41Sopenharmony_ci start(); 1091cb0ef41Sopenharmony_ci} 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci(async () => { 1121cb0ef41Sopenharmony_ci emitExperimentalWarning('Watch mode'); 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci try { 1151cb0ef41Sopenharmony_ci start(); 1161cb0ef41Sopenharmony_ci 1171cb0ef41Sopenharmony_ci // eslint-disable-next-line no-unused-vars 1181cb0ef41Sopenharmony_ci for await (const _ of on(watcher, 'changed')) { 1191cb0ef41Sopenharmony_ci await restart(); 1201cb0ef41Sopenharmony_ci } 1211cb0ef41Sopenharmony_ci } catch (error) { 1221cb0ef41Sopenharmony_ci triggerUncaughtException(error, true /* fromPromise */); 1231cb0ef41Sopenharmony_ci } 1241cb0ef41Sopenharmony_ci})(); 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci// Exiting gracefully to avoid stdout/stderr getting written after 1271cb0ef41Sopenharmony_ci// parent process is killed. 1281cb0ef41Sopenharmony_ci// this is fairly safe since user code cannot run in this process 1291cb0ef41Sopenharmony_cifunction signalHandler(signal) { 1301cb0ef41Sopenharmony_ci return async () => { 1311cb0ef41Sopenharmony_ci watcher.clear(); 1321cb0ef41Sopenharmony_ci const exitCode = await killAndWait(signal, true); 1331cb0ef41Sopenharmony_ci process.exit(exitCode ?? 0); 1341cb0ef41Sopenharmony_ci }; 1351cb0ef41Sopenharmony_ci} 1361cb0ef41Sopenharmony_ciprocess.on('SIGTERM', signalHandler('SIGTERM')); 1371cb0ef41Sopenharmony_ciprocess.on('SIGINT', signalHandler('SIGINT')); 138