From 85df6f0d67c7969ffa231237ce7b560fa0134c32 Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Mon, 6 Feb 2023 15:15:00 -0800 Subject: [PATCH 1/7] Refactor process output handling. --- src/services/daprCliClient.ts | 37 +++++++- src/tasks/commandTaskProvider.ts | 22 ++--- src/util/process.ts | 146 ++++++++++++++++++++++--------- 3 files changed, 145 insertions(+), 60 deletions(-) diff --git a/src/services/daprCliClient.ts b/src/services/daprCliClient.ts index c1d4a48..0add39b 100644 --- a/src/services/daprCliClient.ts +++ b/src/services/daprCliClient.ts @@ -7,6 +7,7 @@ import * as nls from 'vscode-nls'; import { getLocalizationPathForFile } from '../util/localization'; import { DaprApplication } from "./daprApplicationProvider"; import * as os from 'os' +import * as vscode from 'vscode'; const localize = nls.loadMessageBundle(getLocalizationPathForFile(__filename)); @@ -16,6 +17,7 @@ export interface DaprVersion { } export interface DaprCliClient { + startDashboard(token: vscode.CancellationToken): Promise; version(): Promise; stopApp(application: DaprApplication | undefined): void; } @@ -26,9 +28,42 @@ interface DaprCliVersion { } export default class LocalDaprCliClient implements DaprCliClient { + private static readonly DashboardRunningRegex = /^Dapr Dashboard running on http:\/\/localhost:(?\d+)$/; + constructor(private readonly daprPathProvider: () => string) { } + async startDashboard(token: vscode.CancellationToken): Promise { + const command = + CommandLineBuilder + .create(this.daprPathProvider(), 'dashboard', '--port', '0') + .build(); + + let port = 0; + + await Process.start( + command, + line => { + const match = LocalDaprCliClient.DashboardRunningRegex.exec(line); + + if (match) { + const portString = match.groups?.['port']; + + if (portString) { + port = parseInt(portString, 10); + + return true; + } + } + + return false; + }, + {}, + token); + + return port; + } + async version(): Promise { const daprPath = this.daprPathProvider(); const command = @@ -60,6 +95,4 @@ export default class LocalDaprCliClient implements DaprCliClient { processId !== undefined ? process.kill(processId, 'SIGTERM') : null; } } - - } \ No newline at end of file diff --git a/src/tasks/commandTaskProvider.ts b/src/tasks/commandTaskProvider.ts index c18550d..443d23d 100644 --- a/src/tasks/commandTaskProvider.ts +++ b/src/tasks/commandTaskProvider.ts @@ -5,7 +5,7 @@ import * as cp from 'child_process'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import CustomExecutionTaskProvider from "./customExecutionTaskProvider"; -import { Process } from '../util/process'; +import { Process, WrittenOutputHandler } from '../util/process'; import { TaskDefinition } from './taskDefinition'; import { getLocalizationPathForFile } from '../util/localization'; @@ -24,20 +24,12 @@ export default class CommandTaskProvider extends CustomExecutionTaskProvider { return callback( definition, async (command, options) => { - const process = new Process(); + const outputHandler = new WrittenOutputHandler( + data => writer.write(data), + data => writer.write(data)); try { - process.onStdErr( - data => { - writer.write(data); - }); - - process.onStdOut( - data => { - writer.write(data); - }); - - const spawnOptions = options || {}; + const spawnOptions = { ...(options ?? {}), outputHandler }; if (spawnOptions.cwd === undefined) { if (vscode.workspace.workspaceFolders === undefined || vscode.workspace.workspaceFolders.length === 0) { @@ -50,9 +42,9 @@ export default class CommandTaskProvider extends CustomExecutionTaskProvider { writer.writeLine(localize('tasks.commandTaskProvider.executingMessage', '> Executing command: {0} <', command), 'bold'); writer.writeLine(''); - await process.spawn(command, spawnOptions, token); + await Process.spawn(command, spawnOptions, token); } finally { - process.dispose(); + outputHandler.dispose(); } }, token); diff --git a/src/util/process.ts b/src/util/process.ts index 1cd1978..e04c08f 100644 --- a/src/util/process.ts +++ b/src/util/process.ts @@ -2,9 +2,11 @@ // Licensed under the MIT license. import * as cp from 'child_process'; +import internal from 'stream'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import * as localization from './localization'; +import * as readline from 'node:readline'; const localize = nls.loadMessageBundle(localization.getLocalizationPathForFile(__filename)); @@ -16,54 +18,126 @@ function bufferToString(buffer: Buffer): string { return buffer.toString().replace(/\0/g, '').replace(/\r?\n$/g, ''); } -export class Process extends vscode.Disposable { - private readonly onStdErrEmitter = new vscode.EventEmitter(); - private readonly onStdOutEmitter = new vscode.EventEmitter(); +export interface ProcessOutputHandler { + listen(stderr: internal.Readable | null, stdout: internal.Readable | null): void; +} + +export interface SpawnOptions extends cp.SpawnOptions { + outputHandler?: ProcessOutputHandler; +} - constructor() { +export class LineOutputHandler extends vscode.Disposable implements ProcessOutputHandler { + private rl: readline.Interface | undefined; + + constructor(private readonly onLine: (line: string) => void) { super( () => { - this.onStdErrEmitter.dispose(); - this.onStdOutEmitter.dispose(); + this.rl?.close(); }); } - onStdErr = this.onStdErrEmitter.event; - onStdOut = this.onStdOutEmitter.event; + listen(stderr: internal.Readable | null, stdout: internal.Readable | null): void { + if (stdout) { + this.rl = readline.createInterface({ + input: stdout, + }); + + this.rl.on('line', this.onLine); + } + } +} - static async exec(command: string, options?: cp.ExecOptions, token?: vscode.CancellationToken): Promise<{ code: number; stderr: string; stdout: string }> { - const process = new Process(); +export class WrittenOutputHandler extends vscode.Disposable implements ProcessOutputHandler { + private readonly onStdErrCallback: (data: string | Buffer) => void; + private readonly onStdOutCallback: (data: string | Buffer) => void; - let stdoutBytesWritten = 0; - let stderrBytesWritten = 0; + private stderr: internal.Readable | null = null; + private stdout: internal.Readable | null = null; - const stdoutBuffer = Buffer.alloc(options && options.maxBuffer || DEFAULT_BUFFER_SIZE); - const stderrBuffer = Buffer.alloc(options && options.maxBuffer || DEFAULT_BUFFER_SIZE); + constructor( + onStdErr: (data: string) => void, + onStdOut: (data: string) => void) { + super( + () => { + this.stderr?.removeListener('data', this.onStdErrCallback); + this.stdout?.removeListener('data', this.onStdOutCallback); + }); - try { - process.onStdErr( - data => { - stderrBytesWritten += stderrBuffer.write(data, stderrBytesWritten); - }); + this.onStdErrCallback = data => onStdErr(data.toString()); + this.onStdOutCallback = data => onStdOut(data.toString()); + } - process.onStdOut( - data => { - stdoutBytesWritten += stdoutBuffer.write(data, stdoutBytesWritten); - }); + listen(stderr: internal.Readable | null, stdout: internal.Readable | null): void { + this.stderr = stderr; + this.stdout = stdout; + + if (stderr) { + stderr.on('data', this.onStdErrCallback); + } + + if (stdout) { + stdout.on('data', this.onStdOutCallback); + } + } +} + +export class BufferedOutputHandler extends WrittenOutputHandler { + private stdoutBytesWritten = 0; + private stderrBytesWritten = 0; - const code = await process.spawn(command, options, token); + constructor(private readonly maxBuffer: number = DEFAULT_BUFFER_SIZE) { + super( + data => { this.stderrBytesWritten += this.stderrBuffer.write(data.toString(), this.stderrBytesWritten); }, + data => { this.stdoutBytesWritten += this.stdoutBuffer.write(data.toString(), this.stdoutBytesWritten); }); + + this.stdoutBuffer = Buffer.alloc(maxBuffer); + this.stderrBuffer = Buffer.alloc(maxBuffer); + } + + public readonly stdoutBuffer: Buffer; + public readonly stderrBuffer: Buffer; +} + +export class Process { + static async exec(command: string, options?: cp.ExecOptions, token?: vscode.CancellationToken): Promise<{ code: number; stderr: string; stdout: string }> { + const outputHandler = new BufferedOutputHandler(); + + try { + const code = await Process.spawn(command, { ...options, outputHandler }, token); return { code, - stderr: bufferToString(stderrBuffer), - stdout: bufferToString(stdoutBuffer) + stderr: bufferToString(outputHandler.stderrBuffer), + stdout: bufferToString(outputHandler.stdoutBuffer) }; } finally { - process.dispose(); + outputHandler.dispose(); } } - spawn(command: string, options?: cp.SpawnOptions, token?: vscode.CancellationToken): Promise { + static async start(command: string, readyPredicate: (stdout: string) => boolean, options?: cp.ExecOptions, token?: vscode.CancellationToken): Promise { + let outputHandler: LineOutputHandler | undefined; + + try { + const waiter = new Promise( + resolve => { + outputHandler = new LineOutputHandler( + line => { + if (readyPredicate(line)) { + resolve(); + } + }); + }); + + void Process.spawn(command, { ...options, outputHandler }, token); + + await waiter; + } finally { + outputHandler?.dispose(); + } + } + + static spawn(command: string, options?: SpawnOptions, token?: vscode.CancellationToken): Promise { return new Promise( (resolve, reject) => { @@ -89,21 +163,7 @@ export class Process extends vscode.Disposable { } }); - if (process.stderr) { - process.stderr.on( - 'data', - (data: string | Buffer) => { - this.onStdErrEmitter.fire(data.toString()); - }); - } - - if (process.stdout) { - process.stdout.on( - 'data', - (data: string | Buffer) => { - this.onStdOutEmitter.fire(data.toString()); - }); - } + options.outputHandler?.listen(process.stderr, process.stdout); if (token) { const tokenListener = token.onCancellationRequested( From 6f0123a51040440f35c869a00ad024b194eb6890 Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Tue, 7 Feb 2023 09:09:36 -0800 Subject: [PATCH 2/7] Try to switch to new Dapr dashboard process. --- package-lock.json | 178 ++++---------------------- package.json | 4 +- src/extension.ts | 6 +- src/services/daprCliClient.ts | 16 +-- src/services/daprDashboardProvider.ts | 55 +++----- src/util/process.ts | 7 +- 6 files changed, 58 insertions(+), 208 deletions(-) diff --git a/package-lock.json b/package-lock.json index c1ebb9f..773b5d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,10 +15,9 @@ "axios": "^0.27.2", "handlebars": "^4.7.7", "lodash.isequal": "^4.5.0", - "portfinder": "^1.0.28", "rxjs": "^7.8.0", "semver": "^7.3.5", - "tcp-port-used": "^1.0.2", + "tree-kill": "^1.2.2", "vscode-nls": "^5.0.0" }, "devDependencies": { @@ -28,7 +27,6 @@ "@types/mocha": "^9.1.1", "@types/node": "^16.11.38", "@types/semver": "^7.3.9", - "@types/tcp-port-used": "^1.0.1", "@types/terser-webpack-plugin": "^5.2.0", "@types/vscode": "^1.67.0", "@types/webpack": "^4.41.26", @@ -552,12 +550,6 @@ "integrity": "sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==", "dev": true }, - "node_modules/@types/tcp-port-used": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/tcp-port-used/-/tcp-port-used-1.0.1.tgz", - "integrity": "sha512-6pwWTx8oUtWvsiZUCrhrK/53MzKVLnuNSSaZILPy3uMes9QnTrLMar9BDlJArbMOjDcjb3QXFk6Rz8qmmuySZw==", - "dev": true - }, "node_modules/@types/terser-webpack-plugin": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@types/terser-webpack-plugin/-/terser-webpack-plugin-5.2.0.tgz", @@ -1295,14 +1287,6 @@ "node": ">=8" } }, - "node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dependencies": { - "lodash": "^4.17.14" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1850,6 +1834,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -1881,7 +1866,8 @@ "node_modules/deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true }, "node_modules/deepmerge": { "version": "4.2.2", @@ -3271,11 +3257,6 @@ "node": ">=10" } }, - "node_modules/is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" - }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -3287,27 +3268,6 @@ "node": ">=8" } }, - "node_modules/is2": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.7.tgz", - "integrity": "sha512-4vBQoURAXC6hnLFxD4VW7uc04XiwTTl/8ydYJxKvPwkWQrSjInkuM5VZVg6BGr1/natq69zDuvO9lGpLClJqvA==", - "dependencies": { - "deep-is": "^0.1.3", - "ip-regex": "^4.1.0", - "is-url": "^1.2.4" - }, - "engines": { - "node": ">=v0.10.0" - } - }, - "node_modules/is2/node_modules/ip-regex": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", - "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", - "engines": { - "node": ">=8" - } - }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3478,11 +3438,6 @@ "node": ">=10" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -3707,6 +3662,7 @@ "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, "dependencies": { "minimist": "^1.2.5" }, @@ -4070,7 +4026,8 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node_modules/mute-stream": { "version": "0.0.8", @@ -4525,27 +4482,6 @@ "node": ">=8" } }, - "node_modules/portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dependencies": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/portfinder/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/prebuild-install": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", @@ -5234,15 +5170,6 @@ "follow-redirects": "^1.14.8" } }, - "node_modules/tcp-port-used": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz", - "integrity": "sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==", - "dependencies": { - "debug": "4.3.1", - "is2": "^2.0.6" - } - }, "node_modules/terser": { "version": "5.14.2", "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", @@ -5346,6 +5273,14 @@ "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", "dev": true }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/ts-loader": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.0.tgz", @@ -6744,12 +6679,6 @@ "integrity": "sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==", "dev": true }, - "@types/tcp-port-used": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/tcp-port-used/-/tcp-port-used-1.0.1.tgz", - "integrity": "sha512-6pwWTx8oUtWvsiZUCrhrK/53MzKVLnuNSSaZILPy3uMes9QnTrLMar9BDlJArbMOjDcjb3QXFk6Rz8qmmuySZw==", - "dev": true - }, "@types/terser-webpack-plugin": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@types/terser-webpack-plugin/-/terser-webpack-plugin-5.2.0.tgz", @@ -7323,14 +7252,6 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, - "async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "requires": { - "lodash": "^4.17.14" - } - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -7813,6 +7734,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, "requires": { "ms": "2.1.2" } @@ -7835,7 +7757,8 @@ "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true }, "deepmerge": { "version": "4.2.2", @@ -8885,11 +8808,6 @@ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, - "is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" - }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -8898,23 +8816,6 @@ "is-docker": "^2.0.0" } }, - "is2": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.7.tgz", - "integrity": "sha512-4vBQoURAXC6hnLFxD4VW7uc04XiwTTl/8ydYJxKvPwkWQrSjInkuM5VZVg6BGr1/natq69zDuvO9lGpLClJqvA==", - "requires": { - "deep-is": "^0.1.3", - "ip-regex": "^4.1.0", - "is-url": "^1.2.4" - }, - "dependencies": { - "ip-regex": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", - "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==" - } - } - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -9057,11 +8958,6 @@ "p-locate": "^5.0.0" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -9242,6 +9138,7 @@ "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, "requires": { "minimist": "^1.2.5" } @@ -9517,7 +9414,8 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "mute-stream": { "version": "0.0.8", @@ -9877,26 +9775,6 @@ } } }, - "portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, "prebuild-install": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", @@ -10448,15 +10326,6 @@ } } }, - "tcp-port-used": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz", - "integrity": "sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==", - "requires": { - "debug": "4.3.1", - "is2": "^2.0.6" - } - }, "terser": { "version": "5.14.2", "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", @@ -10524,6 +10393,11 @@ "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", "dev": true }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==" + }, "ts-loader": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.0.tgz", diff --git a/package.json b/package.json index 13191ea..7990471 100644 --- a/package.json +++ b/package.json @@ -609,7 +609,6 @@ "@types/mocha": "^9.1.1", "@types/node": "^16.11.38", "@types/semver": "^7.3.9", - "@types/tcp-port-used": "^1.0.1", "@types/terser-webpack-plugin": "^5.2.0", "@types/vscode": "^1.67.0", "@types/webpack": "^4.41.26", @@ -637,10 +636,9 @@ "axios": "^0.27.2", "handlebars": "^4.7.7", "lodash.isequal": "^4.5.0", - "portfinder": "^1.0.28", "rxjs": "^7.8.0", "semver": "^7.3.5", - "tcp-port-used": "^1.0.2", + "tree-kill": "^1.2.2", "vscode-nls": "^5.0.0" }, "overrides": { diff --git a/src/extension.ts b/src/extension.ts index 3635b7b..0a31252 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -29,7 +29,7 @@ import LocalScaffolder from './scaffolding/scaffolder'; import NodeEnvironmentProvider from './services/environmentProvider'; import createScaffoldDaprComponentsCommand from './commands/scaffoldDaprComponents'; import VsCodeSettingsProvider from './services/settingsProvider'; -import ProcessBasedDaprDashboardProvider from './services/daprDashboardProvider'; +import DaprBasedDaprDashboardProvider from './services/daprDashboardProvider'; import createStopCommand from './commands/applications/stopApp'; import LocalDaprCliClient from './services/daprCliClient'; import createInstallDaprCommand from './commands/help/installDapr'; @@ -72,8 +72,7 @@ export function activate(context: vscode.ExtensionContext): Promise { const templateScaffolder = new HandlebarsTemplateScaffolder(templatesPath); const daprCliClient = new LocalDaprCliClient(() => settingsProvider.daprPath) - const daprDashboardProvider = new ProcessBasedDaprDashboardProvider(() => settingsProvider.daprPath); - + const daprDashboardProvider = registerDisposable(new DaprBasedDaprDashboardProvider(daprCliClient)); telemetryProvider.registerContextCommandWithTelemetry('vscode-dapr.applications.invoke-get', createInvokeGetCommand(daprApplicationProvider, daprClient, ext.outputChannel, ui, context.workspaceState)); telemetryProvider.registerContextCommandWithTelemetry('vscode-dapr.applications.invoke-post', createInvokePostCommand(daprApplicationProvider, daprClient, ext.outputChannel, ui, context.workspaceState)); @@ -89,7 +88,6 @@ export function activate(context: vscode.ExtensionContext): Promise { telemetryProvider.registerCommandWithTelemetry('vscode-dapr.tasks.scaffoldDaprTasks', createScaffoldDaprTasksCommand(scaffolder, templateScaffolder, ui)); telemetryProvider.registerContextCommandWithTelemetry('vscode-dapr.tasks.openDaprDashboard', createOpenDaprDashboardCommand(daprDashboardProvider)); - const extensionPackage = context.extension.packageJSON; const daprInstallationManager = new LocalDaprInstallationManager( extensionPackage.engines['dapr-cli'], diff --git a/src/services/daprCliClient.ts b/src/services/daprCliClient.ts index 0add39b..48fce81 100644 --- a/src/services/daprCliClient.ts +++ b/src/services/daprCliClient.ts @@ -17,7 +17,7 @@ export interface DaprVersion { } export interface DaprCliClient { - startDashboard(token: vscode.CancellationToken): Promise; + startDashboard(token: vscode.CancellationToken): Promise; version(): Promise; stopApp(application: DaprApplication | undefined): void; } @@ -28,18 +28,18 @@ interface DaprCliVersion { } export default class LocalDaprCliClient implements DaprCliClient { - private static readonly DashboardRunningRegex = /^Dapr Dashboard running on http:\/\/localhost:(?\d+)$/; + private static readonly DashboardRunningRegex = /^Dapr Dashboard running on (?.+)$/; constructor(private readonly daprPathProvider: () => string) { } - async startDashboard(token: vscode.CancellationToken): Promise { + async startDashboard(token: vscode.CancellationToken): Promise { const command = CommandLineBuilder .create(this.daprPathProvider(), 'dashboard', '--port', '0') .build(); - let port = 0; + let url = ''; await Process.start( command, @@ -47,11 +47,9 @@ export default class LocalDaprCliClient implements DaprCliClient { const match = LocalDaprCliClient.DashboardRunningRegex.exec(line); if (match) { - const portString = match.groups?.['port']; - - if (portString) { - port = parseInt(portString, 10); + url = match.groups?.['url'] ?? ''; + if (url) { return true; } } @@ -61,7 +59,7 @@ export default class LocalDaprCliClient implements DaprCliClient { {}, token); - return port; + return url; } async version(): Promise { diff --git a/src/services/daprDashboardProvider.ts b/src/services/daprDashboardProvider.ts index 617bf5c..04d4e4b 100644 --- a/src/services/daprDashboardProvider.ts +++ b/src/services/daprDashboardProvider.ts @@ -1,51 +1,30 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import * as portfinder from 'portfinder' -import {Process} from '../util/process' -import * as nls from 'vscode-nls' -import { getLocalizationPathForFile } from '../util/localization'; -import * as tcp from 'tcp-port-used' - -const localize = nls.loadMessageBundle(getLocalizationPathForFile(__filename)); +import * as vscode from 'vscode'; +import { DaprCliClient } from './daprCliClient'; export interface DaprDashboardProvider { startDashboard(): Promise; } -export default class ProcessBasedDaprDashboardProvider implements DaprDashboardProvider { - private port: number | undefined; - private startUp: Promise | undefined; - - constructor(private readonly daprPathProvider: () => string) { +export default class DaprBasedDaprDashboardProvider extends vscode.Disposable implements DaprDashboardProvider { + private dashboardTask: Promise | undefined; + private readonly tokenProvider = new vscode.CancellationTokenSource(); + + constructor(private readonly daprCliClient: DaprCliClient) { + super( + () => { + this.tokenProvider.cancel(); + this.tokenProvider.dispose(); + }); } async startDashboard(): Promise { - let localStartup = this.startUp; - - if (!localStartup) { - localStartup = new Promise( - // eslint-disable-next-line @typescript-eslint/no-misused-promises, no-async-promise-executor - async (resolve, reject) => { - try { - const openPort = await portfinder.getPortPromise(); - void Process.exec(`${this.daprPathProvider()} dashboard -p ${openPort}`) - - await tcp.waitForStatus(openPort, 'localhost', true, 500, 4000) - - resolve(openPort); - } catch(error) { - this.startUp = undefined; - const msg = localize('dashboard.startDashboard.startupError', 'Dashboard instance failed to start. \'{0}\' ', (error).message); - reject(msg); - } - }); - - this.startUp = localStartup; + if (this.dashboardTask === undefined) { + this.dashboardTask = this.daprCliClient.startDashboard(this.tokenProvider.token); } - - this.port = await localStartup; - return `http://localhost:${this.port}`; - } -} \ No newline at end of file + return await this.dashboardTask; + } +} diff --git a/src/util/process.ts b/src/util/process.ts index e04c08f..291301b 100644 --- a/src/util/process.ts +++ b/src/util/process.ts @@ -7,6 +7,7 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import * as localization from './localization'; import * as readline from 'node:readline'; +import treeKill from 'tree-kill'; const localize = nls.loadMessageBundle(localization.getLocalizationPathForFile(__filename)); @@ -115,7 +116,7 @@ export class Process { } } - static async start(command: string, readyPredicate: (stdout: string) => boolean, options?: cp.ExecOptions, token?: vscode.CancellationToken): Promise { + static async start(command: string, readyPredicate: (stdout: string) => boolean, options?: cp.SpawnOptions, token?: vscode.CancellationToken): Promise { let outputHandler: LineOutputHandler | undefined; try { @@ -168,7 +169,9 @@ export class Process { if (token) { const tokenListener = token.onCancellationRequested( () => { - process.kill(); + if (process.pid !== undefined) { + treeKill(process.pid); + } tokenListener.dispose(); }); From 25895d519008809493436fbc643a43d488d8b207 Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Tue, 7 Feb 2023 22:19:33 -0800 Subject: [PATCH 3/7] Sketch stopping dashboard on deactivate. --- main.js | 6 ++- src/extension.ts | 19 +++++++-- src/services/daprCliClient.ts | 56 +++++++++++++++++---------- src/services/daprDashboardProvider.ts | 28 ++++++++------ src/util/asyncDisposable.ts | 3 ++ src/util/process.ts | 53 ++++++++++++++++++++++++- src/util/treeKill.ts | 16 ++++++++ 7 files changed, 141 insertions(+), 40 deletions(-) create mode 100644 src/util/asyncDisposable.ts create mode 100644 src/util/treeKill.ts diff --git a/main.js b/main.js index b1762db..70f70c2 100644 --- a/main.js +++ b/main.js @@ -41,8 +41,10 @@ function activate(ctx) { getExtension(ctx.extensionPath).activate(ctx); } -function deactivate(ctx) { - getExtension(ctx.extensionPath).deactivate(ctx); +function deactivate() { + if (actualExtension) { + return actualExtension.deactivate(); + } } exports.activate = activate; diff --git a/src/extension.ts b/src/extension.ts index 40cb3e8..0cb3d3d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -39,11 +39,20 @@ import { Observable } from 'rxjs'; import TreeNode from './views/treeNode'; import createDebugApplicationCommand from './commands/applications/debugApplication'; import createDebugRunCommand from './commands/applications/debugRun'; +import { AsyncDisposable } from './util/asyncDisposable'; interface ExtensionPackage { engines: { [key: string]: string }; } +const asyncDisposables: AsyncDisposable[] = []; + +function registerAsyncDisposable(disposable: T): T { + asyncDisposables.push(disposable); + + return disposable; +} + export function activate(context: vscode.ExtensionContext): Promise { function registerDisposable(disposable: T): T { context.subscriptions.push(disposable); @@ -74,7 +83,7 @@ export function activate(context: vscode.ExtensionContext): Promise { const templateScaffolder = new HandlebarsTemplateScaffolder(templatesPath); const daprCliClient = new LocalDaprCliClient(() => settingsProvider.daprPath) - const daprDashboardProvider = registerDisposable(new DaprBasedDaprDashboardProvider(daprCliClient)); + const daprDashboardProvider = registerAsyncDisposable(new DaprBasedDaprDashboardProvider(daprCliClient)); telemetryProvider.registerContextCommandWithTelemetry('vscode-dapr.applications.debug', createDebugApplicationCommand()); telemetryProvider.registerContextCommandWithTelemetry('vscode-dapr.applications.invoke-get', createInvokeGetCommand(daprApplicationProvider, daprClient, ext.outputChannel, ui, context.workspaceState)); @@ -136,6 +145,8 @@ export function activate(context: vscode.ExtensionContext): Promise { }); } -export function deactivate(): Promise { - return Promise.resolve(); -} \ No newline at end of file +export async function deactivate(): Promise { + for (const disposable of asyncDisposables) { + await disposable.dispose(); + } +} diff --git a/src/services/daprCliClient.ts b/src/services/daprCliClient.ts index 48fce81..5ad2568 100644 --- a/src/services/daprCliClient.ts +++ b/src/services/daprCliClient.ts @@ -2,12 +2,13 @@ // Licensed under the MIT license. import CommandLineBuilder from "../util/commandLineBuilder"; -import { Process } from "../util/process"; +import { LineOutputHandler, Process } from "../util/process"; import * as nls from 'vscode-nls'; import { getLocalizationPathForFile } from '../util/localization'; import { DaprApplication } from "./daprApplicationProvider"; import * as os from 'os' import * as vscode from 'vscode'; +import { AsyncDisposable } from "../util/asyncDisposable"; const localize = nls.loadMessageBundle(getLocalizationPathForFile(__filename)); @@ -16,8 +17,12 @@ export interface DaprVersion { runtime: string | undefined; } +export interface DaprDashboard extends AsyncDisposable { + readonly url: string; +} + export interface DaprCliClient { - startDashboard(token: vscode.CancellationToken): Promise; + startDashboard(): Promise; version(): Promise; stopApp(application: DaprApplication | undefined): void; } @@ -33,33 +38,44 @@ export default class LocalDaprCliClient implements DaprCliClient { constructor(private readonly daprPathProvider: () => string) { } - async startDashboard(token: vscode.CancellationToken): Promise { + async startDashboard(): Promise { const command = CommandLineBuilder .create(this.daprPathProvider(), 'dashboard', '--port', '0') .build(); - let url = ''; - - await Process.start( - command, - line => { - const match = LocalDaprCliClient.DashboardRunningRegex.exec(line); + let onLine: (line: string) => void; + + const readyTask = new Promise( + resolve => { + onLine = (line: string) => { + const match = LocalDaprCliClient.DashboardRunningRegex.exec(line); + + if (match) { + const url = match.groups?.['url']; + + if (url) { + resolve(url); + } + } + }; + }); - if (match) { - url = match.groups?.['url'] ?? ''; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const outputHandler = new LineOutputHandler(onLine!); - if (url) { - return true; - } - } + try { + const process = await Process.spawnProcess(command, { outputHandler }); - return false; - }, - {}, - token); + const url = await readyTask; - return url; + return { + dispose: () => process.killAll(), + url + }; + } finally { + outputHandler.dispose(); + } } async version(): Promise { diff --git a/src/services/daprDashboardProvider.ts b/src/services/daprDashboardProvider.ts index 04d4e4b..5a6f31e 100644 --- a/src/services/daprDashboardProvider.ts +++ b/src/services/daprDashboardProvider.ts @@ -1,30 +1,34 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import * as vscode from 'vscode'; -import { DaprCliClient } from './daprCliClient'; +import { AsyncDisposable } from '../util/asyncDisposable'; +import { DaprCliClient, DaprDashboard } from './daprCliClient'; export interface DaprDashboardProvider { startDashboard(): Promise; } -export default class DaprBasedDaprDashboardProvider extends vscode.Disposable implements DaprDashboardProvider { - private dashboardTask: Promise | undefined; - private readonly tokenProvider = new vscode.CancellationTokenSource(); +export default class DaprBasedDaprDashboardProvider implements DaprDashboardProvider, AsyncDisposable { + private dashboardTask: Promise | undefined; constructor(private readonly daprCliClient: DaprCliClient) { - super( - () => { - this.tokenProvider.cancel(); - this.tokenProvider.dispose(); - }); + } + + async dispose() { + if (this.dashboardTask) { + const dashboard = await this.dashboardTask; + + await dashboard.dispose(); + } } async startDashboard(): Promise { if (this.dashboardTask === undefined) { - this.dashboardTask = this.daprCliClient.startDashboard(this.tokenProvider.token); + this.dashboardTask = this.daprCliClient.startDashboard(); } - return await this.dashboardTask; + const dashboard = await this.dashboardTask; + + return dashboard.url; } } diff --git a/src/util/asyncDisposable.ts b/src/util/asyncDisposable.ts new file mode 100644 index 0000000..ef92b5c --- /dev/null +++ b/src/util/asyncDisposable.ts @@ -0,0 +1,3 @@ +export interface AsyncDisposable { + dispose(): Promise; +} diff --git a/src/util/process.ts b/src/util/process.ts index 291301b..7f60a43 100644 --- a/src/util/process.ts +++ b/src/util/process.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import * as localization from './localization'; import * as readline from 'node:readline'; -import treeKill from 'tree-kill'; +import { treeKill } from './treeKill'; const localize = nls.loadMessageBundle(localization.getLocalizationPathForFile(__filename)); @@ -170,7 +170,7 @@ export class Process { const tokenListener = token.onCancellationRequested( () => { if (process.pid !== undefined) { - treeKill(process.pid); + process.kill(); } tokenListener.dispose(); @@ -178,4 +178,53 @@ export class Process { } }); } + + static async spawnProcess(command: string, options?: SpawnOptions): Promise { + options = options || {}; + options.shell ??= true; + + const process = cp.spawn(command, options); + + options.outputHandler?.listen(process.stderr, process.stdout); + + const spawnTask = new Promise( + (resolve, reject) => { + process.on( + 'spawn', + () => { + resolve(); + }); + + process.on( + 'error', + err => { + reject(err); + }); + }); + + await spawnTask; + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const pid = process.pid!; + + return { + pid, + kill: () => new Promise( + resolve => { + if (process.exitCode === null) { + process.once('exit', resolve); + } else { + resolve(); + } + }), + killAll: async () => treeKill(pid) + } + } } + +export interface SpawnedProcess { + pid: number; + + kill(): Promise; + killAll(): Promise; +} \ No newline at end of file diff --git a/src/util/treeKill.ts b/src/util/treeKill.ts new file mode 100644 index 0000000..41195e6 --- /dev/null +++ b/src/util/treeKill.ts @@ -0,0 +1,16 @@ +import { default as tk } from "tree-kill"; + +export function treeKill(pid: number): Promise { + return new Promise( + (resolve, reject) => { + tk( + pid, + error => { + if (error) { + return reject(error); + } + + return resolve(); + }); + }); +} From 3ab59866958c63582d154cf864a5bc0046b02cd6 Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Tue, 7 Feb 2023 22:24:22 -0800 Subject: [PATCH 4/7] Minor updates. --- src/util/asyncDisposable.ts | 3 +++ src/util/process.ts | 36 +++++++----------------------------- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/src/util/asyncDisposable.ts b/src/util/asyncDisposable.ts index ef92b5c..0e99f51 100644 --- a/src/util/asyncDisposable.ts +++ b/src/util/asyncDisposable.ts @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + export interface AsyncDisposable { dispose(): Promise; } diff --git a/src/util/process.ts b/src/util/process.ts index 7f60a43..c76420e 100644 --- a/src/util/process.ts +++ b/src/util/process.ts @@ -99,6 +99,13 @@ export class BufferedOutputHandler extends WrittenOutputHandler { public readonly stderrBuffer: Buffer; } +export interface SpawnedProcess { + pid: number; + + kill(): Promise; + killAll(): Promise; +} + export class Process { static async exec(command: string, options?: cp.ExecOptions, token?: vscode.CancellationToken): Promise<{ code: number; stderr: string; stdout: string }> { const outputHandler = new BufferedOutputHandler(); @@ -116,28 +123,6 @@ export class Process { } } - static async start(command: string, readyPredicate: (stdout: string) => boolean, options?: cp.SpawnOptions, token?: vscode.CancellationToken): Promise { - let outputHandler: LineOutputHandler | undefined; - - try { - const waiter = new Promise( - resolve => { - outputHandler = new LineOutputHandler( - line => { - if (readyPredicate(line)) { - resolve(); - } - }); - }); - - void Process.spawn(command, { ...options, outputHandler }, token); - - await waiter; - } finally { - outputHandler?.dispose(); - } - } - static spawn(command: string, options?: SpawnOptions, token?: vscode.CancellationToken): Promise { return new Promise( (resolve, reject) => { @@ -221,10 +206,3 @@ export class Process { } } } - -export interface SpawnedProcess { - pid: number; - - kill(): Promise; - killAll(): Promise; -} \ No newline at end of file From 84ccc957c8b1e4482263e245a58dc7e257940840 Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Tue, 7 Feb 2023 22:30:56 -0800 Subject: [PATCH 5/7] Missed header. --- src/util/treeKill.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/treeKill.ts b/src/util/treeKill.ts index 41195e6..d939e95 100644 --- a/src/util/treeKill.ts +++ b/src/util/treeKill.ts @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + import { default as tk } from "tree-kill"; export function treeKill(pid: number): Promise { From 33ed06f17a39e49e4108c475cda8805bb4cfdecf Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Tue, 7 Feb 2023 22:35:34 -0800 Subject: [PATCH 6/7] Insist on Dapr CLI 1.10. --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7aa5ed6..c1c6264 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,7 @@ "webpack-cli": "^4.9.2" }, "engines": { - "dapr-cli": ">=1.9", + "dapr-cli": ">=1.10", "dapr-runtime": ">=1.9", "vscode": "^1.74.0" } diff --git a/package.json b/package.json index 61ae666..eee4065 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "ui" ], "engines": { - "dapr-cli": ">=1.9", + "dapr-cli": ">=1.10", "dapr-runtime": ">=1.9", "vscode": "^1.74.0" }, From 5b3fdaa080e1080dc37563ccb510ba85eaf28f6c Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Tue, 7 Feb 2023 22:48:04 -0800 Subject: [PATCH 7/7] Satisfy linter. --- src/services/daprCliClient.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/services/daprCliClient.ts b/src/services/daprCliClient.ts index 5ad2568..cb7e70c 100644 --- a/src/services/daprCliClient.ts +++ b/src/services/daprCliClient.ts @@ -7,7 +7,6 @@ import * as nls from 'vscode-nls'; import { getLocalizationPathForFile } from '../util/localization'; import { DaprApplication } from "./daprApplicationProvider"; import * as os from 'os' -import * as vscode from 'vscode'; import { AsyncDisposable } from "../util/asyncDisposable"; const localize = nls.loadMessageBundle(getLocalizationPathForFile(__filename));