From 81f8fe9f7735ed2878a583bf0edebc63680d1eb4 Mon Sep 17 00:00:00 2001 From: David First Date: Mon, 4 Nov 2024 15:45:29 -0500 Subject: [PATCH] improve suggestion when server-forever is unable to use the port --- scopes/harmony/bit/server-forever.ts | 63 ++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/scopes/harmony/bit/server-forever.ts b/scopes/harmony/bit/server-forever.ts index d74d989a2b12..04cd12391f9b 100644 --- a/scopes/harmony/bit/server-forever.ts +++ b/scopes/harmony/bit/server-forever.ts @@ -9,6 +9,7 @@ import net from 'net'; import crypto from 'crypto'; +import { execSync } from 'child_process'; import { spawn } from '@lydell/node-pty'; export function spawnPTY() { @@ -79,15 +80,18 @@ export function spawnPTY() { server.on('error', (err: any) => { if (err.code === 'EADDRINUSE') { - console.error(`Error: Port ${PORT} is already in use.`); - console.error(`This port is assigned based on the workspace path: '${process.cwd()}'`); - console.error(`This means another instance may already be running in this workspace.`); - console.error(`\nTo resolve this issue:`); - console.error(`- If another instance is running, please stop it before starting a new one.`); - console.error(`- If no other instance is running, the port may be occupied by another application.`); - console.error( - ` You can override the default port by setting the 'BIT_CLI_SERVER_SOCKET_PORT' environment variable.` - ); + const pid = getPidByPort(PORT); + const usedByPid = pid ? ` (used by PID ${pid})` : ''; + const killCmd = pid ? `\nAlternatively, you can kill the process by running "kill ${pid}".` : ''; + console.error(`Error: Port ${PORT} is already in use${usedByPid}. +This port is assigned based on the workspace path: '${process.cwd()}' +This means another instance may already be running in this workspace. +\nTo resolve this issue: +- If another instance is running, please stop it before starting a new one. + If a vscode is open on this workspace, it might be running the server. Close it.${killCmd} +- If no other instance is running, the port may be occupied by another application. + You can override the default port by setting the 'BIT_CLI_SERVER_SOCKET_PORT' environment variable. +`); process.exit(1); // Exit the process with an error code } else { console.error('Server encountered an error:', err); @@ -140,3 +144,44 @@ export function getPortFromPath(path: string): number { return port; } + +function getPidByPort(port: number): string | null { + const platform = process.platform; + try { + if (platform === 'darwin' || platform === 'linux') { + // For macOS and Linux + const cmd = `lsof -iTCP:${port} -sTCP:LISTEN -n -P`; + const stdout = execSync(cmd).toString(); + const lines = stdout.trim().split('\n'); + + if (lines.length > 1) { + // Skip the header line and parse the first result + const columns = lines[1].split(/\s+/); + const pid = columns[1]; + return pid; + } + } else if (platform === 'win32') { + // For Windows + const cmd = `netstat -ano -p tcp`; + const stdout = execSync(cmd).toString(); + const lines = stdout.trim().split('\n'); + + for (const line of lines) { + if (line.trim().startsWith('TCP')) { + const columns = line.trim().split(/\s+/); + const localAddress = columns[1]; + const pid = columns[4]; + + if (localAddress.endsWith(`:${port}`)) { + return pid; + } + } + } + } else { + console.error('Unsupported platform:', platform); + } + } catch (error: any) { + console.error('Error executing command:', error.message); + } + return null; +}