diff --git a/src/Output.ts b/src/Output.ts index 0772593b..ab05cb81 100644 --- a/src/Output.ts +++ b/src/Output.ts @@ -1,7 +1,7 @@ // Copyright (c) Consensys Software Inc. All rights reserved. // Licensed under the MIT license. -import {commands} from 'vscode'; +import {commands, ExtensionContext, window} from 'vscode'; import {LogView} from './views/LogView'; export enum OutputLabel { @@ -16,6 +16,8 @@ export enum OutputLabel { } export class Output { + private static readonly _outputChannel = window.createOutputChannel(OutputLabel.truffleForVSCode); + /** * Append the given value and a line feed character * to the log panel @@ -26,6 +28,9 @@ export class Output { */ public static outputLine(label: OutputLabel, message: string, description?: string): void { commands.executeCommand(`${LogView.viewType}.create.log`, label, this.formatMessage(label, message), description); + + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + this._outputChannel.appendLine(this.formatMessage(label, message)); } /** @@ -34,7 +39,7 @@ export class Output { * @param label - represents the log type * @param description - represents the log description */ - public static dispose(label: OutputLabel, description?: string): void { + public static async dispose(label: OutputLabel, description?: string): Promise { commands.executeCommand(`${LogView.viewType}.dispose.tab`, label, description); } @@ -47,4 +52,20 @@ export class Output { private static formatMessage(label = '', message = ''): string { return `${label ? `[${label}] ` : ''}${message}`; } + + /** + * INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + * Call this only once to push the outputChannel into the list of subscriptions. + */ + public static init(context: ExtensionContext) { + context.subscriptions.push(this._outputChannel); + } + + public static show(): void { + this._outputChannel.show(); + } + + public static hide(): void { + this._outputChannel.hide(); + } } diff --git a/src/commands/TruffleCommands.ts b/src/commands/TruffleCommands.ts index 01163274..93a53bb2 100644 --- a/src/commands/TruffleCommands.ts +++ b/src/commands/TruffleCommands.ts @@ -77,6 +77,9 @@ export namespace TruffleCommands { } await showIgnorableNotification(Constants.statusBarMessages.buildingContracts, async () => { + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + Output.show(); + await outputCommandHelper.executeCommand(contractDirectory, 'npx', args.join(' ')); commands.executeCommand('truffle-vscode.views.deployments.refresh'); @@ -509,6 +512,9 @@ async function deployToNetwork(networkName: string, truffleConfigPath: string): const truffleConfigName = path.basename(truffleConfigPath); await fs.ensureDir(workspaceRoot); + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + Output.show(); + try { await installRequiredDependencies(); await outputCommandHelper.executeCommand( diff --git a/src/extension.ts b/src/extension.ts index e060235d..5a7f668a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -40,6 +40,7 @@ import {registerGanacheDetails} from './pages/GanacheDetails'; import {registerLogView} from './views/LogView'; import {saveTextDocument} from './helpers/workspace'; import {StatusBarItems} from './Models/StatusBarItems/Contract'; +import {Output} from './Output'; export async function activate(context: ExtensionContext) { /** @@ -58,6 +59,9 @@ export async function activate(context: ExtensionContext) { Constants.initialize(context); // still do this first. + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + Output.init(context); + DebuggerConfiguration.initialize(context); // Registering the log view as first because it needs to print the requirement log diff --git a/src/services/dashboard/DashboardService.ts b/src/services/dashboard/DashboardService.ts index c406e96b..c89884b7 100644 --- a/src/services/dashboard/DashboardService.ts +++ b/src/services/dashboard/DashboardService.ts @@ -3,6 +3,7 @@ import {Output, OutputLabel} from '@/Output'; import {ChildProcess} from 'child_process'; +import {OutputChannel, window} from 'vscode'; import {Constants, RequiredApps} from '../../Constants'; import {shell, spawnProcess} from '../../helpers'; import {findPid, killPid} from '../../helpers/shell'; @@ -12,6 +13,8 @@ import {isDashboardRunning, waitDashboardStarted} from './DashboardServiceClient export namespace DashboardService { export interface IDashboardProcess { + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + output?: OutputChannel; pid?: number; port: number | string; process?: ChildProcess; @@ -64,6 +67,10 @@ export namespace DashboardService { dashboardProcesses[port] = await spawnDashboardServer(port); } + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + // open the channel to show the output. + dashboardProcesses[port]?.output?.show(false); + Telemetry.sendEvent('DashboardService.waitDashboardStarted.serverStarted'); return dashboardProcesses[port]; @@ -87,15 +94,23 @@ export namespace DashboardService { async function spawnDashboardServer(port: number | string): Promise { const process = spawnProcess(undefined, `${RequiredApps.truffle} ${RequiredApps.dashboard}`, []); - const dashboardProcess = {port, process} as IDashboardProcess; + + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + const output = window.createOutputChannel(`${OutputLabel.dashboardCommands}:${port}`); + + const dashboardProcess = {port, process, output} as IDashboardProcess; + + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + output.show(true); try { - addAllListeners(port, process); + addAllListeners(output, port, process); await waitDashboardStarted(port, Constants.dashboardRetryAttempts); dashboardProcess.pid = await findPid(port); } catch (error) { Telemetry.sendException(error as Error); await stopDashboardProcess(dashboardProcess, true); + await Output.dispose(OutputLabel.dashboardCommands, port.toString()); throw error; } @@ -107,27 +122,34 @@ export namespace DashboardService { return; } - const {pid, port, process} = dashboardProcess; + const {output, pid, port, process} = dashboardProcess; delete dashboardProcesses[port]; - Output.dispose(OutputLabel.dashboardCommands, port.toString()); + await Output.dispose(OutputLabel.dashboardCommands, port.toString()); if (process) { removeAllListeners(process); process.kill('SIGINT'); } + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + if (output) { + output.dispose(); + } + if (pid && (killOutOfBand ? true : !!process)) { return killPid(pid); } } - function addAllListeners(port: number | string, process: ChildProcess): void { + function addAllListeners(output: OutputChannel, port: number | string, process: ChildProcess): void { process.stdout!.on('data', (data: string | Buffer) => { Output.outputLine(OutputLabel.dashboardCommands, data.toString(), port.toString()); + output.appendLine(data.toString()); }); process.stderr!.on('data', (data: string | Buffer) => { Output.outputLine(OutputLabel.dashboardCommands, data.toString(), port.toString()); + output.appendLine(data.toString()); }); process.on('exit', () => { diff --git a/src/services/ganache/GanacheService.ts b/src/services/ganache/GanacheService.ts index 877522c2..91b83ac3 100644 --- a/src/services/ganache/GanacheService.ts +++ b/src/services/ganache/GanacheService.ts @@ -3,6 +3,7 @@ import {Output, OutputLabel} from '@/Output'; import {ChildProcess} from 'child_process'; +import {OutputChannel, window} from 'vscode'; import {Constants, RequiredApps} from '../../Constants'; import {shell, spawnProcess} from '../../helpers'; import {findPid, killPid} from '../../helpers/shell'; @@ -13,6 +14,8 @@ import {isGanacheServer, waitGanacheStarted} from './GanacheServiceClient'; export namespace GanacheService { export interface IGanacheProcess { + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + output?: OutputChannel; pid?: number; port: number | string; process?: ChildProcess; @@ -59,13 +62,17 @@ export namespace GanacheService { if (portStatus === PortStatus.GANACHE) { const pid = await findPid(port); - ganacheProcesses[port] = {pid, port}; + ganacheProcesses[port] = ganacheProcesses[port] ? ganacheProcesses[port] : {pid, port}; } if (portStatus === PortStatus.FREE) { ganacheProcesses[port] = await spawnGanacheServer(port, options); } + + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS // open the channel to show the output. + ganacheProcesses[port]?.output?.show(false); + Telemetry.sendEvent('GanacheServiceClient.waitGanacheStarted.serverStarted'); return ganacheProcesses[port]; } @@ -99,15 +106,23 @@ export namespace GanacheService { } const process = spawnProcess(undefined, 'npx', args); - const ganacheProcess = {port, process} as IGanacheProcess; + + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + const output = window.createOutputChannel(`${OutputLabel.ganacheCommands}:${port}`); + + const ganacheProcess = {port, process, output} as IGanacheProcess; + + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + output.show(true); try { - addAllListeners(port, process); + addAllListeners(output, port, process); await waitGanacheStarted(port, Constants.ganacheRetryAttempts); ganacheProcess.pid = await findPid(port); } catch (error) { Telemetry.sendException(error as Error); await stopGanacheProcess(ganacheProcess, true); + await Output.dispose(OutputLabel.ganacheCommands, port.toString()); throw error; } @@ -119,27 +134,34 @@ export namespace GanacheService { return; } - const {pid, port, process} = ganacheProcess; + const {output, pid, port, process} = ganacheProcess; delete ganacheProcesses[port]; - Output.dispose(OutputLabel.ganacheCommands, port.toString()); + await Output.dispose(OutputLabel.ganacheCommands, port.toString()); if (process) { removeAllListeners(process); process.kill('SIGINT'); } + // INFO: THIS IS THE OLD VERSION OF LOGGER USING OUTPUT CHANNELS + if (output) { + output.dispose(); + } + if (pid && (killOutOfBand ? true : !!process)) { return killPid(pid); } } - function addAllListeners(port: number | string, process: ChildProcess): void { + function addAllListeners(output: OutputChannel, port: number | string, process: ChildProcess): void { process.stdout!.on('data', (data: string | Buffer) => { Output.outputLine(OutputLabel.ganacheCommands, data.toString(), port.toString()); + output.appendLine(data.toString()); }); process.stderr!.on('data', (data: string | Buffer) => { Output.outputLine(OutputLabel.ganacheCommands, data.toString(), port.toString()); + output.appendLine(data.toString()); }); process.on('exit', () => { diff --git a/src/views/LogView.ts b/src/views/LogView.ts index 6e9df971..66f81141 100644 --- a/src/views/LogView.ts +++ b/src/views/LogView.ts @@ -75,6 +75,9 @@ export class LogView implements WebviewViewProvider { * @param description - represents the log description */ public async createLog(label: OutputLabel, message: string, description?: string): Promise { + // Displays the log panel. Unfortunately it doesn't load immediately so we have to wait for the html to load + // this._view?.show?.(true); // `show` is not implemented in 1.49 but is for 1.50 insiders + // Checks if the log panel has already been loaded and is visible if (this._view == null || this._view?.visible === false) { // If it has not yet been loaded, save the log to be executed after loading the log panel @@ -96,7 +99,7 @@ export class LogView implements WebviewViewProvider { */ public async disposeTab(label: OutputLabel, description?: string): Promise { // Displays the log panel. Unfortunately it doesn't load immediately so we have to wait for the html to load - this._view?.show?.(true); // `show` is not implemented in 1.49 but is for 1.50 insiders + // this._view?.show?.(true); // `show` is not implemented in 1.49 but is for 1.50 insiders // Checks if the log panel has already been loaded and is visible if (this._view?.visible === false) { diff --git a/test/commands/GanacheService.test.ts b/test/commands/GanacheService.test.ts index b851e15a..0625451b 100644 --- a/test/commands/GanacheService.test.ts +++ b/test/commands/GanacheService.test.ts @@ -71,7 +71,7 @@ describe('Unit tests GanacheService', () => { }); }); - ['1', '65535', '8454', 8000, 8454].forEach((port) => { + ['1', '65535', 8000, 8454].forEach((port) => { it(`startGanacheServer should pass validation if port is ${port}`, async () => { // Arrange const urlValidatorSpy = sinon.spy(UrlValidator, 'validatePort');