diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index b448930f..bf7cdabf 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -8,6 +8,7 @@ }, "dependencies": { "@grpc/grpc-js": "^0.4.0", + "@theia/application-package": "next", "@theia/core": "next", "@theia/editor": "next", "@theia/filesystem": "next", @@ -18,9 +19,12 @@ "@theia/workspace": "next", "@theia/navigator": "next", "@theia/terminal": "next", + "@types/ps-tree": "^1.1.0", "@types/which": "^1.3.1", "css-element-queries": "^1.2.0", "p-queue": "^5.0.0", + "ps-tree": "^1.2.0", + "tree-kill": "^1.2.1", "which": "^1.3.1" }, "scripts": { diff --git a/arduino-ide-extension/src/node/arduino-daemon.ts b/arduino-ide-extension/src/node/arduino-daemon.ts index a214fe90..f5d0365b 100644 --- a/arduino-ide-extension/src/node/arduino-daemon.ts +++ b/arduino-ide-extension/src/node/arduino-daemon.ts @@ -1,12 +1,12 @@ import * as which from 'which'; import * as os from 'os'; import { join, delimiter } from 'path'; -import { exec } from 'child_process'; -import { ChildProcess } from 'child_process'; +import { exec, spawn, SpawnOptions } from 'child_process'; import { inject, injectable, named } from 'inversify'; import { ILogger } from '@theia/core/lib/common/logger'; import { BackendApplicationContribution } from '@theia/core/lib/node'; import { Deferred } from '@theia/core/lib/common/promise-util'; +import { environment } from '@theia/application-package/lib/environment'; import { DaemonLog } from './daemon-log'; import { ToolOutputServiceServer } from '../common/protocol/tool-output-service'; @@ -23,8 +23,6 @@ export class ArduinoDaemon implements BackendApplicationContribution { @inject(ToolOutputServiceServer) protected readonly toolOutputService: ToolOutputServiceServer; - protected process: ChildProcess | undefined; - protected isReady = new Deferred(); async onStart() { @@ -48,6 +46,15 @@ export class ArduinoDaemon implements BackendApplicationContribution { } console.log(stdout); }); + const options: SpawnOptions = { + env: environment.electron.runAsNodeEnv(), + detached: true, + stdio: 'ignore' + } + const command = process.execPath; + const cp = spawn(command, [join(__dirname, 'daemon-watcher.js'), String(process.pid), String(daemon.pid)], options); + cp.unref(); + if (daemon.stdout) { daemon.stdout.on('data', data => { this.toolOutputService.publishNewOutput('daemon', data.toString()); @@ -63,7 +70,6 @@ export class ArduinoDaemon implements BackendApplicationContribution { if (daemon.stderr) { daemon.on('exit', (code, signal) => DaemonLog.log(this.logger, `Daemon exited with code: ${code}. Signal was: ${signal}.`)); } - this.process = daemon; } await new Promise(resolve => setTimeout(resolve, 2000)); @@ -78,13 +84,4 @@ export class ArduinoDaemon implements BackendApplicationContribution { } } - onStop() { - if (!this.process) { - return; - } - - DaemonLog.log(this.logger, `Shutting down daemon.`); - this.process.kill("SIGTERM"); - } - } diff --git a/arduino-ide-extension/src/node/boards-service-impl.ts b/arduino-ide-extension/src/node/boards-service-impl.ts index 40b981df..ef2f45d5 100644 --- a/arduino-ide-extension/src/node/boards-service-impl.ts +++ b/arduino-ide-extension/src/node/boards-service-impl.ts @@ -55,7 +55,7 @@ export class BoardsServiceImpl implements BoardsService { } } } - resolve({boards}); + resolve({ boards }); }) }); } diff --git a/arduino-ide-extension/src/node/daemon-watcher.ts b/arduino-ide-extension/src/node/daemon-watcher.ts new file mode 100644 index 00000000..e1cd692f --- /dev/null +++ b/arduino-ide-extension/src/node/daemon-watcher.ts @@ -0,0 +1,17 @@ +import * as psTree from 'ps-tree'; +const kill = require('tree-kill'); +const [theiaPid, daemonPid] = process.argv.slice(2).map(id => Number.parseInt(id, 10)); + +setInterval(() => { + try { + // Throws an exception if the Theia process doesn't exist anymore. + process.kill(theiaPid, 0); + } catch { + psTree(daemonPid, function (_, children) { + for (const { PID } of children) { + kill(PID); + } + kill(daemonPid, () => process.exit()); + }); + } +}, 1000); diff --git a/yarn.lock b/yarn.lock index c759d9e4..577c2094 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1015,6 +1015,22 @@ semver "^5.4.1" write-json-file "^2.2.0" +"@theia/application-package@next": + version "0.9.0-next.7a419b76" + resolved "https://registry.yarnpkg.com/@theia/application-package/-/application-package-0.9.0-next.7a419b76.tgz#9061d364a9e03218285c04477ca4b8ca3cfcca89" + integrity sha512-MoYXQiFSAjSvMClGz6GSSWwKe6cnLp9mprDBQRGfVXkVeQIc2nB6reKlRMpnp+UCo9jmQwyZbvUxsiMWO5wo6A== + dependencies: + "@types/fs-extra" "^4.0.2" + "@types/request" "^2.0.3" + "@types/semver" "^5.4.0" + "@types/write-json-file" "^2.2.1" + changes-stream "^2.2.0" + fs-extra "^4.0.2" + is-electron "^2.1.0" + request "^2.82.0" + semver "^5.4.1" + write-json-file "^2.2.0" + "@theia/cli@next": version "0.9.0-next.3587c237" resolved "https://registry.yarnpkg.com/@theia/cli/-/cli-0.9.0-next.3587c237.tgz#0cd61bc15ce8fe8bfbc9bb40fa305c444799489f" @@ -1414,6 +1430,11 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6" integrity sha512-CFzn9idOEpHrgdw8JsoTkaDDyRWk1jrzIV8djzcgpq0y9tG4B4lFT+Nxh52DVpDXV+n4+NPNv7M1Dj5uMp6XFg== +"@types/ps-tree@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@types/ps-tree/-/ps-tree-1.1.0.tgz#7e2034e8ccdc16f6b0ced7a88529ebcb3b1dc424" + integrity sha512-rm5GU5sefQpg2d/DQ+fMDZnl9aPiJjJ9FYA12isIocNTZqu9VDZRgCRBx3oYFEdmDpmPmY4hxxmY/+1a84Rtzg== + "@types/range-parser@*": version "1.2.3" resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" @@ -4665,7 +4686,7 @@ duplexer3@^0.1.4: resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= -duplexer@^0.1.1: +duplexer@^0.1.1, duplexer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= @@ -4964,6 +4985,19 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +event-stream@=3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE= + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + eventemitter3@^3.1.0: version "3.1.2" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" @@ -5541,6 +5575,11 @@ from2@^2.1.0, from2@^2.1.1: inherits "^2.0.1" readable-stream "^2.0.0" +from@~0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" + integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= + fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" @@ -7626,6 +7665,11 @@ map-obj@^2.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ= + map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -8913,6 +8957,13 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= + dependencies: + through "~2.3" + pbkdf2@^3.0.3: version "3.0.17" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" @@ -9414,6 +9465,13 @@ prr@~1.0.1: resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= +ps-tree@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd" + integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== + dependencies: + event-stream "=3.3.4" + pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -10584,6 +10642,13 @@ split2@^2.0.0: dependencies: through2 "^2.0.2" +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + integrity sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8= + dependencies: + through "2" + split@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" @@ -10646,6 +10711,13 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + integrity sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ= + dependencies: + duplexer "~0.1.1" + stream-each@^1.1.0: version "1.2.3" resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" @@ -11045,7 +11117,7 @@ through2@~0.2.3: readable-stream "~1.1.9" xtend "~2.1.1" -through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@^2.3.8: +through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -11166,6 +11238,11 @@ trash@^4.0.1: resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= +tree-kill@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a" + integrity sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q== + trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"