Skip to content

Commit 946b9ec

Browse files
vinnymacKyleAMathews
authored andcommitted
Closes #569 Add port process conflict resolution and Chalk (#579)
* add some chalk to gatsby * #569 add port process conflict resolution * fix lint for chalk * use a dependency that includes getProcessForPort * remove other react-dev-utils * bring getProcessForPort into source, fix formatting
1 parent 39b7273 commit 946b9ec

File tree

4 files changed

+83
-8
lines changed

4 files changed

+83
-8
lines changed

lib/utils/develop.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import opn from 'opn'
1515
import fs from 'fs'
1616
import glob from 'glob'
1717
import rl from 'readline'
18+
import chalk from 'chalk'
19+
import getProcessForPort from './getProcessForPort'
1820

1921
const rlInterface = rl.createInterface({
2022
input: process.stdin,
@@ -181,17 +183,21 @@ function startServer (program) {
181183
if (e) {
182184
if (e.code === 'EADDRINUSE') {
183185
// eslint-disable-next-line max-len
184-
console.log(`Unable to start Gatsby on port ${program.port} as there's already a process listing on that port.`)
186+
console.log(chalk.red(`Unable to start Gatsby on port ${program.port} as there's already a process listing on that port.`))
185187
} else {
186-
console.log(e)
188+
console.log(chalk.red(e))
187189
}
188190

189191
process.exit()
190192
} else {
191193
if (program.open) {
192194
opn(server.info.uri)
193195
}
194-
console.log('Listening at:', server.info.uri)
196+
console.log(chalk.green('Server started successfully!'))
197+
console.log()
198+
console.log('Listening at:')
199+
console.log()
200+
console.log(' ', chalk.cyan(server.info.uri))
195201
}
196202
})
197203
})
@@ -204,6 +210,8 @@ module.exports = (program) => {
204210
? parseInt(program.port, 10)
205211
: program.port
206212

213+
const existingProcess = getProcessForPort(port)
214+
207215
detect(port, (err, _port) => {
208216
if (err) {
209217
console.error(err)
@@ -212,7 +220,7 @@ module.exports = (program) => {
212220

213221
if (port !== _port) {
214222
// eslint-disable-next-line max-len
215-
const question = `Something is already running at port ${port} \nWould you like to run the app at another port instead? [Y/n] `
223+
const question = chalk.yellow(`Something is already running on port ${port}.\n${(existingProcess) ? ` Probably:\n ${existingProcess}\n` : ''}\nWould you like to run the app at another port instead? [Y/n]`)
216224

217225
return rlInterface.question(question, (answer) => {
218226
if (answer.length === 0 || answer.match(/^yes|y$/i)) {

lib/utils/getProcessForPort.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import chalk from 'chalk'
2+
import { execSync } from 'child_process'
3+
import path from 'path'
4+
5+
const execOptions = {
6+
encoding: 'utf8',
7+
stdio: [
8+
'pipe', // stdin (default)
9+
'pipe', // stdout (default)
10+
'ignore', // stderr
11+
],
12+
}
13+
14+
function isProcessAReactApp (processCommand) {
15+
return /^node .*react-scripts\/scripts\/start\.js\s?$/.test(processCommand)
16+
}
17+
18+
function getProcessIdOnPort (port) {
19+
return execSync(`lsof -i:${port} -P -t -sTCP:LISTEN`, execOptions).trim()
20+
}
21+
22+
function getPackageNameInDirectory (directory) {
23+
const packagePath = path.join(directory.trim(), 'package.json')
24+
25+
try {
26+
return require(packagePath).name
27+
} catch (e) {
28+
return null
29+
}
30+
}
31+
32+
function getProcessCommand (processId, processDirectory) {
33+
const command = execSync(`ps -o command -p ${processId} | sed -n 2p`, execOptions)
34+
35+
if (isProcessAReactApp(command)) {
36+
const packageName = getPackageNameInDirectory(processDirectory)
37+
return (packageName) ? '${packageName}\n' : command
38+
} else {
39+
return command
40+
}
41+
}
42+
43+
function getDirectoryOfProcessById (processId) {
44+
return execSync(`lsof -p ${processId} | grep cwd | awk \'{print $9}\'`, execOptions).trim()
45+
}
46+
47+
function getProcessForPort (port) {
48+
try {
49+
const processId = getProcessIdOnPort(port)
50+
const directory = getDirectoryOfProcessById(processId)
51+
const command = getProcessCommand(processId, directory)
52+
return chalk.cyan(command) + chalk.blue(' in ') + chalk.cyan(directory)
53+
} catch (e) {
54+
return null
55+
}
56+
}
57+
58+
module.exports = getProcessForPort

lib/utils/serve-build.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import detect from 'detect-port'
33
import Hapi from 'hapi'
44
import opn from 'opn'
55
import rl from 'readline'
6+
import chalk from 'chalk'
7+
import getProcessForPort from './getProcessForPort'
68

79
const rlInterface = rl.createInterface({
810
input: process.stdin,
@@ -40,22 +42,28 @@ function startServer (program, launchPort) {
4042
if (e) {
4143
if (e.code === 'EADDRINUSE') {
4244
// eslint-disable-next-line max-len
43-
console.log(`Unable to start Gatsby on port ${serverPort} as there's already a process listing on that port.`)
45+
console.log(chalk.red(`Unable to start Gatsby on port ${serverPort} as there's already a process listing on that port.`))
4446
} else {
45-
console.log(e)
47+
console.log(chalk.red(e))
4648
}
4749

4850
process.exit()
4951
} else {
5052
if (program.open) {
5153
opn(server.info.uri)
5254
}
53-
console.log('Listening at:', server.info.uri)
55+
console.log(chalk.green('Server started successfully!'))
56+
console.log()
57+
console.log('Listening at:')
58+
console.log()
59+
console.log(' ', chalk.cyan(server.info.uri))
5460
}
5561
})
5662
}
5763

5864
module.exports = (program) => {
65+
const existingProcess = getProcessForPort(program.port)
66+
5967
detect(program.port, (err, _port) => {
6068
if (err) {
6169
console.error(err)
@@ -64,7 +72,7 @@ module.exports = (program) => {
6472

6573
if (program.port !== _port) {
6674
// eslint-disable-next-line max-len
67-
const question = `Something is already running at port ${program.port} \nWould you like to run the app at another port instead? [Y/n] `
75+
const question = chalk.yellow(`Something is already running on port ${program.port}.\n${(existingProcess) ? ` Probably:\n ${existingProcess}\n` : ''}\nWould you like to run the app at another port instead? [Y/n]`)
6876

6977
return rlInterface.question(question, (answer) => {
7078
let launchPort = program.port

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"babel-plugin-transform-flow-strip-types": "^6.8.0",
9797
"babel-register": "^6.11.6",
9898
"bluebird": "^3.4.1",
99+
"chalk": "^1.1.3",
99100
"cheerio": "^0.20.0",
100101
"eslint": "^2.11.1",
101102
"eslint-config-airbnb": "^9.0.1",

0 commit comments

Comments
 (0)