%PDF- %PDF-
| Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/npm/test/fixtures/ |
| Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/npm/test/fixtures/sandbox.js |
const { createHook, executionAsyncId } = require('async_hooks')
const { EventEmitter } = require('events')
const { homedir, tmpdir } = require('os')
const { dirname, join } = require('path')
const { mkdir, rm } = require('fs/promises')
const mockLogs = require('./mock-logs')
const pkg = require('../../package.json')
const chain = new Map()
const sandboxes = new Map()
// keep a reference to the real process
const _process = process
createHook({
init: (asyncId, type, triggerAsyncId, resource) => {
// track parentage of asyncIds
chain.set(asyncId, triggerAsyncId)
},
before: (asyncId) => {
// find the nearest parent id that has a sandbox
let parent = asyncId
while (chain.has(parent) && !sandboxes.has(parent)) {
parent = chain.get(parent)
}
process = sandboxes.has(parent)
? sandboxes.get(parent)
: _process
},
}).enable()
const _data = Symbol('sandbox.data')
const _dirs = Symbol('sandbox.dirs')
const _test = Symbol('sandbox.test')
const _mocks = Symbol('sandbox.mocks')
const _npm = Symbol('sandbox.npm')
const _parent = Symbol('sandbox.parent')
const _output = Symbol('sandbox.output')
const _proxy = Symbol('sandbox.proxy')
const _get = Symbol('sandbox.proxy.get')
const _set = Symbol('sandbox.proxy.set')
const _logs = Symbol('sandbox.logs')
// we can't just replace these values everywhere because they're known to be
// very short strings that could be present all over the place, so we only
// replace them if they're located within quotes for now
const vagueRedactedDefaults = [
'editor',
'shell',
]
const normalize = (str) => str
.replace(/\r\n/g, '\n') // normalize line endings (for ini)
.replace(/[A-z]:\\/g, '\\') // turn windows roots to posix ones
.replace(/\\+/g, '/') // replace \ with /
class Sandbox extends EventEmitter {
constructor (test, options = {}) {
super()
this[_test] = test
this[_mocks] = options.mocks || {}
this[_data] = new Map()
this[_output] = []
const tempDir = `${test.testdirName}-sandbox`
this[_dirs] = {
temp: tempDir,
global: options.global || join(tempDir, 'global'),
home: options.home || join(tempDir, 'home'),
project: options.project || join(tempDir, 'project'),
cache: options.cache || join(tempDir, 'cache'),
}
this[_proxy] = new Proxy(_process, {
get: this[_get].bind(this),
set: this[_set].bind(this),
})
this[_proxy].env = { ...options.env }
this[_proxy].argv = []
test.cleanSnapshot = this.cleanSnapshot.bind(this)
test.afterEach(() => this.reset())
test.teardown(() => this.teardown())
}
get config () {
return this[_npm] && this[_npm].config
}
get logs () {
return this[_logs]
}
get global () {
return this[_dirs].global
}
get home () {
return this[_dirs].home
}
get project () {
return this[_dirs].project
}
get cache () {
return this[_dirs].cache
}
get process () {
return this[_proxy]
}
get output () {
return this[_output].map((line) => line.join(' ')).join('\n')
}
cleanSnapshot (snapshot) {
let clean = normalize(snapshot)
const viewer = _process.platform === 'win32'
? /"browser"([^:]+|$)/g
: /"man"([^:]+|$)/g
// the global prefix is platform dependent
const realGlobalPrefix = _process.platform === 'win32'
? dirname(_process.execPath)
: dirname(dirname(_process.execPath))
const cache = _process.platform === 'win32'
? /\{HOME\}\/npm-cache(\r?\n|"|\/|$)/g
: /\{HOME\}\/\.npm(\n|"|\/|$)/g
// and finally replace some paths we know could be present
clean = clean
.replace(viewer, '"{VIEWER}"$1')
.split(normalize(this[_proxy].execPath)).join('{EXECPATH}')
.split(normalize(_process.execPath)).join('{REALEXECPATH}')
.split(normalize(this.global)).join('{GLOBALPREFIX}')
.split(normalize(realGlobalPrefix)).join('{REALGLOBALREFIX}')
.split(normalize(this.project)).join('{LOCALPREFIX}')
.split(normalize(this.home)).join('{HOME}')
.replace(cache, '{CACHE}$1')
.split(normalize(dirname(dirname(__dirname)))).join('{NPMDIR}')
.split(normalize(tmpdir())).join('{TMP}')
.split(normalize(homedir())).join('{REALHOME}')
.split(this[_proxy].platform).join('{PLATFORM}')
.split(this[_proxy].arch).join('{ARCH}')
.replace(new RegExp(process.version, 'g'), '{NODE-VERSION}')
.replace(new RegExp(pkg.version, 'g'), '{NPM-VERSION}')
// We do the defaults after everything else so that they don't cause the
// other cleaners to miss values we would have clobbered here. For
// instance if execPath is /home/user/.nvm/versions/node/1.0.0/bin/node,
// and we replaced the node version first, the real execPath we're trying
// to replace would no longer be represented, and be missed.
if (this[_npm]) {
// replace vague default config values that are present within quotes
// with placeholders
for (const name of vagueRedactedDefaults) {
const value = this[_npm].config.defaults[name]
clean = clean.split(`"${normalize(value)}"`).join(`"{${name.toUpperCase()}}"`)
}
}
return clean
}
// test.afterEach hook
reset () {
this.removeAllListeners()
this[_parent] = undefined
this[_output] = []
this[_data].clear()
this[_proxy].env = {}
this[_proxy].argv = []
this[_npm] = undefined
}
// test.teardown hook
teardown () {
if (this[_parent]) {
const sandboxProcess = sandboxes.get(this[_parent])
sandboxProcess.removeAllListeners('log')
sandboxes.delete(this[_parent])
}
if (this[_npm]) {
this[_npm].unload()
}
return rm(this[_dirs].temp, { recursive: true, force: true }).catch(() => null)
}
// proxy get handler
[_get] (target, prop, receiver) {
if (this[_data].has(prop)) {
return this[_data].get(prop)
}
if (this[prop] !== undefined) {
return Reflect.get(this, prop, this)
}
return Reflect.get(target, prop, receiver)
}
// proxy set handler
[_set] (target, prop, value) {
if (prop === 'env') {
value = {
...value,
HOME: this.home,
}
}
if (prop === 'argv') {
value = [
process.execPath,
join(dirname(process.execPath), 'npm'),
...value,
]
}
return this[_data].set(prop, value)
}
async run (command, argv = []) {
await Promise.all([
mkdir(this.project, { recursive: true }),
mkdir(this.home, { recursive: true }),
mkdir(this.global, { recursive: true }),
])
// attach the sandbox process now, doing it after the promise above is
// necessary to make sure that only async calls spawned as part of this
// call to run will receive the sandbox. if we attach it too early, we
// end up interfering with tap
this[_parent] = executionAsyncId()
this[_data].set('_asyncId', this[_parent])
sandboxes.set(this[_parent], this[_proxy])
process = this[_proxy]
this[_proxy].argv = [
'--prefix', this.project,
'--userconfig', join(this.home, '.npmrc'),
'--globalconfig', join(this.global, 'npmrc'),
'--cache', this.cache,
command,
...argv,
]
const mockedLogs = mockLogs(this[_mocks])
this[_logs] = mockedLogs.logs
const definitions = this[_test].mock('@npmcli/config/lib/definitions')
const Npm = this[_test].mock('../../lib/npm.js', {
'@npmcli/config/lib/definitions': definitions,
'../../lib/utils/update-notifier.js': async () => {},
...this[_mocks],
...mockedLogs.logMocks,
})
this.process.on('log', (l, ...args) => {
if (l !== 'pause' && l !== 'resume') {
this[_logs].push([l, ...args])
}
})
this[_npm] = new Npm()
this[_npm].output = (...args) => this[_output].push(args)
await this[_npm].load()
const cmd = this[_npm].argv.shift()
return this[_npm].exec(cmd, this[_npm].argv)
}
async complete (command, argv, partial) {
if (!Array.isArray(argv)) {
partial = argv
argv = []
}
await Promise.all([
mkdir(this.project, { recursive: true }),
mkdir(this.home, { recursive: true }),
mkdir(this.global, { recursive: true }),
])
// attach the sandbox process now, doing it after the promise above is
// necessary to make sure that only async calls spawned as part of this
// call to run will receive the sandbox. if we attach it too early, we
// end up interfering with tap
this[_parent] = executionAsyncId()
this[_data].set('_asyncId', this[_parent])
sandboxes.set(this[_parent], this[_proxy])
process = this[_proxy]
this[_proxy].argv = [
'--prefix', this.project,
'--userconfig', join(this.home, '.npmrc'),
'--globalconfig', join(this.global, 'npmrc'),
'--cache', this.cache,
command,
...argv,
]
const mockedLogs = mockLogs(this[_mocks])
this[_logs] = mockedLogs.logs
const definitions = this[_test].mock('@npmcli/config/lib/definitions')
const Npm = this[_test].mock('../../lib/npm.js', {
'@npmcli/config/lib/definitions': definitions,
'../../lib/utils/update-notifier.js': async () => {},
...this[_mocks],
...mockedLogs.logMocks,
})
this.process.on('log', (l, ...args) => {
if (l !== 'pause' && l !== 'resume') {
this[_logs].push([l, ...args])
}
})
this[_npm] = new Npm()
this[_npm].output = (...args) => this[_output].push(args)
await this[_npm].load()
const Cmd = Npm.cmd(command)
return Cmd.completion({
partialWord: partial,
conf: {
argv: {
remain: ['npm', command, ...argv],
},
},
})
}
}
module.exports = Sandbox