tsoa
This commit is contained in:
574
node_modules/@scarf/scarf/report.js
generated
vendored
Normal file
574
node_modules/@scarf/scarf/report.js
generated
vendored
Normal file
@@ -0,0 +1,574 @@
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
const exec = require('child_process').exec
|
||||
const localDevPort = process.env.SCARF_LOCAL_PORT
|
||||
const https = localDevPort ? require('http') : require('https')
|
||||
const fs = require('fs')
|
||||
const fsAsync = fs.promises
|
||||
const util = require('util')
|
||||
|
||||
const scarfHost = localDevPort ? 'localhost' : 'scarf.sh'
|
||||
const scarfLibName = '@scarf/scarf'
|
||||
const privatePackageRewrite = '@private/private'
|
||||
const privateVersionRewrite = '0'
|
||||
|
||||
const rootPath = process.env.INIT_CWD
|
||||
|
||||
// Pulled into a function for test mocking
|
||||
function tmpFileName () {
|
||||
// throttle per user
|
||||
const username = os.userInfo().username
|
||||
return path.join(os.tmpdir(), `scarf-js-history-${username}.log`)
|
||||
}
|
||||
|
||||
// Pulled into a function for test mocking
|
||||
function dirName () {
|
||||
return __dirname
|
||||
}
|
||||
|
||||
function npmExecPath () {
|
||||
return process.env.npm_execpath
|
||||
}
|
||||
|
||||
const userMessageThrottleTime = 1000 * 60 // 1 minute
|
||||
|
||||
const execTimeout = 3000
|
||||
|
||||
// In general, these keys should never change to remain backwards compatible
|
||||
// with previous versions of Scarf. If we need to update them, we'll need to
|
||||
// make sure we can read the previous values as well
|
||||
const optedInLogRateLimitKey = 'optedInLastLog'
|
||||
const optedOutLogRateLimitKey = 'optedOutLastLog'
|
||||
|
||||
const makeDefaultSettings = () => {
|
||||
return {
|
||||
defaultOptIn: true
|
||||
}
|
||||
}
|
||||
|
||||
function logIfVerbose (toLog, stream) {
|
||||
if (process.env.SCARF_VERBOSE === 'true') {
|
||||
(stream || console.log)(toLog)
|
||||
}
|
||||
}
|
||||
|
||||
// SCARF_NO_ANALYTICS was the original variable, we'll get rid of it eventually
|
||||
const userHasOptedOut = (rootPackage) => {
|
||||
return (rootPackage && rootPackage.scarfSettings && rootPackage.scarfSettings.enabled === false) ||
|
||||
(process.env.SCARF_ANALYTICS === 'false' || process.env.SCARF_NO_ANALYTICS === 'true' || process.env.DO_NOT_TRACK === '1')
|
||||
}
|
||||
|
||||
const userHasOptedIn = (rootPackage) => {
|
||||
return (rootPackage && rootPackage.scarfSettings && rootPackage.scarfSettings.enabled) || process.env.SCARF_ANALYTICS === 'true'
|
||||
}
|
||||
|
||||
// Packages that depend on Scarf can configure whether to should fire when
|
||||
// `npm install` is being run directly from within the package, rather than from a
|
||||
// dependent package
|
||||
function allowTopLevel (rootPackage) {
|
||||
return rootPackage && rootPackage.scarfSettings && rootPackage.scarfSettings.allowTopLevel
|
||||
}
|
||||
|
||||
function skipTraversal (rootPackage) {
|
||||
return rootPackage && rootPackage.scarfSettings && rootPackage.scarfSettings.skipTraversal
|
||||
}
|
||||
|
||||
function parentIsRoot (dependencyToReport) {
|
||||
const parent = dependencyToReport.parent
|
||||
const rootPackage = dependencyToReport.rootPackage
|
||||
|
||||
return parent && rootPackage && parent.name === rootPackage.name && parent.version === rootPackage.version
|
||||
}
|
||||
|
||||
function isTopLevel (dependencyToReport) {
|
||||
return parentIsRoot(dependencyToReport) && !process.env.npm_config_global
|
||||
}
|
||||
|
||||
function isGlobal (dependencyToReport) {
|
||||
return parentIsRoot(dependencyToReport) && !!process.env.npm_config_global
|
||||
}
|
||||
|
||||
function hashWithDefault (toHash, defaultReturn) {
|
||||
let crypto
|
||||
try {
|
||||
crypto = require('crypto')
|
||||
} catch (err) {
|
||||
logIfVerbose('node crypto module unavailable')
|
||||
}
|
||||
|
||||
if (crypto && toHash) {
|
||||
return crypto.createHash('sha256').update(toHash, 'utf-8').digest('hex')
|
||||
} else {
|
||||
return defaultReturn
|
||||
}
|
||||
}
|
||||
|
||||
// We don't send any paths, hash package names and versions
|
||||
function redactSensitivePackageInfo (dependencyInfo) {
|
||||
if (dependencyInfo.grandparent && dependencyInfo.grandparent.name) {
|
||||
dependencyInfo.grandparent.nameHash = hashWithDefault(dependencyInfo.grandparent.name, privatePackageRewrite)
|
||||
dependencyInfo.grandparent.versionHash = hashWithDefault(dependencyInfo.grandparent.version, privateVersionRewrite)
|
||||
}
|
||||
|
||||
if (dependencyInfo.rootPackage && dependencyInfo.rootPackage.name) {
|
||||
dependencyInfo.rootPackage.nameHash = hashWithDefault(dependencyInfo.rootPackage.name, privatePackageRewrite)
|
||||
dependencyInfo.rootPackage.versionHash = hashWithDefault(dependencyInfo.rootPackage.version, privateVersionRewrite)
|
||||
}
|
||||
|
||||
delete (dependencyInfo.rootPackage.packageJsonPath)
|
||||
delete (dependencyInfo.rootPackage.path)
|
||||
delete (dependencyInfo.rootPackage.name)
|
||||
delete (dependencyInfo.rootPackage.version)
|
||||
delete (dependencyInfo.parent.path)
|
||||
delete (dependencyInfo.scarf.path)
|
||||
if (dependencyInfo.grandparent) {
|
||||
delete (dependencyInfo.grandparent.path)
|
||||
delete (dependencyInfo.grandparent.name)
|
||||
delete (dependencyInfo.grandparent.version)
|
||||
}
|
||||
return dependencyInfo
|
||||
}
|
||||
|
||||
/*
|
||||
Scarf-js is automatically disabled when being run inside of a yarn install.
|
||||
The `npm_execpath` environment variable tells us which package manager is
|
||||
running our install
|
||||
*/
|
||||
function isYarn () {
|
||||
const execPath = module.exports.npmExecPath() || ''
|
||||
return ['yarn', 'yarn.js', 'yarnpkg', 'yarn.cmd', 'yarnpkg.cmd']
|
||||
.some(packageManBinName => execPath.endsWith(packageManBinName))
|
||||
}
|
||||
|
||||
function processDependencyTreeOutput (resolve, reject) {
|
||||
return function (error, stdout, stderr) {
|
||||
if (error && !stdout) {
|
||||
return reject(new Error(`Scarf received an error from npm -ls: ${error} | ${stderr}`))
|
||||
}
|
||||
|
||||
try {
|
||||
const output = JSON.parse(stdout)
|
||||
|
||||
const depsToScarf = findScarfInFullDependencyTree(output).filter(depChain => depChain.length >= 2)
|
||||
if (!depsToScarf.length) {
|
||||
return reject(new Error('No Scarf parent package found'))
|
||||
}
|
||||
const rootPackageDetails = rootPackageDepInfo(output)
|
||||
|
||||
const dependencyInfo = depsToScarf.map(depChain => {
|
||||
return {
|
||||
scarf: depChain[depChain.length - 1],
|
||||
parent: depChain[depChain.length - 2],
|
||||
grandparent: depChain[depChain.length - 3],
|
||||
rootPackage: rootPackageDetails,
|
||||
anyInChainDisabled: depChain.some(dep => {
|
||||
return (dep.scarfSettings || {}).enabled === false
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
dependencyInfo.forEach(d => {
|
||||
d.parent.scarfSettings = Object.assign(makeDefaultSettings(), d.parent.scarfSettings || {})
|
||||
})
|
||||
|
||||
// Here, we find the dependency chain that corresponds to the scarf package we're currently in
|
||||
const dependencyToReport = dependencyInfo.find(dep => (dep.scarf.path === module.exports.dirName())) || dependencyInfo[0]
|
||||
if (!dependencyToReport) {
|
||||
return reject(new Error(`Couldn't find dependency info for path ${module.exports.dirName()}`))
|
||||
}
|
||||
|
||||
// If any intermediate dependency in the chain of deps that leads to scarf
|
||||
// has disabled Scarf, we must respect that setting unless the user overrides it.
|
||||
if (dependencyToReport.anyInChainDisabled && !userHasOptedIn(dependencyToReport.rootPackage)) {
|
||||
return reject(new Error('Scarf has been disabled via a package.json in the dependency chain.'))
|
||||
}
|
||||
|
||||
if (isTopLevel(dependencyToReport) && !isGlobal(dependencyToReport) && !allowTopLevel(rootPackageDetails)) {
|
||||
return reject(new Error('The package depending on Scarf is the root package being installed, but Scarf is not configured to run in this case. To enable it, set `scarfSettings.allowTopLevel = true` in your package.json'))
|
||||
}
|
||||
|
||||
return resolve(dependencyToReport)
|
||||
} catch (err) {
|
||||
logIfVerbose(err, console.error)
|
||||
return reject(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processGitRevParseOutput (resolve, reject) {
|
||||
return function (error, stdout, stderr) {
|
||||
if (error && !stdout) {
|
||||
return reject(new Error(`Scarf received an error from git rev-parse: ${error} | ${stderr}`))
|
||||
}
|
||||
|
||||
const output = String(stdout).trim()
|
||||
|
||||
if (output.length > 0) {
|
||||
return resolve(output)
|
||||
} else {
|
||||
return reject(new Error('Scarf did not receive usable output from git rev-parse'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// packageJSONOverride: a test convenience to set a packageJSON explicitly.
|
||||
// Leave empty to use the actual root package.json.
|
||||
async function getDependencyInfo (packageJSONOverride) {
|
||||
try {
|
||||
const rootPackageJSON = require(packageJSONOverride || path.join(rootPath, 'package.json'))
|
||||
const scarfPackageJSON = require(path.join(dirName(), 'package.json'))
|
||||
|
||||
if (skipTraversal(rootPackageJSON)) {
|
||||
logIfVerbose('skipping dependency tree traversal')
|
||||
const rootInfoToReport = {
|
||||
name: rootPackageJSON.name,
|
||||
version: rootPackageJSON.version,
|
||||
scarfSettings: { ...makeDefaultSettings(), ...rootPackageJSON.scarfSettings }
|
||||
}
|
||||
const shallowDepInfo = {
|
||||
scarf: { name: '@scarf/scarf', version: scarfPackageJSON.version },
|
||||
parent: { ...rootInfoToReport },
|
||||
rootPackage: { ...rootInfoToReport },
|
||||
anyInChainDisabled: false,
|
||||
skippedTraversal: true
|
||||
}
|
||||
logIfVerbose(util.inspect(shallowDepInfo))
|
||||
return shallowDepInfo
|
||||
}
|
||||
} catch (err) {
|
||||
logIfVerbose(err, console.error)
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(`cd ${rootPath} && npm ls @scarf/scarf --json --long`, { timeout: execTimeout, maxBuffer: 1024 * 1024 * 1024 }, processDependencyTreeOutput(resolve, reject))
|
||||
})
|
||||
}
|
||||
|
||||
async function getGitShaFromRootPath () {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
exec(`cd ${rootPath} && git rev-parse HEAD`, { timeout: execTimeout, maxBuffer: 1024 * 1024 * 1024 }, processGitRevParseOutput(resolve, reject))
|
||||
})
|
||||
try {
|
||||
return await promise
|
||||
} catch (e) {
|
||||
logIfVerbose(e)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
async function reportPostInstall () {
|
||||
const scarfApiToken = process.env.SCARF_API_TOKEN
|
||||
|
||||
const dependencyInfo = await module.exports.getDependencyInfo()
|
||||
logIfVerbose(dependencyInfo)
|
||||
if (!dependencyInfo.parent || !dependencyInfo.parent.name) {
|
||||
return Promise.reject(new Error('No parent found, nothing to report'))
|
||||
}
|
||||
|
||||
if (parentIsRoot(dependencyInfo) && allowTopLevel(dependencyInfo.rootPackage)) {
|
||||
const gitSha = await getGitShaFromRootPath()
|
||||
logIfVerbose(`Injecting sha to parent: ${gitSha}`)
|
||||
dependencyInfo.parent.gitSha = gitSha
|
||||
}
|
||||
|
||||
const rootPackage = dependencyInfo.rootPackage
|
||||
|
||||
if (!userHasOptedIn(rootPackage) && isYarn()) {
|
||||
return Promise.reject(new Error('Package manager is yarn. scarf-js is unable to inform user of analytics. Aborting.'))
|
||||
}
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
if (dependencyInfo.parent.scarfSettings.defaultOptIn) {
|
||||
if (userHasOptedOut(rootPackage)) {
|
||||
return reject(new Error('User has opted out'))
|
||||
}
|
||||
|
||||
if (!userHasOptedIn(rootPackage)) {
|
||||
rateLimitedUserLog(optedInLogRateLimitKey, `
|
||||
The dependency '${dependencyInfo.parent.name}' is tracking installation
|
||||
statistics using scarf-js (https://scarf.sh), which helps open-source developers
|
||||
fund and maintain their projects. Scarf securely logs basic installation
|
||||
details when this package is installed. The Scarf npm library is open source
|
||||
and permissively licensed at https://github.com/scarf-sh/scarf-js. For more
|
||||
details about your project's dependencies, try running 'npm ls'. To opt out of
|
||||
analytics, set the environment variable 'SCARF_ANALYTICS=false'.
|
||||
`)
|
||||
}
|
||||
resolve(dependencyInfo)
|
||||
} else {
|
||||
if (!userHasOptedIn(rootPackage)) {
|
||||
if (!userHasOptedOut(rootPackage)) {
|
||||
// We'll only print the 'please opt in' text if the user hasn't
|
||||
// already opted out, and our logging rate limit hasn't been reached
|
||||
if (hasHitRateLimit(optedOutLogRateLimitKey, getRateLimitedLogHistory())) {
|
||||
return reject(new Error('Analytics are opt-out by default, but rate limit already hit for prompting opt-in.'))
|
||||
}
|
||||
rateLimitedUserLog(optedOutLogRateLimitKey, `
|
||||
The dependency '${dependencyInfo.parent.name}' would like to track
|
||||
installation statistics using scarf-js (https://scarf.sh), which helps
|
||||
open-source developers fund and maintain their projects. Reporting is disabled
|
||||
by default for this package. When enabled, Scarf securely logs basic
|
||||
installation details when this package is installed. The Scarf npm library is
|
||||
open source and permissively licensed at https://github.com/scarf-sh/scarf-js.
|
||||
For more details about your project's dependencies, try running 'npm ls'.
|
||||
`
|
||||
)
|
||||
const stdin = process.stdin
|
||||
stdin.setEncoding('utf-8')
|
||||
|
||||
process.stdout.write(`Would you like to support ${dependencyInfo.parent.name} by sending analytics for this install? (y/N): `)
|
||||
|
||||
const timeout1 = setTimeout(() => {
|
||||
console.log('')
|
||||
console.log('No opt in received, skipping analytics')
|
||||
reject(new Error('Timeout waiting for user opt in'))
|
||||
}, 7000)
|
||||
|
||||
stdin.on('data', async function (data) {
|
||||
clearTimeout(timeout1)
|
||||
const enabled = data.trim().toLowerCase() === 'y'
|
||||
|
||||
const afterUserInput = (enabled, saved) => {
|
||||
if (enabled) {
|
||||
console.log('Thanks for enabling analytics!')
|
||||
}
|
||||
|
||||
if (!saved) {
|
||||
console.log('To prevent this message in the future, you can also set the `SCARF_ANALYTICS=true|false` environment variable')
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
return resolve(dependencyInfo)
|
||||
} else {
|
||||
return reject(new Error('Not enabled via cli'))
|
||||
}
|
||||
}
|
||||
|
||||
process.stdout.write('Save this preference to your project\'s package.json file? (y/N): ')
|
||||
|
||||
setTimeout(() => {
|
||||
console.log('')
|
||||
return afterUserInput(enabled, false)
|
||||
}, 15000)
|
||||
|
||||
stdin.removeAllListeners('data')
|
||||
stdin.on('data', async function (data) {
|
||||
try {
|
||||
const savePreference = data.trim().toLowerCase() === 'y'
|
||||
if (savePreference) {
|
||||
await savePreferencesToRootPackage(dependencyInfo.rootPackage.packageJsonPath, enabled)
|
||||
}
|
||||
return afterUserInput(enabled, savePreference)
|
||||
} catch (err) {
|
||||
logIfVerbose(err, console.error)
|
||||
return reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
} else {
|
||||
resolve(dependencyInfo)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
redactSensitivePackageInfo(dependencyInfo)
|
||||
|
||||
const infoPayload = {
|
||||
libraryType: 'npm',
|
||||
rawPlatform: os.platform(),
|
||||
rawArch: os.arch(),
|
||||
nodeVersion: process.versions.node,
|
||||
dependencyInfo: dependencyInfo
|
||||
}
|
||||
|
||||
const data = JSON.stringify(infoPayload)
|
||||
logIfVerbose(`Scarf payload: ${data}`)
|
||||
|
||||
const reqOptions = {
|
||||
host: scarfHost,
|
||||
port: localDevPort,
|
||||
method: 'POST',
|
||||
path: '/package-event/install',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': data.length
|
||||
},
|
||||
timeout: execTimeout
|
||||
}
|
||||
|
||||
if (scarfApiToken) {
|
||||
const authToken = Buffer.from(`n/a:${scarfApiToken}`).toString('base64')
|
||||
reqOptions.headers.Authorization = `Basic ${authToken}`
|
||||
}
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
const req = https.request(reqOptions, (res) => {
|
||||
logIfVerbose(`Response status: ${res.statusCode}`)
|
||||
resolve()
|
||||
})
|
||||
|
||||
req.on('error', error => {
|
||||
logIfVerbose(error, console.error)
|
||||
reject(error)
|
||||
})
|
||||
|
||||
req.on('timeout', error => {
|
||||
logIfVerbose(error, console.error)
|
||||
reject(error)
|
||||
})
|
||||
|
||||
req.write(data)
|
||||
req.end()
|
||||
})
|
||||
}
|
||||
|
||||
// Find all paths to Scarf from the json output of npm ls @scarf/scarf --json in
|
||||
// the root package being installed by the user
|
||||
//
|
||||
// [{
|
||||
// scarf: {name: `@scarf/scarf`, version: '0.0.1'},
|
||||
// parent: { name: 'scarfed-library', version: '1.0.0', scarfSettings: { defaultOptIn: true } },
|
||||
// grandparent: { name: 'scarfed-lib-consumer', version: '1.0.0' }
|
||||
// }]
|
||||
function findScarfInSubDepTree (pathToDep, deps) {
|
||||
const depNames = Object.keys(deps || {})
|
||||
|
||||
if (!depNames) {
|
||||
return []
|
||||
}
|
||||
|
||||
const scarfFound = depNames.find(depName => depName === scarfLibName)
|
||||
const output = []
|
||||
if (scarfFound) {
|
||||
output.push(pathToDep.concat([{ name: scarfLibName, version: deps[scarfLibName].version, path: deps[scarfLibName].path }]))
|
||||
}
|
||||
for (let i = 0; i < depNames.length; i++) {
|
||||
const depName = depNames[i]
|
||||
const newPathToDep = pathToDep.concat([
|
||||
{
|
||||
name: depName,
|
||||
version: deps[depName].version,
|
||||
scarfSettings: deps[depName].scarfSettings,
|
||||
path: deps[depName].path
|
||||
}
|
||||
])
|
||||
const results = findScarfInSubDepTree(newPathToDep, deps[depName].dependencies)
|
||||
if (results) {
|
||||
for (let j = 0; j < results.length; j++) {
|
||||
output.push(results[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
function findScarfInFullDependencyTree (tree) {
|
||||
if (tree.name === scarfLibName) {
|
||||
return [[{ name: scarfLibName, version: tree.version }]]
|
||||
} else {
|
||||
return findScarfInSubDepTree([packageDetailsFromDepInfo(tree)], tree.dependencies)
|
||||
}
|
||||
}
|
||||
|
||||
function packageDetailsFromDepInfo (tree) {
|
||||
return {
|
||||
name: tree.name,
|
||||
version: tree.version,
|
||||
scarfSettings: tree.scarfSettings,
|
||||
path: tree.path
|
||||
}
|
||||
}
|
||||
|
||||
function rootPackageDepInfo (packageInfo) {
|
||||
if (process.env.npm_config_global) {
|
||||
packageInfo = Object.values(packageInfo.dependencies)[0]
|
||||
}
|
||||
const info = packageDetailsFromDepInfo(packageInfo)
|
||||
info.packageJsonPath = `${packageInfo.path}/package.json`
|
||||
return info
|
||||
}
|
||||
|
||||
async function savePreferencesToRootPackage (path, optIn) {
|
||||
const packageJsonString = await fsAsync.readFile(path)
|
||||
const parsed = JSON.parse(packageJsonString)
|
||||
parsed.scarfSettings = {
|
||||
enabled: optIn
|
||||
}
|
||||
await fsAsync.writeFile(path, JSON.stringify(parsed, null, 2))
|
||||
}
|
||||
|
||||
/*
|
||||
If Scarf-js appears in many different spots in a package's dependency tree, we
|
||||
want to avoid spamming the user with the same message informing them of
|
||||
Scarf's analytics. Rate limited logs will record timestamps of logging in a
|
||||
temp file. Before logging something to the user, we will verify we're not over
|
||||
the rate limit.
|
||||
*/
|
||||
function rateLimitedUserLog (rateLimitKey, toLog) {
|
||||
const history = getRateLimitedLogHistory()
|
||||
if (!hasHitRateLimit(rateLimitKey, history)) {
|
||||
writeCurrentTimeToLogHistory(rateLimitKey, history)
|
||||
console.log(toLog)
|
||||
} else {
|
||||
logIfVerbose(`[SUPPRESSED USER MESSAGE, RATE LIMIT HIT] ${toLog}`)
|
||||
}
|
||||
}
|
||||
|
||||
function getRateLimitedLogHistory () {
|
||||
let history
|
||||
try {
|
||||
history = JSON.parse(fs.readFileSync(module.exports.tmpFileName()))
|
||||
} catch (e) {
|
||||
logIfVerbose(e)
|
||||
}
|
||||
return history || {}
|
||||
}
|
||||
|
||||
// Current rate limit: 1/minute
|
||||
function hasHitRateLimit (rateLimitKey, history) {
|
||||
if (!history || !history[rateLimitKey]) {
|
||||
return false
|
||||
}
|
||||
|
||||
const lastLog = history[rateLimitKey]
|
||||
return (new Date().getTime() - lastLog) < userMessageThrottleTime
|
||||
}
|
||||
|
||||
function writeCurrentTimeToLogHistory (rateLimitKey, history) {
|
||||
history[rateLimitKey] = new Date().getTime()
|
||||
fs.writeFileSync(module.exports.tmpFileName(), JSON.stringify(history))
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
redactSensitivePackageInfo,
|
||||
hasHitRateLimit,
|
||||
getRateLimitedLogHistory,
|
||||
rateLimitedUserLog,
|
||||
tmpFileName,
|
||||
dirName,
|
||||
processDependencyTreeOutput,
|
||||
processGitRevParseOutput,
|
||||
npmExecPath,
|
||||
getDependencyInfo,
|
||||
getGitShaFromRootPath,
|
||||
reportPostInstall,
|
||||
hashWithDefault,
|
||||
findScarfInFullDependencyTree
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
try {
|
||||
reportPostInstall().catch(e => {
|
||||
// This is an optional, best effort attempt. If there are any errors in
|
||||
// Scarf, we must not interfere with whatever the user is doing
|
||||
logIfVerbose(`\n\n${e}`, console.error)
|
||||
}).finally(() => {
|
||||
process.exit(0)
|
||||
})
|
||||
} catch (e) {
|
||||
logIfVerbose(`\n\nTop level error: ${e}`, console.error)
|
||||
process.exit(0)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user