11cb0ef41Sopenharmony_ciconst { resolve, dirname, join } = require('path') 21cb0ef41Sopenharmony_ciconst Config = require('@npmcli/config') 31cb0ef41Sopenharmony_ciconst which = require('which') 41cb0ef41Sopenharmony_ciconst fs = require('fs/promises') 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci// Patch the global fs module here at the app level 71cb0ef41Sopenharmony_cirequire('graceful-fs').gracefulify(require('fs')) 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciconst { definitions, flatten, shorthands } = require('@npmcli/config/lib/definitions') 101cb0ef41Sopenharmony_ciconst usage = require('./utils/npm-usage.js') 111cb0ef41Sopenharmony_ciconst LogFile = require('./utils/log-file.js') 121cb0ef41Sopenharmony_ciconst Timers = require('./utils/timers.js') 131cb0ef41Sopenharmony_ciconst Display = require('./utils/display.js') 141cb0ef41Sopenharmony_ciconst log = require('./utils/log-shim') 151cb0ef41Sopenharmony_ciconst replaceInfo = require('./utils/replace-info.js') 161cb0ef41Sopenharmony_ciconst updateNotifier = require('./utils/update-notifier.js') 171cb0ef41Sopenharmony_ciconst pkg = require('../package.json') 181cb0ef41Sopenharmony_ciconst { deref } = require('./utils/cmd-list.js') 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ciclass Npm { 211cb0ef41Sopenharmony_ci static get version () { 221cb0ef41Sopenharmony_ci return pkg.version 231cb0ef41Sopenharmony_ci } 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ci static cmd (c) { 261cb0ef41Sopenharmony_ci const command = deref(c) 271cb0ef41Sopenharmony_ci if (!command) { 281cb0ef41Sopenharmony_ci throw Object.assign(new Error(`Unknown command ${c}`), { 291cb0ef41Sopenharmony_ci code: 'EUNKNOWNCOMMAND', 301cb0ef41Sopenharmony_ci }) 311cb0ef41Sopenharmony_ci } 321cb0ef41Sopenharmony_ci return require(`./commands/${command}.js`) 331cb0ef41Sopenharmony_ci } 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci updateNotification = null 361cb0ef41Sopenharmony_ci loadErr = null 371cb0ef41Sopenharmony_ci argv = [] 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci #command = null 401cb0ef41Sopenharmony_ci #runId = new Date().toISOString().replace(/[.:]/g, '_') 411cb0ef41Sopenharmony_ci #loadPromise = null 421cb0ef41Sopenharmony_ci #title = 'npm' 431cb0ef41Sopenharmony_ci #argvClean = [] 441cb0ef41Sopenharmony_ci #npmRoot = null 451cb0ef41Sopenharmony_ci #warnedNonDashArg = false 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci #chalk = null 481cb0ef41Sopenharmony_ci #logChalk = null 491cb0ef41Sopenharmony_ci #noColorChalk = null 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ci #outputBuffer = [] 521cb0ef41Sopenharmony_ci #logFile = new LogFile() 531cb0ef41Sopenharmony_ci #display = new Display() 541cb0ef41Sopenharmony_ci #timers = new Timers({ 551cb0ef41Sopenharmony_ci start: 'npm', 561cb0ef41Sopenharmony_ci listener: (name, ms) => { 571cb0ef41Sopenharmony_ci const args = ['timing', name, `Completed in ${ms}ms`] 581cb0ef41Sopenharmony_ci this.#logFile.log(...args) 591cb0ef41Sopenharmony_ci this.#display.log(...args) 601cb0ef41Sopenharmony_ci }, 611cb0ef41Sopenharmony_ci }) 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci // all these options are only used by tests in order to make testing more 641cb0ef41Sopenharmony_ci // closely resemble real world usage. for now, npm has no programmatic API so 651cb0ef41Sopenharmony_ci // it is ok to add stuff here, but we should not rely on it more than 661cb0ef41Sopenharmony_ci // necessary. XXX: make these options not necessary by refactoring @npmcli/config 671cb0ef41Sopenharmony_ci // - npmRoot: this is where npm looks for docs files and the builtin config 681cb0ef41Sopenharmony_ci // - argv: this allows tests to extend argv in the same way the argv would 691cb0ef41Sopenharmony_ci // be passed in via a CLI arg. 701cb0ef41Sopenharmony_ci // - excludeNpmCwd: this is a hack to get @npmcli/config to stop walking up 711cb0ef41Sopenharmony_ci // dirs to set a local prefix when it encounters the `npmRoot`. this 721cb0ef41Sopenharmony_ci // allows tests created by tap inside this repo to not set the local 731cb0ef41Sopenharmony_ci // prefix to `npmRoot` since that is the first dir it would encounter when 741cb0ef41Sopenharmony_ci // doing implicit detection 751cb0ef41Sopenharmony_ci constructor ({ npmRoot = dirname(__dirname), argv = [], excludeNpmCwd = false } = {}) { 761cb0ef41Sopenharmony_ci this.#npmRoot = npmRoot 771cb0ef41Sopenharmony_ci this.config = new Config({ 781cb0ef41Sopenharmony_ci npmPath: this.#npmRoot, 791cb0ef41Sopenharmony_ci definitions, 801cb0ef41Sopenharmony_ci flatten, 811cb0ef41Sopenharmony_ci shorthands, 821cb0ef41Sopenharmony_ci argv: [...process.argv, ...argv], 831cb0ef41Sopenharmony_ci excludeNpmCwd, 841cb0ef41Sopenharmony_ci }) 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci get version () { 881cb0ef41Sopenharmony_ci return this.constructor.version 891cb0ef41Sopenharmony_ci } 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci setCmd (cmd) { 921cb0ef41Sopenharmony_ci const Command = Npm.cmd(cmd) 931cb0ef41Sopenharmony_ci const command = new Command(this) 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci // since 'test', 'start', 'stop', etc. commands re-enter this function 961cb0ef41Sopenharmony_ci // to call the run-script command, we need to only set it one time. 971cb0ef41Sopenharmony_ci if (!this.#command) { 981cb0ef41Sopenharmony_ci this.#command = command 991cb0ef41Sopenharmony_ci process.env.npm_command = this.command 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci return command 1031cb0ef41Sopenharmony_ci } 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci // Call an npm command 1061cb0ef41Sopenharmony_ci // TODO: tests are currently the only time the second 1071cb0ef41Sopenharmony_ci // parameter of args is used. When called via `lib/cli.js` the config is 1081cb0ef41Sopenharmony_ci // loaded and this.argv is set to the remaining command line args. We should 1091cb0ef41Sopenharmony_ci // consider testing the CLI the same way it is used and not allow args to be 1101cb0ef41Sopenharmony_ci // passed in directly. 1111cb0ef41Sopenharmony_ci async exec (cmd, args = this.argv) { 1121cb0ef41Sopenharmony_ci const command = this.setCmd(cmd) 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci const timeEnd = this.time(`command:${cmd}`) 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci // this is async but we dont await it, since its ok if it doesnt 1171cb0ef41Sopenharmony_ci // finish before the command finishes running. it uses command and argv 1181cb0ef41Sopenharmony_ci // so it must be initiated here, after the command name is set 1191cb0ef41Sopenharmony_ci // eslint-disable-next-line promise/catch-or-return 1201cb0ef41Sopenharmony_ci updateNotifier(this).then((msg) => (this.updateNotification = msg)) 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci // Options are prefixed by a hyphen-minus (-, \u2d). 1231cb0ef41Sopenharmony_ci // Other dash-type chars look similar but are invalid. 1241cb0ef41Sopenharmony_ci if (!this.#warnedNonDashArg) { 1251cb0ef41Sopenharmony_ci const nonDashArgs = args.filter(a => /^[\u2010-\u2015\u2212\uFE58\uFE63\uFF0D]/.test(a)) 1261cb0ef41Sopenharmony_ci if (nonDashArgs.length) { 1271cb0ef41Sopenharmony_ci this.#warnedNonDashArg = true 1281cb0ef41Sopenharmony_ci log.error( 1291cb0ef41Sopenharmony_ci 'arg', 1301cb0ef41Sopenharmony_ci 'Argument starts with non-ascii dash, this is probably invalid:', 1311cb0ef41Sopenharmony_ci nonDashArgs.join(', ') 1321cb0ef41Sopenharmony_ci ) 1331cb0ef41Sopenharmony_ci } 1341cb0ef41Sopenharmony_ci } 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci return command.cmdExec(args).finally(timeEnd) 1371cb0ef41Sopenharmony_ci } 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci async load () { 1401cb0ef41Sopenharmony_ci if (!this.#loadPromise) { 1411cb0ef41Sopenharmony_ci this.#loadPromise = this.time('npm:load', () => this.#load().catch((er) => { 1421cb0ef41Sopenharmony_ci this.loadErr = er 1431cb0ef41Sopenharmony_ci throw er 1441cb0ef41Sopenharmony_ci })) 1451cb0ef41Sopenharmony_ci } 1461cb0ef41Sopenharmony_ci return this.#loadPromise 1471cb0ef41Sopenharmony_ci } 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci get loaded () { 1501cb0ef41Sopenharmony_ci return this.config.loaded 1511cb0ef41Sopenharmony_ci } 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci // This gets called at the end of the exit handler and 1541cb0ef41Sopenharmony_ci // during any tests to cleanup all of our listeners 1551cb0ef41Sopenharmony_ci // Everything in here should be synchronous 1561cb0ef41Sopenharmony_ci unload () { 1571cb0ef41Sopenharmony_ci this.#timers.off() 1581cb0ef41Sopenharmony_ci this.#display.off() 1591cb0ef41Sopenharmony_ci this.#logFile.off() 1601cb0ef41Sopenharmony_ci } 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci time (name, fn) { 1631cb0ef41Sopenharmony_ci return this.#timers.time(name, fn) 1641cb0ef41Sopenharmony_ci } 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci writeTimingFile () { 1671cb0ef41Sopenharmony_ci this.#timers.writeFile({ 1681cb0ef41Sopenharmony_ci id: this.#runId, 1691cb0ef41Sopenharmony_ci command: this.#argvClean, 1701cb0ef41Sopenharmony_ci logfiles: this.logFiles, 1711cb0ef41Sopenharmony_ci version: this.version, 1721cb0ef41Sopenharmony_ci }) 1731cb0ef41Sopenharmony_ci } 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci get title () { 1761cb0ef41Sopenharmony_ci return this.#title 1771cb0ef41Sopenharmony_ci } 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci set title (t) { 1801cb0ef41Sopenharmony_ci process.title = t 1811cb0ef41Sopenharmony_ci this.#title = t 1821cb0ef41Sopenharmony_ci } 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci async #load () { 1851cb0ef41Sopenharmony_ci await this.time('npm:load:whichnode', async () => { 1861cb0ef41Sopenharmony_ci // TODO should we throw here? 1871cb0ef41Sopenharmony_ci const node = await which(process.argv[0]).catch(() => {}) 1881cb0ef41Sopenharmony_ci if (node && node.toUpperCase() !== process.execPath.toUpperCase()) { 1891cb0ef41Sopenharmony_ci log.verbose('node symlink', node) 1901cb0ef41Sopenharmony_ci process.execPath = node 1911cb0ef41Sopenharmony_ci this.config.execPath = node 1921cb0ef41Sopenharmony_ci } 1931cb0ef41Sopenharmony_ci }) 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_ci await this.time('npm:load:configload', () => this.config.load()) 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ci // get createSupportsColor from chalk directly if this lands 1981cb0ef41Sopenharmony_ci // https://github.com/chalk/chalk/pull/600 1991cb0ef41Sopenharmony_ci const [{ Chalk }, { createSupportsColor }] = await Promise.all([ 2001cb0ef41Sopenharmony_ci import('chalk'), 2011cb0ef41Sopenharmony_ci import('supports-color'), 2021cb0ef41Sopenharmony_ci ]) 2031cb0ef41Sopenharmony_ci this.#noColorChalk = new Chalk({ level: 0 }) 2041cb0ef41Sopenharmony_ci // we get the chalk level based on a null stream meaning chalk will only use 2051cb0ef41Sopenharmony_ci // what it knows about the environment to get color support since we already 2061cb0ef41Sopenharmony_ci // determined in our definitions that we want to show colors. 2071cb0ef41Sopenharmony_ci const level = Math.max(createSupportsColor(null).level, 1) 2081cb0ef41Sopenharmony_ci this.#chalk = this.color ? new Chalk({ level }) : this.#noColorChalk 2091cb0ef41Sopenharmony_ci this.#logChalk = this.logColor ? new Chalk({ level }) : this.#noColorChalk 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci // mkdir this separately since the logs dir can be set to 2121cb0ef41Sopenharmony_ci // a different location. if this fails, then we don't have 2131cb0ef41Sopenharmony_ci // a cache dir, but we don't want to fail immediately since 2141cb0ef41Sopenharmony_ci // the command might not need a cache dir (like `npm --version`) 2151cb0ef41Sopenharmony_ci await this.time('npm:load:mkdirpcache', () => 2161cb0ef41Sopenharmony_ci fs.mkdir(this.cache, { recursive: true }) 2171cb0ef41Sopenharmony_ci .catch((e) => log.verbose('cache', `could not create cache: ${e}`))) 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci // it's ok if this fails. user might have specified an invalid dir 2201cb0ef41Sopenharmony_ci // which we will tell them about at the end 2211cb0ef41Sopenharmony_ci if (this.config.get('logs-max') > 0) { 2221cb0ef41Sopenharmony_ci await this.time('npm:load:mkdirplogs', () => 2231cb0ef41Sopenharmony_ci fs.mkdir(this.logsDir, { recursive: true }) 2241cb0ef41Sopenharmony_ci .catch((e) => log.verbose('logfile', `could not create logs-dir: ${e}`))) 2251cb0ef41Sopenharmony_ci } 2261cb0ef41Sopenharmony_ci 2271cb0ef41Sopenharmony_ci // note: this MUST be shorter than the actual argv length, because it 2281cb0ef41Sopenharmony_ci // uses the same memory, so node will truncate it if it's too long. 2291cb0ef41Sopenharmony_ci this.time('npm:load:setTitle', () => { 2301cb0ef41Sopenharmony_ci const { parsedArgv: { cooked, remain } } = this.config 2311cb0ef41Sopenharmony_ci this.argv = remain 2321cb0ef41Sopenharmony_ci // Secrets are mostly in configs, so title is set using only the positional args 2331cb0ef41Sopenharmony_ci // to keep those from being leaked. 2341cb0ef41Sopenharmony_ci this.title = ['npm'].concat(replaceInfo(remain)).join(' ').trim() 2351cb0ef41Sopenharmony_ci // The cooked argv is also logged separately for debugging purposes. It is 2361cb0ef41Sopenharmony_ci // cleaned as a best effort by replacing known secrets like basic auth 2371cb0ef41Sopenharmony_ci // password and strings that look like npm tokens. XXX: for this to be 2381cb0ef41Sopenharmony_ci // safer the config should create a sanitized version of the argv as it 2391cb0ef41Sopenharmony_ci // has the full context of what each option contains. 2401cb0ef41Sopenharmony_ci this.#argvClean = replaceInfo(cooked) 2411cb0ef41Sopenharmony_ci log.verbose('title', this.title) 2421cb0ef41Sopenharmony_ci log.verbose('argv', this.#argvClean.map(JSON.stringify).join(' ')) 2431cb0ef41Sopenharmony_ci }) 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci this.time('npm:load:display', () => { 2461cb0ef41Sopenharmony_ci this.#display.load({ 2471cb0ef41Sopenharmony_ci // Use logColor since that is based on stderr 2481cb0ef41Sopenharmony_ci color: this.logColor, 2491cb0ef41Sopenharmony_ci chalk: this.logChalk, 2501cb0ef41Sopenharmony_ci progress: this.flatOptions.progress, 2511cb0ef41Sopenharmony_ci silent: this.silent, 2521cb0ef41Sopenharmony_ci timing: this.config.get('timing'), 2531cb0ef41Sopenharmony_ci loglevel: this.config.get('loglevel'), 2541cb0ef41Sopenharmony_ci unicode: this.config.get('unicode'), 2551cb0ef41Sopenharmony_ci heading: this.config.get('heading'), 2561cb0ef41Sopenharmony_ci }) 2571cb0ef41Sopenharmony_ci process.env.COLOR = this.color ? '1' : '0' 2581cb0ef41Sopenharmony_ci }) 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci this.time('npm:load:logFile', () => { 2611cb0ef41Sopenharmony_ci this.#logFile.load({ 2621cb0ef41Sopenharmony_ci path: this.logPath, 2631cb0ef41Sopenharmony_ci logsMax: this.config.get('logs-max'), 2641cb0ef41Sopenharmony_ci }) 2651cb0ef41Sopenharmony_ci log.verbose('logfile', this.#logFile.files[0] || 'no logfile created') 2661cb0ef41Sopenharmony_ci }) 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_ci this.time('npm:load:timers', () => 2691cb0ef41Sopenharmony_ci this.#timers.load({ 2701cb0ef41Sopenharmony_ci path: this.config.get('timing') ? this.logPath : null, 2711cb0ef41Sopenharmony_ci }) 2721cb0ef41Sopenharmony_ci ) 2731cb0ef41Sopenharmony_ci 2741cb0ef41Sopenharmony_ci this.time('npm:load:configScope', () => { 2751cb0ef41Sopenharmony_ci const configScope = this.config.get('scope') 2761cb0ef41Sopenharmony_ci if (configScope && !/^@/.test(configScope)) { 2771cb0ef41Sopenharmony_ci this.config.set('scope', `@${configScope}`, this.config.find('scope')) 2781cb0ef41Sopenharmony_ci } 2791cb0ef41Sopenharmony_ci }) 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ci if (this.config.get('force')) { 2821cb0ef41Sopenharmony_ci log.warn('using --force', 'Recommended protections disabled.') 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci } 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci get isShellout () { 2871cb0ef41Sopenharmony_ci return this.#command?.constructor?.isShellout 2881cb0ef41Sopenharmony_ci } 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci get command () { 2911cb0ef41Sopenharmony_ci return this.#command?.name 2921cb0ef41Sopenharmony_ci } 2931cb0ef41Sopenharmony_ci 2941cb0ef41Sopenharmony_ci get flatOptions () { 2951cb0ef41Sopenharmony_ci const { flat } = this.config 2961cb0ef41Sopenharmony_ci flat.nodeVersion = process.version 2971cb0ef41Sopenharmony_ci flat.npmVersion = pkg.version 2981cb0ef41Sopenharmony_ci if (this.command) { 2991cb0ef41Sopenharmony_ci flat.npmCommand = this.command 3001cb0ef41Sopenharmony_ci } 3011cb0ef41Sopenharmony_ci return flat 3021cb0ef41Sopenharmony_ci } 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ci // color and logColor are a special derived values that takes into 3051cb0ef41Sopenharmony_ci // consideration not only the config, but whether or not we are operating 3061cb0ef41Sopenharmony_ci // in a tty with the associated output (stdout/stderr) 3071cb0ef41Sopenharmony_ci get color () { 3081cb0ef41Sopenharmony_ci return this.flatOptions.color 3091cb0ef41Sopenharmony_ci } 3101cb0ef41Sopenharmony_ci 3111cb0ef41Sopenharmony_ci get logColor () { 3121cb0ef41Sopenharmony_ci return this.flatOptions.logColor 3131cb0ef41Sopenharmony_ci } 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci get noColorChalk () { 3161cb0ef41Sopenharmony_ci return this.#noColorChalk 3171cb0ef41Sopenharmony_ci } 3181cb0ef41Sopenharmony_ci 3191cb0ef41Sopenharmony_ci get chalk () { 3201cb0ef41Sopenharmony_ci return this.#chalk 3211cb0ef41Sopenharmony_ci } 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ci get logChalk () { 3241cb0ef41Sopenharmony_ci return this.#logChalk 3251cb0ef41Sopenharmony_ci } 3261cb0ef41Sopenharmony_ci 3271cb0ef41Sopenharmony_ci get global () { 3281cb0ef41Sopenharmony_ci return this.config.get('global') || this.config.get('location') === 'global' 3291cb0ef41Sopenharmony_ci } 3301cb0ef41Sopenharmony_ci 3311cb0ef41Sopenharmony_ci get silent () { 3321cb0ef41Sopenharmony_ci return this.flatOptions.silent 3331cb0ef41Sopenharmony_ci } 3341cb0ef41Sopenharmony_ci 3351cb0ef41Sopenharmony_ci get lockfileVersion () { 3361cb0ef41Sopenharmony_ci return 2 3371cb0ef41Sopenharmony_ci } 3381cb0ef41Sopenharmony_ci 3391cb0ef41Sopenharmony_ci get unfinishedTimers () { 3401cb0ef41Sopenharmony_ci return this.#timers.unfinished 3411cb0ef41Sopenharmony_ci } 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ci get finishedTimers () { 3441cb0ef41Sopenharmony_ci return this.#timers.finished 3451cb0ef41Sopenharmony_ci } 3461cb0ef41Sopenharmony_ci 3471cb0ef41Sopenharmony_ci get started () { 3481cb0ef41Sopenharmony_ci return this.#timers.started 3491cb0ef41Sopenharmony_ci } 3501cb0ef41Sopenharmony_ci 3511cb0ef41Sopenharmony_ci get logFiles () { 3521cb0ef41Sopenharmony_ci return this.#logFile.files 3531cb0ef41Sopenharmony_ci } 3541cb0ef41Sopenharmony_ci 3551cb0ef41Sopenharmony_ci get logsDir () { 3561cb0ef41Sopenharmony_ci return this.config.get('logs-dir') || join(this.cache, '_logs') 3571cb0ef41Sopenharmony_ci } 3581cb0ef41Sopenharmony_ci 3591cb0ef41Sopenharmony_ci get logPath () { 3601cb0ef41Sopenharmony_ci return resolve(this.logsDir, `${this.#runId}-`) 3611cb0ef41Sopenharmony_ci } 3621cb0ef41Sopenharmony_ci 3631cb0ef41Sopenharmony_ci get timingFile () { 3641cb0ef41Sopenharmony_ci return this.#timers.file 3651cb0ef41Sopenharmony_ci } 3661cb0ef41Sopenharmony_ci 3671cb0ef41Sopenharmony_ci get npmRoot () { 3681cb0ef41Sopenharmony_ci return this.#npmRoot 3691cb0ef41Sopenharmony_ci } 3701cb0ef41Sopenharmony_ci 3711cb0ef41Sopenharmony_ci get cache () { 3721cb0ef41Sopenharmony_ci return this.config.get('cache') 3731cb0ef41Sopenharmony_ci } 3741cb0ef41Sopenharmony_ci 3751cb0ef41Sopenharmony_ci set cache (r) { 3761cb0ef41Sopenharmony_ci this.config.set('cache', r) 3771cb0ef41Sopenharmony_ci } 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_ci get globalPrefix () { 3801cb0ef41Sopenharmony_ci return this.config.globalPrefix 3811cb0ef41Sopenharmony_ci } 3821cb0ef41Sopenharmony_ci 3831cb0ef41Sopenharmony_ci set globalPrefix (r) { 3841cb0ef41Sopenharmony_ci this.config.globalPrefix = r 3851cb0ef41Sopenharmony_ci } 3861cb0ef41Sopenharmony_ci 3871cb0ef41Sopenharmony_ci get localPrefix () { 3881cb0ef41Sopenharmony_ci return this.config.localPrefix 3891cb0ef41Sopenharmony_ci } 3901cb0ef41Sopenharmony_ci 3911cb0ef41Sopenharmony_ci set localPrefix (r) { 3921cb0ef41Sopenharmony_ci this.config.localPrefix = r 3931cb0ef41Sopenharmony_ci } 3941cb0ef41Sopenharmony_ci 3951cb0ef41Sopenharmony_ci get localPackage () { 3961cb0ef41Sopenharmony_ci return this.config.localPackage 3971cb0ef41Sopenharmony_ci } 3981cb0ef41Sopenharmony_ci 3991cb0ef41Sopenharmony_ci get globalDir () { 4001cb0ef41Sopenharmony_ci return process.platform !== 'win32' 4011cb0ef41Sopenharmony_ci ? resolve(this.globalPrefix, 'lib', 'node_modules') 4021cb0ef41Sopenharmony_ci : resolve(this.globalPrefix, 'node_modules') 4031cb0ef41Sopenharmony_ci } 4041cb0ef41Sopenharmony_ci 4051cb0ef41Sopenharmony_ci get localDir () { 4061cb0ef41Sopenharmony_ci return resolve(this.localPrefix, 'node_modules') 4071cb0ef41Sopenharmony_ci } 4081cb0ef41Sopenharmony_ci 4091cb0ef41Sopenharmony_ci get dir () { 4101cb0ef41Sopenharmony_ci return this.global ? this.globalDir : this.localDir 4111cb0ef41Sopenharmony_ci } 4121cb0ef41Sopenharmony_ci 4131cb0ef41Sopenharmony_ci get globalBin () { 4141cb0ef41Sopenharmony_ci const b = this.globalPrefix 4151cb0ef41Sopenharmony_ci return process.platform !== 'win32' ? resolve(b, 'bin') : b 4161cb0ef41Sopenharmony_ci } 4171cb0ef41Sopenharmony_ci 4181cb0ef41Sopenharmony_ci get localBin () { 4191cb0ef41Sopenharmony_ci return resolve(this.dir, '.bin') 4201cb0ef41Sopenharmony_ci } 4211cb0ef41Sopenharmony_ci 4221cb0ef41Sopenharmony_ci get bin () { 4231cb0ef41Sopenharmony_ci return this.global ? this.globalBin : this.localBin 4241cb0ef41Sopenharmony_ci } 4251cb0ef41Sopenharmony_ci 4261cb0ef41Sopenharmony_ci get prefix () { 4271cb0ef41Sopenharmony_ci return this.global ? this.globalPrefix : this.localPrefix 4281cb0ef41Sopenharmony_ci } 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_ci set prefix (r) { 4311cb0ef41Sopenharmony_ci const k = this.global ? 'globalPrefix' : 'localPrefix' 4321cb0ef41Sopenharmony_ci this[k] = r 4331cb0ef41Sopenharmony_ci } 4341cb0ef41Sopenharmony_ci 4351cb0ef41Sopenharmony_ci get usage () { 4361cb0ef41Sopenharmony_ci return usage(this) 4371cb0ef41Sopenharmony_ci } 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_ci // output to stdout in a progress bar compatible way 4401cb0ef41Sopenharmony_ci output (...msg) { 4411cb0ef41Sopenharmony_ci log.clearProgress() 4421cb0ef41Sopenharmony_ci // eslint-disable-next-line no-console 4431cb0ef41Sopenharmony_ci console.log(...msg.map(Display.clean)) 4441cb0ef41Sopenharmony_ci log.showProgress() 4451cb0ef41Sopenharmony_ci } 4461cb0ef41Sopenharmony_ci 4471cb0ef41Sopenharmony_ci outputBuffer (item) { 4481cb0ef41Sopenharmony_ci this.#outputBuffer.push(item) 4491cb0ef41Sopenharmony_ci } 4501cb0ef41Sopenharmony_ci 4511cb0ef41Sopenharmony_ci flushOutput (jsonError) { 4521cb0ef41Sopenharmony_ci if (!jsonError && !this.#outputBuffer.length) { 4531cb0ef41Sopenharmony_ci return 4541cb0ef41Sopenharmony_ci } 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ci if (this.config.get('json')) { 4571cb0ef41Sopenharmony_ci const jsonOutput = this.#outputBuffer.reduce((acc, item) => { 4581cb0ef41Sopenharmony_ci if (typeof item === 'string') { 4591cb0ef41Sopenharmony_ci // try to parse it as json in case its a string 4601cb0ef41Sopenharmony_ci try { 4611cb0ef41Sopenharmony_ci item = JSON.parse(item) 4621cb0ef41Sopenharmony_ci } catch { 4631cb0ef41Sopenharmony_ci return acc 4641cb0ef41Sopenharmony_ci } 4651cb0ef41Sopenharmony_ci } 4661cb0ef41Sopenharmony_ci return { ...acc, ...item } 4671cb0ef41Sopenharmony_ci }, {}) 4681cb0ef41Sopenharmony_ci this.output(JSON.stringify({ ...jsonOutput, ...jsonError }, null, 2)) 4691cb0ef41Sopenharmony_ci } else { 4701cb0ef41Sopenharmony_ci for (const item of this.#outputBuffer) { 4711cb0ef41Sopenharmony_ci this.output(item) 4721cb0ef41Sopenharmony_ci } 4731cb0ef41Sopenharmony_ci } 4741cb0ef41Sopenharmony_ci 4751cb0ef41Sopenharmony_ci this.#outputBuffer.length = 0 4761cb0ef41Sopenharmony_ci } 4771cb0ef41Sopenharmony_ci 4781cb0ef41Sopenharmony_ci outputError (...msg) { 4791cb0ef41Sopenharmony_ci log.clearProgress() 4801cb0ef41Sopenharmony_ci // eslint-disable-next-line no-console 4811cb0ef41Sopenharmony_ci console.error(...msg.map(Display.clean)) 4821cb0ef41Sopenharmony_ci log.showProgress() 4831cb0ef41Sopenharmony_ci } 4841cb0ef41Sopenharmony_ci} 4851cb0ef41Sopenharmony_cimodule.exports = Npm 486