Skip to content

Commit 0b54c98

Browse files
authored
introduce socket-npm and socket-npx
1 parent 1ebd997 commit 0b54c98

File tree

13 files changed

+1221
-4
lines changed

13 files changed

+1221
-4
lines changed

.eslintrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
"parserOptions": {
77
"project": "./tsconfig.json"
88
},
9+
"ignorePatterns": [
10+
"lib/shadow/bin"
11+
],
912
"rules": {
1013
"@typescript-eslint/quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": false }],
1114
"no-console": "warn"

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
/.nyc_output
77
/.vscode
88

9+
/lib/shadow/bin
10+
911
# We're a library, so please, no lock files
1012
/package-lock.json
1113
/yarn.lock

lib/commands/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
export * from './info/index.js'
22
export * from './report/index.js'
3+
export * from './npm/index.js'
4+
export * from './npx/index.js'

lib/commands/npm/index.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { spawn } from 'child_process'
2+
import { fileURLToPath } from 'url'
3+
4+
const description = 'npm wrapper functionality'
5+
6+
/** @type {import('../../utils/meow-with-subcommands').CliSubcommand} */
7+
export const npm = {
8+
description,
9+
run: async (argv, _importMeta, _ctx) => {
10+
const wrapperPath = fileURLToPath(new URL('../../shadow/npm-cli.cjs', import.meta.url))
11+
process.exitCode = 1
12+
spawn(process.execPath, [wrapperPath, ...argv], {
13+
stdio: 'inherit'
14+
}).on('exit', (code, signal) => {
15+
if (signal) {
16+
process.kill(process.pid, signal)
17+
} else if (code !== null) {
18+
process.exit(code)
19+
}
20+
})
21+
}
22+
}

lib/commands/npx/index.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { spawn } from 'child_process'
2+
import { fileURLToPath } from 'url'
3+
4+
const description = 'npx wrapper functionality'
5+
6+
/** @type {import('../../utils/meow-with-subcommands').CliSubcommand} */
7+
export const npx = {
8+
description,
9+
run: async (argv, _importMeta, _ctx) => {
10+
const wrapperPath = fileURLToPath(new URL('../../shadow/npx-cli.cjs', import.meta.url))
11+
process.exitCode = 1
12+
spawn(process.execPath, [wrapperPath, ...argv], {
13+
stdio: 'inherit'
14+
}).on('exit', (code, signal) => {
15+
if (signal) {
16+
process.kill(process.pid, signal)
17+
} else if (code !== null) {
18+
process.exit(code)
19+
}
20+
})
21+
}
22+
}

lib/shadow/link.cjs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* eslint-disable no-console */
2+
const { chmodSync, realpathSync } = require('fs')
3+
const path = require('path')
4+
5+
const which = require('which')
6+
7+
/**
8+
* @param {string} realDirname path to shadow/bin
9+
* @param {'npm' | 'npx'} binname
10+
* @returns {string} path to npm provided cli / npx bin
11+
*/
12+
function installLinks (realDirname, binname) {
13+
const realNpmShadowBinDir = realDirname
14+
// find npm being shadowed by this process
15+
const npms = which.sync(binname, {
16+
all: true
17+
})
18+
let shadowIndex = -1
19+
const npmpath = npms.find((npmPath, i) => {
20+
const isShadow = realpathSync(path.dirname(npmPath)) === realNpmShadowBinDir
21+
if (isShadow) {
22+
shadowIndex = i
23+
}
24+
return !isShadow
25+
})
26+
if (!npmpath) {
27+
console.error('Socket unable to locate npm ensure it is available in the PATH environment variable')
28+
process.exit(127)
29+
}
30+
if (shadowIndex === -1) {
31+
chmodSync(realNpmShadowBinDir, parseInt('755', 8))
32+
const bindir = path.join(realDirname)
33+
process.env['PATH'] = `${
34+
bindir
35+
}${
36+
process.platform === 'win32' ? ';' : ':'
37+
}${
38+
process.env['PATH']
39+
}`
40+
}
41+
return npmpath
42+
}
43+
module.exports = installLinks

lib/shadow/npm-cli.cjs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env node
2+
// THIS FILE USES .cjs to get around the extension-free entrypoint problem with ESM
3+
'use strict'
4+
const { spawn } = require('child_process')
5+
const { realpathSync } = require('fs')
6+
const path = require('path')
7+
8+
const realFilename = realpathSync(__filename)
9+
const realDirname = path.dirname(realFilename)
10+
11+
/**
12+
*/
13+
async function main () {
14+
const npmpath = await require('./link.cjs')(path.join(realDirname, 'bin'), 'npm')
15+
process.exitCode = 1
16+
const injectionpath = path.join(realDirname, 'npm-injection.cjs')
17+
spawn(process.execPath, ['--require', injectionpath, npmpath, ...process.argv.slice(2)], {
18+
stdio: 'inherit'
19+
}).on('exit', (code, signal) => {
20+
if (signal) {
21+
process.kill(process.pid, signal)
22+
} else if (code !== null) {
23+
process.exit(code)
24+
}
25+
})
26+
}
27+
main()

0 commit comments

Comments
 (0)