@take-out/scripts 0.0.34 → 0.0.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/ensure-port.ts +97 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@take-out/scripts",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.36",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@take-out/helpers": "0.0.
|
|
27
|
+
"@take-out/helpers": "0.0.36"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"vxrn": "*"
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @description Ensure a port is available, exit with error if in use
|
|
5
|
+
* @args --auto-kill <prefix>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { execSync } from 'node:child_process'
|
|
9
|
+
import { parseArgs } from 'node:util'
|
|
10
|
+
|
|
11
|
+
const { values, positionals } = parseArgs({
|
|
12
|
+
args: process.argv.slice(2),
|
|
13
|
+
options: {
|
|
14
|
+
'auto-kill': {
|
|
15
|
+
type: 'string',
|
|
16
|
+
short: 'k',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
allowPositionals: true,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const port = positionals[0]
|
|
23
|
+
|
|
24
|
+
if (!port) {
|
|
25
|
+
console.error('usage: bun tko ensure-port <port> [--auto-kill <prefix>]')
|
|
26
|
+
process.exit(1)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const portNum = Number.parseInt(port, 10)
|
|
30
|
+
|
|
31
|
+
if (Number.isNaN(portNum) || portNum < 1 || portNum > 65535) {
|
|
32
|
+
console.error(`invalid port: ${port}`)
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getListeningProcess(p: number): { pid?: number; command?: string } {
|
|
37
|
+
try {
|
|
38
|
+
// use -sTCP:LISTEN to only find processes LISTENING on the port (servers)
|
|
39
|
+
// not clients connected to it
|
|
40
|
+
const output = execSync(`lsof -i :${p} -sTCP:LISTEN -t`, {
|
|
41
|
+
encoding: 'utf-8',
|
|
42
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
43
|
+
}).trim()
|
|
44
|
+
|
|
45
|
+
if (!output) return {}
|
|
46
|
+
|
|
47
|
+
const pid = Number.parseInt(output.split('\n')[0] || '', 10)
|
|
48
|
+
if (Number.isNaN(pid)) return {}
|
|
49
|
+
|
|
50
|
+
// get command name
|
|
51
|
+
const ps = execSync(`ps -p ${pid} -o comm=`, {
|
|
52
|
+
encoding: 'utf-8',
|
|
53
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
54
|
+
}).trim()
|
|
55
|
+
|
|
56
|
+
return { pid, command: ps }
|
|
57
|
+
} catch {
|
|
58
|
+
return {}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function killProcess(pid: number): boolean {
|
|
63
|
+
try {
|
|
64
|
+
execSync(`kill ${pid}`, { stdio: 'ignore' })
|
|
65
|
+
return true
|
|
66
|
+
} catch {
|
|
67
|
+
return false
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const { pid, command } = getListeningProcess(portNum)
|
|
72
|
+
|
|
73
|
+
if (pid) {
|
|
74
|
+
const autoKillPrefix = values['auto-kill']
|
|
75
|
+
|
|
76
|
+
// check if we should auto-kill this process
|
|
77
|
+
if (autoKillPrefix && command?.startsWith(autoKillPrefix)) {
|
|
78
|
+
console.info(`killing ${command} (pid ${pid}) on port ${portNum}`)
|
|
79
|
+
if (killProcess(pid)) {
|
|
80
|
+
// give it a moment to release the port
|
|
81
|
+
Bun.sleepSync(100)
|
|
82
|
+
// verify it's gone
|
|
83
|
+
const check = getListeningProcess(portNum)
|
|
84
|
+
if (!check.pid) {
|
|
85
|
+
process.exit(0)
|
|
86
|
+
}
|
|
87
|
+
console.error(`failed to free port ${portNum}`)
|
|
88
|
+
process.exit(1)
|
|
89
|
+
}
|
|
90
|
+
console.error(`failed to kill pid ${pid}`)
|
|
91
|
+
process.exit(1)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.error(`port ${portNum} in use by ${command || 'unknown'} (pid ${pid})`)
|
|
95
|
+
console.error(`run: kill ${pid}`)
|
|
96
|
+
process.exit(1)
|
|
97
|
+
}
|