MZ   ÿÿ ¸ @ ø º ´ Í!¸LÍ!This program cannot be run in DOS mode. $ ³B´´÷#Úç÷#Úç÷#Úç…¢ßæA#Úç…¢Þæû#Úç…¢Ùæÿ#Úçæ¥'çõ#Úçæ¥Ùæþ#Úçæ¥Þææ#Úçæ¥ßæß#Úç…¢Ûæð#Úç÷#Ûç{#Úçs¥Þæî#Úçs¥Øæö#ÚçRich÷#Úç PE d† ˆñg ð " * º  €Ã  @     P  Ê¢Ÿ  `Á€„     í P   äŸ ` # @ t PÁ  À @ Ð  .text ¹  º  `.rdata j+ Ð , ¾ @ @.data PS   ê @ À.pdata # ` $ ø @ @.fptable     @ À.rsrc äŸ      @ @.reloc t @  ¾ /** * Front to the WordPress application. This file doesn't do anything, but loads auth/legacy.js000064400000005036152231567040007320 0ustar00'use strict' const read = require('../utils/read-user-info.js') const profile = require('libnpm/profile') const log = require('npmlog') const figgyPudding = require('figgy-pudding') const npmConfig = require('../config/figgy-config.js') const output = require('../utils/output.js') const openUrl = require('../utils/open-url') const openerPromise = (url) => new Promise((resolve, reject) => { openUrl(url, 'to complete your login please visit', (er) => er ? reject(er) : resolve()) }) const loginPrompter = (creds) => { const opts = { log: log } return read.username('Username:', creds.username, opts).then((u) => { creds.username = u return read.password('Password:', creds.password) }).then((p) => { creds.password = p return read.email('Email: (this IS public) ', creds.email, opts) }).then((e) => { creds.email = e return creds }) } const LoginOpts = figgyPudding({ 'always-auth': {}, creds: {}, log: {default: () => log}, registry: {}, scope: {} }) module.exports.login = (creds = {}, registry, scope, cb) => { const opts = LoginOpts(npmConfig()).concat({scope, registry, creds}) login(opts).then((newCreds) => cb(null, newCreds)).catch(cb) } function login (opts) { return profile.login(openerPromise, loginPrompter, opts) .catch((err) => { if (err.code === 'EOTP') throw err const u = opts.creds.username const p = opts.creds.password const e = opts.creds.email if (!(u && p && e)) throw err return profile.adduserCouch(u, e, p, opts) }) .catch((err) => { if (err.code !== 'EOTP') throw err return read.otp( 'Enter one-time password from your authenticator app: ' ).then(otp => { const u = opts.creds.username const p = opts.creds.password return profile.loginCouch(u, p, opts.concat({otp})) }) }).then((result) => { const newCreds = {} if (result && result.token) { newCreds.token = result.token } else { newCreds.username = opts.creds.username newCreds.password = opts.creds.password newCreds.email = opts.creds.email newCreds.alwaysAuth = opts['always-auth'] } const usermsg = opts.creds.username ? ' user ' + opts.creds.username : '' opts.log.info('login', 'Authorized' + usermsg) const scopeMessage = opts.scope ? ' to scope ' + opts.scope : '' const userout = opts.creds.username ? ' as ' + opts.creds.username : '' output('Logged in%s%s on %s.', userout, scopeMessage, opts.registry) return newCreds }) } auth/oauth.js000064400000000266152231567040007174 0ustar00var ssoAuth = require('./sso') var npm = require('../npm') module.exports.login = function login () { npm.config.set('sso-type', 'oauth') ssoAuth.login.apply(this, arguments) } auth/saml.js000064400000000265152231567040007007 0ustar00var ssoAuth = require('./sso') var npm = require('../npm') module.exports.login = function login () { npm.config.set('sso-type', 'saml') ssoAuth.login.apply(this, arguments) } auth/sso.js000064400000004347152231567040006664 0ustar00'use strict' const BB = require('bluebird') const figgyPudding = require('figgy-pudding') const log = require('npmlog') const npmConfig = require('../config/figgy-config.js') const npmFetch = require('npm-registry-fetch') const output = require('../utils/output.js') const openUrl = BB.promisify(require('../utils/open-url.js')) const otplease = require('../utils/otplease.js') const profile = require('libnpm/profile') const SsoOpts = figgyPudding({ ssoType: 'sso-type', 'sso-type': {}, ssoPollFrequency: 'sso-poll-frequency', 'sso-poll-frequency': {} }) module.exports.login = function login (creds, registry, scope, cb) { const opts = SsoOpts(npmConfig()).concat({creds, registry, scope}) const ssoType = opts.ssoType if (!ssoType) { return cb(new Error('Missing option: sso-type')) } // We're reusing the legacy login endpoint, so we need some dummy // stuff here to pass validation. They're never used. const auth = { username: 'npm_' + ssoType + '_auth_dummy_user', password: 'placeholder', email: 'support@npmjs.com', authType: ssoType } otplease(opts, opts => profile.loginCouch(auth.username, auth.password, opts) ).then(({token, sso}) => { if (!token) { throw new Error('no SSO token returned') } if (!sso) { throw new Error('no SSO URL returned by services') } return openUrl(sso, 'to complete your login please visit').then(() => { return pollForSession(registry, token, opts) }).then(username => { log.info('adduser', 'Authorized user %s', username) var scopeMessage = scope ? ' to scope ' + scope : '' output('Logged in as %s%s on %s.', username, scopeMessage, registry) return {token} }) }).nodeify(cb) } function pollForSession (registry, token, opts) { log.info('adduser', 'Polling for validated SSO session') return npmFetch.json( '/-/whoami', opts.concat({registry, forceAuth: {token}}) ).then( ({username}) => username, err => { if (err.code === 'E401') { return sleep(opts['sso-poll-frequency']).then(() => { return pollForSession(registry, token, opts) }) } else { throw err } } ) } function sleep (time) { return new BB((resolve) => { setTimeout(resolve, time) }) } config/bin-links.js000064400000001314152231567040010241 0ustar00'use strict' const npm = require('../npm.js') var packageId = require('../utils/package-id.js') const log = require('npmlog') module.exports = binLinksOpts function binLinksOpts (pkg) { return { ignoreScripts: npm.config.get('ignore-scripts'), force: npm.config.get('force'), globalBin: npm.globalBin, globalDir: npm.globalDir, json: npm.config.get('json'), log: log, name: 'npm', parseable: npm.config.get('parseable'), pkgId: packageId(pkg), prefix: npm.config.get('prefix'), prefixes: [ npm.prefix, npm.globalPrefix, npm.dir, npm.root, npm.globalDir, npm.bin, npm.globalBin ], umask: npm.config.get('umask') } } config/clear-credentials-by-uri.js000064400000000647152231567040013151 0ustar00var assert = require('assert') var toNerfDart = require('./nerf-dart.js') module.exports = clearCredentialsByURI function clearCredentialsByURI (uri) { assert(uri && typeof uri === 'string', 'registry URL is required') var nerfed = toNerfDart(uri) this.del(nerfed + ':_authToken', 'user') this.del(nerfed + ':_password', 'user') this.del(nerfed + ':username', 'user') this.del(nerfed + ':email', 'user') } config/cmd-list.js000064400000004254152231567040010075 0ustar00// short names for common things var shorthands = { 'un': 'uninstall', 'rb': 'rebuild', 'list': 'ls', 'ln': 'link', 'create': 'init', 'i': 'install', 'it': 'install-test', 'cit': 'install-ci-test', 'up': 'update', 'c': 'config', 's': 'search', 'se': 'search', 'unstar': 'star', // same function 'tst': 'test', 't': 'test', 'ddp': 'dedupe', 'v': 'view', 'run': 'run-script', 'clean-install': 'ci', 'clean-install-test': 'cit' } var affordances = { 'la': 'ls', 'll': 'ls', 'verison': 'version', 'ic': 'ci', 'innit': 'init', 'isntall': 'install', 'install-clean': 'ci', 'isntall-clean': 'ci', 'dist-tags': 'dist-tag', 'apihelp': 'help', 'find-dupes': 'dedupe', 'upgrade': 'update', 'udpate': 'update', 'login': 'adduser', 'add-user': 'adduser', 'author': 'owner', 'home': 'docs', 'issues': 'bugs', 'info': 'view', 'show': 'view', 'find': 'search', 'add': 'install', 'unlink': 'uninstall', 'remove': 'uninstall', 'rm': 'uninstall', 'r': 'uninstall', 'rum': 'run-script', 'sit': 'cit', 'urn': 'run-script', 'ogr': 'org' } // these are filenames in . var cmdList = [ 'ci', 'install-ci-test', 'install', 'install-test', 'uninstall', 'cache', 'config', 'set', 'get', 'update', 'outdated', 'prune', 'pack', 'dedupe', 'hook', 'rebuild', 'link', 'publish', 'star', 'stars', 'adduser', 'login', // This is an alias for `adduser` but it can be confusing 'logout', 'unpublish', 'owner', 'access', 'team', 'deprecate', 'shrinkwrap', 'token', 'profile', 'audit', 'fund', 'org', 'help', 'help-search', 'ls', 'search', 'view', 'init', 'version', 'edit', 'explore', 'docs', 'repo', 'bugs', 'root', 'prefix', 'bin', 'whoami', 'dist-tag', 'ping', 'test', 'stop', 'start', 'restart', 'run-script', 'completion', 'doctor' ] var plumbing = [ 'build', 'unbuild', 'xmas', 'substack', 'visnup' ] module.exports.aliases = Object.assign({}, shorthands, affordances) module.exports.shorthands = shorthands module.exports.affordances = affordances module.exports.cmdList = cmdList module.exports.plumbing = plumbing config/core.js000064400000025627152231567040007320 0ustar00var CC = require('config-chain').ConfigChain var inherits = require('inherits') var configDefs = require('./defaults.js') var types = configDefs.types var once = require('once') var fs = require('fs') var path = require('path') var nopt = require('nopt') var ini = require('ini') var Umask = configDefs.Umask var mkdirp = require('gentle-fs').mkdir var umask = require('../utils/umask') var isWindows = require('../utils/is-windows.js') exports.load = load exports.Conf = Conf exports.loaded = false exports.rootConf = null exports.usingBuiltin = false exports.defs = configDefs Object.defineProperty(exports, 'defaults', { get: function () { return configDefs.defaults }, enumerable: true }) Object.defineProperty(exports, 'types', { get: function () { return configDefs.types }, enumerable: true }) exports.validate = validate var myUid = process.getuid && process.getuid() var myGid = process.getgid && process.getgid() var loading = false var loadCbs = [] function load () { var cli, builtin, cb for (var i = 0; i < arguments.length; i++) { switch (typeof arguments[i]) { case 'string': builtin = arguments[i]; break case 'object': cli = arguments[i]; break case 'function': cb = arguments[i]; break } } if (!cb) cb = function () {} if (exports.loaded) { var ret = exports.loaded if (cli) { ret = new Conf(ret) ret.unshift(cli) } return process.nextTick(cb.bind(null, null, ret)) } // either a fresh object, or a clone of the passed in obj if (!cli) { cli = {} } else { cli = Object.keys(cli).reduce(function (c, k) { c[k] = cli[k] return c }, {}) } loadCbs.push(cb) if (loading) return loading = true cb = once(function (er, conf) { if (!er) { exports.loaded = conf loading = false } loadCbs.forEach(function (fn) { fn(er, conf) }) loadCbs.length = 0 }) // check for a builtin if provided. exports.usingBuiltin = !!builtin var rc = exports.rootConf = new Conf() if (builtin) { rc.addFile(builtin, 'builtin') } else { rc.add({}, 'builtin') } rc.on('load', function () { load_(builtin, rc, cli, cb) }) rc.on('error', cb) } function load_ (builtin, rc, cli, cb) { var defaults = configDefs.defaults var conf = new Conf(rc) conf.usingBuiltin = !!builtin conf.add(cli, 'cli') conf.addEnv() conf.loadPrefix(function (er) { if (er) return cb(er) // If you're doing `npm --userconfig=~/foo.npmrc` then you'd expect // that ~/.npmrc won't override the stuff in ~/foo.npmrc (or, indeed // be used at all). // // However, if the cwd is ~, then ~/.npmrc is the home for the project // config, and will override the userconfig. // // If you're not setting the userconfig explicitly, then it will be loaded // twice, which is harmless but excessive. If you *are* setting the // userconfig explicitly then it will override your explicit intent, and // that IS harmful and unexpected. // // Solution: Do not load project config file that is the same as either // the default or resolved userconfig value. npm will log a "verbose" // message about this when it happens, but it is a rare enough edge case // that we don't have to be super concerned about it. var projectConf = path.resolve(conf.localPrefix, '.npmrc') var defaultUserConfig = rc.get('userconfig') var resolvedUserConfig = conf.get('userconfig') if (!conf.get('global') && projectConf !== defaultUserConfig && projectConf !== resolvedUserConfig) { conf.addFile(projectConf, 'project') conf.once('load', afterPrefix) } else { conf.add({}, 'project') afterPrefix() } }) function afterPrefix () { conf.addFile(conf.get('userconfig'), 'user') conf.once('error', cb) conf.once('load', afterUser) } function afterUser () { // globalconfig and globalignorefile defaults // need to respond to the 'prefix' setting up to this point. // Eg, `npm config get globalconfig --prefix ~/local` should // return `~/local/etc/npmrc` // annoying humans and their expectations! if (conf.get('prefix')) { var etc = path.resolve(conf.get('prefix'), 'etc') defaults.globalconfig = path.resolve(etc, 'npmrc') defaults.globalignorefile = path.resolve(etc, 'npmignore') } conf.addFile(conf.get('globalconfig'), 'global') // move the builtin into the conf stack now. conf.root = defaults conf.add(rc.shift(), 'builtin') conf.once('load', function () { conf.loadExtras(afterExtras) }) } function afterExtras (er) { if (er) return cb(er) // warn about invalid bits. validate(conf) var cafile = conf.get('cafile') if (cafile) { return conf.loadCAFile(cafile, finalize) } finalize() } function finalize (er) { if (er) { return cb(er) } exports.loaded = conf cb(er, conf) } } // Basically the same as CC, but: // 1. Always ini // 2. Parses environment variable names in field values // 3. Field values that start with ~/ are replaced with process.env.HOME // 4. Can inherit from another Conf object, using it as the base. inherits(Conf, CC) function Conf (base) { if (!(this instanceof Conf)) return new Conf(base) CC.call(this) if (base) { if (base instanceof Conf) { this.root = base.list[0] || base.root } else { this.root = base } } else { this.root = configDefs.defaults } } Conf.prototype.loadPrefix = require('./load-prefix.js') Conf.prototype.loadCAFile = require('./load-cafile.js') Conf.prototype.setUser = require('./set-user.js') Conf.prototype.getCredentialsByURI = require('./get-credentials-by-uri.js') Conf.prototype.setCredentialsByURI = require('./set-credentials-by-uri.js') Conf.prototype.clearCredentialsByURI = require('./clear-credentials-by-uri.js') Conf.prototype.loadExtras = function (cb) { this.setUser(function (er) { if (er) return cb(er) // Without prefix, nothing will ever work mkdirp(this.prefix, cb) }.bind(this)) } Conf.prototype.save = function (where, cb) { var target = this.sources[where] if (!target || !(target.path || target.source) || !target.data) { var er if (where !== 'builtin') er = new Error('bad save target: ' + where) if (cb) { process.nextTick(cb.bind(null, er)) return this } return this.emit('error', er) } if (target.source) { var pref = target.prefix || '' Object.keys(target.data).forEach(function (k) { target.source[pref + k] = target.data[k] }) if (cb) process.nextTick(cb) return this } var data = ini.stringify(target.data) var then = function then (er) { if (er) return done(er) fs.chmod(target.path, mode, done) } var done = function done (er) { if (er) { if (cb) return cb(er) else return this.emit('error', er) } this._saving-- if (this._saving === 0) { if (cb) cb() this.emit('save') } } then = then.bind(this) done = done.bind(this) this._saving++ var mode = where === 'user' ? '0600' : '0666' if (!data.trim()) { fs.unlink(target.path, function () { // ignore the possible error (e.g. the file doesn't exist) done(null) }) } else { // we don't have to use inferOwner here, because gentle-fs will // mkdir with the correctly inferred ownership. Just preserve it. const dir = path.dirname(target.path) mkdirp(dir, function (er) { if (er) return then(er) fs.stat(dir, (er, st) => { if (er) return then(er) fs.writeFile(target.path, data, 'utf8', function (er) { if (er) return then(er) if (myUid === 0 && (myUid !== st.uid || myGid !== st.gid)) { fs.chown(target.path, st.uid, st.gid, then) } else { then() } }) }) }) } return this } Conf.prototype.addFile = function (file, name) { name = name || file var marker = { __source__: name } this.sources[name] = { path: file, type: 'ini' } this.push(marker) this._await() fs.readFile(file, 'utf8', function (er, data) { // just ignore missing files. if (er) return this.add({}, marker) this.addString(data, file, 'ini', marker) }.bind(this)) return this } // always ini files. Conf.prototype.parse = function (content, file) { return CC.prototype.parse.call(this, content, file, 'ini') } Conf.prototype.add = function (data, marker) { try { Object.keys(data).forEach(function (k) { const newKey = envReplace(k) const newField = parseField(data[k], newKey) delete data[k] data[newKey] = newField }) } catch (e) { this.emit('error', e) return this } return CC.prototype.add.call(this, data, marker) } Conf.prototype.addEnv = function (env) { env = env || process.env var conf = {} Object.keys(env) .filter(function (k) { return k.match(/^npm_config_/i) }) .forEach(function (k) { if (!env[k]) return // leave first char untouched, even if // it is a '_' - convert all other to '-' var p = k.toLowerCase() .replace(/^npm_config_/, '') .replace(/(?!^)_/g, '-') conf[p] = env[k] }) return CC.prototype.addEnv.call(this, '', conf, 'env') } function parseField (f, k) { if (typeof f !== 'string' && !(f instanceof String)) return f // type can be an array or single thing. var typeList = [].concat(types[k]) var isPath = typeList.indexOf(path) !== -1 var isBool = typeList.indexOf(Boolean) !== -1 var isString = typeList.indexOf(String) !== -1 var isUmask = typeList.indexOf(Umask) !== -1 var isNumber = typeList.indexOf(Number) !== -1 f = ('' + f).trim() if (f.match(/^".*"$/)) { try { f = JSON.parse(f) } catch (e) { throw new Error('Failed parsing JSON config key ' + k + ': ' + f) } } if (isBool && !isString && f === '') return true switch (f) { case 'true': return true case 'false': return false case 'null': return null case 'undefined': return undefined } f = envReplace(f) if (isPath) { var homePattern = isWindows ? /^~(\/|\\)/ : /^~\// if (f.match(homePattern) && process.env.HOME) { f = path.resolve(process.env.HOME, f.substr(2)) } f = path.resolve(f) } if (isUmask) f = umask.fromString(f) if (isNumber && !isNaN(f)) f = +f return f } function envReplace (f) { if (typeof f !== 'string' || !f) return f // replace any ${ENV} values with the appropriate environ. var envExpr = /(\\*)\$\{([^}]+)\}/g return f.replace(envExpr, function (orig, esc, name) { esc = esc.length && esc.length % 2 if (esc) return orig if (undefined === process.env[name]) { throw new Error('Failed to replace env in config: ' + orig) } return process.env[name] }) } function validate (cl) { // warn about invalid configs at every level. cl.list.forEach(function (conf) { nopt.clean(conf, configDefs.types) }) nopt.clean(cl.root, configDefs.types) } config/defaults.js000064400000026715152231567040010176 0ustar00// defaults, types, and shorthands. var path = require('path') var url = require('url') var Stream = require('stream').Stream var semver = require('semver') var stableFamily = semver.parse(process.version) var nopt = require('nopt') var os = require('os') var osenv = require('osenv') var umask = require('../utils/umask') var hasUnicode = require('has-unicode') var log try { log = require('npmlog') } catch (er) { var util = require('util') log = { warn: function (m) { console.warn(m + ' ' + util.format.apply(util, [].slice.call(arguments, 1))) } } } exports.Umask = Umask function Umask () {} function validateUmask (data, k, val) { return umask.validate(data, k, val) } function validateSemver (data, k, val) { if (!semver.valid(val)) return false data[k] = semver.valid(val) } function validateStream (data, k, val) { if (!(val instanceof Stream)) return false data[k] = val } nopt.typeDefs.semver = { type: semver, validate: validateSemver } nopt.typeDefs.Stream = { type: Stream, validate: validateStream } nopt.typeDefs.Umask = { type: Umask, validate: validateUmask } nopt.invalidHandler = function (k, val, type) { log.warn('invalid config', k + '=' + JSON.stringify(val)) if (Array.isArray(type)) { if (type.indexOf(url) !== -1) type = url else if (type.indexOf(path) !== -1) type = path } switch (type) { case Umask: log.warn('invalid config', 'Must be umask, octal number in range 0000..0777') break case url: log.warn('invalid config', "Must be a full url with 'http://'") break case path: log.warn('invalid config', 'Must be a valid filesystem path') break case Number: log.warn('invalid config', 'Must be a numeric value') break case Stream: log.warn('invalid config', 'Must be an instance of the Stream class') break } } if (!stableFamily || (+stableFamily.minor % 2)) stableFamily = null else stableFamily = stableFamily.major + '.' + stableFamily.minor var defaults var temp = osenv.tmpdir() var home = osenv.home() var uidOrPid = process.getuid ? process.getuid() : process.pid if (home) process.env.HOME = home else home = path.resolve(temp, 'npm-' + uidOrPid) var cacheExtra = process.platform === 'win32' ? 'npm-cache' : '.npm' var cacheRoot = (process.platform === 'win32' && process.env.APPDATA) || home var cache = path.resolve(cacheRoot, cacheExtra) var globalPrefix Object.defineProperty(exports, 'defaults', {get: function () { if (defaults) return defaults if (process.env.PREFIX) { globalPrefix = process.env.PREFIX } else if (process.platform === 'win32') { // c:\node\node.exe --> prefix=c:\node\ globalPrefix = path.dirname(process.execPath) } else { // /usr/local/bin/node --> prefix=/usr/local globalPrefix = path.dirname(path.dirname(process.execPath)) // destdir only is respected on Unix if (process.env.DESTDIR) { globalPrefix = path.join(process.env.DESTDIR, globalPrefix) } } defaults = { access: null, 'allow-same-version': false, 'always-auth': false, also: null, audit: true, 'audit-level': 'low', 'auth-type': 'legacy', 'before': null, 'bin-links': true, browser: null, ca: null, cafile: null, cache: cache, 'cache-lock-stale': 60000, 'cache-lock-retries': 10, 'cache-lock-wait': 10000, 'cache-max': Infinity, 'cache-min': 10, cert: null, cidr: null, color: process.env.NO_COLOR == null, depth: Infinity, description: true, dev: false, 'dry-run': false, editor: osenv.editor(), 'engine-strict': false, force: false, 'format-package-lock': true, fund: true, 'fetch-retries': 2, 'fetch-retry-factor': 10, 'fetch-retry-mintimeout': 10000, 'fetch-retry-maxtimeout': 60000, git: 'git', 'git-tag-version': true, 'commit-hooks': true, global: false, globalconfig: path.resolve(globalPrefix, 'etc', 'npmrc'), 'global-style': false, group: process.platform === 'win32' ? 0 : process.env.SUDO_GID || (process.getgid && process.getgid()), 'ham-it-up': false, heading: 'npm', 'if-present': false, 'ignore-prepublish': false, 'ignore-scripts': false, 'init-module': path.resolve(home, '.npm-init.js'), 'init-author-name': '', 'init-author-email': '', 'init-author-url': '', 'init-version': '1.0.0', 'init-license': 'ISC', json: false, key: null, 'legacy-bundling': false, link: false, 'local-address': undefined, loglevel: 'notice', logstream: process.stderr, 'logs-max': 10, long: false, maxsockets: 50, message: '%s', 'metrics-registry': null, 'node-options': null, 'node-version': process.version, 'offline': false, 'onload-script': false, only: null, optional: true, otp: null, 'package-lock': true, 'package-lock-only': false, parseable: false, 'prefer-offline': false, 'prefer-online': false, prefix: globalPrefix, preid: '', production: process.env.NODE_ENV === 'production', 'progress': !process.env.TRAVIS && !process.env.CI, proxy: null, 'https-proxy': null, 'noproxy': null, 'user-agent': 'npm/{npm-version} ' + 'node/{node-version} ' + '{platform} ' + '{arch} ' + '{ci}', 'read-only': false, 'rebuild-bundle': true, registry: 'https://registry.npmjs.org/', rollback: true, save: true, 'save-bundle': false, 'save-dev': false, 'save-exact': false, 'save-optional': false, 'save-prefix': '^', 'save-prod': false, scope: '', 'script-shell': null, 'scripts-prepend-node-path': 'warn-only', searchopts: '', searchexclude: null, searchlimit: 20, searchstaleness: 15 * 60, 'send-metrics': false, shell: osenv.shell(), shrinkwrap: true, 'sign-git-commit': false, 'sign-git-tag': false, 'sso-poll-frequency': 500, 'sso-type': 'oauth', 'strict-ssl': true, tag: 'latest', 'tag-version-prefix': 'v', timing: false, tmp: temp, unicode: hasUnicode(), 'unsafe-perm': process.platform === 'win32' || process.platform === 'cygwin' || !(process.getuid && process.setuid && process.getgid && process.setgid) || process.getuid() !== 0, 'update-notifier': true, usage: false, user: (process.platform === 'win32' || os.type() === 'OS400') ? 0 : 'nobody', userconfig: path.resolve(home, '.npmrc'), umask: process.umask ? process.umask() : umask.fromString('022'), version: false, versions: false, viewer: process.platform === 'win32' ? 'browser' : 'man', _exit: true } return defaults }}) exports.types = { access: [null, 'restricted', 'public'], 'allow-same-version': Boolean, 'always-auth': Boolean, also: [null, 'dev', 'development'], audit: Boolean, 'audit-level': ['low', 'moderate', 'high', 'critical'], 'auth-type': ['legacy', 'sso', 'saml', 'oauth'], 'before': [null, Date], 'bin-links': Boolean, browser: [null, String], ca: [null, String, Array], cafile: path, cache: path, 'cache-lock-stale': Number, 'cache-lock-retries': Number, 'cache-lock-wait': Number, 'cache-max': Number, 'cache-min': Number, cert: [null, String], cidr: [null, String, Array], color: ['always', Boolean], depth: Number, description: Boolean, dev: Boolean, 'dry-run': Boolean, editor: String, 'engine-strict': Boolean, force: Boolean, fund: Boolean, 'format-package-lock': Boolean, 'fetch-retries': Number, 'fetch-retry-factor': Number, 'fetch-retry-mintimeout': Number, 'fetch-retry-maxtimeout': Number, git: String, 'git-tag-version': Boolean, 'commit-hooks': Boolean, global: Boolean, globalconfig: path, 'global-style': Boolean, group: [Number, String], 'https-proxy': [null, url], 'user-agent': String, 'ham-it-up': Boolean, 'heading': String, 'if-present': Boolean, 'ignore-prepublish': Boolean, 'ignore-scripts': Boolean, 'init-module': path, 'init-author-name': String, 'init-author-email': String, 'init-author-url': ['', url], 'init-license': String, 'init-version': semver, json: Boolean, key: [null, String], 'legacy-bundling': Boolean, link: Boolean, 'local-address': getLocalAddresses(), loglevel: ['silent', 'error', 'warn', 'notice', 'http', 'timing', 'info', 'verbose', 'silly'], logstream: Stream, 'logs-max': Number, long: Boolean, maxsockets: Number, message: String, 'metrics-registry': [null, String], 'node-options': [null, String], 'node-version': [null, semver], 'noproxy': [null, String, Array], offline: Boolean, 'onload-script': [null, String], only: [null, 'dev', 'development', 'prod', 'production'], optional: Boolean, 'package-lock': Boolean, otp: [null, String], 'package-lock-only': Boolean, parseable: Boolean, 'prefer-offline': Boolean, 'prefer-online': Boolean, prefix: path, preid: String, production: Boolean, progress: Boolean, proxy: [null, false, url], // allow proxy to be disabled explicitly 'read-only': Boolean, 'rebuild-bundle': Boolean, registry: [null, url], rollback: Boolean, save: Boolean, 'save-bundle': Boolean, 'save-dev': Boolean, 'save-exact': Boolean, 'save-optional': Boolean, 'save-prefix': String, 'save-prod': Boolean, scope: String, 'script-shell': [null, String], 'scripts-prepend-node-path': [false, true, 'auto', 'warn-only'], searchopts: String, searchexclude: [null, String], searchlimit: Number, searchstaleness: Number, 'send-metrics': Boolean, shell: String, shrinkwrap: Boolean, 'sign-git-commit': Boolean, 'sign-git-tag': Boolean, 'sso-poll-frequency': Number, 'sso-type': [null, 'oauth', 'saml'], 'strict-ssl': Boolean, tag: String, timing: Boolean, tmp: path, unicode: Boolean, 'unsafe-perm': Boolean, 'update-notifier': Boolean, usage: Boolean, user: [Number, String], userconfig: path, umask: Umask, version: Boolean, 'tag-version-prefix': String, versions: Boolean, viewer: String, _exit: Boolean } function getLocalAddresses () { var interfaces // #8094: some environments require elevated permissions to enumerate // interfaces, and synchronously throw EPERM when run without // elevated privileges try { interfaces = os.networkInterfaces() } catch (e) { interfaces = {} } return Object.keys(interfaces).map( nic => interfaces[nic].map(({address}) => address) ).reduce((curr, next) => curr.concat(next), []).concat(undefined) } exports.shorthands = { before: ['--enjoy-by'], s: ['--loglevel', 'silent'], d: ['--loglevel', 'info'], dd: ['--loglevel', 'verbose'], ddd: ['--loglevel', 'silly'], noreg: ['--no-registry'], N: ['--no-registry'], reg: ['--registry'], 'no-reg': ['--no-registry'], silent: ['--loglevel', 'silent'], verbose: ['--loglevel', 'verbose'], quiet: ['--loglevel', 'warn'], q: ['--loglevel', 'warn'], h: ['--usage'], H: ['--usage'], '?': ['--usage'], help: ['--usage'], v: ['--version'], f: ['--force'], desc: ['--description'], 'no-desc': ['--no-description'], 'local': ['--no-global'], l: ['--long'], m: ['--message'], p: ['--parseable'], porcelain: ['--parseable'], readonly: ['--read-only'], g: ['--global'], S: ['--save'], D: ['--save-dev'], E: ['--save-exact'], O: ['--save-optional'], P: ['--save-prod'], y: ['--yes'], n: ['--no-yes'], B: ['--save-bundle'], C: ['--prefix'] } config/figgy-config.js000064400000004473152231567040010734 0ustar00'use strict' const BB = require('bluebird') const crypto = require('crypto') const figgyPudding = require('figgy-pudding') const log = require('npmlog') const npm = require('../npm.js') const pack = require('../pack.js') const path = require('path') const npmSession = npm.session = crypto.randomBytes(8).toString('hex') log.verbose('npm-session', npmSession) const SCOPE_REGISTRY_REGEX = /@.*:registry$/gi const NpmConfig = figgyPudding({}, { other (key) { return key.match(SCOPE_REGISTRY_REGEX) } }) let baseConfig module.exports = mkConfig function mkConfig (...providers) { if (!baseConfig) { baseConfig = NpmConfig(npm.config, { // Add some non-npm-config opts by hand. cache: path.join(npm.config.get('cache'), '_cacache'), // NOTE: npm has some magic logic around color distinct from the config // value, so we have to override it here color: !!npm.color, dirPacker: pack.packGitDep, hashAlgorithm: 'sha1', includeDeprecated: false, log, 'npm-session': npmSession, 'project-scope': npm.projectScope, refer: npm.referer, dmode: npm.modes.exec, fmode: npm.modes.file, umask: npm.modes.umask, npmVersion: npm.version, tmp: npm.tmp, Promise: BB }) const ownerStats = calculateOwner() if (ownerStats.uid != null || ownerStats.gid != null) { baseConfig = baseConfig.concat(ownerStats) } } let conf = baseConfig.concat(...providers) // Adapt some other configs if missing if (npm.config.get('prefer-online') === undefined) { conf = conf.concat({ 'prefer-online': npm.config.get('cache-max') <= 0 }) } if (npm.config.get('prefer-online') === undefined) { conf = conf.concat({ 'prefer-online': npm.config.get('cache-min') >= 9999 }) } return conf } let effectiveOwner function calculateOwner () { if (!effectiveOwner) { effectiveOwner = { uid: 0, gid: 0 } // Pretty much only on windows if (!process.getuid) { return effectiveOwner } effectiveOwner.uid = +process.getuid() effectiveOwner.gid = +process.getgid() if (effectiveOwner.uid === 0) { if (process.env.SUDO_UID) effectiveOwner.uid = +process.env.SUDO_UID if (process.env.SUDO_GID) effectiveOwner.gid = +process.env.SUDO_GID } } return effectiveOwner } config/gentle-fs.js000064400000001257152231567040010245 0ustar00'use strict' const npm = require('../npm.js') const log = require('npmlog') module.exports = gentleFSOpts function gentleFSOpts (gently, base, abs) { return { // never rm the root, prefix, or bin dirs // // globals included because of `npm link` -- as far as the package // requesting the link is concerned, the linked package is always // installed globally prefixes: [ npm.prefix, npm.globalPrefix, npm.dir, npm.root, npm.globalDir, npm.bin, npm.globalBin ], absolute: abs, log: log, prefix: npm.prefix, force: npm.config.get('force'), gently: gently, base: base, name: 'npm' } } config/get-credentials-by-uri.js000064400000004242152231567040012635 0ustar00var assert = require('assert') var toNerfDart = require('./nerf-dart.js') module.exports = getCredentialsByURI function getCredentialsByURI (uri) { assert(uri && typeof uri === 'string', 'registry URL is required') var nerfed = toNerfDart(uri) var defnerf = toNerfDart(this.get('registry')) // hidden class micro-optimization var c = { scope: nerfed, token: undefined, password: undefined, username: undefined, email: undefined, auth: undefined, alwaysAuth: undefined } // used to override scope matching for tokens as well as legacy auth if (this.get(nerfed + ':always-auth') !== undefined) { var val = this.get(nerfed + ':always-auth') c.alwaysAuth = val === 'false' ? false : !!val } else if (this.get('always-auth') !== undefined) { c.alwaysAuth = this.get('always-auth') } if (this.get(nerfed + ':_authToken')) { c.token = this.get(nerfed + ':_authToken') // the bearer token is enough, don't confuse things return c } if (this.get(nerfed + ':-authtoken')) { c.token = this.get(nerfed + ':-authtoken') // the bearer token is enough, don't confuse things return c } // Handle the old-style _auth= style for the default // registry, if set. var authDef = this.get('_auth') var userDef = this.get('username') var passDef = this.get('_password') if (authDef && !(userDef && passDef)) { authDef = Buffer.from(authDef, 'base64').toString() authDef = authDef.split(':') userDef = authDef.shift() passDef = authDef.join(':') } if (this.get(nerfed + ':_password')) { c.password = Buffer.from(this.get(nerfed + ':_password'), 'base64').toString('utf8') } else if (nerfed === defnerf && passDef) { c.password = passDef } if (this.get(nerfed + ':username')) { c.username = this.get(nerfed + ':username') } else if (nerfed === defnerf && userDef) { c.username = userDef } if (this.get(nerfed + ':email')) { c.email = this.get(nerfed + ':email') } else if (this.get('email')) { c.email = this.get('email') } if (c.username && c.password) { c.auth = Buffer.from(c.username + ':' + c.password).toString('base64') } return c } config/lifecycle.js000064400000001523152231567040010314 0ustar00'use strict' const npm = require('../npm.js') const log = require('npmlog') module.exports = lifecycleOpts let opts function lifecycleOpts (moreOpts) { if (!opts) { opts = { config: npm.config.snapshot, dir: npm.dir, failOk: false, force: npm.config.get('force'), group: npm.config.get('group'), ignorePrepublish: npm.config.get('ignore-prepublish'), ignoreScripts: npm.config.get('ignore-scripts'), log: log, nodeOptions: npm.config.get('node-options'), production: npm.config.get('production'), scriptShell: npm.config.get('script-shell'), scriptsPrependNodePath: npm.config.get('scripts-prepend-node-path'), unsafePerm: npm.config.get('unsafe-perm'), user: npm.config.get('user') } } return moreOpts ? Object.assign({}, opts, moreOpts) : opts } config/load-cafile.js000064400000001252152231567040010514 0ustar00module.exports = loadCAFile var fs = require('fs') function loadCAFile (cafilePath, cb) { if (!cafilePath) return process.nextTick(cb) fs.readFile(cafilePath, 'utf8', afterCARead.bind(this)) function afterCARead (er, cadata) { if (er) { // previous cafile no longer exists, so just continue on gracefully if (er.code === 'ENOENT') return cb() return cb(er) } var delim = '-----END CERTIFICATE-----' var output output = cadata .split(delim) .filter(function (xs) { return !!xs.trim() }) .map(function (xs) { return xs.trimLeft() + delim }) this.set('ca', output) cb(null) } } config/load-prefix.js000064400000002463152231567040010573 0ustar00module.exports = loadPrefix var findPrefix = require('find-npm-prefix') var path = require('path') function loadPrefix (cb) { var cli = this.list[0] Object.defineProperty(this, 'prefix', { set: function (prefix) { var g = this.get('global') this[g ? 'globalPrefix' : 'localPrefix'] = prefix }.bind(this), get: function () { var g = this.get('global') return g ? this.globalPrefix : this.localPrefix }.bind(this), enumerable: true }) Object.defineProperty(this, 'globalPrefix', { set: function (prefix) { this.set('prefix', prefix) }.bind(this), get: function () { return path.resolve(this.get('prefix')) }.bind(this), enumerable: true }) var p Object.defineProperty(this, 'localPrefix', { set: function (prefix) { p = prefix }, get: function () { return p }, enumerable: true }) // try to guess at a good node_modules location. // If we are *explicitly* given a prefix on the cli, then // always use that. otherwise, infer local prefix from cwd. if (Object.prototype.hasOwnProperty.call(cli, 'prefix')) { p = path.resolve(cli.prefix) process.nextTick(cb) } else { findPrefix(process.cwd()).then((found) => { p = found cb() }, cb) } } config/nerf-dart.js000064400000000727152231567040010244 0ustar00var url = require('url') module.exports = toNerfDart /** * Maps a URL to an identifier. * * Name courtesy schiffertronix media LLC, a New Jersey corporation * * @param {String} uri The URL to be nerfed. * * @returns {String} A nerfed URL. */ function toNerfDart (uri) { var parsed = url.parse(uri) delete parsed.protocol delete parsed.auth delete parsed.query delete parsed.search delete parsed.hash return url.resolve(url.format(parsed), '.') } config/set-credentials-by-uri.js000064400000002363152231567040012653 0ustar00var assert = require('assert') var toNerfDart = require('./nerf-dart.js') module.exports = setCredentialsByURI function setCredentialsByURI (uri, c) { assert(uri && typeof uri === 'string', 'registry URL is required') assert(c && typeof c === 'object', 'credentials are required') var nerfed = toNerfDart(uri) if (c.token) { this.set(nerfed + ':_authToken', c.token, 'user') this.del(nerfed + ':_password', 'user') this.del(nerfed + ':username', 'user') this.del(nerfed + ':email', 'user') this.del(nerfed + ':always-auth', 'user') } else if (c.username || c.password || c.email) { assert(c.username, 'must include username') assert(c.password, 'must include password') assert(c.email, 'must include email address') this.del(nerfed + ':_authToken', 'user') var encoded = Buffer.from(c.password, 'utf8').toString('base64') this.set(nerfed + ':_password', encoded, 'user') this.set(nerfed + ':username', c.username, 'user') this.set(nerfed + ':email', c.email, 'user') if (c.alwaysAuth !== undefined) { this.set(nerfed + ':always-auth', c.alwaysAuth, 'user') } else { this.del(nerfed + ':always-auth', 'user') } } else { throw new Error('No credentials to set.') } } config/set-user.js000064400000001366152231567040010131 0ustar00module.exports = setUser var assert = require('assert') var path = require('path') var fs = require('fs') var mkdirp = require('gentle-fs').mkdir function setUser (cb) { var defaultConf = this.root assert(defaultConf !== Object.prototype) // If global, leave it as-is. // If not global, then set the user to the owner of the prefix folder. // Just set the default, so it can be overridden. if (this.get('global')) return cb() if (process.env.SUDO_UID) { defaultConf.user = +(process.env.SUDO_UID) return cb() } var prefix = path.resolve(this.get('prefix')) mkdirp(prefix, function (er) { if (er) return cb(er) fs.stat(prefix, function (er, st) { defaultConf.user = st && st.uid return cb(er) }) }) } doctor/check-files-permission.js000064400000003671152231567040012753 0ustar00var fs = require('fs') var path = require('path') var getUid = require('uid-number') var chain = require('slide').chain var log = require('npmlog') var npm = require('../npm.js') var fileCompletion = require('../utils/completion/file-completion.js') function checkFilesPermission (root, fmask, dmask, cb) { if (process.platform === 'win32') return cb(null, true) getUid(npm.config.get('user'), npm.config.get('group'), function (e, uid, gid) { var tracker = log.newItem('checkFilePermissions', 1) if (e) { tracker.finish() tracker.warn('checkFilePermissions', 'Error looking up user and group:', e) return cb(e) } tracker.info('checkFilePermissions', 'Building file list of ' + root) fileCompletion(root, '.', Infinity, function (e, files) { if (e) { tracker.warn('checkFilePermissions', 'Error building file list:', e) tracker.finish() return cb(e) } tracker.addWork(files.length) tracker.completeWork(1) chain(files.map(andCheckFile), function (er) { tracker.finish() cb(null, !er) }) function andCheckFile (f) { return [checkFile, f] } function checkFile (f, next) { var file = path.join(root, f) tracker.silly('checkFilePermissions', f) fs.lstat(file, function (e, stat) { tracker.completeWork(1) if (e) return next(e) if (!stat.isDirectory() && !stat.isFile()) return next() // 6 = fs.constants.R_OK | fs.constants.W_OK // constants aren't available on v4 fs.access(file, stat.isFile() ? fmask : dmask, (err) => { if (err) { tracker.error('checkFilePermissions', `Missing permissions on ${file}`) return next(new Error('Missing permissions for ' + file)) } else { return next() } }) }) } }) }) } module.exports = checkFilesPermission doctor/check-ping.js000064400000000627152231567040010416 0ustar00var log = require('npmlog') var ping = require('../ping.js') function checkPing (cb) { var tracker = log.newItem('checkPing', 1) tracker.info('checkPing', 'Pinging registry') ping({}, true, (err, pong) => { if (err && err.code && err.code.match(/^E\d{3}$/)) { return cb(null, [err.code.substr(1), 'failed']) } else { cb(null, [200, 'ok']) } }) } module.exports = checkPing doctor/get-git-path.js000064400000000454152231567040010676 0ustar00var log = require('npmlog') var which = require('which') function getGitPath (cb) { var tracker = log.newItem('getGitPath', 1) tracker.info('getGitPath', 'Finding git in your PATH') which('git', function (err, path) { tracker.finish() cb(err, path) }) } module.exports = getGitPath doctor/get-latest-nodejs-version.js000064400000001440152231567040013414 0ustar00var log = require('npmlog') var request = require('request') var semver = require('semver') function getLatestNodejsVersion (url, cb) { var tracker = log.newItem('getLatestNodejsVersion', 1) tracker.info('getLatestNodejsVersion', 'Getting Node.js release information') var version = 'v0.0.0' url = url || 'https://nodejs.org/dist/index.json' request(url, function (e, res, index) { tracker.finish() if (e) return cb(e) if (res.statusCode !== 200) { return cb(new Error('Status not 200, ' + res.statusCode)) } try { JSON.parse(index).forEach(function (item) { if (item.lts && semver.gt(item.version, version)) version = item.version }) cb(null, version) } catch (e) { cb(e) } }) } module.exports = getLatestNodejsVersion doctor/get-latest-npm-version.js000064400000000674152231567040012734 0ustar00var log = require('npmlog') var fetchPackageMetadata = require('../fetch-package-metadata') function getLatestNpmVersion (cb) { var tracker = log.newItem('getLatestNpmVersion', 1) tracker.info('getLatestNpmVersion', 'Getting npm package information') fetchPackageMetadata('npm@latest', '.', {}, function (err, d) { tracker.finish() if (err) { return cb(err) } cb(null, d.version) }) } module.exports = getLatestNpmVersion doctor/verify-cached-files.js000064400000001641152231567040012214 0ustar00'use strict' const cacache = require('cacache') const log = require('npmlog') module.exports = verifyCachedFiles function verifyCachedFiles (cache, cb) { log.info('verifyCachedFiles', `Verifying cache at ${cache}`) cacache.verify(cache).then((stats) => { log.info('verifyCachedFiles', `Verification complete. Stats: ${JSON.stringify(stats, 2)}`) if (stats.reclaimedCount || stats.badContentCount || stats.missingContent) { stats.badContentCount && log.warn('verifyCachedFiles', `Corrupted content removed: ${stats.badContentCount}`) stats.reclaimedCount && log.warn('verifyCachedFiles', `Content garbage-collected: ${stats.reclaimedCount} (${stats.reclaimedSize} bytes)`) stats.missingContent && log.warn('verifyCachedFiles', `Missing content: ${stats.missingContent}`) log.warn('verifyCachedFiles', 'Cache issues have been fixed') } return stats }).then((s) => cb(null, s), cb) } install-test.js000064400000000773152231567040007541 0ustar00'use strict' // npm install-test // Runs `npm install` and then runs `npm test` module.exports = installTest var install = require('./install.js') var test = require('./test.js') var usage = require('./utils/usage') installTest.usage = usage( 'install-test', '\nnpm install-test [args]' + '\nSame args as `npm install`' ) installTest.completion = install.completion function installTest (args, cb) { install(args, function (er) { if (er) { return cb(er) } test([], cb) }) } link.js000064400000013153152231567040006047 0ustar00// link with no args: symlink the folder to the global location // link with package arg: symlink the global to the local var npm = require('./npm.js') var symlink = require('./utils/link.js') var fs = require('graceful-fs') var log = require('npmlog') var asyncMap = require('slide').asyncMap var chain = require('slide').chain var path = require('path') var build = require('./build.js') var npa = require('npm-package-arg') var usage = require('./utils/usage') var output = require('./utils/output.js') module.exports = link link.usage = usage( 'link', 'npm link (in package dir)' + '\nnpm link [<@scope>/][@]' ) link.completion = function (opts, cb) { var dir = npm.globalDir fs.readdir(dir, function (er, files) { cb(er, files.filter(function (f) { return !f.match(/^[._-]/) })) }) } function link (args, cb) { if (process.platform === 'win32') { var semver = require('semver') if (!semver.gte(process.version, '0.7.9')) { var msg = 'npm link not supported on windows prior to node 0.7.9' var e = new Error(msg) e.code = 'ENOTSUP' e.errno = require('constants').ENOTSUP // eslint-disable-line node/no-deprecated-api return cb(e) } } if (npm.config.get('global')) { return cb(new Error( 'link should never be --global.\n' + 'Please re-run this command with --local' )) } if (args.length === 1 && args[0] === '.') args = [] if (args.length) return linkInstall(args, cb) linkPkg(npm.prefix, cb) } function parentFolder (id, folder) { if (id[0] === '@') { return path.resolve(folder, '..', '..') } else { return path.resolve(folder, '..') } } function linkInstall (pkgs, cb) { asyncMap(pkgs, function (pkg, cb) { var t = path.resolve(npm.globalDir, '..') var pp = path.resolve(npm.globalDir, pkg) var rp = null var target = path.resolve(npm.dir, pkg) function n (er, data) { if (er) return cb(er, data) // we want the ONE thing that was installed into the global dir var installed = data.filter(function (info) { var id = info[0] var folder = info[1] return parentFolder(id, folder) === npm.globalDir }) var id = installed[0][0] pp = installed[0][1] var what = npa(id) pkg = what.name target = path.resolve(npm.dir, pkg) next() } // if it's a folder, a random not-installed thing, or not a scoped package, // then link or install it first if (pkg[0] !== '@' && (pkg.indexOf('/') !== -1 || pkg.indexOf('\\') !== -1)) { return fs.lstat(path.resolve(pkg), function (er, st) { if (er || !st.isDirectory()) { npm.commands.install(t, pkg, n) } else { rp = path.resolve(pkg) linkPkg(rp, n) } }) } fs.lstat(pp, function (er, st) { if (er) { rp = pp return npm.commands.install(t, [pkg], n) } else if (!st.isSymbolicLink()) { rp = pp next() } else { return fs.realpath(pp, function (er, real) { if (er) log.warn('invalid symbolic link', pkg) else rp = real next() }) } }) function next () { if (npm.config.get('dry-run')) return resultPrinter(pkg, pp, target, rp, cb) chain( [ [ function (cb) { log.verbose('link', 'symlinking %s to %s', pp, target) cb() } ], [symlink, pp, target, false, false], // do not run any scripts rp && [build, [target], npm.config.get('global'), build._noLC, true], [resultPrinter, pkg, pp, target, rp] ], cb ) } }, cb) } function linkPkg (folder, cb_) { var me = folder || npm.prefix var readJson = require('read-package-json') log.verbose('linkPkg', folder) readJson(path.resolve(me, 'package.json'), function (er, d) { function cb (er) { return cb_(er, [[d && d._id, target, null, null]]) } if (er) return cb(er) if (!d.name) { er = new Error('Package must have a name field to be linked') return cb(er) } var target = path.resolve(npm.globalDir, d.name) if (npm.config.get('dry-run')) return resultPrinter(path.basename(me), me, target, cb) symlink(me, target, false, true, function (er) { if (er) return cb(er) log.verbose('link', 'build target', target) // also install missing dependencies. npm.commands.install(me, [], function (er) { if (er) return cb(er) // build the global stuff. Don't run *any* scripts, because // install command already will have done that. build([target], true, build._noLC, true, function (er) { if (er) return cb(er) resultPrinter(path.basename(me), me, target, cb) }) }) }) }) } function resultPrinter (pkg, src, dest, rp, cb) { if (typeof cb !== 'function') { cb = rp rp = null } var where = dest rp = (rp || '').trim() src = (src || '').trim() // XXX If --json is set, then look up the data from the package.json if (npm.config.get('parseable')) { return parseableOutput(dest, rp || src, cb) } if (rp === src) rp = null output(where + ' -> ' + src + (rp ? ' -> ' + rp : '')) cb() } function parseableOutput (dest, rp, cb) { // XXX this should match ls --parseable and install --parseable // look up the data from package.json, format it the same way. // // link is always effectively 'long', since it doesn't help much to // *just* print the target folder. // However, we don't actually ever read the version number, so // the second field is always blank. output(dest + '::' + rp) cb() } ls.js000064400000040140152231567040005524 0ustar00// show the installed versions of packages // // --parseable creates output like this: // ::: // Flags are a :-separated list of zero or more indicators module.exports = exports = ls var path = require('path') var url = require('url') var readPackageTree = require('read-package-tree') var archy = require('archy') var semver = require('semver') var color = require('ansicolors') var moduleName = require('./utils/module-name.js') var npa = require('npm-package-arg') var sortedObject = require('sorted-object') var npm = require('./npm.js') var mutateIntoLogicalTree = require('./install/mutate-into-logical-tree.js') var computeMetadata = require('./install/deps.js').computeMetadata var readShrinkwrap = require('./install/read-shrinkwrap.js') var packageId = require('./utils/package-id.js') var usage = require('./utils/usage') var output = require('./utils/output.js') ls.usage = usage( 'ls', 'npm ls [[<@scope>/] ...]' ) ls.completion = require('./utils/completion/installed-deep.js') function ls (args, silent, cb) { if (typeof cb !== 'function') { cb = silent silent = false } var dir = path.resolve(npm.dir, '..') readPackageTree(dir, function (_, physicalTree) { if (!physicalTree) physicalTree = {package: {}, path: dir} physicalTree.isTop = true readShrinkwrap.andInflate(physicalTree, function () { lsFromTree(dir, computeMetadata(physicalTree), args, silent, cb) }) }) } function inList (list, value) { return list.indexOf(value) !== -1 } var lsFromTree = ls.fromTree = function (dir, physicalTree, args, silent, cb) { if (typeof cb !== 'function') { cb = silent silent = false } // npm ls 'foo@~1.3' bar 'baz@<2' if (!args) { args = [] } else { args = args.map(function (a) { if (typeof a === 'object' && a.package._requested.type === 'alias') { return [moduleName(a), `npm:${a.package.name}@${a.package.version}`, a] } else if (typeof a === 'object') { return [a.package.name, a.package.version, a] } else { var p = npa(a) var name = p.name // When version spec is missing, we'll skip using it when filtering. // Otherwise, `semver.validRange` would return '*', which won't // match prerelease versions. var ver = (p.rawSpec && (semver.validRange(p.rawSpec) || '')) return [ name, ver, a ] } }) } var data = mutateIntoLogicalTree.asReadInstalled(physicalTree) pruneNestedExtraneous(data) filterByEnv(data) filterByLink(data) var unlooped = filterFound(unloop(data), args) var lite = getLite(unlooped) if (silent) return cb(null, data, lite) var long = npm.config.get('long') var json = npm.config.get('json') var out if (json) { var seen = new Set() var d = long ? unlooped : lite // the raw data can be circular out = JSON.stringify(d, function (k, o) { if (typeof o === 'object') { if (seen.has(o)) return '[Circular]' seen.add(o) } return o }, 2) } else if (npm.config.get('parseable')) { out = makeParseable(unlooped, long, dir) } else if (data) { out = makeArchy(unlooped, long, dir) } output(out) if (args.length && !data._found) process.exitCode = 1 var er // if any errors were found, then complain and exit status 1 if (lite.problems && lite.problems.length) { er = lite.problems.join('\n') } cb(er, data, lite) } function pruneNestedExtraneous (data, visited) { visited = visited || [] visited.push(data) for (var i in data.dependencies) { if (data.dependencies[i].extraneous) { data.dependencies[i].dependencies = {} } else if (visited.indexOf(data.dependencies[i]) === -1) { pruneNestedExtraneous(data.dependencies[i], visited) } } } function filterByEnv (data) { var dev = npm.config.get('dev') || /^dev(elopment)?$/.test(npm.config.get('only')) var production = npm.config.get('production') || /^prod(uction)?$/.test(npm.config.get('only')) var dependencies = {} var devKeys = Object.keys(data.devDependencies || []) var prodKeys = Object.keys(data._dependencies || []) Object.keys(data.dependencies).forEach(function (name) { if (!dev && inList(devKeys, name) && !inList(prodKeys, name) && data.dependencies[name].missing) { return } if ((dev && inList(devKeys, name)) || // only --dev (production && inList(prodKeys, name)) || // only --production (!dev && !production)) { // no --production|--dev|--only=xxx dependencies[name] = data.dependencies[name] } }) data.dependencies = dependencies } function filterByLink (data) { if (npm.config.get('link')) { var dependencies = {} Object.keys(data.dependencies).forEach(function (name) { var dependency = data.dependencies[name] if (dependency.link) { dependencies[name] = dependency } }) data.dependencies = dependencies } } function alphasort (a, b) { a = a.toLowerCase() b = b.toLowerCase() return a > b ? 1 : a < b ? -1 : 0 } function isCruft (data) { return data.extraneous && data.error && data.error.code === 'ENOTDIR' } function getLite (data, noname, depth) { var lite = {} if (isCruft(data)) return lite var maxDepth = npm.config.get('depth') if (typeof depth === 'undefined') depth = 0 if (!noname && data.name) lite.name = data.name if (data.version) lite.version = data.version if (data.extraneous) { lite.extraneous = true lite.problems = lite.problems || [] lite.problems.push('extraneous: ' + packageId(data) + ' ' + (data.path || '')) } if (data.error && data.path !== path.resolve(npm.globalDir, '..') && (data.error.code !== 'ENOENT' || noname)) { lite.invalid = true lite.problems = lite.problems || [] var message = data.error.message lite.problems.push('error in ' + data.path + ': ' + message) } if (data._from) { lite.from = data._from } if (data._resolved) { lite.resolved = data._resolved } if (data.invalid) { lite.invalid = true lite.problems = lite.problems || [] lite.problems.push('invalid: ' + packageId(data) + ' ' + (data.path || '')) } if (data.peerInvalid) { lite.peerInvalid = true lite.problems = lite.problems || [] lite.problems.push('peer dep not met: ' + packageId(data) + ' ' + (data.path || '')) } var deps = (data.dependencies && Object.keys(data.dependencies)) || [] if (deps.length) { lite.dependencies = deps.map(function (d) { var dep = data.dependencies[d] if (dep.missing && !dep.optional) { lite.problems = lite.problems || [] var p if (data.depth > maxDepth) { p = 'max depth reached: ' } else { p = 'missing: ' } p += d + '@' + dep.requiredBy + ', required by ' + packageId(data) lite.problems.push(p) if (dep.dependencies) { return [d, getLite(dep, true)] } else { return [d, { required: dep.requiredBy, missing: true }] } } else if (dep.peerMissing) { lite.problems = lite.problems || [] dep.peerMissing.forEach(function (missing) { var pdm = 'peer dep missing: ' + missing.requires + ', required by ' + missing.requiredBy lite.problems.push(pdm) }) return [d, { required: dep, peerMissing: true }] } else if (npm.config.get('json')) { if (depth === maxDepth) delete dep.dependencies return [d, getLite(dep, true, depth + 1)] } return [d, getLite(dep, true)] }).reduce(function (deps, d) { if (d[1].problems) { lite.problems = lite.problems || [] lite.problems.push.apply(lite.problems, d[1].problems) } deps[d[0]] = d[1] return deps }, {}) } return lite } function unloop (root) { var queue = [root] var seen = new Set() seen.add(root) while (queue.length) { var current = queue.shift() var deps = current.dependencies = current.dependencies || {} Object.keys(deps).forEach(function (d) { var dep = deps[d] if (dep.missing && !dep.dependencies) return if (dep.path && seen.has(dep)) { dep = deps[d] = Object.assign({}, dep) dep.dependencies = {} dep._deduped = path.relative(root.path, dep.path).replace(/node_modules\//g, '') return } seen.add(dep) queue.push(dep) }) } return root } function filterFound (root, args) { if (!args.length) return root if (!root.dependencies) return root // Mark all deps var toMark = [root] while (toMark.length) { var markPkg = toMark.shift() var markDeps = markPkg.dependencies if (!markDeps) continue Object.keys(markDeps).forEach(function (depName) { var dep = markDeps[depName] if (dep.peerMissing && !dep._from) return dep._parent = markPkg for (var ii = 0; ii < args.length; ii++) { var argName = args[ii][0] var argVersion = args[ii][1] var argRaw = args[ii][2] var found if (typeof argRaw === 'object') { if (dep.path === argRaw.path) { found = true } } else if (depName === argName && argVersion) { found = semver.satisfies(dep.version, argVersion, true) } else if (depName === argName) { // If version is missing from arg, just do a name match. found = true } if (found) { dep._found = 'explicit' var parent = dep._parent while (parent && !parent._found && !parent._deduped) { parent._found = 'implicit' parent = parent._parent } break } } toMark.push(dep) }) } var toTrim = [root] while (toTrim.length) { var trimPkg = toTrim.shift() var trimDeps = trimPkg.dependencies if (!trimDeps) continue trimPkg.dependencies = {} Object.keys(trimDeps).forEach(function (name) { var dep = trimDeps[name] if (!dep._found) return if (dep._found === 'implicit' && dep._deduped) return trimPkg.dependencies[name] = dep toTrim.push(dep) }) } return root } function makeArchy (data, long, dir) { var out = makeArchy_(data, long, dir, 0) return archy(out, '', { unicode: npm.config.get('unicode') }) } function makeArchy_ (data, long, dir, depth, parent, d) { if (data.missing) { if (depth - 1 <= npm.config.get('depth')) { // just missing var unmet = 'UNMET ' + (data.optional ? 'OPTIONAL ' : '') + 'DEPENDENCY' if (npm.color) { if (data.optional) { unmet = color.bgBlack(color.yellow(unmet)) } else { unmet = color.bgBlack(color.red(unmet)) } } var label = data._id || (d + '@' + data.requiredBy) if (data._found === 'explicit' && data._id) { if (npm.color) { label = color.bgBlack(color.yellow(label.trim())) + ' ' } else { label = label.trim() + ' ' } } return { label: unmet + ' ' + label, nodes: Object.keys(data.dependencies || {}) .sort(alphasort).filter(function (d) { return !isCruft(data.dependencies[d]) }).map(function (d) { return makeArchy_(sortedObject(data.dependencies[d]), long, dir, depth + 1, data, d) }) } } else { return {label: d + '@' + data.requiredBy} } } var out = {} if (data._requested && data._requested.type === 'alias') { out.label = `${d}@npm:${data._id}` } else { out.label = data._id || '' } if (data._found === 'explicit' && data._id) { if (npm.color) { out.label = color.bgBlack(color.yellow(out.label.trim())) + ' ' } else { out.label = out.label.trim() + ' ' } } if (data.link) out.label += ' -> ' + data.link if (data._deduped) { if (npm.color) { out.label += ' ' + color.brightBlack('deduped') } else { out.label += ' deduped' } } if (data.invalid) { if (data.realName !== data.name) out.label += ' (' + data.realName + ')' var invalid = 'invalid' if (npm.color) invalid = color.bgBlack(color.red(invalid)) out.label += ' ' + invalid } if (data.peerInvalid) { var peerInvalid = 'peer invalid' if (npm.color) peerInvalid = color.bgBlack(color.red(peerInvalid)) out.label += ' ' + peerInvalid } if (data.peerMissing) { var peerMissing = 'UNMET PEER DEPENDENCY' if (npm.color) peerMissing = color.bgBlack(color.red(peerMissing)) out.label = peerMissing + ' ' + out.label } if (data.extraneous && data.path !== dir) { var extraneous = 'extraneous' if (npm.color) extraneous = color.bgBlack(color.green(extraneous)) out.label += ' ' + extraneous } if (data.error && depth) { var message = data.error.message if (message.indexOf('\n')) message = message.slice(0, message.indexOf('\n')) var error = 'error: ' + message if (npm.color) error = color.bgRed(color.brightWhite(error)) out.label += ' ' + error } // add giturl to name@version if (data._resolved) { try { var type = npa(data._resolved).type var isGit = type === 'git' || type === 'hosted' if (isGit) { out.label += ' (' + data._resolved + ')' } } catch (ex) { // npa threw an exception then it ain't git so whatev } } if (long) { if (dir === data.path) out.label += '\n' + dir out.label += '\n' + getExtras(data) } else if (dir === data.path) { if (out.label) out.label += ' ' out.label += dir } // now all the children. out.nodes = [] if (depth <= npm.config.get('depth')) { out.nodes = Object.keys(data.dependencies || {}) .sort(alphasort).filter(function (d) { return !isCruft(data.dependencies[d]) }).map(function (d) { return makeArchy_(sortedObject(data.dependencies[d]), long, dir, depth + 1, data, d) }) } if (out.nodes.length === 0 && data.path === dir) { out.nodes = ['(empty)'] } return out } function getExtras (data) { var extras = [] if (data.description) extras.push(data.description) if (data.repository) extras.push(data.repository.url) if (data.homepage) extras.push(data.homepage) if (data._from) { var from = data._from if (from.indexOf(data.name + '@') === 0) { from = from.substr(data.name.length + 1) } var u = url.parse(from) if (u.protocol) extras.push(from) } return extras.join('\n') } function makeParseable (data, long, dir, depth, parent, d) { if (data._deduped) return [] depth = depth || 0 if (depth > npm.config.get('depth')) return [ makeParseable_(data, long, dir, depth, parent, d) ] return [ makeParseable_(data, long, dir, depth, parent, d) ] .concat(Object.keys(data.dependencies || {}) .sort(alphasort).map(function (d) { return makeParseable(data.dependencies[d], long, dir, depth + 1, data, d) })) .filter(function (x) { return x && x.length }) .join('\n') } function makeParseable_ (data, long, dir, depth, parent, d) { if (data.hasOwnProperty('_found') && data._found !== 'explicit') return '' if (data.missing) { if (depth < npm.config.get('depth')) { data = npm.config.get('long') ? path.resolve(parent.path, 'node_modules', d) + ':' + d + '@' + JSON.stringify(data.requiredBy) + ':INVALID:MISSING' : '' } else { data = path.resolve(dir || '', 'node_modules', d || '') + (npm.config.get('long') ? ':' + d + '@' + JSON.stringify(data.requiredBy) + ':' + // no realpath resolved ':MAXDEPTH' : '') } return data } if (!npm.config.get('long')) return data.path return data.path + ':' + (data._id || '') + (data.link && data.link !== data.path ? ':' + data.link : '') + (data.extraneous ? ':EXTRANEOUS' : '') + (data.error && data.path !== path.resolve(npm.globalDir, '..') ? ':ERROR' : '') + (data.invalid ? ':INVALID' : '') + (data.peerInvalid ? ':PEERINVALID' : '') + (data.peerMissing ? ':PEERINVALID:MISSING' : '') } npm.js000064400000034577152231567040005721 0ustar00;(function () { // windows: running 'npm blah' in this folder will invoke WSH, not node. /* globals WScript */ if (typeof WScript !== 'undefined') { WScript.echo( 'npm does not work when run\n' + 'with the Windows Scripting Host\n\n' + '"cd" to a different directory,\n' + 'or type "npm.cmd ",\n' + 'or type "node npm ".' ) WScript.quit(1) return } var unsupported = require('../lib/utils/unsupported.js') unsupported.checkForBrokenNode() var gfs = require('graceful-fs') // Patch the global fs module here at the app level var fs = gfs.gracefulify(require('fs')) var EventEmitter = require('events').EventEmitter var npm = module.exports = new EventEmitter() var npmconf = require('./config/core.js') var log = require('npmlog') var inspect = require('util').inspect // capture global logging process.on('log', function (level) { try { return log[level].apply(log, [].slice.call(arguments, 1)) } catch (ex) { log.verbose('attempt to log ' + inspect(arguments) + ' crashed: ' + ex.message) } }) var path = require('path') var abbrev = require('abbrev') var which = require('which') var glob = require('glob') var rimraf = require('rimraf') var parseJSON = require('./utils/parse-json.js') var aliases = require('./config/cmd-list').aliases var cmdList = require('./config/cmd-list').cmdList var plumbing = require('./config/cmd-list').plumbing var output = require('./utils/output.js') var startMetrics = require('./utils/metrics.js').start var perf = require('./utils/perf.js') perf.emit('time', 'npm') perf.on('timing', function (name, finished) { log.timing(name, 'Completed in', finished + 'ms') }) npm.config = { loaded: false, get: function () { throw new Error('npm.load() required') }, set: function () { throw new Error('npm.load() required') } } npm.commands = {} // TUNING npm.limit = { fetch: 10, action: 50 } // *** npm.lockfileVersion = 1 npm.rollbacks = [] try { // startup, ok to do this synchronously var j = parseJSON(fs.readFileSync( path.join(__dirname, '../package.json')) + '') npm.name = j.name npm.version = j.version } catch (ex) { try { log.info('error reading version', ex) } catch (er) {} npm.version = ex } var commandCache = {} var aliasNames = Object.keys(aliases) var littleGuys = [ 'isntall', 'verison' ] var fullList = cmdList.concat(aliasNames).filter(function (c) { return plumbing.indexOf(c) === -1 }) var abbrevs = abbrev(fullList) // we have our reasons fullList = npm.fullList = fullList.filter(function (c) { return littleGuys.indexOf(c) === -1 }) var registryRefer Object.keys(abbrevs).concat(plumbing).forEach(function addCommand (c) { Object.defineProperty(npm.commands, c, { get: function () { if (!loaded) { throw new Error( 'Call npm.load(config, cb) before using this command.\n' + 'See the README.md or bin/npm-cli.js for example usage.' ) } var a = npm.deref(c) if (c === 'la' || c === 'll') { npm.config.set('long', true) } npm.command = c if (commandCache[a]) return commandCache[a] var cmd = require(path.join(__dirname, a + '.js')) commandCache[a] = function () { var args = Array.prototype.slice.call(arguments, 0) if (typeof args[args.length - 1] !== 'function') { args.push(defaultCb) } if (args.length === 1) args.unshift([]) // Options are prefixed by a hyphen-minus (-, \u2d). // Other dash-type chars look similar but are invalid. Array(args[0]).forEach(function (arg) { if (/^[\u2010-\u2015\u2212\uFE58\uFE63\uFF0D]/.test(arg)) { log.error('arg', 'Argument starts with non-ascii dash, this is probably invalid:', arg) } }) if (!registryRefer) { registryRefer = [a].concat(args[0]).map(function (arg) { // exclude anything that might be a URL, path, or private module // Those things will always have a slash in them somewhere if (arg && arg.match && arg.match(/\/|\\/)) { return '[REDACTED]' } else { return arg } }).filter(function (arg) { return arg && arg.match }).join(' ') npm.referer = registryRefer } cmd.apply(npm, args) } Object.keys(cmd).forEach(function (k) { commandCache[a][k] = cmd[k] }) return commandCache[a] }, enumerable: fullList.indexOf(c) !== -1, configurable: true }) // make css-case commands callable via camelCase as well if (c.match(/-([a-z])/)) { addCommand(c.replace(/-([a-z])/g, function (a, b) { return b.toUpperCase() })) } }) function defaultCb (er, data) { log.disableProgress() if (er) console.error(er.stack || er.message) else output(data) } npm.deref = function (c) { if (!c) return '' if (c.match(/[A-Z]/)) { c = c.replace(/([A-Z])/g, function (m) { return '-' + m.toLowerCase() }) } if (plumbing.indexOf(c) !== -1) return c var a = abbrevs[c] while (aliases[a]) { a = aliases[a] } return a } var loaded = false var loading = false var loadErr = null var loadListeners = [] function loadCb (er) { loadListeners.forEach(function (cb) { process.nextTick(cb.bind(npm, er, npm)) }) loadListeners.length = 0 } npm.load = function (cli, cb_) { if (!cb_ && typeof cli === 'function') { cb_ = cli cli = {} } if (!cb_) cb_ = function () {} if (!cli) cli = {} loadListeners.push(cb_) if (loaded || loadErr) return cb(loadErr) if (loading) return loading = true var onload = true function cb (er) { if (loadErr) return loadErr = er if (er) return cb_(er) if (npm.config.get('force')) { log.warn('using --force', 'I sure hope you know what you are doing.') } npm.config.loaded = true loaded = true loadCb(loadErr = er) onload = onload && npm.config.get('onload-script') if (onload) { try { require(onload) } catch (err) { log.warn('onload-script', 'failed to require onload script', onload) log.warn('onload-script', err) } onload = false } } log.pause() load(npm, cli, cb) } function load (npm, cli, cb) { which(process.argv[0], function (er, node) { if (!er && node.toUpperCase() !== process.execPath.toUpperCase()) { log.verbose('node symlink', node) process.execPath = node process.installPrefix = path.resolve(node, '..', '..') } // look up configs var builtin = path.resolve(__dirname, '..', 'npmrc') npmconf.load(cli, builtin, function (er, config) { if (er === config) er = null npm.config = config if (er) return cb(er) // if the 'project' config is not a filename, and we're // not in global mode, then that means that it collided // with either the default or effective userland config if (!config.get('global') && config.sources.project && config.sources.project.type !== 'ini') { log.verbose( 'config', 'Skipping project config: %s. (matches userconfig)', config.localPrefix + '/.npmrc' ) } // Include npm-version and node-version in user-agent var ua = config.get('user-agent') || '' ua = ua.replace(/\{node-version\}/gi, process.version) ua = ua.replace(/\{npm-version\}/gi, npm.version) ua = ua.replace(/\{platform\}/gi, process.platform) ua = ua.replace(/\{arch\}/gi, process.arch) // continuous integration platforms const ciName = process.env.GERRIT_PROJECT ? 'gerrit' : process.env.GITLAB_CI ? 'gitlab' : process.env.APPVEYOR ? 'appveyor' : process.env.CIRCLECI ? 'circle-ci' : process.env.SEMAPHORE ? 'semaphore' : process.env.DRONE ? 'drone' : process.env.GITHUB_ACTION ? 'github-actions' : process.env.TDDIUM ? 'tddium' : process.env.JENKINS_URL ? 'jenkins' : process.env['bamboo.buildKey'] ? 'bamboo' : process.env.GO_PIPELINE_NAME ? 'gocd' // codeship and a few others : process.env.CI_NAME ? process.env.CI_NAME // test travis after the others, since several CI systems mimic it : process.env.TRAVIS ? 'travis-ci' // aws CodeBuild/CodePipeline : process.env.CODEBUILD_SRC_DIR ? 'aws-codebuild' : process.env.CI === 'true' || process.env.CI === '1' ? 'custom' // Google Cloud Build - it sets almost nothing : process.env.BUILDER_OUTPUT ? 'builder' : false const ci = ciName ? `ci/${ciName}` : '' ua = ua.replace(/\{ci\}/gi, ci) config.set('user-agent', ua.trim()) if (config.get('metrics-registry') == null) { config.set('metrics-registry', config.get('registry')) } var color = config.get('color') if (npm.config.get('timing') && npm.config.get('loglevel') === 'notice') { log.level = 'timing' } else { log.level = config.get('loglevel') } log.heading = config.get('heading') || 'npm' log.stream = config.get('logstream') switch (color) { case 'always': npm.color = true break case false: npm.color = false break default: npm.color = process.stdout.isTTY && process.env['TERM'] !== 'dumb' break } if (npm.color) { log.enableColor() } else { log.disableColor() } if (config.get('unicode')) { log.enableUnicode() } else { log.disableUnicode() } if (config.get('progress') && process.stderr.isTTY && process.env['TERM'] !== 'dumb') { log.enableProgress() } else { log.disableProgress() } glob(path.resolve(npm.cache, '_logs', '*-debug.log'), function (er, files) { if (er) return cb(er) while (files.length >= npm.config.get('logs-max')) { rimraf.sync(files[0]) files.splice(0, 1) } }) log.resume() var umask = npm.config.get('umask') npm.modes = { exec: parseInt('0777', 8) & (~umask), file: parseInt('0666', 8) & (~umask), umask: umask } var gp = Object.getOwnPropertyDescriptor(config, 'globalPrefix') Object.defineProperty(npm, 'globalPrefix', gp) var lp = Object.getOwnPropertyDescriptor(config, 'localPrefix') Object.defineProperty(npm, 'localPrefix', lp) config.set('scope', scopeifyScope(config.get('scope'))) npm.projectScope = config.get('scope') || scopeifyScope(getProjectScope(npm.prefix)) startMetrics() return cb(null, npm) }) }) } Object.defineProperty(npm, 'prefix', { get: function () { return npm.config.get('global') ? npm.globalPrefix : npm.localPrefix }, set: function (r) { var k = npm.config.get('global') ? 'globalPrefix' : 'localPrefix' npm[k] = r return r }, enumerable: true }) Object.defineProperty(npm, 'bin', { get: function () { if (npm.config.get('global')) return npm.globalBin return path.resolve(npm.root, '.bin') }, enumerable: true }) Object.defineProperty(npm, 'globalBin', { get: function () { var b = npm.globalPrefix if (process.platform !== 'win32') b = path.resolve(b, 'bin') return b } }) Object.defineProperty(npm, 'dir', { get: function () { if (npm.config.get('global')) return npm.globalDir return path.resolve(npm.prefix, 'node_modules') }, enumerable: true }) Object.defineProperty(npm, 'globalDir', { get: function () { return (process.platform !== 'win32') ? path.resolve(npm.globalPrefix, 'lib', 'node_modules') : path.resolve(npm.globalPrefix, 'node_modules') }, enumerable: true }) Object.defineProperty(npm, 'root', { get: function () { return npm.dir } }) Object.defineProperty(npm, 'cache', { get: function () { return npm.config.get('cache') }, set: function (r) { return npm.config.set('cache', r) }, enumerable: true }) var tmpFolder var rand = require('crypto').randomBytes(4).toString('hex') Object.defineProperty(npm, 'tmp', { get: function () { if (!tmpFolder) tmpFolder = 'npm-' + process.pid + '-' + rand return path.resolve(npm.config.get('tmp'), tmpFolder) }, enumerable: true }) // the better to repl you with Object.getOwnPropertyNames(npm.commands).forEach(function (n) { if (npm.hasOwnProperty(n) || n === 'config') return Object.defineProperty(npm, n, { get: function () { return function () { var args = Array.prototype.slice.call(arguments, 0) var cb = defaultCb if (args.length === 1 && Array.isArray(args[0])) { args = args[0] } if (typeof args[args.length - 1] === 'function') { cb = args.pop() } npm.commands[n](args, cb) } }, enumerable: false, configurable: true }) }) if (require.main === module) { require('../bin/npm-cli.js') } function scopeifyScope (scope) { return (!scope || scope[0] === '@') ? scope : ('@' + scope) } function getProjectScope (prefix) { try { var pkg = JSON.parse(fs.readFileSync(path.join(prefix, 'package.json'))) if (typeof pkg.name !== 'string') return '' var sep = pkg.name.indexOf('/') if (sep === -1) return '' return pkg.name.slice(0, sep) } catch (ex) { return '' } } })() outdated.js000064400000030434152231567050006725 0ustar00/* npm outdated [pkg] Does the following: 1. check for a new version of pkg If no packages are specified, then run for all installed packages. --parseable creates output like this: ::: */ module.exports = outdated outdated.usage = 'npm outdated [[<@scope>/] ...]' outdated.completion = require('./utils/completion/installed-deep.js') const os = require('os') const url = require('url') const path = require('path') const readPackageTree = require('read-package-tree') const asyncMap = require('slide').asyncMap const color = require('ansicolors') const styles = require('ansistyles') const table = require('text-table') const semver = require('semver') const npa = require('libnpm/parse-arg') const pickManifest = require('npm-pick-manifest') const fetchPackageMetadata = require('./fetch-package-metadata.js') const mutateIntoLogicalTree = require('./install/mutate-into-logical-tree.js') const npm = require('./npm.js') const npmConfig = require('./config/figgy-config.js') const figgyPudding = require('figgy-pudding') const packument = require('libnpm/packument') const long = npm.config.get('long') const isExtraneous = require('./install/is-extraneous.js') const computeMetadata = require('./install/deps.js').computeMetadata const computeVersionSpec = require('./install/deps.js').computeVersionSpec const moduleName = require('./utils/module-name.js') const output = require('./utils/output.js') const ansiTrim = require('./utils/ansi-trim') const OutdatedConfig = figgyPudding({ also: {}, color: {}, depth: {}, dev: 'development', development: {}, global: {}, json: {}, only: {}, parseable: {}, prod: 'production', production: {}, save: {}, 'save-dev': {}, 'save-optional': {} }) function uniq (list) { // we maintain the array because we need an array, not iterator, return // value. var uniqed = [] var seen = new Set() list.forEach(function (item) { if (seen.has(item)) return seen.add(item) uniqed.push(item) }) return uniqed } function andComputeMetadata (next) { return function (er, tree) { if (er) return next(er) next(null, computeMetadata(tree)) } } function outdated (args, silent, cb) { if (typeof cb !== 'function') { cb = silent silent = false } let opts = OutdatedConfig(npmConfig()) var dir = path.resolve(npm.dir, '..') // default depth for `outdated` is 0 (cf. `ls`) if (opts.depth === Infinity) opts = opts.concat({depth: 0}) readPackageTree(dir, andComputeMetadata(function (er, tree) { if (!tree) return cb(er) mutateIntoLogicalTree(tree) outdated_(args, '', tree, {}, 0, opts, function (er, list) { list = uniq(list || []).sort(function (aa, bb) { return aa[0].path.localeCompare(bb[0].path) || aa[1].localeCompare(bb[1]) }) if (er || silent || (list.length === 0 && !opts.json)) { return cb(er, list) } if (opts.json) { output(makeJSON(list, opts)) } else if (opts.parseable) { output(makeParseable(list, opts)) } else { var outList = list.map(x => makePretty(x, opts)) var outHead = [ 'Package', 'Current', 'Wanted', 'Latest', 'Location' ] if (long) outHead.push('Package Type', 'Homepage') var outTable = [outHead].concat(outList) if (opts.color) { outTable[0] = outTable[0].map(function (heading) { return styles.underline(heading) }) } var tableOpts = { align: ['l', 'r', 'r', 'r', 'l'], stringLength: function (s) { return ansiTrim(s).length } } output(table(outTable, tableOpts)) } process.exitCode = list.length ? 1 : 0 cb(null, list.map(function (item) { return [item[0].parent.path].concat(item.slice(1, 7)) })) }) })) } // [[ dir, dep, has, want, latest, type ]] function makePretty (p, opts) { var depname = p[1] var has = p[2] var want = p[3] var latest = p[4] var type = p[6] var deppath = p[7] var homepage = p[0].package.homepage || '' var columns = [ depname, has || 'MISSING', want, latest, deppath || 'global' ] if (long) { columns[5] = type columns[6] = homepage } if (opts.color) { columns[0] = color[has === want ? 'yellow' : 'red'](columns[0]) // dep columns[2] = color.green(columns[2]) // want columns[3] = color.magenta(columns[3]) // latest } return columns } function makeParseable (list) { return list.map(function (p) { var dep = p[0] var depname = p[1] var dir = dep.path var has = p[2] var want = p[3] var latest = p[4] var type = p[6] var out = [ dir, depname + '@' + want, (has ? (depname + '@' + has) : 'MISSING'), depname + '@' + latest ] if (long) out.push(type, dep.package.homepage) return out.join(':') }).join(os.EOL) } function makeJSON (list, opts) { var out = {} list.forEach(function (p) { var dep = p[0] var depname = p[1] var dir = dep.path var has = p[2] var want = p[3] var latest = p[4] var type = p[6] if (!opts.global) { dir = path.relative(process.cwd(), dir) } out[depname] = { current: has, wanted: want, latest: latest, location: dir } if (long) { out[depname].type = type out[depname].homepage = dep.package.homepage } }) return JSON.stringify(out, null, 2) } function outdated_ (args, path, tree, parentHas, depth, opts, cb) { if (!tree.package) tree.package = {} if (path && moduleName(tree)) path += ' > ' + tree.package.name if (!path && moduleName(tree)) path = tree.package.name if (depth > opts.depth) { return cb(null, []) } var types = {} var pkg = tree.package if (!tree.children) tree.children = [] var deps = tree.error ? tree.children : tree.children.filter((child) => !isExtraneous(child)) deps.forEach(function (dep) { types[moduleName(dep)] = 'dependencies' }) Object.keys(tree.missingDeps || {}).forEach(function (name) { deps.push({ package: { name: name }, path: tree.path, parent: tree, isMissing: true }) types[name] = 'dependencies' }) // If we explicitly asked for dev deps OR we didn't ask for production deps // AND we asked to save dev-deps OR we didn't ask to save anything that's NOT // dev deps then… // (All the save checking here is because this gets called from npm-update currently // and that requires this logic around dev deps.) // FIXME: Refactor npm update to not be in terms of outdated. var dev = opts.dev || /^dev(elopment)?$/.test(opts.also) var prod = opts.production || /^prod(uction)?$/.test(opts.only) if ( (dev || !prod) && ( opts['save-dev'] || (!opts.save && !opts['save-optional']) ) ) { Object.keys(tree.missingDevDeps).forEach(function (name) { deps.push({ package: { name: name }, path: tree.path, parent: tree, isMissing: true }) if (!types[name]) { types[name] = 'devDependencies' } }) } if (opts['save-dev']) { deps = deps.filter(function (dep) { return pkg.devDependencies[moduleName(dep)] }) deps.forEach(function (dep) { types[moduleName(dep)] = 'devDependencies' }) } else if (opts.save) { // remove optional dependencies from dependencies during --save. deps = deps.filter(function (dep) { return !pkg.optionalDependencies[moduleName(dep)] }) } else if (opts['save-optional']) { deps = deps.filter(function (dep) { return pkg.optionalDependencies[moduleName(dep)] }) deps.forEach(function (dep) { types[moduleName(dep)] = 'optionalDependencies' }) } var doUpdate = dev || ( !prod && !Object.keys(parentHas).length && !opts.global ) if (doUpdate) { Object.keys(pkg.devDependencies || {}).forEach(function (k) { if (!(k in parentHas)) { deps[k] = pkg.devDependencies[k] types[k] = 'devDependencies' } }) } var has = Object.create(parentHas) tree.children.forEach(function (child) { if (moduleName(child) && child.package.private) { deps = deps.filter(function (dep) { return dep !== child }) } has[moduleName(child)] = { version: child.isLink ? 'linked' : child.package.version, from: child.isLink ? 'file:' + child.path : child.package._from } }) // now get what we should have, based on the dep. // if has[dep] !== shouldHave[dep], then cb with the data // otherwise dive into the folder asyncMap(deps, function (dep, cb) { var name = moduleName(dep) var required if (tree.package.dependencies && name in tree.package.dependencies) { required = tree.package.dependencies[name] } else if (tree.package.optionalDependencies && name in tree.package.optionalDependencies) { required = tree.package.optionalDependencies[name] } else if (tree.package.devDependencies && name in tree.package.devDependencies) { required = tree.package.devDependencies[name] } else if (has[name]) { required = computeVersionSpec(tree, dep) } if (!long) return shouldUpdate(args, dep, name, has, required, depth, path, opts, cb) shouldUpdate(args, dep, name, has, required, depth, path, opts, cb, types[name]) }, cb) } function shouldUpdate (args, tree, dep, has, req, depth, pkgpath, opts, cb, type) { // look up the most recent version. // if that's what we already have, or if it's not on the args list, // then dive into it. Otherwise, cb() with the data. // { version: , from: } var curr = has[dep] function skip (er) { // show user that no viable version can be found if (er) return cb(er) outdated_(args, pkgpath, tree, has, depth + 1, opts, cb) } if (args.length && args.indexOf(dep) === -1) return skip() if (tree.isLink && req == null) return skip() if (req == null || req === '') req = '*' var parsed = npa.resolve(dep, req) if (parsed.type === 'directory') { if (tree.isLink) { return skip() } else { return doIt('linked', 'linked') } } else if (parsed.type === 'git') { return doIt('git', 'git') } else if (parsed.type === 'file') { return updateLocalDeps() } else if (parsed.type === 'remote') { return doIt('remote', 'remote') } else { return packument(parsed, opts.concat({ 'prefer-online': true })).nodeify(updateDeps) } function doIt (wanted, latest) { let c = curr && curr.version if (parsed.type === 'alias') { c = `npm:${parsed.subSpec.name}@${c}` } if (!long) { return cb(null, [[tree, dep, c, wanted, latest, req, null, pkgpath]]) } cb(null, [[tree, dep, c, wanted, latest, req, type, pkgpath]]) } function updateLocalDeps (latestRegistryVersion) { fetchPackageMetadata('file:' + parsed.fetchSpec, '.', (er, localDependency) => { if (er) return cb() var wanted = localDependency.version var latest = localDependency.version if (latestRegistryVersion) { latest = latestRegistryVersion if (semver.lt(wanted, latestRegistryVersion)) { wanted = latestRegistryVersion req = dep + '@' + latest } } if (!curr || curr.version !== wanted) { doIt(wanted, latest) } else { skip() } }) } function updateDeps (er, d) { if (er) return cb(er) if (parsed.type === 'alias') { req = parsed.subSpec.rawSpec } try { var l = pickManifest(d, 'latest') var m = pickManifest(d, req) } catch (er) { if (er.code === 'ETARGET' || er.code === 'E403') { return skip(er) } else { return skip() } } // check that the url origin hasn't changed (#1727) and that // there is no newer version available var dFromUrl = m._from && url.parse(m._from).protocol var cFromUrl = curr && curr.from && url.parse(curr.from).protocol if ( !curr || (dFromUrl && cFromUrl && m._from !== curr.from) || m.version !== curr.version || m.version !== l.version ) { if (parsed.type === 'alias') { doIt( `npm:${parsed.subSpec.name}@${m.version}`, `npm:${parsed.subSpec.name}@${l.version}` ) } else { doIt(m.version, l.version) } } else { skip() } } } substack.js000064400000000775152231567050006740 0ustar00module.exports = substack var npm = require('./npm.js') var output = require('./utils/output.js') var isms = [ '\u001b[32mbeep \u001b[35mboop\u001b[m', 'Replace your configs with services', 'SEPARATE ALL THE CONCERNS!', 'MODULE ALL THE THINGS!', '\\o/', 'but first, burritos', 'full time mad scientist here', 'c/,,\\' ] function substack (args, cb) { var i = Math.floor(Math.random() * isms.length) output(isms[i]) var c = args.shift() if (c) npm.commands[c](args, cb) else cb() } install/action/build.js000064400000000634152231567050011135 0ustar00'use strict' var chain = require('slide').chain var build = require('../../build.js') var npm = require('../../npm.js') var packageId = require('../../utils/package-id.js') module.exports = function (staging, pkg, log, next) { log.silly('build', packageId(pkg)) chain([ [build.linkStuff, pkg.package, pkg.path, npm.config.get('global')], [build.writeBuiltinConf, pkg.package, pkg.path] ], next) } install/action/extract-worker.js000064400000000731152231567050013015 0ustar00'use strict' const BB = require('bluebird') const extract = require('pacote/extract') // const npmlog = require('npmlog') module.exports = (args, cb) => { const parsed = typeof args === 'string' ? JSON.parse(args) : args const spec = parsed[0] const extractTo = parsed[1] const opts = parsed[2] // if (!opts.log) { // opts.log = npmlog // } // opts.log.level = opts.loglevel || opts.log.level BB.resolve(extract(spec, extractTo, opts)).nodeify(cb) } install/action/extract.js000064400000007573152231567050011521 0ustar00'use strict' const BB = require('bluebird') const figgyPudding = require('figgy-pudding') const stat = BB.promisify(require('graceful-fs').stat) const gentlyRm = BB.promisify(require('../../utils/gently-rm.js')) const mkdirp = BB.promisify(require('gentle-fs').mkdir) const moduleName = require('../../utils/module-name.js') const moduleStagingPath = require('../module-staging-path.js') const move = require('../../utils/move.js') const npa = require('npm-package-arg') const npm = require('../../npm.js') let npmConfig const packageId = require('../../utils/package-id.js') const path = require('path') const localWorker = require('./extract-worker.js') const workerFarm = require('worker-farm') const isRegistry = require('../../utils/is-registry.js') const WORKER_PATH = require.resolve('./extract-worker.js') let workers const ExtractOpts = figgyPudding({ log: {} }, { other () { return true } }) // Disabled for now. Re-enable someday. Just not today. const ENABLE_WORKERS = false extract.init = () => { if (ENABLE_WORKERS) { workers = workerFarm({ maxConcurrentCallsPerWorker: npm.limit.fetch, maxRetries: 1 }, WORKER_PATH) } return BB.resolve() } extract.teardown = () => { if (ENABLE_WORKERS) { workerFarm.end(workers) workers = null } return BB.resolve() } module.exports = extract function extract (staging, pkg, log) { log.silly('extract', packageId(pkg)) const extractTo = moduleStagingPath(staging, pkg) if (!npmConfig) { npmConfig = require('../../config/figgy-config.js') } let opts = ExtractOpts(npmConfig()).concat({ integrity: pkg.package._integrity, resolved: pkg.package._resolved }) const args = [ pkg.package._requested, extractTo, opts ] return BB.fromNode((cb) => { let launcher = localWorker let msg = args const spec = typeof args[0] === 'string' ? npa(args[0]) : args[0] args[0] = spec.raw if (ENABLE_WORKERS && (isRegistry(spec) || spec.type === 'remote')) { // We can't serialize these options opts = opts.concat({ loglevel: opts.log.level, log: null, dirPacker: null, Promise: null, _events: null, _eventsCount: null, list: null, sources: null, _maxListeners: null, root: null }) // workers will run things in parallel! launcher = workers try { msg = JSON.stringify(msg) } catch (e) { return cb(e) } } launcher(msg, cb) }).then(() => { if (pkg.package.bundleDependencies || anyBundled(pkg)) { return readBundled(pkg, staging, extractTo) } }).then(() => { return gentlyRm(path.join(extractTo, 'node_modules')) }) } function anyBundled (top, pkg) { if (!pkg) pkg = top return pkg.children.some((child) => child.fromBundle === top || anyBundled(top, child)) } function readBundled (pkg, staging, extractTo) { return BB.map(pkg.children, (child) => { if (!child.fromBundle) return if (child.error) { throw child.error } else { return stageBundledModule(pkg, child, staging, extractTo) } }, {concurrency: 10}) } function stageBundledModule (bundler, child, staging, parentPath) { const stageFrom = path.join(parentPath, 'node_modules', moduleName(child)) const stageTo = moduleStagingPath(staging, child) return BB.map(child.children, (child) => { if (child.error) { throw child.error } else { return stageBundledModule(bundler, child, staging, stageFrom) } }).then(() => { return finishModule(bundler, child, stageTo, stageFrom) }) } function finishModule (bundler, child, stageTo, stageFrom) { // If we were the one's who bundled this module… if (child.fromBundle === bundler) { return mkdirp(path.dirname(stageTo)).then(() => { return move(stageFrom, stageTo) }) } else { return stat(stageFrom).then(() => gentlyRm(stageFrom), () => {}) } } install/action/fetch.js000064400000001014152231567050011120 0ustar00'use strict' const BB = require('bluebird') const finished = BB.promisify(require('mississippi').finished) const npmConfig = require('../../config/figgy-config.js') const packageId = require('../../utils/package-id.js') const pacote = require('pacote') module.exports = fetch function fetch (staging, pkg, log, next) { log.silly('fetch', packageId(pkg)) const opts = npmConfig({integrity: pkg.package._integrity}) return finished(pacote.tarball.stream(pkg.package._requested, opts)) .then(() => next(), next) } install/action/finalize.js000064400000007502152231567050011640 0ustar00'use strict' const path = require('path') const fs = require('graceful-fs') const Bluebird = require('bluebird') const rimraf = Bluebird.promisify(require('rimraf')) const mkdirp = Bluebird.promisify(require('gentle-fs').mkdir) const lstat = Bluebird.promisify(fs.lstat) const readdir = Bluebird.promisify(fs.readdir) const symlink = Bluebird.promisify(fs.symlink) const gentlyRm = Bluebird.promisify(require('../../utils/gently-rm')) const moduleStagingPath = require('../module-staging-path.js') const move = require('move-concurrently') const moveOpts = {fs: fs, Promise: Bluebird, maxConcurrency: 4} const getRequested = require('../get-requested.js') const log = require('npmlog') const packageId = require('../../utils/package-id.js') module.exports = function (staging, pkg, log) { log.silly('finalize', pkg.realpath) const extractedTo = moduleStagingPath(staging, pkg) const delpath = path.join(path.dirname(pkg.realpath), '.' + path.basename(pkg.realpath) + '.DELETE') let movedDestAway = false const requested = pkg.package._requested || getRequested(pkg) if (requested.type === 'directory') { const relative = path.relative(path.dirname(pkg.path), pkg.realpath) return makeParentPath(pkg.path) .then(() => symlink(relative, pkg.path, 'junction')) .catch((ex) => { return rimraf(pkg.path).then(() => symlink(relative, pkg.path, 'junction')) }) } else { return makeParentPath(pkg.realpath) .then(moveStagingToDestination) .then(restoreOldNodeModules) .catch((err) => { if (movedDestAway) { return rimraf(pkg.realpath).then(moveOldDestinationBack).then(() => { throw err }) } else { throw err } }) .then(() => rimraf(delpath)) } function makeParentPath (dir) { return mkdirp(path.dirname(dir)) } function moveStagingToDestination () { return destinationIsClear() .then(actuallyMoveStaging) .catch(() => moveOldDestinationAway().then(actuallyMoveStaging)) } function destinationIsClear () { return lstat(pkg.realpath).then(() => { throw new Error('destination exists') }, () => {}) } function actuallyMoveStaging () { return move(extractedTo, pkg.realpath, moveOpts) } function moveOldDestinationAway () { return rimraf(delpath).then(() => { return move(pkg.realpath, delpath, moveOpts) }).then(() => { movedDestAway = true }) } function moveOldDestinationBack () { return move(delpath, pkg.realpath, moveOpts).then(() => { movedDestAway = false }) } function restoreOldNodeModules () { if (!movedDestAway) return return readdir(path.join(delpath, 'node_modules')).catch(() => []).then((modules) => { if (!modules.length) return return mkdirp(path.join(pkg.realpath, 'node_modules')).then(() => Bluebird.map(modules, (file) => { const from = path.join(delpath, 'node_modules', file) const to = path.join(pkg.realpath, 'node_modules', file) return move(from, to, moveOpts) })) }) } } module.exports.rollback = function (top, staging, pkg) { return Bluebird.try(() => { const requested = pkg.package._requested || getRequested(pkg) if (requested && requested.type === 'directory') return Promise.resolve() // strictly speaking rolling back a finalize should ONLY remove module that // was being finalized, not any of the things under it. But currently // those modules are guaranteed to be useless so we may as well remove them too. // When/if we separate `commit` step and can rollback to previous versions // of upgraded modules then we'll need to revisit this… return gentlyRm(pkg.path, false, top).catch((err) => { log.warn('rollback', `Rolling back ${packageId(pkg)} failed (this is probably harmless): ${err.message ? err.message : err}`) }) }) } install/action/global-install.js000064400000001220152231567050012732 0ustar00'use strict' var path = require('path') var npm = require('../../npm.js') var Installer = require('../../install.js').Installer var packageId = require('../../utils/package-id.js') var moduleName = require('../../utils/module-name.js') module.exports = function (staging, pkg, log, next) { log.silly('global-install', packageId(pkg)) var globalRoot = path.resolve(npm.globalDir, '..') npm.config.set('global', true) var install = new Installer(globalRoot, false, [moduleName(pkg) + '@' + pkg.package._requested.rawSpec]) install.link = false install.run(function () { npm.config.set('global', false) next.apply(null, arguments) }) } install/action/global-link.js000064400000000441152231567050012225 0ustar00'use strict' var moduleName = require('../../utils/module-name.js') var npm = require('../../npm.js') var packageId = require('../../utils/package-id.js') module.exports = function (staging, pkg, log, next) { log.silly('global-link', packageId(pkg)) npm.link(moduleName(pkg), next) } install/action/install.js000064400000000412152231567050011476 0ustar00'use strict' var lifecycle = require('../../utils/lifecycle.js') var packageId = require('../../utils/package-id.js') module.exports = function (staging, pkg, log, next) { log.silly('install', packageId(pkg)) lifecycle(pkg.package, 'install', pkg.path, next) } install/action/move.js000064400000006140152231567050011002 0ustar00'use strict' var fs = require('graceful-fs') var path = require('path') var chain = require('slide').chain var iferr = require('iferr') var rimraf = require('rimraf') var mkdirp = require('gentle-fs').mkdir var rmStuff = require('../../unbuild.js').rmStuff var lifecycle = require('../../utils/lifecycle.js') var move = require('../../utils/move.js') /* Move a module from one point in the node_modules tree to another. Do not disturb either the source or target location's node_modules folders. */ module.exports = function (staging, pkg, log, next) { log.silly('move', pkg.fromPath, pkg.path) chain([ [lifecycle, pkg.package, 'preuninstall', pkg.fromPath, { failOk: true }], [lifecycle, pkg.package, 'uninstall', pkg.fromPath, { failOk: true }], [rmStuff, pkg.package, pkg.fromPath], [lifecycle, pkg.package, 'postuninstall', pkg.fromPath, { failOk: true }], [moveModuleOnly, pkg.fromPath, pkg.path, log], [lifecycle, pkg.package, 'preinstall', pkg.path, { failOk: true }], [removeEmptyParents, path.resolve(pkg.fromPath, '..')] ], next) } function removeEmptyParents (pkgdir, next) { fs.rmdir(pkgdir, function (er) { // FIXME: Make sure windows does what we want here if (er && er.code !== 'ENOENT') return next() removeEmptyParents(path.resolve(pkgdir, '..'), next) }) } function moveModuleOnly (from, to, log, done) { var fromModules = path.join(from, 'node_modules') var tempFromModules = from + '.node_modules' var toModules = path.join(to, 'node_modules') var tempToModules = to + '.node_modules' log.silly('move', 'move existing destination node_modules away', toModules) move(toModules, tempToModules).then(removeDestination(done), removeDestination(done)) function removeDestination (next) { return function (er) { log.silly('move', 'remove existing destination', to) if (er) { rimraf(to, iferr(next, makeDestination(next))) } else { rimraf(to, iferr(next, makeDestination(iferr(next, moveToModulesBack(next))))) } } } function moveToModulesBack (next) { return function () { log.silly('move', 'move existing destination node_modules back', toModules) move(tempToModules, toModules).then(next, done) } } function makeDestination (next) { return function () { log.silly('move', 'make sure destination parent exists', path.resolve(to, '..')) mkdirp(path.resolve(to, '..'), iferr(done, moveNodeModules(next))) } } function moveNodeModules (next) { return function () { log.silly('move', 'move source node_modules away', fromModules) move(fromModules, tempFromModules).then(doMove(moveNodeModulesBack(next)), doMove(next)) } } function doMove (next) { return function () { log.silly('move', 'move module dir to final dest', from, to) move(from, to).then(next, done) } } function moveNodeModulesBack (next) { return function () { mkdirp(from, iferr(done, function () { log.silly('move', 'put source node_modules back', fromModules) move(tempFromModules, fromModules).then(next, done) })) } } } install/action/postinstall.js000064400000000422152231567050012405 0ustar00'use strict' var lifecycle = require('../../utils/lifecycle.js') var packageId = require('../../utils/package-id.js') module.exports = function (staging, pkg, log, next) { log.silly('postinstall', packageId(pkg)) lifecycle(pkg.package, 'postinstall', pkg.path, next) } install/action/preinstall.js000064400000000420152231567050012204 0ustar00'use strict' var lifecycle = require('../../utils/lifecycle.js') var packageId = require('../../utils/package-id.js') module.exports = function (staging, pkg, log, next) { log.silly('preinstall', packageId(pkg)) lifecycle(pkg.package, 'preinstall', pkg.path, next) } install/action/prepare.js000064400000002037152231567050011473 0ustar00'use strict' var chain = require('slide').chain var lifecycle = require('../../utils/lifecycle.js') var packageId = require('../../utils/package-id.js') var prepublishWarning = require('../../utils/warn-deprecated.js')('prepublish-on-install') var moduleStagingPath = require('../module-staging-path.js') module.exports = function (staging, pkg, log, next) { log.silly('prepublish', packageId(pkg)) // TODO: for `npm@5`, change the behavior and remove this warning. // see https://github.com/npm/npm/issues/10074 for details if (pkg.package && pkg.package.scripts && pkg.package.scripts.prepublish) { prepublishWarning([ 'As of npm@5, `prepublish` scripts are deprecated.', 'Use `prepare` for build steps and `prepublishOnly` for upload-only.', 'See the deprecation note in `npm help scripts` for more information.' ]) } var buildpath = moduleStagingPath(staging, pkg) chain( [ [lifecycle, pkg.package, 'prepublish', buildpath], [lifecycle, pkg.package, 'prepare', buildpath] ], next ) } install/action/refresh-package-json.js000064400000002773152231567050014042 0ustar00'use strict' const Bluebird = require('bluebird') const checkPlatform = Bluebird.promisify(require('npm-install-checks').checkPlatform) const getRequested = require('../get-requested.js') const npm = require('../../npm.js') const path = require('path') const readJson = Bluebird.promisify(require('read-package-json')) const updatePackageJson = Bluebird.promisify(require('../update-package-json')) module.exports = function (staging, pkg, log) { log.silly('refresh-package-json', pkg.realpath) return readJson(path.join(pkg.path, 'package.json'), false).then((metadata) => { Object.keys(pkg.package).forEach(function (key) { if (key !== 'version' && key !== 'dependencies' && !isEmpty(pkg.package[key])) { metadata[key] = pkg.package[key] } }) if (metadata._resolved == null && pkg.fakeChild) { metadata._resolved = pkg.fakeChild.resolved } // These two sneak in and it's awful delete metadata.readme delete metadata.readmeFilename pkg.package = metadata pkg.fakeChild = false }).catch(() => 'ignore').then(() => { return checkPlatform(pkg.package, npm.config.get('force')) }).then(() => { const requested = pkg.package._requested || getRequested(pkg) if (requested.type !== 'directory') { return updatePackageJson(pkg, pkg.path) } }) } function isEmpty (value) { if (value == null) return true if (Array.isArray(value)) return !value.length if (typeof value === 'object') return !Object.keys(value).length return false } install/action/remove.js000064400000005136152231567050011335 0ustar00'use strict' var path = require('path') var fs = require('graceful-fs') var rimraf = require('rimraf') var asyncMap = require('slide').asyncMap var mkdirp = require('gentle-fs').mkdir var npm = require('../../npm.js') var andIgnoreErrors = require('../and-ignore-errors.js') var move = require('../../utils/move.js') var isInside = require('path-is-inside') var vacuum = require('fs-vacuum') // This is weird because we want to remove the module but not it's node_modules folder // allowing for this allows us to not worry about the order of operations module.exports = function (staging, pkg, log, next) { log.silly('remove', pkg.path) if (pkg.target) { removeLink(pkg, next) } else { removeDir(pkg, log, next) } } function removeLink (pkg, next) { var base = isInside(pkg.path, npm.prefix) ? npm.prefix : pkg.path rimraf(pkg.path, (err) => { if (err) return next(err) vacuum(pkg.path, {base: base}, next) }) } function removeDir (pkg, log, next) { var modpath = path.join(path.dirname(pkg.path), '.' + path.basename(pkg.path) + '.MODULES') move(path.join(pkg.path, 'node_modules'), modpath).then(unbuildPackage, unbuildPackage) function unbuildPackage (moveEr) { rimraf(pkg.path, moveEr ? andRemoveEmptyParents(pkg.path) : moveModulesBack) } function andRemoveEmptyParents (path) { return function (er) { if (er) return next(er) removeEmptyParents(pkg.path) } } function moveModulesBack () { fs.readdir(modpath, makeTarget) } function makeTarget (readdirEr, files) { if (readdirEr) return cleanup() if (!files.length) return cleanup() mkdirp(path.join(pkg.path, 'node_modules'), function (mkdirEr) { moveModules(mkdirEr, files) }) } function moveModules (mkdirEr, files) { if (mkdirEr) return next(mkdirEr) asyncMap(files, function (file, done) { var from = path.join(modpath, file) var to = path.join(pkg.path, 'node_modules', file) // we ignore errors here, because they can legitimately happen, for instance, // bundled modules will be in both node_modules folders move(from, to).then(andIgnoreErrors(done), andIgnoreErrors(done)) }, cleanup) } function cleanup () { rimraf(modpath, afterCleanup) } function afterCleanup (rimrafEr) { if (rimrafEr) log.warn('remove', rimrafEr) removeEmptyParents(path.resolve(pkg.path, '..')) } function removeEmptyParents (pkgdir) { fs.rmdir(pkgdir, function (er) { // FIXME: Make sure windows does what we want here if (er && er.code !== 'ENOENT') return next() removeEmptyParents(path.resolve(pkgdir, '..')) }) } } install/action/unbuild.js000064400000001223152231567050011473 0ustar00'use strict' var Bluebird = require('bluebird') var lifecycle = Bluebird.promisify(require('../../utils/lifecycle.js')) var packageId = require('../../utils/package-id.js') var rmStuff = Bluebird.promisify(require('../../unbuild.js').rmStuff) module.exports = function (staging, pkg, log) { log.silly('unbuild', packageId(pkg)) return lifecycle(pkg.package, 'preuninstall', pkg.path, { failOk: true }).then(() => { return lifecycle(pkg.package, 'uninstall', pkg.path, { failOk: true }) }).then(() => { return rmStuff(pkg.package, pkg.path) }).then(() => { return lifecycle(pkg.package, 'postuninstall', pkg.path, { failOk: true }) }) } install/save.js000064400000013642152231567050007522 0ustar00'use strict' const deepSortObject = require('../utils/deep-sort-object.js') const detectIndent = require('detect-indent') const detectNewline = require('detect-newline') const fs = require('graceful-fs') const iferr = require('iferr') const log = require('npmlog') const moduleName = require('../utils/module-name.js') const npm = require('../npm.js') const packageId = require('../utils/package-id.js') const parseJSON = require('../utils/parse-json.js') const path = require('path') const stringifyPackage = require('stringify-package') const validate = require('aproba') const without = require('lodash.without') const writeFileAtomic = require('write-file-atomic') // if the -S|--save option is specified, then write installed packages // as dependencies to a package.json file. exports.saveRequested = function (tree, andReturn) { validate('OF', arguments) savePackageJson(tree, andWarnErrors(andSaveShrinkwrap(tree, andReturn))) } function andSaveShrinkwrap (tree, andReturn) { validate('OF', arguments) return function (er) { validate('E', arguments) saveShrinkwrap(tree, andWarnErrors(andReturn)) } } function andWarnErrors (cb) { validate('F', arguments) return function (er) { if (er) log.warn('saveError', er.message) arguments[0] = null cb.apply(null, arguments) } } exports.saveShrinkwrap = saveShrinkwrap function saveShrinkwrap (tree, next) { validate('OF', arguments) if (!npm.config.get('package-lock-only') && (!npm.config.get('shrinkwrap') || !npm.config.get('package-lock'))) { return next() } require('../shrinkwrap.js').createShrinkwrap(tree, {silent: false}, next) } function savePackageJson (tree, next) { validate('OF', arguments) var saveBundle = npm.config.get('save-bundle') // each item in the tree is a top-level thing that should be saved // to the package.json file. // The relevant tree shape is { : {what:} } var saveTarget = path.resolve(tree.path, 'package.json') // don't use readJson, because we don't want to do all the other // tricky npm-specific stuff that's in there. fs.readFile(saveTarget, 'utf8', iferr(next, function (packagejson) { const indent = detectIndent(packagejson).indent const newline = detectNewline(packagejson) try { tree.package = parseJSON(packagejson) } catch (ex) { return next(ex) } // If we're saving bundled deps, normalize the key before we start if (saveBundle) { var bundle = tree.package.bundleDependencies || tree.package.bundledDependencies delete tree.package.bundledDependencies if (!Array.isArray(bundle)) bundle = [] } var toSave = getThingsToSave(tree) var toRemove = getThingsToRemove(tree) var savingTo = {} toSave.forEach(function (pkg) { if (pkg.save) savingTo[pkg.save] = true }) toRemove.forEach(function (pkg) { if (pkg.save) savingTo[pkg.save] = true }) Object.keys(savingTo).forEach(function (save) { if (!tree.package[save]) tree.package[save] = {} }) log.verbose('saving', toSave) const types = ['dependencies', 'devDependencies', 'optionalDependencies'] toSave.forEach(function (pkg) { if (pkg.save) tree.package[pkg.save][pkg.name] = pkg.spec const movedFrom = [] for (let saveType of types) { if ( pkg.save !== saveType && tree.package[saveType] && tree.package[saveType][pkg.name] ) { movedFrom.push(saveType) delete tree.package[saveType][pkg.name] } } if (movedFrom.length) { log.notice('save', `${pkg.name} is being moved from ${movedFrom.join(' and ')} to ${pkg.save}`) } if (saveBundle) { var ii = bundle.indexOf(pkg.name) if (ii === -1) bundle.push(pkg.name) } }) toRemove.forEach(function (pkg) { if (pkg.save) delete tree.package[pkg.save][pkg.name] if (saveBundle) { bundle = without(bundle, pkg.name) } }) Object.keys(savingTo).forEach(function (key) { tree.package[key] = deepSortObject(tree.package[key]) }) if (saveBundle) { tree.package.bundleDependencies = deepSortObject(bundle) } var json = stringifyPackage(tree.package, indent, newline) if (json === packagejson) { log.verbose('shrinkwrap', 'skipping write for package.json because there were no changes.') next() } else { writeFileAtomic(saveTarget, json, next) } // Restore derived id as it was removed when reloading from disk tree.package._id = packageId(tree.package) })) } exports.getSaveType = function (tree, arg) { if (arguments.length) validate('OO', arguments) var globalInstall = npm.config.get('global') var noSaveFlags = !npm.config.get('save') && !npm.config.get('save-dev') && !npm.config.get('save-prod') && !npm.config.get('save-optional') if (globalInstall || noSaveFlags) return null if (npm.config.get('save-optional')) { return 'optionalDependencies' } else if (npm.config.get('save-dev')) { return 'devDependencies' } else if (npm.config.get('save-prod')) { return 'dependencies' } else { if (arg) { var name = moduleName(arg) if (tree.package.optionalDependencies[name]) { return 'optionalDependencies' } else if (tree.package.devDependencies[name]) { return 'devDependencies' } } return 'dependencies' } } function getThingsToSave (tree) { validate('O', arguments) var toSave = tree.children.filter(function (child) { return child.save }).map(function (child) { return { name: moduleName(child), spec: child.saveSpec, save: child.save } }) return toSave } function getThingsToRemove (tree) { validate('O', arguments) if (!tree.removedChildren) return [] var toRemove = tree.removedChildren.map(function (child) { return { name: moduleName(child), save: child.save } }) return toRemove } install/update-package-json.js000064400000003573152231567050012410 0ustar00'use strict' var path = require('path') var writeFileAtomic = require('write-file-atomic') var moduleName = require('../utils/module-name.js') var deepSortObject = require('../utils/deep-sort-object.js') var sortedObject = require('sorted-object') var isWindows = require('../utils/is-windows.js') var sortKeys = [ 'dependencies', 'devDependencies', 'bundleDependencies', 'optionalDependencies', 'keywords', 'engines', 'scripts', 'files' ] module.exports = function (mod, buildpath, next) { var pkg = sortedObject(mod.package) var name = moduleName(mod) // Add our diagnostic keys to the package.json. // Note that there are folks relying on these, for ex, the Visual Studio // Node.js addon. pkg._requiredBy = mod.requiredBy .map(function (req) { if ( req.package.devDependencies && req.package.devDependencies[name] && !req.package.dependencies[name] ) { return '#DEV:' + req.location } else { return req.location } }) .concat(mod.userRequired ? ['#USER'] : []) .sort() pkg._location = mod.location pkg._phantomChildren = {} Object.keys(mod.phantomChildren).sort().forEach(function (name) { pkg._phantomChildren[name] = mod.phantomChildren[name].package.version }) pkg._inBundle = !!mod.fromBundle // sort keys that are known safe to sort to produce more consistent output sortKeys.forEach(function (key) { if (pkg[key] != null) pkg[key] = deepSortObject(pkg[key]) }) var data = JSON.stringify(sortedObject(pkg), null, 2) + '\n' writeFileAtomic(path.resolve(buildpath, 'package.json'), data, { // We really don't need this guarantee, and fsyncing here is super slow. Except on // Windows where there isn't a big performance difference and it prevents errors when // rolling back optional packages (#17671) fsync: isWindows }, next) } install/validate-args.js000064400000005355152231567050011311 0ustar00'use strict' var validate = require('aproba') var asyncMap = require('slide').asyncMap var chain = require('slide').chain var npmInstallChecks = require('npm-install-checks') var iferr = require('iferr') var checkEngine = npmInstallChecks.checkEngine var checkPlatform = npmInstallChecks.checkPlatform var npm = require('../npm.js') module.exports = function (idealTree, args, next) { validate('OAF', arguments) var force = npm.config.get('force') asyncMap(args, function (pkg, done) { chain([ [hasMinimumFields, pkg], [checkSelf, idealTree, pkg, force], [isInstallable, idealTree, pkg] ], done) }, next) } function hasMinimumFields (pkg, cb) { if (pkg.name === '' || pkg.name == null) { return cb(new Error(`Can't install ${pkg._resolved}: Missing package name`)) } else if (pkg.version === '' || pkg.version == null) { return cb(new Error(`Can't install ${pkg._resolved}: Missing package version`)) } else { return cb() } } function setWarnings (idealTree, warn) { function top (tree) { if (tree.parent) return top(tree.parent) return tree } var topTree = top(idealTree) if (!topTree.warnings) topTree.warnings = [] if (topTree.warnings.every(i => ( i.code !== warn.code || i.required !== warn.required || i.pkgid !== warn.pkgid))) { topTree.warnings.push(warn) } } var isInstallable = module.exports.isInstallable = function (idealTree, pkg, next) { var force = npm.config.get('force') var nodeVersion = npm.config.get('node-version') if (/-/.test(nodeVersion)) { // for the purposes of validation, if the node version is a prerelease, // strip that. We check and warn about this sceanrio over in validate-tree. nodeVersion = nodeVersion.replace(/-.*/, '') } var strict = npm.config.get('engine-strict') checkEngine(pkg, npm.version, nodeVersion, force, strict, iferr(next, thenWarnEngineIssues)) function thenWarnEngineIssues (warn) { if (idealTree && warn) setWarnings(idealTree, warn) checkPlatform(pkg, force, next) } } function checkSelf (idealTree, pkg, force, next) { if (idealTree.package && idealTree.package.name !== pkg.name) return next() if (force) { var warn = new Error("Wouldn't install " + pkg.name + ' as a dependency of itself, but being forced') warn.code = 'ENOSELF' idealTree.warnings.push(warn) next() } else { var er = new Error('Refusing to install package with name "' + pkg.name + '" under a package\n' + 'also called "' + pkg.name + '". Did you name your project the same\n' + 'as the dependency you\'re installing?\n\n' + 'For more information, see:\n' + ' ') er.code = 'ENOSELF' next(er) } } install/validate-tree.js000064400000006152152231567050011310 0ustar00'use strict' var path = require('path') var validate = require('aproba') var asyncMap = require('slide').asyncMap var chain = require('slide').chain var npmInstallChecks = require('npm-install-checks') var checkGit = npmInstallChecks.checkGit var clone = require('lodash.clonedeep') var normalizePackageData = require('normalize-package-data') var npm = require('../npm.js') var andFinishTracker = require('./and-finish-tracker.js') var flattenTree = require('./flatten-tree.js') var validateAllPeerDeps = require('./deps.js').validateAllPeerDeps var packageId = require('../utils/package-id.js') module.exports = function (idealTree, log, next) { validate('OOF', arguments) var moduleMap = flattenTree(idealTree) var modules = Object.keys(moduleMap).map(function (name) { return moduleMap[name] }) chain([ [asyncMap, modules, function (mod, done) { chain([ mod.parent && !mod.isLink && [checkGit, mod.realpath], [checkErrors, mod, idealTree] ], done) }], [thenValidateAllPeerDeps, idealTree], [thenCheckTop, idealTree], [thenCheckDuplicateDeps, idealTree] ], andFinishTracker(log, next)) } function checkErrors (mod, idealTree, next) { if (mod.error && (mod.parent || path.resolve(npm.globalDir, '..') !== mod.path)) idealTree.warnings.push(mod.error) next() } function thenValidateAllPeerDeps (idealTree, next) { validate('OF', arguments) validateAllPeerDeps(idealTree, function (tree, pkgname, version) { var warn = new Error(packageId(tree) + ' requires a peer of ' + pkgname + '@' + version + ' but none is installed. You must install peer dependencies yourself.') warn.code = 'EPEERINVALID' idealTree.warnings.push(warn) }) next() } function thenCheckTop (idealTree, next) { validate('OF', arguments) if (idealTree.package.error) return next() // FIXME: when we replace read-package-json with something less magic, // this should done elsewhere. // As it is, the package has already been normalized and thus some // errors are suppressed. var pkg = clone(idealTree.package) try { normalizePackageData(pkg, function (warn) { var warnObj = new Error(packageId(idealTree) + ' ' + warn) warnObj.code = 'EPACKAGEJSON' idealTree.warnings.push(warnObj) }, false) } catch (er) { er.code = 'EPACKAGEJSON' idealTree.warnings.push(er) } var nodeVersion = npm.config.get('node-version') if (/-/.test(nodeVersion)) { // if this is a prerelease node… var warnObj = new Error('You are using a pre-release version of node and things may not work as expected') warnObj.code = 'ENODEPRE' idealTree.warnings.push(warnObj) } next() } // check for deps duplciated between devdeps and regular deps function thenCheckDuplicateDeps (idealTree, next) { var deps = idealTree.package.dependencies || {} var devDeps = idealTree.package.devDependencies || {} for (var pkg in devDeps) { if (pkg in deps) { var warnObj = new Error('The package ' + pkg + ' is included as both a dev and production dependency.') warnObj.code = 'EDUPLICATEDEP' idealTree.warnings.push(warnObj) } } next() } install/writable.js000064400000002003152231567050010362 0ustar00'use strict' var path = require('path') var fs = require('fs') var inflight = require('inflight') var accessError = require('./access-error.js') var andIgnoreErrors = require('./and-ignore-errors.js') var isFsAccessAvailable = require('./is-fs-access-available.js') if (isFsAccessAvailable) { module.exports = fsAccessImplementation } else { module.exports = fsOpenImplementation } // exposed only for testing purposes module.exports.fsAccessImplementation = fsAccessImplementation module.exports.fsOpenImplementation = fsOpenImplementation function fsAccessImplementation (dir, done) { done = inflight('writable:' + dir, done) if (!done) return fs.access(dir, fs.W_OK, done) } function fsOpenImplementation (dir, done) { done = inflight('writable:' + dir, done) if (!done) return var tmp = path.join(dir, '.npm.check.permissions') fs.open(tmp, 'w', function (er, fd) { if (er) return done(accessError(dir, er)) fs.close(fd, function () { fs.unlink(tmp, andIgnoreErrors(done)) }) }) } install/access-error.js000064400000000312152231567050011142 0ustar00'use strict' module.exports = function (dir, er) { if (!er) return var accessEr = new Error("EACCES, access '" + dir + "'", -13) accessEr.code = 'EACCES' accessEr.path = dir return accessEr } install/actions.js000064400000013020152231567050010212 0ustar00'use strict' const BB = require('bluebird') const andAddParentToErrors = require('./and-add-parent-to-errors.js') const failedDependency = require('./deps.js').failedDependency const isInstallable = BB.promisify(require('./validate-args.js').isInstallable) const moduleName = require('../utils/module-name.js') const npm = require('../npm.js') const reportOptionalFailure = require('./report-optional-failure.js') const validate = require('aproba') const actions = {} actions.fetch = require('./action/fetch.js') actions.extract = require('./action/extract.js') actions.build = require('./action/build.js') actions.preinstall = require('./action/preinstall.js') actions.install = require('./action/install.js') actions.postinstall = require('./action/postinstall.js') actions.prepare = require('./action/prepare.js') actions.finalize = require('./action/finalize.js') actions.remove = require('./action/remove.js') actions.unbuild = require('./action/unbuild.js') actions.move = require('./action/move.js') actions['global-install'] = require('./action/global-install.js') actions['global-link'] = require('./action/global-link.js') actions['refresh-package-json'] = require('./action/refresh-package-json.js') // FIXME: We wrap actions like three ways to sunday here. // Rewrite this to only work one way. Object.keys(actions).forEach(function (actionName) { var action = actions[actionName] actions[actionName] = (staging, pkg, log) => { validate('SOO', [staging, pkg, log]) // refuse to run actions for failed packages if (pkg.failed) return BB.resolve() if (action.rollback) { if (!pkg.rollback) pkg.rollback = [] pkg.rollback.unshift(action.rollback) } if (action.commit) { if (!pkg.commit) pkg.commit = [] pkg.commit.push(action.commit) } let actionP if (pkg.knownInstallable) { actionP = runAction(action, staging, pkg, log) } else { actionP = isInstallable(null, pkg.package).then(() => { pkg.knownInstallable = true return runAction(action, staging, pkg, log) }) } return actionP.then(() => { log.finish() }, (err) => { return BB.fromNode((cb) => { andAddParentToErrors(pkg.parent, cb)(err) }).catch((err) => { return handleOptionalDepErrors(pkg, err) }) }) } actions[actionName].init = action.init || (() => BB.resolve()) actions[actionName].teardown = action.teardown || (() => BB.resolve()) }) exports.actions = actions function runAction (action, staging, pkg, log) { return BB.fromNode((cb) => { const result = action(staging, pkg, log, cb) if (result && result.then) { result.then(() => cb(), cb) } }) } function markAsFailed (pkg) { if (pkg.failed) return pkg.failed = true pkg.requires.forEach((req) => { var requiredBy = req.requiredBy.filter((reqReqBy) => !reqReqBy.failed) if (requiredBy.length === 0 && !req.userRequired) { markAsFailed(req) } }) } function handleOptionalDepErrors (pkg, err) { markAsFailed(pkg) var anyFatal = failedDependency(pkg) if (anyFatal) { throw err } else { reportOptionalFailure(pkg, null, err) } } exports.doOne = doOne function doOne (cmd, staging, pkg, log, next) { validate('SSOOF', arguments) const prepped = prepareAction([cmd, pkg], staging, log) return withInit(actions[cmd], () => { return execAction(prepped) }).nodeify(next) } exports.doParallel = doParallel function doParallel (type, staging, actionsToRun, log, next) { validate('SSAOF', arguments) const acts = actionsToRun.reduce((acc, todo) => { if (todo[0] === type) { acc.push(prepareAction(todo, staging, log)) } return acc }, []) log.silly('doParallel', type + ' ' + acts.length) time(log) if (!acts.length) { return next() } return withInit(actions[type], () => { return BB.map(acts, execAction, { concurrency: npm.limit.action }) }).nodeify((err) => { log.finish() timeEnd(log) next(err) }) } exports.doSerial = doSerial function doSerial (type, staging, actionsToRun, log, next) { validate('SSAOF', arguments) log.silly('doSerial', '%s %d', type, actionsToRun.length) runSerial(type, staging, actionsToRun, log, next) } exports.doReverseSerial = doReverseSerial function doReverseSerial (type, staging, actionsToRun, log, next) { validate('SSAOF', arguments) log.silly('doReverseSerial', '%s %d', type, actionsToRun.length) runSerial(type, staging, [].concat(actionsToRun).reverse(), log, next) } function runSerial (type, staging, actionsToRun, log, next) { const acts = actionsToRun.reduce((acc, todo) => { if (todo[0] === type) { acc.push(prepareAction(todo, staging, log)) } return acc }, []) time(log) if (!acts.length) { return next() } return withInit(actions[type], () => { return BB.each(acts, execAction) }).nodeify((err) => { log.finish() timeEnd(log) next(err) }) } function time (log) { process.emit('time', 'action:' + log.name) } function timeEnd (log) { process.emit('timeEnd', 'action:' + log.name) } function withInit (action, body) { return BB.using( action.init().disposer(() => action.teardown()), body ) } function prepareAction (action, staging, log) { validate('ASO', arguments) validate('SO', action) var cmd = action[0] var pkg = action[1] if (!actions[cmd]) throw new Error('Unknown decomposed command "' + cmd + '" (is it new?)') return [actions[cmd], staging, pkg, log.newGroup(cmd + ':' + moduleName(pkg))] } function execAction (todo) { return todo[0].apply(null, todo.slice(1)) } install/and-add-parent-to-errors.js000064400000000567152231567050013277 0ustar00'use strict' var moduleName = require('../utils/module-name.js') var validate = require('aproba') module.exports = function (parent, cb) { validate('F', [cb]) return function (er) { if (!er) return cb.apply(null, arguments) if (er instanceof Error && parent && parent.package && parent.package.name) { er.parent = moduleName(parent) } cb(er) } } install/and-finish-tracker.js000064400000000550152231567050012227 0ustar00'use strict' var validate = require('aproba') module.exports = function (tracker, cb) { validate('OF', [tracker, cb]) return function () { tracker.finish() cb.apply(null, arguments) } } module.exports.now = function (tracker, cb) { validate('OF', [tracker, cb]) tracker.finish() cb.apply(null, Array.prototype.slice.call(arguments, 2)) } install/and-ignore-errors.js000064400000000314152231567050012111 0ustar00'use strict' module.exports = function (cb) { return function () { var args = Array.prototype.slice.call(arguments, 1) if (args.length) args.unshift(null) return cb.apply(null, args) } } install/audit.js000064400000020371152231567050007667 0ustar00'use strict' exports.generate = generate exports.generateFromInstall = generateFromInstall exports.submitForInstallReport = submitForInstallReport exports.submitForFullReport = submitForFullReport exports.printInstallReport = printInstallReport exports.printParseableReport = printParseableReport exports.printFullReport = printFullReport const auditReport = require('npm-audit-report') const npmConfig = require('../config/figgy-config.js') const figgyPudding = require('figgy-pudding') const treeToShrinkwrap = require('../shrinkwrap.js').treeToShrinkwrap const packageId = require('../utils/package-id.js') const output = require('../utils/output.js') const npm = require('../npm.js') const qw = require('qw') const regFetch = require('npm-registry-fetch') const perf = require('../utils/perf.js') const npa = require('npm-package-arg') const uuid = require('uuid') const ssri = require('ssri') const cloneDeep = require('lodash.clonedeep') // used when scrubbing module names/specifiers const runId = uuid.v4() const InstallAuditConfig = figgyPudding({ color: {}, json: {}, unicode: {} }, { other (key) { return /:registry$/.test(key) } }) function submitForInstallReport (auditData) { const opts = InstallAuditConfig(npmConfig()) const scopedRegistries = [...opts.keys()].filter( k => /:registry$/.test(k) ).map(k => opts[k]) scopedRegistries.forEach(registry => { // we don't care about the response so destroy the stream if we can, or leave it flowing // so it can eventually finish and clean up after itself regFetch('/-/npm/v1/security/audits/quick', opts.concat({ method: 'POST', registry, gzip: true, body: auditData })).then(_ => { _.body.on('error', () => {}) if (_.body.destroy) { _.body.destroy() } else { _.body.resume() } }, _ => {}) }) perf.emit('time', 'audit submit') return regFetch('/-/npm/v1/security/audits/quick', opts.concat({ method: 'POST', gzip: true, body: auditData })).then(response => { perf.emit('timeEnd', 'audit submit') perf.emit('time', 'audit body') return response.json() }).then(result => { perf.emit('timeEnd', 'audit body') return result }) } function submitForFullReport (auditData) { perf.emit('time', 'audit submit') const opts = InstallAuditConfig(npmConfig()) return regFetch('/-/npm/v1/security/audits', opts.concat({ method: 'POST', gzip: true, body: auditData })).then(response => { perf.emit('timeEnd', 'audit submit') perf.emit('time', 'audit body') return response.json() }).then(result => { perf.emit('timeEnd', 'audit body') result.runId = runId return result }) } function printInstallReport (auditResult) { const opts = InstallAuditConfig(npmConfig()) return auditReport(auditResult, { reporter: 'install', withColor: opts.color, withUnicode: opts.unicode }).then(result => output(result.report)) } function printFullReport (auditResult) { const opts = InstallAuditConfig(npmConfig()) return auditReport(auditResult, { log: output, reporter: opts.json ? 'json' : 'detail', withColor: opts.color, withUnicode: opts.unicode }).then(result => output(result.report)) } function printParseableReport (auditResult) { const opts = InstallAuditConfig(npmConfig()) return auditReport(auditResult, { log: output, reporter: 'parseable', withColor: opts.color, withUnicode: opts.unicode }).then(result => output(result.report)) } function generate (shrinkwrap, requires, diffs, install, remove) { const sw = cloneDeep(shrinkwrap) delete sw.lockfileVersion sw.requires = scrubRequires(requires) scrubDeps(sw.dependencies) // sw.diffs = diffs || {} sw.install = (install || []).map(scrubArg) sw.remove = (remove || []).map(scrubArg) return generateMetadata().then((md) => { sw.metadata = md return sw }) } const scrubKeys = qw`version` const deleteKeys = qw`from resolved` function scrubDeps (deps) { if (!deps) return Object.keys(deps).forEach(name => { if (!shouldScrubName(name) && !shouldScrubSpec(name, deps[name].version)) return const value = deps[name] delete deps[name] deps[scrub(name)] = value }) Object.keys(deps).forEach(name => { for (let toScrub of scrubKeys) { if (!deps[name][toScrub]) continue deps[name][toScrub] = scrubSpec(name, deps[name][toScrub]) } for (let toDelete of deleteKeys) delete deps[name][toDelete] scrubRequires(deps[name].requires) scrubDeps(deps[name].dependencies) }) } function scrubRequires (reqs) { if (!reqs) return reqs Object.keys(reqs).forEach(name => { const spec = reqs[name] if (shouldScrubName(name) || shouldScrubSpec(name, spec)) { delete reqs[name] reqs[scrub(name)] = scrubSpec(name, spec) } else { reqs[name] = scrubSpec(name, spec) } }) return reqs } function getScope (name) { if (name[0] === '@') return name.slice(0, name.indexOf('/')) } function shouldScrubName (name) { const scope = getScope(name) const cfg = npm.config // avoid the no-dynamic-lookups test return Boolean(scope && cfg.get(scope + ':registry')) } function shouldScrubSpec (name, spec) { const req = npa.resolve(name, spec) return !req.registry } function scrubArg (arg) { const req = npa(arg) let name = req.name if (shouldScrubName(name) || shouldScrubSpec(name, req.rawSpec)) { name = scrubName(name) } const spec = scrubSpec(req.name, req.rawSpec) return name + '@' + spec } function scrubName (name) { return shouldScrubName(name) ? scrub(name) : name } function scrubSpec (name, spec) { const req = npa.resolve(name, spec) if (req.registry) return spec if (req.type === 'git') { return 'git+ssh://' + scrub(spec) } else if (req.type === 'remote') { return 'https://' + scrub(spec) } else if (req.type === 'directory') { return 'file:' + scrub(spec) } else if (req.type === 'file') { return 'file:' + scrub(spec) + '.tar' } else { return scrub(spec) } } module.exports.scrub = scrub function scrub (value, rid) { return ssri.fromData((rid || runId) + ' ' + value, {algorithms: ['sha256']}).hexDigest() } function generateMetadata () { const meta = {} meta.npm_version = npm.version meta.node_version = process.version meta.platform = process.platform meta.node_env = process.env.NODE_ENV return Promise.resolve(meta) } /* const head = path.resolve(npm.prefix, '.git/HEAD') return readFile(head, 'utf8').then((head) => { if (!head.match(/^ref: /)) { meta.commit_hash = head.trim() return } const headFile = head.replace(/^ref: /, '').trim() meta.branch = headFile.replace(/^refs[/]heads[/]/, '') return readFile(path.resolve(npm.prefix, '.git', headFile), 'utf8') }).then((commitHash) => { meta.commit_hash = commitHash.trim() const proc = spawn('git', qw`diff --quiet --exit-code package.json package-lock.json`, {cwd: npm.prefix, stdio: 'ignore'}) return new Promise((resolve, reject) => { proc.once('error', reject) proc.on('exit', (code, signal) => { if (signal == null) meta.state = code === 0 ? 'clean' : 'dirty' resolve() }) }) }).then(() => meta, () => meta) */ function generateFromInstall (tree, diffs, install, remove) { const requires = {} tree.requires.forEach((pkg) => { requires[pkg.package.name] = tree.package.dependencies[pkg.package.name] || tree.package.devDependencies[pkg.package.name] || pkg.package.version }) const auditInstall = (install || []).filter((a) => a.name).map(packageId) const auditRemove = (remove || []).filter((a) => a.name).map(packageId) const auditDiffs = {} diffs.forEach((action) => { const mutation = action[0] const child = action[1] if (mutation !== 'add' && mutation !== 'update' && mutation !== 'remove') return if (!auditDiffs[mutation]) auditDiffs[mutation] = [] if (mutation === 'add') { auditDiffs[mutation].push({location: child.location}) } else if (mutation === 'update') { auditDiffs[mutation].push({location: child.location, previous: packageId(child.oldPkg)}) } else if (mutation === 'remove') { auditDiffs[mutation].push({previous: packageId(child)}) } }) return generate(treeToShrinkwrap(tree), requires, auditDiffs, auditInstall, auditRemove) } install/check-permissions.js000064400000003551152231567050012210 0ustar00'use strict' var path = require('path') var log = require('npmlog') var validate = require('aproba') var uniq = require('lodash.uniq') var asyncMap = require('slide').asyncMap var npm = require('../npm.js') var exists = require('./exists.js') var writable = require('./writable.js') module.exports = function (actions, next) { validate('AF', arguments) var errors = [] asyncMap(actions, function (action, done) { var cmd = action[0] var pkg = action[1] switch (cmd) { case 'add': hasAnyWriteAccess(path.resolve(pkg.path, '..'), errors, done) break case 'update': case 'remove': hasWriteAccess(pkg.path, errors, andHasWriteAccess(path.resolve(pkg.path, '..'), errors, done)) break case 'move': hasAnyWriteAccess(pkg.path, errors, andHasWriteAccess(path.resolve(pkg.fromPath, '..'), errors, done)) break default: done() } }, function () { if (!errors.length) return next() uniq(errors.map(function (er) { return 'Missing write access to ' + er.path })).forEach(function (er) { log.warn('checkPermissions', er) }) npm.config.get('force') ? next() : next(errors[0]) }) } function andHasWriteAccess (dir, errors, done) { validate('SAF', arguments) return function () { hasWriteAccess(dir, errors, done) } } function hasAnyWriteAccess (dir, errors, done) { validate('SAF', arguments) findNearestDir() function findNearestDir () { var nextDir = path.resolve(dir, '..') exists(dir, function (dirDoesntExist) { if (!dirDoesntExist || nextDir === dir) { return hasWriteAccess(dir, errors, done) } else { dir = nextDir findNearestDir() } }) } } function hasWriteAccess (dir, errors, done) { validate('SAF', arguments) writable(dir, function (er) { if (er) errors.push(er) done() }) } install/copy-tree.js000064400000001402152231567050010462 0ustar00'use strict' var createNode = require('./node.js').create module.exports = function (tree) { return copyTree(tree, {}) } function copyTree (tree, cache) { if (cache[tree.path]) { return cache[tree.path] } var newTree = cache[tree.path] = createNode(Object.assign({}, tree)) copyModuleList(newTree, 'children', cache) newTree.children.forEach(function (child) { child.parent = newTree }) copyModuleList(newTree, 'requires', cache) copyModuleList(newTree, 'requiredBy', cache) return newTree } function copyModuleList (tree, key, cache) { var newList = [] if (tree[key]) { tree[key].forEach(function (child) { const copy = copyTree(child, cache) if (copy) { newList.push(copy) } }) } tree[key] = newList } install/decompose-actions.js000064400000004270152231567050012175 0ustar00'use strict' var validate = require('aproba') var npm = require('../npm.js') module.exports = function (differences, decomposed, next) { validate('AAF', arguments) differences.forEach((action) => { var cmd = action[0] var pkg = action[1] switch (cmd) { case 'add': addSteps(decomposed, pkg) break case 'update': updateSteps(decomposed, pkg) break case 'move': moveSteps(decomposed, pkg) break case 'remove': removeSteps(decomposed, pkg) break default: defaultSteps(decomposed, cmd, pkg) } }) next() } function addAction (decomposed, action, pkg) { if (decomposed.some((_) => _[0] === action && _[1] === pkg)) return decomposed.push([action, pkg]) } function addSteps (decomposed, pkg) { if (pkg.fromBundle) { // make sure our source module exists to extract ourselves from // if we're installing our source module anyway, the duplication // of these steps will be elided by `addAction` automatically addAction(decomposed, 'fetch', pkg.fromBundle) addAction(decomposed, 'extract', pkg.fromBundle) } if (!pkg.fromBundle && !pkg.isLink) { addAction(decomposed, 'fetch', pkg) addAction(decomposed, 'extract', pkg) } if (!pkg.fromBundle || npm.config.get('rebuild-bundle')) { addAction(decomposed, 'preinstall', pkg) addAction(decomposed, 'build', pkg) addAction(decomposed, 'install', pkg) addAction(decomposed, 'postinstall', pkg) } if (!pkg.fromBundle || !pkg.isLink) { addAction(decomposed, 'finalize', pkg) } addAction(decomposed, 'refresh-package-json', pkg) } function updateSteps (decomposed, pkg) { removeSteps(decomposed, pkg.oldPkg) addSteps(decomposed, pkg) } function removeSteps (decomposed, pkg) { addAction(decomposed, 'unbuild', pkg) addAction(decomposed, 'remove', pkg) } function moveSteps (decomposed, pkg) { addAction(decomposed, 'move', pkg) addAction(decomposed, 'build', pkg) addAction(decomposed, 'install', pkg) addAction(decomposed, 'postinstall', pkg) addAction(decomposed, 'refresh-package-json', pkg) } function defaultSteps (decomposed, cmd, pkg) { addAction(decomposed, cmd, pkg) } install/deps.js000064400000074510152231567050007520 0ustar00'use strict' const BB = require('bluebird') var fs = require('fs') var assert = require('assert') var path = require('path') var semver = require('semver') var asyncMap = require('slide').asyncMap var chain = require('slide').chain var iferr = require('iferr') var npa = require('npm-package-arg') var validate = require('aproba') var dezalgo = require('dezalgo') var fetchPackageMetadata = require('../fetch-package-metadata.js') var andAddParentToErrors = require('./and-add-parent-to-errors.js') var addBundled = require('../fetch-package-metadata.js').addBundled var readShrinkwrap = require('./read-shrinkwrap.js') var inflateShrinkwrap = require('./inflate-shrinkwrap.js') var inflateBundled = require('./inflate-bundled.js') var andFinishTracker = require('./and-finish-tracker.js') var npm = require('../npm.js') var flatNameFromTree = require('./flatten-tree.js').flatNameFromTree var createChild = require('./node.js').create var resetMetadata = require('./node.js').reset var isInstallable = require('./validate-args.js').isInstallable var packageId = require('../utils/package-id.js') var moduleName = require('../utils/module-name.js') var isDevDep = require('./is-dev-dep.js') var isProdDep = require('./is-prod-dep.js') var reportOptionalFailure = require('./report-optional-failure.js') var getSaveType = require('./save.js').getSaveType var unixFormatPath = require('../utils/unix-format-path.js') var isExtraneous = require('./is-extraneous.js') var isRegistry = require('../utils/is-registry.js') var hasModernMeta = require('./has-modern-meta.js') // The export functions in this module mutate a dependency tree, adding // items to them. var registryTypes = { range: true, version: true } function doesChildVersionMatch (child, requested, requestor) { if (child.fromShrinkwrap && !child.hasRequiresFromLock) return true // ranges of * ALWAYS count as a match, because when downloading we allow // prereleases to match * if there are ONLY prereleases if (requested.type === 'range' && requested.fetchSpec === '*') return true if (requested.type === 'directory') { if (!child.isLink) return false return path.relative(child.realpath, requested.fetchSpec) === '' } if (requested.type === 'git' && child.fromShrinkwrap) { const fromSw = child.package._from ? npa(child.package._from) : child.fromShrinkwrap fromSw.name = requested.name // we're only checking specifiers here if (fromSw.toString() === requested.toString()) return true } if (requested.type === 'git' && requested.gitRange) { const sameRepo = npa(child.package._from).fetchSpec === requested.fetchSpec try { return sameRepo && semver.satisfies(child.package.version, requested.gitRange, true) } catch (e) { return false } } if (requested.type === 'alias') { return doesChildVersionMatch(child, requested.subSpec, requestor) } if (!registryTypes[requested.type]) { var childReq = child.package._requested if (childReq) { if (childReq.rawSpec === requested.rawSpec) return true if (childReq.type === requested.type) { if (childReq.saveSpec === requested.saveSpec) return true if ((childReq.fetchSpec === requested.fetchSpec) && requested.type !== 'git') return true } } // If _requested didn't exist OR if it didn't match then we'll try using // _from. We pass it through npa to normalize the specifier. // This can happen when installing from an `npm-shrinkwrap.json` where `_requested` will // be the tarball URL from `resolved` and thus can't match what's in the `package.json`. // In those cases _from, will be preserved and we can compare that to ensure that they // really came from the same sources. // You'll see this scenario happen with at least tags and git dependencies. // Some buggy clients will write spaces into the module name part of a _from. if (child.package._from) { var fromReq = npa(child.package._from) if (fromReq.rawSpec === requested.rawSpec) return true if (fromReq.type === requested.type && fromReq.saveSpec && fromReq.saveSpec === requested.saveSpec) return true } return false } try { return semver.satisfies(child.package.version, requested.fetchSpec, true) } catch (e) { return false } } function childDependencySpecifier (tree, name, spec, where) { return npa.resolve(name, spec, where || packageRelativePath(tree)) } exports.computeMetadata = computeMetadata function computeMetadata (tree, seen) { if (!seen) seen = new Set() if (!tree || seen.has(tree)) return seen.add(tree) if (tree.parent == null) { resetMetadata(tree) tree.isTop = true } tree.location = flatNameFromTree(tree) function findChild (name, spec, kind) { try { var req = childDependencySpecifier(tree, name, spec) } catch (err) { return } var child = findRequirement(tree, req.name, req) if (child) { resolveWithExistingModule(child, tree) return true } } const deps = tree.package.dependencies || {} const reqs = tree.swRequires || {} for (let name of Object.keys(deps)) { if (findChild(name, deps[name])) continue if (name in reqs && findChild(name, reqs[name])) continue tree.missingDeps[name] = deps[name] } if (tree.isTop) { const devDeps = tree.package.devDependencies || {} for (let name of Object.keys(devDeps)) { if (findChild(name, devDeps[name])) continue tree.missingDevDeps[name] = devDeps[name] } } tree.children.filter((child) => !child.removed).forEach((child) => computeMetadata(child, seen)) return tree } function isDep (tree, child) { var name = moduleName(child) var prodVer = isProdDep(tree, name) var devVer = isDevDep(tree, name) try { var prodSpec = childDependencySpecifier(tree, name, prodVer) } catch (err) { return {isDep: true, isProdDep: false, isDevDep: false} } var matches if (prodSpec) matches = doesChildVersionMatch(child, prodSpec, tree) if (matches) return {isDep: true, isProdDep: prodSpec, isDevDep: false} if (devVer === prodVer) return {isDep: child.fromShrinkwrap, isProdDep: false, isDevDep: false} try { var devSpec = childDependencySpecifier(tree, name, devVer) return {isDep: doesChildVersionMatch(child, devSpec, tree) || child.fromShrinkwrap, isProdDep: false, isDevDep: devSpec} } catch (err) { return {isDep: child.fromShrinkwrap, isProdDep: false, isDevDep: false} } } function addRequiredDep (tree, child) { var dep = isDep(tree, child) if (!dep.isDep) return false replaceModuleByPath(child, 'requiredBy', tree) replaceModuleByName(tree, 'requires', child) if (dep.isProdDep && tree.missingDeps) delete tree.missingDeps[moduleName(child)] if (dep.isDevDep && tree.missingDevDeps) delete tree.missingDevDeps[moduleName(child)] return true } exports.removeObsoleteDep = removeObsoleteDep function removeObsoleteDep (child, log) { if (child.removed) return child.removed = true if (log) { log.silly('removeObsoleteDep', 'removing ' + packageId(child) + ' from the tree as its been replaced by a newer version or is no longer required') } // remove from physical tree if (child.parent) { child.parent.children = child.parent.children.filter(function (pchild) { return pchild !== child }) } // remove from logical tree var requires = child.requires || [] requires.forEach(function (requirement) { requirement.requiredBy = requirement.requiredBy.filter(function (reqBy) { return reqBy !== child }) // we don't just check requirement.requires because that doesn't account // for circular deps. isExtraneous does. if (isExtraneous(requirement)) removeObsoleteDep(requirement, log) }) } exports.packageRelativePath = packageRelativePath function packageRelativePath (tree) { if (!tree) return '' var requested = tree.package._requested || {} if (requested.type === 'directory') { return requested.fetchSpec } else if (requested.type === 'file') { return path.dirname(requested.fetchSpec) } else if ((tree.isLink || tree.isInLink) && !preserveSymlinks()) { return tree.realpath } else { return tree.path } } function matchingDep (tree, name) { if (!tree || !tree.package) return if (tree.package.dependencies && tree.package.dependencies[name]) return tree.package.dependencies[name] if (tree.package.devDependencies && tree.package.devDependencies[name]) return tree.package.devDependencies[name] } exports.getAllMetadata = function (args, tree, where, next) { asyncMap(args, function (arg, done) { let spec try { spec = npa(arg) } catch (e) { return done(e) } if (spec.type !== 'file' && spec.type !== 'directory' && (spec.name == null || spec.rawSpec === '')) { return fs.stat(path.join(arg, 'package.json'), (err) => { if (err) { var version = matchingDep(tree, spec.name) if (version) { try { return fetchPackageMetadata(npa.resolve(spec.name, version), where, done) } catch (e) { return done(e) } } else { return fetchPackageMetadata(spec, where, done) } } else { try { return fetchPackageMetadata(npa('file:' + arg), where, done) } catch (e) { return done(e) } } }) } else { return fetchPackageMetadata(spec, where, done) } }, next) } // Add a list of args to tree's top level dependencies exports.loadRequestedDeps = function (args, tree, saveToDependencies, log, next) { validate('AOOF', [args, tree, log, next]) asyncMap(args, function (pkg, done) { var depLoaded = andAddParentToErrors(tree, done) resolveWithNewModule(pkg, tree, log.newGroup('loadRequestedDeps'), iferr(depLoaded, function (child, tracker) { validate('OO', arguments) if (npm.config.get('global')) { child.isGlobal = true } var childName = moduleName(child) child.saveSpec = computeVersionSpec(tree, child) child.userRequired = true child.save = getSaveType(tree, child) const types = ['dependencies', 'devDependencies', 'optionalDependencies'] if (child.save) { tree.package[child.save][childName] = child.saveSpec // Astute readers might notice that this exact same code exists in // save.js under a different guise. That code is responsible for deps // being removed from the final written `package.json`. The removal in // this function is specifically to prevent "installed as both X and Y" // warnings when moving an existing dep between different dep fields. // // Or, try it by removing this loop, and do `npm i -P x && npm i -D x` for (let saveType of types) { if (child.save !== saveType) { delete tree.package[saveType][childName] } } if (child.save === 'optionalDependencies') tree.package.dependencies[childName] = child.saveSpec } // For things the user asked to install, that aren't a dependency (or // won't be when we're done), flag it as "depending" on the user // themselves, so we don't remove it as a dep that no longer exists var childIsDep = addRequiredDep(tree, child) if (!childIsDep) child.userRequired = true depLoaded(null, child, tracker) })) }, andForEachChild(loadDeps, andFinishTracker(log, next))) } function isNotEmpty (value) { return value != null && value !== '' } exports.computeVersionSpec = computeVersionSpec function computeVersionSpec (tree, child) { validate('OO', arguments) var requested var childReq = child.package._requested if (child.isLink) { requested = npa.resolve(moduleName(child), 'file:' + child.realpath, getTop(tree).path) } else if (childReq && (isNotEmpty(childReq.saveSpec) || (isNotEmpty(childReq.rawSpec) && isNotEmpty(childReq.fetchSpec)))) { requested = child.package._requested } else if (child.package._from) { requested = npa(child.package._from, tree.path) } else if (child.name && child.name !== child.package.name) { requested = npa.resolve(child.name, `npm:${child.package.name}@${child.package.version})`) } else { requested = npa.resolve(child.package.name, child.package.version) } if (isRegistry(requested)) { var version = child.package.version var rangeDescriptor = '' if (semver.valid(version, true) && semver.gte(version, '0.1.0', true) && !npm.config.get('save-exact')) { rangeDescriptor = npm.config.get('save-prefix') } if (requested.type === 'alias') { rangeDescriptor = `npm:${requested.subSpec.name}@${rangeDescriptor}` } return rangeDescriptor + version } else if (requested.type === 'directory' || requested.type === 'file') { return 'file:' + unixFormatPath(path.relative(getTop(tree).path, requested.fetchSpec)) } else { return requested.saveSpec || requested.rawSpec } } function moduleNameMatches (name) { return function (child) { return moduleName(child) === name } } // while this implementation does not require async calling, doing so // gives this a consistent interface with loadDeps et al exports.removeDeps = function (args, tree, saveToDependencies, next) { validate('AOSF|AOZF', [args, tree, saveToDependencies, next]) for (let pkg of args) { var pkgName = moduleName(pkg) var toRemove = tree.children.filter(moduleNameMatches(pkgName)) var pkgToRemove = toRemove[0] || createChild({name: pkgName}) var saveType = getSaveType(tree, pkg) || 'dependencies' if (tree.isTop && saveToDependencies) { pkgToRemove.save = saveType } if (tree.package[saveType][pkgName]) { delete tree.package[saveType][pkgName] if (saveType === 'optionalDependencies' && tree.package.dependencies[pkgName]) { delete tree.package.dependencies[pkgName] } } replaceModuleByPath(tree, 'removedChildren', pkgToRemove) for (let parent of pkgToRemove.requiredBy) { parent.requires = parent.requires.filter((child) => child !== pkgToRemove) } pkgToRemove.requiredBy = pkgToRemove.requiredBy.filter((parent) => parent !== tree) flagAsRemoving(pkgToRemove) } next() } function flagAsRemoving (toRemove, seen) { if (!seen) seen = new Set() if (seen.has(toRemove)) return seen.add(toRemove) toRemove.removing = true toRemove.requires.forEach((required) => { flagAsRemoving(required, seen) }) } exports.removeExtraneous = function (args, tree, next) { for (let pkg of args) { var pkgName = moduleName(pkg) var toRemove = tree.children.filter(moduleNameMatches(pkgName)) if (toRemove.length) { removeObsoleteDep(toRemove[0]) } } next() } function andForEachChild (load, next) { validate('F', [next]) next = dezalgo(next) return function (er, children, logs) { // when children is empty, logs won't be passed in at all (asyncMap is weird) // so shortcircuit before arg validation if (!er && (!children || children.length === 0)) return next() validate('EAA', arguments) if (er) return next(er) assert(children.length === logs.length) var cmds = [] for (var ii = 0; ii < children.length; ++ii) { cmds.push([load, children[ii], logs[ii]]) } var sortedCmds = cmds.sort(function installOrder (aa, bb) { return moduleName(aa[1]).localeCompare(moduleName(bb[1])) }) chain(sortedCmds, next) } } function isDepOptional (tree, name, pkg) { if (pkg.package && pkg.package._optional) return true const optDeps = tree.package.optionalDependencies if (optDeps && optDeps[name] != null) return true const devDeps = tree.package.devDependencies if (devDeps && devDeps[name] != null) { const includeDev = npm.config.get('dev') || (!/^prod(uction)?$/.test(npm.config.get('only')) && !npm.config.get('production')) || /^dev(elopment)?$/.test(npm.config.get('only')) || /^dev(elopment)?$/.test(npm.config.get('also')) return !includeDev } const prodDeps = tree.package.dependencies if (prodDeps && prodDeps[name] != null) { const includeProd = !/^dev(elopment)?$/.test(npm.config.get('only')) return !includeProd } return false } exports.failedDependency = failedDependency function failedDependency (tree, name, pkg) { if (name) { if (isDepOptional(tree, name, pkg || {})) { return false } } tree.failed = true if (tree.isTop) return true if (tree.userRequired) return true if (!tree.requiredBy) return false let anyFailed = false for (var ii = 0; ii < tree.requiredBy.length; ++ii) { var requireParent = tree.requiredBy[ii] if (failedDependency(requireParent, moduleName(tree), tree)) { anyFailed = true } } return anyFailed } function andHandleOptionalErrors (log, tree, name, done) { validate('OOSF', arguments) return function (er, child, childLog) { if (!er) validate('OO', [child, childLog]) if (!er) return done(er, child, childLog) var isFatal = failedDependency(tree, name) if (er && !isFatal) { reportOptionalFailure(tree, name, er) return done() } else { return done(er, child, childLog) } } } exports.prefetchDeps = prefetchDeps function prefetchDeps (tree, deps, log, next) { validate('OOOF', arguments) var skipOptional = !npm.config.get('optional') var seen = new Set() const finished = andFinishTracker(log, next) const fpm = BB.promisify(fetchPackageMetadata) resolveBranchDeps(tree.package, deps).then( () => finished(), finished ) function resolveBranchDeps (pkg, deps) { return BB.resolve(null).then(() => { var allDependencies = Object.keys(deps).map((dep) => { return npa.resolve(dep, deps[dep]) }).filter((dep) => { return isRegistry(dep) && !seen.has(dep.toString()) && !findRequirement(tree, dep.name, dep) }) if (skipOptional) { var optDeps = pkg.optionalDependencies || {} allDependencies = allDependencies.filter((dep) => !optDeps[dep.name]) } return BB.map(allDependencies, (dep) => { seen.add(dep.toString()) return fpm(dep, '', {tracker: log.newItem('fetchMetadata')}).then( (pkg) => { return pkg && pkg.dependencies && resolveBranchDeps(pkg, pkg.dependencies) }, () => null ) }) }) } } // Load any missing dependencies in the given tree exports.loadDeps = loadDeps function loadDeps (tree, log, next) { validate('OOF', arguments) if (tree.loaded || (tree.parent && tree.parent.failed) || tree.removed) return andFinishTracker.now(log, next) if (tree.parent) tree.loaded = true if (!tree.package.dependencies) tree.package.dependencies = {} asyncMap(Object.keys(tree.package.dependencies), function (dep, done) { var version = tree.package.dependencies[dep] addDependency(dep, version, tree, log.newGroup('loadDep:' + dep), andHandleOptionalErrors(log, tree, dep, done)) }, andForEachChild(loadDeps, andFinishTracker(log, next))) } // Load development dependencies into the given tree exports.loadDevDeps = function (tree, log, next) { validate('OOF', arguments) if (!tree.package.devDependencies) return andFinishTracker.now(log, next) asyncMap(Object.keys(tree.package.devDependencies), function (dep, done) { // things defined as both dev dependencies and regular dependencies are treated // as the former if (tree.package.dependencies[dep]) return done() var logGroup = log.newGroup('loadDevDep:' + dep) addDependency(dep, tree.package.devDependencies[dep], tree, logGroup, andHandleOptionalErrors(log, tree, dep, done)) }, andForEachChild(loadDeps, andFinishTracker(log, next))) } var loadExtraneous = exports.loadExtraneous = function (tree, log, next) { var seen = new Set() function loadExtraneous (tree) { if (seen.has(tree)) return seen.add(tree) for (var child of tree.children) { if (child.loaded) continue resolveWithExistingModule(child, tree) loadExtraneous(child) } } loadExtraneous(tree) log.finish() next() } exports.loadExtraneous.andResolveDeps = function (tree, log, next) { validate('OOF', arguments) // For canonicalized trees (eg from shrinkwrap) we don't want to bother // resolving the dependencies of extraneous deps. if (tree.loaded) return loadExtraneous(tree, log, next) asyncMap(tree.children.filter(function (child) { return !child.loaded }), function (child, done) { resolveWithExistingModule(child, tree) done(null, child, log) }, andForEachChild(loadDeps, andFinishTracker(log, next))) } function addDependency (name, versionSpec, tree, log, done) { validate('SSOOF', arguments) var next = andAddParentToErrors(tree, done) try { var req = childDependencySpecifier(tree, name, versionSpec) if (tree.swRequires && tree.swRequires[name]) { var swReq = childDependencySpecifier(tree, name, tree.swRequires[name]) } } catch (err) { return done(err) } var child = findRequirement(tree, name, req) if (!child && swReq) child = findRequirement(tree, name, swReq) if (hasModernMeta(child)) { resolveWithExistingModule(child, tree) if (child.package._shrinkwrap === undefined) { readShrinkwrap.andInflate(child, function (er) { next(er, child, log) }) } else { next(null, child, log) } } else { if (child) { if (req.registry) { req = childDependencySpecifier(tree, name, child.package.version) } if (child.fromBundle) reportBundleOverride(child, log) removeObsoleteDep(child, log) } fetchPackageMetadata(req, packageRelativePath(tree), {tracker: log.newItem('fetchMetadata')}, iferr(next, function (pkg) { resolveWithNewModule(pkg, tree, log, next) })) } } function getTop (pkg) { const seen = new Set() while (pkg.parent && !seen.has(pkg.parent)) { pkg = pkg.parent seen.add(pkg) } return pkg } function reportBundleOverride (child, log) { const code = 'EBUNDLEOVERRIDE' const top = getTop(child.fromBundle) const bundlerId = packageId(child.fromBundle) if (!top.warnings.some((w) => { return w.code === code })) { const err = new Error(`${bundlerId} had bundled packages that do not match the required version(s). They have been replaced with non-bundled versions.`) err.code = code top.warnings.push(err) } if (log) log.verbose('bundle', `${code}: Replacing ${bundlerId}'s bundled version of ${moduleName(child)} with ${packageId(child)}.`) } function resolveWithExistingModule (child, tree) { validate('OO', arguments) addRequiredDep(tree, child) if (tree.parent && child.parent !== tree) updatePhantomChildren(tree.parent, child) } var updatePhantomChildren = exports.updatePhantomChildren = function (current, child) { validate('OO', arguments) while (current && current !== child.parent) { if (!current.phantomChildren) current.phantomChildren = {} current.phantomChildren[moduleName(child)] = child current = current.parent } } exports._replaceModuleByPath = replaceModuleByPath function replaceModuleByPath (obj, key, child) { return replaceModule(obj, key, child, function (replacing, child) { return replacing.path === child.path }) } exports._replaceModuleByName = replaceModuleByName function replaceModuleByName (obj, key, child) { var childName = moduleName(child) return replaceModule(obj, key, child, function (replacing, child) { return moduleName(replacing) === childName }) } function replaceModule (obj, key, child, matchBy) { validate('OSOF', arguments) if (!obj[key]) obj[key] = [] // we replace children with a new array object instead of mutating it // because mutating it results in weird failure states. // I would very much like to know _why_ this is. =/ var children = [].concat(obj[key]) for (var replaceAt = 0; replaceAt < children.length; ++replaceAt) { if (matchBy(children[replaceAt], child)) break } var replacing = children.splice(replaceAt, 1, child) obj[key] = children return replacing[0] } function resolveWithNewModule (pkg, tree, log, next) { validate('OOOF', arguments) log.silly('resolveWithNewModule', packageId(pkg), 'checking installable status') return isInstallable(tree, pkg, (err) => { let installable = !err addBundled(pkg, (bundleErr) => { var parent = earliestInstallable(tree, tree, pkg, log) || tree var isLink = pkg._requested.type === 'directory' var name = pkg._requested.name || pkg.name var child = createChild({ name, package: pkg, parent: parent, path: path.join(parent.isLink ? parent.realpath : parent.path, 'node_modules', name), realpath: isLink ? pkg._requested.fetchSpec : path.join(parent.realpath, 'node_modules', name), children: pkg._bundled || [], isLink: isLink, isInLink: parent.isLink, knownInstallable: installable }) if (!installable || bundleErr) child.failed = true delete pkg._bundled var hasBundled = child.children.length var replaced = replaceModuleByName(parent, 'children', child) if (replaced) { if (replaced.fromBundle) reportBundleOverride(replaced, log) removeObsoleteDep(replaced) } addRequiredDep(tree, child) child.location = flatNameFromTree(child) if (tree.parent && parent !== tree) updatePhantomChildren(tree.parent, child) if (hasBundled) { inflateBundled(child, child, child.children) } if (pkg._shrinkwrap && pkg._shrinkwrap.dependencies) { return inflateShrinkwrap(child, pkg._shrinkwrap, (swErr) => { if (swErr) child.failed = true next(err || bundleErr || swErr, child, log) }) } next(err || bundleErr, child, log) }) }) } var isOptionalPeerDep = exports.isOptionalPeerDep = function (tree, pkgname) { if (!tree.package.peerDependenciesMeta) return if (!tree.package.peerDependenciesMeta[pkgname]) return return !!tree.package.peerDependenciesMeta[pkgname].optional } var validatePeerDeps = exports.validatePeerDeps = function (tree, onInvalid) { if (!tree.package.peerDependencies) return Object.keys(tree.package.peerDependencies).forEach(function (pkgname) { var version = tree.package.peerDependencies[pkgname] try { var spec = npa.resolve(pkgname, version) } catch (e) {} var match = spec && findRequirement(tree.parent || tree, pkgname, spec) if (!match && !isOptionalPeerDep(tree, pkgname)) onInvalid(tree, pkgname, version) }) } exports.validateAllPeerDeps = function (tree, onInvalid) { validateAllPeerDeps(tree, onInvalid, new Set()) } function validateAllPeerDeps (tree, onInvalid, seen) { validate('OFO', arguments) if (seen.has(tree)) return seen.add(tree) validatePeerDeps(tree, onInvalid) tree.children.forEach(function (child) { validateAllPeerDeps(child, onInvalid, seen) }) } // Determine if a module requirement is already met by the tree at or above // our current location in the tree. var findRequirement = exports.findRequirement = function (tree, name, requested, requestor) { validate('OSO', [tree, name, requested]) if (!requestor) requestor = tree var nameMatch = function (child) { return moduleName(child) === name && child.parent && !child.removed } var versionMatch = function (child) { return doesChildVersionMatch(child, requested, requestor) } if (nameMatch(tree)) { // this *is* the module, but it doesn't match the version, so a // new copy will have to be installed return versionMatch(tree) ? tree : null } var matches = tree.children.filter(nameMatch) if (matches.length) { matches = matches.filter(versionMatch) // the module exists as a dependent, but the version doesn't match, so // a new copy will have to be installed above here if (matches.length) return matches[0] return null } if (tree.isTop) return null if (!preserveSymlinks() && /^[.][.][\\/]/.test(path.relative(tree.parent.realpath, tree.realpath))) return null return findRequirement(tree.parent, name, requested, requestor) } function preserveSymlinks () { if (!('NODE_PRESERVE_SYMLINKS' in process.env)) return false const value = process.env.NODE_PRESERVE_SYMLINKS if (value == null || value === '' || value === 'false' || value === 'no' || value === '0') return false return true } // Find the highest level in the tree that we can install this module in. // If the module isn't installed above us yet, that'd be the very top. // If it is, then it's the level below where its installed. var earliestInstallable = exports.earliestInstallable = function (requiredBy, tree, pkg, log) { validate('OOOO', arguments) function undeletedModuleMatches (child) { return !child.removed && moduleName(child) === ((pkg._requested && pkg._requested.name) || pkg.name) } const undeletedMatches = tree.children.filter(undeletedModuleMatches) if (undeletedMatches.length) { // if there's a conflict with another child AT THE SAME level then we're replacing it, so // mark it as removed and continue with resolution normally. if (tree === requiredBy) { undeletedMatches.forEach((pkg) => { if (pkg.fromBundle) reportBundleOverride(pkg, log) removeObsoleteDep(pkg, log) }) } else { return null } } // If any of the children of this tree have conflicting // binaries then we need to decline to install this package here. var binaryMatches = pkg.bin && tree.children.some(function (child) { if (child.removed || !child.package.bin) return false return Object.keys(child.package.bin).some(function (bin) { return pkg.bin[bin] }) }) if (binaryMatches) return null // if this tree location requested the same module then we KNOW it // isn't compatible because if it were findRequirement would have // found that version. var deps = tree.package.dependencies || {} if (!tree.removed && requiredBy !== tree && deps[pkg.name]) { return null } var devDeps = tree.package.devDependencies || {} if (tree.isTop && devDeps[pkg.name]) { var requested = childDependencySpecifier(tree, pkg.name, devDeps[pkg.name]) if (!doesChildVersionMatch({package: pkg}, requested, tree)) { return null } } if (tree.phantomChildren && tree.phantomChildren[pkg.name]) return null if (tree.isTop) return tree if (tree.isGlobal) return tree if (npm.config.get('global-style') && tree.parent.isTop) return tree if (npm.config.get('legacy-bundling')) return tree if (!preserveSymlinks() && /^[.][.][\\/]/.test(path.relative(tree.parent.realpath, tree.realpath))) return tree return (earliestInstallable(requiredBy, tree.parent, pkg, log) || tree) } install/diff-trees.js000064400000022172152231567050010612 0ustar00'use strict' var npm = require('../npm.js') var validate = require('aproba') var npa = require('npm-package-arg') var flattenTree = require('./flatten-tree.js') var isOnlyDev = require('./is-only-dev.js') var log = require('npmlog') var path = require('path') var ssri = require('ssri') var moduleName = require('../utils/module-name.js') var isOnlyOptional = require('./is-only-optional.js') // we don't use get-requested because we're operating on files on disk, and // we don't want to extrapolate from what _should_ be there. function pkgRequested (pkg) { return pkg._requested || (pkg._resolved && npa(pkg._resolved)) || (pkg._from && npa(pkg._from)) } function nonRegistrySource (requested) { if (fromGit(requested)) return true if (fromLocal(requested)) return true if (fromRemote(requested)) return true return false } function fromRemote (requested) { if (requested.type === 'remote') return true } function fromLocal (requested) { // local is an npm@3 type that meant "file" if (requested.type === 'file' || requested.type === 'directory' || requested.type === 'local') return true return false } function fromGit (requested) { if (requested.type === 'hosted' || requested.type === 'git') return true return false } function pkgIntegrity (pkg) { try { // dist is provided by the registry var sri = (pkg.dist && pkg.dist.integrity) || // _integrity is provided by pacote pkg._integrity || // _shasum is legacy (pkg._shasum && ssri.fromHex(pkg._shasum, 'sha1').toString()) if (!sri) return var integrity = ssri.parse(sri) if (Object.keys(integrity).length === 0) return return integrity } catch (ex) { } } function sriMatch (aa, bb) { if (!aa || !bb) return false for (let algo of Object.keys(aa)) { if (!bb[algo]) continue for (let aaHash of aa[algo]) { for (let bbHash of bb[algo]) { return aaHash.digest === bbHash.digest } } } return false } function pkgAreEquiv (aa, bb) { // coming in we know they share a path… // if one is inside a link and the other is not, then they are not equivalent // this happens when we're replacing a linked dep with a non-linked version if (aa.isInLink !== bb.isInLink) return false // if they share package metadata _identity_, they're the same thing if (aa.package === bb.package) return true // if they share integrity information, they're the same thing var aaIntegrity = pkgIntegrity(aa.package) var bbIntegrity = pkgIntegrity(bb.package) if (aaIntegrity || bbIntegrity) return sriMatch(aaIntegrity, bbIntegrity) // if they're links and they share the same target, they're the same thing if (aa.isLink && bb.isLink) return aa.realpath === bb.realpath // if we can't determine both their sources then we have no way to know // if they're the same thing, so we have to assume they aren't var aaReq = pkgRequested(aa.package) var bbReq = pkgRequested(bb.package) if (!aaReq || !bbReq) return false if (fromGit(aaReq) && fromGit(bbReq)) { // if both are git and share a _resolved specifier (one with the // comittish replaced by a commit hash) then they're the same return aa.package._resolved && bb.package._resolved && aa.package._resolved === bb.package._resolved } // we have to give up trying to find matches for non-registry sources at this point… if (nonRegistrySource(aaReq) || nonRegistrySource(bbReq)) return false // finally, if they ARE a registry source then version matching counts return aa.package.version === bb.package.version } function pushAll (aa, bb) { Array.prototype.push.apply(aa, bb) } module.exports = function (oldTree, newTree, differences, log, next) { validate('OOAOF', arguments) pushAll(differences, sortActions(diffTrees(oldTree, newTree))) log.finish() next() } function isNotTopOrExtraneous (node) { return !node.isTop && !node.userRequired && !node.existing } var sortActions = module.exports.sortActions = function (differences) { var actions = {} differences.forEach(function (action) { var child = action[1] actions[child.location] = action }) var sorted = [] var added = {} var sortedlocs = Object.keys(actions).sort(sortByLocation) // We're going to sort the actions taken on top level dependencies first, before // considering the order of transitive deps. Because we're building our list // from the bottom up, this means we will return a list with top level deps LAST. // This is important in terms of keeping installations as consistent as possible // as folks add new dependencies. var toplocs = sortedlocs.filter(function (location) { var mod = actions[location][1] if (!mod.requiredBy) return true // If this module is required by any non-top level module // or by any extraneous module, eg user requested or existing // then we don't want to give this priority sorting. return !mod.requiredBy.some(isNotTopOrExtraneous) }) toplocs.concat(sortedlocs).forEach(function (location) { sortByDeps(actions[location]) }) function sortByLocation (aa, bb) { return bb.localeCompare(aa) } function sortModuleByLocation (aa, bb) { return sortByLocation(aa && aa.location, bb && bb.location) } function sortByDeps (action) { var mod = action[1] if (added[mod.location]) return added[mod.location] = action if (!mod.requiredBy) mod.requiredBy = [] mod.requiredBy.sort(sortModuleByLocation).forEach(function (mod) { if (actions[mod.location]) sortByDeps(actions[mod.location]) }) sorted.unshift(action) } // safety net, anything excluded above gets tacked on the end differences.forEach((_) => { if (sorted.indexOf(_) === -1) sorted.push(_) }) return sorted } function setAction (differences, action, pkg) { differences.push([action, pkg]) } var diffTrees = module.exports._diffTrees = function (oldTree, newTree) { validate('OO', arguments) var differences = [] var flatOldTree = flattenTree(oldTree) var flatNewTree = flattenTree(newTree) var toRemove = {} var toRemoveByName = {} // Build our tentative remove list. We don't add remove actions yet // because we might resuse them as part of a move. Object.keys(flatOldTree).forEach(function (flatname) { if (flatname === '/') return if (flatNewTree[flatname]) return var pkg = flatOldTree[flatname] if (pkg.isInLink && /^[.][.][/\\]/.test(path.relative(newTree.realpath, pkg.realpath))) return toRemove[flatname] = pkg var name = moduleName(pkg) if (!toRemoveByName[name]) toRemoveByName[name] = [] toRemoveByName[name].push({flatname: flatname, pkg: pkg}) }) // generate our add/update/move actions Object.keys(flatNewTree).forEach(function (flatname) { if (flatname === '/') return var pkg = flatNewTree[flatname] var oldPkg = pkg.oldPkg = flatOldTree[flatname] if (oldPkg) { // if the versions are equivalent then we don't need to update… unless // the user explicitly asked us to. if (!pkg.userRequired && pkgAreEquiv(oldPkg, pkg)) return setAction(differences, 'update', pkg) } else { var name = moduleName(pkg) // find any packages we're removing that share the same name and are equivalent var removing = (toRemoveByName[name] || []).filter((rm) => pkgAreEquiv(rm.pkg, pkg)) var bundlesOrFromBundle = pkg.fromBundle || pkg.package.bundleDependencies // if we have any removes that match AND we're not working with a bundle then upgrade to a move if (removing.length && !bundlesOrFromBundle) { var toMv = removing.shift() toRemoveByName[name] = toRemoveByName[name].filter((rm) => rm !== toMv) pkg.fromPath = toMv.pkg.path setAction(differences, 'move', pkg) delete toRemove[toMv.flatname] // we don't generate add actions for things found in links (which already exist on disk) } else if (!pkg.isInLink || !(pkg.fromBundle && pkg.fromBundle.isLink)) { setAction(differences, 'add', pkg) } } }) // finally generate our remove actions from any not consumed by moves Object .keys(toRemove) .map((flatname) => toRemove[flatname]) .forEach((pkg) => setAction(differences, 'remove', pkg)) return filterActions(differences) } function filterActions (differences) { const includeOpt = npm.config.get('optional') const includeDev = npm.config.get('dev') || (!/^prod(uction)?$/.test(npm.config.get('only')) && !npm.config.get('production')) || /^dev(elopment)?$/.test(npm.config.get('only')) || /^dev(elopment)?$/.test(npm.config.get('also')) const includeProd = !/^dev(elopment)?$/.test(npm.config.get('only')) if (includeProd && includeDev && includeOpt) return differences log.silly('diff-trees', 'filtering actions:', 'includeDev', includeDev, 'includeProd', includeProd, 'includeOpt', includeOpt) return differences.filter((diff) => { const pkg = diff[1] const pkgIsOnlyDev = isOnlyDev(pkg) const pkgIsOnlyOpt = isOnlyOptional(pkg) if (!includeProd && pkgIsOnlyDev) return true if (includeDev && pkgIsOnlyDev) return true if (includeProd && !pkgIsOnlyDev && (includeOpt || !pkgIsOnlyOpt)) return true return false }) } install/exists.js000064400000001407152231567050010077 0ustar00'use strict' var fs = require('fs') var inflight = require('inflight') var accessError = require('./access-error.js') var isFsAccessAvailable = require('./is-fs-access-available.js') if (isFsAccessAvailable) { module.exports = fsAccessImplementation } else { module.exports = fsStatImplementation } // exposed only for testing purposes module.exports.fsAccessImplementation = fsAccessImplementation module.exports.fsStatImplementation = fsStatImplementation function fsAccessImplementation (dir, done) { done = inflight('exists:' + dir, done) if (!done) return fs.access(dir, fs.F_OK, done) } function fsStatImplementation (dir, done) { done = inflight('exists:' + dir, done) if (!done) return fs.stat(dir, function (er) { done(accessError(dir, er)) }) } install/flatten-tree.js000064400000001775152231567050011162 0ustar00'use strict' var validate = require('aproba') var moduleName = require('../utils/module-name.js') module.exports = flattenTree module.exports.flatName = flatName module.exports.flatNameFromTree = flatNameFromTree function flattenTree (tree) { validate('O', arguments) var seen = new Set() var flat = {} var todo = [[tree, '/']] while (todo.length) { var next = todo.shift() var pkg = next[0] seen.add(pkg) var path = next[1] flat[path] = pkg if (path !== '/') path += '/' for (var ii = 0; ii < pkg.children.length; ++ii) { var child = pkg.children[ii] if (!seen.has(child)) { todo.push([child, flatName(path, child)]) } } } return flat } function flatName (path, child) { validate('SO', arguments) return path + (moduleName(child) || 'TOP') } function flatNameFromTree (tree) { validate('O', arguments) if (tree.isTop) return '/' var path = flatNameFromTree(tree.parent) if (path !== '/') path += '/' return flatName(path, tree) } install/fund.js000064400000002441152231567050007513 0ustar00'use strict' const { EOL } = require('os') const computeMetadata = require('./deps.js').computeMetadata const mutateIntoLogicalTree = require('./mutate-into-logical-tree.js') var { getFundingInfo } = require('../utils/funding.js') exports.getPrintFundingReport = getPrintFundingReport exports.getPrintFundingReportJSON = getPrintFundingReportJSON function getFundingResult ({ fund, idealTree }) { if (fund) { const fundingInfoTree = mutateIntoLogicalTree.asReadInstalled( computeMetadata(idealTree) ) const fundResult = getFundingInfo(fundingInfoTree, { countOnly: true }) return fundResult } else { return {} } } function getPrintFundingReport ({ fund, idealTree }, opts) { const fundResult = getFundingResult({ fund, idealTree }) const { length } = fundResult || {} const { json } = opts || {} function padding (msg) { return json ? '' : (EOL + msg) } function packageQuantity (amount) { return `package${amount > 1 ? 's are' : ' is'}` } if (!length) return '' return padding('') + length + ' ' + packageQuantity(length) + ' looking for funding' + padding(' run `npm fund` for details\n') } function getPrintFundingReportJSON ({ fund, idealTree }) { return getPrintFundingReport({ fund, idealTree }, { json: true }) } install/get-requested.js000064400000001173152231567050011336 0ustar00'use strict' const npa = require('npm-package-arg') const moduleName = require('../utils/module-name.js') const packageRelativePath = require('./deps').packageRelativePath module.exports = function (child, reqBy) { if (!child.requiredBy.length) return if (!reqBy) reqBy = child.requiredBy[0] const deps = reqBy.package.dependencies || {} const devDeps = reqBy.package.devDependencies || {} const optDeps = reqBy.package.optionalDependencies || {} const name = moduleName(child) const spec = deps[name] || devDeps[name] || optDeps[name] const where = packageRelativePath(reqBy) return npa.resolve(name, spec, where) } install/has-modern-meta.js000064400000001276152231567050011545 0ustar00'use strict' module.exports = hasModernMeta const npa = require('npm-package-arg') const moduleName = require('../utils/module-name.js') function isLink (child) { return child.isLink || (child.parent && isLink(child.parent)) } function hasModernMeta (child) { if (!child) return false const resolved = child.package._resolved && npa.resolve(moduleName(child), child.package._resolved) const version = npa.resolve(moduleName(child), child.package.version) return child.isTop || isLink(child) || child.fromBundle || child.package._inBundle || child.package._integrity || child.package._shasum || (resolved && resolved.type === 'git') || (version && version.type === 'git') } install/inflate-bundled.js000064400000001164152231567050011615 0ustar00'use strict' var childPath = require('../utils/child-path.js') var reset = require('./node.js').reset module.exports = function inflateBundled (bundler, parent, children) { children.forEach(function (child) { if (child.fromBundle === bundler) return reset(child) child.fromBundle = bundler child.isInLink = bundler.isLink child.parent = parent child.path = childPath(parent.path, child) child.realpath = bundler.isLink ? child.realpath : childPath(parent.realpath, child) child.isLink = child.isLink || parent.isLink || parent.target inflateBundled(bundler, child, child.children) }) } install/inflate-shrinkwrap.js000064400000021576152231567050012401 0ustar00'use strict' const BB = require('bluebird') let addBundled const childPath = require('../utils/child-path.js') const createChild = require('./node.js').create let fetchPackageMetadata const inflateBundled = require('./inflate-bundled.js') const moduleName = require('../utils/module-name.js') const normalizePackageData = require('normalize-package-data') const npm = require('../npm.js') const realizeShrinkwrapSpecifier = require('./realize-shrinkwrap-specifier.js') const validate = require('aproba') const path = require('path') const isRegistry = require('../utils/is-registry.js') const hasModernMeta = require('./has-modern-meta.js') const ssri = require('ssri') const npa = require('npm-package-arg') module.exports = function (tree, sw, opts, finishInflating) { if (!fetchPackageMetadata) { fetchPackageMetadata = BB.promisify(require('../fetch-package-metadata.js')) addBundled = BB.promisify(fetchPackageMetadata.addBundled) } if (arguments.length === 3) { finishInflating = opts opts = {} } if (!npm.config.get('shrinkwrap') || !npm.config.get('package-lock')) { return finishInflating() } tree.loaded = false tree.hasRequiresFromLock = sw.requires return inflateShrinkwrap(tree.path, tree, sw.dependencies, opts).then( () => finishInflating(), finishInflating ) } function inflateShrinkwrap (topPath, tree, swdeps, opts) { if (!swdeps) return Promise.resolve() if (!opts) opts = {} const onDisk = {} tree.children.forEach((child) => { onDisk[moduleName(child)] = child }) tree.children = [] return BB.each(Object.keys(swdeps), (name) => { const sw = swdeps[name] const dependencies = sw.dependencies || {} const requested = realizeShrinkwrapSpecifier(name, sw, topPath) if (Object.keys(sw).length === 0) { let message = `Object for dependency "${name}" is empty.\n` message += 'Something went wrong. Regenerate the package-lock.json with "npm install".\n' message += 'If using a shrinkwrap, regenerate with "npm shrinkwrap".' return Promise.reject(new Error(message)) } return inflatableChild( onDisk[name], name, topPath, tree, sw, requested, opts ).then((child) => { child.hasRequiresFromLock = tree.hasRequiresFromLock return inflateShrinkwrap(topPath, child, dependencies) }) }) } function normalizePackageDataNoErrors (pkg) { try { normalizePackageData(pkg) } catch (ex) { // don't care } } function quotemeta (str) { return str.replace(/([^A-Za-z_0-9/])/g, '\\$1') } function tarballToVersion (name, tb) { const registry = quotemeta(npm.config.get('registry') || '') .replace(/https?:/, 'https?:') .replace(/([^/])$/, '$1/') let matchRegTarball if (name) { const nameMatch = quotemeta(name) matchRegTarball = new RegExp(`^${registry}${nameMatch}/-/${nameMatch}-(.*)[.]tgz$`) } else { matchRegTarball = new RegExp(`^${registry}(.*)?/-/\\1-(.*)[.]tgz$`) } const match = tb.match(matchRegTarball) if (!match) return return match[2] || match[1] } function relativizeLink (name, spec, topPath, requested) { if (!spec.startsWith('file:')) { return } let requestedPath = requested.fetchSpec if (requested.type === 'file') { requestedPath = path.dirname(requestedPath) } const relativized = path.relative(requestedPath, path.resolve(topPath, spec.slice(5))) return 'file:' + relativized } function inflatableChild (onDiskChild, name, topPath, tree, sw, requested, opts) { validate('OSSOOOO|ZSSOOOO', arguments) const usesIntegrity = ( requested.registry || requested.type === 'remote' || requested.type === 'file' ) const regTarball = tarballToVersion(name, sw.version) if (regTarball) { sw.resolved = sw.version sw.version = regTarball } if (sw.requires) { Object.keys(sw.requires).forEach(name => { const spec = sw.requires[name] sw.requires[name] = tarballToVersion(name, spec) || relativizeLink(name, spec, topPath, requested) || spec }) } const modernLink = requested.type === 'directory' && !sw.from if (hasModernMeta(onDiskChild) && childIsEquivalent(sw, requested, onDiskChild)) { // The version on disk matches the shrinkwrap entry. if (!onDiskChild.fromShrinkwrap) onDiskChild.fromShrinkwrap = requested onDiskChild.package._requested = requested onDiskChild.package._spec = requested.rawSpec onDiskChild.package._where = topPath onDiskChild.package._optional = sw.optional onDiskChild.package._development = sw.dev onDiskChild.package._inBundle = sw.bundled onDiskChild.fromBundle = (sw.bundled || onDiskChild.package._inBundle) ? tree.fromBundle || tree : null if (!onDiskChild.package._args) onDiskChild.package._args = [] onDiskChild.package._args.push([String(requested), topPath]) // non-npm registries can and will return unnormalized data, plus // even the npm registry may have package data normalized with older // normalization rules. This ensures we get package data in a consistent, // stable format. normalizePackageDataNoErrors(onDiskChild.package) onDiskChild.swRequires = sw.requires tree.children.push(onDiskChild) return BB.resolve(onDiskChild) } else if ((sw.version && (sw.integrity || !usesIntegrity) && (requested.type !== 'directory' || modernLink)) || sw.bundled) { // The shrinkwrap entry has an integrity field. We can fake a pkg to get // the installer to do a content-address fetch from the cache, if possible. return BB.resolve(makeFakeChild(name, topPath, tree, sw, requested)) } else { // It's not on disk, and we can't just look it up by address -- do a full // fpm/inflate bundle pass. For registry deps, this will go straight to the // tarball URL, as if it were a remote tarball dep. return fetchChild(topPath, tree, sw, requested) } } function isGit (sw) { const version = npa.resolve(sw.name, sw.version) return (version && version.type === 'git') } function makeFakeChild (name, topPath, tree, sw, requested) { const isDirectory = requested.type === 'directory' const from = sw.from || requested.raw const pkg = { name: name, version: sw.version, _id: name + '@' + sw.version, _resolved: sw.resolved || (isGit(sw) && sw.version), _requested: requested, _optional: sw.optional, _development: sw.dev, _inBundle: sw.bundled, _integrity: sw.integrity, _from: from, _spec: requested.rawSpec, _where: topPath, _args: [[requested.toString(), topPath]], dependencies: sw.requires } if (!sw.bundled) { const bundleDependencies = Object.keys(sw.dependencies || {}).filter((d) => sw.dependencies[d].bundled) if (bundleDependencies.length === 0) { pkg.bundleDependencies = bundleDependencies } } const child = createChild({ package: pkg, loaded: isDirectory, parent: tree, children: [], fromShrinkwrap: requested, fakeChild: sw, fromBundle: sw.bundled ? tree.fromBundle || tree : null, path: childPath(tree.path, pkg), realpath: isDirectory ? requested.fetchSpec : childPath(tree.realpath, pkg), location: (tree.location === '/' ? '' : tree.location + '/') + pkg.name, isLink: isDirectory, isInLink: tree.isLink || tree.isInLink, swRequires: sw.requires }) tree.children.push(child) return child } function fetchChild (topPath, tree, sw, requested) { return fetchPackageMetadata(requested, topPath).then((pkg) => { pkg._from = sw.from || requested.raw pkg._optional = sw.optional pkg._development = sw.dev pkg._inBundle = false return addBundled(pkg).then(() => pkg) }).then((pkg) => { var isLink = pkg._requested.type === 'directory' const child = createChild({ package: pkg, loaded: false, parent: tree, fromShrinkwrap: requested, path: childPath(tree.path, pkg), realpath: isLink ? requested.fetchSpec : childPath(tree.realpath, pkg), children: pkg._bundled || [], location: (tree.location === '/' ? '' : tree.location + '/') + pkg.name, fromBundle: null, isLink: isLink, isInLink: tree.isLink, swRequires: sw.requires }) tree.children.push(child) if (pkg._bundled) { delete pkg._bundled inflateBundled(child, child, child.children) } return child }) } function childIsEquivalent (sw, requested, child) { if (!child) return false if (child.fromShrinkwrap) return true if ( sw.integrity && child.package._integrity && ssri.parse(sw.integrity).match(child.package._integrity) ) return true if (child.isLink && requested.type === 'directory') return path.relative(child.realpath, requested.fetchSpec) === '' if (sw.resolved) return child.package._resolved === sw.resolved if (!isRegistry(requested) && sw.from) return child.package._from === sw.from if (!isRegistry(requested) && child.package._resolved) return sw.version === child.package._resolved return child.package.version === sw.version } install/is-dev-dep.js000064400000000257152231567050010517 0ustar00'use strict' module.exports = isDevDep function isDevDep (node, name) { return node.package && node.package.devDependencies && node.package.devDependencies[name] } install/is-extraneous.js000064400000001152152231567050011363 0ustar00'use strict' module.exports = isExtraneous function isExtraneous (tree) { var result = !isNotExtraneous(tree) return result } function topHasNoPjson (tree) { var top = tree while (!top.isTop) top = top.parent return top.error } function isNotExtraneous (tree, isCycle) { if (!isCycle) isCycle = {} if (tree.isTop || tree.userRequired) { return true } else if (isCycle[tree.path]) { return topHasNoPjson(tree) } else { isCycle[tree.path] = true return tree.requiredBy && tree.requiredBy.some(function (node) { return isNotExtraneous(node, Object.create(isCycle)) }) } } install/is-fs-access-available.js000064400000001373152231567050012760 0ustar00'use strict' var fs = require('fs') var semver = require('semver') var isWindows = process.platform === 'win32' // fs.access first introduced in node 0.12 / io.js if (!fs.access) { module.exports = false } else if (!isWindows) { // fs.access always works on non-Windows OSes module.exports = true } else { // The Windows implementation of `fs.access` has a bug where it will // sometimes return access errors all the time for directories, even // when access is available. As all we actually test ARE directories, this // is a bit of a problem. // This was fixed in io.js version 1.5.0 // As of 2015-07-20, it is still unfixed in node: // https://github.com/joyent/node/issues/25657 module.exports = semver.gte(process.version, '1.5.0') } install/is-only-dev.js000064400000002364152231567050010731 0ustar00'use strict' module.exports = isOnlyDev const moduleName = require('../utils/module-name.js') const isDevDep = require('./is-dev-dep.js') const isProdDep = require('./is-prod-dep.js') // Returns true if the module `node` is only required direcctly as a dev // dependency of the top level or transitively _from_ top level dev // dependencies. // Dual mode modules (that are both dev AND prod) should return false. function isOnlyDev (node, seen) { if (!seen) seen = new Set() return node.requiredBy.length && node.requiredBy.every(andIsOnlyDev(moduleName(node), seen)) } // There is a known limitation with this implementation: If a dependency is // ONLY required by cycles that are detached from the top level then it will // ultimately return true. // // This is ok though: We don't allow shrinkwraps with extraneous deps and // these situation is caught by the extraneous checker before we get here. function andIsOnlyDev (name, seen) { return function (req) { const isDev = isDevDep(req, name) const isProd = isProdDep(req, name) if (req.isTop) { return isDev && !isProd } else { if (seen.has(req)) return true seen.add(req) const result = isOnlyDev(req, seen) seen.delete(req) return result } } } install/is-only-optional.js000064400000001242152231567050011772 0ustar00'use strict' module.exports = isOptional const isOptDep = require('./is-opt-dep.js') const moduleName = require('../utils/module-name.js') function isOptional (node, seen) { if (!seen) seen = new Set() // If a node is not required by anything, then we've reached // the top level package. if (seen.has(node) || node.requiredBy.length === 0) { return false } seen.add(node) const swOptional = node.fromShrinkwrap && node.package._optional const result = node.requiredBy.every(function (req) { if (req.fakeChild && swOptional) return true return isOptDep(req, moduleName(node)) || isOptional(req, seen) }) seen.delete(node) return result } install/is-opt-dep.js000064400000000271152231567050010537 0ustar00'use strict' module.exports = isOptDep function isOptDep (node, name) { return node.package && node.package.optionalDependencies && node.package.optionalDependencies[name] } install/is-prod-dep.js000064400000000254152231567050010702 0ustar00'use strict' module.exports = isProdDep function isProdDep (node, name) { return node.package && node.package.dependencies && node.package.dependencies[name] } install/module-staging-path.js000064400000000403152231567050012424 0ustar00'use strict' var uniqueFilename = require('unique-filename') var moduleName = require('../utils/module-name.js') module.exports = moduleStagingPath function moduleStagingPath (staging, pkg) { return uniqueFilename(staging, moduleName(pkg), pkg.realpath) } install/mutate-into-logical-tree.js000064400000011020152231567050013363 0ustar00'use strict' var union = require('lodash.union') var without = require('lodash.without') var validate = require('aproba') var flattenTree = require('./flatten-tree.js') var isExtraneous = require('./is-extraneous.js') var validateAllPeerDeps = require('./deps.js').validateAllPeerDeps var packageId = require('../utils/package-id.js') var moduleName = require('../utils/module-name.js') var npm = require('../npm.js') // Return true if tree is a part of a cycle that: // A) Never connects to the top of the tree // B) Has not not had a point in the cycle arbitrarily declared its top // yet. function isDisconnectedCycle (tree, seen) { if (!seen) seen = {} if (tree.isTop || tree.cycleTop || tree.requiredBy.length === 0) { return false } else if (seen[tree.path]) { return true } else { seen[tree.path] = true return tree.requiredBy.every(function (node) { return isDisconnectedCycle(node, Object.create(seen)) }) } } var mutateIntoLogicalTree = module.exports = function (tree) { validate('O', arguments) validateAllPeerDeps(tree, function (tree, pkgname, version) { if (!tree.missingPeers) tree.missingPeers = {} tree.missingPeers[pkgname] = version }) var flat = flattenTree(tree) Object.keys(flat).sort().forEach(function (flatname) { var node = flat[flatname] if (!(node.requiredBy && node.requiredBy.length)) return if (node.parent) { // If a node is a cycle that never reaches the root of the logical // tree then we'll leave it attached to the root, or else it // would go missing. Further we'll note that this is the node in the // cycle that we picked arbitrarily to be the one attached to the root. // others will fall if (isDisconnectedCycle(node)) { node.cycleTop = true // Nor do we want to disconnect non-cyclical extraneous modules from the tree. } else if (node.requiredBy.length) { // regular deps though, we do, as we're moving them into the capable // hands of the modules that require them. node.parent.children = without(node.parent.children, node) } } node.requiredBy.forEach(function (parentNode) { parentNode.children = union(parentNode.children, [node]) }) }) return tree } module.exports.asReadInstalled = function (tree) { mutateIntoLogicalTree(tree) return translateTree(tree) } function translateTree (tree) { return translateTree_(tree, new Set()) } function translateTree_ (tree, seen) { var pkg = tree.package if (seen.has(tree)) return pkg seen.add(tree) if (pkg._dependencies) return pkg pkg._dependencies = pkg.dependencies pkg.dependencies = {} tree.children.forEach(function (child) { const dep = pkg.dependencies[moduleName(child)] = translateTree_(child, seen) if (child.fakeChild) { dep.missing = true dep.optional = child.package._optional dep.requiredBy = child.package._spec } }) function markMissing (name, requiredBy) { if (pkg.dependencies[name]) { if (pkg.dependencies[name].missing) return pkg.dependencies[name].invalid = true pkg.dependencies[name].realName = name pkg.dependencies[name].extraneous = false } else { pkg.dependencies[name] = { requiredBy: requiredBy, missing: true, optional: !!pkg.optionalDependencies[name] } } } Object.keys(tree.missingDeps).forEach(function (name) { markMissing(name, tree.missingDeps[name]) }) Object.keys(tree.missingDevDeps).forEach(function (name) { markMissing(name, tree.missingDevDeps[name]) }) var checkForMissingPeers = (tree.parent ? [] : [tree]).concat(tree.children) checkForMissingPeers.filter(function (child) { return child.missingPeers }).forEach(function (child) { Object.keys(child.missingPeers).forEach(function (pkgname) { var version = child.missingPeers[pkgname] var peerPkg = pkg.dependencies[pkgname] if (!peerPkg) { peerPkg = pkg.dependencies[pkgname] = { _id: pkgname + '@' + version, name: pkgname, version: version } } if (!peerPkg.peerMissing) peerPkg.peerMissing = [] peerPkg.peerMissing.push({ requiredBy: packageId(child), requires: pkgname + '@' + version }) }) }) pkg.path = tree.path pkg.error = tree.error pkg.extraneous = !tree.isTop && (!tree.parent.isTop || !tree.parent.error) && !npm.config.get('global') && isExtraneous(tree) if (tree.target && tree.parent && !tree.parent.target) pkg.link = tree.realpath return pkg } install/node.js000064400000003547152231567050007514 0ustar00'use strict' var defaultTemplate = { package: { version: '', dependencies: {}, devDependencies: {}, optionalDependencies: {} }, loaded: false, children: [], requiredBy: [], requires: [], missingDeps: {}, missingDevDeps: {}, phantomChildren: {}, path: null, realpath: null, location: null, userRequired: false, save: false, saveSpec: null, isTop: false, fromBundle: false } function isLink (node) { return node && node.isLink } function isInLink (node) { return node && (node.isInLink || node.isLink) } var create = exports.create = function (node, template, isNotTop) { if (!template) template = defaultTemplate Object.keys(template).forEach(function (key) { if (template[key] != null && typeof template[key] === 'object' && !(template[key] instanceof Array)) { if (!node[key]) node[key] = {} return create(node[key], template[key], true) } if (node[key] != null) return node[key] = template[key] }) if (!isNotTop) { // isLink is true for the symlink and everything inside it. // by contrast, isInLink is true for only the things inside a link if (node.isLink == null) node.isLink = isLink(node.parent) if (node.isInLink == null) node.isInLink = isInLink(node.parent) if (node.fromBundle == null) { node.fromBundle = false } } return node } exports.reset = function (node) { reset(node, new Set()) } function reset (node, seen) { if (seen.has(node)) return seen.add(node) var child = create(node) // FIXME: cleaning up after read-package-json's mess =( if (child.package._id === '@') delete child.package._id child.isTop = false child.requiredBy = [] child.requires = [] child.missingDeps = {} child.missingDevDeps = {} child.phantomChildren = {} child.location = null child.children.forEach(function (child) { reset(child, seen) }) } install/read-shrinkwrap.js000064400000007260152231567050011664 0ustar00'use strict' const BB = require('bluebird') const fs = require('graceful-fs') const iferr = require('iferr') const inflateShrinkwrap = require('./inflate-shrinkwrap.js') const log = require('npmlog') const parseJSON = require('../utils/parse-json.js') const path = require('path') const PKGLOCK_VERSION = require('../npm.js').lockfileVersion const readFileAsync = BB.promisify(fs.readFile) module.exports = readShrinkwrap function readShrinkwrap (child, next) { if (child.package._shrinkwrap) return process.nextTick(next) BB.join( maybeReadFile('npm-shrinkwrap.json', child), // Don't read non-root lockfiles child.isTop && maybeReadFile('package-lock.json', child), (shrinkwrap, lockfile) => { if (shrinkwrap && lockfile) { log.warn('read-shrinkwrap', 'Ignoring package-lock.json because there is already an npm-shrinkwrap.json. Please use only one of the two.') } const name = shrinkwrap ? 'npm-shrinkwrap.json' : 'package-lock.json' const parsed = parsePkgLock(shrinkwrap || lockfile, name) if (parsed && parsed.lockfileVersion !== PKGLOCK_VERSION) { log.warn('read-shrinkwrap', `This version of npm is compatible with lockfileVersion@${PKGLOCK_VERSION}, but ${name} was generated for lockfileVersion@${parsed.lockfileVersion || 0}. I'll try to do my best with it!`) } child.package._shrinkwrap = parsed } ).then(() => next(), next) } function maybeReadFile (name, child) { return readFileAsync( path.join(child.path, name), 'utf8' ).catch({code: 'ENOENT'}, () => null) } module.exports.andInflate = function (child, next) { readShrinkwrap(child, iferr(next, function () { if (child.package._shrinkwrap) { return inflateShrinkwrap(child, child.package._shrinkwrap || {}, next) } else { return next() } })) } const PARENT_RE = /\|{7,}/g const OURS_RE = /<{7,}/g const THEIRS_RE = /={7,}/g const END_RE = />{7,}/g module.exports._isDiff = isDiff function isDiff (str) { return str.match(OURS_RE) && str.match(THEIRS_RE) && str.match(END_RE) } module.exports._parsePkgLock = parsePkgLock function parsePkgLock (str, filename) { if (!str) { return null } try { return parseJSON(str) } catch (e) { if (isDiff(str)) { log.warn('conflict', `A git conflict was detected in ${filename}. Attempting to auto-resolve.`) log.warn('conflict', 'To make this happen automatically on git rebase/merge, consider using the npm-merge-driver:') log.warn('conflict', '$ npx npm-merge-driver install -g') const pieces = str.split(/[\n\r]+/g).reduce((acc, line) => { if (line.match(PARENT_RE)) acc.state = 'parent' else if (line.match(OURS_RE)) acc.state = 'ours' else if (line.match(THEIRS_RE)) acc.state = 'theirs' else if (line.match(END_RE)) acc.state = 'top' else { if (acc.state === 'top' || acc.state === 'ours') acc.ours += line if (acc.state === 'top' || acc.state === 'theirs') acc.theirs += line if (acc.state === 'top' || acc.state === 'parent') acc.parent += line } return acc }, { state: 'top', ours: '', theirs: '', parent: '' }) try { const ours = parseJSON(pieces.ours) const theirs = parseJSON(pieces.theirs) return reconcileLockfiles(ours, theirs) } catch (_e) { log.error('conflict', `Automatic conflict resolution failed. Please manually resolve conflicts in ${filename} and try again.`) log.silly('conflict', `Error during resolution: ${_e}`) throw e } } else { throw e } } } function reconcileLockfiles (parent, ours, theirs) { return Object.assign({}, ours, theirs) } install/realize-shrinkwrap-specifier.js000064400000001155152231567050014350 0ustar00'use strict' var npa = require('npm-package-arg') const isRegistry = require('../utils/is-registry.js') module.exports = function (name, sw, where) { try { if (sw.version && sw.integrity) { return npa.resolve(name, sw.version, where) } else if (sw.from) { const spec = npa(sw.from, where) if (isRegistry(spec) && sw.version) { return npa.resolve(name, sw.version, where) } else if (!sw.resolved) { return spec } } if (sw.resolved) { return npa.resolve(name, sw.resolved, where) } } catch (_) { } return npa.resolve(name, sw.version, where) } install/report-optional-failure.js000064400000002021152231567050013334 0ustar00'use strict' var path = require('path') var moduleName = require('../utils/module-name.js') module.exports = reportOptionalFailure function top (tree) { if (tree.parent) return top(tree.parent) return tree } function reportOptionalFailure (tree, what, error) { var topTree = top(tree) if (!topTree.warnings) topTree.warnings = [] var id if (what) { var depVer = tree.package.dependencies && tree.package.dependencies[what] var optDepVer = tree.package.optionalDependencies && tree.package.optionalDependencies[what] var devDepVer = tree.package.devDependencies && tree.package.devDependencies[what] var version = depVer || optDepVer || devDepVer id = what + (version ? '@' + version : '') } else { id = tree._id || moduleName(tree) + (tree.package.version ? '@' + tree.package.version : '') } var location = path.relative(topTree.path, tree.path) if (what) location = path.join(location, 'node_modules', what) error.optional = id error.location = location topTree.warnings.push(error) } owner.js000064400000015142152231567050006245 0ustar00module.exports = owner const BB = require('bluebird') const log = require('npmlog') const npa = require('libnpm/parse-arg') const npmConfig = require('./config/figgy-config.js') const npmFetch = require('libnpm/fetch') const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const packument = require('libnpm/packument') const readLocalPkg = BB.promisify(require('./utils/read-local-package.js')) const usage = require('./utils/usage') const whoami = BB.promisify(require('./whoami.js')) owner.usage = usage( 'owner', 'npm owner add [<@scope>/]' + '\nnpm owner rm [<@scope>/]' + '\nnpm owner ls [<@scope>/]' ) owner.completion = function (opts, cb) { const argv = opts.conf.argv.remain if (argv.length > 4) return cb() if (argv.length <= 2) { var subs = ['add', 'rm'] if (opts.partialWord === 'l') subs.push('ls') else subs.push('ls', 'list') return cb(null, subs) } BB.try(() => { const opts = npmConfig() return whoami([], true).then(username => { const un = encodeURIComponent(username) let byUser, theUser switch (argv[2]) { case 'ls': // FIXME: there used to be registry completion here, but it stopped // making sense somewhere around 50,000 packages on the registry return case 'rm': if (argv.length > 3) { theUser = encodeURIComponent(argv[3]) byUser = `/-/by-user/${theUser}|${un}` return npmFetch.json(byUser, opts).then(d => { return d[theUser].filter( // kludge for server adminery. p => un === 'isaacs' || d[un].indexOf(p) === -1 ) }) } // else fallthrough /* eslint no-fallthrough:0 */ case 'add': if (argv.length > 3) { theUser = encodeURIComponent(argv[3]) byUser = `/-/by-user/${theUser}|${un}` return npmFetch.json(byUser, opts).then(d => { var mine = d[un] || [] var theirs = d[theUser] || [] return mine.filter(p => theirs.indexOf(p) === -1) }) } else { // just list all users who aren't me. return npmFetch.json('/-/users', opts).then(list => { return Object.keys(list).filter(n => n !== un) }) } default: return cb() } }) }).nodeify(cb) } function UsageError () { throw Object.assign(new Error(owner.usage), {code: 'EUSAGE'}) } function owner ([action, ...args], cb) { const opts = npmConfig() BB.try(() => { switch (action) { case 'ls': case 'list': return ls(args[0], opts) case 'add': return add(args[0], args[1], opts) case 'rm': case 'remove': return rm(args[0], args[1], opts) default: UsageError() } }).then( data => cb(null, data), err => err.code === 'EUSAGE' ? cb(err.message) : cb(err) ) } function ls (pkg, opts) { if (!pkg) { return readLocalPkg().then(pkg => { if (!pkg) { UsageError() } return ls(pkg, opts) }) } const spec = npa(pkg) return packument(spec, opts.concat({fullMetadata: true})).then( data => { var owners = data.maintainers if (!owners || !owners.length) { output('admin party!') } else { output(owners.map(o => `${o.name} <${o.email}>`).join('\n')) } return owners }, err => { log.error('owner ls', "Couldn't get owner data", pkg) throw err } ) } function add (user, pkg, opts) { if (!user) { UsageError() } if (!pkg) { return readLocalPkg().then(pkg => { if (!pkg) { UsageError() } return add(user, pkg, opts) }) } log.verbose('owner add', '%s to %s', user, pkg) const spec = npa(pkg) return withMutation(spec, user, opts, (u, owners) => { if (!owners) owners = [] for (var i = 0, l = owners.length; i < l; i++) { var o = owners[i] if (o.name === u.name) { log.info( 'owner add', 'Already a package owner: ' + o.name + ' <' + o.email + '>' ) return false } } owners.push(u) return owners }) } function rm (user, pkg, opts) { if (!user) { UsageError() } if (!pkg) { return readLocalPkg().then(pkg => { if (!pkg) { UsageError() } return add(user, pkg, opts) }) } log.verbose('owner rm', '%s from %s', user, pkg) const spec = npa(pkg) return withMutation(spec, user, opts, function (u, owners) { let found = false const m = owners.filter(function (o) { var match = (o.name === user) found = found || match return !match }) if (!found) { log.info('owner rm', 'Not a package owner: ' + user) return false } if (!m.length) { throw new Error( 'Cannot remove all owners of a package. Add someone else first.' ) } return m }) } function withMutation (spec, user, opts, mutation) { return BB.try(() => { if (user) { const uri = `/-/user/org.couchdb.user:${encodeURIComponent(user)}` return npmFetch.json(uri, opts).then(mutate_, err => { log.error('owner mutate', 'Error getting user data for %s', user) throw err }) } else { return mutate_(null) } }) function mutate_ (u) { if (user && (!u || u.error)) { throw new Error( "Couldn't get user data for " + user + ': ' + JSON.stringify(u) ) } if (u) u = { name: u.name, email: u.email } return packument(spec, opts.concat({ fullMetadata: true })).then(data => { // save the number of maintainers before mutation so that we can figure // out if maintainers were added or removed const beforeMutation = data.maintainers.length const m = mutation(u, data.maintainers) if (!m) return // handled if (m instanceof Error) throw m // error data = { _id: data._id, _rev: data._rev, maintainers: m } const dataPath = `/${spec.escapedName}/-rev/${encodeURIComponent(data._rev)}` return otplease(opts, opts => { const reqOpts = opts.concat({ method: 'PUT', body: data, spec }) return npmFetch.json(dataPath, reqOpts) }).then(data => { if (data.error) { throw new Error('Failed to update package metadata: ' + JSON.stringify(data)) } else if (m.length > beforeMutation) { output('+ %s (%s)', user, spec.name) } else if (m.length < beforeMutation) { output('- %s (%s)', user, spec.name) } return data }) }) } } pack.js000064400000027444152231567050006041 0ustar00'use strict' // npm pack // Packs the specified package into a .tgz file, which can then // be installed. // Set this early to avoid issues with circular dependencies. module.exports = pack const BB = require('bluebird') const byteSize = require('byte-size') const cacache = require('cacache') const columnify = require('columnify') const cp = require('child_process') const deprCheck = require('./utils/depr-check') const fpm = require('./fetch-package-metadata') const fs = require('graceful-fs') const install = require('./install') const lifecycle = BB.promisify(require('./utils/lifecycle')) const log = require('npmlog') const move = require('move-concurrently') const npm = require('./npm') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output') const pacote = require('pacote') const path = require('path') const PassThrough = require('stream').PassThrough const pathIsInside = require('path-is-inside') const pipe = BB.promisify(require('mississippi').pipe) const prepublishWarning = require('./utils/warn-deprecated')('prepublish-on-install') const pinflight = require('promise-inflight') const readJson = BB.promisify(require('read-package-json')) const tar = require('tar') const packlist = require('npm-packlist') const ssri = require('ssri') pack.usage = 'npm pack [[<@scope>/]...] [--dry-run]' // if it can be installed, it can be packed. pack.completion = install.completion function pack (args, silent, cb) { const cwd = process.cwd() if (typeof cb !== 'function') { cb = silent silent = false } if (args.length === 0) args = ['.'] BB.all( args.map((arg) => pack_(arg, cwd)) ).then((tarballs) => { if (!silent && npm.config.get('json')) { output(JSON.stringify(tarballs, null, 2)) } else if (!silent) { tarballs.forEach(logContents) output(tarballs.map((f) => path.relative(cwd, f.filename)).join('\n')) } return tarballs }).nodeify(cb) } function pack_ (pkg, dir) { return BB.fromNode((cb) => fpm(pkg, dir, cb)).then((mani) => { let name = mani.name[0] === '@' // scoped packages get special treatment ? mani.name.substr(1).replace(/\//g, '-') : mani.name const target = `${name}-${mani.version}.tgz` return pinflight(target, () => { const dryRun = npm.config.get('dry-run') if (mani._requested.type === 'directory') { return prepareDirectory(mani._resolved) .then(() => { return packDirectory(mani, mani._resolved, target, target, true, dryRun) }) } else if (dryRun) { log.verbose('pack', '--dry-run mode enabled. Skipping write.') return cacache.tmp.withTmp(npm.tmp, {tmpPrefix: 'packing'}, (tmp) => { const tmpTarget = path.join(tmp, path.basename(target)) return packFromPackage(pkg, tmpTarget, target) }) } else { return packFromPackage(pkg, target, target) } }) }) } function packFromPackage (arg, target, filename) { const opts = npmConfig() return pacote.tarball.toFile(arg, target, opts) .then(() => cacache.tmp.withTmp(npm.tmp, {tmpPrefix: 'unpacking'}, (tmp) => { const tmpTarget = path.join(tmp, filename) return pacote.extract(arg, tmpTarget, opts) .then(() => readJson(path.join(tmpTarget, 'package.json'))) })) .then((pkg) => getContents(pkg, target, filename)) } module.exports.prepareDirectory = prepareDirectory function prepareDirectory (dir) { return readJson(path.join(dir, 'package.json')).then((pkg) => { if (!pkg.name) { throw new Error('package.json requires a "name" field') } if (!pkg.version) { throw new Error('package.json requires a valid "version" field') } if (!pathIsInside(dir, npm.tmp)) { if (pkg.scripts && pkg.scripts.prepublish) { prepublishWarning([ 'As of npm@5, `prepublish` scripts are deprecated.', 'Use `prepare` for build steps and `prepublishOnly` for upload-only.', 'See the deprecation note in `npm help scripts` for more information.' ]) } if (npm.config.get('ignore-prepublish')) { return lifecycle(pkg, 'prepare', dir).then(() => pkg) } else { return lifecycle(pkg, 'prepublish', dir).then(() => { return lifecycle(pkg, 'prepare', dir) }).then(() => pkg) } } return pkg }) } module.exports.packDirectory = packDirectory function packDirectory (mani, dir, target, filename, logIt, dryRun) { deprCheck(mani) return readJson(path.join(dir, 'package.json')).then((pkg) => { return lifecycle(pkg, 'prepack', dir) }).then(() => { return readJson(path.join(dir, 'package.json')) }).then((pkg) => { return cacache.tmp.withTmp(npm.tmp, {tmpPrefix: 'packing'}, (tmp) => { const tmpTarget = path.join(tmp, path.basename(target)) const tarOpt = { file: tmpTarget, cwd: dir, prefix: 'package/', portable: true, // Provide a specific date in the 1980s for the benefit of zip, // which is confounded by files dated at the Unix epoch 0. mtime: new Date('1985-10-26T08:15:00.000Z'), gzip: true } return BB.resolve(packlist({ path: dir })) // NOTE: node-tar does some Magic Stuff depending on prefixes for files // specifically with @ signs, so we just neutralize that one // and any such future "features" by prepending `./` .then((files) => tar.create(tarOpt, files.map((f) => `./${f}`))) .then(() => getContents(pkg, tmpTarget, filename, logIt)) // thread the content info through .tap(() => { if (dryRun) { log.verbose('pack', '--dry-run mode enabled. Skipping write.') } else { return move(tmpTarget, target, {Promise: BB, fs}) } }) .tap(() => lifecycle(pkg, 'postpack', dir)) }) }) } module.exports.logContents = logContents function logContents (tarball) { log.notice('') log.notice('', `${npm.config.get('unicode') ? '📦 ' : 'package:'} ${tarball.name}@${tarball.version}`) log.notice('=== Tarball Contents ===') if (tarball.files.length) { log.notice('', columnify(tarball.files.map((f) => { const bytes = byteSize(f.size) return {path: f.path, size: `${bytes.value}${bytes.unit}`} }), { include: ['size', 'path'], showHeaders: false })) } if (tarball.bundled.length) { log.notice('=== Bundled Dependencies ===') tarball.bundled.forEach((name) => log.notice('', name)) } log.notice('=== Tarball Details ===') log.notice('', columnify([ {name: 'name:', value: tarball.name}, {name: 'version:', value: tarball.version}, tarball.filename && {name: 'filename:', value: tarball.filename}, {name: 'package size:', value: byteSize(tarball.size)}, {name: 'unpacked size:', value: byteSize(tarball.unpackedSize)}, {name: 'shasum:', value: tarball.shasum}, { name: 'integrity:', value: tarball.integrity.toString().substr(0, 20) + '[...]' + tarball.integrity.toString().substr(80)}, tarball.bundled.length && {name: 'bundled deps:', value: tarball.bundled.length}, tarball.bundled.length && {name: 'bundled files:', value: tarball.entryCount - tarball.files.length}, tarball.bundled.length && {name: 'own files:', value: tarball.files.length}, {name: 'total files:', value: tarball.entryCount} ].filter((x) => x), { include: ['name', 'value'], showHeaders: false })) log.notice('', '') } module.exports.getContents = getContents function getContents (pkg, target, filename, silent) { const bundledWanted = new Set( pkg.bundleDependencies || pkg.bundledDependencies || [] ) const files = [] const bundled = new Set() let totalEntries = 0 let totalEntrySize = 0 return tar.t({ file: target, onentry (entry) { totalEntries++ totalEntrySize += entry.size const p = entry.path if (p.startsWith('package/node_modules/')) { const name = p.match(/^package\/node_modules\/((?:@[^/]+\/)?[^/]+)/)[1] if (bundledWanted.has(name)) { bundled.add(name) } } else { files.push({ path: entry.path.replace(/^package\//, ''), size: entry.size, mode: entry.mode }) } }, strip: 1 }) .then(() => BB.all([ BB.fromNode((cb) => fs.stat(target, cb)), ssri.fromStream(fs.createReadStream(target), { algorithms: ['sha1', 'sha512'] }) ])) .then(([stat, integrity]) => { const shasum = integrity['sha1'][0].hexDigest() return { id: pkg._id, name: pkg.name, version: pkg.version, from: pkg._from, size: stat.size, unpackedSize: totalEntrySize, shasum, integrity: ssri.parse(integrity['sha512'][0]), filename, files, entryCount: totalEntries, bundled: Array.from(bundled) } }) } const PASSTHROUGH_OPTS = [ 'always-auth', 'auth-type', 'ca', 'cafile', 'cert', 'git', 'local-address', 'maxsockets', 'offline', 'prefer-offline', 'prefer-online', 'proxy', 'https-proxy', 'registry', 'send-metrics', 'sso-poll-frequency', 'sso-type', 'strict-ssl' ] module.exports.packGitDep = packGitDep function packGitDep (manifest, dir) { const stream = new PassThrough() readJson(path.join(dir, 'package.json')).then((pkg) => { if (pkg.scripts && pkg.scripts.prepare) { log.verbose('prepareGitDep', `${manifest._spec}: installing devDeps and running prepare script.`) const cliArgs = PASSTHROUGH_OPTS.reduce((acc, opt) => { if (npm.config.get(opt, 'cli') != null) { acc.push(`--${opt}=${npm.config.get(opt)}`) } return acc }, []) const child = cp.spawn(process.env.NODE || process.execPath, [ require.resolve('../bin/npm-cli.js'), 'install', '--dev', '--prod', '--ignore-prepublish', '--no-progress', '--no-save' ].concat(cliArgs), { cwd: dir, env: process.env }) let errData = [] let errDataLen = 0 let outData = [] let outDataLen = 0 child.stdout.on('data', (data) => { outData.push(data) outDataLen += data.length log.gauge.pulse('preparing git package') }) child.stderr.on('data', (data) => { errData.push(data) errDataLen += data.length log.gauge.pulse('preparing git package') }) return BB.fromNode((cb) => { child.on('error', cb) child.on('exit', (code, signal) => { if (code > 0) { const err = new Error(`${signal}: npm exited with code ${code} while attempting to build ${manifest._requested}. Clone the repository manually and run 'npm install' in it for more information.`) err.code = code err.signal = signal cb(err) } else { cb() } }) }).then(() => { if (outDataLen > 0) log.silly('prepareGitDep', '1>', Buffer.concat(outData, outDataLen).toString()) if (errDataLen > 0) log.silly('prepareGitDep', '2>', Buffer.concat(errData, errDataLen).toString()) }, (err) => { if (outDataLen > 0) log.error('prepareGitDep', '1>', Buffer.concat(outData, outDataLen).toString()) if (errDataLen > 0) log.error('prepareGitDep', '2>', Buffer.concat(errData, errDataLen).toString()) throw err }) } }).then(() => { return readJson(path.join(dir, 'package.json')) }).then((pkg) => { return cacache.tmp.withTmp(npm.tmp, { tmpPrefix: 'pacote-packing' }, (tmp) => { const tmpTar = path.join(tmp, 'package.tgz') return packDirectory(manifest, dir, tmpTar).then(() => { return pipe(fs.createReadStream(tmpTar), stream) }) }) }).catch((err) => stream.emit('error', err)) return stream } ping.js000064400000002165152231567050006051 0ustar00'use strict' const npmConfig = require('./config/figgy-config.js') const fetch = require('libnpm/fetch') const figgyPudding = require('figgy-pudding') const log = require('npmlog') const npm = require('./npm.js') const output = require('./utils/output.js') const PingConfig = figgyPudding({ json: {}, registry: {} }) module.exports = ping ping.usage = 'npm ping\nping registry' function ping (args, silent, cb) { if (typeof cb !== 'function') { cb = silent silent = false } const opts = PingConfig(npmConfig()) const registry = opts.registry log.notice('PING', registry) const start = Date.now() return fetch('/-/ping?write=true', opts).then( res => res.json().catch(() => ({})) ).then(details => { if (silent) { } else { const time = Date.now() - start log.notice('PONG', `${time / 1000}ms`) if (npm.config.get('json')) { output(JSON.stringify({ registry, time, details }, null, 2)) } else if (Object.keys(details).length) { log.notice('PONG', `${JSON.stringify(details, null, 2)}`) } } }).nodeify(cb) } prefix.js000064400000000512152231567050006403 0ustar00module.exports = prefix var npm = require('./npm.js') var output = require('./utils/output.js') prefix.usage = 'npm prefix [-g]' function prefix (args, silent, cb) { if (typeof cb !== 'function') { cb = silent silent = false } if (!silent) output(npm.prefix) process.nextTick(cb.bind(this, null, npm.prefix)) } profile.js000064400000026211152231567050006552 0ustar00'use strict' const BB = require('bluebird') const ansistyles = require('ansistyles') const figgyPudding = require('figgy-pudding') const inspect = require('util').inspect const log = require('npmlog') const npm = require('./npm.js') const npmConfig = require('./config/figgy-config.js') const otplease = require('./utils/otplease.js') const output = require('./utils/output.js') const profile = require('libnpm/profile') const pulseTillDone = require('./utils/pulse-till-done.js') const qrcodeTerminal = require('qrcode-terminal') const queryString = require('query-string') const qw = require('qw') const readUserInfo = require('./utils/read-user-info.js') const Table = require('cli-table3') const url = require('url') module.exports = profileCmd profileCmd.usage = 'npm profile enable-2fa [auth-only|auth-and-writes]\n' + 'npm profile disable-2fa\n' + 'npm profile get []\n' + 'npm profile set ' profileCmd.subcommands = qw`enable-2fa disable-2fa get set` profileCmd.completion = function (opts, cb) { var argv = opts.conf.argv.remain switch (argv[2]) { case 'enable-2fa': case 'enable-tfa': if (argv.length === 3) { return cb(null, qw`auth-and-writes auth-only`) } else { return cb(null, []) } case 'disable-2fa': case 'disable-tfa': case 'get': case 'set': return cb(null, []) default: return cb(new Error(argv[2] + ' not recognized')) } } function withCb (prom, cb) { prom.then((value) => cb(null, value), cb) } const ProfileOpts = figgyPudding({ json: {}, otp: {}, parseable: {}, registry: {} }) function profileCmd (args, cb) { if (args.length === 0) return cb(new Error(profileCmd.usage)) log.gauge.show('profile') switch (args[0]) { case 'enable-2fa': case 'enable-tfa': case 'enable2fa': case 'enabletfa': withCb(enable2fa(args.slice(1)), cb) break case 'disable-2fa': case 'disable-tfa': case 'disable2fa': case 'disabletfa': withCb(disable2fa(), cb) break case 'get': withCb(get(args.slice(1)), cb) break case 'set': withCb(set(args.slice(1)), cb) break default: cb(new Error('Unknown profile command: ' + args[0])) } } const knownProfileKeys = qw` name email ${'two-factor auth'} fullname homepage freenode twitter github created updated` function get (args) { const tfa = 'two-factor auth' const conf = ProfileOpts(npmConfig()) return pulseTillDone.withPromise(profile.get(conf)).then((info) => { if (!info.cidr_whitelist) delete info.cidr_whitelist if (conf.json) { output(JSON.stringify(info, null, 2)) return } const cleaned = {} knownProfileKeys.forEach((k) => { cleaned[k] = info[k] || '' }) Object.keys(info).filter((k) => !(k in cleaned)).forEach((k) => { cleaned[k] = info[k] || '' }) delete cleaned.tfa delete cleaned.email_verified cleaned['email'] += info.email_verified ? ' (verified)' : '(unverified)' if (info.tfa && !info.tfa.pending) { cleaned[tfa] = info.tfa.mode } else { cleaned[tfa] = 'disabled' } if (args.length) { const values = args // comma or space separated ↓ .join(',').split(/,/).map((arg) => arg.trim()).filter((arg) => arg !== '') .map((arg) => cleaned[arg]) .join('\t') output(values) } else { if (conf.parseable) { Object.keys(info).forEach((key) => { if (key === 'tfa') { output(`${key}\t${cleaned[tfa]}`) } else { output(`${key}\t${info[key]}`) } }) } else { const table = new Table() Object.keys(cleaned).forEach((k) => table.push({[ansistyles.bright(k)]: cleaned[k]})) output(table.toString()) } } }) } const writableProfileKeys = qw` email password fullname homepage freenode twitter github` function set (args) { let conf = ProfileOpts(npmConfig()) const prop = (args[0] || '').toLowerCase().trim() let value = args.length > 1 ? args.slice(1).join(' ') : null if (prop !== 'password' && value === null) { return Promise.reject(Error('npm profile set ')) } if (prop === 'password' && value !== null) { return Promise.reject(Error( 'npm profile set password\n' + 'Do not include your current or new passwords on the command line.')) } if (writableProfileKeys.indexOf(prop) === -1) { return Promise.reject(Error(`"${prop}" is not a property we can set. Valid properties are: ` + writableProfileKeys.join(', '))) } return BB.try(() => { if (prop === 'password') { return readUserInfo.password('Current password: ').then((current) => { return readPasswords().then((newpassword) => { value = {old: current, new: newpassword} }) }) } else if (prop === 'email') { return readUserInfo.password('Password: ').then((current) => { return {password: current, email: value} }) } function readPasswords () { return readUserInfo.password('New password: ').then((password1) => { return readUserInfo.password(' Again: ').then((password2) => { if (password1 !== password2) { log.warn('profile', 'Passwords do not match, please try again.') return readPasswords() } return password1 }) }) } }).then(() => { // FIXME: Work around to not clear everything other than what we're setting return pulseTillDone.withPromise(profile.get(conf).then((user) => { const newUser = {} writableProfileKeys.forEach((k) => { newUser[k] = user[k] }) newUser[prop] = value return otplease(conf, conf => profile.set(newUser, conf)) .then((result) => { if (conf.json) { output(JSON.stringify({[prop]: result[prop]}, null, 2)) } else if (conf.parseable) { output(prop + '\t' + result[prop]) } else if (result[prop] != null) { output('Set', prop, 'to', result[prop]) } else { output('Set', prop) } }) })) }) } function enable2fa (args) { if (args.length > 1) { return Promise.reject(new Error('npm profile enable-2fa [auth-and-writes|auth-only]')) } const mode = args[0] || 'auth-and-writes' if (mode !== 'auth-only' && mode !== 'auth-and-writes') { return Promise.reject(new Error(`Invalid two-factor authentication mode "${mode}".\n` + 'Valid modes are:\n' + ' auth-only - Require two-factor authentication only when logging in\n' + ' auth-and-writes - Require two-factor authentication when logging in AND when publishing')) } const conf = ProfileOpts(npmConfig()) if (conf.json || conf.parseable) { return Promise.reject(new Error( 'Enabling two-factor authentication is an interactive operation and ' + (conf.json ? 'JSON' : 'parseable') + ' output mode is not available')) } const info = { tfa: { mode: mode } } return BB.try(() => { // if they're using legacy auth currently then we have to update them to a // bearer token before continuing. const auth = getAuth(conf) if (auth.basic) { log.info('profile', 'Updating authentication to bearer token') return profile.createToken( auth.basic.password, false, [], conf ).then((result) => { if (!result.token) throw new Error('Your registry ' + conf.registry + 'does not seem to support bearer tokens. Bearer tokens are required for two-factor authentication') npm.config.setCredentialsByURI(conf.registry, {token: result.token}) return BB.fromNode((cb) => npm.config.save('user', cb)) }) } }).then(() => { log.notice('profile', 'Enabling two factor authentication for ' + mode) return readUserInfo.password() }).then((password) => { info.tfa.password = password log.info('profile', 'Determine if tfa is pending') return pulseTillDone.withPromise(profile.get(conf)).then((info) => { if (!info.tfa) return if (info.tfa.pending) { log.info('profile', 'Resetting two-factor authentication') return pulseTillDone.withPromise(profile.set({tfa: {password, mode: 'disable'}}, conf)) } else { if (conf.auth.otp) return return readUserInfo.otp('Enter one-time password from your authenticator app: ').then((otp) => { conf.auth.otp = otp }) } }) }).then(() => { log.info('profile', 'Setting two-factor authentication to ' + mode) return pulseTillDone.withPromise(profile.set(info, conf)) }).then((challenge) => { if (challenge.tfa === null) { output('Two factor authentication mode changed to: ' + mode) return } if (typeof challenge.tfa !== 'string' || !/^otpauth:[/][/]/.test(challenge.tfa)) { throw new Error('Unknown error enabling two-factor authentication. Expected otpauth URL, got: ' + inspect(challenge.tfa)) } const otpauth = url.parse(challenge.tfa) const opts = queryString.parse(otpauth.query) return qrcode(challenge.tfa).then((code) => { output('Scan into your authenticator app:\n' + code + '\n Or enter code:', opts.secret) }).then((code) => { return readUserInfo.otp('And an OTP code from your authenticator: ') }).then((otp1) => { log.info('profile', 'Finalizing two-factor authentication') return profile.set({tfa: [otp1]}, conf) }).then((result) => { output('2FA successfully enabled. Below are your recovery codes, please print these out.') output('You will need these to recover access to your account if you lose your authentication device.') result.tfa.forEach((c) => output('\t' + c)) }) }) } function getAuth (conf) { const creds = npm.config.getCredentialsByURI(conf.registry) let auth if (creds.token) { auth = {token: creds.token} } else if (creds.username) { auth = {basic: {username: creds.username, password: creds.password}} } else if (creds.auth) { const basic = Buffer.from(creds.auth, 'base64').toString().split(':', 2) auth = {basic: {username: basic[0], password: basic[1]}} } else { auth = {} } if (conf.otp) auth.otp = conf.otp return auth } function disable2fa (args) { let conf = ProfileOpts(npmConfig()) return pulseTillDone.withPromise(profile.get(conf)).then((info) => { if (!info.tfa || info.tfa.pending) { output('Two factor authentication not enabled.') return } return readUserInfo.password().then((password) => { return BB.try(() => { if (conf.otp) return return readUserInfo.otp('Enter one-time password from your authenticator: ').then((otp) => { conf = conf.concat({otp}) }) }).then(() => { log.info('profile', 'disabling tfa') return pulseTillDone.withPromise(profile.set({tfa: {password: password, mode: 'disable'}}, conf)).then(() => { if (conf.json) { output(JSON.stringify({tfa: false}, null, 2)) } else if (conf.parseable) { output('tfa\tfalse') } else { output('Two factor authentication disabled.') } }) }) }) }) } function qrcode (url) { return new Promise((resolve) => qrcodeTerminal.generate(url, resolve)) } prune.js000064400000004351152231567050006244 0ustar00// prune extraneous packages. module.exports = prune module.exports.Pruner = Pruner prune.usage = 'npm prune [[<@scope>/]...] [--production]' var npm = require('./npm.js') var log = require('npmlog') var util = require('util') var moduleName = require('./utils/module-name.js') var Installer = require('./install.js').Installer var isExtraneous = require('./install/is-extraneous.js') var isOnlyDev = require('./install/is-only-dev.js') var removeDeps = require('./install/deps.js').removeDeps var loadExtraneous = require('./install/deps.js').loadExtraneous var chain = require('slide').chain var computeMetadata = require('./install/deps.js').computeMetadata prune.completion = require('./utils/completion/installed-deep.js') function prune (args, cb) { var dryrun = !!npm.config.get('dry-run') new Pruner('.', dryrun, args).run(cb) } function Pruner (where, dryrun, args) { Installer.call(this, where, dryrun, args) this.autoPrune = true } util.inherits(Pruner, Installer) Pruner.prototype.loadAllDepsIntoIdealTree = function (cb) { log.silly('uninstall', 'loadAllDepsIntoIdealTree') var cg = this.progress['loadIdealTree:loadAllDepsIntoIdealTree'] var steps = [] computeMetadata(this.idealTree) var self = this var excludeDev = npm.config.get('production') || /^prod(uction)?$/.test(npm.config.get('only')) function shouldPrune (child) { if (isExtraneous(child)) return true if (!excludeDev) return false return isOnlyDev(child) } function getModuleName (child) { // wrapping because moduleName doesn't like extra args and we're called // from map. return moduleName(child) } function matchesArg (name) { return self.args.length === 0 || self.args.indexOf(name) !== -1 } function nameObj (name) { return {name: name} } var toPrune = this.idealTree.children.filter(shouldPrune).map(getModuleName).filter(matchesArg).map(nameObj) steps.push( [removeDeps, toPrune, this.idealTree, null], [loadExtraneous, this.idealTree, cg.newGroup('loadExtraneous')]) chain(steps, cb) } Pruner.prototype.runPreinstallTopLevelLifecycles = function (cb) { cb() } Pruner.prototype.runPostinstallTopLevelLifecycles = function (cb) { cb() } Pruner.prototype.saveToDependencies = function (cb) { cb() } publish.js000064400000012220152231567050006553 0ustar00'use strict' const BB = require('bluebird') const cacache = require('cacache') const figgyPudding = require('figgy-pudding') const libpub = require('libnpm/publish') const libunpub = require('libnpm/unpublish') const lifecycle = BB.promisify(require('./utils/lifecycle.js')) const log = require('npmlog') const npa = require('libnpm/parse-arg') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const pack = require('./pack') const { tarball, extract } = require('libnpm') const path = require('path') const readFileAsync = BB.promisify(require('graceful-fs').readFile) const readJson = BB.promisify(require('read-package-json')) const semver = require('semver') const statAsync = BB.promisify(require('graceful-fs').stat) publish.usage = 'npm publish [|] [--tag ] [--access ] [--dry-run]' + "\n\nPublishes '.' if no argument supplied" + '\n\nSets tag `latest` if no --tag specified' publish.completion = function (opts, cb) { // publish can complete to a folder with a package.json // or a tarball, or a tarball url. // for now, not yet implemented. return cb() } const PublishConfig = figgyPudding({ dryRun: 'dry-run', 'dry-run': { default: false }, force: { default: false }, json: { default: false }, Promise: { default: () => Promise }, tag: { default: 'latest' }, tmp: {} }) module.exports = publish function publish (args, isRetry, cb) { if (typeof cb !== 'function') { cb = isRetry isRetry = false } if (args.length === 0) args = ['.'] if (args.length !== 1) return cb(publish.usage) log.verbose('publish', args) const opts = PublishConfig(npmConfig()) const t = opts.tag.trim() if (semver.validRange(t)) { return cb(new Error('Tag name must not be a valid SemVer range: ' + t)) } return publish_(args[0], opts) .then((tarball) => { const silent = log.level === 'silent' if (!silent && opts.json) { output(JSON.stringify(tarball, null, 2)) } else if (!silent) { output(`+ ${tarball.id}`) } }) .nodeify(cb) } function publish_ (arg, opts) { return statAsync(arg).then((stat) => { if (stat.isDirectory()) { return stat } else { const err = new Error('not a directory') err.code = 'ENOTDIR' throw err } }).then(() => { return publishFromDirectory(arg, opts) }, (err) => { if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { throw err } else { return publishFromPackage(arg, opts) } }) } function publishFromDirectory (arg, opts) { // All this readJson is because any of the given scripts might modify the // package.json in question, so we need to refresh after every step. let contents return pack.prepareDirectory(arg).then(() => { return readJson(path.join(arg, 'package.json')) }).then((pkg) => { return lifecycle(pkg, 'prepublishOnly', arg) }).then(() => { return readJson(path.join(arg, 'package.json')) }).then((pkg) => { return cacache.tmp.withTmp(opts.tmp, {tmpPrefix: 'fromDir'}, (tmpDir) => { const target = path.join(tmpDir, 'package.tgz') return pack.packDirectory(pkg, arg, target, null, true) .tap((c) => { contents = c }) .then((c) => !opts.json && pack.logContents(c)) .then(() => upload(pkg, false, target, opts)) }) }).then(() => { return readJson(path.join(arg, 'package.json')) }).tap((pkg) => { return lifecycle(pkg, 'publish', arg) }).tap((pkg) => { return lifecycle(pkg, 'postpublish', arg) }) .then(() => contents) } function publishFromPackage (arg, opts) { return cacache.tmp.withTmp(opts.tmp, {tmpPrefix: 'fromPackage'}, tmp => { const extracted = path.join(tmp, 'package') const target = path.join(tmp, 'package.json') return tarball.toFile(arg, target, opts) .then(() => extract(arg, extracted, opts)) .then(() => readJson(path.join(extracted, 'package.json'))) .then((pkg) => { return BB.resolve(pack.getContents(pkg, target)) .tap((c) => !opts.json && pack.logContents(c)) .tap(() => upload(pkg, false, target, opts)) }) }) } function upload (pkg, isRetry, cached, opts) { if (!opts.dryRun) { return readFileAsync(cached).then(tarball => { return otplease(opts, opts => { return libpub(pkg, tarball, opts) }).catch(err => { if ( err.code === 'EPUBLISHCONFLICT' && opts.force && !isRetry ) { log.warn('publish', 'Forced publish over ' + pkg._id) return otplease(opts, opts => libunpub( npa.resolve(pkg.name, pkg.version), opts )).finally(() => { // ignore errors. Use the force. Reach out with your feelings. return otplease(opts, opts => { return upload(pkg, true, tarball, opts) }).catch(() => { // but if it fails again, then report the first error. throw err }) }) } else { throw err } }) }) } else { return opts.Promise.resolve(true) } } rebuild.js000064400000004137152231567050006543 0ustar00 module.exports = rebuild var readInstalled = require('read-installed') var semver = require('semver') var log = require('npmlog') var npm = require('./npm.js') var npa = require('npm-package-arg') var usage = require('./utils/usage') var output = require('./utils/output.js') rebuild.usage = usage( 'rebuild', 'npm rebuild [[<@scope>/]...]' ) rebuild.completion = require('./utils/completion/installed-deep.js') function rebuild (args, cb) { var opt = { depth: npm.config.get('depth'), dev: true } readInstalled(npm.prefix, opt, function (er, data) { log.info('readInstalled', typeof data) if (er) return cb(er) var set = filter(data, args) var folders = Object.keys(set).filter(function (f) { return f !== npm.prefix }) if (!folders.length) return cb() log.silly('rebuild set', folders) cleanBuild(folders, set, cb) }) } function cleanBuild (folders, set, cb) { npm.commands.build(folders, function (er) { if (er) return cb(er) output(folders.map(function (f) { return set[f] + ' ' + f }).join('\n')) cb() }) } function filter (data, args, set, seen) { if (!set) set = {} if (!seen) seen = new Set() if (set.hasOwnProperty(data.path)) return set if (seen.has(data)) return set seen.add(data) var pass if (!args.length) pass = true // rebuild everything else if (data.name && data._id) { for (var i = 0, l = args.length; i < l; i++) { var arg = args[i] var nv = npa(arg) var n = nv.name var v = nv.rawSpec if (n !== data.name) continue if (!semver.satisfies(data.version, v, true)) continue pass = true break } } if (pass && data._id) { log.verbose('rebuild', 'path, id', [data.path, data._id]) set[data.path] = data._id } // need to also dive through kids, always. // since this isn't an install these won't get auto-built unless // they're not dependencies. Object.keys(data.dependencies || {}).forEach(function (d) { // return var dep = data.dependencies[d] if (typeof dep === 'string') return filter(dep, args, set, seen) }) return set } repo.js000064400000002677152231567050006071 0ustar00module.exports = repo repo.usage = 'npm repo []' const openUrl = require('./utils/open-url') const hostedGitInfo = require('hosted-git-info') const url_ = require('url') const fetchPackageMetadata = require('./fetch-package-metadata.js') repo.completion = function (opts, cb) { // FIXME: there used to be registry completion here, but it stopped making // sense somewhere around 50,000 packages on the registry cb() } function repo (args, cb) { const n = args.length ? args[0] : '.' fetchPackageMetadata(n, '.', {fullMetadata: true}, function (er, d) { if (er) return cb(er) getUrlAndOpen(d, cb) }) } function getUrlAndOpen (d, cb) { const r = d.repository if (!r) return cb(new Error('no repository')) // XXX remove this when npm@v1.3.10 from node 0.10 is deprecated // from https://github.com/npm/npm-www/issues/418 const info = hostedGitInfo.fromUrl(r.url) const url = info ? info.browse() : unknownHostedUrl(r.url) if (!url) return cb(new Error('no repository: could not get url')) openUrl(url, 'repository available at the following URL', cb) } function unknownHostedUrl (url) { try { const idx = url.indexOf('@') if (idx !== -1) { url = url.slice(idx + 1).replace(/:([^\d]+)/, '/$1') } url = url_.parse(url) const protocol = url.protocol === 'https:' ? 'https:' : 'http:' return protocol + '//' + (url.host || '') + url.path.replace(/\.git$/, '') } catch (e) {} } restart.js000064400000000100152231567050006563 0ustar00module.exports = require('./utils/lifecycle-cmd.js')('restart') root.js000064400000000500152231567050006066 0ustar00module.exports = root const npm = require('./npm.js') const output = require('./utils/output.js') root.usage = 'npm root [-g]' function root (args, silent, cb) { if (typeof cb !== 'function') { cb = silent silent = false } if (!silent) output(npm.dir) process.nextTick(cb.bind(this, null, npm.dir)) } run-script.js000064400000012644152231567050007225 0ustar00module.exports = runScript var lifecycle = require('./utils/lifecycle.js') var npm = require('./npm.js') var path = require('path') var readJson = require('read-package-json') var log = require('npmlog') var chain = require('slide').chain var usage = require('./utils/usage') var output = require('./utils/output.js') var didYouMean = require('./utils/did-you-mean') var isWindowsShell = require('./utils/is-windows-shell.js') runScript.usage = usage( 'run-script', 'npm run-script [-- ...]' ) runScript.completion = function (opts, cb) { // see if there's already a package specified. var argv = opts.conf.argv.remain if (argv.length >= 4) return cb() if (argv.length === 3) { // either specified a script locally, in which case, done, // or a package, in which case, complete against its scripts var json = path.join(npm.localPrefix, 'package.json') return readJson(json, function (er, d) { if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er) if (er) d = {} var scripts = Object.keys(d.scripts || {}) console.error('local scripts', scripts) if (scripts.indexOf(argv[2]) !== -1) return cb() // ok, try to find out which package it was, then var pref = npm.config.get('global') ? npm.config.get('prefix') : npm.localPrefix var pkgDir = path.resolve(pref, 'node_modules', argv[2], 'package.json') readJson(pkgDir, function (er, d) { if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er) if (er) d = {} var scripts = Object.keys(d.scripts || {}) return cb(null, scripts) }) }) } readJson(path.join(npm.localPrefix, 'package.json'), function (er, d) { if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er) d = d || {} cb(null, Object.keys(d.scripts || {})) }) } function runScript (args, cb) { if (!args.length) return list(cb) var pkgdir = npm.localPrefix var cmd = args.shift() readJson(path.resolve(pkgdir, 'package.json'), function (er, d) { if (er) return cb(er) run(d, pkgdir, cmd, args, cb) }) } function list (cb) { var json = path.join(npm.localPrefix, 'package.json') var cmdList = [ 'publish', 'install', 'uninstall', 'test', 'stop', 'start', 'restart', 'version' ].reduce(function (l, p) { return l.concat(['pre' + p, p, 'post' + p]) }, []) return readJson(json, function (er, d) { if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er) if (er) d = {} var allScripts = Object.keys(d.scripts || {}) var scripts = [] var runScripts = [] allScripts.forEach(function (script) { if (cmdList.indexOf(script) !== -1) scripts.push(script) else runScripts.push(script) }) if (log.level === 'silent') { return cb(null, allScripts) } if (npm.config.get('json')) { output(JSON.stringify(d.scripts || {}, null, 2)) return cb(null, allScripts) } if (npm.config.get('parseable')) { allScripts.forEach(function (script) { output(script + ':' + d.scripts[script]) }) return cb(null, allScripts) } var s = '\n ' var prefix = ' ' if (scripts.length) { output('Lifecycle scripts included in %s:', d.name) } scripts.forEach(function (script) { output(prefix + script + s + d.scripts[script]) }) if (!scripts.length && runScripts.length) { output('Scripts available in %s via `npm run-script`:', d.name) } else if (runScripts.length) { output('\navailable via `npm run-script`:') } runScripts.forEach(function (script) { output(prefix + script + s + d.scripts[script]) }) return cb(null, allScripts) }) } function run (pkg, wd, cmd, args, cb) { if (!pkg.scripts) pkg.scripts = {} var cmds if (cmd === 'restart' && !pkg.scripts.restart) { cmds = [ 'prestop', 'stop', 'poststop', 'restart', 'prestart', 'start', 'poststart' ] } else { if (pkg.scripts[cmd] == null) { if (cmd === 'test') { pkg.scripts.test = 'echo \'Error: no test specified\'' } else if (cmd === 'env') { if (isWindowsShell) { log.verbose('run-script using default platform env: SET (Windows)') pkg.scripts[cmd] = 'SET' } else { log.verbose('run-script using default platform env: env (Unix)') pkg.scripts[cmd] = 'env' } } else if (npm.config.get('if-present')) { return cb(null) } else { let suggestions = didYouMean(cmd, Object.keys(pkg.scripts)) suggestions = suggestions ? '\n' + suggestions : '' return cb(new Error('missing script: ' + cmd + suggestions)) } } cmds = [cmd] } if (!cmd.match(/^(pre|post)/)) { cmds = ['pre' + cmd].concat(cmds).concat('post' + cmd) } log.verbose('run-script', cmds) chain(cmds.map(function (c) { // pass cli arguments after -- to script. if (pkg.scripts[c] && c === cmd) { pkg.scripts[c] = pkg.scripts[c] + joinArgs(args) } // when running scripts explicitly, assume that they're trusted. return [lifecycle, pkg, c, wd, { unsafePerm: true }] }), cb) } // join arguments after '--' and pass them to script, // handle special characters such as ', ", ' '. function joinArgs (args) { var joinedArgs = '' args.forEach(function (arg) { joinedArgs += ' "' + arg.replace(/"/g, '\\"') + '"' }) return joinedArgs } search.js000064400000006562152231567050006366 0ustar00'use strict' module.exports = exports = search const npm = require('./npm.js') const allPackageSearch = require('./search/all-package-search') const figgyPudding = require('figgy-pudding') const formatPackageStream = require('./search/format-package-stream.js') const libSearch = require('libnpm/search') const log = require('npmlog') const ms = require('mississippi') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const usage = require('./utils/usage') search.usage = usage( 'search', 'npm search [--long] [search terms ...]' ) search.completion = function (opts, cb) { cb(null, []) } const SearchOpts = figgyPudding({ description: {}, exclude: {}, include: {}, limit: {}, log: {}, staleness: {}, unicode: {} }) function search (args, cb) { const opts = SearchOpts(npmConfig()).concat({ description: npm.config.get('description'), exclude: prepareExcludes(npm.config.get('searchexclude')), include: prepareIncludes(args, npm.config.get('searchopts')), limit: npm.config.get('searchlimit') || 20, log: log, staleness: npm.config.get('searchstaleness'), unicode: npm.config.get('unicode') }) if (opts.include.length === 0) { return cb(new Error('search must be called with arguments')) } // Used later to figure out whether we had any packages go out let anyOutput = false const entriesStream = ms.through.obj() let esearchWritten = false libSearch.stream(opts.include, opts).on('data', pkg => { entriesStream.write(pkg) !esearchWritten && (esearchWritten = true) }).on('error', err => { if (esearchWritten) { // If esearch errored after already starting output, we can't fall back. return entriesStream.emit('error', err) } log.warn('search', 'fast search endpoint errored. Using old search.') allPackageSearch(opts) .on('data', pkg => entriesStream.write(pkg)) .on('error', err => entriesStream.emit('error', err)) .on('end', () => entriesStream.end()) }).on('end', () => entriesStream.end()) // Grab a configured output stream that will spit out packages in the // desired format. var outputStream = formatPackageStream({ args: args, // --searchinclude options are not highlighted long: npm.config.get('long'), description: npm.config.get('description'), json: npm.config.get('json'), parseable: npm.config.get('parseable'), color: npm.color }) outputStream.on('data', chunk => { if (!anyOutput) { anyOutput = true } output(chunk.toString('utf8')) }) log.silly('search', 'searching packages') ms.pipe(entriesStream, outputStream, err => { if (err) return cb(err) if (!anyOutput && !npm.config.get('json') && !npm.config.get('parseable')) { output('No matches found for ' + (args.map(JSON.stringify).join(' '))) } log.silly('search', 'search completed') log.clearProgress() cb(null, {}) }) } function prepareIncludes (args, searchopts) { if (typeof searchopts !== 'string') searchopts = '' return searchopts.split(/\s+/).concat(args).map(function (s) { return s.toLowerCase() }).filter(function (s) { return s }) } function prepareExcludes (searchexclude) { var exclude if (typeof searchexclude === 'string') { exclude = searchexclude.split(/\s+/) } else { exclude = [] } return exclude.map(function (s) { return s.toLowerCase() }) } set.js000064400000000424152231567050005703 0ustar00 module.exports = set set.usage = 'npm set (See `npm config`)' var npm = require('./npm.js') set.completion = npm.commands.config.completion function set (args, cb) { if (!args.length) return cb(set.usage) npm.commands.config(['set'].concat(args), cb) } shrinkwrap.js000064400000023510152231567050007301 0ustar00'use strict' const BB = require('bluebird') const chain = require('slide').chain const detectIndent = require('detect-indent') const detectNewline = require('detect-newline') const readFile = BB.promisify(require('graceful-fs').readFile) const getRequested = require('./install/get-requested.js') const id = require('./install/deps.js') const iferr = require('iferr') const isOnlyOptional = require('./install/is-only-optional.js') const isOnlyDev = require('./install/is-only-dev.js') const lifecycle = require('./utils/lifecycle.js') const log = require('npmlog') const moduleName = require('./utils/module-name.js') const move = require('move-concurrently') const npm = require('./npm.js') const path = require('path') const readPackageTree = BB.promisify(require('read-package-tree')) const ssri = require('ssri') const stringifyPackage = require('stringify-package') const validate = require('aproba') const writeFileAtomic = require('write-file-atomic') const unixFormatPath = require('./utils/unix-format-path.js') const isRegistry = require('./utils/is-registry.js') const { chown } = require('fs') const inferOwner = require('infer-owner') const selfOwner = { uid: process.getuid && process.getuid(), gid: process.getgid && process.getgid() } const PKGLOCK = 'package-lock.json' const SHRINKWRAP = 'npm-shrinkwrap.json' const PKGLOCK_VERSION = npm.lockfileVersion // emit JSON describing versions of all packages currently installed (for later // use with shrinkwrap install) shrinkwrap.usage = 'npm shrinkwrap' module.exports = exports = shrinkwrap exports.treeToShrinkwrap = treeToShrinkwrap function shrinkwrap (args, silent, cb) { if (typeof cb !== 'function') { cb = silent silent = false } if (args.length) { log.warn('shrinkwrap', "doesn't take positional args") } move( path.resolve(npm.prefix, PKGLOCK), path.resolve(npm.prefix, SHRINKWRAP), { Promise: BB } ).then(() => { log.notice('', `${PKGLOCK} has been renamed to ${SHRINKWRAP}. ${SHRINKWRAP} will be used for future installations.`) return readFile(path.resolve(npm.prefix, SHRINKWRAP)).then((d) => { return JSON.parse(d) }) }, (err) => { if (err.code !== 'ENOENT') { throw err } else { return readPackageTree(npm.localPrefix).then( id.computeMetadata ).then((tree) => { return BB.fromNode((cb) => { createShrinkwrap(tree, { silent, defaultFile: SHRINKWRAP }, cb) }) }) } }).then((data) => cb(null, data), cb) } module.exports.createShrinkwrap = createShrinkwrap function createShrinkwrap (tree, opts, cb) { opts = opts || {} lifecycle(tree.package, 'preshrinkwrap', tree.path, function () { const pkginfo = treeToShrinkwrap(tree) chain([ [lifecycle, tree.package, 'shrinkwrap', tree.path], [shrinkwrap_, tree.path, pkginfo, opts], [lifecycle, tree.package, 'postshrinkwrap', tree.path] ], iferr(cb, function (data) { cb(null, pkginfo) })) }) } function treeToShrinkwrap (tree) { validate('O', arguments) var pkginfo = {} if (tree.package.name) pkginfo.name = tree.package.name if (tree.package.version) pkginfo.version = tree.package.version if (tree.children.length) { pkginfo.requires = true shrinkwrapDeps(pkginfo.dependencies = {}, tree, tree) } return pkginfo } function shrinkwrapDeps (deps, top, tree, seen) { validate('OOO', [deps, top, tree]) if (!seen) seen = new Set() if (seen.has(tree)) return seen.add(tree) sortModules(tree.children).forEach(function (child) { var childIsOnlyDev = isOnlyDev(child) var pkginfo = deps[moduleName(child)] = {} var requested = getRequested(child) || child.package._requested || {} var linked = child.isLink || child.isInLink pkginfo.version = childVersion(top, child, requested) if (requested.type === 'git' && child.package._from) { pkginfo.from = child.package._from } if (child.fromBundle && !linked) { pkginfo.bundled = true } else { if (isRegistry(requested)) { pkginfo.resolved = child.package._resolved } // no integrity for git deps as integrity hashes are based on the // tarball and we can't (yet) create consistent tarballs from a stable // source. if (requested.type !== 'git') { pkginfo.integrity = child.package._integrity || undefined if (!pkginfo.integrity && child.package._shasum) { pkginfo.integrity = ssri.fromHex(child.package._shasum, 'sha1') } } } if (childIsOnlyDev) pkginfo.dev = true if (isOnlyOptional(child)) pkginfo.optional = true if (child.requires.length) { pkginfo.requires = {} sortModules(child.requires).forEach((required) => { var requested = getRequested(required, child) || required.package._requested || {} pkginfo.requires[moduleName(required)] = childRequested(top, required, requested) }) } // iterate into children on non-links and links contained within the top level package if (child.children.length) { pkginfo.dependencies = {} shrinkwrapDeps(pkginfo.dependencies, top, child, seen) } }) } function sortModules (modules) { // sort modules with the locale-agnostic Unicode sort var sortedModuleNames = modules.map(moduleName).sort() return modules.sort((a, b) => ( sortedModuleNames.indexOf(moduleName(a)) - sortedModuleNames.indexOf(moduleName(b)) )) } function childVersion (top, child, req) { if (req.type === 'directory' || req.type === 'file') { return 'file:' + unixFormatPath(path.relative(top.path, child.package._resolved || req.fetchSpec)) } else if (!isRegistry(req) && !child.fromBundle) { return child.package._resolved || req.saveSpec || req.rawSpec } else if (req.type === 'alias') { return `npm:${child.package.name}@${child.package.version}` } else { return child.package.version } } function childRequested (top, child, requested) { if (requested.type === 'directory' || requested.type === 'file') { return 'file:' + unixFormatPath(path.relative(top.path, child.package._resolved || requested.fetchSpec)) } else if (requested.type === 'git' && child.package._from) { return child.package._from } else if (!isRegistry(requested) && !child.fromBundle) { return child.package._resolved || requested.saveSpec || requested.rawSpec } else if (requested.type === 'tag') { // tags are not ranges we can match against, so we invent a "reasonable" // one based on what we actually installed. return npm.config.get('save-prefix') + child.package.version } else if (requested.saveSpec || requested.rawSpec) { return requested.saveSpec || requested.rawSpec } else if (child.package._from || (child.package._requested && child.package._requested.rawSpec)) { return child.package._from.replace(/^@?[^@]+@/, '') || child.package._requested.rawSpec } else { return child.package.version } } function shrinkwrap_ (dir, pkginfo, opts, cb) { save(dir, pkginfo, opts, cb) } function save (dir, pkginfo, opts, cb) { // copy the keys over in a well defined order // because javascript objects serialize arbitrarily BB.join( checkPackageFile(dir, SHRINKWRAP), checkPackageFile(dir, PKGLOCK), checkPackageFile(dir, 'package.json'), (shrinkwrap, lockfile, pkg) => { const info = ( shrinkwrap || lockfile || { path: path.resolve(dir, opts.defaultFile || PKGLOCK), data: '{}', indent: pkg && pkg.indent, newline: pkg && pkg.newline } ) const updated = updateLockfileMetadata(pkginfo, pkg && JSON.parse(pkg.raw)) const swdata = stringifyPackage(updated, info.indent, info.newline) if (swdata === info.raw) { // skip writing if file is identical log.verbose('shrinkwrap', `skipping write for ${path.basename(info.path)} because there were no changes.`) cb(null, pkginfo) } else { inferOwner(info.path).then(owner => { writeFileAtomic(info.path, swdata, (err) => { if (err) return cb(err) if (opts.silent) return cb(null, pkginfo) if (!shrinkwrap && !lockfile) { log.notice('', `created a lockfile as ${path.basename(info.path)}. You should commit this file.`) } if (selfOwner.uid === 0 && (selfOwner.uid !== owner.uid || selfOwner.gid !== owner.gid)) { chown(info.path, owner.uid, owner.gid, er => cb(er, pkginfo)) } else { cb(null, pkginfo) } }) }) } } ).then((file) => { }, cb) } function updateLockfileMetadata (pkginfo, pkgJson) { // This is a lot of work just to make sure the extra metadata fields are // between version and dependencies fields, without affecting any other stuff const newPkg = {} let metainfoWritten = false const metainfo = new Set([ 'lockfileVersion', 'preserveSymlinks' ]) Object.keys(pkginfo).forEach((k) => { if (k === 'dependencies') { writeMetainfo(newPkg) } if (!metainfo.has(k)) { newPkg[k] = pkginfo[k] } if (k === 'version') { writeMetainfo(newPkg) } }) if (!metainfoWritten) { writeMetainfo(newPkg) } function writeMetainfo (pkginfo) { pkginfo.lockfileVersion = PKGLOCK_VERSION if (process.env.NODE_PRESERVE_SYMLINKS) { pkginfo.preserveSymlinks = process.env.NODE_PRESERVE_SYMLINKS } metainfoWritten = true } return newPkg } function checkPackageFile (dir, name) { const file = path.resolve(dir, name) return readFile( file, 'utf8' ).then((data) => { const format = npm.config.get('format-package-lock') !== false const indent = format ? detectIndent(data).indent : 0 const newline = format ? detectNewline(data) : 0 return { path: file, raw: data, indent, newline } }).catch({code: 'ENOENT'}, () => {}) } star.js000064400000004155152231567050006066 0ustar00'use strict' const BB = require('bluebird') const fetch = require('libnpm/fetch') const figgyPudding = require('figgy-pudding') const log = require('npmlog') const npa = require('libnpm/parse-arg') const npm = require('./npm.js') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const usage = require('./utils/usage.js') const whoami = require('./whoami.js') const StarConfig = figgyPudding({ 'unicode': {} }) star.usage = usage( 'star', 'npm star [...]\n' + 'npm unstar [...]' ) star.completion = function (opts, cb) { // FIXME: there used to be registry completion here, but it stopped making // sense somewhere around 50,000 packages on the registry cb() } module.exports = star function star (args, cb) { const opts = StarConfig(npmConfig()) return BB.try(() => { if (!args.length) throw new Error(star.usage) let s = opts.unicode ? '\u2605 ' : '(*)' const u = opts.unicode ? '\u2606 ' : '( )' const using = !(npm.command.match(/^un/)) if (!using) s = u return BB.map(args.map(npa), pkg => { return BB.all([ whoami([pkg], true, () => {}), fetch.json(pkg.escapedName, opts.concat({ spec: pkg, query: {write: true}, 'prefer-online': true })) ]).then(([username, fullData]) => { if (!username) { throw new Error('You need to be logged in!') } const body = { _id: fullData._id, _rev: fullData._rev, users: fullData.users || {} } if (using) { log.info('star', 'starring', body._id) body.users[username] = true log.verbose('star', 'starring', body) } else { delete body.users[username] log.info('star', 'unstarring', body._id) log.verbose('star', 'unstarring', body) } return fetch.json(pkg.escapedName, opts.concat({ spec: pkg, method: 'PUT', body })) }).then(data => { output(s + ' ' + pkg.name) log.verbose('star', data) return data }) }) }).nodeify(cb) } stars.js000064400000002036152231567050006245 0ustar00'use strict' const BB = require('bluebird') const npmConfig = require('./config/figgy-config.js') const fetch = require('libnpm/fetch') const log = require('npmlog') const output = require('./utils/output.js') const whoami = require('./whoami.js') stars.usage = 'npm stars []' module.exports = stars function stars ([user], cb) { const opts = npmConfig() return BB.try(() => { return (user ? BB.resolve(user) : whoami([], true, () => {})).then(usr => { return fetch.json('/-/_view/starredByUser', opts.concat({ query: {key: `"${usr}"`} // WHY. WHY THE ""?! })) }).then(data => data.rows).then(stars => { if (stars.length === 0) { log.warn('stars', 'user has not starred any packages.') } else { stars.forEach(s => output(s.value)) } }) }).catch(err => { if (err.code === 'ENEEDAUTH') { throw Object.assign(new Error("'npm stars' on your own user account requires auth"), { code: 'ENEEDAUTH' }) } else { throw err } }).nodeify(cb) } stop.js000064400000000075152231567050006077 0ustar00module.exports = require('./utils/lifecycle-cmd.js')('stop') search/all-package-metadata.js000064400000027403152231567050012302 0ustar00'use strict' const BB = require('bluebird') const cacheFile = require('npm-cache-filename') const chownr = BB.promisify(require('chownr')) const correctMkdir = BB.promisify(require('../utils/correct-mkdir.js')) const figgyPudding = require('figgy-pudding') const fs = require('graceful-fs') const JSONStream = require('JSONStream') const log = require('npmlog') const mkdir = BB.promisify(require('gentle-fs').mkdir) const ms = require('mississippi') const npmFetch = require('libnpm/fetch') const path = require('path') const sortedUnionStream = require('sorted-union-stream') const url = require('url') const writeStreamAtomic = require('fs-write-stream-atomic') const statAsync = BB.promisify(fs.stat) const APMOpts = figgyPudding({ cache: {}, registry: {} }) // Returns a sorted stream of all package metadata. Internally, takes care of // maintaining its metadata cache and making partial or full remote requests, // according to staleness, validity, etc. // // The local cache must hold certain invariants: // 1. It must be a proper JSON object // 2. It must have its keys lexically sorted // 3. The first entry must be `_updated` with a millisecond timestamp as a val. // 4. It must include all entries that exist in the metadata endpoint as of // the value in `_updated` module.exports = allPackageMetadata function allPackageMetadata (opts) { const staleness = opts.staleness const stream = ms.through.obj() opts = APMOpts(opts) const cacheBase = cacheFile(path.resolve(path.dirname(opts.cache)))(url.resolve(opts.registry, '/-/all')) const cachePath = path.join(cacheBase, '.cache.json') createEntryStream( cachePath, staleness, opts ).then(({entryStream, latest, newEntries}) => { log.silly('all-package-metadata', 'entry stream created') if (entryStream && newEntries) { return createCacheWriteStream(cachePath, latest, opts).then(writer => { log.silly('all-package-metadata', 'output stream created') ms.pipeline.obj(entryStream, writer, stream) }) } else if (entryStream) { ms.pipeline.obj(entryStream, stream) } else { stream.emit('error', new Error('No search sources available')) } }).catch(err => stream.emit('error', err)) return stream } // Creates a stream of the latest available package metadata. // Metadata will come from a combination of the local cache and remote data. module.exports._createEntryStream = createEntryStream function createEntryStream (cachePath, staleness, opts) { return createCacheEntryStream( cachePath, opts ).catch(err => { log.warn('', 'Failed to read search cache. Rebuilding') log.silly('all-package-metadata', 'cache read error: ', err) return {} }).then(({ updateStream: cacheStream, updatedLatest: cacheLatest }) => { cacheLatest = cacheLatest || 0 return createEntryUpdateStream(staleness, cacheLatest, opts).catch(err => { log.warn('', 'Search data request failed, search might be stale') log.silly('all-package-metadata', 'update request error: ', err) return {} }).then(({updateStream, updatedLatest}) => { updatedLatest = updatedLatest || 0 const latest = updatedLatest || cacheLatest if (!cacheStream && !updateStream) { throw new Error('No search sources available') } if (cacheStream && updateStream) { // Deduped, unioned, sorted stream from the combination of both. return { entryStream: createMergedStream(cacheStream, updateStream), latest, newEntries: !!updatedLatest } } else { // Either one works if one or the other failed return { entryStream: cacheStream || updateStream, latest, newEntries: !!updatedLatest } } }) }) } // Merges `a` and `b` into one stream, dropping duplicates in favor of entries // in `b`. Both input streams should already be individually sorted, and the // returned output stream will have semantics resembling the merge step of a // plain old merge sort. module.exports._createMergedStream = createMergedStream function createMergedStream (a, b) { linkStreams(a, b) return sortedUnionStream(b, a, ({name}) => name) } // Reads the local index and returns a stream that spits out package data. module.exports._createCacheEntryStream = createCacheEntryStream function createCacheEntryStream (cacheFile, opts) { log.verbose('all-package-metadata', 'creating entry stream from local cache') log.verbose('all-package-metadata', cacheFile) return statAsync(cacheFile).then(stat => { // TODO - This isn't very helpful if `cacheFile` is empty or just `{}` const entryStream = ms.pipeline.obj( fs.createReadStream(cacheFile), JSONStream.parse('*'), // I believe this passthrough is necessary cause `jsonstream` returns // weird custom streams that behave funny sometimes. ms.through.obj() ) return extractUpdated(entryStream, 'cached-entry-stream', opts) }) } // Stream of entry updates from the server. If `latest` is `0`, streams the // entire metadata object from the registry. module.exports._createEntryUpdateStream = createEntryUpdateStream function createEntryUpdateStream (staleness, latest, opts) { log.verbose('all-package-metadata', 'creating remote entry stream') let partialUpdate = false let uri = '/-/all' if (latest && (Date.now() - latest < (staleness * 1000))) { // Skip the request altogether if our `latest` isn't stale. log.verbose('all-package-metadata', 'Local data up to date, skipping update') return BB.resolve({}) } else if (latest === 0) { log.warn('', 'Building the local index for the first time, please be patient') log.verbose('all-package-metadata', 'No cached data: requesting full metadata db') } else { log.verbose('all-package-metadata', 'Cached data present with timestamp:', latest, 'requesting partial index update') uri += '/since?stale=update_after&startkey=' + latest partialUpdate = true } return npmFetch(uri, opts).then(res => { log.silly('all-package-metadata', 'request stream opened, code:', res.statusCode) let entryStream = ms.pipeline.obj( res.body, JSONStream.parse('*', (pkg, key) => { if (key[0] === '_updated' || key[0][0] !== '_') { return pkg } }) ) if (partialUpdate) { // The `/all/since` endpoint doesn't return `_updated`, so we // just use the request's own timestamp. return { updateStream: entryStream, updatedLatest: Date.parse(res.headers.get('date')) } } else { return extractUpdated(entryStream, 'entry-update-stream', opts) } }) } // Both the (full) remote requests and the local index have `_updated` as their // first returned entries. This is the "latest" unix timestamp for the metadata // in question. This code does a bit of juggling with the data streams // so that we can pretend that field doesn't exist, but still extract `latest` function extractUpdated (entryStream, label, opts) { log.silly('all-package-metadata', 'extracting latest') return new BB((resolve, reject) => { function nope (msg) { return function () { log.warn('all-package-metadata', label, msg) entryStream.removeAllListeners() entryStream.destroy() reject(new Error(msg)) } } const onErr = nope('Failed to read stream') const onEnd = nope('Empty or invalid stream') entryStream.on('error', onErr) entryStream.on('end', onEnd) entryStream.once('data', latest => { log.silly('all-package-metadata', 'got first stream entry for', label, latest) entryStream.removeListener('error', onErr) entryStream.removeListener('end', onEnd) if (typeof latest === 'number') { // The extra pipeline is to return a stream that will implicitly unpause // after having an `.on('data')` listener attached, since using this // `data` event broke its initial state. resolve({ updateStream: entryStream.pipe(ms.through.obj()), updatedLatest: latest }) } else { reject(new Error('expected first entry to be _updated')) } }) }) } // Creates a stream that writes input metadata to the current cache. // Cache updates are atomic, and the stream closes when *everything* is done. // The stream is also passthrough, so entries going through it will also // be output from it. module.exports._createCacheWriteStream = createCacheWriteStream function createCacheWriteStream (cacheFile, latest, opts) { return _ensureCacheDirExists(cacheFile, opts).then(({uid, gid}) => { log.silly('all-package-metadata', 'creating output stream') const outStream = _createCacheOutStream() const cacheFileStream = writeStreamAtomic(cacheFile) const inputStream = _createCacheInStream( cacheFileStream, outStream, latest ) // Glue together the various streams so they fail together. // `cacheFileStream` errors are already handled by the `inputStream` // pipeline let errEmitted = false linkStreams(inputStream, outStream, () => { errEmitted = true }) cacheFileStream.on('close', () => { if (!errEmitted) { if (typeof uid === 'number' && typeof gid === 'number' && process.getuid && process.getgid && (process.getuid() !== uid || process.getgid() !== gid)) { chownr.sync(cacheFile, uid, gid) } outStream.end() } }) return ms.duplex.obj(inputStream, outStream) }) } // return the {uid,gid} that the cache should have function _ensureCacheDirExists (cacheFile, opts) { var cacheBase = path.dirname(cacheFile) log.silly('all-package-metadata', 'making sure cache dir exists at', cacheBase) return correctMkdir(opts.cache).then(st => { return mkdir(cacheBase).then(made => { return chownr(made || cacheBase, st.uid, st.gid) }).then(() => ({ uid: st.uid, gid: st.gid })) }) } function _createCacheOutStream () { // NOTE: this looks goofy, but it's necessary in order to get // JSONStream to play nice with the rest of everything. return ms.pipeline.obj( ms.through(), JSONStream.parse('*', (obj, key) => { // This stream happens to get _updated passed through it, for // implementation reasons. We make sure to filter it out cause // the fact that it comes t if (typeof obj === 'object') { return obj } }), ms.through.obj() ) } function _createCacheInStream (writer, outStream, latest) { let updatedWritten = false const inStream = ms.pipeline.obj( ms.through.obj((pkg, enc, cb) => { if (!updatedWritten && typeof pkg === 'number') { // This is the `_updated` value getting sent through. updatedWritten = true return cb(null, ['_updated', pkg]) } else if (typeof pkg !== 'object') { this.emit('error', new Error('invalid value written to input stream')) } else { // The [key, val] format is expected by `jsonstream` for object writing cb(null, [pkg.name, pkg]) } }), JSONStream.stringifyObject('{', ',', '}'), ms.through((chunk, enc, cb) => { // This tees off the buffer data to `outStream`, and then continues // the pipeline as usual outStream.write(chunk, enc, () => cb(null, chunk)) }), // And finally, we write to the cache file. writer ) inStream.write(latest) return inStream } // Links errors between `a` and `b`, preventing cycles, and calls `cb` if // an error happens, once per error. function linkStreams (a, b, cb) { var lastError = null a.on('error', function (err) { if (err !== lastError) { lastError = err b.emit('error', err) cb && cb(err) } }) b.on('error', function (err) { if (err !== lastError) { lastError = err a.emit('error', err) cb && cb(err) } }) } search/all-package-search.js000064400000003020152231567050011754 0ustar00var ms = require('mississippi') var allPackageMetadata = require('./all-package-metadata') var packageFilter = require('./package-filter.js') module.exports = allPackageSearch function allPackageSearch (opts) { var searchSection = (opts.unicode ? '🤔 ' : '') + 'search' // Get a stream with *all* the packages. This takes care of dealing // with the local cache as well, but that's an internal detail. var allEntriesStream = allPackageMetadata(opts) // Grab a stream that filters those packages according to given params. var filterStream = streamFilter(function (pkg) { opts.log.gauge.pulse('search') opts.log.gauge.show({section: searchSection, logline: 'scanning ' + pkg.name}) // Simply 'true' if the package matches search parameters. var match = packageFilter(pkg, opts.include, opts.exclude, { description: opts.description }) return match }) return ms.pipeline.obj(allEntriesStream, filterStream) } function streamFilter (filter) { return ms.through.obj(function (data, enc, cb) { if (filter(data)) { this.push(standardizePkg(data)) } cb() }) } function standardizePkg (data) { return { name: data.name, description: data.description, maintainers: (data.maintainers || []).map(function (m) { return { username: m.name, email: m.email } }), keywords: data.keywords || [], version: Object.keys(data.versions || {})[0] || [], date: ( data.time && data.time.modified && new Date(data.time.modified) ) || null } } search/format-package-stream.js000064400000010405152231567050012527 0ustar00'use strict' var ms = require('mississippi') var jsonstream = require('JSONStream') var columnify = require('columnify') // This module consumes package data in the following format: // // { // name: String, // description: String, // maintainers: [{ username: String, email: String }], // keywords: String | [String], // version: String, // date: Date // can be null, // } // // The returned stream will format this package data // into a byte stream of formatted, displayable output. module.exports = formatPackageStream function formatPackageStream (opts) { opts = opts || {} if (opts.json) { return jsonOutputStream() } else { return textOutputStream(opts) } } function jsonOutputStream () { return ms.pipeline.obj( ms.through.obj(), jsonstream.stringify('[', ',', ']'), ms.through() ) } function textOutputStream (opts) { var line = 0 return ms.through.obj(function (pkg, enc, cb) { cb(null, prettify(pkg, ++line, opts)) }) } function prettify (data, num, opts) { opts = opts || {} var truncate = !opts.long var pkg = normalizePackage(data, opts) var columns = opts.description ? ['name', 'description', 'author', 'date', 'version', 'keywords'] : ['name', 'author', 'date', 'version', 'keywords'] if (opts.parseable) { return columns.map(function (col) { return pkg[col] && ('' + pkg[col]).replace(/\t/g, ' ') }).join('\t') } var output = columnify( [pkg], { include: columns, showHeaders: num <= 1, columnSplitter: ' | ', truncate: truncate, config: { name: { minWidth: 25, maxWidth: 25, truncate: false, truncateMarker: '' }, description: { minWidth: 20, maxWidth: 20 }, author: { minWidth: 15, maxWidth: 15 }, date: { maxWidth: 11 }, version: { minWidth: 8, maxWidth: 8 }, keywords: { maxWidth: Infinity } } } ) output = trimToMaxWidth(output) if (opts.color) { output = highlightSearchTerms(output, opts.args) } return output } var colors = [31, 33, 32, 36, 34, 35] var cl = colors.length function addColorMarker (str, arg, i) { var m = i % cl + 1 var markStart = String.fromCharCode(m) var markEnd = String.fromCharCode(0) if (arg.charAt(0) === '/') { return str.replace( new RegExp(arg.substr(1, arg.length - 2), 'gi'), function (bit) { return markStart + bit + markEnd } ) } // just a normal string, do the split/map thing var pieces = str.toLowerCase().split(arg.toLowerCase()) var p = 0 return pieces.map(function (piece) { piece = str.substr(p, piece.length) var mark = markStart + str.substr(p + piece.length, arg.length) + markEnd p += piece.length + arg.length return piece + mark }).join('') } function colorize (line) { for (var i = 0; i < cl; i++) { var m = i + 1 var color = '\u001B[' + colors[i] + 'm' line = line.split(String.fromCharCode(m)).join(color) } var uncolor = '\u001B[0m' return line.split('\u0000').join(uncolor) } function getMaxWidth () { var cols try { var tty = require('tty') var stdout = process.stdout cols = !tty.isatty(stdout.fd) ? Infinity : process.stdout.getWindowSize()[0] cols = (cols === 0) ? Infinity : cols } catch (ex) { cols = Infinity } return cols } function trimToMaxWidth (str) { var maxWidth = getMaxWidth() return str.split('\n').map(function (line) { return line.slice(0, maxWidth) }).join('\n') } function highlightSearchTerms (str, terms) { terms.forEach(function (arg, i) { str = addColorMarker(str, arg, i) }) return colorize(str).trim() } function normalizePackage (data, opts) { opts = opts || {} return { name: data.name, description: opts.description ? data.description : '', author: (data.maintainers || []).map(function (m) { return '=' + m.username }).join(' '), keywords: Array.isArray(data.keywords) ? data.keywords.join(' ') : typeof data.keywords === 'string' ? data.keywords.replace(/[,\s]+/, ' ') : '', version: data.version, date: (data.date && (data.date.toISOString() // remove time .split('T').join(' ') .replace(/:[0-9]{2}\.[0-9]{3}Z$/, '')) .slice(0, -5)) || 'prehistoric' } } search/package-filter.js000064400000002264152231567050011237 0ustar00'use strict' module.exports = filter function filter (data, include, exclude, opts) { return typeof data === 'object' && filterWords(data, include, exclude, opts) } function getWords (data, opts) { return [ data.name ] .concat((opts && opts.description) ? data.description : []) .concat((data.maintainers || []).map(function (m) { return '=' + m.name })) .concat(data.versions && data.versions.length && data.url && ('<' + data.url + '>')) .concat(data.keywords || []) .map(function (f) { return f && f.trim && f.trim() }) .filter(function (f) { return f }) .join(' ') .toLowerCase() } function filterWords (data, include, exclude, opts) { var words = getWords(data, opts) for (var i = 0, l = include.length; i < l; i++) { if (!match(words, include[i])) return false } for (i = 0, l = exclude.length; i < l; i++) { if (match(words, exclude[i])) return false } return true } function match (words, pattern) { if (pattern.charAt(0) === '/') { pattern = pattern.replace(/\/$/, '') pattern = new RegExp(pattern.substr(1, pattern.length - 1)) return words.match(pattern) } return words.indexOf(pattern) !== -1 } team.js000064400000011164152231567050006041 0ustar00/* eslint-disable standard/no-callback-literal */ const columns = require('cli-columns') const figgyPudding = require('figgy-pudding') const libteam = require('libnpm/team') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const usage = require('./utils/usage') module.exports = team team.subcommands = ['create', 'destroy', 'add', 'rm', 'ls', 'edit'] team.usage = usage( 'team', 'npm team create [--otp ]\n' + 'npm team destroy [--otp ]\n' + 'npm team add [--otp ]\n' + 'npm team rm [--otp ]\n' + 'npm team ls |\n' + 'npm team edit ' ) const TeamConfig = figgyPudding({ json: {}, loglevel: {}, parseable: {}, silent: {} }) function UsageError () { throw Object.assign(new Error(team.usage), {code: 'EUSAGE'}) } team.completion = function (opts, cb) { var argv = opts.conf.argv.remain if (argv.length === 2) { return cb(null, team.subcommands) } switch (argv[2]) { case 'ls': case 'create': case 'destroy': case 'add': case 'rm': case 'edit': return cb(null, []) default: return cb(new Error(argv[2] + ' not recognized')) } } function team ([cmd, entity = '', user = ''], cb) { // Entities are in the format : otplease(npmConfig(), opts => { opts = TeamConfig(opts).concat({description: null}) entity = entity.replace(/^@/, '') switch (cmd) { case 'create': return teamCreate(entity, opts) case 'destroy': return teamDestroy(entity, opts) case 'add': return teamAdd(entity, user, opts) case 'rm': return teamRm(entity, user, opts) case 'ls': { const match = entity.match(/[^:]+:.+/) if (match) { return teamListUsers(entity, opts) } else { return teamListTeams(entity, opts) } } case 'edit': throw new Error('`npm team edit` is not implemented yet.') default: UsageError() } }).then( data => cb(null, data), err => err.code === 'EUSAGE' ? cb(err.message) : cb(err) ) } function teamCreate (entity, opts) { return libteam.create(entity, opts).then(() => { if (opts.json) { output(JSON.stringify({ created: true, team: entity })) } else if (opts.parseable) { output(`${entity}\tcreated`) } else if (!opts.silent && opts.loglevel !== 'silent') { output(`+@${entity}`) } }) } function teamDestroy (entity, opts) { return libteam.destroy(entity, opts).then(() => { if (opts.json) { output(JSON.stringify({ deleted: true, team: entity })) } else if (opts.parseable) { output(`${entity}\tdeleted`) } else if (!opts.silent && opts.loglevel !== 'silent') { output(`-@${entity}`) } }) } function teamAdd (entity, user, opts) { return libteam.add(user, entity, opts).then(() => { if (opts.json) { output(JSON.stringify({ added: true, team: entity, user })) } else if (opts.parseable) { output(`${user}\t${entity}\tadded`) } else if (!opts.silent && opts.loglevel !== 'silent') { output(`${user} added to @${entity}`) } }) } function teamRm (entity, user, opts) { return libteam.rm(user, entity, opts).then(() => { if (opts.json) { output(JSON.stringify({ removed: true, team: entity, user })) } else if (opts.parseable) { output(`${user}\t${entity}\tremoved`) } else if (!opts.silent && opts.loglevel !== 'silent') { output(`${user} removed from @${entity}`) } }) } function teamListUsers (entity, opts) { return libteam.lsUsers(entity, opts).then(users => { users = users.sort() if (opts.json) { output(JSON.stringify(users, null, 2)) } else if (opts.parseable) { output(users.join('\n')) } else if (!opts.silent && opts.loglevel !== 'silent') { output(`\n@${entity} has ${users.length} user${users.length === 1 ? '' : 's'}:\n`) output(columns(users, {padding: 1})) } }) } function teamListTeams (entity, opts) { return libteam.lsTeams(entity, opts).then(teams => { teams = teams.sort() if (opts.json) { output(JSON.stringify(teams, null, 2)) } else if (opts.parseable) { output(teams.join('\n')) } else if (!opts.silent && opts.loglevel !== 'silent') { output(`\n@${entity} has ${teams.length} team${teams.length === 1 ? '' : 's'}:\n`) output(columns(teams.map(t => `@${t}`), {padding: 1})) } }) } test.js000064400000000566152231567050006076 0ustar00/* eslint-disable standard/no-callback-literal */ module.exports = test const testCmd = require('./utils/lifecycle-cmd.js')('test') test.usage = testCmd.usage function test (args, cb) { testCmd(args, function (er) { if (!er) return cb() if (er.code === 'ELIFECYCLE') { return cb('Test failed. See above for more details.') } return cb(er) }) } token.js000064400000015242152231567050006234 0ustar00'use strict' const profile = require('libnpm/profile') const npm = require('./npm.js') const figgyPudding = require('figgy-pudding') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const Table = require('cli-table3') const Bluebird = require('bluebird') const isCidrV4 = require('is-cidr').v4 const isCidrV6 = require('is-cidr').v6 const readUserInfo = require('./utils/read-user-info.js') const ansistyles = require('ansistyles') const log = require('npmlog') const pulseTillDone = require('./utils/pulse-till-done.js') module.exports = token token._validateCIDRList = validateCIDRList token.usage = 'npm token list\n' + 'npm token revoke \n' + 'npm token create [--read-only] [--cidr=list]\n' token.subcommands = ['list', 'revoke', 'create'] token.completion = function (opts, cb) { var argv = opts.conf.argv.remain switch (argv[2]) { case 'list': case 'revoke': case 'create': return cb(null, []) default: return cb(new Error(argv[2] + ' not recognized')) } } function withCb (prom, cb) { prom.then((value) => cb(null, value), cb) } function token (args, cb) { log.gauge.show('token') if (args.length === 0) return withCb(list([]), cb) switch (args[0]) { case 'list': case 'ls': withCb(list(), cb) break case 'delete': case 'revoke': case 'remove': case 'rm': withCb(rm(args.slice(1)), cb) break case 'create': withCb(create(args.slice(1)), cb) break default: cb(new Error('Unknown profile command: ' + args[0])) } } function generateTokenIds (tokens, minLength) { const byId = {} tokens.forEach((token) => { token.id = token.key for (let ii = minLength; ii < token.key.length; ++ii) { if (!tokens.some((ot) => ot !== token && ot.key.slice(0, ii) === token.key.slice(0, ii))) { token.id = token.key.slice(0, ii) break } } byId[token.id] = token }) return byId } const TokenConfig = figgyPudding({ auth: {}, registry: {}, otp: {}, cidr: {}, 'read-only': {}, json: {}, parseable: {} }) function config () { let conf = TokenConfig(npmConfig()) const creds = npm.config.getCredentialsByURI(conf.registry) if (creds.token) { conf = conf.concat({ auth: { token: creds.token } }) } else if (creds.username) { conf = conf.concat({ auth: { basic: { username: creds.username, password: creds.password } } }) } else if (creds.auth) { const auth = Buffer.from(creds.auth, 'base64').toString().split(':', 2) conf = conf.concat({ auth: { basic: { username: auth[0], password: auth[1] } } }) } else { conf = conf.concat({ auth: {} }) } if (conf.otp) conf.auth.otp = conf.otp return conf } function list (args) { const conf = config() log.info('token', 'getting list') return pulseTillDone.withPromise(profile.listTokens(conf)).then((tokens) => { if (conf.json) { output(JSON.stringify(tokens, null, 2)) return } else if (conf.parseable) { output(['key', 'token', 'created', 'readonly', 'CIDR whitelist'].join('\t')) tokens.forEach((token) => { output([ token.key, token.token, token.created, token.readonly ? 'true' : 'false', token.cidr_whitelist ? token.cidr_whitelist.join(',') : '' ].join('\t')) }) return } generateTokenIds(tokens, 6) const idWidth = tokens.reduce((acc, token) => Math.max(acc, token.id.length), 0) const table = new Table({ head: ['id', 'token', 'created', 'readonly', 'CIDR whitelist'], colWidths: [Math.max(idWidth, 2) + 2, 9, 12, 10] }) tokens.forEach((token) => { table.push([ token.id, token.token + '…', String(token.created).slice(0, 10), token.readonly ? 'yes' : 'no', token.cidr_whitelist ? token.cidr_whitelist.join(', ') : '' ]) }) output(table.toString()) }) } function rm (args) { if (args.length === 0) { throw new Error('npm token revoke ') } const conf = config() const toRemove = [] const progress = log.newItem('removing tokens', toRemove.length) progress.info('token', 'getting existing list') return pulseTillDone.withPromise(profile.listTokens(conf).then((tokens) => { args.forEach((id) => { const matches = tokens.filter((token) => token.key.indexOf(id) === 0) if (matches.length === 1) { toRemove.push(matches[0].key) } else if (matches.length > 1) { throw new Error(`Token ID "${id}" was ambiguous, a new token may have been created since you last ran \`npm-profile token list\`.`) } else { const tokenMatches = tokens.filter((token) => id.indexOf(token.token) === 0) if (tokenMatches === 0) { throw new Error(`Unknown token id or value "${id}".`) } toRemove.push(id) } }) return Bluebird.map(toRemove, (key) => { return otplease(conf, conf => { return profile.removeToken(key, conf) }) }) })).then(() => { if (conf.json) { output(JSON.stringify(toRemove)) } else if (conf.parseable) { output(toRemove.join('\t')) } else { output('Removed ' + toRemove.length + ' token' + (toRemove.length !== 1 ? 's' : '')) } }) } function create (args) { const conf = config() const cidr = conf.cidr const readonly = conf['read-only'] const validCIDR = validateCIDRList(cidr) return readUserInfo.password().then((password) => { log.info('token', 'creating') return pulseTillDone.withPromise(otplease(conf, conf => { return profile.createToken(password, readonly, validCIDR, conf) })) }).then((result) => { delete result.key delete result.updated if (conf.json) { output(JSON.stringify(result)) } else if (conf.parseable) { Object.keys(result).forEach((k) => output(k + '\t' + result[k])) } else { const table = new Table() Object.keys(result).forEach((k) => table.push({[ansistyles.bright(k)]: String(result[k])})) output(table.toString()) } }) } function validateCIDR (cidr) { if (isCidrV6(cidr)) { throw new Error('CIDR whitelist can only contain IPv4 addresses, ' + cidr + ' is IPv6') } if (!isCidrV4(cidr)) { throw new Error('CIDR whitelist contains invalid CIDR entry: ' + cidr) } } function validateCIDRList (cidrs) { const maybeList = cidrs ? (Array.isArray(cidrs) ? cidrs : [cidrs]) : [] const list = maybeList.length === 1 ? maybeList[0].split(/,\s*/) : maybeList list.forEach(validateCIDR) return list } unbuild.js000064400000010426152231567050006555 0ustar00module.exports = unbuild module.exports.rmStuff = rmStuff unbuild.usage = 'npm unbuild \n(this is plumbing)' const readJson = require('read-package-json') const gentlyRm = require('./utils/gently-rm.js') const npm = require('./npm.js') const path = require('path') const isInside = require('path-is-inside') const lifecycle = require('./utils/lifecycle.js') const asyncMap = require('slide').asyncMap const chain = require('slide').chain const log = require('npmlog') const build = require('./build.js') const output = require('./utils/output.js') // args is a list of folders. // remove any bins/etc, and then delete the folder. function unbuild (args, silent, cb) { if (typeof silent === 'function') { cb = silent silent = false } asyncMap(args, unbuild_(silent), cb) } function unbuild_ (silent) { return function (folder, cb_) { function cb (er) { cb_(er, path.relative(npm.root, folder)) } folder = path.resolve(folder) const base = isInside(folder, npm.prefix) ? npm.prefix : folder delete build._didBuild[folder] log.verbose('unbuild', folder.substr(npm.prefix.length + 1)) readJson(path.resolve(folder, 'package.json'), function (er, pkg) { // if no json, then just trash it, but no scripts or whatever. if (er) return gentlyRm(folder, false, base, cb) chain( [ [lifecycle, pkg, 'preuninstall', folder, { failOk: true }], [lifecycle, pkg, 'uninstall', folder, { failOk: true }], !silent && function (cb) { output('unbuild ' + pkg._id) cb() }, [rmStuff, pkg, folder], [lifecycle, pkg, 'postuninstall', folder, { failOk: true }], [gentlyRm, folder, false, base] ], cb ) }) } } function rmStuff (pkg, folder, cb) { // if it's global, and folder is in {prefix}/node_modules, // then bins are in {prefix}/bin // otherwise, then bins are in folder/../.bin const dir = path.dirname(folder) const scope = path.basename(dir) const parent = scope.charAt(0) === '@' ? path.dirname(dir) : dir const gnm = npm.dir // gnm might be an absolute path, parent might be relative // this checks they're the same directory regardless const top = path.relative(gnm, parent) === '' log.verbose('unbuild rmStuff', pkg._id, 'from', gnm) if (!top) log.verbose('unbuild rmStuff', 'in', parent) asyncMap([rmBins, rmMans], function (fn, cb) { fn(pkg, folder, parent, top, cb) }, cb) } function rmBins (pkg, folder, parent, top, cb) { if (!pkg.bin) return cb() const binRoot = top ? npm.bin : path.resolve(parent, '.bin') asyncMap(Object.keys(pkg.bin), function (b, cb) { if (process.platform === 'win32') { chain([ [gentlyRm, path.resolve(binRoot, b) + '.ps1', true, folder], [gentlyRm, path.resolve(binRoot, b) + '.cmd', true, folder], [gentlyRm, path.resolve(binRoot, b), true, folder] ], cb) } else { gentlyRm(path.resolve(binRoot, b), true, folder, cb) } }, gentlyRmBinRoot) function gentlyRmBinRoot (err) { if (err || top) return cb(err) return gentlyRm(binRoot, true, parent, cb) } } function rmMans (pkg, folder, parent, top, cb) { if (!pkg.man || !top || process.platform === 'win32' || !npm.config.get('global')) { return cb() } const manRoot = path.resolve(npm.config.get('prefix'), 'share', 'man') log.verbose('rmMans', 'man files are', pkg.man, 'in', manRoot) asyncMap(pkg.man, function (man, cb) { if (Array.isArray(man)) { man.forEach(rmMan) } else { rmMan(man) } function rmMan (man) { log.silly('rmMan', 'preparing to remove', man) const parseMan = man.match(/(.*\.([0-9]+)(\.gz)?)$/) if (!parseMan) { log.error( 'rmMan', man, 'is not a valid name for a man file.', 'Man files must end with a number, ' + 'and optionally a .gz suffix if they are compressed.' ) return cb() } const stem = parseMan[1] const sxn = parseMan[2] const gz = parseMan[3] || '' const bn = path.basename(stem) const manDest = path.join( manRoot, 'man' + sxn, (bn.indexOf(pkg.name) === 0 ? bn : pkg.name + '-' + bn) + '.' + sxn + gz ) gentlyRm(manDest, true, cb) } }, cb) } uninstall.js000064400000004325152231567050007125 0ustar00'use strict' // remove a package. module.exports = uninstall const path = require('path') const validate = require('aproba') const readJson = require('read-package-json') const iferr = require('iferr') const npm = require('./npm.js') const Installer = require('./install.js').Installer const getSaveType = require('./install/save.js').getSaveType const removeDeps = require('./install/deps.js').removeDeps const log = require('npmlog') const usage = require('./utils/usage') uninstall.usage = usage( 'uninstall', 'npm uninstall [<@scope>/][@]... [--save-prod|--save-dev|--save-optional] [--no-save]' ) uninstall.completion = require('./utils/completion/installed-shallow.js') function uninstall (args, cb) { validate('AF', arguments) // the /path/to/node_modules/.. const dryrun = !!npm.config.get('dry-run') if (args.length === 1 && args[0] === '.') args = [] const where = npm.config.get('global') || !args.length ? path.resolve(npm.globalDir, '..') : npm.prefix args = args.filter(function (a) { return path.resolve(a) !== where }) if (args.length) { new Uninstaller(where, dryrun, args).run(cb) } else { // remove this package from the global space, if it's installed there readJson(path.resolve(npm.localPrefix, 'package.json'), function (er, pkg) { if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er) if (er) return cb(uninstall.usage) new Uninstaller(where, dryrun, [pkg.name]).run(cb) }) } } class Uninstaller extends Installer { constructor (where, dryrun, args) { super(where, dryrun, args) this.remove = [] } loadArgMetadata (next) { this.args = this.args.map(function (arg) { return {name: arg} }) next() } loadAllDepsIntoIdealTree (cb) { validate('F', arguments) this.remove = this.args this.args = [] log.silly('uninstall', 'loadAllDepsIntoIdealTree') const saveDeps = getSaveType() super.loadAllDepsIntoIdealTree(iferr(cb, () => { removeDeps(this.remove, this.idealTree, saveDeps, cb) })) } // no top level lifecycles on rm runPreinstallTopLevelLifecycles (cb) { cb() } runPostinstallTopLevelLifecycles (cb) { cb() } } module.exports.Uninstaller = Uninstaller unpublish.js000064400000007012152231567050007121 0ustar00/* eslint-disable standard/no-callback-literal */ 'use strict' module.exports = unpublish const BB = require('bluebird') const figgyPudding = require('figgy-pudding') const libaccess = require('libnpm/access') const libunpub = require('libnpm/unpublish') const log = require('npmlog') const npa = require('npm-package-arg') const npm = require('./npm.js') const npmConfig = require('./config/figgy-config.js') const npmFetch = require('npm-registry-fetch') const otplease = require('./utils/otplease.js') const output = require('./utils/output.js') const path = require('path') const readJson = BB.promisify(require('read-package-json')) const usage = require('./utils/usage.js') const whoami = BB.promisify(require('./whoami.js')) unpublish.usage = usage( 'unpublish', '\nnpm unpublish [<@scope>/]@' + '\nnpm unpublish [<@scope>/] --force' ) function UsageError () { throw Object.assign(new Error(`Usage: ${unpublish.usage}`), { code: 'EUSAGE' }) } const UnpublishConfig = figgyPudding({ force: {}, loglevel: {}, silent: {} }) unpublish.completion = function (cliOpts, cb) { if (cliOpts.conf.argv.remain.length >= 3) return cb() whoami([], true).then(username => { if (!username) { return [] } const opts = UnpublishConfig(npmConfig()) return libaccess.lsPackages(username, opts).then(access => { // do a bit of filtering at this point, so that we don't need // to fetch versions for more than one thing, but also don't // accidentally a whole project. let pkgs = Object.keys(access) if (!cliOpts.partialWord || !pkgs.length) { return pkgs } const pp = npa(cliOpts.partialWord).name pkgs = pkgs.filter(p => !p.indexOf(pp)) if (pkgs.length > 1) return pkgs return npmFetch.json(npa(pkgs[0]).escapedName, opts).then(doc => { const vers = Object.keys(doc.versions) if (!vers.length) { return pkgs } else { return vers.map(v => `${pkgs[0]}@${v}`) } }) }) }).nodeify(cb) } function unpublish (args, cb) { if (args.length > 1) return cb(unpublish.usage) const spec = args.length && npa(args[0]) const opts = UnpublishConfig(npmConfig()) const version = spec.rawSpec BB.try(() => { log.silly('unpublish', 'args[0]', args[0]) log.silly('unpublish', 'spec', spec) if (!version && !opts.force) { throw Object.assign(new Error( 'Refusing to delete entire project.\n' + 'Run with --force to do this.\n' + unpublish.usage ), { code: 'EUSAGE' }) } if (!spec || path.resolve(spec.name) === npm.localPrefix) { // if there's a package.json in the current folder, then // read the package name and version out of that. const cwdJson = path.join(npm.localPrefix, 'package.json') return readJson(cwdJson).then(data => { log.verbose('unpublish', data) return otplease(opts, opts => { return libunpub(npa.resolve(data.name, data.version), opts.concat(data.publishConfig)) }) }, err => { if (err && err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { throw err } else { UsageError() } }) } else { return otplease(opts, opts => libunpub(spec, opts)) } }).then( ret => { if (!opts.silent && opts.loglevel !== 'silent') { output(`- ${spec.name}${ spec.type === 'version' ? `@${spec.rawSpec}` : '' }`) } cb(null, ret) }, err => err.code === 'EUSAGE' ? cb(err.message) : cb(err) ) } update.js000064400000004245152231567050006377 0ustar00'use strict' module.exports = update const url = require('url') const log = require('npmlog') const Bluebird = require('bluebird') const npm = require('./npm.js') const Installer = require('./install.js').Installer const usage = require('./utils/usage') const outdated = Bluebird.promisify(npm.commands.outdated) update.usage = usage( 'update', 'npm update [-g] [...]' ) update.completion = npm.commands.outdated.completion function update (args, cb) { return update_(args).asCallback(cb) } function update_ (args) { let dryrun = false if (npm.config.get('dry-run')) dryrun = true log.verbose('update', 'computing outdated modules to update') return outdated(args, true).then((rawOutdated) => { const outdated = rawOutdated.map(function (ww) { return { dep: ww[0], depname: ww[1], current: ww[2], wanted: ww[3], latest: ww[4], req: ww[5], what: ww[1] + '@' + ww[3] } }) const wanted = outdated.filter(function (ww) { if (ww.current === ww.wanted && ww.wanted !== ww.latest) { log.verbose( 'outdated', 'not updating', ww.depname, "because it's currently at the maximum version that matches its specified semver range" ) } return ww.current !== ww.wanted }) if (wanted.length === 0) return log.info('outdated', 'updating', wanted) const toInstall = {} wanted.forEach(function (ww) { // use the initial installation method (repo, tar, git) for updating if (url.parse(ww.req).protocol) ww.what = ww.req const where = (ww.dep.parent && ww.dep.parent.path) || ww.dep.path const isTransitive = !(ww.dep.requiredBy || []).some((p) => p.isTop) const key = where + ':' + String(isTransitive) if (!toInstall[key]) toInstall[key] = {where: where, opts: {saveOnlyLock: isTransitive}, what: []} if (toInstall[key].what.indexOf(ww.what) === -1) toInstall[key].what.push(ww.what) }) return Bluebird.each(Object.keys(toInstall), (key) => { const deps = toInstall[key] const inst = new Installer(deps.where, dryrun, deps.what, deps.opts) return inst.run() }) }) } version.js000064400000023455152231567050006606 0ustar00'use strict' const BB = require('bluebird') const assert = require('assert') const chain = require('slide').chain const detectIndent = require('detect-indent') const detectNewline = require('detect-newline') const fs = require('graceful-fs') const readFile = BB.promisify(require('graceful-fs').readFile) const git = require('./utils/git.js') const lifecycle = require('./utils/lifecycle.js') const log = require('npmlog') const npm = require('./npm.js') const output = require('./utils/output.js') const parseJSON = require('./utils/parse-json.js') const path = require('path') const semver = require('semver') const stringifyPackage = require('stringify-package') const writeFileAtomic = require('write-file-atomic') version.usage = 'npm version [ | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=] | from-git]' + '\n(run in package dir)\n' + "'npm -v' or 'npm --version' to print npm version " + '(' + npm.version + ')\n' + "'npm view version' to view a package's " + 'published version\n' + "'npm ls' to inspect current package/dependency versions" // npm version module.exports = version function version (args, silent, cb_) { if (typeof cb_ !== 'function') { cb_ = silent silent = false } if (args.length > 1) return cb_(version.usage) readPackage(function (er, data, indent, newline) { if (!args.length) return dump(data, cb_) if (er) { log.error('version', 'No valid package.json found') return cb_(er) } if (args[0] === 'from-git') { retrieveTagVersion(silent, data, cb_) } else { var newVersion = semver.valid(args[0]) if (!newVersion) newVersion = semver.inc(data.version, args[0], npm.config.get('preid')) if (!newVersion) return cb_(version.usage) persistVersion(newVersion, silent, data, cb_) } }) } function retrieveTagVersion (silent, data, cb_) { chain([ verifyGit, parseLastGitTag ], function (er, results) { if (er) return cb_(er) var localData = { hasGit: true, existingTag: true } var version = results[results.length - 1] persistVersion(version, silent, data, localData, cb_) }) } function parseLastGitTag (cb) { var options = { env: process.env } git.whichAndExec(['describe', '--abbrev=0'], options, function (er, stdout) { if (er) { if (er.message.indexOf('No names found') !== -1) return cb(new Error('No tags found')) return cb(er) } var tag = stdout.trim() var prefix = npm.config.get('tag-version-prefix') // Strip the prefix from the start of the tag: if (tag.indexOf(prefix) === 0) tag = tag.slice(prefix.length) var version = semver.valid(tag) if (!version) return cb(new Error(tag + ' is not a valid version')) cb(null, version) }) } function persistVersion (newVersion, silent, data, localData, cb_) { if (typeof localData === 'function') { cb_ = localData localData = {} } if (!npm.config.get('allow-same-version') && data.version === newVersion) { return cb_(new Error('Version not changed, might want --allow-same-version')) } data.version = newVersion var lifecycleData = Object.create(data) lifecycleData._id = data.name + '@' + newVersion var where = npm.prefix chain([ !localData.hasGit && [checkGit, localData], [lifecycle, lifecycleData, 'preversion', where], [updatePackage, newVersion, silent], [lifecycle, lifecycleData, 'version', where], [commit, localData, newVersion], [lifecycle, lifecycleData, 'postversion', where] ], cb_) } function readPackage (cb) { var packagePath = path.join(npm.localPrefix, 'package.json') fs.readFile(packagePath, 'utf8', function (er, data) { if (er) return cb(new Error(er)) var indent var newline try { indent = detectIndent(data).indent newline = detectNewline(data) data = JSON.parse(data) } catch (e) { er = e data = null } cb(er, data, indent, newline) }) } function updatePackage (newVersion, silent, cb_) { function cb (er) { if (!er && !silent) output('v' + newVersion) cb_(er) } readPackage(function (er, data, indent, newline) { if (er) return cb(new Error(er)) data.version = newVersion write(data, 'package.json', indent, newline, cb) }) } function commit (localData, newVersion, cb) { updateShrinkwrap(newVersion, function (er, hasShrinkwrap, hasLock) { if (er || !localData.hasGit) return cb(er) localData.hasShrinkwrap = hasShrinkwrap localData.hasPackageLock = hasLock _commit(newVersion, localData, cb) }) } const SHRINKWRAP = 'npm-shrinkwrap.json' const PKGLOCK = 'package-lock.json' function readLockfile (name) { return readFile( path.join(npm.localPrefix, name), 'utf8' ).catch({code: 'ENOENT'}, () => null) } function updateShrinkwrap (newVersion, cb) { BB.join( readLockfile(SHRINKWRAP), readLockfile(PKGLOCK), (shrinkwrap, lockfile) => { if (!shrinkwrap && !lockfile) { return cb(null, false, false) } const file = shrinkwrap ? SHRINKWRAP : PKGLOCK let data let indent let newline try { data = parseJSON(shrinkwrap || lockfile) indent = detectIndent(shrinkwrap || lockfile).indent newline = detectNewline(shrinkwrap || lockfile) } catch (err) { log.error('version', `Bad ${file} data.`) return cb(err) } data.version = newVersion write(data, file, indent, newline, (err) => { if (err) { log.error('version', `Failed to update version in ${file}`) return cb(err) } else { return cb(null, !!shrinkwrap, !!lockfile) } }) } ) } function dump (data, cb) { var v = {} if (data && data.name && data.version) v[data.name] = data.version v.npm = npm.version Object.keys(process.versions).sort().forEach(function (k) { v[k] = process.versions[k] }) if (npm.config.get('json')) v = JSON.stringify(v, null, 2) output(v) cb() } function statGitFolder (cb) { fs.stat(path.join(npm.localPrefix, '.git'), cb) } function callGitStatus (cb) { git.whichAndExec( [ 'status', '--porcelain' ], { env: process.env }, cb ) } function cleanStatusLines (stdout) { var lines = stdout.trim().split('\n').filter(function (line) { return line.trim() && !line.match(/^\?\? /) }).map(function (line) { return line.trim() }) return lines } function verifyGit (cb) { function checkStatus (er) { if (er) return cb(er) callGitStatus(checkStdout) } function checkStdout (er, stdout) { if (er) return cb(er) var lines = cleanStatusLines(stdout) if (lines.length > 0) { return cb(new Error( 'Git working directory not clean.\n' + lines.join('\n') )) } cb() } statGitFolder(checkStatus) } function checkGit (localData, cb) { statGitFolder(function (er) { var doGit = !er && npm.config.get('git-tag-version') if (!doGit) { if (er && npm.config.get('git-tag-version')) log.verbose('version', 'error checking for .git', er) log.verbose('version', 'not tagging in git') return cb(null, false) } // check for git callGitStatus(function (er, stdout) { if (er && er.code === 'ENOGIT') { log.warn( 'version', 'This is a Git checkout, but the git command was not found.', 'npm could not create a Git tag for this release!' ) return cb(null, false) } var lines = cleanStatusLines(stdout) if (lines.length && !npm.config.get('force')) { return cb(new Error( 'Git working directory not clean.\n' + lines.join('\n') )) } localData.hasGit = true cb(null, true) }) }) } module.exports.buildCommitArgs = buildCommitArgs function buildCommitArgs (args) { const add = [] args = args || [] if (args[0] === 'commit') args.shift() if (!npm.config.get('commit-hooks')) add.push('-n') if (npm.config.get('allow-same-version')) add.push('--allow-empty') return ['commit', ...add, ...args] } module.exports.buildTagFlags = buildTagFlags function buildTagFlags () { return '-'.concat( npm.config.get('sign-git-tag') ? 's' : '', npm.config.get('allow-same-version') ? 'f' : '', 'm' ) } function _commit (version, localData, cb) { const options = { env: process.env } const message = npm.config.get('message').replace(/%s/g, version) const signCommit = npm.config.get('sign-git-commit') const commitArgs = buildCommitArgs([ 'commit', ...(signCommit ? ['-S', '-m'] : ['-m']), message ]) stagePackageFiles(localData, options).then(() => { return git.exec(commitArgs, options) }).then(() => { if (!localData.existingTag) { return git.exec([ 'tag', npm.config.get('tag-version-prefix') + version, buildTagFlags(), message ], options) } }).nodeify(cb) } function stagePackageFiles (localData, options) { return addLocalFile('package.json', options, false).then(() => { if (localData.hasShrinkwrap) { return addLocalFile('npm-shrinkwrap.json', options, true) } else if (localData.hasPackageLock) { return addLocalFile('package-lock.json', options, true) } }) } function addLocalFile (file, options, ignoreFailure) { const p = git.exec(['add', path.join(npm.localPrefix, file)], options) return ignoreFailure ? p.catch(() => {}) : p } function write (data, file, indent, newline, cb) { assert(data && typeof data === 'object', 'must pass data to version write') assert(typeof file === 'string', 'must pass filename to write to version write') log.verbose('version.write', 'data', data, 'to', file) writeFileAtomic( path.join(npm.localPrefix, file), stringifyPackage(data, indent, newline), cb ) } view.js000064400000036161152231567050006071 0ustar00'use strict' // npm view [pkg [pkg ...]] module.exports = view const BB = require('bluebird') const byteSize = require('byte-size') const color = require('ansicolors') const columns = require('cli-columns') const npmConfig = require('./config/figgy-config.js') const log = require('npmlog') const figgyPudding = require('figgy-pudding') const npa = require('libnpm/parse-arg') const npm = require('./npm.js') const packument = require('libnpm/packument') const path = require('path') const readJson = require('libnpm/read-json') const relativeDate = require('tiny-relative-date') const semver = require('semver') const style = require('ansistyles') const usage = require('./utils/usage') const util = require('util') const validateName = require('validate-npm-package-name') const ViewConfig = figgyPudding({ global: {}, json: {}, tag: {}, unicode: {} }) view.usage = usage( 'view', 'npm view [<@scope>/][@] [[.subfield]...]' ) view.completion = function (opts, cb) { if (opts.conf.argv.remain.length <= 2) { // FIXME: there used to be registry completion here, but it stopped making // sense somewhere around 50,000 packages on the registry return cb() } // have the package, get the fields. const config = ViewConfig(npmConfig()) const tag = config.tag const spec = npa(opts.conf.argv.remain[2]) return packument(spec, config).then(d => { const dv = d.versions[d['dist-tags'][tag]] d.versions = Object.keys(d.versions).sort(semver.compareLoose) return getFields(d).concat(getFields(dv)) }).nodeify(cb) function getFields (d, f, pref) { f = f || [] if (!d) return f pref = pref || [] Object.keys(d).forEach(function (k) { if (k.charAt(0) === '_' || k.indexOf('.') !== -1) return const p = pref.concat(k).join('.') f.push(p) if (Array.isArray(d[k])) { d[k].forEach(function (val, i) { const pi = p + '[' + i + ']' if (val && typeof val === 'object') getFields(val, f, [p]) else f.push(pi) }) return } if (typeof d[k] === 'object') getFields(d[k], f, [p]) }) return f } } function view (args, silent, cb) { if (typeof cb !== 'function') { cb = silent silent = false } if (!args.length) args = ['.'] const opts = ViewConfig(npmConfig()) const pkg = args.shift() let nv if (/^[.]@/.test(pkg)) { nv = npa.resolve(null, pkg.slice(2)) } else { nv = npa(pkg) } const name = nv.name const local = (name === '.' || !name) if (opts.global && local) { return cb(new Error('Cannot use view command in global mode.')) } if (local) { const dir = npm.prefix BB.resolve(readJson(path.resolve(dir, 'package.json'))).nodeify((er, d) => { d = d || {} if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er) if (!d.name) return cb(new Error('Invalid package.json')) const p = d.name nv = npa(p) if (pkg && ~pkg.indexOf('@')) { nv.rawSpec = pkg.split('@')[pkg.indexOf('@')] } fetchAndRead(nv, args, silent, opts, cb) }) } else { fetchAndRead(nv, args, silent, opts, cb) } } function fetchAndRead (nv, args, silent, opts, cb) { // get the data about this package let version = nv.rawSpec || npm.config.get('tag') return packument(nv, opts.concat({ fullMetadata: true, 'prefer-online': true })).catch(err => { // TODO - this should probably go into pacote, but the tests expect it. if (err.code === 'E404') { err.message = `'${nv.name}' is not in the npm registry.` const validated = validateName(nv.name) if (!validated.validForNewPackages) { err.message += '\n' err.message += (validated.errors || []).join('\n') err.message += (validated.warnings || []).join('\n') } else { err.message += '\nYou should bug the author to publish it' err.message += '\n(or use the name yourself!)' err.message += '\n' err.message += '\nNote that you can also install from a' err.message += '\ntarball, folder, http url, or git url.' } } throw err }).then(data => { if (data['dist-tags'] && data['dist-tags'][version]) { version = data['dist-tags'][version] } if (data.time && data.time.unpublished) { const u = data.time.unpublished let er = new Error('Unpublished by ' + u.name + ' on ' + u.time) er.statusCode = 404 er.code = 'E404' er.pkgid = data._id throw er } const results = [] let error = null const versions = data.versions || {} data.versions = Object.keys(versions).sort(semver.compareLoose) if (!args.length) args = [''] // remove readme unless we asked for it if (args.indexOf('readme') === -1) { delete data.readme } Object.keys(versions).forEach(function (v) { if (semver.satisfies(v, version, true)) { args.forEach(function (args) { // remove readme unless we asked for it if (args.indexOf('readme') !== -1) { delete versions[v].readme } results.push(showFields(data, versions[v], args)) }) } }) let retval = results.reduce(reducer, {}) if (args.length === 1 && args[0] === '') { retval = cleanBlanks(retval) log.silly('view', retval) } if (silent) { return retval } else if (error) { throw error } else if ( !opts.json && args.length === 1 && args[0] === '' ) { data.version = version return BB.all( results.map((v) => prettyView(data, v[Object.keys(v)[0]][''], opts)) ).then(() => retval) } else { return BB.fromNode(cb => { printData(retval, data._id, opts, cb) }).then(() => retval) } }).nodeify(cb) } function prettyView (packument, manifest, opts) { // More modern, pretty printing of default view const unicode = opts.unicode return BB.try(() => { if (!manifest) { log.error( 'view', 'No matching versions.\n' + 'To see a list of versions, run:\n' + `> npm view ${packument.name} versions` ) return } const tags = [] Object.keys(packument['dist-tags']).forEach((t) => { const version = packument['dist-tags'][t] tags.push(`${style.bright(color.green(t))}: ${version}`) }) const unpackedSize = manifest.dist.unpackedSize && byteSize(manifest.dist.unpackedSize) const licenseField = manifest.license || manifest.licence || 'Proprietary' const info = { name: color.green(manifest.name), version: color.green(manifest.version), bins: Object.keys(manifest.bin || {}).map(color.yellow), versions: color.yellow(packument.versions.length + ''), description: manifest.description, deprecated: manifest.deprecated, keywords: (packument.keywords || []).map(color.yellow), license: typeof licenseField === 'string' ? licenseField : (licenseField.type || 'Proprietary'), deps: Object.keys(manifest.dependencies || {}).map((dep) => { return `${color.yellow(dep)}: ${manifest.dependencies[dep]}` }), publisher: manifest._npmUser && unparsePerson({ name: color.yellow(manifest._npmUser.name), email: color.cyan(manifest._npmUser.email) }), modified: packument.time ? color.yellow(relativeDate(packument.time[packument.version])) : undefined, maintainers: (packument.maintainers || []).map((u) => unparsePerson({ name: color.yellow(u.name), email: color.cyan(u.email) })), repo: ( manifest.bugs && (manifest.bugs.url || manifest.bugs) ) || ( manifest.repository && (manifest.repository.url || manifest.repository) ), site: ( manifest.homepage && (manifest.homepage.url || manifest.homepage) ), stars: color.yellow('' + packument.users ? Object.keys(packument.users || {}).length : 0), tags, tarball: color.cyan(manifest.dist.tarball), shasum: color.yellow(manifest.dist.shasum), integrity: manifest.dist.integrity && color.yellow(manifest.dist.integrity), fileCount: manifest.dist.fileCount && color.yellow(manifest.dist.fileCount), unpackedSize: unpackedSize && color.yellow(unpackedSize.value) + ' ' + unpackedSize.unit } if (info.license.toLowerCase().trim() === 'proprietary') { info.license = style.bright(color.red(info.license)) } else { info.license = color.green(info.license) } console.log('') console.log( style.underline(style.bright(`${info.name}@${info.version}`)) + ' | ' + info.license + ' | deps: ' + (info.deps.length ? color.cyan(info.deps.length) : color.green('none')) + ' | versions: ' + info.versions ) info.description && console.log(info.description) if (info.repo || info.site) { info.site && console.log(color.cyan(info.site)) } const warningSign = unicode ? ' ⚠️ ' : '!!' info.deprecated && console.log( `\n${style.bright(color.red('DEPRECATED'))}${ warningSign } - ${info.deprecated}` ) if (info.keywords.length) { console.log('') console.log('keywords:', info.keywords.join(', ')) } if (info.bins.length) { console.log('') console.log('bin:', info.bins.join(', ')) } console.log('') console.log('dist') console.log('.tarball:', info.tarball) console.log('.shasum:', info.shasum) info.integrity && console.log('.integrity:', info.integrity) info.unpackedSize && console.log('.unpackedSize:', info.unpackedSize) const maxDeps = 24 if (info.deps.length) { console.log('') console.log('dependencies:') console.log(columns(info.deps.slice(0, maxDeps), {padding: 1})) if (info.deps.length > maxDeps) { console.log(`(...and ${info.deps.length - maxDeps} more.)`) } } if (info.maintainers && info.maintainers.length) { console.log('') console.log('maintainers:') info.maintainers.forEach((u) => console.log('-', u)) } console.log('') console.log('dist-tags:') console.log(columns(info.tags)) if (info.publisher || info.modified) { let publishInfo = 'published' if (info.modified) { publishInfo += ` ${info.modified}` } if (info.publisher) { publishInfo += ` by ${info.publisher}` } console.log('') console.log(publishInfo) } }) } function cleanBlanks (obj) { const clean = {} Object.keys(obj).forEach(function (version) { clean[version] = obj[version][''] }) return clean } function reducer (l, r) { if (r) { Object.keys(r).forEach(function (v) { l[v] = l[v] || {} Object.keys(r[v]).forEach(function (t) { l[v][t] = r[v][t] }) }) } return l } // return whatever was printed function showFields (data, version, fields) { const o = {} ;[data, version].forEach(function (s) { Object.keys(s).forEach(function (k) { o[k] = s[k] }) }) return search(o, fields.split('.'), version.version, fields) } function search (data, fields, version, title) { let field const tail = fields while (!field && fields.length) field = tail.shift() fields = [field].concat(tail) let o if (!field && !tail.length) { o = {} o[version] = {} o[version][title] = data return o } let index = field.match(/(.+)\[([^\]]+)\]$/) if (index) { field = index[1] index = index[2] if (data.field && data.field.hasOwnProperty(index)) { return search(data[field][index], tail, version, title) } else { field = field + '[' + index + ']' } } if (Array.isArray(data)) { if (data.length === 1) { return search(data[0], fields, version, title) } let results = [] data.forEach(function (data, i) { const tl = title.length const newt = title.substr(0, tl - fields.join('.').length - 1) + '[' + i + ']' + [''].concat(fields).join('.') results.push(search(data, fields.slice(), version, newt)) }) results = results.reduce(reducer, {}) return results } if (!data.hasOwnProperty(field)) return undefined data = data[field] if (tail.length) { if (typeof data === 'object') { // there are more fields to deal with. return search(data, tail, version, title) } else { return new Error('Not an object: ' + data) } } o = {} o[version] = {} o[version][title] = data return o } function printData (data, name, opts, cb) { const versions = Object.keys(data) let msg = '' let msgJson = [] const includeVersions = versions.length > 1 let includeFields versions.forEach(function (v) { const fields = Object.keys(data[v]) includeFields = includeFields || (fields.length > 1) if (opts.json) msgJson.push({}) fields.forEach(function (f) { let d = cleanup(data[v][f]) if (fields.length === 1 && opts.json) { msgJson[msgJson.length - 1][f] = d } if (includeVersions || includeFields || typeof d !== 'string') { if (opts.json) { msgJson[msgJson.length - 1][f] = d } else { d = util.inspect(d, { showHidden: false, depth: 5, colors: npm.color, maxArrayLength: null }) } } else if (typeof d === 'string' && opts.json) { d = JSON.stringify(d) } if (!opts.json) { if (f && includeFields) f += ' = ' if (d.indexOf('\n') !== -1) d = ' \n' + d msg += (includeVersions ? name + '@' + v + ' ' : '') + (includeFields ? f : '') + d + '\n' } }) }) if (opts.json) { if (msgJson.length && Object.keys(msgJson[0]).length === 1) { const k = Object.keys(msgJson[0])[0] msgJson = msgJson.map(function (m) { return m[k] }) } if (msgJson.length === 1) { msg = JSON.stringify(msgJson[0], null, 2) + '\n' } else if (msgJson.length > 1) { msg = JSON.stringify(msgJson, null, 2) + '\n' } } // preserve output symmetry by adding a whitespace-only line at the end if // there's one at the beginning if (/^\s*\n/.test(msg)) msg += '\n' // disable the progress bar entirely, as we can't meaningfully update it if // we may have partial lines printed. log.disableProgress() // print directly to stdout to not unnecessarily add blank lines process.stdout.write(msg, () => cb(null, data)) } function cleanup (data) { if (Array.isArray(data)) { return data.map(cleanup) } if (!data || typeof data !== 'object') return data if (typeof data.versions === 'object' && data.versions && !Array.isArray(data.versions)) { data.versions = Object.keys(data.versions || {}) } let keys = Object.keys(data) keys.forEach(function (d) { if (d.charAt(0) === '_') delete data[d] else if (typeof data[d] === 'object') data[d] = cleanup(data[d]) }) keys = Object.keys(data) if (keys.length <= 3 && data.name && (keys.length === 1 || (keys.length === 3 && data.email && data.url) || (keys.length === 2 && (data.email || data.url)))) { data = unparsePerson(data) } return data } function unparsePerson (d) { if (typeof d === 'string') return d return d.name + (d.email ? ' <' + d.email + '>' : '') + (d.url ? ' (' + d.url + ')' : '') } visnup.js000064400000010010152231567050006424 0ustar00module.exports = visnup var npm = require('./npm.js') var output = require('./utils/output.js') var handsomeFace = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 237, 236, 236, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 235, 236, 235, 233, 237, 235, 233, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 235, 233, 232, 235, 235, 234, 233, 236, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 237, 235, 232, 232, 234, 233, 233, 232, 232, 233, 232, 232, 235, 232, 233, 234, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 232, 232, 232, 239, 238, 235, 233, 232, 232, 232, 232, 232, 232, 232, 233, 235, 232, 233, 233, 232, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 234, 234, 232, 233, 234, 233, 234, 235, 233, 235, 60, 238, 238, 234, 234, 233, 234, 233, 238, 251, 246, 233, 233, 232, 0, 0, 0, 0, 0, 0], [0, 0, 233, 233, 233, 232, 232, 239, 249, 251, 252, 231, 231, 188, 250, 254, 59, 60, 255, 231, 231, 231, 252, 235, 239, 235, 232, 233, 0, 0, 0, 0, 0, 0], [0, 0, 232, 233, 232, 232, 232, 248, 231, 231, 231, 231, 231, 231, 231, 254, 238, 254, 231, 231, 231, 231, 231, 252, 233, 235, 237, 233, 234, 0, 0, 0, 0, 0], [0, 0, 233, 232, 232, 232, 248, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 251, 233, 233, 233, 236, 233, 0, 0, 0, 0], [232, 233, 233, 232, 232, 246, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 249, 233, 234, 234, 0, 0, 0, 0], [232, 232, 232, 232, 233, 249, 231, 255, 255, 255, 255, 254, 109, 60, 239, 237, 238, 237, 235, 235, 235, 235, 236, 235, 235, 235, 234, 232, 232, 232, 232, 232, 233, 0], [0, 232, 232, 233, 233, 233, 233, 233, 233, 233, 233, 233, 235, 236, 238, 238, 235, 188, 254, 254, 145, 236, 252, 254, 254, 254, 254, 249, 236, 235, 232, 232, 233, 0], [0, 0, 233, 237, 249, 239, 233, 252, 231, 231, 231, 231, 231, 231, 254, 235, 235, 254, 231, 231, 251, 235, 237, 231, 231, 231, 231, 7, 237, 235, 232, 233, 233, 0], [0, 0, 0, 0, 233, 248, 239, 233, 231, 231, 231, 231, 254, 233, 233, 235, 254, 255, 231, 254, 237, 236, 254, 239, 235, 235, 233, 233, 232, 232, 233, 232, 0, 0], [0, 0, 0, 232, 233, 246, 255, 255, 236, 236, 236, 236, 236, 255, 231, 231, 231, 231, 231, 231, 252, 234, 248, 231, 231, 231, 231, 248, 232, 232, 232, 0, 0, 0], [0, 0, 0, 0, 235, 237, 7, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 255, 238, 235, 7, 231, 231, 231, 246, 232, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 235, 103, 188, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 252, 232, 238, 231, 231, 255, 244, 232, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 235, 236, 103, 146, 253, 255, 231, 231, 231, 231, 231, 253, 251, 250, 250, 250, 246, 232, 235, 152, 255, 146, 66, 233, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 233, 103, 146, 146, 146, 146, 254, 231, 231, 231, 109, 103, 146, 255, 188, 239, 240, 103, 255, 253, 103, 238, 234, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 232, 235, 109, 146, 146, 146, 146, 146, 252, 152, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 103, 235, 233, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 235, 235, 103, 146, 146, 146, 146, 146, 146, 188, 188, 188, 188, 188, 188, 152, 146, 146, 146, 66, 235, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 233, 235, 66, 146, 146, 146, 146, 152, 255, 146, 240, 239, 241, 109, 146, 146, 146, 103, 233, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 237, 109, 146, 146, 146, 146, 146, 254, 231, 231, 188, 146, 146, 146, 103, 233, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 237, 60, 103, 146, 146, 146, 146, 146, 103, 66, 60, 235, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 233, 233, 236, 235, 237, 235, 237, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ] function visnup (args, cb) { handsomeFace.forEach(function (line) { output(line.map(function (ch) { return '\u001b[' + (ch ? '48;5;' + ch : ch) + 'm' }).join(' ')) }) var c = args.shift() if (c) npm.commands[c](args, cb) else cb() } xmas.js000064400000003177152231567050006070 0ustar00// happy xmas var log = require('npmlog') module.exports = function (args, cb) { var s = process.platform === 'win32' ? ' *' : ' \u2605' var f = '\uFF0F' var b = '\uFF3C' var x = process.platform === 'win32' ? ' ' : '' var o = [ '\u0069', '\u0020', '\u0020', '\u0020', '\u0020', '\u0020', '\u0020', '\u0020', '\u0020', '\u0020', '\u0020', '\u0020', '\u0020', '\u2E1B', '\u2042', '\u2E2E', '&', '@', '\uFF61' ] var oc = [33, 34, 35, 36, 37] var l = '\u005e' function w (s) { process.stderr.write(s) } w('\n') ;(function T (H) { for (var i = 0; i < H; i++) w(' ') w(x + '\u001b[33m' + s + '\n') var M = H * 2 - 1 for (var L = 1; L <= H; L++) { var O = L * 2 - 2 var S = (M - O) / 2 for (i = 0; i < S; i++) w(' ') w(x + '\u001b[21m') w(x + '\u001b[32m' + f) for (i = 0; i < O; i++) { w( '\u001b[' + oc[Math.floor(Math.random() * oc.length)] + 'm' + o[Math.floor(Math.random() * o.length)] ) } w(x + '\u001b[32m' + b + '\n') w(x + '\u001b[0m') } w(' ') for (i = 1; i < H; i++) w('\u001b[32m' + l) w('| ' + x + ' |') for (i = 1; i < H; i++) w('\u001b[32m' + l) if (H > 10) { w('\n ') for (i = 1; i < H; i++) w(' ') w('| ' + x + ' |') for (i = 1; i < H; i++) w(' ') } })(20) w('\n\n') log.heading = '' log.addLevel('npm', 100000, log.headingStyle) log.npm('loves you', 'Happy Xmas, JavaScripters!') cb() } var dg = false Object.defineProperty(module.exports, 'usage', {get: function () { if (dg) module.exports([], function () {}) dg = true return ' ' }}) utils/completion/file-completion.js000064400000001225152231567050013507 0ustar00module.exports = fileCompletion var mkdir = require('mkdirp') var glob = require('glob') function fileCompletion (root, req, depth, cb) { if (typeof cb !== 'function') { cb = depth depth = Infinity } mkdir(root, function (er) { if (er) return cb(er) // can be either exactly the req, or a descendent var pattern = root + '/{' + req + ',' + req + '/**/*}' var opts = { mark: true, dot: true, maxDepth: depth } glob(pattern, opts, function (er, files) { if (er) return cb(er) return cb(null, (files || []).map(function (f) { return f.substr(root.length + 1).replace(/^\/|\/$/g, '') })) }) }) } utils/completion/installed-deep.js000064400000002166152231567050013320 0ustar00module.exports = installedDeep var npm = require('../../npm.js') var readInstalled = require('read-installed') function installedDeep (opts, cb) { var local var global var depth = npm.config.get('depth') var opt = { depth: depth, dev: true } if (npm.config.get('global')) { local = [] next() } else { readInstalled(npm.prefix, opt, function (er, data) { local = getNames(data || {}) next() }) } readInstalled(npm.config.get('prefix'), opt, function (er, data) { global = getNames(data || {}) next() }) function getNames_ (d, n) { if (d.realName && n) { if (n[d.realName]) return n n[d.realName] = true } if (!n) n = {} Object.keys(d.dependencies || {}).forEach(function (dep) { getNames_(d.dependencies[dep], n) }) return n } function getNames (d) { return Object.keys(getNames_(d)) } function next () { if (!local || !global) return if (!npm.config.get('global')) { global = global.map(function (g) { return [g, '-g'] }) } var names = local.concat(global) return cb(null, names) } } utils/completion/installed-shallow.js000064400000003620152231567050014050 0ustar00 module.exports = installedShallow var npm = require('../../npm.js') var fs = require('graceful-fs') var path = require('path') var readJson = require('read-package-json') var asyncMap = require('slide').asyncMap function installedShallow (opts, filter, cb) { if (typeof cb !== 'function') { cb = filter filter = null } var conf = opts.conf var args = conf.argv.remain if (args.length > 3) return cb() var local var global var localDir = npm.dir var globalDir = npm.globalDir if (npm.config.get('global')) { local = [] next() } else { fs.readdir(localDir, function (er, pkgs) { local = (pkgs || []).filter(function (p) { return p.charAt(0) !== '.' }) next() }) } fs.readdir(globalDir, function (er, pkgs) { global = (pkgs || []).filter(function (p) { return p.charAt(0) !== '.' }) next() }) function next () { if (!local || !global) return filterInstalled(local, global, filter, cb) } } function filterInstalled (local, global, filter, cb) { var fl var fg if (!filter) { fl = local fg = global return next() } asyncMap(local, function (p, cb) { readJson(path.join(npm.dir, p, 'package.json'), function (er, d) { if (!d || !filter(d)) return cb(null, []) return cb(null, d.name) }) }, function (er, local) { fl = local || [] next() }) var globalDir = npm.globalDir asyncMap(global, function (p, cb) { readJson(path.join(globalDir, p, 'package.json'), function (er, d) { if (!d || !filter(d)) return cb(null, []) return cb(null, d.name) }) }, function (er, global) { fg = global || [] next() }) function next () { if (!fg || !fl) return if (!npm.config.get('global')) { fg = fg.map(function (g) { return [g, '-g'] }) } console.error('filtered', fl, fg) return cb(null, fl.concat(fg)) } } utils/move.js000064400000000442152231567050007216 0ustar00'use strict' module.exports = wrappedMove const fs = require('graceful-fs') const move = require('move-concurrently') const Bluebird = require('bluebird') const options = {fs: fs, Promise: Bluebird, maxConcurrency: 4} function wrappedMove (from, to) { return move(from, to, options) } utils/no-progress-while-running.js000064400000001035152231567050013311 0ustar00'use strict' var log = require('npmlog') var progressEnabled var running = 0 var startRunning = exports.startRunning = function () { if (progressEnabled == null) progressEnabled = log.progressEnabled if (progressEnabled) log.disableProgress() ++running } var stopRunning = exports.stopRunning = function () { --running if (progressEnabled && running === 0) log.enableProgress() } exports.tillDone = function noProgressTillDone (cb) { startRunning() return function () { stopRunning() cb.apply(this, arguments) } } utils/open-url.js000064400000001463152231567050010015 0ustar00'use strict' const npm = require('../npm.js') const output = require('./output.js') const opener = require('opener') // attempt to open URL in web-browser, print address otherwise: module.exports = function open (url, errMsg, cb, browser = npm.config.get('browser')) { function printAlternateMsg () { const json = npm.config.get('json') const alternateMsg = json ? JSON.stringify({ title: errMsg, url }, null, 2) : `${errMsg}:\n\n${url}` output(alternateMsg) } const skipBrowser = process.argv.indexOf('--no-browser') > -1 if (skipBrowser) { printAlternateMsg() return cb() } opener(url, { command: browser }, (er) => { if (er && er.code === 'ENOENT') { printAlternateMsg() return cb() } else { return cb(er) } }) } utils/otplease.js000064400000001321152231567050010061 0ustar00'use strict' const BB = require('bluebird') const optCheck = require('figgy-pudding')({ prompt: {default: 'This operation requires a one-time password.\nEnter OTP:'}, otp: {} }) const readUserInfo = require('./read-user-info.js') module.exports = otplease function otplease (opts, fn) { opts = opts.concat ? opts : optCheck(opts) return BB.try(() => { return fn(opts) }).catch(err => { if (err.code !== 'EOTP' && !(err.code === 'E401' && /one-time pass/.test(err.body))) { throw err } else if (!process.stdin.isTTY || !process.stdout.isTTY) { throw err } else { return readUserInfo.otp( optCheck(opts).prompt ).then(otp => fn(opts.concat({otp}))) } }) } utils/output.js000064400000000322152231567050007605 0ustar00'use strict' var log = require('npmlog') // output to stdout in a progress bar compatible way module.exports = function () { log.clearProgress() console.log.apply(console, arguments) log.showProgress() } utils/package-id.js000064400000000617152231567050010241 0ustar00'use strict' var moduleName = require('./module-name.js') module.exports = function (tree) { var pkg = tree.package || tree // FIXME: Excluding the '@' here is cleaning up after the mess that // read-package-json makes. =( if (pkg._id && pkg._id !== '@') return pkg._id var name = moduleName(tree) if (pkg.version) { return name + '@' + pkg.version } else { return name } } utils/parse-json.js000064400000001215152231567050010330 0ustar00'use strict' var parseJsonWithErrors = require('json-parse-better-errors') var parseJSON = module.exports = function (content) { return parseJsonWithErrors(stripBOM(content)) } parseJSON.noExceptions = function (content) { try { return parseJSON(content) } catch (ex) { } } // from read-package-json function stripBOM (content) { content = content.toString() // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) // because the buffer-to-string conversion in `fs.readFileSync()` // translates it to FEFF, the UTF-16 BOM. if (content.charCodeAt(0) === 0xFEFF) { content = content.slice(1) } return content } utils/perf.js000064400000001044152231567050007203 0ustar00'use strict' var log = require('npmlog') var EventEmitter = require('events').EventEmitter var perf = new EventEmitter() module.exports = perf var timings = {} process.on('time', time) process.on('timeEnd', timeEnd) perf.on('time', time) perf.on('timeEnd', timeEnd) function time (name) { timings[name] = Date.now() } function timeEnd (name) { if (name in timings) { perf.emit('timing', name, Date.now() - timings[name]) delete timings[name] } else { log.silly('timing', "Tried to end timer that doesn't exist:", name) } } utils/pick-manifest-from-registry-metadata.js000064400000001577152231567050015401 0ustar00'use strict' module.exports = pickManifestFromRegistryMetadata var log = require('npmlog') var semver = require('semver') function pickManifestFromRegistryMetadata (spec, tag, versions, metadata) { log.silly('pickManifestFromRegistryMetadata', 'spec', spec, 'tag', tag, 'versions', versions) // if the tagged version satisfies, then use that. var tagged = metadata['dist-tags'][tag] if (tagged && metadata.versions[tagged] && semver.satisfies(tagged, spec, true)) { return {resolvedTo: tag, manifest: metadata.versions[tagged]} } // find the max satisfying version. var ms = semver.maxSatisfying(versions, spec, true) if (ms) { return {resolvedTo: ms, manifest: metadata.versions[ms]} } else if (spec === '*' && versions.length && tagged && metadata.versions[tagged]) { return {resolvedTo: tag, manifest: metadata.versions[tagged]} } else { } } utils/pulse-till-done.js000064400000001417152231567050011270 0ustar00'use strict' const validate = require('aproba') const log = require('npmlog') const Bluebird = require('bluebird') let pulsers = 0 let pulse function pulseStart (prefix) { if (++pulsers > 1) return pulse = setInterval(function () { log.gauge.pulse(prefix) }, 150) } function pulseStop () { if (--pulsers > 0) return clearInterval(pulse) } module.exports = function (prefix, cb) { validate('SF', [prefix, cb]) if (!prefix) prefix = 'network' pulseStart(prefix) return function () { pulseStop() cb.apply(null, arguments) } } module.exports.withPromise = pulseWhile function pulseWhile (prefix, promise) { if (!promise) { promise = prefix prefix = '' } pulseStart(prefix) return Bluebird.resolve(promise).finally(() => pulseStop()) } utils/read-local-package.js000064400000000511152231567050011641 0ustar00exports = module.exports = readLocalPkg var npm = require('../npm.js') var readJson = require('read-package-json') function readLocalPkg (cb) { if (npm.config.get('global')) return cb() var path = require('path') readJson(path.resolve(npm.prefix, 'package.json'), function (er, d) { return cb(er, d && d.name) }) } utils/read-user-info.js000064400000004120152231567050011065 0ustar00'use strict' const Bluebird = require('bluebird') const readAsync = Bluebird.promisify(require('read')) const userValidate = require('npm-user-validate') const log = require('npmlog') exports.otp = readOTP exports.password = readPassword exports.username = readUsername exports.email = readEmail function read (opts) { return Bluebird.try(() => { log.clearProgress() return readAsync(opts) }).finally(() => { log.showProgress() }) } function readOTP (msg, otp, isRetry) { if (!msg) { msg = [ 'This command requires a one-time password (OTP) from your authenticator app.', 'Enter one below. You can also pass one on the command line by appending --otp=123456.', 'For more information, see:', 'https://docs.npmjs.com/getting-started/using-two-factor-authentication', 'Enter OTP: ' ].join('\n') } if (isRetry && otp && /^[\d ]+$|^[A-Fa-f0-9]{64,64}$/.test(otp)) return otp.replace(/\s+/g, '') return read({prompt: msg, default: otp || ''}) .then((otp) => readOTP(msg, otp, true)) } function readPassword (msg, password, isRetry) { if (!msg) msg = 'npm password: ' if (isRetry && password) return password return read({prompt: msg, silent: true, default: password || ''}) .then((password) => readPassword(msg, password, true)) } function readUsername (msg, username, opts, isRetry) { if (!msg) msg = 'npm username: ' if (isRetry && username) { const error = userValidate.username(username) if (error) { opts.log && opts.log.warn(error.message) } else { return Promise.resolve(username.trim()) } } return read({prompt: msg, default: username || ''}) .then((username) => readUsername(msg, username, opts, true)) } function readEmail (msg, email, opts, isRetry) { if (!msg) msg = 'email (this IS public): ' if (isRetry && email) { const error = userValidate.email(email) if (error) { opts.log && opts.log.warn(error.message) } else { return email.trim() } } return read({prompt: msg, default: email || ''}) .then((username) => readEmail(msg, username, opts, true)) } utils/replace-info.js000064400000001054152231567050010614 0ustar00const URL = require('url').URL // replaces auth info in an array // of arguments or in a strings function replaceInfo (arg) { const isArray = Array.isArray(arg) const isString = typeof arg === 'string' if (!isArray && !isString) return arg const args = isString ? arg.split(' ') : arg const info = args.map(arg => { try { const url = new URL(arg) return url.password === '' ? arg : arg.replace(url.password, '***') } catch (e) { return arg } }) return isString ? info.join(' ') : info } module.exports = replaceInfo utils/save-stack.js000064400000000535152231567050010314 0ustar00'use strict' var inherits = require('inherits') module.exports = SaveStack function SaveStack (fn) { Error.call(this) Error.captureStackTrace(this, fn || SaveStack) } inherits(SaveStack, Error) SaveStack.prototype.completeWith = function (er) { this['__' + 'proto' + '__'] = er this.stack = this.stack + '\n\n' + er.stack return this } utils/spawn.js000064400000002602152231567050007400 0ustar00module.exports = spawn var _spawn = require('child_process').spawn var EventEmitter = require('events').EventEmitter var npwr = require('./no-progress-while-running.js') function willCmdOutput (stdio) { if (stdio === 'inherit') return true if (!Array.isArray(stdio)) return false for (var fh = 1; fh <= 2; ++fh) { if (stdio[fh] === 'inherit') return true if (stdio[fh] === 1 || stdio[fh] === 2) return true } return false } function spawn (cmd, args, options) { var cmdWillOutput = willCmdOutput(options && options.stdio) if (cmdWillOutput) npwr.startRunning() var raw = _spawn(cmd, args, options) var cooked = new EventEmitter() raw.on('error', function (er) { if (cmdWillOutput) npwr.stopRunning() er.file = cmd cooked.emit('error', er) }).on('close', function (code, signal) { if (cmdWillOutput) npwr.stopRunning() // Create ENOENT error because Node.js v0.8 will not emit // an `error` event if the command could not be found. if (code === 127) { var er = new Error('spawn ENOENT') er.code = 'ENOENT' er.errno = 'ENOENT' er.syscall = 'spawn' er.file = cmd cooked.emit('error', er) } else { cooked.emit('close', code, signal) } }) cooked.stdin = raw.stdin cooked.stdout = raw.stdout cooked.stderr = raw.stderr cooked.kill = function (sig) { return raw.kill(sig) } return cooked } utils/temp-filename.js000064400000000255152231567050010775 0ustar00'use strict' var uniqueFilename = require('unique-filename') var npm = require('../npm.js') module.exports = function (prefix) { return uniqueFilename(npm.tmp, prefix) } utils/umask.js000064400000000527152231567050007374 0ustar00var umask = require('umask') var npmlog = require('npmlog') var _fromString = umask.fromString module.exports = umask // fromString with logging callback umask.fromString = function (val) { _fromString(val, function (err, result) { if (err) { npmlog.warn('invalid umask', err.message) } val = result }) return val } utils/unix-format-path.js000064400000000125152231567050011451 0ustar00'use strict' module.exports = function (path) { return path.replace(/\\/g, '/') } utils/unsupported.js000064400000002456152231567050010647 0ustar00'use strict' var semver = require('semver') var supported = require('../../package.json').engines.node var knownBroken = '<6.2.0 || 9 <9.3.0' var checkVersion = exports.checkVersion = function (version) { var versionNoPrerelease = version.replace(/-.*$/, '') return { version: versionNoPrerelease, broken: semver.satisfies(versionNoPrerelease, knownBroken), unsupported: !semver.satisfies(versionNoPrerelease, supported) } } exports.checkForBrokenNode = function () { var nodejs = checkVersion(process.version) if (nodejs.broken) { console.error('ERROR: npm is known not to run on Node.js ' + process.version) console.error("You'll need to upgrade to a newer Node.js version in order to use this") console.error('version of npm. You can find the latest version at https://nodejs.org/') process.exit(1) } } exports.checkForUnsupportedNode = function () { var nodejs = checkVersion(process.version) if (nodejs.unsupported) { var log = require('npmlog') log.warn('npm', 'npm does not support Node.js ' + process.version) log.warn('npm', 'You should probably upgrade to a newer version of node as we') log.warn('npm', "can't make any promises that npm will work with this version.") log.warn('npm', 'You can find the latest version at https://nodejs.org/') } } utils/usage.js000064400000001100152231567050007344 0ustar00'use strict' var aliases = require('../config/cmd-list').aliases module.exports = function usage (cmd, txt, opt) { var post = Object.keys(aliases).reduce(function (p, c) { var val = aliases[c] if (val !== cmd) return p return p.concat(c) }, []) if (opt || post.length > 0) txt += '\n\n' if (post.length === 1) { txt += 'alias: ' txt += post.join(', ') } else if (post.length > 1) { txt += 'aliases: ' txt += post.join(', ') } if (opt) { if (post.length > 0) txt += '\n' txt += 'common options: ' + opt } return txt } utils/warn-deprecated.js000064400000001054152231567050011315 0ustar00module.exports = warnDeprecated var log = require('npmlog') var deprecations = {} function warnDeprecated (type) { return function warn (messages, instance) { if (!instance) { if (!deprecations[type]) { deprecations[type] = {} messages.forEach(function (m) { log.warn(type, m) }) } } else { if (!deprecations[type]) deprecations[type] = {} if (!deprecations[type][instance]) { deprecations[type][instance] = true messages.forEach(function (m) { log.warn(type, m) }) } } } } utils/ansi-trim.js000064400000000323152231567050010151 0ustar00function ansiTrim (str) { var r = new RegExp('\x1b(?:\\[(?:\\d+[ABCDEFGJKSTm]|\\d+;\\d+[Hfm]|' + '\\d+;\\d+;\\d+m|6n|s|u|\\?25[lh])|\\w)', 'g') return str.replace(r, '') } module.exports = ansiTrim utils/cache-file.js000064400000003321152231567050010227 0ustar00// XXX use infer-owner or gentle-fs.mkdir here const npm = require('../npm.js') const path = require('path') const chownr = require('chownr') const writeFileAtomic = require('write-file-atomic') const mkdirp = require('mkdirp') const fs = require('graceful-fs') let cache = null let cacheUid = null let cacheGid = null let needChown = typeof process.getuid === 'function' const getCacheOwner = () => { let st try { st = fs.lstatSync(cache) } catch (er) { if (er.code !== 'ENOENT') { throw er } st = fs.lstatSync(path.dirname(cache)) } cacheUid = st.uid cacheGid = st.gid needChown = st.uid !== process.getuid() || st.gid !== process.getgid() } const writeOrAppend = (method, file, data) => { if (!cache) { cache = npm.config.get('cache') } // redundant if already absolute, but prevents non-absolute files // from being written as if they're part of the cache. file = path.resolve(cache, file) if (cacheUid === null && needChown) { getCacheOwner() } const dir = path.dirname(file) const firstMade = mkdirp.sync(dir) if (!needChown) { return method(file, data) } let methodThrew = true try { method(file, data) methodThrew = false } finally { // always try to leave it in the right ownership state, even on failure // let the method error fail it instead of the chownr error, though if (!methodThrew) { chownr.sync(firstMade || file, cacheUid, cacheGid) } else { try { chownr.sync(firstMade || file, cacheUid, cacheGid) } catch (_) {} } } } exports.append = (file, data) => writeOrAppend(fs.appendFileSync, file, data) exports.write = (file, data) => writeOrAppend(writeFileAtomic.sync, file, data) utils/child-path.js000064400000000442152231567050010265 0ustar00'use strict' var path = require('path') var validate = require('aproba') var moduleName = require('../utils/module-name.js') module.exports = childPath function childPath (parentPath, child) { validate('SO', arguments) return path.join(parentPath, 'node_modules', moduleName(child)) } utils/completion.sh000064400000003365152231567050010426 0ustar00#!/bin/bash ###-begin-npm-completion-### # # npm command completion script # # Installation: npm completion >> ~/.bashrc (or ~/.zshrc) # Or, maybe: npm completion > /usr/local/etc/bash_completion.d/npm # if type complete &>/dev/null; then _npm_completion () { local words cword if type _get_comp_words_by_ref &>/dev/null; then _get_comp_words_by_ref -n = -n @ -n : -w words -i cword else cword="$COMP_CWORD" words=("${COMP_WORDS[@]}") fi local si="$IFS" IFS=$'\n' COMPREPLY=($(COMP_CWORD="$cword" \ COMP_LINE="$COMP_LINE" \ COMP_POINT="$COMP_POINT" \ npm completion -- "${words[@]}" \ 2>/dev/null)) || return $? IFS="$si" if type __ltrim_colon_completions &>/dev/null; then __ltrim_colon_completions "${words[cword]}" fi } complete -o default -F _npm_completion npm elif type compdef &>/dev/null; then _npm_completion() { local si=$IFS compadd -- $(COMP_CWORD=$((CURRENT-1)) \ COMP_LINE=$BUFFER \ COMP_POINT=0 \ npm completion -- "${words[@]}" \ 2>/dev/null) IFS=$si } compdef _npm_completion npm elif type compctl &>/dev/null; then _npm_completion () { local cword line point words si read -Ac words read -cn cword let cword-=1 read -l line read -ln point si="$IFS" IFS=$'\n' reply=($(COMP_CWORD="$cword" \ COMP_LINE="$line" \ COMP_POINT="$point" \ npm completion -- "${words[@]}" \ 2>/dev/null)) || return $? IFS="$si" } compctl -K _npm_completion npm fi ###-end-npm-completion-### utils/correct-mkdir.js000064400000002366152231567050011024 0ustar00// XXX this can probably be replaced with gentle-fs.mkdir everywhere it's used const chownr = require('chownr') const inflight = require('inflight') const log = require('npmlog') const mkdirp = require('mkdirp') const inferOwner = require('infer-owner') // retain ownership of the parent dir // this matches behavior in cacache to infer the cache ownership // based on the ownership of the cache folder or it is parent. module.exports = function correctMkdir (path, cb) { cb = inflight('correctMkdir: ' + path, cb) if (!cb) { return log.verbose('correctMkdir', path, 'correctMkdir already in flight; waiting') } else { log.verbose('correctMkdir', path, 'correctMkdir not in flight; initializing') } if (!process.getuid) { log.verbose('makeCacheDir', 'UID & GID are irrelevant on', process.platform) return mkdirp(path, (er, made) => cb(er, { uid: 0, gid: 0 })) } inferOwner(path).then(owner => { mkdirp(path, (er, made) => { if (er) { log.error('correctMkdir', 'failed to make directory %s', path) return cb(er) } chownr(made || path, owner.uid, owner.gid, (er) => cb(er, owner)) }) }, er => { log.error('correctMkdir', 'failed to infer path ownership %s', path) return cb(er) }) } utils/deep-sort-object.js000064400000000553152231567050011421 0ustar00'use strict' var sortedObject = require('sorted-object') module.exports = function deepSortObject (obj) { if (obj == null || typeof obj !== 'object') return obj if (obj instanceof Array) { return obj.map(deepSortObject) } obj = sortedObject(obj) Object.keys(obj).forEach(function (key) { obj[key] = deepSortObject(obj[key]) }) return obj } utils/depr-check.js000064400000000703152231567050010255 0ustar00'use strict' const log = require('npmlog') const deprecated = {} const deprWarned = {} module.exports = deprCheck function deprCheck (data) { if (deprecated[data._id]) { data.deprecated = deprecated[data._id] } if (data.deprecated) { deprecated[data._id] = data.deprecated if (!deprWarned[data._id]) { deprWarned[data._id] = true log.warn('deprecated', '%s: %s', data._id, data.deprecated) } } return data } utils/did-you-mean.js000064400000000676152231567050010551 0ustar00var meant = require('meant') function didYouMean (scmd, commands) { var bestSimilarity = meant(scmd, commands).map(function (str) { return ' ' + str }) if (bestSimilarity.length === 0) return '' if (bestSimilarity.length === 1) { return '\nDid you mean this?\n' + bestSimilarity[0] } else { return ['\nDid you mean one of these?'] .concat(bestSimilarity.slice(0, 3)).join('\n') } } module.exports = didYouMean utils/error-handler.js000064400000014044152231567050011017 0ustar00 module.exports = errorHandler module.exports.exit = exit var cbCalled = false var log = require('npmlog') var npm = require('../npm.js') var itWorked = false var path = require('path') var wroteLogFile = false var exitCode = 0 var rollbacks = npm.rollbacks var chain = require('slide').chain var errorMessage = require('./error-message.js') var replaceInfo = require('./replace-info.js') var stopMetrics = require('./metrics.js').stop const cacheFile = require('./cache-file.js') var logFileName function getLogFile () { if (!logFileName) { logFileName = path.resolve(npm.config.get('cache'), '_logs', (new Date()).toISOString().replace(/[.:]/g, '_') + '-debug.log') } return logFileName } var timings = { version: npm.version, command: process.argv.slice(2), logfile: null } process.on('timing', function (name, value) { if (timings[name]) { timings[name] += value } else { timings[name] = value } }) process.on('exit', function (code) { process.emit('timeEnd', 'npm') log.disableProgress() if (npm.config && npm.config.loaded && npm.config.get('timing')) { try { timings.logfile = getLogFile() cacheFile.append('_timing.json', JSON.stringify(timings) + '\n') } catch (_) { // ignore } } // kill any outstanding stats reporter if it hasn't finished yet stopMetrics() if (code) itWorked = false if (itWorked) { log.info('ok') } else { if (!cbCalled) { log.error('', 'cb() never called!') console.error('') log.error('', 'This is an error with npm itself. Please report this error at:') log.error('', ' ') writeLogFile() } if (code) { log.verbose('code', code) } } if (npm.config && npm.config.loaded && npm.config.get('timing') && !wroteLogFile) writeLogFile() if (wroteLogFile) { // just a line break if (log.levels[log.level] <= log.levels.error) console.error('') log.error( '', [ 'A complete log of this run can be found in:', ' ' + getLogFile() ].join('\n') ) wroteLogFile = false } var doExit = npm.config && npm.config.loaded && npm.config.get('_exit') if (doExit) { // actually exit. if (exitCode === 0 && !itWorked) { exitCode = 1 } if (exitCode !== 0) process.exit(exitCode) } else { itWorked = false // ready for next exit } }) function exit (code, noLog) { exitCode = exitCode || process.exitCode || code var doExit = npm.config && npm.config.loaded ? npm.config.get('_exit') : true log.verbose('exit', [code, doExit]) if (log.level === 'silent') noLog = true if (rollbacks.length) { chain(rollbacks.map(function (f) { return function (cb) { npm.commands.unbuild([f], true, cb) } }), function (er) { if (er) { log.error('error rolling back', er) if (!code) { errorHandler(er) } else { if (!noLog) writeLogFile() reallyExit(er) } } else { if (!noLog && code) writeLogFile() reallyExit() } }) rollbacks.length = 0 } else if (code && !noLog) { writeLogFile() } else { reallyExit() } function reallyExit (er) { if (er && !code) code = typeof er.errno === 'number' ? er.errno : 1 itWorked = !code // Exit directly -- nothing in the CLI should still be running in the // background at this point, and this makes sure anything left dangling // for whatever reason gets thrown away, instead of leaving the CLI open // // Commands that expect long-running actions should just delay `cb()` process.stdout.write('', () => { process.exit(code) }) } } function errorHandler (er) { log.disableProgress() if (!npm.config || !npm.config.loaded) { // logging won't work unless we pretend that it's ready er = er || new Error('Exit prior to config file resolving.') console.error(er.stack || er.message) } if (cbCalled) { er = er || new Error('Callback called more than once.') } cbCalled = true if (!er) return exit(0) if (typeof er === 'string') { log.error('', er) return exit(1, true) } else if (!(er instanceof Error)) { log.error('weird error', er) return exit(1, true) } var m = er.code || er.message.match(/^(?:Error: )?(E[A-Z]+)/) if (m && !er.code) { er.code = m } ;[ 'type', 'stack', 'statusCode', 'pkgid' ].forEach(function (k) { var v = er[k] if (!v) return v = replaceInfo(v) log.verbose(k, v) }) log.verbose('cwd', process.cwd()) var os = require('os') var args = replaceInfo(process.argv) log.verbose('', os.type() + ' ' + os.release()) log.verbose('argv', args.map(JSON.stringify).join(' ')) log.verbose('node', process.version) log.verbose('npm ', 'v' + npm.version) ;[ 'code', 'syscall', 'file', 'path', 'dest', 'errno' ].forEach(function (k) { var v = er[k] if (v) log.error(k, v) }) var msg = errorMessage(er) msg.summary.concat(msg.detail).forEach(function (errline) { log.error.apply(log, errline) }) if (npm.config && npm.config.get('json')) { var error = { error: { code: er.code, summary: messageText(msg.summary), detail: messageText(msg.detail) } } console.log(JSON.stringify(error, null, 2)) } exit(typeof er.errno === 'number' ? er.errno : 1) } function messageText (msg) { return msg.map(function (line) { return line.slice(1).join(' ') }).join('\n') } function writeLogFile () { if (wroteLogFile) return var os = require('os') try { var logOutput = '' log.record.forEach(function (m) { var pref = [m.id, m.level] if (m.prefix) pref.push(m.prefix) pref = pref.join(' ') m.message.trim().split(/\r?\n/).map(function (line) { return (pref + ' ' + line).trim() }).forEach(function (line) { logOutput += line + os.EOL }) }) cacheFile.write(getLogFile(), logOutput) // truncate once it's been written. log.record.length = 0 wroteLogFile = true } catch (ex) { } } utils/error-message.js000064400000032706152231567050011033 0ustar00'use strict' var npm = require('../npm.js') var util = require('util') var nameValidator = require('validate-npm-package-name') var npmlog = require('npmlog') var replaceInfo = require('./replace-info.js') module.exports = errorMessage function errorMessage (er) { var short = [] var detail = [] er.message = replaceInfo(er.message) er.stack = replaceInfo(er.stack) switch (er.code) { case 'ENOAUDIT': short.push(['audit', er.message]) break case 'EAUDITNOPJSON': short.push(['audit', er.message]) break case 'EAUDITNOLOCK': short.push(['audit', er.message]) detail.push(['audit', 'Try creating one first with: npm i --package-lock-only']) break case 'ECONNREFUSED': short.push(['', er]) detail.push([ '', [ '\nIf you are behind a proxy, please make sure that the', "'proxy' config is set properly. See: 'npm help config'" ].join('\n') ]) break case 'EACCES': case 'EPERM': const isCachePath = typeof er.path === 'string' && npm.config && er.path.startsWith(npm.config.get('cache')) const isCacheDest = typeof er.dest === 'string' && npm.config && er.dest.startsWith(npm.config.get('cache')) const isWindows = process.platform === 'win32' if (!isWindows && (isCachePath || isCacheDest)) { // user probably doesn't need this, but still add it to the debug log npmlog.verbose(er.stack) short.push([ '', [ '', 'Your cache folder contains root-owned files, due to a bug in', 'previous versions of npm which has since been addressed.', '', 'To permanently fix this problem, please run:', ` sudo chown -R ${process.getuid()}:${process.getgid()} ${JSON.stringify(npm.config.get('cache'))}` ].join('\n') ]) } else { short.push(['', er]) detail.push([ '', [ '\nThe operation was rejected by your operating system.', (process.platform === 'win32' ? 'It\'s possible that the file was already in use (by a text editor or antivirus),\n' + 'or that you lack permissions to access it.' : 'It is likely you do not have the permissions to access this file as the current user'), '\nIf you believe this might be a permissions issue, please double-check the', 'permissions of the file and its containing directories, or try running', 'the command again as root/Administrator.' ].join('\n')]) } break case 'EUIDLOOKUP': short.push(['lifecycle', er.message]) detail.push([ '', [ '', 'Failed to look up the user/group for running scripts.', '', 'Try again with a different --user or --group settings, or', 'run with --unsafe-perm to execute scripts as root.' ].join('\n') ]) break case 'ELIFECYCLE': short.push(['', er.message]) detail.push([ '', [ '', 'Failed at the ' + er.pkgid + ' ' + er.stage + ' script.', 'This is probably not a problem with npm. There is likely additional logging output above.' ].join('\n')] ) break case 'ENOGIT': short.push(['', er.message]) detail.push([ '', [ '', 'Failed using git.', 'Please check if you have git installed and in your PATH.' ].join('\n') ]) break case 'EJSONPARSE': const path = require('path') // Check whether we ran into a conflict in our own package.json if (er.file === path.join(npm.prefix, 'package.json')) { const isDiff = require('../install/read-shrinkwrap.js')._isDiff const txt = require('fs').readFileSync(er.file, 'utf8') if (isDiff(txt)) { detail.push([ '', [ 'Merge conflict detected in your package.json.', '', 'Please resolve the package.json conflict and retry the command:', '', `$ ${process.argv.join(' ')}` ].join('\n') ]) break } } short.push(['JSON.parse', er.message]) detail.push([ 'JSON.parse', [ 'Failed to parse package.json data.', 'package.json must be actual JSON, not just JavaScript.' ].join('\n') ]) break case 'EOTP': case 'E401': // E401 is for places where we accidentally neglect OTP stuff if (er.code === 'EOTP' || /one-time pass/.test(er.message)) { short.push(['', 'This operation requires a one-time password from your authenticator.']) detail.push([ '', [ 'You can provide a one-time password by passing --otp= to the command you ran.', 'If you already provided a one-time password then it is likely that you either typoed', 'it, or it timed out. Please try again.' ].join('\n') ]) } else { // npm ERR! code E401 // npm ERR! Unable to authenticate, need: Basic const auth = (er.headers && er.headers['www-authenticate'] && er.headers['www-authenticate'].map((au) => au.split(/,\s*/))[0]) || [] if (auth.indexOf('Bearer') !== -1) { short.push(['', 'Unable to authenticate, your authentication token seems to be invalid.']) detail.push([ '', [ 'To correct this please trying logging in again with:', ' npm login' ].join('\n') ]) } else if (auth.indexOf('Basic') !== -1) { short.push(['', 'Incorrect or missing password.']) detail.push([ '', [ 'If you were trying to login, change your password, create an', 'authentication token or enable two-factor authentication then', 'that means you likely typed your password in incorrectly.', 'Please try again, or recover your password at:', ' https://www.npmjs.com/forgot', '', 'If you were doing some other operation then your saved credentials are', 'probably out of date. To correct this please try logging in again with:', ' npm login' ].join('\n') ]) } else { short.push(['', er.message || er]) } } break case 'E404': // There's no need to have 404 in the message as well. var msg = er.message.replace(/^404\s+/, '') short.push(['404', msg]) if (er.pkgid && er.pkgid !== '-') { var pkg = er.pkgid.replace(/(?!^)@.*$/, '') detail.push(['404', '']) detail.push(['404', '', "'" + er.pkgid + "' is not in the npm registry."]) var valResult = nameValidator(pkg) if (valResult.validForNewPackages) { detail.push(['404', 'You should bug the author to publish it (or use the name yourself!)']) } else { detail.push(['404', 'Your package name is not valid, because', '']) var errorsArray = (valResult.errors || []).concat(valResult.warnings || []) errorsArray.forEach(function (item, idx) { detail.push(['404', ' ' + (idx + 1) + '. ' + item]) }) } if (er.parent) { detail.push(['404', "It was specified as a dependency of '" + er.parent + "'"]) } detail.push(['404', '\nNote that you can also install from a']) detail.push(['404', 'tarball, folder, http url, or git url.']) } break case 'EPUBLISHCONFLICT': short.push(['publish fail', 'Cannot publish over existing version.']) detail.push(['publish fail', "Update the 'version' field in package.json and try again."]) detail.push(['publish fail', '']) detail.push(['publish fail', 'To automatically increment version numbers, see:']) detail.push(['publish fail', ' npm help version']) break case 'EISGIT': short.push(['git', er.message]) short.push(['git', ' ' + er.path]) detail.push([ 'git', [ 'Refusing to remove it. Update manually,', 'or move it out of the way first.' ].join('\n') ]) break case 'ECYCLE': short.push([ 'cycle', [ er.message, 'While installing: ' + er.pkgid ].join('\n') ]) detail.push([ 'cycle', [ 'Found a pathological dependency case that npm cannot solve.', 'Please report this to the package author.' ].join('\n') ]) break case 'EBADPLATFORM': var validOs = er.os.join ? er.os.join(',') : er.os var validArch = er.cpu.join ? er.cpu.join(',') : er.cpu var expected = {os: validOs, arch: validArch} var actual = {os: process.platform, arch: process.arch} short.push([ 'notsup', [ util.format('Unsupported platform for %s: wanted %j (current: %j)', er.pkgid, expected, actual) ].join('\n') ]) detail.push([ 'notsup', [ 'Valid OS: ' + validOs, 'Valid Arch: ' + validArch, 'Actual OS: ' + process.platform, 'Actual Arch: ' + process.arch ].join('\n') ]) break case 'EEXIST': short.push(['', er.message]) short.push(['', 'File exists: ' + (er.dest || er.path)]) detail.push(['', 'Remove the existing file and try again, or run npm']) detail.push(['', 'with --force to overwrite files recklessly.']) break case 'ENEEDAUTH': short.push(['need auth', er.message]) detail.push(['need auth', 'You need to authorize this machine using `npm adduser`']) break case 'ECONNRESET': case 'ENOTFOUND': case 'ETIMEDOUT': case 'EAI_FAIL': short.push(['network', er.message]) detail.push([ 'network', [ 'This is a problem related to network connectivity.', 'In most cases you are behind a proxy or have bad network settings.', '\nIf you are behind a proxy, please make sure that the', "'proxy' config is set properly. See: 'npm help config'" ].join('\n') ]) break case 'ENOPACKAGEJSON': short.push(['package.json', er.message]) detail.push([ 'package.json', [ "npm can't find a package.json file in your current directory." ].join('\n') ]) break case 'ETARGET': short.push(['notarget', er.message]) msg = [ 'In most cases you or one of your dependencies are requesting', "a package version that doesn't exist." ] if (er.parent) { msg.push("\nIt was specified as a dependency of '" + er.parent + "'\n") } detail.push(['notarget', msg.join('\n')]) break case 'E403': short.push(['403', er.message]) msg = [ 'In most cases, you or one of your dependencies are requesting', 'a package version that is forbidden by your security policy.' ] if (er.parent) { msg.push("\nIt was specified as a dependency of '" + er.parent + "'\n") } detail.push(['403', msg.join('\n')]) break case 'ENOTSUP': if (er.required) { short.push(['notsup', er.message]) short.push(['notsup', 'Not compatible with your version of node/npm: ' + er.pkgid]) detail.push([ 'notsup', [ 'Not compatible with your version of node/npm: ' + er.pkgid, 'Required: ' + JSON.stringify(er.required), 'Actual: ' + JSON.stringify({ npm: npm.version, node: npm.config.get('node-version') }) ].join('\n') ]) break } // else passthrough /* eslint no-fallthrough:0 */ case 'ENOSPC': short.push(['nospc', er.message]) detail.push([ 'nospc', [ 'There appears to be insufficient space on your system to finish.', 'Clear up some disk space and try again.' ].join('\n') ]) break case 'EROFS': short.push(['rofs', er.message]) detail.push([ 'rofs', [ 'Often virtualized file systems, or other file systems', "that don't support symlinks, give this error." ].join('\n') ]) break case 'ENOENT': short.push(['enoent', er.message]) detail.push([ 'enoent', [ 'This is related to npm not being able to find a file.', er.file ? "\nCheck if the file '" + er.file + "' is present." : '' ].join('\n') ]) break case 'EMISSINGARG': case 'EUNKNOWNTYPE': case 'EINVALIDTYPE': case 'ETOOMANYARGS': short.push(['typeerror', er.stack]) detail.push([ 'typeerror', [ 'This is an error with npm itself. Please report this error at:', ' ' ].join('\n') ]) break default: short.push(['', er.message || er]) break } if (er.optional) { short.unshift(['optional', er.optional + ' (' + er.location + '):']) short.concat(detail).forEach(function (msg) { if (!msg[0]) msg[0] = 'optional' if (msg[1]) msg[1] = msg[1].toString().replace(/(^|\n)/g, '$1SKIPPING OPTIONAL DEPENDENCY: ') }) } return {summary: short, detail: detail} } utils/escape-arg.js000064400000001221152231567050010253 0ustar00'use strict' var path = require('path') var isWindows = require('./is-windows.js') /* Escape the name of an executable suitable for passing to the system shell. Windows is easy, wrap in double quotes and you're done, as there's no facility to create files with quotes in their names. Unix-likes are a little more complicated, wrap in single quotes and escape any single quotes in the filename. */ module.exports = escapify function escapify (str) { if (isWindows) { return '"' + path.normalize(str) + '"' } else { if (/[^-_.~/\w]/.test(str)) { return "'" + str.replace(/'/g, "'\"'\"'") + "'" } else { return str } } } utils/escape-exec-path.js000064400000001371152231567050011366 0ustar00'use strict' var path = require('path') var isWindows = require('./is-windows.js') /* Escape the name of an executable suitable for passing to the system shell. Windows is easy, wrap in double quotes and you're done, as there's no facility to create files with quotes in their names. Unix-likes are a little more complicated, wrap in single quotes and escape any single quotes in the filename. */ module.exports = escapify function windowsQuotes (str) { if (!/ /.test(str)) return str return '"' + str + '"' } function escapify (str) { if (isWindows) { return path.normalize(str).split(/\\/).map(windowsQuotes).join('\\') } else if (/[^-_.~/\w]/.test(str)) { return "'" + str.replace(/'/g, "'\"'\"'") + "'" } else { return str } } utils/funding.js000064400000010760152231567050007706 0ustar00'use strict' const URL = require('url').URL exports.getFundingInfo = getFundingInfo exports.retrieveFunding = retrieveFunding exports.validFundingField = validFundingField const flatCacheSymbol = Symbol('npm flat cache') exports.flatCacheSymbol = flatCacheSymbol // supports object funding and string shorthand, or an array of these // if original was an array, returns an array; else returns the lone item function retrieveFunding (funding) { const sources = [].concat(funding || []).map(item => ( typeof item === 'string' ? { url: item } : item )) return Array.isArray(funding) ? sources : sources[0] } // Is the value of a `funding` property of a `package.json` // a valid type+url for `npm fund` to display? function validFundingField (funding) { if (!funding) return false if (Array.isArray(funding)) { return funding.every(f => !Array.isArray(f) && validFundingField(f)) } try { var parsed = new URL(funding.url || funding) } catch (error) { return false } if ( parsed.protocol !== 'https:' && parsed.protocol !== 'http:' ) return false return Boolean(parsed.host) } const empty = () => Object.create(null) function getFundingInfo (idealTree, opts) { let packageWithFundingCount = 0 const flat = empty() const seen = new Set() const { countOnly } = opts || {} const _trailingDependencies = Symbol('trailingDependencies') function tracked (name, version) { const key = String(name) + String(version) if (seen.has(key)) { return true } seen.add(key) } function retrieveDependencies (dependencies) { const trailing = dependencies[_trailingDependencies] if (trailing) { return Object.assign( empty(), dependencies, trailing ) } return dependencies } function hasDependencies (dependencies) { return dependencies && ( Object.keys(dependencies).length || dependencies[_trailingDependencies] ) } function addToFlatCache (funding, dep) { [].concat(funding || []).forEach((f) => { const key = f.url if (!Array.isArray(flat[key])) { flat[key] = [] } flat[key].push(dep) }) } function attachFundingInfo (target, funding, dep) { if (funding && validFundingField(funding)) { target.funding = retrieveFunding(funding) if (!countOnly) { addToFlatCache(target.funding, dep) } packageWithFundingCount++ } } function getFundingDependencies (tree) { const deps = tree && tree.dependencies if (!deps) return empty() const directDepsWithFunding = Object.keys(deps).map((key) => { const dep = deps[key] const { name, funding, version } = dep // avoids duplicated items within the funding tree if (tracked(name, version)) return empty() const fundingItem = {} if (version) { fundingItem.version = version } attachFundingInfo(fundingItem, funding, dep) return { dep, fundingItem } }) return directDepsWithFunding.reduce((res, { dep: directDep, fundingItem }, i) => { if (!fundingItem || fundingItem.length === 0) return res // recurse const transitiveDependencies = directDep.dependencies && Object.keys(directDep.dependencies).length > 0 && getFundingDependencies(directDep) // if we're only counting items there's no need // to add all the data to the resulting object if (countOnly) return null if (hasDependencies(transitiveDependencies)) { fundingItem.dependencies = retrieveDependencies(transitiveDependencies) } if (fundingItem.funding && fundingItem.funding.length !== 0) { res[directDep.name] = fundingItem } else if (fundingItem.dependencies) { res[_trailingDependencies] = Object.assign( empty(), res[_trailingDependencies], fundingItem.dependencies ) } return res }, countOnly ? null : empty()) } const idealTreeDependencies = getFundingDependencies(idealTree) const result = { length: packageWithFundingCount } if (!countOnly) { result.name = idealTree.name || idealTree.path if (idealTree && idealTree.version) { result.version = idealTree.version } if (idealTree && idealTree.funding) { result.funding = retrieveFunding(idealTree.funding) } result.dependencies = retrieveDependencies(idealTreeDependencies) result[flatCacheSymbol] = flat } return result } utils/gently-rm.js000064400000000744152231567050010173 0ustar00// only remove the thing if it's a symlink into a specific folder. This is // a very common use-case of npm's, but not so common elsewhere. exports = module.exports = gentlyRm var gentleFS = require('gentle-fs') var gentleFSOpts = require('../config/gentle-fs.js') function gentlyRm (target, gently, base, cb) { if (!cb) { cb = base base = undefined } if (!cb) { cb = gently gently = false } return gentleFS.rm(target, gentleFSOpts(gently, base), cb) } utils/git.js000064400000003314152231567050007034 0ustar00'use strict' const BB = require('bluebird') const exec = require('child_process').execFile const spawn = require('./spawn') const npm = require('../npm.js') const which = require('which') const git = npm.config.get('git') const assert = require('assert') const log = require('npmlog') const noProgressTillDone = require('./no-progress-while-running.js').tillDone exports.spawn = spawnGit exports.exec = BB.promisify(execGit) exports.chainableExec = chainableExec exports.whichAndExec = whichAndExec function prefixGitArgs () { return process.platform === 'win32' ? ['-c', 'core.longpaths=true'] : [] } function execGit (args, options, cb) { log.info('git', args) const fullArgs = prefixGitArgs().concat(args || []) return exec(git, fullArgs, options, noProgressTillDone(cb)) } function spawnGit (args, options) { log.info('git', args) // If we're already in a git command (eg, running test as an exec // line in an interactive rebase) then these environment variables // will force git to operate on the current project, instead of // checking out/fetching/etc. whatever the user actually intends. options.env = options.env || Object.keys(process.env) .filter(k => !/^GIT/.test(k)) .reduce((set, k) => { set[k] = process.env[k] return set }, {}) return spawn(git, prefixGitArgs().concat(args || []), options) } function chainableExec () { var args = Array.prototype.slice.call(arguments) return [execGit].concat(args) } function whichAndExec (args, options, cb) { assert.equal(typeof cb, 'function', 'no callback provided') // check for git which(git, function (err) { if (err) { err.code = 'ENOGIT' return cb(err) } execGit(args, options, cb) }) } utils/gunzip-maybe.js000064400000001054152231567050010657 0ustar00var duplex = require('mississippi').duplex var through = require('mississippi').through var zlib = require('zlib') function hasGzipHeader (c) { return c[0] === 0x1F && c[1] === 0x8B && c[2] === 0x08 } module.exports = gunzip function gunzip () { var stream = duplex() var peeker = through(function (chunk, enc, cb) { var newStream = hasGzipHeader(chunk) ? zlib.createGunzip() : through() stream.setReadable(newStream) stream.setWritable(newStream) stream.write(chunk) }) stream.setWritable(peeker) return stream } utils/is-registry.js000064400000000446152231567050010535 0ustar00'use strict' module.exports = isRegistry function isRegistry (req) { if (req == null) return false // modern metadata if ('registry' in req) return req.registry // legacy metadata if (req.type === 'range' || req.type === 'version' || req.type === 'tag') return true return false } utils/is-windows-bash.js000064400000000246152231567050011270 0ustar00'use strict' var isWindows = require('./is-windows.js') module.exports = isWindows && (/^MINGW(32|64)$/.test(process.env.MSYSTEM) || process.env.TERM === 'cygwin') utils/is-windows-shell.js000064400000000231152231567050011454 0ustar00'use strict' var isWindows = require('./is-windows.js') var isWindowsBash = require('./is-windows-bash.js') module.exports = isWindows && !isWindowsBash utils/is-windows.js000064400000000073152231567050010353 0ustar00'use strict' module.exports = process.platform === 'win32' utils/lifecycle-cmd.js000064400000000760152231567050010753 0ustar00exports = module.exports = cmd var npm = require('../npm.js') var usage = require('./usage.js') function cmd (stage) { function CMD (args, cb) { npm.commands['run-script']([stage].concat(args), cb) } CMD.usage = usage(stage, 'npm ' + stage + ' [-- ]') var installedShallow = require('./completion/installed-shallow.js') CMD.completion = function (opts, cb) { installedShallow(opts, function (d) { return d.scripts && d.scripts[stage] }, cb) } return CMD } utils/lifecycle.js000064400000000554152231567050010213 0ustar00exports = module.exports = runLifecycle const lifecycleOpts = require('../config/lifecycle') const lifecycle = require('npm-lifecycle') function runLifecycle (pkg, stage, wd, moreOpts, cb) { if (typeof moreOpts === 'function') { cb = moreOpts moreOpts = null } const opts = lifecycleOpts(moreOpts) lifecycle(pkg, stage, wd, opts).then(cb, cb) } utils/link.js000064400000000352152231567050007205 0ustar00module.exports = link var gentleFS = require('gentle-fs') var gentleFSOpts = require('../config/gentle-fs.js') function link (from, to, gently, abs, cb) { return gentleFS.link(from, to, gentleFSOpts(gently, undefined, abs), cb) } utils/locker.js000064400000003475152231567050007540 0ustar00var crypto = require('crypto') var resolve = require('path').resolve var lockfile = require('lockfile') var log = require('npmlog') var npm = require('../npm.js') var correctMkdir = require('../utils/correct-mkdir.js') var installLocks = {} function lockFileName (base, name) { var c = name.replace(/[^a-zA-Z0-9]+/g, '-').replace(/^-+|-+$/g, '') var p = resolve(base, name) var h = crypto.createHash('sha1').update(p).digest('hex') var l = resolve(npm.cache, '_locks') return resolve(l, c.substr(0, 24) + '-' + h.substr(0, 16) + '.lock') } function lock (base, name, cb) { var lockDir = resolve(npm.cache, '_locks') correctMkdir(lockDir, function (er) { if (er) return cb(er) var opts = { stale: npm.config.get('cache-lock-stale'), retries: npm.config.get('cache-lock-retries'), wait: npm.config.get('cache-lock-wait') } var lf = lockFileName(base, name) lockfile.lock(lf, opts, function (er) { if (er) log.warn('locking', lf, 'failed', er) if (!er) { log.verbose('lock', 'using', lf, 'for', resolve(base, name)) installLocks[lf] = true } cb(er) }) }) } function unlock (base, name, cb) { var lf = lockFileName(base, name) var locked = installLocks[lf] if (locked === false) { return process.nextTick(cb) } else if (locked === true) { lockfile.unlock(lf, function (er) { if (er) { log.warn('unlocking', lf, 'failed', er) } else { installLocks[lf] = false log.verbose('unlock', 'done using', lf, 'for', resolve(base, name)) } cb(er) }) } else { var notLocked = new Error( 'Attempt to unlock ' + resolve(base, name) + ", which hasn't been locked" ) notLocked.code = 'ENOTLOCKED' throw notLocked } } module.exports = { lock: lock, unlock: unlock } utils/metrics-launch.js000064400000002124152231567050011165 0ustar00'use strict' /* eslint-disable camelcase */ module.exports = launchSendMetrics var fs = require('graceful-fs') var child_process = require('child_process') if (require.main === module) main() function launchSendMetrics () { var path = require('path') var npm = require('../npm.js') try { if (!npm.config.get('send-metrics')) return var cliMetrics = path.join(npm.config.get('cache'), 'anonymous-cli-metrics.json') var targetRegistry = npm.config.get('metrics-registry') fs.statSync(cliMetrics) return runInBackground(__filename, [cliMetrics, targetRegistry]) } catch (ex) { // if the metrics file doesn't exist, don't run } } function runInBackground (js, args, opts) { if (!args) args = [] args.unshift(js) if (!opts) opts = {} opts.stdio = 'ignore' opts.detached = true var child = child_process.spawn(process.execPath, args, opts) child.unref() return child } function main () { var sendMetrics = require('./metrics.js').send var metricsFile = process.argv[2] var metricsRegistry = process.argv[3] sendMetrics(metricsFile, metricsRegistry) } utils/metrics.js000064400000004253152231567050007722 0ustar00'use strict' exports.start = startMetrics exports.stop = stopMetrics exports.save = saveMetrics exports.send = sendMetrics const fs = require('fs') const path = require('path') const npm = require('../npm.js') const regFetch = require('libnpm/fetch') const uuid = require('uuid') const cacheFile = require('./cache-file.js') let inMetrics = false function startMetrics () { if (inMetrics) return // loaded on demand to avoid any recursive deps when `./metrics-launch` requires us. var metricsLaunch = require('./metrics-launch.js') npm.metricsProcess = metricsLaunch() } function stopMetrics () { if (inMetrics) return if (npm.metricsProcess) npm.metricsProcess.kill('SIGKILL') } function saveMetrics (itWorked) { if (inMetrics) return // If the metrics reporter hasn't managed to PUT yet then kill it so that it doesn't // step on our updating the anonymous-cli-metrics json stopMetrics() var metricsFile = path.join(npm.config.get('cache'), 'anonymous-cli-metrics.json') var metrics try { metrics = JSON.parse(fs.readFileSync(metricsFile)) metrics.metrics.to = new Date().toISOString() if (itWorked) { ++metrics.metrics.successfulInstalls } else { ++metrics.metrics.failedInstalls } } catch (ex) { metrics = { metricId: uuid.v4(), metrics: { from: new Date().toISOString(), to: new Date().toISOString(), successfulInstalls: itWorked ? 1 : 0, failedInstalls: itWorked ? 0 : 1 } } } try { cacheFile.write(metricsFile, JSON.stringify(metrics)) } catch (ex) { // we couldn't write and/or chown the error metrics file, oh well. } } function sendMetrics (metricsFile, metricsRegistry) { inMetrics = true var cliMetrics = JSON.parse(fs.readFileSync(metricsFile)) regFetch( `/-/npm/anon-metrics/v1/${encodeURIComponent(cliMetrics.metricId)}`, // NOTE: skip npmConfig() to prevent auth { registry: metricsRegistry, method: 'PUT', body: cliMetrics.metrics, retry: false } ).then(() => { fs.unlinkSync(metricsFile) }, err => { cacheFile.write(path.join(path.dirname(metricsFile), 'last-send-metrics-error.txt'), err.stack) }) } utils/module-name.js000064400000001715152231567050010457 0ustar00'use strict' var path = require('path') module.exports = moduleName module.exports.test = {} module.exports.test.pathToPackageName = pathToPackageName function pathToPackageName (dir) { if (dir == null) return '' if (dir === '') return '' var name = path.relative(path.resolve(dir, '..'), dir) var scoped = path.relative(path.resolve(dir, '../..'), dir) if (scoped[0] === '@') return scoped.replace(/\\/g, '/') return name.trim() } module.exports.test.isNotEmpty = isNotEmpty function isNotEmpty (str) { return str != null && str !== '' } var unknown = 0 function moduleName (tree) { if (tree.name) { return tree.name } var pkg = tree.package || tree if (isNotEmpty(pkg.name) && typeof pkg.name === 'string') return pkg.name.trim() var pkgName = pathToPackageName(tree.path) if (pkgName !== '') return pkgName if (tree._invalidName != null) return tree._invalidName tree._invalidName = '!invalid#' + (++unknown) return tree._invalidName } access.js000064400000013050152231567050006350 0ustar00'use strict' /* eslint-disable standard/no-callback-literal */ const BB = require('bluebird') const figgyPudding = require('figgy-pudding') const libaccess = require('libnpm/access') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const path = require('path') const prefix = require('./npm.js').prefix const readPackageJson = BB.promisify(require('read-package-json')) const usage = require('./utils/usage.js') const whoami = require('./whoami.js') module.exports = access access.usage = usage( 'npm access', 'npm access public []\n' + 'npm access restricted []\n' + 'npm access grant []\n' + 'npm access revoke []\n' + 'npm access 2fa-required []\n' + 'npm access 2fa-not-required []\n' + 'npm access ls-packages [||]\n' + 'npm access ls-collaborators [ []]\n' + 'npm access edit []' ) access.subcommands = [ 'public', 'restricted', 'grant', 'revoke', 'ls-packages', 'ls-collaborators', 'edit', '2fa-required', '2fa-not-required' ] const AccessConfig = figgyPudding({ json: {} }) function UsageError (msg = '') { throw Object.assign(new Error( (msg ? `\nUsage: ${msg}\n\n` : '') + access.usage ), {code: 'EUSAGE'}) } access.completion = function (opts, cb) { var argv = opts.conf.argv.remain if (argv.length === 2) { return cb(null, access.subcommands) } switch (argv[2]) { case 'grant': if (argv.length === 3) { return cb(null, ['read-only', 'read-write']) } else { return cb(null, []) } case 'public': case 'restricted': case 'ls-packages': case 'ls-collaborators': case 'edit': case '2fa-required': case '2fa-not-required': return cb(null, []) case 'revoke': return cb(null, []) default: return cb(new Error(argv[2] + ' not recognized')) } } function access ([cmd, ...args], cb) { return BB.try(() => { const fn = access.subcommands.includes(cmd) && access[cmd] if (!cmd) { UsageError('Subcommand is required.') } if (!fn) { UsageError(`${cmd} is not a recognized subcommand.`) } return fn(args, AccessConfig(npmConfig())) }).then( x => cb(null, x), err => err.code === 'EUSAGE' ? cb(err.message) : cb(err) ) } access.public = ([pkg], opts) => { return modifyPackage(pkg, opts, libaccess.public) } access.restricted = ([pkg], opts) => { return modifyPackage(pkg, opts, libaccess.restricted) } access.grant = ([perms, scopeteam, pkg], opts) => { return BB.try(() => { if (!perms || (perms !== 'read-only' && perms !== 'read-write')) { UsageError('First argument must be either `read-only` or `read-write.`') } if (!scopeteam) { UsageError('`` argument is required.') } const [, scope, team] = scopeteam.match(/^@?([^:]+):(.*)$/) || [] if (!scope && !team) { UsageError( 'Second argument used incorrect format.\n' + 'Example: @example:developers' ) } return modifyPackage(pkg, opts, (pkgName, opts) => { return libaccess.grant(pkgName, scopeteam, perms, opts) }, false) }) } access.revoke = ([scopeteam, pkg], opts) => { return BB.try(() => { if (!scopeteam) { UsageError('`` argument is required.') } const [, scope, team] = scopeteam.match(/^@?([^:]+):(.*)$/) || [] if (!scope || !team) { UsageError( 'First argument used incorrect format.\n' + 'Example: @example:developers' ) } return modifyPackage(pkg, opts, (pkgName, opts) => { return libaccess.revoke(pkgName, scopeteam, opts) }) }) } access['2fa-required'] = access.tfaRequired = ([pkg], opts) => { return modifyPackage(pkg, opts, libaccess.tfaRequired, false) } access['2fa-not-required'] = access.tfaNotRequired = ([pkg], opts) => { return modifyPackage(pkg, opts, libaccess.tfaNotRequired, false) } access['ls-packages'] = access.lsPackages = ([owner], opts) => { return ( owner ? BB.resolve(owner) : BB.fromNode(cb => whoami([], true, cb)) ).then(owner => { return libaccess.lsPackages(owner, opts) }).then(pkgs => { // TODO - print these out nicely (breaking change) output(JSON.stringify(pkgs, null, 2)) }) } access['ls-collaborators'] = access.lsCollaborators = ([pkg, usr], opts) => { return getPackage(pkg, false).then(pkgName => libaccess.lsCollaborators(pkgName, usr, opts) ).then(collabs => { // TODO - print these out nicely (breaking change) output(JSON.stringify(collabs, null, 2)) }) } access['edit'] = () => BB.reject(new Error('edit subcommand is not implemented yet')) function modifyPackage (pkg, opts, fn, requireScope = true) { return getPackage(pkg, requireScope).then(pkgName => otplease(opts, opts => fn(pkgName, opts)) ) } function getPackage (name, requireScope = true) { return BB.try(() => { if (name && name.trim()) { return name.trim() } else { return readPackageJson( path.resolve(prefix, 'package.json') ).then( data => data.name, err => { if (err.code === 'ENOENT') { throw new Error('no package name passed to command and no package.json found') } else { throw err } } ) } }).then(name => { if (requireScope && !name.match(/^@[^/]+\/.*$/)) { UsageError('This command is only available for scoped packages.') } else { return name } }) } adduser.js000064400000002471152231567050006543 0ustar00module.exports = adduser const log = require('npmlog') const npm = require('./npm.js') const usage = require('./utils/usage') let crypto try { crypto = require('crypto') } catch (ex) {} adduser.usage = usage( 'adduser', 'npm adduser [--registry=url] [--scope=@orgname] [--auth-type=legacy] [--always-auth]' ) function adduser (args, cb) { if (!crypto) { return cb(new Error( 'You must compile node with ssl support to use the adduser feature' )) } let registry = npm.config.get('registry') const scope = npm.config.get('scope') const creds = npm.config.getCredentialsByURI(npm.config.get('registry')) if (scope) { const scopedRegistry = npm.config.get(scope + ':registry') const cliRegistry = npm.config.get('registry', 'cli') if (scopedRegistry && !cliRegistry) registry = scopedRegistry } log.disableProgress() let auth try { auth = require('./auth/' + npm.config.get('auth-type')) } catch (e) { return cb(new Error('no such auth module')) } auth.login(creds, registry, scope, function (err, newCreds) { if (err) return cb(err) npm.config.del('_token', 'user') // prevent legacy pollution if (scope) npm.config.set(scope + ':registry', registry, 'user') npm.config.setCredentialsByURI(registry, newCreds) npm.config.save('user', cb) }) } audit.js000064400000025073152231567050006225 0ustar00'use strict' const Bluebird = require('bluebird') const audit = require('./install/audit.js') const figgyPudding = require('figgy-pudding') const fs = require('graceful-fs') const Installer = require('./install.js').Installer const lockVerify = require('lock-verify') const log = require('npmlog') const npa = require('libnpm/parse-arg') const npm = require('./npm.js') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const parseJson = require('json-parse-better-errors') const readFile = Bluebird.promisify(fs.readFile) const AuditConfig = figgyPudding({ also: {}, 'audit-level': {}, deepArgs: 'deep-args', 'deep-args': {}, dev: {}, force: {}, 'dry-run': {}, global: {}, json: {}, only: {}, parseable: {}, prod: {}, production: {}, registry: {}, runId: {} }) module.exports = auditCmd const usage = require('./utils/usage') auditCmd.usage = usage( 'audit', '\nnpm audit [--json] [--production]' + '\nnpm audit fix ' + '[--force|--package-lock-only|--dry-run|--production|--only=(dev|prod)]' ) auditCmd.completion = function (opts, cb) { const argv = opts.conf.argv.remain switch (argv[2]) { case 'audit': return cb(null, []) default: return cb(new Error(argv[2] + ' not recognized')) } } class Auditor extends Installer { constructor (where, dryrun, args, opts) { super(where, dryrun, args, opts) this.deepArgs = (opts && opts.deepArgs) || [] this.runId = opts.runId || '' this.audit = false } loadAllDepsIntoIdealTree (cb) { Bluebird.fromNode(cb => super.loadAllDepsIntoIdealTree(cb)).then(() => { if (this.deepArgs && this.deepArgs.length) { this.deepArgs.forEach(arg => { arg.reduce((acc, child, ii) => { if (!acc) { // We might not always be able to find `target` through the given // path. If we can't we'll just ignore it. return } const spec = npa(child) const target = ( acc.requires.find(n => n.package.name === spec.name) || acc.requires.find( n => audit.scrub(n.package.name, this.runId) === spec.name ) ) if (target && ii === arg.length - 1) { target.loaded = false // This kills `hasModernMeta()` and forces a re-fetch target.package = { name: spec.name, version: spec.fetchSpec, _requested: target.package._requested } delete target.fakeChild let parent = target.parent while (parent) { parent.loaded = false parent = parent.parent } target.requiredBy.forEach(par => { par.loaded = false delete par.fakeChild }) } return target }, this.idealTree) }) return Bluebird.fromNode(cb => super.loadAllDepsIntoIdealTree(cb)) } }).nodeify(cb) } // no top level lifecycles on audit runPreinstallTopLevelLifecycles (cb) { cb() } runPostinstallTopLevelLifecycles (cb) { cb() } } function maybeReadFile (name) { const file = `${npm.prefix}/${name}` return readFile(file) .then((data) => { try { return parseJson(data) } catch (ex) { ex.code = 'EJSONPARSE' throw ex } }) .catch({code: 'ENOENT'}, () => null) .catch((ex) => { ex.file = file throw ex }) } function filterEnv (action, opts) { const includeDev = opts.dev || (!/^prod(uction)?$/.test(opts.only) && !opts.production) || /^dev(elopment)?$/.test(opts.only) || /^dev(elopment)?$/.test(opts.also) const includeProd = !/^dev(elopment)?$/.test(opts.only) const resolves = action.resolves.filter(({dev}) => { return (dev && includeDev) || (!dev && includeProd) }) if (resolves.length) { return Object.assign({}, action, {resolves}) } } function auditCmd (args, cb) { const opts = AuditConfig(npmConfig()) if (opts.global) { const err = new Error('`npm audit` does not support testing globals') err.code = 'EAUDITGLOBAL' throw err } if (args.length && args[0] !== 'fix') { return cb(new Error('Invalid audit subcommand: `' + args[0] + '`\n\nUsage:\n' + auditCmd.usage)) } return Bluebird.all([ maybeReadFile('npm-shrinkwrap.json'), maybeReadFile('package-lock.json'), maybeReadFile('package.json') ]).spread((shrinkwrap, lockfile, pkgJson) => { const sw = shrinkwrap || lockfile if (!pkgJson) { const err = new Error('No package.json found: Cannot audit a project without a package.json') err.code = 'EAUDITNOPJSON' throw err } if (!sw) { const err = new Error('Neither npm-shrinkwrap.json nor package-lock.json found: Cannot audit a project without a lockfile') err.code = 'EAUDITNOLOCK' throw err } else if (shrinkwrap && lockfile) { log.warn('audit', 'Both npm-shrinkwrap.json and package-lock.json exist, using npm-shrinkwrap.json.') } const requires = Object.assign( {}, (pkgJson && pkgJson.dependencies) || {}, (!opts.production && pkgJson && pkgJson.devDependencies) || {} ) return lockVerify(npm.prefix).then((result) => { if (result.status) return audit.generate(sw, requires) const lockFile = shrinkwrap ? 'npm-shrinkwrap.json' : 'package-lock.json' const err = new Error(`Errors were found in your ${lockFile}, run npm install to fix them.\n ` + result.errors.join('\n ')) err.code = 'ELOCKVERIFY' throw err }) }).then((auditReport) => { return audit.submitForFullReport(auditReport) }).catch((err) => { if (err.statusCode >= 400) { let msg if (err.statusCode === 401) { msg = `Either your login credentials are invalid or your registry (${opts.registry}) does not support audit.` } else if (err.statusCode === 404) { msg = `Your configured registry (${opts.registry}) does not support audit requests.` } else { msg = `Your configured registry (${opts.registry}) may not support audit requests, or the audit endpoint may be temporarily unavailable.` } if (err.body.length) { msg += '\nThe server said: ' + err.body } const ne = new Error(msg) ne.code = 'ENOAUDIT' ne.wrapped = err throw ne } throw err }).then((auditResult) => { if (args[0] === 'fix') { const actions = (auditResult.actions || []).reduce((acc, action) => { action = filterEnv(action, opts) if (!action) { return acc } if (action.isMajor) { acc.major.add(`${action.module}@${action.target}`) action.resolves.forEach(({id, path}) => acc.majorFixes.add(`${id}::${path}`)) } else if (action.action === 'install') { acc.install.add(`${action.module}@${action.target}`) action.resolves.forEach(({id, path}) => acc.installFixes.add(`${id}::${path}`)) } else if (action.action === 'update') { const name = action.module const version = action.target action.resolves.forEach(vuln => { acc.updateFixes.add(`${vuln.id}::${vuln.path}`) const modPath = vuln.path.split('>') const newPath = modPath.slice( 0, modPath.indexOf(name) ).concat(`${name}@${version}`) if (newPath.length === 1) { acc.install.add(newPath[0]) } else { acc.update.add(newPath.join('>')) } }) } else if (action.action === 'review') { action.resolves.forEach(({id, path}) => acc.review.add(`${id}::${path}`)) } return acc }, { install: new Set(), installFixes: new Set(), update: new Set(), updateFixes: new Set(), major: new Set(), majorFixes: new Set(), review: new Set() }) return Bluebird.try(() => { const installMajor = opts.force const installCount = actions.install.size + (installMajor ? actions.major.size : 0) + actions.update.size const vulnFixCount = new Set([...actions.installFixes, ...actions.updateFixes, ...(installMajor ? actions.majorFixes : [])]).size const metavuln = auditResult.metadata.vulnerabilities const total = Object.keys(metavuln).reduce((acc, key) => acc + metavuln[key], 0) if (installCount) { log.verbose( 'audit', 'installing', [...actions.install, ...(installMajor ? actions.major : []), ...actions.update] ) } return Bluebird.fromNode(cb => { new Auditor( npm.prefix, !!opts['dry-run'], [...actions.install, ...(installMajor ? actions.major : [])], opts.concat({ runId: auditResult.runId, deepArgs: [...actions.update].map(u => u.split('>')) }).toJSON() ).run(cb) }).then(() => { const numScanned = auditResult.metadata.totalDependencies if (!opts.json && !opts.parseable) { output(`fixed ${vulnFixCount} of ${total} vulnerabilit${total === 1 ? 'y' : 'ies'} in ${numScanned} scanned package${numScanned === 1 ? '' : 's'}`) if (actions.review.size) { output(` ${actions.review.size} vulnerabilit${actions.review.size === 1 ? 'y' : 'ies'} required manual review and could not be updated`) } if (actions.major.size) { output(` ${actions.major.size} package update${actions.major.size === 1 ? '' : 's'} for ${actions.majorFixes.size} vulnerabilit${actions.majorFixes.size === 1 ? 'y' : 'ies'} involved breaking changes`) if (installMajor) { output(' (installed due to `--force` option)') } else { output(' (use `npm audit fix --force` to install breaking changes;' + ' or refer to `npm audit` for steps to fix these manually)') } } } }) }) } else { const levels = ['low', 'moderate', 'high', 'critical'] const minLevel = levels.indexOf(opts['audit-level']) const vulns = levels.reduce((count, level, i) => { return i < minLevel ? count : count + (auditResult.metadata.vulnerabilities[level] || 0) }, 0) if (vulns > 0) process.exitCode = 1 if (opts.parseable) { return audit.printParseableReport(auditResult) } else { return audit.printFullReport(auditResult) } } }).asCallback(cb) } bin.js000064400000001003152231567050005652 0ustar00module.exports = bin var npm = require('./npm.js') var osenv = require('osenv') var output = require('./utils/output.js') bin.usage = 'npm bin [--global]' function bin (args, silent, cb) { if (typeof cb !== 'function') { cb = silent silent = false } var b = npm.bin var PATH = osenv.path() if (!silent) output(b) process.nextTick(cb.bind(this, null, b)) if (npm.config.get('global') && PATH.indexOf(b) === -1) { npm.config.get('logstream').write('(not in PATH env variable)\n') } } bugs.js000064400000001540152231567050006050 0ustar00module.exports = bugs var log = require('npmlog') var openUrl = require('./utils/open-url') var fetchPackageMetadata = require('./fetch-package-metadata.js') var usage = require('./utils/usage') bugs.usage = usage( 'bugs', 'npm bugs []' ) bugs.completion = function (opts, cb) { // FIXME: there used to be registry completion here, but it stopped making // sense somewhere around 50,000 packages on the registry cb() } function bugs (args, cb) { var n = args.length ? args[0] : '.' fetchPackageMetadata(n, '.', {fullMetadata: true}, function (er, d) { if (er) return cb(er) var url = d.bugs && ((typeof d.bugs === 'string') ? d.bugs : d.bugs.url) if (!url) { url = 'https://www.npmjs.org/package/' + d.name } log.silly('bugs', 'url', url) openUrl(url, 'bug list available at the following URL', cb) }) } build.js000064400000010701152231567050006206 0ustar00// npm build command // everything about the installation after the creation of // the .npm/{name}/{version}/package folder. // linking the modules into the npm.root, // resolving dependencies, etc. // This runs AFTER install or link are completed. var npm = require('./npm.js') var log = require('npmlog') var chain = require('slide').chain var path = require('path') var fs = require('graceful-fs') var lifecycle = require('./utils/lifecycle.js') var readJson = require('read-package-json') var binLinks = require('bin-links') var binLinksConfig = require('./config/bin-links.js') var ini = require('ini') var writeFile = require('write-file-atomic') module.exports = build build.usage = 'npm build []' build._didBuild = {} build._noLC = {} function build (args, global, didPre, didRB, cb) { if (typeof cb !== 'function') { cb = didRB didRB = false } if (typeof cb !== 'function') { cb = didPre didPre = false } if (typeof cb !== 'function') { cb = global global = npm.config.get('global') } if (!args.length) { readJson(path.resolve(npm.localPrefix, 'package.json'), function (er, pkg) { if (!args.length && pkg && pkg.scripts && pkg.scripts.build) { log.warn('build', '`npm build` called with no arguments. Did you mean to `npm run-script build`?') } cb() }) } else { // it'd be nice to asyncMap these, but actually, doing them // in parallel generally munges up the output from node-waf var builder = build_(global, didPre, didRB) chain(args.map(function (arg) { return function (cb) { builder(arg, cb) } }), cb) } } function build_ (global, didPre, didRB) { return function (folder, cb) { folder = path.resolve(folder) if (build._didBuild[folder]) log.info('build', 'already built', folder) build._didBuild[folder] = true log.info('build', folder) readJson(path.resolve(folder, 'package.json'), function (er, pkg) { if (er) return cb(er) chain([ !didPre && [lifecycle, pkg, 'preinstall', folder], [linkStuff, pkg, folder, global], !didRB && [rebuildBundles, pkg, folder], [writeBuiltinConf, pkg, folder], didPre !== build._noLC && [lifecycle, pkg, 'install', folder], didPre !== build._noLC && [lifecycle, pkg, 'postinstall', folder] ], cb) }) } } var writeBuiltinConf = build.writeBuiltinConf = function (pkg, folder, cb) { // the builtin config is "sticky". Any time npm installs // itself globally, it puts its builtin config file there var parent = path.dirname(folder) var dir = npm.globalDir // Make this count for canary, too if ((pkg.name !== 'npm' && pkg.name !== 'npmc') || !npm.config.get('global') || !npm.config.usingBuiltin || dir !== parent) { return cb() } var data = ini.stringify(npm.config.sources.builtin.data) writeFile(path.resolve(folder, 'npmrc'), data, cb) } var linkStuff = build.linkStuff = function (pkg, folder, global, cb) { // allow to opt out of linking binaries. if (npm.config.get('bin-links') === false) return cb() return binLinks(pkg, folder, global, binLinksConfig(pkg), cb) } function rebuildBundles (pkg, folder, cb) { if (!npm.config.get('rebuild-bundle')) return cb() var deps = Object.keys(pkg.dependencies || {}) .concat(Object.keys(pkg.devDependencies || {})) var bundles = pkg.bundleDependencies || pkg.bundledDependencies || [] fs.readdir(path.resolve(folder, 'node_modules'), function (er, files) { // error means no bundles if (er) return cb() log.verbose('rebuildBundles', files) // don't asyncMap these, because otherwise build script output // gets interleaved and is impossible to read chain(files.filter(function (file) { // rebuild if: // not a .folder, like .bin or .hooks return !file.match(/^[._-]/) && // not some old 0.x style bundle file.indexOf('@') === -1 && // either not a dep, or explicitly bundled (deps.indexOf(file) === -1 || bundles.indexOf(file) !== -1) }).map(function (file) { file = path.resolve(folder, 'node_modules', file) return function (cb) { if (build._didBuild[file]) return cb() log.verbose('rebuild bundle', file) // if file is not a package dir, then don't do it. fs.lstat(path.resolve(file, 'package.json'), function (er) { if (er) return cb() build_(false)(file, cb) }) } }), cb) }) } cache.js000064400000011245152231567050006156 0ustar00'use strict' /* eslint-disable standard/no-callback-literal */ const BB = require('bluebird') const assert = require('assert') const cacache = require('cacache') const finished = BB.promisify(require('mississippi').finished) const log = require('npmlog') const npa = require('npm-package-arg') const npm = require('./npm.js') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const pacote = require('pacote') const path = require('path') const rm = BB.promisify(require('./utils/gently-rm.js')) const unbuild = BB.promisify(npm.commands.unbuild) cache.usage = 'npm cache add ' + '\nnpm cache add ' + '\nnpm cache add ' + '\nnpm cache add ' + '\nnpm cache add @' + '\nnpm cache clean' + '\nnpm cache verify' cache.completion = function (opts, cb) { var argv = opts.conf.argv.remain if (argv.length === 2) { return cb(null, ['add', 'clean']) } // TODO - eventually... switch (argv[2]) { case 'clean': case 'add': return cb(null, []) } } exports = module.exports = cache function cache (args, cb) { const cmd = args.shift() let result switch (cmd) { case 'rm': case 'clear': case 'clean': result = clean(args) break case 'add': result = add(args, npm.prefix) break case 'verify': case 'check': result = verify() break default: return cb('Usage: ' + cache.usage) } if (!result || !result.then) { throw new Error(`npm cache ${cmd} handler did not return a Promise`) } result.then(() => cb(), cb) } // npm cache clean [pkg]* cache.clean = clean function clean (args) { if (!args) args = [] if (args.length) { return BB.reject(new Error('npm cache clear does not accept arguments')) } const cachePath = path.join(npm.cache, '_cacache') if (!npm.config.get('force')) { return BB.reject(new Error("As of npm@5, the npm cache self-heals from corruption issues and data extracted from the cache is guaranteed to be valid. If you want to make sure everything is consistent, use 'npm cache verify' instead. On the other hand, if you're debugging an issue with the installer, you can use `npm install --cache /tmp/empty-cache` to use a temporary cache instead of nuking the actual one.\n\nIf you're sure you want to delete the entire cache, rerun this command with --force.")) } // TODO - remove specific packages or package versions return rm(cachePath) } // npm cache add // npm cache add // npm cache add // npm cache add cache.add = function (pkg, ver, where, scrub) { assert(typeof pkg === 'string', 'must include name of package to install') if (scrub) { return clean([]).then(() => { return add([pkg, ver], where) }) } return add([pkg, ver], where) } function add (args, where) { var usage = 'Usage:\n' + ' npm cache add \n' + ' npm cache add @\n' + ' npm cache add \n' + ' npm cache add \n' var spec log.silly('cache add', 'args', args) if (args[1] === undefined) args[1] = null // at this point the args length must ==2 if (args[1] !== null) { spec = args[0] + '@' + args[1] } else if (args.length === 2) { spec = args[0] } log.verbose('cache add', 'spec', spec) if (!spec) return BB.reject(new Error(usage)) log.silly('cache add', 'parsed spec', spec) return finished(pacote.tarball.stream(spec, npmConfig({where})).resume()) } cache.verify = verify function verify () { const cache = path.join(npm.config.get('cache'), '_cacache') let prefix = cache if (prefix.indexOf(process.env.HOME) === 0) { prefix = '~' + prefix.substr(process.env.HOME.length) } return cacache.verify(cache).then((stats) => { output(`Cache verified and compressed (${prefix}):`) output(`Content verified: ${stats.verifiedContent} (${stats.keptSize} bytes)`) stats.badContentCount && output(`Corrupted content removed: ${stats.badContentCount}`) stats.reclaimedCount && output(`Content garbage-collected: ${stats.reclaimedCount} (${stats.reclaimedSize} bytes)`) stats.missingContent && output(`Missing content: ${stats.missingContent}`) output(`Index entries: ${stats.totalEntries}`) output(`Finished in ${stats.runTime.total / 1000}s`) }) } cache.unpack = unpack function unpack (pkg, ver, unpackTarget, dmode, fmode, uid, gid) { return unbuild([unpackTarget], true).then(() => { const opts = npmConfig({dmode, fmode, uid, gid, offline: true}) return pacote.extract(npa.resolve(pkg, ver), unpackTarget, opts) }) } ci.js000064400000002475152231567050005513 0ustar00'use strict' const npm = require('./npm.js') const Installer = require('libcipm') const log = require('npmlog') const path = require('path') const pack = require('./pack.js') ci.usage = 'npm ci' ci.completion = (cb) => cb(null, []) module.exports = ci function ci (args, cb) { const opts = { // Add some non-npm-config opts by hand. cache: path.join(npm.config.get('cache'), '_cacache'), // NOTE: npm has some magic logic around color distinct from the config // value, so we have to override it here color: !!npm.color, hashAlgorithm: 'sha1', includeDeprecated: false, log, 'npm-session': npm.session, 'project-scope': npm.projectScope, refer: npm.referer, dmode: npm.modes.exec, fmode: npm.modes.file, umask: npm.modes.umask, npmVersion: npm.version, tmp: npm.tmp, dirPacker: pack.packGitDep } if (npm.config.get('dev')) { log.warn('ci', 'Usage of the `--dev` option is deprecated. Use `--also=dev` instead.') } for (const key in npm.config.list[0]) { if (!['log', 'cache'].includes(key)) { opts[key] = npm.config.list[0][key] } } return new Installer(opts).run().then(details => { log.disableProgress() console.log(`added ${details.pkgCount} packages in ${ details.runTime / 1000 }s`) }).then(() => cb(), cb) } completion.js000064400000016156152231567050007272 0ustar00module.exports = completion completion.usage = 'source <(npm completion)' var npm = require('./npm.js') var npmconf = require('./config/core.js') var configDefs = npmconf.defs var configTypes = configDefs.types var shorthands = configDefs.shorthands var nopt = require('nopt') var configNames = Object.keys(configTypes) .filter(function (e) { return e.charAt(0) !== '_' }) var shorthandNames = Object.keys(shorthands) var allConfs = configNames.concat(shorthandNames) var once = require('once') var isWindowsShell = require('./utils/is-windows-shell.js') var output = require('./utils/output.js') completion.completion = function (opts, cb) { if (opts.w > 3) return cb() var fs = require('graceful-fs') var path = require('path') var bashExists = null var zshExists = null fs.stat(path.resolve(process.env.HOME, '.bashrc'), function (er) { bashExists = !er next() }) fs.stat(path.resolve(process.env.HOME, '.zshrc'), function (er) { zshExists = !er next() }) function next () { if (zshExists === null || bashExists === null) return var out = [] if (zshExists) out.push('~/.zshrc') if (bashExists) out.push('~/.bashrc') if (opts.w === 2) { out = out.map(function (m) { return ['>>', m] }) } cb(null, out) } } function completion (args, cb) { if (isWindowsShell) { var e = new Error('npm completion supported only in MINGW / Git bash on Windows') e.code = 'ENOTSUP' e.errno = require('constants').ENOTSUP // eslint-disable-line node/no-deprecated-api return cb(e) } // if the COMP_* isn't in the env, then just dump the script. if (process.env.COMP_CWORD === undefined || process.env.COMP_LINE === undefined || process.env.COMP_POINT === undefined) { return dumpScript(cb) } console.error(process.env.COMP_CWORD) console.error(process.env.COMP_LINE) console.error(process.env.COMP_POINT) // get the partial line and partial word, // if the point isn't at the end. // ie, tabbing at: npm foo b|ar var w = +process.env.COMP_CWORD var words = args.map(unescape) var word = words[w] var line = process.env.COMP_LINE var point = +process.env.COMP_POINT var partialLine = line.substr(0, point) var partialWords = words.slice(0, w) // figure out where in that last word the point is. var partialWord = args[w] var i = partialWord.length while (partialWord.substr(0, i) !== partialLine.substr(-1 * i) && i > 0) { i-- } partialWord = unescape(partialWord.substr(0, i)) partialWords.push(partialWord) var opts = { words: words, w: w, word: word, line: line, lineLength: line.length, point: point, partialLine: partialLine, partialWords: partialWords, partialWord: partialWord, raw: args } cb = wrapCb(cb, opts) console.error(opts) if (partialWords.slice(0, -1).indexOf('--') === -1) { if (word.charAt(0) === '-') return configCompl(opts, cb) if (words[w - 1] && words[w - 1].charAt(0) === '-' && !isFlag(words[w - 1])) { // awaiting a value for a non-bool config. // don't even try to do this for now console.error('configValueCompl') return configValueCompl(opts, cb) } } // try to find the npm command. // it's the first thing after all the configs. // take a little shortcut and use npm's arg parsing logic. // don't have to worry about the last arg being implicitly // boolean'ed, since the last block will catch that. var parsed = opts.conf = nopt(configTypes, shorthands, partialWords.slice(0, -1), 0) // check if there's a command already. console.error(parsed) var cmd = parsed.argv.remain[1] if (!cmd) return cmdCompl(opts, cb) Object.keys(parsed).forEach(function (k) { npm.config.set(k, parsed[k]) }) // at this point, if words[1] is some kind of npm command, // then complete on it. // otherwise, do nothing cmd = npm.commands[cmd] if (cmd && cmd.completion) return cmd.completion(opts, cb) // nothing to do. cb() } function dumpScript (cb) { var fs = require('graceful-fs') var path = require('path') var p = path.resolve(__dirname, 'utils/completion.sh') // The Darwin patch below results in callbacks first for the write and then // for the error handler, so make sure we only call our callback once. cb = once(cb) fs.readFile(p, 'utf8', function (er, d) { if (er) return cb(er) d = d.replace(/^#!.*?\n/, '') process.stdout.write(d, function () { cb() }) process.stdout.on('error', function (er) { // Darwin is a pain sometimes. // // This is necessary because the "source" or "." program in // bash on OS X closes its file argument before reading // from it, meaning that you get exactly 1 write, which will // work most of the time, and will always raise an EPIPE. // // Really, one should not be tossing away EPIPE errors, or any // errors, so casually. But, without this, `. <(npm completion)` // can never ever work on OS X. if (er.errno === 'EPIPE') er = null cb(er) }) }) } function unescape (w) { if (w.charAt(0) === '\'') return w.replace(/^'|'$/g, '') else return w.replace(/\\ /g, ' ') } function escape (w) { if (!w.match(/\s+/)) return w return '\'' + w + '\'' } // The command should respond with an array. Loop over that, // wrapping quotes around any that have spaces, and writing // them to stdout. Use console.log, not the outfd config. // If any of the items are arrays, then join them with a space. // Ie, returning ['a', 'b c', ['d', 'e']] would allow it to expand // to: 'a', 'b c', or 'd' 'e' function wrapCb (cb, opts) { return function (er, compls) { if (!Array.isArray(compls)) compls = compls ? [compls] : [] compls = compls.map(function (c) { if (Array.isArray(c)) c = c.map(escape).join(' ') else c = escape(c) return c }) if (opts.partialWord) { compls = compls.filter(function (c) { return c.indexOf(opts.partialWord) === 0 }) } console.error([er && er.stack, compls, opts.partialWord]) if (er || compls.length === 0) return cb(er) output(compls.join('\n')) cb() } } // the current word has a dash. Return the config names, // with the same number of dashes as the current word has. function configCompl (opts, cb) { var word = opts.word var split = word.match(/^(-+)((?:no-)*)(.*)$/) var dashes = split[1] var no = split[2] var flags = configNames.filter(isFlag) console.error(flags) return cb(null, allConfs.map(function (c) { return dashes + c }).concat(flags.map(function (f) { return dashes + (no || 'no-') + f }))) } // expand with the valid values of various config values. // not yet implemented. function configValueCompl (opts, cb) { console.error('configValue', opts) return cb(null, []) } // check if the thing is a flag or not. function isFlag (word) { // shorthands never take args. var split = word.match(/^(-*)((?:no-)+)?(.*)$/) var no = split[2] var conf = split[3] return no || configTypes[conf] === Boolean || shorthands[conf] } // complete against the npm commands function cmdCompl (opts, cb) { return cb(null, npm.fullList) } config.js000064400000016674152231567050006373 0ustar00/* eslint-disable standard/no-callback-literal */ module.exports = config var log = require('npmlog') var npm = require('./npm.js') var npmconf = require('./config/core.js') var fs = require('graceful-fs') var writeFileAtomic = require('write-file-atomic') var types = npmconf.defs.types var ini = require('ini') var editor = require('editor') var os = require('os') var path = require('path') var mkdirp = require('gentle-fs').mkdir var umask = require('./utils/umask') var usage = require('./utils/usage') var output = require('./utils/output') var noProgressTillDone = require('./utils/no-progress-while-running').tillDone config.usage = usage( 'config', 'npm config set ' + '\nnpm config get []' + '\nnpm config delete ' + '\nnpm config list [--json]' + '\nnpm config edit' + '\nnpm set ' + '\nnpm get []' ) config.completion = function (opts, cb) { var argv = opts.conf.argv.remain if (argv[1] !== 'config') argv.unshift('config') if (argv.length === 2) { var cmds = ['get', 'set', 'delete', 'ls', 'rm', 'edit'] if (opts.partialWord !== 'l') cmds.push('list') return cb(null, cmds) } var action = argv[2] switch (action) { case 'set': // todo: complete with valid values, if possible. if (argv.length > 3) return cb(null, []) // fallthrough /* eslint no-fallthrough:0 */ case 'get': case 'delete': case 'rm': return cb(null, Object.keys(types)) case 'edit': case 'list': case 'ls': return cb(null, []) default: return cb(null, []) } } // npm config set key value // npm config get key // npm config list function config (args, cb) { var action = args.shift() switch (action) { case 'set': return set(args[0], args[1], cb) case 'get': return get(args[0], cb) case 'delete': case 'rm': case 'del': return del(args[0], cb) case 'list': case 'ls': return npm.config.get('json') ? listJson(cb) : list(cb) case 'edit': return edit(cb) default: return unknown(action, cb) } } function edit (cb) { var e = npm.config.get('editor') var which = npm.config.get('global') ? 'global' : 'user' var f = npm.config.get(which + 'config') if (!e) return cb(new Error('No EDITOR config or environ set.')) npm.config.save(which, function (er) { if (er) return cb(er) fs.readFile(f, 'utf8', function (er, data) { if (er) data = '' data = [ ';;;;', '; npm ' + (npm.config.get('global') ? 'globalconfig' : 'userconfig') + ' file', '; this is a simple ini-formatted file', '; lines that start with semi-colons are comments.', '; read `npm help config` for help on the various options', ';;;;', '', data ].concat([ ';;;;', '; all options with default values', ';;;;' ]).concat(Object.keys(npmconf.defaults).reduce(function (arr, key) { var obj = {} obj[key] = npmconf.defaults[key] if (key === 'logstream') return arr return arr.concat( ini.stringify(obj) .replace(/\n$/m, '') .replace(/^/g, '; ') .replace(/\n/g, '\n; ') .split('\n')) }, [])) .concat(['']) .join(os.EOL) mkdirp(path.dirname(f), function (er) { if (er) return cb(er) writeFileAtomic( f, data, function (er) { if (er) return cb(er) editor(f, { editor: e }, noProgressTillDone(cb)) } ) }) }) }) } function del (key, cb) { if (!key) return cb(new Error('no key provided')) var where = npm.config.get('global') ? 'global' : 'user' npm.config.del(key, where) npm.config.save(where, cb) } function set (key, val, cb) { if (key === undefined) { return unknown('', cb) } if (val === undefined) { if (key.indexOf('=') !== -1) { var k = key.split('=') key = k.shift() val = k.join('=') } else { val = '' } } key = key.trim() val = val.trim() log.info('config', 'set %j %j', key, val) var where = npm.config.get('global') ? 'global' : 'user' if (key.match(/umask/)) val = umask.fromString(val) npm.config.set(key, val, where) npm.config.save(where, cb) } function get (key, cb) { if (!key) return list(cb) if (!publicVar(key)) { return cb(new Error('---sekretz---')) } var val = npm.config.get(key) if (key.match(/umask/)) val = umask.toString(val) output(val) cb() } function sort (a, b) { return a > b ? 1 : -1 } function publicVar (k) { return !(k.charAt(0) === '_' || k.indexOf(':_') !== -1) } function getKeys (data) { return Object.keys(data).filter(publicVar).sort(sort) } function listJson (cb) { const publicConf = npm.config.keys.reduce((publicConf, k) => { var value = npm.config.get(k) if (publicVar(k) && // argv is not really config, it's command config k !== 'argv' && // logstream is a Stream, and would otherwise produce circular refs k !== 'logstream') publicConf[k] = value return publicConf }, {}) output(JSON.stringify(publicConf, null, 2)) return cb() } function listFromSource (title, conf, long) { var confKeys = getKeys(conf) var msg = '' if (confKeys.length) { msg += '; ' + title + '\n' confKeys.forEach(function (k) { var val = JSON.stringify(conf[k]) if (conf[k] !== npm.config.get(k)) { if (!long) return msg += '; ' + k + ' = ' + val + ' (overridden)\n' } else msg += k + ' = ' + val + '\n' }) msg += '\n' } return msg } function list (cb) { var msg = '' var long = npm.config.get('long') var cli = npm.config.sources.cli.data var cliKeys = getKeys(cli) if (cliKeys.length) { msg += '; cli configs\n' cliKeys.forEach(function (k) { if (cli[k] && typeof cli[k] === 'object') return if (k === 'argv') return msg += k + ' = ' + JSON.stringify(cli[k]) + '\n' }) msg += '\n' } // env configs msg += listFromSource('environment configs', npm.config.sources.env.data, long) // project config file var project = npm.config.sources.project msg += listFromSource('project config ' + project.path, project.data, long) // user config file msg += listFromSource('userconfig ' + npm.config.get('userconfig'), npm.config.sources.user.data, long) // global config file msg += listFromSource('globalconfig ' + npm.config.get('globalconfig'), npm.config.sources.global.data, long) // builtin config file var builtin = npm.config.sources.builtin || {} if (builtin && builtin.data) { msg += listFromSource('builtin config ' + builtin.path, builtin.data, long) } // only show defaults if --long if (!long) { msg += '; node bin location = ' + process.execPath + '\n' + '; cwd = ' + process.cwd() + '\n' + '; HOME = ' + process.env.HOME + '\n' + '; "npm config ls -l" to show all defaults.\n' output(msg) return cb() } var defaults = npmconf.defaults var defKeys = getKeys(defaults) msg += '; default values\n' defKeys.forEach(function (k) { if (defaults[k] && typeof defaults[k] === 'object') return var val = JSON.stringify(defaults[k]) if (defaults[k] !== npm.config.get(k)) { msg += '; ' + k + ' = ' + val + ' (overridden)\n' } else msg += k + ' = ' + val + '\n' }) msg += '\n' output(msg) return cb() } function unknown (action, cb) { cb('Usage:\n' + config.usage) } dedupe.js000064400000011607152231567050006363 0ustar00var util = require('util') var path = require('path') var validate = require('aproba') var without = require('lodash.without') var asyncMap = require('slide').asyncMap var chain = require('slide').chain var npa = require('npm-package-arg') var log = require('npmlog') var npm = require('./npm.js') var Installer = require('./install.js').Installer var findRequirement = require('./install/deps.js').findRequirement var earliestInstallable = require('./install/deps.js').earliestInstallable var checkPermissions = require('./install/check-permissions.js') var decomposeActions = require('./install/decompose-actions.js') var loadExtraneous = require('./install/deps.js').loadExtraneous var computeMetadata = require('./install/deps.js').computeMetadata var sortActions = require('./install/diff-trees.js').sortActions var moduleName = require('./utils/module-name.js') var packageId = require('./utils/package-id.js') var childPath = require('./utils/child-path.js') var usage = require('./utils/usage') var getRequested = require('./install/get-requested.js') module.exports = dedupe module.exports.Deduper = Deduper dedupe.usage = usage( 'dedupe', 'npm dedupe' ) function dedupe (args, cb) { validate('AF', arguments) // the /path/to/node_modules/.. var where = path.resolve(npm.dir, '..') var dryrun = false if (npm.command.match(/^find/)) dryrun = true if (npm.config.get('dry-run')) dryrun = true if (dryrun && !npm.config.get('json')) npm.config.set('parseable', true) new Deduper(where, dryrun).run(cb) } function Deduper (where, dryrun) { validate('SB', arguments) Installer.call(this, where, dryrun, []) this.noPackageJsonOk = true this.topLevelLifecycles = false } util.inherits(Deduper, Installer) Deduper.prototype.loadIdealTree = function (cb) { validate('F', arguments) log.silly('install', 'loadIdealTree') var self = this chain([ [this.newTracker(this.progress.loadIdealTree, 'cloneCurrentTree')], [this, this.cloneCurrentTreeToIdealTree], [this, this.finishTracker, 'cloneCurrentTree'], [this.newTracker(this.progress.loadIdealTree, 'loadAllDepsIntoIdealTree', 10)], [ function (next) { loadExtraneous(self.idealTree, self.progress.loadAllDepsIntoIdealTree, next) } ], [this, this.finishTracker, 'loadAllDepsIntoIdealTree'], [this, andComputeMetadata(this.idealTree)] ], cb) } function andComputeMetadata (tree) { return function (next) { next(null, computeMetadata(tree)) } } Deduper.prototype.generateActionsToTake = function (cb) { validate('F', arguments) log.silly('dedupe', 'generateActionsToTake') chain([ [this.newTracker(log, 'hoist', 1)], [hoistChildren, this.idealTree, this.differences], [this, this.finishTracker, 'hoist'], [this.newTracker(log, 'sort-actions', 1)], [this, function (next) { this.differences = sortActions(this.differences) next() }], [this, this.finishTracker, 'sort-actions'], [checkPermissions, this.differences], [decomposeActions, this.differences, this.todo] ], cb) } function move (node, hoistTo, diff) { node.parent.children = without(node.parent.children, node) hoistTo.children.push(node) node.fromPath = node.path node.path = childPath(hoistTo.path, node) node.parent = hoistTo if (!diff.filter(function (action) { return action[0] === 'move' && action[1] === node }).length) { diff.push(['move', node]) } } function moveRemainingChildren (node, diff) { node.children.forEach(function (child) { move(child, node, diff) moveRemainingChildren(child, diff) }) } function remove (child, diff, done) { remove_(child, diff, new Set(), done) } function remove_ (child, diff, seen, done) { if (seen.has(child)) return done() seen.add(child) diff.push(['remove', child]) child.parent.children = without(child.parent.children, child) asyncMap(child.children, function (child, next) { remove_(child, diff, seen, next) }, done) } function hoistChildren (tree, diff, next) { hoistChildren_(tree, diff, new Set(), next) } function hoistChildren_ (tree, diff, seen, next) { validate('OAOF', arguments) if (seen.has(tree)) return next() seen.add(tree) asyncMap(tree.children, function (child, done) { if (!tree.parent || child.fromBundle || child.package._inBundle) return hoistChildren_(child, diff, seen, done) var better = findRequirement(tree.parent, moduleName(child), getRequested(child) || npa(packageId(child))) if (better) { return chain([ [remove, child, diff], [andComputeMetadata(tree)] ], done) } var hoistTo = earliestInstallable(tree, tree.parent, child.package, log) if (hoistTo) { move(child, hoistTo, diff) chain([ [andComputeMetadata(hoistTo)], [hoistChildren_, child, diff, seen], [ function (next) { moveRemainingChildren(child, diff) next() } ] ], done) } else { done() } }, next) } deprecate.js000064400000004155152231567050007051 0ustar00'use strict' const BB = require('bluebird') const npmConfig = require('./config/figgy-config.js') const fetch = require('libnpm/fetch') const figgyPudding = require('figgy-pudding') const otplease = require('./utils/otplease.js') const npa = require('libnpm/parse-arg') const semver = require('semver') const whoami = require('./whoami.js') const DeprecateConfig = figgyPudding({}) module.exports = deprecate deprecate.usage = 'npm deprecate [@] ' deprecate.completion = function (opts, cb) { return BB.try(() => { if (opts.conf.argv.remain.length > 2) { return } return whoami([], true, () => {}).then(username => { if (username) { // first, get a list of remote packages this user owns. // once we have a user account, then don't complete anything. // get the list of packages by user return fetch( `/-/by-user/${encodeURIComponent(username)}`, DeprecateConfig() ).then(list => list[username]) } }) }).nodeify(cb) } function deprecate ([pkg, msg], opts, cb) { if (typeof cb !== 'function') { cb = opts opts = null } opts = DeprecateConfig(opts || npmConfig()) return BB.try(() => { if (msg == null) throw new Error(`Usage: ${deprecate.usage}`) // fetch the data and make sure it exists. const p = npa(pkg) // npa makes the default spec "latest", but for deprecation // "*" is the appropriate default. const spec = p.rawSpec === '' ? '*' : p.fetchSpec if (semver.validRange(spec, true) === null) { throw new Error('invalid version range: ' + spec) } const uri = '/' + p.escapedName return fetch.json(uri, opts.concat({ spec: p, query: {write: true} })).then(packument => { // filter all the versions that match Object.keys(packument.versions) .filter(v => semver.satisfies(v, spec)) .forEach(v => { packument.versions[v].deprecated = msg }) return otplease(opts, opts => fetch(uri, opts.concat({ spec: p, method: 'PUT', body: packument, ignoreBody: true }))) }) }).nodeify(cb) } dist-tag.js000064400000010154152231567050006625 0ustar00/* eslint-disable standard/no-callback-literal */ module.exports = distTag const BB = require('bluebird') const figgyPudding = require('figgy-pudding') const log = require('npmlog') const npa = require('libnpm/parse-arg') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const readLocalPkg = BB.promisify(require('./utils/read-local-package.js')) const regFetch = require('libnpm/fetch') const semver = require('semver') const usage = require('./utils/usage') const DistTagOpts = figgyPudding({ tag: {} }) distTag.usage = usage( 'dist-tag', 'npm dist-tag add @ []' + '\nnpm dist-tag rm ' + '\nnpm dist-tag ls []' ) distTag.completion = function (opts, cb) { var argv = opts.conf.argv.remain if (argv.length === 2) { return cb(null, ['add', 'rm', 'ls']) } switch (argv[2]) { default: return cb() } } function UsageError () { throw Object.assign(new Error('Usage:\n' + distTag.usage), { code: 'EUSAGE' }) } function distTag ([cmd, pkg, tag], cb) { const opts = DistTagOpts(npmConfig()) return BB.try(() => { switch (cmd) { case 'add': case 'a': case 'set': case 's': return add(pkg, tag, opts) case 'rm': case 'r': case 'del': case 'd': case 'remove': return remove(pkg, tag, opts) case 'ls': case 'l': case 'sl': case 'list': return list(pkg, opts) default: if (!pkg) { return list(cmd, opts) } else { UsageError() } } }).then( x => cb(null, x), err => { if (err.code === 'EUSAGE') { cb(err.message) } else { cb(err) } } ) } function add (spec, tag, opts) { spec = npa(spec || '') const version = spec.rawSpec const t = (tag || opts.tag).trim() log.verbose('dist-tag add', t, 'to', spec.name + '@' + version) if (!spec || !version || !t) UsageError() if (semver.validRange(t)) { throw new Error('Tag name must not be a valid SemVer range: ' + t) } return fetchTags(spec, opts).then(tags => { if (tags[t] === version) { log.warn('dist-tag add', t, 'is already set to version', version) return } tags[t] = version const url = `/-/package/${spec.escapedName}/dist-tags/${encodeURIComponent(t)}` const reqOpts = opts.concat({ method: 'PUT', body: JSON.stringify(version), headers: { 'content-type': 'application/json' }, spec }) return otplease(reqOpts, reqOpts => regFetch(url, reqOpts)).then(() => { output(`+${t}: ${spec.name}@${version}`) }) }) } function remove (spec, tag, opts) { spec = npa(spec || '') log.verbose('dist-tag del', tag, 'from', spec.name) return fetchTags(spec, opts).then(tags => { if (!tags[tag]) { log.info('dist-tag del', tag, 'is not a dist-tag on', spec.name) throw new Error(tag + ' is not a dist-tag on ' + spec.name) } const version = tags[tag] delete tags[tag] const url = `/-/package/${spec.escapedName}/dist-tags/${encodeURIComponent(tag)}` const reqOpts = opts.concat({ method: 'DELETE', spec }) return otplease(reqOpts, reqOpts => regFetch(url, reqOpts)).then(() => { output(`-${tag}: ${spec.name}@${version}`) }) }) } function list (spec, opts) { if (!spec) { return readLocalPkg().then(pkg => { if (!pkg) { UsageError() } return list(pkg, opts) }) } spec = npa(spec) return fetchTags(spec, opts).then(tags => { var msg = Object.keys(tags).map(k => `${k}: ${tags[k]}`).sort().join('\n') output(msg) return tags }, err => { log.error('dist-tag ls', "Couldn't get dist-tag data for", spec) throw err }) } function fetchTags (spec, opts) { return regFetch.json( `/-/package/${spec.escapedName}/dist-tags`, opts.concat({ 'prefer-online': true, spec }) ).then(data => { if (data && typeof data === 'object') delete data._etag if (!data || !Object.keys(data).length) { throw new Error('No dist-tags found for ' + spec.name) } return data }) } docs.js000064400000002047152231567050006043 0ustar00module.exports = docs var openUrl = require('./utils/open-url') var log = require('npmlog') var fetchPackageMetadata = require('./fetch-package-metadata.js') var usage = require('./utils/usage') docs.usage = usage( 'docs', 'npm docs ' + '\nnpm docs .' ) docs.completion = function (opts, cb) { // FIXME: there used to be registry completion here, but it stopped making // sense somewhere around 50,000 packages on the registry cb() } function docs (args, cb) { if (!args || !args.length) args = ['.'] var pending = args.length log.silly('docs', args) args.forEach(function (proj) { getDoc(proj, function (err) { if (err) { return cb(err) } --pending || cb() }) }) } function getDoc (project, cb) { log.silly('getDoc', project) fetchPackageMetadata(project, '.', {fullMetadata: true}, function (er, d) { if (er) return cb(er) var url = d.homepage if (!url) url = 'https://www.npmjs.org/package/' + d.name return openUrl(url, 'docs available at the following URL', cb) }) } doctor.js000064400000007753152231567050006416 0ustar00'use strict' const ansiTrim = require('./utils/ansi-trim') const chain = require('slide').chain const color = require('ansicolors') const defaultRegistry = require('./config/defaults').defaults.registry const log = require('npmlog') const npm = require('./npm') const output = require('./utils/output') const path = require('path') const semver = require('semver') const styles = require('ansistyles') const table = require('text-table') // steps const checkFilesPermission = require('./doctor/check-files-permission') const checkPing = require('./doctor/check-ping') const getGitPath = require('./doctor/get-git-path') const getLatestNodejsVersion = require('./doctor/get-latest-nodejs-version') const getLatestNpmVersion = require('./doctor/get-latest-npm-version') const verifyCachedFiles = require('./doctor/verify-cached-files') const globalNodeModules = path.join(npm.config.globalPrefix, 'lib', 'node_modules') const localNodeModules = path.join(npm.config.localPrefix, 'node_modules') module.exports = doctor doctor.usage = 'npm doctor' function doctor (args, silent, cb) { args = args || {} if (typeof cb !== 'function') { cb = silent silent = false } const actionsToRun = [ [checkPing], [getLatestNpmVersion], [getLatestNodejsVersion, args['node-url']], [getGitPath], [checkFilesPermission, npm.cache, 4, 6], [checkFilesPermission, globalNodeModules, 4, 4], [checkFilesPermission, localNodeModules, 6, 6], [verifyCachedFiles, path.join(npm.cache, '_cacache')] ] log.info('doctor', 'Running checkup') chain(actionsToRun, function (stderr, stdout) { if (stderr && stderr.message !== 'not found: git') return cb(stderr) const list = makePretty(stdout) let outHead = ['Check', 'Value', 'Recommendation'] let outBody = list if (npm.color) { outHead = outHead.map(function (item) { return styles.underline(item) }) outBody = outBody.map(function (item) { if (item[2]) { item[0] = color.red(item[0]) item[2] = color.magenta(item[2]) } return item }) } const outTable = [outHead].concat(outBody) const tableOpts = { stringLength: function (s) { return ansiTrim(s).length } } if (!silent) output(table(outTable, tableOpts)) cb(null, list) }) } function makePretty (p) { const ping = p[1] const npmLTS = p[2] const nodeLTS = p[3].replace('v', '') const whichGit = p[4] || 'not installed' const readbleCaches = p[5] ? 'ok' : 'notOk' const executableGlobalModules = p[6] ? 'ok' : 'notOk' const executableLocalModules = p[7] ? 'ok' : 'notOk' const cacheStatus = p[8] ? `verified ${p[8].verifiedContent} tarballs` : 'notOk' const npmV = npm.version const nodeV = process.version.replace('v', '') const registry = npm.config.get('registry') || '' const list = [ ['npm ping', ping], ['npm -v', 'v' + npmV], ['node -v', 'v' + nodeV], ['npm config get registry', registry], ['which git', whichGit], ['Perms check on cached files', readbleCaches], ['Perms check on global node_modules', executableGlobalModules], ['Perms check on local node_modules', executableLocalModules], ['Verify cache contents', cacheStatus] ] if (p[0] !== 200) list[0][2] = 'Check your internet connection' if (!semver.satisfies(npmV, '>=' + npmLTS)) list[1][2] = 'Use npm v' + npmLTS if (!semver.satisfies(nodeV, '>=' + nodeLTS)) list[2][2] = 'Use node v' + nodeLTS if (registry !== defaultRegistry) list[3][2] = 'Try `npm config set registry ' + defaultRegistry + '`' if (whichGit === 'not installed') list[4][2] = 'Install git and ensure it\'s in your PATH.' if (readbleCaches !== 'ok') list[5][2] = 'Check the permissions of your files in ' + npm.config.get('cache') if (executableGlobalModules !== 'ok') list[6][2] = globalNodeModules + ' must be readable and writable by the current user.' if (executableLocalModules !== 'ok') list[7][2] = localNodeModules + ' must be readable and writable by the current user.' return list } edit.js000064400000002577152231567050006050 0ustar00// npm edit // open the package folder in the $EDITOR module.exports = edit edit.usage = 'npm edit [/...]' edit.completion = require('./utils/completion/installed-shallow.js') var npm = require('./npm.js') var path = require('path') var fs = require('graceful-fs') var editor = require('editor') var noProgressTillDone = require('./utils/no-progress-while-running').tillDone function edit (args, cb) { var p = args[0] if (args.length !== 1 || !p) return cb(edit.usage) var e = npm.config.get('editor') if (!e) { return cb(new Error( "No editor set. Set the 'editor' config, or $EDITOR environ." )) } p = p.split('/') // combine scoped parts .reduce(function (parts, part) { if (parts.length === 0) { return [part] } var lastPart = parts[parts.length - 1] // check if previous part is the first part of a scoped package if (lastPart[0] === '@' && !lastPart.includes('/')) { parts[parts.length - 1] += '/' + part } else { parts.push(part) } return parts }, []) .join('/node_modules/') .replace(/(\/node_modules)+/, '/node_modules') var f = path.resolve(npm.dir, p) fs.lstat(f, function (er) { if (er) return cb(er) editor(f, { editor: e }, noProgressTillDone(function (er) { if (er) return cb(er) npm.commands.rebuild(args, cb) })) }) } explore.js000064400000003255152231567050006573 0ustar00// npm explore [@] // open a subshell to the package folder. module.exports = explore explore.usage = 'npm explore [ -- ]' explore.completion = require('./utils/completion/installed-shallow.js') var npm = require('./npm.js') var spawn = require('./utils/spawn') var path = require('path') var fs = require('graceful-fs') var isWindows = require('./utils/is-windows.js') var escapeExecPath = require('./utils/escape-exec-path.js') var escapeArg = require('./utils/escape-arg.js') var output = require('./utils/output.js') var log = require('npmlog') function explore (args, cb) { if (args.length < 1 || !args[0]) return cb(explore.usage) var p = args.shift() var cwd = path.resolve(npm.dir, p) var opts = {cwd: cwd, stdio: 'inherit'} var shellArgs = [] if (args.length) { if (isWindows) { var execCmd = escapeExecPath(args.shift()) var execArgs = [execCmd].concat(args.map(escapeArg)) opts.windowsVerbatimArguments = true shellArgs = ['/d', '/s', '/c'].concat(execArgs) } else { shellArgs = ['-c', args.map(escapeArg).join(' ').trim()] } } var sh = npm.config.get('shell') fs.stat(cwd, function (er, s) { if (er || !s.isDirectory()) { return cb(new Error( "It doesn't look like " + p + ' is installed.' )) } if (!shellArgs.length) { output( '\nExploring ' + cwd + '\n' + "Type 'exit' or ^D when finished\n" ) } log.silly('explore', {sh, shellArgs, opts}) var shell = spawn(sh, shellArgs, opts) shell.on('close', function (er) { // only fail if non-interactive. if (!shellArgs.length) return cb() cb(er) }) }) } fetch-package-metadata.js000064400000007740152231567050011360 0ustar00'use strict' const deprCheck = require('./utils/depr-check') const path = require('path') const log = require('npmlog') const pacote = require('pacote') const readPackageTree = require('read-package-tree') const rimraf = require('rimraf') const validate = require('aproba') const npa = require('npm-package-arg') const npm = require('./npm') let npmConfig const npmlog = require('npmlog') const limit = require('call-limit') const tempFilename = require('./utils/temp-filename.js') const replaceInfo = require('./utils/replace-info.js') const isWindows = require('./utils/is-windows.js') function andLogAndFinish (spec, tracker, done) { validate('SOF|SZF|OOF|OZF', [spec, tracker, done]) return (er, pkg) => { if (er) { er.message = replaceInfo(er.message) var spc = replaceInfo(String(spec)) log.silly('fetchPackageMetaData', 'error for ' + spc, er.message) if (tracker) tracker.finish() } return done(er, pkg) } } const LRUCache = require('lru-cache') const CACHE = new LRUCache({ max: 300 * 1024 * 1024, length: (p) => p._contentLength }) module.exports = limit(fetchPackageMetadata, npm.limit.fetch) function fetchPackageMetadata (spec, where, opts, done) { validate('SSOF|SSFZ|OSOF|OSFZ', [spec, where, opts, done]) if (!done) { done = opts opts = {} } var tracker = opts.tracker const logAndFinish = andLogAndFinish(spec, tracker, done) if (typeof spec === 'object') { var dep = spec } else { dep = npa(spec) } if (!isWindows && dep.type === 'directory' && /^[a-zA-Z]:/.test(dep.fetchSpec)) { var err = new Error(`Can't install from windows path on a non-windows system: ${dep.fetchSpec.replace(/[/]/g, '\\')}`) err.code = 'EWINDOWSPATH' return logAndFinish(err) } if (!npmConfig) { npmConfig = require('./config/figgy-config.js') } pacote.manifest(dep, npmConfig({ annotate: true, fullMetadata: opts.fullMetadata, log: tracker || npmlog, memoize: CACHE, where: where })).then( (pkg) => logAndFinish(null, deprCheck(pkg)), (err) => { if (dep.type !== 'directory') return logAndFinish(err) if (err.code === 'ENOTDIR') { var enolocal = new Error(`Could not install "${path.relative(process.cwd(), dep.fetchSpec)}" as it is not a directory and is not a file with a name ending in .tgz, .tar.gz or .tar`) enolocal.code = 'ENOLOCAL' if (err.stack) enolocal.stack = err.stack return logAndFinish(enolocal) } else if (err.code === 'ENOPACKAGEJSON') { var enopackage = new Error(`Could not install from "${path.relative(process.cwd(), dep.fetchSpec)}" as it does not contain a package.json file.`) enopackage.code = 'ENOLOCAL' if (err.stack) enopackage.stack = err.stack return logAndFinish(enopackage) } else { return logAndFinish(err) } } ) } module.exports.addBundled = addBundled function addBundled (pkg, next) { validate('OF', arguments) if (pkg._bundled !== undefined) return next(null, pkg) if (!pkg.bundleDependencies && pkg._requested.type !== 'directory') return next(null, pkg) const requested = pkg._requested || npa(pkg._from) if (requested.type === 'directory') { pkg._bundled = null return readPackageTree(pkg._requested.fetchSpec, function (er, tree) { if (tree) pkg._bundled = tree.children return next(null, pkg) }) } pkg._bundled = null const target = tempFilename('unpack') if (!npmConfig) { npmConfig = require('./config/figgy-config.js') } const opts = npmConfig({integrity: pkg._integrity}) pacote.extract(pkg._resolved || pkg._requested || npa.resolve(pkg.name, pkg.version), target, opts).then(() => { log.silly('addBundled', 'read tarball') readPackageTree(target, (err, tree) => { if (err) { return next(err) } log.silly('cleanup', 'remove extracted module') rimraf(target, function () { if (tree) { pkg._bundled = tree.children } next(null, pkg) }) }) }, next) } fetch-package-metadata.md000064400000003423152231567050011336 0ustar00fetch-package-metadata ---------------------- const fetchPackageMetadata = require("npm/lib/fetch-package-metadata") fetchPackageMetadata(spec, contextdir, callback) This will get package metadata (and if possible, ONLY package metadata) for a specifier as passed to `npm install` et al, eg `npm@next` or `npm@^2.0.3` ## fetchPackageMetadata(*spec*, *contextdir*, *tracker*, *callback*) * *spec* **string** | **object** -- The package specifier, can be anything npm can understand (see [realize-package-specifier]), or it can be the result from realize-package-specifier or npm-package-arg (for non-local deps). * *contextdir* **string** -- The directory from which relative paths to local packages should be resolved. * *tracker* **object** -- **(optional)** An are-we-there-yet tracker group as provided by `npm.log.newGroup()`. * *callback* **function (er, package)** -- Called when the package information has been loaded. `package` is the object for of the `package.json` matching the requested spec. In the case of named packages, it comes from the registry and thus may not exactly match what's found in the associated tarball. [realize-package-specifier]: (https://github.com/npm/realize-package-specifier) In the case of tarballs and git repos, it will use the cache to download them in order to get the package metadata. For named packages, only the metadata is downloaded (eg https://registry.npmjs.org/package). For local directories, the package.json is read directly. For local tarballs, the tarball is streamed in memory and just the package.json is extracted from it. (Due to the nature of tars, having the package.json early in the file will result in it being loaded faster– the extractor short-circuits the uncompress/untar streams as best as it can.) fund.js000064400000011642152231567050006050 0ustar00'use strict' const path = require('path') const archy = require('archy') const figgyPudding = require('figgy-pudding') const readPackageTree = require('read-package-tree') const npm = require('./npm.js') const npmConfig = require('./config/figgy-config.js') const fetchPackageMetadata = require('./fetch-package-metadata.js') const computeMetadata = require('./install/deps.js').computeMetadata const readShrinkwrap = require('./install/read-shrinkwrap.js') const mutateIntoLogicalTree = require('./install/mutate-into-logical-tree.js') const output = require('./utils/output.js') const openUrl = require('./utils/open-url.js') const { getFundingInfo, retrieveFunding, validFundingField, flatCacheSymbol } = require('./utils/funding.js') const FundConfig = figgyPudding({ browser: {}, // used by ./utils/open-url global: {}, json: {}, unicode: {}, which: {} }) module.exports = fundCmd const usage = require('./utils/usage') fundCmd.usage = usage( 'fund', 'npm fund [--json]', 'npm fund [--browser] [[<@scope>/] [--which=]' ) fundCmd.completion = function (opts, cb) { const argv = opts.conf.argv.remain switch (argv[2]) { case 'fund': return cb(null, []) default: return cb(new Error(argv[2] + ' not recognized')) } } function printJSON (fundingInfo) { return JSON.stringify(fundingInfo, null, 2) } // the human-printable version does some special things that turned out to // be very verbose but hopefully not hard to follow: we stack up items // that have a shared url/type and make sure they're printed at the highest // level possible, in that process they also carry their dependencies along // with them, moving those up in the visual tree function printHuman (fundingInfo, opts) { const flatCache = fundingInfo[flatCacheSymbol] const { name, version } = fundingInfo const printableVersion = version ? `@${version}` : '' const items = Object.keys(flatCache).map((url) => { const deps = flatCache[url] const packages = deps.map((dep) => { const { name, version } = dep const printableVersion = version ? `@${version}` : '' return `${name}${printableVersion}` }) return { label: url, nodes: [packages.join(', ')] } }) return archy({ label: `${name}${printableVersion}`, nodes: items }, '', { unicode: opts.unicode }) } function openFundingUrl (packageName, fundingSourceNumber, cb) { function getUrlAndOpen (packageMetadata) { const { funding } = packageMetadata const validSources = [].concat(retrieveFunding(funding)).filter(validFundingField) if (validSources.length === 1 || (fundingSourceNumber > 0 && fundingSourceNumber <= validSources.length)) { const { type, url } = validSources[fundingSourceNumber ? fundingSourceNumber - 1 : 0] const typePrefix = type ? `${type} funding` : 'Funding' const msg = `${typePrefix} available at the following URL` openUrl(url, msg, cb) } else if (!(fundingSourceNumber >= 1)) { validSources.forEach(({ type, url }, i) => { const typePrefix = type ? `${type} funding` : 'Funding' const msg = `${typePrefix} available at the following URL` console.log(`${i + 1}: ${msg}: ${url}`) }) console.log('Run `npm fund [<@scope>/] --which=1`, for example, to open the first funding URL listed in that package') cb() } else { const noFundingError = new Error(`No valid funding method available for: ${packageName}`) noFundingError.code = 'ENOFUND' throw noFundingError } } fetchPackageMetadata( packageName, '.', { fullMetadata: true }, function (err, packageMetadata) { if (err) return cb(err) getUrlAndOpen(packageMetadata) } ) } function fundCmd (args, cb) { const opts = FundConfig(npmConfig()) const dir = path.resolve(npm.dir, '..') const packageName = args[0] const numberArg = opts.which const fundingSourceNumber = numberArg && parseInt(numberArg, 10) if (numberArg !== undefined && (String(fundingSourceNumber) !== numberArg || fundingSourceNumber < 1)) { const err = new Error('`npm fund [<@scope>/] [--which=fundingSourceNumber]` must be given a positive integer') err.code = 'EFUNDNUMBER' throw err } if (opts.global) { const err = new Error('`npm fund` does not support global packages') err.code = 'EFUNDGLOBAL' throw err } if (packageName) { openFundingUrl(packageName, fundingSourceNumber, cb) return } readPackageTree(dir, function (err, tree) { if (err) { process.exitCode = 1 return cb(err) } readShrinkwrap.andInflate(tree, function () { const fundingInfo = getFundingInfo( mutateIntoLogicalTree.asReadInstalled( computeMetadata(tree) ) ) const print = opts.json ? printJSON : printHuman output( print( fundingInfo, opts ) ) cb(err, tree) }) }) } get.js000064400000000353152231567050005670 0ustar00 module.exports = get get.usage = 'npm get (See `npm config`)' var npm = require('./npm.js') get.completion = npm.commands.config.completion function get (args, cb) { npm.commands.config(['get'].concat(args), cb) } help-search.js000064400000013221152231567050007302 0ustar00 module.exports = helpSearch var fs = require('graceful-fs') var path = require('path') var asyncMap = require('slide').asyncMap var npm = require('./npm.js') var glob = require('glob') var color = require('ansicolors') var output = require('./utils/output.js') helpSearch.usage = 'npm help-search ' function helpSearch (args, silent, cb) { if (typeof cb !== 'function') { cb = silent silent = false } if (!args.length) return cb(helpSearch.usage) var docPath = path.resolve(__dirname, '..', 'doc') return glob(docPath + '/*/*.md', function (er, files) { if (er) return cb(er) readFiles(files, function (er, data) { if (er) return cb(er) searchFiles(args, data, function (er, results) { if (er) return cb(er) formatResults(args, results, cb) }) }) }) } function readFiles (files, cb) { var res = {} asyncMap(files, function (file, cb) { fs.readFile(file, 'utf8', function (er, data) { res[file] = data return cb(er) }) }, function (er) { return cb(er, res) }) } function searchFiles (args, files, cb) { var results = [] Object.keys(files).forEach(function (file) { var data = files[file] // skip if no matches at all var match for (var a = 0, l = args.length; a < l && !match; a++) { match = data.toLowerCase().indexOf(args[a].toLowerCase()) !== -1 } if (!match) return var lines = data.split(/\n+/) // if a line has a search term, then skip it and the next line. // if the next line has a search term, then skip all 3 // otherwise, set the line to null. then remove the nulls. l = lines.length for (var i = 0; i < l; i++) { var line = lines[i] var nextLine = lines[i + 1] var ll match = false if (nextLine) { for (a = 0, ll = args.length; a < ll && !match; a++) { match = nextLine.toLowerCase() .indexOf(args[a].toLowerCase()) !== -1 } if (match) { // skip over the next line, and the line after it. i += 2 continue } } match = false for (a = 0, ll = args.length; a < ll && !match; a++) { match = line.toLowerCase().indexOf(args[a].toLowerCase()) !== -1 } if (match) { // skip over the next line i++ continue } lines[i] = null } // now squish any string of nulls into a single null lines = lines.reduce(function (l, r) { if (!(r === null && l[l.length - 1] === null)) l.push(r) return l }, []) if (lines[lines.length - 1] === null) lines.pop() if (lines[0] === null) lines.shift() // now see how many args were found at all. var found = {} var totalHits = 0 lines.forEach(function (line) { args.forEach(function (arg) { var hit = (line || '').toLowerCase() .split(arg.toLowerCase()).length - 1 if (hit > 0) { found[arg] = (found[arg] || 0) + hit totalHits += hit } }) }) var cmd = 'npm help ' if (path.basename(path.dirname(file)) === 'api') { cmd = 'npm apihelp ' } cmd += path.basename(file, '.md').replace(/^npm-/, '') results.push({ file: file, cmd: cmd, lines: lines, found: Object.keys(found), hits: found, totalHits: totalHits }) }) // if only one result, then just show that help section. if (results.length === 1) { return npm.commands.help([results[0].file.replace(/\.md$/, '')], cb) } if (results.length === 0) { output('No results for ' + args.map(JSON.stringify).join(' ')) return cb() } // sort results by number of results found, then by number of hits // then by number of matching lines results = results.sort(function (a, b) { return a.found.length > b.found.length ? -1 : a.found.length < b.found.length ? 1 : a.totalHits > b.totalHits ? -1 : a.totalHits < b.totalHits ? 1 : a.lines.length > b.lines.length ? -1 : a.lines.length < b.lines.length ? 1 : 0 }) cb(null, results) } function formatResults (args, results, cb) { if (!results) return cb(null) var cols = Math.min(process.stdout.columns || Infinity, 80) + 1 var out = results.map(function (res) { var out = res.cmd var r = Object.keys(res.hits) .map(function (k) { return k + ':' + res.hits[k] }).sort(function (a, b) { return a > b ? 1 : -1 }).join(' ') out += ((new Array(Math.max(1, cols - out.length - r.length))) .join(' ')) + r if (!npm.config.get('long')) return out out = '\n\n' + out + '\n' + (new Array(cols)).join('—') + '\n' + res.lines.map(function (line, i) { if (line === null || i > 3) return '' for (var out = line, a = 0, l = args.length; a < l; a++) { var finder = out.toLowerCase().split(args[a].toLowerCase()) var newOut = '' var p = 0 finder.forEach(function (f) { newOut += out.substr(p, f.length) var hilit = out.substr(p + f.length, args[a].length) if (npm.color) hilit = color.bgBlack(color.red(hilit)) newOut += hilit p += f.length + args[a].length }) } return newOut }).join('\n').trim() return out }).join('\n') if (results.length && !npm.config.get('long')) { out = 'Top hits for ' + (args.map(JSON.stringify).join(' ')) + '\n' + (new Array(cols)).join('—') + '\n' + out + '\n' + (new Array(cols)).join('—') + '\n' + '(run with -l or --long to see more context)' } output(out.trim()) cb(null, results) } help.js000064400000014553152231567050006050 0ustar00 module.exports = help help.completion = function (opts, cb) { if (opts.conf.argv.remain.length > 2) return cb(null, []) getSections(cb) } var path = require('path') var spawn = require('./utils/spawn') var npm = require('./npm.js') var log = require('npmlog') var openUrl = require('./utils/open-url') var glob = require('glob') var didYouMean = require('./utils/did-you-mean') var cmdList = require('./config/cmd-list').cmdList var shorthands = require('./config/cmd-list').shorthands var commands = cmdList.concat(Object.keys(shorthands)) var output = require('./utils/output.js') function help (args, cb) { var argv = npm.config.get('argv').cooked var argnum = 0 if (args.length === 2 && ~~args[0]) { argnum = ~~args.shift() } // npm help foo bar baz: search topics if (args.length > 1 && args[0]) { return npm.commands['help-search'](args, argnum, cb) } var section = npm.deref(args[0]) || args[0] // npm help : show basic usage if (!section) { var valid = argv[0] === 'help' ? 0 : 1 return npmUsage(valid, cb) } // npm -h: show command usage if (npm.config.get('usage') && npm.commands[section] && npm.commands[section].usage) { npm.config.set('loglevel', 'silent') log.level = 'silent' output(npm.commands[section].usage) return cb() } // npm apihelp
: Prefer section 3 over section 1 var apihelp = argv.length && argv[0].indexOf('api') !== -1 var pref = apihelp ? [3, 1, 5, 7] : [1, 3, 5, 7] if (argnum) { pref = [ argnum ].concat(pref.filter(function (n) { return n !== argnum })) } // npm help
: Try to find the path var manroot = path.resolve(__dirname, '..', 'man') // legacy if (section === 'global') section = 'folders' else if (section.match(/.*json/)) section = section.replace('.json', '-json') // find either /section.n or /npm-section.n // The glob is used in the glob. The regexp is used much // further down. Globs and regexps are different var compextglob = '.+(gz|bz2|lzma|[FYzZ]|xz)' var compextre = '\\.(gz|bz2|lzma|[FYzZ]|xz)$' var f = '+(npm-' + section + '|' + section + ').[0-9]?(' + compextglob + ')' return glob(manroot + '/*/' + f, function (er, mans) { if (er) return cb(er) if (!mans.length) return npm.commands['help-search'](args, cb) mans = mans.map(function (man) { var ext = path.extname(man) if (man.match(new RegExp(compextre))) man = path.basename(man, ext) return man }) viewMan(pickMan(mans, pref), cb) }) } function pickMan (mans, pref_) { var nre = /([0-9]+)$/ var pref = {} pref_.forEach(function (sect, i) { pref[sect] = i }) mans = mans.sort(function (a, b) { var an = a.match(nre)[1] var bn = b.match(nre)[1] return an === bn ? (a > b ? -1 : 1) : pref[an] < pref[bn] ? -1 : 1 }) return mans[0] } function viewMan (man, cb) { var nre = /([0-9]+)$/ var num = man.match(nre)[1] var section = path.basename(man, '.' + num) // at this point, we know that the specified man page exists var manpath = path.join(__dirname, '..', 'man') var env = {} Object.keys(process.env).forEach(function (i) { env[i] = process.env[i] }) env.MANPATH = manpath var viewer = npm.config.get('viewer') var conf switch (viewer) { case 'woman': var a = ['-e', '(woman-find-file \'' + man + '\')'] conf = { env: env, stdio: 'inherit' } var woman = spawn('emacsclient', a, conf) woman.on('close', cb) break case 'browser': openUrl(htmlMan(man), 'help available at the following URL', cb) break default: conf = { env: env, stdio: 'inherit' } var manProcess = spawn('man', [num, section], conf) manProcess.on('close', cb) break } } function htmlMan (man) { var sect = +man.match(/([0-9]+)$/)[1] var f = path.basename(man).replace(/[.]([0-9]+)$/, '') switch (sect) { case 1: sect = 'cli-commands' break case 5: sect = 'configuring-npm' break case 7: sect = 'using-npm' break default: throw new Error('invalid man section: ' + sect) } return path.resolve(__dirname, '..', 'docs', 'public', sect, f, 'index.html') } function npmUsage (valid, cb) { npm.config.set('loglevel', 'silent') log.level = 'silent' output([ '\nUsage: npm ', '', 'where is one of:', npm.config.get('long') ? usages() : ' ' + wrap(commands), '', 'npm -h quick help on ', 'npm -l display full usage info', 'npm help search for help on ', 'npm help npm involved overview', '', 'Specify configs in the ini-formatted file:', ' ' + npm.config.get('userconfig'), 'or on the command line via: npm --key value', 'Config info can be viewed via: npm help config', '', 'npm@' + npm.version + ' ' + path.dirname(__dirname) ].join('\n')) if (npm.argv.length > 1) { output(didYouMean(npm.argv[1], commands)) } cb(valid) } function usages () { // return a string of : var maxLen = 0 return Object.keys(npm.commands).filter(function (c) { return c === npm.deref(c) }).reduce(function (set, c) { set.push([c, npm.commands[c].usage || '']) maxLen = Math.max(maxLen, c.length) return set }, []).map(function (item) { var c = item[0] var usage = item[1] return '\n ' + c + (new Array(maxLen - c.length + 2).join(' ')) + (usage.split('\n').join('\n' + (new Array(maxLen + 6).join(' ')))) }).join('\n') } function wrap (arr) { var out = [''] var l = 0 var line line = process.stdout.columns if (!line) { line = 60 } else { line = Math.min(60, Math.max(line - 16, 24)) } arr.sort(function (a, b) { return a < b ? -1 : 1 }) .forEach(function (c) { if (out[l].length + c.length + 2 < line) { out[l] += ', ' + c } else { out[l++] += ',' out[l] = c } }) return out.join('\n ').substr(2) } function getSections (cb) { var g = path.resolve(__dirname, '../man/man[0-9]/*.[0-9]') glob(g, function (er, files) { if (er) return cb(er) cb(null, Object.keys(files.reduce(function (acc, file) { file = path.basename(file).replace(/\.[0-9]+$/, '') file = file.replace(/^npm-/, '') acc[file] = true return acc }, { help: true }))) }) } hook.js000064400000011167152231567050006056 0ustar00'use strict' const BB = require('bluebird') const hookApi = require('libnpm/hook') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const pudding = require('figgy-pudding') const relativeDate = require('tiny-relative-date') const Table = require('cli-table3') const validate = require('aproba') const npm = require('./npm') hook.usage = [ 'npm hook add [--type=]', 'npm hook ls [pkg]', 'npm hook rm ', 'npm hook update ' ].join('\n') hook.completion = (opts, cb) => { validate('OF', [opts, cb]) return cb(null, []) // fill in this array with completion values } const HookConfig = pudding({ json: {}, loglevel: {}, parseable: {}, silent: {}, unicode: {} }) function UsageError () { throw Object.assign(new Error(hook.usage), {code: 'EUSAGE'}) } module.exports = (args, cb) => BB.try(() => hook(args)).then( val => cb(null, val), err => err.code === 'EUSAGE' ? cb(err.message) : cb(err) ) function hook (args) { if (args.length === 4) { // secret is passed in the args // we have the user secret in the CLI args, we need to redact it from the referer. redactUserSecret() } return otplease(npmConfig(), opts => { opts = HookConfig(opts) switch (args[0]) { case 'add': return add(args[1], args[2], args[3], opts) case 'ls': return ls(args[1], opts) case 'rm': return rm(args[1], opts) case 'update': case 'up': return update(args[1], args[2], args[3], opts) default: UsageError() } }) } function add (pkg, uri, secret, opts) { return hookApi.add(pkg, uri, secret, opts).then(hook => { if (opts.json) { output(JSON.stringify(hook, null, 2)) } else if (opts.parseable) { output(Object.keys(hook).join('\t')) output(Object.keys(hook).map(k => hook[k]).join('\t')) } else if (!opts.silent && opts.loglevel !== 'silent') { output(`+ ${hookName(hook)} ${ opts.unicode ? ' ➜ ' : ' -> ' } ${hook.endpoint}`) } }) } function ls (pkg, opts) { return hookApi.ls(opts.concat({package: pkg})).then(hooks => { if (opts.json) { output(JSON.stringify(hooks, null, 2)) } else if (opts.parseable) { output(Object.keys(hooks[0]).join('\t')) hooks.forEach(hook => { output(Object.keys(hook).map(k => hook[k]).join('\t')) }) } else if (!hooks.length) { output("You don't have any hooks configured yet.") } else if (!opts.silent && opts.loglevel !== 'silent') { if (hooks.length === 1) { output('You have one hook configured.') } else { output(`You have ${hooks.length} hooks configured.`) } const table = new Table({head: ['id', 'target', 'endpoint']}) hooks.forEach((hook) => { table.push([ {rowSpan: 2, content: hook.id}, hookName(hook), hook.endpoint ]) if (hook.last_delivery) { table.push([ { colSpan: 1, content: `triggered ${relativeDate(hook.last_delivery)}` }, hook.response_code ]) } else { table.push([{colSpan: 2, content: 'never triggered'}]) } }) output(table.toString()) } }) } function rm (id, opts) { return hookApi.rm(id, opts).then(hook => { if (opts.json) { output(JSON.stringify(hook, null, 2)) } else if (opts.parseable) { output(Object.keys(hook).join('\t')) output(Object.keys(hook).map(k => hook[k]).join('\t')) } else if (!opts.silent && opts.loglevel !== 'silent') { output(`- ${hookName(hook)} ${ opts.unicode ? ' ✘ ' : ' X ' } ${hook.endpoint}`) } }) } function update (id, uri, secret, opts) { return hookApi.update(id, uri, secret, opts).then(hook => { if (opts.json) { output(JSON.stringify(hook, null, 2)) } else if (opts.parseable) { output(Object.keys(hook).join('\t')) output(Object.keys(hook).map(k => hook[k]).join('\t')) } else if (!opts.silent && opts.loglevel !== 'silent') { output(`+ ${hookName(hook)} ${ opts.unicode ? ' ➜ ' : ' -> ' } ${hook.endpoint}`) } }) } function hookName (hook) { let target = hook.name if (hook.type === 'scope') { target = '@' + target } if (hook.type === 'owner') { target = '~' + target } return target } function redactUserSecret () { const referer = npm.referer if (!referer) return const splittedReferer = referer.split(' ') splittedReferer[4] = '[REDACTED]' npm.referer = splittedReferer.join(' ') } init.js000064400000005365152231567050006064 0ustar00// initialize a package.json file module.exports = init var path = require('path') var log = require('npmlog') var npa = require('npm-package-arg') var npm = require('./npm.js') var npx = require('libnpx') var initJson = require('init-package-json') var isRegistry = require('./utils/is-registry.js') var output = require('./utils/output.js') var noProgressTillDone = require('./utils/no-progress-while-running').tillDone var usage = require('./utils/usage') init.usage = usage( 'init', '\nnpm init [--force|-f|--yes|-y|--scope]' + '\nnpm init <@scope> (same as `npx <@scope>/create`)' + '\nnpm init [<@scope>/] (same as `npx [<@scope>/]create-`)' ) function init (args, cb) { if (args.length) { var NPM_PATH = path.resolve(__dirname, '../bin/npm-cli.js') var initerName = args[0] var packageName = initerName if (/^@[^/]+$/.test(initerName)) { packageName = initerName + '/create' } else { var req = npa(initerName) if (req.type === 'git' && req.hosted) { var { user, project } = req.hosted packageName = initerName .replace(user + '/' + project, user + '/create-' + project) } else if (isRegistry(req)) { packageName = req.name.replace(/^(@[^/]+\/)?/, '$1create-') if (req.rawSpec) { packageName += '@' + req.rawSpec } } else { var err = new Error( 'Unrecognized initializer: ' + initerName + '\nFor more package binary executing power check out `npx`:' + '\nhttps://www.npmjs.com/package/npx' ) err.code = 'EUNSUPPORTED' throw err } } var npxArgs = [process.argv0, '[fake arg]', '--always-spawn', packageName, ...process.argv.slice(4)] var parsed = npx.parseArgs(npxArgs, NPM_PATH) return npx(parsed) .then(() => cb()) .catch(cb) } var dir = process.cwd() log.pause() var initFile = npm.config.get('init-module') if (!initJson.yes(npm.config)) { output([ 'This utility will walk you through creating a package.json file.', 'It only covers the most common items, and tries to guess sensible defaults.', '', 'See `npm help init` for definitive documentation on these fields', 'and exactly what they do.', '', 'Use `npm install ` afterwards to install a package and', 'save it as a dependency in the package.json file.', '', 'Press ^C at any time to quit.' ].join('\n')) } initJson(dir, initFile, npm.config, noProgressTillDone(function (er, data) { log.resume() log.silly('package data', data) if (er && er.message === 'canceled') { log.warn('init', 'canceled') return cb(null, data) } log.info('init', 'written successfully') cb(er, data) })) } install-ci-test.js000064400000000746152231567050010133 0ustar00'use strict' // npm install-ci-test // Runs `npm ci` and then runs `npm test` module.exports = installTest var ci = require('./ci.js') var test = require('./test.js') var usage = require('./utils/usage') installTest.usage = usage( 'install-ci-test', '\nnpm install-ci-test [args]' + '\nSame args as `npm ci`' ) installTest.completion = ci.completion function installTest (args, cb) { ci(args, function (er) { if (er) { return cb(er) } test([], cb) }) } install.js000064400000110741152231567050006562 0ustar00'use strict' /* eslint-disable camelcase */ /* eslint-disable standard/no-callback-literal */ // npm install // // See doc/cli/npm-install.md for more description // // Managing contexts... // there's a lot of state associated with an "install" operation, including // packages that are already installed, parent packages, current shrinkwrap, and // so on. We maintain this state in a "context" object that gets passed around. // every time we dive into a deeper node_modules folder, the "family" list that // gets passed along uses the previous "family" list as its __proto__. Any // "resolved precise dependency" things that aren't already on this object get // added, and then that's passed to the next generation of installation. module.exports = install module.exports.Installer = Installer var usage = require('./utils/usage') install.usage = usage( 'install', '\nnpm install (with no args, in package dir)' + '\nnpm install [<@scope>/]' + '\nnpm install [<@scope>/]@' + '\nnpm install [<@scope>/]@' + '\nnpm install [<@scope>/]@' + '\nnpm install @npm:' + '\nnpm install ' + '\nnpm install ' + '\nnpm install ' + '\nnpm install ' + '\nnpm install /', '[--save-prod|--save-dev|--save-optional] [--save-exact] [--no-save]' ) install.completion = function (opts, cb) { validate('OF', arguments) // install can complete to a folder with a package.json, or any package. // if it has a slash, then it's gotta be a folder // if it starts with https?://, then just give up, because it's a url if (/^https?:\/\//.test(opts.partialWord)) { // do not complete to URLs return cb(null, []) } if (/\//.test(opts.partialWord)) { // Complete fully to folder if there is exactly one match and it // is a folder containing a package.json file. If that is not the // case we return 0 matches, which will trigger the default bash // complete. var lastSlashIdx = opts.partialWord.lastIndexOf('/') var partialName = opts.partialWord.slice(lastSlashIdx + 1) var partialPath = opts.partialWord.slice(0, lastSlashIdx) if (partialPath === '') partialPath = '/' var annotatePackageDirMatch = function (sibling, cb) { var fullPath = path.join(partialPath, sibling) if (sibling.slice(0, partialName.length) !== partialName) { return cb(null, null) // not name match } fs.readdir(fullPath, function (err, contents) { if (err) return cb(null, { isPackage: false }) cb( null, { fullPath: fullPath, isPackage: contents.indexOf('package.json') !== -1 } ) }) } return fs.readdir(partialPath, function (err, siblings) { if (err) return cb(null, []) // invalid dir: no matching asyncMap(siblings, annotatePackageDirMatch, function (err, matches) { if (err) return cb(err) var cleaned = matches.filter(function (x) { return x !== null }) if (cleaned.length !== 1) return cb(null, []) if (!cleaned[0].isPackage) return cb(null, []) // Success - only one match and it is a package dir return cb(null, [cleaned[0].fullPath]) }) }) } // FIXME: there used to be registry completion here, but it stopped making // sense somewhere around 50,000 packages on the registry cb() } // system packages var fs = require('fs') var path = require('path') // dependencies var log = require('npmlog') var readPackageTree = require('read-package-tree') var readPackageJson = require('read-package-json') var chain = require('slide').chain var asyncMap = require('slide').asyncMap var archy = require('archy') var mkdirp = require('gentle-fs').mkdir var rimraf = require('rimraf') var iferr = require('iferr') var validate = require('aproba') var uniq = require('lodash.uniq') var Bluebird = require('bluebird') // npm internal utils var npm = require('./npm.js') var locker = require('./utils/locker.js') var lock = locker.lock var unlock = locker.unlock var parseJSON = require('./utils/parse-json.js') var output = require('./utils/output.js') var saveMetrics = require('./utils/metrics.js').save // install specific libraries var copyTree = require('./install/copy-tree.js') var readShrinkwrap = require('./install/read-shrinkwrap.js') var computeMetadata = require('./install/deps.js').computeMetadata var prefetchDeps = require('./install/deps.js').prefetchDeps var loadDeps = require('./install/deps.js').loadDeps var loadDevDeps = require('./install/deps.js').loadDevDeps var getAllMetadata = require('./install/deps.js').getAllMetadata var loadRequestedDeps = require('./install/deps.js').loadRequestedDeps var loadExtraneous = require('./install/deps.js').loadExtraneous var diffTrees = require('./install/diff-trees.js') var checkPermissions = require('./install/check-permissions.js') var decomposeActions = require('./install/decompose-actions.js') var validateTree = require('./install/validate-tree.js') var validateArgs = require('./install/validate-args.js') var saveRequested = require('./install/save.js').saveRequested var saveShrinkwrap = require('./install/save.js').saveShrinkwrap var audit = require('./install/audit.js') var { getPrintFundingReport, getPrintFundingReportJSON } = require('./install/fund.js') var getSaveType = require('./install/save.js').getSaveType var doSerialActions = require('./install/actions.js').doSerial var doReverseSerialActions = require('./install/actions.js').doReverseSerial var doParallelActions = require('./install/actions.js').doParallel var doOneAction = require('./install/actions.js').doOne var removeObsoleteDep = require('./install/deps.js').removeObsoleteDep var removeExtraneous = require('./install/deps.js').removeExtraneous var computeVersionSpec = require('./install/deps.js').computeVersionSpec var packageId = require('./utils/package-id.js') var moduleName = require('./utils/module-name.js') var errorMessage = require('./utils/error-message.js') var isExtraneous = require('./install/is-extraneous.js') function unlockCB (lockPath, name, cb) { validate('SSF', arguments) return function (installEr) { var args = arguments try { unlock(lockPath, name, reportErrorAndReturn) } catch (unlockEx) { process.nextTick(function () { reportErrorAndReturn(unlockEx) }) } function reportErrorAndReturn (unlockEr) { if (installEr) { if (unlockEr && unlockEr.code !== 'ENOTLOCKED') { log.warn('unlock' + name, unlockEr) } return cb.apply(null, args) } if (unlockEr) return cb(unlockEr) return cb.apply(null, args) } } } function install (where, args, cb) { if (!cb) { cb = args args = where where = null } var globalTop = path.resolve(npm.globalDir, '..') if (!where) { where = npm.config.get('global') ? globalTop : npm.prefix } validate('SAF', [where, args, cb]) // the /path/to/node_modules/.. var dryrun = !!npm.config.get('dry-run') if (npm.config.get('dev')) { log.warn('install', 'Usage of the `--dev` option is deprecated. Use `--also=dev` instead.') } if (where === globalTop && !args.length) { args = ['.'] } args = args.filter(function (a) { return path.resolve(a) !== npm.prefix }) new Installer(where, dryrun, args).run(cb) } function Installer (where, dryrun, args, opts) { validate('SBA|SBAO', arguments) if (!opts) opts = {} this.where = where this.dryrun = dryrun this.args = args // fakechildren are children created from the lockfile and lack relationship data // the only exist when the tree does not match the lockfile // this is fine when doing full tree installs/updates but not ok when modifying only // a few deps via `npm install` or `npm uninstall`. this.currentTree = null this.idealTree = null this.differences = [] this.todo = [] this.progress = {} this.noPackageJsonOk = !!args.length this.topLevelLifecycles = !args.length this.autoPrune = npm.config.get('package-lock') const dev = npm.config.get('dev') const only = npm.config.get('only') const onlyProd = /^prod(uction)?$/.test(only) const onlyDev = /^dev(elopment)?$/.test(only) const prod = npm.config.get('production') this.dev = opts.dev != null ? opts.dev : dev || (!onlyProd && !prod) || onlyDev this.prod = opts.prod != null ? opts.prod : !onlyDev this.packageLockOnly = opts.packageLockOnly != null ? opts.packageLockOnly : npm.config.get('package-lock-only') this.rollback = opts.rollback != null ? opts.rollback : npm.config.get('rollback') this.link = opts.link != null ? opts.link : npm.config.get('link') this.saveOnlyLock = opts.saveOnlyLock this.global = opts.global != null ? opts.global : this.where === path.resolve(npm.globalDir, '..') this.audit = npm.config.get('audit') && !this.global this.fund = npm.config.get('fund') && !this.global this.started = Date.now() } Installer.prototype = {} Installer.prototype.run = function (_cb) { validate('F|', arguments) var result var cb if (_cb) { cb = function (err) { saveMetrics(!err) return _cb.apply(this, arguments) } } else { result = new Promise((resolve, reject) => { cb = (err, value) => err ? reject(err) : resolve(value) }) } // FIXME: This is bad and I should feel bad. // lib/install needs to have some way of sharing _limited_ // state with the things it calls. Passing the object is too // much. The global config is WAY too much. =( =( // But not having this is gonna break linked modules in // subtle stupid ways, and refactoring all this code isn't // the right thing to do just yet. if (this.global) { var prevGlobal = npm.config.get('global') npm.config.set('global', true) var next = cb cb = function () { npm.config.set('global', prevGlobal) next.apply(null, arguments) } } var installSteps = [] var postInstallSteps = [] if (!this.dryrun) { installSteps.push( [this.newTracker(log, 'runTopLevelLifecycles', 2)], [this, this.runPreinstallTopLevelLifecycles]) } installSteps.push( [this.newTracker(log, 'loadCurrentTree', 4)], [this, this.loadCurrentTree], [this, this.finishTracker, 'loadCurrentTree'], [this.newTracker(log, 'loadIdealTree', 12)], [this, this.loadIdealTree], [this, this.finishTracker, 'loadIdealTree'], [this, this.debugTree, 'currentTree', 'currentTree'], [this, this.debugTree, 'idealTree', 'idealTree'], [this.newTracker(log, 'generateActionsToTake')], [this, this.generateActionsToTake], [this, this.finishTracker, 'generateActionsToTake'], [this, this.debugActions, 'diffTrees', 'differences'], [this, this.debugActions, 'decomposeActions', 'todo'], [this, this.startAudit] ) if (this.packageLockOnly) { postInstallSteps.push( [this, this.saveToDependencies]) } else if (!this.dryrun) { installSteps.push( [this.newTracker(log, 'executeActions', 8)], [this, this.executeActions], [this, this.finishTracker, 'executeActions']) var node_modules = path.resolve(this.where, 'node_modules') var staging = path.resolve(node_modules, '.staging') postInstallSteps.push( [this.newTracker(log, 'rollbackFailedOptional', 1)], [this, this.rollbackFailedOptional, staging, this.todo], [this, this.finishTracker, 'rollbackFailedOptional'], [this, this.commit, staging, this.todo], [this, this.runPostinstallTopLevelLifecycles], [this, this.finishTracker, 'runTopLevelLifecycles'] ) if (getSaveType()) { postInstallSteps.push( // this is necessary as we don't fill in `dependencies` and `devDependencies` in deps loaded from shrinkwrap // until after we extract them [this, (next) => { computeMetadata(this.idealTree); next() }], [this, this.pruneIdealTree], [this, this.debugLogicalTree, 'saveTree', 'idealTree'], [this, this.saveToDependencies]) } } postInstallSteps.push( [this, this.printWarnings], [this, this.printInstalled]) var self = this chain(installSteps, function (installEr) { if (installEr) self.failing = true chain(postInstallSteps, function (postInstallEr) { if (installEr && postInstallEr) { var msg = errorMessage(postInstallEr) msg.summary.forEach(function (logline) { log.warn.apply(log, logline) }) msg.detail.forEach(function (logline) { log.verbose.apply(log, logline) }) } cb(installEr || postInstallEr, self.getInstalledModules(), self.idealTree) }) }) return result } Installer.prototype.loadArgMetadata = function (next) { getAllMetadata(this.args, this.currentTree, process.cwd(), iferr(next, (args) => { this.args = args next() })) } Installer.prototype.newTracker = function (tracker, name, size) { validate('OS', [tracker, name]) if (size) validate('N', [size]) this.progress[name] = tracker.newGroup(name, size) return function (next) { process.emit('time', 'stage:' + name) next() } } Installer.prototype.finishTracker = function (name, cb) { validate('SF', arguments) process.emit('timeEnd', 'stage:' + name) cb() } Installer.prototype.loadCurrentTree = function (cb) { validate('F', arguments) log.silly('install', 'loadCurrentTree') var todo = [] if (this.global) { todo.push([this, this.readGlobalPackageData]) } else { todo.push([this, this.readLocalPackageData]) } todo.push([this, this.normalizeCurrentTree]) chain(todo, cb) } var createNode = require('./install/node.js').create var flatNameFromTree = require('./install/flatten-tree.js').flatNameFromTree Installer.prototype.normalizeCurrentTree = function (cb) { this.currentTree.isTop = true normalizeTree(this.currentTree) // If the user didn't have a package.json then fill in deps with what was on disk if (this.currentTree.error) { for (let child of this.currentTree.children) { if (!child.fakeChild && isExtraneous(child)) { this.currentTree.package.dependencies[moduleName(child)] = computeVersionSpec(this.currentTree, child) } } } computeMetadata(this.currentTree) return cb() function normalizeTree (tree, seen) { if (!seen) seen = new Set() if (seen.has(tree)) return seen.add(tree) createNode(tree) tree.location = flatNameFromTree(tree) tree.children.forEach((child) => normalizeTree(child, seen)) } } Installer.prototype.loadIdealTree = function (cb) { validate('F', arguments) log.silly('install', 'loadIdealTree') chain([ [this.newTracker(this.progress.loadIdealTree, 'loadIdealTree:cloneCurrentTree')], [this, this.cloneCurrentTreeToIdealTree], [this, this.finishTracker, 'loadIdealTree:cloneCurrentTree'], [this.newTracker(this.progress.loadIdealTree, 'loadIdealTree:loadShrinkwrap')], [this, this.loadShrinkwrap], [this, this.finishTracker, 'loadIdealTree:loadShrinkwrap'], [this.newTracker(this.progress.loadIdealTree, 'loadIdealTree:loadAllDepsIntoIdealTree', 10)], [this, this.loadAllDepsIntoIdealTree], [this, this.finishTracker, 'loadIdealTree:loadAllDepsIntoIdealTree'], [this, function (next) { computeMetadata(this.idealTree); next() }], [this, this.pruneIdealTree] ], cb) } Installer.prototype.pruneIdealTree = function (cb) { if (!this.idealTree) return cb() // if our lock file didn't have the requires field and there // are any fake children then forgo pruning until we have more info. if (!this.idealTree.hasRequiresFromLock && this.idealTree.children.some((n) => n.fakeChild)) return cb() const toPrune = this.idealTree.children .filter((child) => isExtraneous(child) && (this.autoPrune || child.removing)) .map((n) => ({name: moduleName(n)})) return removeExtraneous(toPrune, this.idealTree, cb) } Installer.prototype.loadAllDepsIntoIdealTree = function (cb) { validate('F', arguments) log.silly('install', 'loadAllDepsIntoIdealTree') var saveDeps = getSaveType() var cg = this.progress['loadIdealTree:loadAllDepsIntoIdealTree'] var installNewModules = !!this.args.length var steps = [] if (installNewModules) { steps.push([validateArgs, this.idealTree, this.args]) steps.push([loadRequestedDeps, this.args, this.idealTree, saveDeps, cg.newGroup('loadRequestedDeps')]) } else { const depsToPreload = Object.assign({}, this.idealTree.package.devDependencies, this.idealTree.package.dependencies ) steps.push( [prefetchDeps, this.idealTree, depsToPreload, cg.newGroup('prefetchDeps')], [loadDeps, this.idealTree, cg.newGroup('loadDeps')], [loadDevDeps, this.idealTree, cg.newGroup('loadDevDeps')]) } steps.push( [loadExtraneous.andResolveDeps, this.idealTree, cg.newGroup('loadExtraneous')]) chain(steps, cb) } Installer.prototype.generateActionsToTake = function (cb) { validate('F', arguments) log.silly('install', 'generateActionsToTake') var cg = this.progress.generateActionsToTake chain([ [validateTree, this.idealTree, cg.newGroup('validateTree')], [diffTrees, this.currentTree, this.idealTree, this.differences, cg.newGroup('diffTrees')], [this, this.computeLinked], [checkPermissions, this.differences], [decomposeActions, this.differences, this.todo] ], cb) } Installer.prototype.computeLinked = function (cb) { validate('F', arguments) if (!this.link || this.global) return cb() var linkTodoList = [] var self = this asyncMap(this.differences, function (action, next) { var cmd = action[0] var pkg = action[1] if (cmd !== 'add' && cmd !== 'update') return next() var isReqByTop = pkg.requiredBy.filter(function (mod) { return mod.isTop }).length var isReqByUser = pkg.userRequired var isExtraneous = pkg.requiredBy.length === 0 if (!isReqByTop && !isReqByUser && !isExtraneous) return next() isLinkable(pkg, function (install, link) { if (install) linkTodoList.push(['global-install', pkg]) if (link) linkTodoList.push(['global-link', pkg]) if (install || link) removeObsoleteDep(pkg) next() }) }, function () { if (linkTodoList.length === 0) return cb() self.differences.length = 0 Array.prototype.push.apply(self.differences, linkTodoList) diffTrees(self.currentTree, self.idealTree, self.differences, log.newGroup('d2'), cb) }) } function isLinkable (pkg, cb) { var globalPackage = path.resolve(npm.globalPrefix, 'lib', 'node_modules', moduleName(pkg)) var globalPackageJson = path.resolve(globalPackage, 'package.json') fs.stat(globalPackage, function (er) { if (er) return cb(true, true) fs.readFile(globalPackageJson, function (er, data) { var json = parseJSON.noExceptions(data) cb(false, json && json.version === pkg.package.version) }) }) } Installer.prototype.executeActions = function (cb) { validate('F', arguments) log.silly('install', 'executeActions') var todo = this.todo var cg = this.progress.executeActions var node_modules = path.resolve(this.where, 'node_modules') var staging = path.resolve(node_modules, '.staging') var steps = [] var trackLifecycle = cg.newGroup('lifecycle') cb = unlockCB(node_modules, '.staging', cb) steps.push( [doSerialActions, 'global-install', staging, todo, trackLifecycle.newGroup('global-install')], [lock, node_modules, '.staging'], [rimraf, staging], [doParallelActions, 'extract', staging, todo, cg.newGroup('extract', 100)], [doReverseSerialActions, 'unbuild', staging, todo, cg.newGroup('unbuild')], [doSerialActions, 'remove', staging, todo, cg.newGroup('remove')], [doSerialActions, 'move', staging, todo, cg.newGroup('move')], [doSerialActions, 'finalize', staging, todo, cg.newGroup('finalize')], [doParallelActions, 'refresh-package-json', staging, todo, cg.newGroup('refresh-package-json')], [doParallelActions, 'preinstall', staging, todo, trackLifecycle.newGroup('preinstall')], [doSerialActions, 'build', staging, todo, trackLifecycle.newGroup('build')], [doSerialActions, 'global-link', staging, todo, trackLifecycle.newGroup('global-link')], [doParallelActions, 'update-linked', staging, todo, trackLifecycle.newGroup('update-linked')], [doSerialActions, 'install', staging, todo, trackLifecycle.newGroup('install')], [doSerialActions, 'postinstall', staging, todo, trackLifecycle.newGroup('postinstall')]) var self = this chain(steps, function (er) { if (!er || self.rollback) { rimraf(staging, function () { cb(er) }) } else { cb(er) } }) } Installer.prototype.rollbackFailedOptional = function (staging, actionsToRun, cb) { if (!this.rollback) return cb() var failed = uniq(actionsToRun.map(function (action) { return action[1] }).filter(function (pkg) { return pkg.failed && pkg.rollback })) var top = this.currentTree && this.currentTree.path Bluebird.map(failed, (pkg) => { return Bluebird.map(pkg.rollback, (rollback) => rollback(top, staging, pkg)) }).asCallback(cb) } Installer.prototype.commit = function (staging, actionsToRun, cb) { var toCommit = actionsToRun.map(function (action) { return action[1] }).filter(function (pkg) { return !pkg.failed && pkg.commit }) asyncMap(toCommit, function (pkg, next) { asyncMap(pkg.commit, function (commit, done) { commit(staging, pkg, done) }, function () { pkg.commit = [] next.apply(null, arguments) }) }, cb) } Installer.prototype.runPreinstallTopLevelLifecycles = function (cb) { validate('F', arguments) if (this.failing) return cb() if (!this.topLevelLifecycles) return cb() log.silly('install', 'runPreinstallTopLevelLifecycles') readPackageJson(path.join(this.where, 'package.json'), log, false, (err, data) => { if (err) return cb() this.currentTree = createNode({ isTop: true, package: data, path: this.where }) doOneAction('preinstall', this.where, this.currentTree, log.newGroup('preinstall:.'), cb) }) } Installer.prototype.runPostinstallTopLevelLifecycles = function (cb) { validate('F', arguments) if (this.failing) return cb() if (!this.topLevelLifecycles) return cb() log.silly('install', 'runPostinstallTopLevelLifecycles') var steps = [] var trackLifecycle = this.progress.runTopLevelLifecycles steps.push( [doOneAction, 'build', this.idealTree.path, this.idealTree, trackLifecycle.newGroup('build:.')], [doOneAction, 'install', this.idealTree.path, this.idealTree, trackLifecycle.newGroup('install:.')], [doOneAction, 'postinstall', this.idealTree.path, this.idealTree, trackLifecycle.newGroup('postinstall:.')]) if (this.dev) { steps.push( [doOneAction, 'prepare', this.idealTree.path, this.idealTree, trackLifecycle.newGroup('prepare')]) } chain(steps, cb) } Installer.prototype.startAudit = function (cb) { if (!this.audit) return cb() this.auditSubmission = Bluebird.try(() => { return audit.generateFromInstall(this.idealTree, this.differences, this.args, this.remove) }).then((auditData) => { return audit.submitForInstallReport(auditData) }).catch(_ => {}) cb() } Installer.prototype.saveToDependencies = function (cb) { validate('F', arguments) if (this.failing) return cb() log.silly('install', 'saveToDependencies') // Note idealTree will be mutated during the save operations below as the // package is reloaded from disk to preserve additional details. This means // steps after postInstall will see a slightly different package object. if (this.saveOnlyLock) { saveShrinkwrap(this.idealTree, cb) } else { saveRequested(this.idealTree, cb) } } Installer.prototype.readGlobalPackageData = function (cb) { validate('F', arguments) log.silly('install', 'readGlobalPackageData') var self = this this.loadArgMetadata(iferr(cb, function () { mkdirp(self.where, iferr(cb, function () { var pkgs = {} self.args.forEach(function (pkg) { pkgs[pkg.name] = true }) readPackageTree(self.where, function (ctx, kid) { return ctx.parent || pkgs[kid] }, iferr(cb, function (currentTree) { self.currentTree = currentTree return cb() })) })) })) } Installer.prototype.readLocalPackageData = function (cb) { validate('F', arguments) log.silly('install', 'readLocalPackageData') var self = this mkdirp(this.where, iferr(cb, function () { readPackageTree(self.where, iferr(cb, function (currentTree) { self.currentTree = currentTree self.currentTree.warnings = [] if (currentTree.error && currentTree.error.code === 'EJSONPARSE') { return cb(currentTree.error) } if (!self.noPackageJsonOk && !currentTree.package) { log.error('install', "Couldn't read dependencies") var er = new Error("ENOENT, open '" + path.join(self.where, 'package.json') + "'") er.code = 'ENOPACKAGEJSON' er.errno = 34 return cb(er) } if (!currentTree.package) currentTree.package = {} readShrinkwrap(currentTree, function (err) { if (err) { cb(err) } else { self.loadArgMetadata(cb) } }) })) })) } Installer.prototype.cloneCurrentTreeToIdealTree = function (cb) { validate('F', arguments) log.silly('install', 'cloneCurrentTreeToIdealTree') if (npm.config.get('before')) { this.idealTree = { package: this.currentTree.package, path: this.currentTree.path, realpath: this.currentTree.realpath, children: [], requires: [], missingDeps: {}, missingDevDeps: {}, requiredBy: [], error: this.currentTree.error, warnings: [], isTop: true } } else { this.idealTree = copyTree(this.currentTree) this.idealTree.warnings = [] } cb() } Installer.prototype.loadShrinkwrap = function (cb) { validate('F', arguments) log.silly('install', 'loadShrinkwrap') readShrinkwrap.andInflate(this.idealTree, iferr(cb, () => { computeMetadata(this.idealTree) cb() })) } Installer.prototype.getInstalledModules = function () { return this.differences.filter(function (action) { var mutation = action[0] return (mutation === 'add' || mutation === 'update') }).map(function (action) { var child = action[1] return [child.package._id, child.path] }) } Installer.prototype.printWarnings = function (cb) { if (!this.idealTree) return cb() var self = this var warned = false this.idealTree.warnings.forEach(function (warning) { if (warning.code === 'EPACKAGEJSON' && self.global) return if (warning.code === 'ENOTDIR') return warned = true var msg = errorMessage(warning) msg.summary.forEach(function (logline) { log.warn.apply(log, logline) }) msg.detail.forEach(function (logline) { log.verbose.apply(log, logline) }) }) if (warned && log.levels[npm.config.get('loglevel')] <= log.levels.warn) console.error() cb() } Installer.prototype.printInstalled = function (cb) { validate('F', arguments) if (this.failing) return cb() log.silly('install', 'printInstalled') const diffs = this.differences if (!this.idealTree.error && this.idealTree.removedChildren) { const deps = this.currentTree.package.dependencies || {} const dev = this.currentTree.package.devDependencies || {} this.idealTree.removedChildren.forEach((r) => { if (diffs.some((d) => d[0] === 'remove' && d[1].path === r.path)) return if (!deps[moduleName(r)] && !dev[moduleName(r)]) return diffs.push(['remove', r]) }) } return Bluebird.try(() => { if (!this.auditSubmission) return return Bluebird.resolve(this.auditSubmission).timeout(10000).catch(() => null) }).then((auditResult) => { if (auditResult && !auditResult.metadata) { log.warn('audit', 'Audit result from registry missing metadata. This is probably an issue with the registry.') } // maybe write audit report w/ hash of pjson & shrinkwrap for later reading by `npm audit` if (npm.config.get('json')) { return this.printInstalledForJSON(diffs, auditResult) } else if (npm.config.get('parseable')) { return this.printInstalledForParseable(diffs, auditResult) } else { return this.printInstalledForHuman(diffs, auditResult) } }).asCallback(cb) } Installer.prototype.printInstalledForHuman = function (diffs, auditResult) { var removed = 0 var added = 0 var updated = 0 var moved = 0 // Count the number of contributors to packages added, tracking // contributors we've seen, so we can produce a running unique count. var contributors = new Set() diffs.forEach(function (action) { var mutation = action[0] var pkg = action[1] if (pkg.failed) return if (mutation === 'remove') { ++removed } else if (mutation === 'move') { ++moved } else if (mutation === 'add') { ++added // Count contributors to added packages. Start by combining `author` // and `contributors` data into a single array of contributor-people // for this package. var people = [] var meta = pkg.package if (meta.author) people.push(meta.author) if (meta.contributors && Array.isArray(meta.contributors)) { people = people.concat(meta.contributors) } // Make sure a normalized string for every person behind this // package is in `contributors`. people.forEach(function (person) { // Ignore errors from malformed `author` and `contributors`. try { var normalized = normalizePerson(person) } catch (error) { return } if (!contributors.has(normalized)) contributors.add(normalized) }) } else if (mutation === 'update' || mutation === 'update-linked') { ++updated } }) var report = '' if (this.args.length && (added || updated)) { report += this.args.map((p) => { return `+ ${p.name}@${p.version}${ !p._requested.name || p._requested.name === p.name ? '' : ` (as ${p._requested.name})` }` }).join('\n') + '\n' } var actions = [] if (added) { var action = 'added ' + packages(added) if (contributors.size) action += from(contributors.size) actions.push(action) } if (removed) actions.push('removed ' + packages(removed)) if (updated) actions.push('updated ' + packages(updated)) if (moved) actions.push('moved ' + packages(moved)) if (auditResult && auditResult.metadata && auditResult.metadata.totalDependencies) { actions.push('audited ' + packages(auditResult.metadata.totalDependencies)) } if (actions.length === 0) { report += 'up to date' } else if (actions.length === 1) { report += actions[0] } else { var lastAction = actions.pop() report += actions.join(', ') + ' and ' + lastAction } report += ' in ' + ((Date.now() - this.started) / 1000) + 's' output(report) function packages (num) { return num + ' package' + (num > 1 ? 's' : '') } function from (num) { return ' from ' + num + ' contributor' + (num > 1 ? 's' : '') } // Values of `author` and elements of `contributors` in `package.json` // files can be e-mail style strings or Objects with `name`, `email, // and `url` String properties. Convert Objects to Strings so that // we can efficiently keep a set of contributors we have already seen. function normalizePerson (argument) { if (typeof argument === 'string') return argument var returned = '' if (argument.name) returned += argument.name if (argument.email) returned += ' <' + argument.email + '>' if (argument.url) returned += ' (' + argument.email + ')' return returned } const { fund, idealTree } = this const printFundingReport = getPrintFundingReport({ fund, idealTree }) if (printFundingReport.length) { output(printFundingReport) } if (auditResult) { return audit.printInstallReport(auditResult) } } Installer.prototype.printInstalledForJSON = function (diffs, auditResult) { const { fund, idealTree } = this const printFundingReport = getPrintFundingReportJSON({ fund, idealTree }) var result = { added: [], removed: [], updated: [], moved: [], failed: [], warnings: [], audit: auditResult, funding: printFundingReport, elapsed: Date.now() - this.started } var self = this this.idealTree.warnings.forEach(function (warning) { if (warning.code === 'EPACKAGEJSON' && self.global) return if (warning.code === 'ENOTDIR') return var output = errorMessage(warning) var message = flattenMessage(output.summary) if (output.detail.length) { message += '\n' + flattenMessage(output.detail) } result.warnings.push(message) }) diffs.forEach(function (action) { var mutation = action[0] var child = action[1] var record = recordAction(action) if (child.failed) { result.failed.push(record) } else if (mutation === 'add') { result.added.push(record) } else if (mutation === 'update' || mutation === 'update-linked') { result.updated.push(record) } else if (mutation === 'move') { result.moved.push(record) } else if (mutation === 'remove') { result.removed.push(record) } }) output(JSON.stringify(result, null, 2)) function flattenMessage (msg) { return msg.map(function (logline) { return logline.slice(1).join(' ') }).join('\n') } function recordAction (action) { var mutation = action[0] var child = action[1] const isAlias = child.package && child.package._requested && child.package._requested.type === 'alias' const name = isAlias ? child.package._requested.name : child.package && child.package.name var result = { action: mutation, name, version: child.package && `${isAlias ? `npm:${child.package.name}@` : ''}${child.package.version}`, path: child.path } if (mutation === 'move') { result.previousPath = child.fromPath } else if (mutation === 'update') { result.previousVersion = child.oldPkg.package && child.oldPkg.package.version } return result } } Installer.prototype.printInstalledForParseable = function (diffs) { var self = this diffs.forEach(function (action) { var mutation = action[0] var child = action[1] if (mutation === 'move') { var previousPath = path.relative(self.where, child.fromPath) } else if (mutation === 'update') { var previousVersion = child.oldPkg.package && child.oldPkg.package.version } const isAlias = child.package._requested && child.package._requested.type === 'alias' const version = child.package && isAlias ? `npm:${child.package.name}@${child.package.version}` : child.package ? child.package.version : '' output( mutation + '\t' + moduleName(child) + '\t' + version + '\t' + (child.path ? path.relative(self.where, child.path) : '') + '\t' + (previousVersion || '') + '\t' + (previousPath || '')) }) } Installer.prototype.debugActions = function (name, actionListName, cb) { validate('SSF', arguments) var actionsToLog = this[actionListName] log.silly(name, 'action count', actionsToLog.length) actionsToLog.forEach(function (action) { log.silly(name, action.map(function (value) { return (value && value.package) ? packageId(value) : value }).join(' ')) }) cb() } // This takes an object and a property name instead of a value to allow us // to define the arguments for use by chain before the property exists yet. Installer.prototype.debugTree = function (name, treeName, cb) { validate('SSF', arguments) log.silly(name, this.archyDebugTree(this[treeName]).trim()) cb() } Installer.prototype.archyDebugTree = function (tree) { validate('O', arguments) var seen = new Set() function byName (aa, bb) { return packageId(aa).localeCompare(packageId(bb)) } function expandTree (tree) { seen.add(tree) return { label: packageId(tree), nodes: tree.children.filter((tree) => { return !seen.has(tree) && !tree.removed }).sort(byName).map(expandTree) } } return archy(expandTree(tree), '', { unicode: npm.config.get('unicode') }) } Installer.prototype.debugLogicalTree = function (name, treeName, cb) { validate('SSF', arguments) this[treeName] && log.silly(name, this.archyDebugLogicalTree(this[treeName]).trim()) cb() } Installer.prototype.archyDebugLogicalTree = function (tree) { validate('O', arguments) var seen = new Set() function byName (aa, bb) { return packageId(aa).localeCompare(packageId(bb)) } function expandTree (tree) { seen.add(tree) return { label: packageId(tree), nodes: tree.requires.filter((tree) => { return !seen.has(tree) && !tree.removed }).sort(byName).map(expandTree) } } return archy(expandTree(tree), '', { unicode: npm.config.get('unicode') }) } logout.js000064400000002411152231567050006417 0ustar00'use strict' const BB = require('bluebird') const eu = encodeURIComponent const getAuth = require('npm-registry-fetch/auth.js') const log = require('npmlog') const npm = require('./npm.js') const npmConfig = require('./config/figgy-config.js') const npmFetch = require('libnpm/fetch') logout.usage = 'npm logout [--registry=] [--scope=<@scope>]' function afterLogout (normalized) { var scope = npm.config.get('scope') if (scope) npm.config.del(scope + ':registry') npm.config.clearCredentialsByURI(normalized) return BB.fromNode(cb => npm.config.save('user', cb)) } module.exports = logout function logout (args, cb) { const opts = npmConfig() BB.try(() => { const reg = npmFetch.pickRegistry('foo', opts) const auth = getAuth(reg, opts) if (auth.token) { log.verbose('logout', 'clearing session token for', reg) return npmFetch(`/-/user/token/${eu(auth.token)}`, opts.concat({ method: 'DELETE', ignoreBody: true })).then(() => afterLogout(reg)) } else if (auth.username || auth.password) { log.verbose('logout', 'clearing user credentials for', reg) return afterLogout(reg) } else { throw new Error( 'Not logged in to', reg + ',', "so can't log out." ) } }).nodeify(cb) } org.js000064400000010264152231567050005702 0ustar00'use strict' const figgyPudding = require('figgy-pudding') const liborg = require('libnpm/org') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const Table = require('cli-table3') module.exports = org org.subcommands = ['set', 'rm', 'ls'] org.usage = 'npm org set orgname username [developer | admin | owner]\n' + 'npm org rm orgname username\n' + 'npm org ls orgname []' const OrgConfig = figgyPudding({ json: {}, loglevel: {}, parseable: {}, silent: {} }) org.completion = function (opts, cb) { var argv = opts.conf.argv.remain if (argv.length === 2) { return cb(null, org.subcommands) } switch (argv[2]) { case 'ls': case 'add': case 'rm': case 'set': return cb(null, []) default: return cb(new Error(argv[2] + ' not recognized')) } } function UsageError () { throw Object.assign(new Error(org.usage), {code: 'EUSAGE'}) } function org ([cmd, orgname, username, role], cb) { otplease(npmConfig(), opts => { opts = OrgConfig(opts) switch (cmd) { case 'add': case 'set': return orgSet(orgname, username, role, opts) case 'rm': return orgRm(orgname, username, opts) case 'ls': return orgList(orgname, username, opts) default: UsageError() } }).then( x => cb(null, x), err => cb(err.code === 'EUSAGE' ? err.message : err) ) } function orgSet (org, user, role, opts) { role = role || 'developer' if (!org) { throw new Error('First argument `orgname` is required.') } if (!user) { throw new Error('Second argument `username` is required.') } if (!['owner', 'admin', 'developer'].find(x => x === role)) { throw new Error('Third argument `role` must be one of `owner`, `admin`, or `developer`, with `developer` being the default value if omitted.') } return liborg.set(org, user, role, opts).then(memDeets => { if (opts.json) { output(JSON.stringify(memDeets, null, 2)) } else if (opts.parseable) { output(['org', 'orgsize', 'user', 'role'].join('\t')) output([ memDeets.org.name, memDeets.org.size, memDeets.user, memDeets.role ]) } else if (!opts.silent && opts.loglevel !== 'silent') { output(`Added ${memDeets.user} as ${memDeets.role} to ${memDeets.org.name}. You now ${memDeets.org.size} member${memDeets.org.size === 1 ? '' : 's'} in this org.`) } return memDeets }) } function orgRm (org, user, opts) { if (!org) { throw new Error('First argument `orgname` is required.') } if (!user) { throw new Error('Second argument `username` is required.') } return liborg.rm(org, user, opts).then(() => { return liborg.ls(org, opts) }).then(roster => { user = user.replace(/^[~@]?/, '') org = org.replace(/^[~@]?/, '') const userCount = Object.keys(roster).length if (opts.json) { output(JSON.stringify({ user, org, userCount, deleted: true })) } else if (opts.parseable) { output(['user', 'org', 'userCount', 'deleted'].join('\t')) output([user, org, userCount, true].join('\t')) } else if (!opts.silent && opts.loglevel !== 'silent') { output(`Successfully removed ${user} from ${org}. You now have ${userCount} member${userCount === 1 ? '' : 's'} in this org.`) } }) } function orgList (org, user, opts) { if (!org) { throw new Error('First argument `orgname` is required.') } return liborg.ls(org, opts).then(roster => { if (user) { const newRoster = {} if (roster[user]) { newRoster[user] = roster[user] } roster = newRoster } if (opts.json) { output(JSON.stringify(roster, null, 2)) } else if (opts.parseable) { output(['user', 'role'].join('\t')) Object.keys(roster).forEach(user => { output([user, roster[user]].join('\t')) }) } else if (!opts.silent && opts.loglevel !== 'silent') { const table = new Table({head: ['user', 'role']}) Object.keys(roster).sort().forEach(user => { table.push([user, roster[user]]) }) output(table.toString()) } }) } start.js000064400000000076152231567050006250 0ustar00module.exports = require('./utils/lifecycle-cmd.js')('start') whoami.js000064400000003421152231567050006374 0ustar00'use strict' const BB = require('bluebird') const npmConfig = require('./config/figgy-config.js') const fetch = require('libnpm/fetch') const figgyPudding = require('figgy-pudding') const npm = require('./npm.js') const output = require('./utils/output.js') const WhoamiConfig = figgyPudding({ json: {}, registry: {} }) module.exports = whoami whoami.usage = 'npm whoami [--registry ]\n(just prints username according to given registry)' function whoami ([spec], silent, cb) { // FIXME: need tighter checking on this, but is a breaking change if (typeof cb !== 'function') { cb = silent silent = false } const opts = WhoamiConfig(npmConfig()) return BB.try(() => { // First, check if we have a user/pass-based auth const registry = opts.registry if (!registry) throw new Error('no default registry set') return npm.config.getCredentialsByURI(registry) }).then(({username, token}) => { if (username) { return username } else if (token) { return fetch.json('/-/whoami', opts.concat({ spec })).then(({username}) => { if (username) { return username } else { throw Object.assign(new Error( 'Your auth token is no longer valid. Please log in again.' ), {code: 'ENEEDAUTH'}) } }) } else { // At this point, if they have a credentials object, it doesn't have a // token or auth in it. Probably just the default registry. throw Object.assign(new Error( 'This command requires you to be logged in.' ), {code: 'ENEEDAUTH'}) } }).then(username => { if (silent) { } else if (opts.json) { output(JSON.stringify(username)) } else { output(username) } return username }).nodeify(cb) } pear/.channels/.alias/pear.txt000064400000000014152231651300012174 0ustar00pear.php.netpear/.channels/.alias/pecl.txt000064400000000014152231651300012170 0ustar00pecl.php.netpear/.channels/.alias/phpdocs.txt000064400000000013152231651300012704 0ustar00doc.php.netpear/.channels/__uri.reg000064400000000413152231651300011134 0ustar00a:4:{s:4:"name";s:5:"__uri";s:7:"servers";a:1:{s:7:"primary";a:1:{s:4:"rest";a:1:{s:7:"baseurl";a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.0";}s:8:"_content";s:4:"****";}}}}s:7:"summary";s:34:"Pseudo-channel for static packages";s:13:"_lastmodified";i:1770291810;}pear/.channels/doc.php.net.reg000064400000001030152231651300012153 0ustar00a:5:{s:14:"suggestedalias";s:7:"phpdocs";s:4:"name";s:11:"doc.php.net";s:7:"summary";s:22:"PHP Documentation Team";s:7:"servers";a:1:{s:7:"primary";a:1:{s:4:"rest";a:1:{s:7:"baseurl";a:3:{i:0;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.0";}s:8:"_content";s:25:"https://doc.php.net/rest/";}i:1;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.1";}s:8:"_content";s:25:"https://doc.php.net/rest/";}i:2;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.3";}s:8:"_content";s:25:"https://doc.php.net/rest/";}}}}}s:13:"_lastmodified";i:1770291810;}pear/.channels/pear.php.net.reg000064400000001053152231651300012342 0ustar00a:5:{s:14:"suggestedalias";s:4:"pear";s:4:"name";s:12:"pear.php.net";s:7:"summary";s:40:"PHP Extension and Application Repository";s:7:"servers";a:1:{s:7:"primary";a:1:{s:4:"rest";a:1:{s:7:"baseurl";a:3:{i:0;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.0";}s:8:"_content";s:26:"https://pear.php.net/rest/";}i:1;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.1";}s:8:"_content";s:26:"https://pear.php.net/rest/";}i:2;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.3";}s:8:"_content";s:26:"https://pear.php.net/rest/";}}}}}s:13:"_lastmodified";i:1770291810;}pear/.channels/pecl.php.net.reg000064400000001055152231651300012340 0ustar00a:6:{s:14:"suggestedalias";s:4:"pecl";s:4:"name";s:12:"pecl.php.net";s:7:"summary";s:31:"PHP Extension Community Library";s:7:"servers";a:1:{s:7:"primary";a:1:{s:4:"rest";a:1:{s:7:"baseurl";a:2:{i:0;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.0";}s:8:"_content";s:26:"https://pecl.php.net/rest/";}i:1;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.1";}s:8:"_content";s:26:"https://pecl.php.net/rest/";}}}}}s:15:"validatepackage";a:2:{s:8:"_content";s:19:"PEAR_Validator_PECL";s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}}s:13:"_lastmodified";i:1770291810;}pear/.registry/archive_tar.reg000064400000057442152231651300012421 0ustar00a:24:{s:7:"attribs";a:6:{s:15:"packagerversion";s:7:"1.10.16";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:11:"Archive_Tar";s:7:"channel";s:12:"pear.php.net";s:7:"summary";s:25:"Tar file management class";s:11:"description";s:321:"This class provides handling of tar files in PHP. It supports creating, listing, extracting and adding to tar files. Gzip support is available if PHP has the zlib extension built-in or loaded. Bz2 compression is also supported with the bz2 extension loaded. Also Lzma2 compressed archives are supported with xz extension.";s:4:"lead";a:4:{i:0;a:4:{s:4:"name";s:14:"Vincent Blavet";s:4:"user";s:7:"vblavet";s:5:"email";s:22:"vincent@phpconcept.net";s:6:"active";s:2:"no";}i:1;a:4:{s:4:"name";s:11:"Greg Beaver";s:4:"user";s:6:"cellog";s:5:"email";s:22:"greg@chiaraquartet.net";s:6:"active";s:2:"no";}i:2;a:4:{s:4:"name";s:12:"Michiel Rook";s:4:"user";s:5:"mrook";s:5:"email";s:13:"mrook@php.net";s:6:"active";s:2:"no";}i:3;a:4:{s:4:"name";s:11:"Drew Webber";s:4:"user";s:7:"mcdruid";s:5:"email";s:18:"drew@mcdruid.co.uk";s:6:"active";s:3:"yes";}}s:6:"helper";a:4:{s:4:"name";s:11:"Stig Bakken";s:4:"user";s:3:"ssb";s:5:"email";s:12:"stig@php.net";s:6:"active";s:2:"no";}s:4:"date";s:10:"2025-07-19";s:4:"time";s:8:"14:50:47";s:7:"version";a:2:{s:7:"release";s:5:"1.6.0";s:3:"api";s:5:"1.6.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:160:"This release drops support for PHP 5.4 and 5.5. * PR #51: big file support * PR #53: Fix return value of _writeBlock * PR #58: Remove gzopen/gztell/gzseek shim";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:2:{i:0;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"5f57c123106959a318491b7e5060acba";s:4:"name";s:15:"Archive/Tar.php";s:4:"role";s:3:"php";}}i:1;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"2fb90f0be7089a45c09a0d1182792419";s:4:"name";s:20:"docs/Archive_Tar.txt";s:4:"role";s:3:"doc";}}}}}s:10:"compatible";a:4:{s:4:"name";s:4:"PEAR";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"1.8.0";s:3:"max";s:7:"1.10.10";}s:12:"dependencies";a:1:{s:8:"required";a:2:{s:3:"php";a:1:{s:3:"min";s:5:"5.6.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:6:"1.10.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";a:1:{s:7:"release";a:42:{i:0;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.6.0";s:3:"api";s:5:"1.6.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2025-07-19";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:160:"This release drops support for PHP 5.4 and 5.5. * PR #51: big file support * PR #53: Fix return value of _writeBlock * PR #58: Remove gzopen/gztell/gzseek shim";}i:1;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.5.0";s:3:"api";s:5:"1.5.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2024-03-16";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:130:"* PR #42: fix @return true... to @return bool true... on some functions * PR #46: use 775 default for mkdirs, to avoid world-write";}i:2;a:5:{s:7:"version";a:2:{s:7:"release";s:6:"1.4.14";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2021-02-16";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:60:"* Properly fix symbolic link path traversal (CVE-2021-32610)";}i:3;a:5:{s:7:"version";a:2:{s:7:"release";s:6:"1.4.13";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2021-02-16";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:81:"* Fix Bug #27010: Relative symlinks failing (out-of path file extraction) [mrook]";}i:4;a:5:{s:7:"version";a:2:{s:7:"release";s:6:"1.4.12";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2021-01-18";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:82:"* Fix Bug #27008: Symlink out-of-path write vulnerability (CVE-2020-36193) [mrook]";}i:5;a:5:{s:7:"version";a:2:{s:7:"release";s:6:"1.4.11";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2020-11-19";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:97:"* Fix Bug #27002: Filename manipulation vulnerabilities (CVE-2020-28948 / CVE-2020-28949) [mrook]";}i:6;a:5:{s:7:"version";a:2:{s:7:"release";s:6:"1.4.10";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2020-09-15";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:165:"* Fix block padding when the file buffer length is a multiple of 512 and smaller than Archive_Tar buffer length * Don't try to copy username/groupname in chroot jail";}i:7;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.9";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2019-12-04";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:67:"* Implement Feature #23861: Add option to disallow symlinks [mrook]";}i:8;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.8";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2019-10-21";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:79:"* Fix Bug #23852: PHP 7.4 - Archive_Tar->_readHeader throws deprecation [mrook]";}i:9;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.7";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2019-04-08";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:53:"* Improved performance by increasing read buffer size";}i:10;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.6";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2019-02-01";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:67:"* Improve path traversal detection for forward and backward slashes";}i:11;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.5";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2019-01-02";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:54:"* Fix Bug #23788: Relative symlinks are broken [mrook]";}i:12;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.4";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2018-12-20";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:127:"* Fix Bug #21058: Long symlinks are not supported [mrook] * Fix Bug #23782: Prevent phar:// files from being extracted [mrook]";}i:13;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.3";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2017-06-11";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:103:"* Fix Bug #21218: Cannot use result of built-in function in write context in PHP 7.2.0alpha1 [mrook]";}i:14;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.2";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2016-02-25";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:164:"* Fix reading of archives with files > 8GB * Performance optimizations * Do not try to call require_once on PEAR.php if it has already been loaded by the autoloader";}i:15;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.1";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2015-08-05";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:60:"* Update composer.json to use pear-core-minimal 1.10.0alpha2";}i:16;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.0";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2015-07-20";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:104:"* Add support for PHP 7 * Drop support for PHP 4 * Add visibility declarations to methods and properties";}i:17;a:5:{s:7:"version";a:2:{s:7:"release";s:6:"1.3.16";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2015-04-14";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:73:"* Fix Bug #20514: invalid package.xml; not installable with pyrus [mrook]";}i:18;a:5:{s:7:"version";a:2:{s:7:"release";s:6:"1.3.15";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2015-03-05";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:33:"* Fixes composer.json parse error";}i:19;a:5:{s:7:"version";a:2:{s:7:"release";s:6:"1.3.14";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2015-02-26";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:74:"* Fix Bug #18505: Possible incorrect handling of file names in TAR [mrook]";}i:20;a:5:{s:7:"version";a:2:{s:7:"release";s:6:"1.3.13";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2014-09-02";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:16:"New BSD License";}s:5:"notes";s:36:"* Fix Bug #20382: gzopen fix [mrook]";}i:21;a:5:{s:7:"version";a:2:{s:7:"release";s:6:"1.3.12";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2014-08-04";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:16:"New BSD License";}s:5:"notes";s:350:"* Fix Bug #19964: Memory leaking in Archive_Tar [mrook] * Fix Bug #20246: Broken with php 5.5.9 [mrook] * Fix Bug #20275: "pax_global_header" looks like a regular file * [mrook] * Implement Feature #19827: pass filename to _addFile function - downstream * patch [mrook] * Implement Feature #20132: Add custom mode/uid/gid to addString() [mrook]";}i:22;a:5:{s:7:"version";a:2:{s:7:"release";s:6:"1.3.11";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2013-02-09";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:18:"New BSD License";}s:5:"notes";s:128:"* Fix Bug #19746: Broken with PHP 5.5 [mrook] * Implement Feature #11258: Custom date/time in files added on-the-fly * [mrook]";}i:23;a:5:{s:7:"version";a:2:{s:7:"release";s:6:"1.3.10";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2012-04-10";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:18:"New BSD License";}s:5:"notes";s:143:"* Fix Bug #13361: Unable to add() some files (ex. mp3) [mrook] * Fix Bug #19330: Class creates incorrect (non-readable) tar.gz file * [mrook]";}i:24;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.3.9";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2012-02-27";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:17:"New BSD License";}s:5:"notes";s:259:"* Fix Bug #16759: No error thrown from missing PHP zlib functions [mrook] * Fix Bug #18877: Incorrect handling of backslashes in filenames on Linux [mrook] * Fix Bug #19085: Error while packaging [mrook] * Fix Bug #19289: Invalid tar file generated [mrook]";}i:25;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.3.8";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2011-10-14";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:449:"* Fix Bug #17853: Test failure: dirtraversal.phpt [mrook] * Fix Bug #18512: dead links are not saved in tar file [mrook] * Fix Bug #18702: Unpacks incorrectly on long file names using header prefix [mrook] * Implement Feature #10145: Patch to return a Pear Error Object on failure [mrook] * Implement Feature #17491: Option to preserve permissions [mrook] * Implement Feature #17813: Prevent PHP notice when extracting corrupted archive [mrook]";}i:26;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.3.7";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2010-04-26";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:25:"PEAR compatibility update";}i:27;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.3.6";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2010-03-09";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:168:"* Fix Bug #16963: extractList can't extract zipped files from big tar [mrook] * Implement Feature #4013: Ignoring files and directories on creating an archive. [mrook]";}i:28;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.3.5";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2009-12-31";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:64:"* Fix Bug #16958: Update 'compatible' tag in package.xml [mrook]";}i:29;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.3.4";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2009-12-30";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:338:"* Fix Bug #11871: wrong result of ::listContent() if filename begins or ends with space [mrook] * Fix Bug #12462: invalid tar magic [mrook] * Fix Bug #13918: Long filenames may get up to 511 0x00 bytes appended on read [mrook] * Fix Bug #16202: Bogus modification times [mrook] * Implement Feature #16212: Die is not exception [mrook]";}i:30;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.3.3";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2009-03-27";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:50:"http://www.opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:249:"Change the license to New BSD license minor bugfix release * fix Bug #9921 compression with bzip2 fails [cellog] * fix Bug #11594 _readLongHeader leaves 0 bytes in filename [jamessas] * fix Bug #11769 Incorrect symlink handing [fajar99]";}i:31;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.3.2";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2007-01-03";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:484:"Correct Bug #4016 Remove duplicate remove error display with '@' Correct Bug #3909 : Check existence of OS_WINDOWS constant Correct Bug #5452 fix for "lone zero block" when untarring packages Change filemode (from pear-core/Archive/Tar.php v.1.21) Correct Bug #6486 Can not extract symlinks Correct Bug #6933 Archive_Tar (Tar file management class) Directory traversal Correct Bug #8114 Files added on-the-fly not storing date Correct Bug #9352 Bug on _dirCheck function over nfs path";}i:32;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.3.1";s:3:"api";s:5:"1.3.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2005-03-17";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:17:"Correct Bug #3855";}i:33;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.3.0";s:3:"api";s:5:"1.3.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2005-03-06";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:40:"Bugs correction (2475, 2488, 2135, 2176)";}i:34;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"1.2";s:3:"api";s:3:"1.2";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2004-05-08";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:71:"Add support for other separator than the space char and bug correction";}i:35;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"1.1";s:3:"api";s:3:"1.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2003-05-28";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:141:"* Add support for BZ2 compression * Add support for add and extract without using temporary files : methods addString() and extractInString()";}i:36;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"1.0";s:3:"api";s:3:"1.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2003-01-24";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:23:"Change status to stable";}i:37;a:5:{s:7:"version";a:2:{s:7:"release";s:7:"0.10-b1";s:3:"api";s:7:"0.10-b1";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:4:"date";s:10:"2003-01-08";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:59:"Add support for long filenames (greater than 99 characters)";}i:38;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"0.9";s:3:"api";s:3:"0.9";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2002-05-27";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:25:"Auto-detect gzip'ed files";}i:39;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"0.4";s:3:"api";s:3:"0.4";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2002-05-20";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:51:"Windows bugfix: use forward slashes inside archives";}i:40;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"0.2";s:3:"api";s:3:"0.2";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2002-02-18";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:29:"From initial commit to stable";}i:41;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"0.3";s:3:"api";s:3:"0.3";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2002-04-13";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:47:"Windows bugfix: used wrong directory separators";}}}s:8:"filelist";a:2:{s:15:"Archive/Tar.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"5f57c123106959a318491b7e5060acba";s:4:"name";s:15:"Archive/Tar.php";s:4:"role";s:3:"php";s:12:"installed_as";s:56:"/opt/cpanel/ea-php84/root/usr/share/pear/Archive/Tar.php";}s:20:"docs/Archive_Tar.txt";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"2fb90f0be7089a45c09a0d1182792419";s:4:"name";s:20:"docs/Archive_Tar.txt";s:4:"role";s:3:"doc";s:12:"installed_as";s:77:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/Archive_Tar/docs/Archive_Tar.txt";}}s:12:"_lastversion";N;s:7:"dirtree";a:3:{s:48:"/opt/cpanel/ea-php84/root/usr/share/pear/Archive";b:1;s:61:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/Archive_Tar/docs";b:1;s:56:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/Archive_Tar";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.6.0";s:12:"release_date";s:10:"2025-07-19";s:13:"release_state";s:6:"stable";s:15:"release_license";s:15:"New BSD License";s:13:"release_notes";s:160:"This release drops support for PHP 5.4 and 5.5. * PR #51: big file support * PR #53: Fix return value of _writeBlock * PR #58: Remove gzopen/gztell/gzseek shim";s:12:"release_deps";a:2:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.6.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:6:"1.10.0";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:5:{i:0;a:5:{s:4:"name";s:14:"Vincent Blavet";s:5:"email";s:22:"vincent@phpconcept.net";s:6:"active";s:2:"no";s:6:"handle";s:7:"vblavet";s:4:"role";s:4:"lead";}i:1;a:5:{s:4:"name";s:11:"Greg Beaver";s:5:"email";s:22:"greg@chiaraquartet.net";s:6:"active";s:2:"no";s:6:"handle";s:6:"cellog";s:4:"role";s:4:"lead";}i:2;a:5:{s:4:"name";s:12:"Michiel Rook";s:5:"email";s:13:"mrook@php.net";s:6:"active";s:2:"no";s:6:"handle";s:5:"mrook";s:4:"role";s:4:"lead";}i:3;a:5:{s:4:"name";s:11:"Drew Webber";s:5:"email";s:18:"drew@mcdruid.co.uk";s:6:"active";s:3:"yes";s:6:"handle";s:7:"mcdruid";s:4:"role";s:4:"lead";}i:4;a:5:{s:4:"name";s:11:"Stig Bakken";s:5:"email";s:12:"stig@php.net";s:6:"active";s:2:"no";s:6:"handle";s:3:"ssb";s:4:"role";s:6:"helper";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1770291810;}pear/.registry/console_getopt.reg000064400000025055152231651300013151 0ustar00a:25:{s:7:"attribs";a:6:{s:15:"packagerversion";s:7:"1.10.10";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:14:"Console_Getopt";s:7:"channel";s:12:"pear.php.net";s:7:"summary";s:26:"Command-line option parser";s:11:"description";s:80:"This is a PHP implementation of "getopt" supporting both short and long options.";s:4:"lead";a:4:{s:4:"name";s:15:"Andrei Zmievski";s:4:"user";s:6:"andrei";s:5:"email";s:14:"andrei@php.net";s:6:"active";s:2:"no";}s:9:"developer";a:4:{s:4:"name";s:11:"Stig Bakken";s:4:"user";s:3:"ssb";s:5:"email";s:12:"stig@php.net";s:6:"active";s:2:"no";}s:6:"helper";a:4:{s:4:"name";s:11:"Greg Beaver";s:4:"user";s:6:"cellog";s:5:"email";s:14:"cellog@php.net";s:6:"active";s:2:"no";}s:4:"date";s:10:"2019-11-20";s:4:"time";s:8:"18:27:07";s:7:"version";a:2:{s:7:"release";s:5:"1.4.3";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:12:"BSD-2-Clause";}s:5:"notes";s:98:"* PR #4: Fix PHP 7.4 deprecation: array/string curly braces access * PR #5: fix phplint warnings";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:5:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"63da5909aa85a0eb76e0ad0b5e00811a";s:4:"name";s:18:"Console/Getopt.php";s:4:"role";s:3:"php";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5a6fa63ce6f2370cdad11dc24a5addd0";s:4:"name";s:21:"tests/001-getopt.phpt";s:4:"role";s:4:"test";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7540b630cb8e7bfd8bb06fb65a010ae9";s:4:"name";s:19:"tests/bug10557.phpt";s:4:"role";s:4:"test";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e469de3628de85779118103b3248a44f";s:4:"name";s:19:"tests/bug11068.phpt";s:4:"role";s:4:"test";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"cdc108b084ad8e82eeb2417f04b49ec8";s:4:"name";s:19:"tests/bug13140.phpt";s:4:"role";s:4:"test";}}}}}s:10:"compatible";a:4:{s:4:"name";s:4:"PEAR";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"1.4.0";s:3:"max";s:9:"1.999.999";}s:12:"dependencies";a:1:{s:8:"required";a:2:{s:3:"php";a:1:{s:3:"min";s:5:"5.4.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.8.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";a:1:{s:7:"release";a:14:{i:0;a:5:{s:4:"date";s:10:"2019-11-20";s:7:"version";a:2:{s:7:"release";s:5:"1.4.3";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:12:"BSD-2-Clause";}s:5:"notes";s:98:"* PR #4: Fix PHP 7.4 deprecation: array/string curly braces access * PR #5: fix phplint warnings";}i:1;a:5:{s:4:"date";s:10:"2019-02-06";s:7:"version";a:2:{s:7:"release";s:5:"1.4.2";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:12:"BSD-2-Clause";}s:5:"notes";s:49:"* Remove use of each(), which is removed in PHP 8";}i:2;a:5:{s:4:"date";s:10:"2015-07-20";s:7:"version";a:2:{s:7:"release";s:5:"1.4.1";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:12:"BSD-2-Clause";}s:5:"notes";s:34:"* Fix unit test on PHP 7 [cweiske]";}i:3;a:5:{s:4:"date";s:10:"2015-02-22";s:7:"version";a:2:{s:7:"release";s:5:"1.4.0";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:12:"BSD-2-Clause";}s:5:"notes";s:111:"* Change license to BSD-2-Clause * Set minimum PHP version to 5.4.0 * Mark static methods with "static" keyword";}i:4;a:5:{s:4:"date";s:10:"2011-03-07";s:7:"version";a:2:{s:7:"release";s:5:"1.3.1";s:3:"api";s:5:"1.3.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:51:"* Change the minimum PEAR installer dep to be lower";}i:5;a:6:{s:4:"date";s:10:"2010-12-11";s:4:"time";s:8:"20:20:13";s:7:"version";a:2:{s:7:"release";s:5:"1.3.0";s:3:"api";s:5:"1.3.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:106:"* Implement Request #13140: [PATCH] to skip unknown parameters. [patch by rquadling, improved on by dufuz]";}i:6;a:5:{s:4:"date";s:10:"2007-06-12";s:7:"version";a:2:{s:7:"release";s:5:"1.2.3";s:3:"api";s:5:"1.2.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:58:"* fix Bug #11068: No way to read plain "-" option [cardoe]";}i:7;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.2.2";s:3:"api";s:5:"1.2.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2007-02-17";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:165:"* fix Bug #4475: An ambiguous error occurred when specifying similar longoption name. * fix Bug #10055: Not failing properly on short options missing required values";}i:8;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.2.1";s:3:"api";s:5:"1.2.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2006-12-08";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:126:"Fixed bugs #4448 (Long parameter values truncated with longoption parameter) and #7444 (Trailing spaces after php closing tag)";}i:9;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"1.2";s:3:"api";s:3:"1.2";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2003-12-11";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:69:"Fix to preserve BC with 1.0 and allow correct behaviour for new users";}i:10;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"1.0";s:3:"api";s:3:"1.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2002-09-13";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:14:"Stable release";}i:11;a:5:{s:7:"version";a:2:{s:7:"release";s:4:"0.11";s:3:"api";s:4:"0.11";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:4:"date";s:10:"2002-05-26";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:89:"POSIX getopt compatibility fix: treat first element of args array as command name";}i:12;a:5:{s:7:"version";a:2:{s:7:"release";s:4:"0.10";s:3:"api";s:4:"0.10";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:4:"date";s:10:"2002-05-12";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:13:"Packaging fix";}i:13;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"0.9";s:3:"api";s:3:"0.9";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:4:"date";s:10:"2002-05-12";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:15:"Initial release";}}}s:8:"filelist";a:5:{s:18:"Console/Getopt.php";a:4:{s:6:"md5sum";s:32:"63da5909aa85a0eb76e0ad0b5e00811a";s:4:"name";s:18:"Console/Getopt.php";s:4:"role";s:3:"php";s:12:"installed_as";s:59:"/opt/cpanel/ea-php84/root/usr/share/pear/Console/Getopt.php";}s:21:"tests/001-getopt.phpt";a:4:{s:6:"md5sum";s:32:"5a6fa63ce6f2370cdad11dc24a5addd0";s:4:"name";s:21:"tests/001-getopt.phpt";s:4:"role";s:4:"test";s:12:"installed_as";s:83:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/Console_Getopt/tests/001-getopt.phpt";}s:19:"tests/bug10557.phpt";a:4:{s:6:"md5sum";s:32:"7540b630cb8e7bfd8bb06fb65a010ae9";s:4:"name";s:19:"tests/bug10557.phpt";s:4:"role";s:4:"test";s:12:"installed_as";s:81:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/Console_Getopt/tests/bug10557.phpt";}s:19:"tests/bug11068.phpt";a:4:{s:6:"md5sum";s:32:"e469de3628de85779118103b3248a44f";s:4:"name";s:19:"tests/bug11068.phpt";s:4:"role";s:4:"test";s:12:"installed_as";s:81:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/Console_Getopt/tests/bug11068.phpt";}s:19:"tests/bug13140.phpt";a:4:{s:6:"md5sum";s:32:"cdc108b084ad8e82eeb2417f04b49ec8";s:4:"name";s:19:"tests/bug13140.phpt";s:4:"role";s:4:"test";s:12:"installed_as";s:81:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/Console_Getopt/tests/bug13140.phpt";}}s:12:"_lastversion";N;s:7:"dirtree";a:3:{s:48:"/opt/cpanel/ea-php84/root/usr/share/pear/Console";b:1;s:67:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/Console_Getopt/tests";b:1;s:61:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/Console_Getopt";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.4.3";s:12:"release_date";s:10:"2019-11-20";s:13:"release_state";s:6:"stable";s:15:"release_license";s:12:"BSD-2-Clause";s:13:"release_notes";s:98:"* PR #4: Fix PHP 7.4 deprecation: array/string curly braces access * PR #5: fix phplint warnings";s:12:"release_deps";a:2:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.4.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.8.0";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:3:{i:0;a:5:{s:4:"name";s:15:"Andrei Zmievski";s:5:"email";s:14:"andrei@php.net";s:6:"active";s:2:"no";s:6:"handle";s:6:"andrei";s:4:"role";s:4:"lead";}i:1;a:5:{s:4:"name";s:11:"Stig Bakken";s:5:"email";s:12:"stig@php.net";s:6:"active";s:2:"no";s:6:"handle";s:3:"ssb";s:4:"role";s:9:"developer";}i:2;a:5:{s:4:"name";s:11:"Greg Beaver";s:5:"email";s:14:"cellog@php.net";s:6:"active";s:2:"no";s:6:"handle";s:6:"cellog";s:4:"role";s:6:"helper";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1770291810;}pear/.registry/pear.reg000064400000311642152231651300011054 0ustar00a:24:{s:7:"attribs";a:6:{s:15:"packagerversion";s:7:"1.10.18";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:4:"PEAR";s:7:"channel";s:12:"pear.php.net";s:7:"summary";s:16:"PEAR Base System";s:11:"description";s:1100:"The PEAR package contains: * the PEAR installer, for creating, distributing and installing packages * the PEAR_Exception PHP5 error handling mechanism * the PEAR_ErrorStack advanced error handling mechanism * the PEAR_Error error handling mechanism * the OS_Guess class for retrieving info about the OS where PHP is running on * the System class for quick handling of common operations with files and directories * the PEAR base class Features in a nutshell: * full support for channels * pre-download dependency validation * new package.xml 2.0 format allows tremendous flexibility while maintaining BC * support for optional dependency groups and limited support for sub-packaging * robust dependency support * full dependency validation on uninstall * remote install for hosts with only ftp access - no more problems with restricted host installation * full support for mirroring * support for bundling several packages into a single tarball * support for static dependencies on a url-based package * support for custom file roles and installation tasks";s:4:"lead";a:7:{i:0;a:4:{s:4:"name";s:11:"Greg Beaver";s:4:"user";s:6:"cellog";s:5:"email";s:14:"cellog@php.net";s:6:"active";s:2:"no";}i:1;a:4:{s:4:"name";s:17:"Pierre-Alain Joye";s:4:"user";s:6:"pajoye";s:5:"email";s:14:"pierre@php.net";s:6:"active";s:2:"no";}i:2;a:4:{s:4:"name";s:11:"Stig Bakken";s:4:"user";s:3:"ssb";s:5:"email";s:12:"stig@php.net";s:6:"active";s:2:"no";}i:3;a:4:{s:4:"name";s:13:"Tomas V.V.Cox";s:4:"user";s:3:"cox";s:5:"email";s:15:"cox@idecnet.com";s:6:"active";s:2:"no";}i:4;a:4:{s:4:"name";s:13:"Helgi Thormar";s:4:"user";s:5:"dufuz";s:5:"email";s:13:"dufuz@php.net";s:6:"active";s:2:"no";}i:5;a:4:{s:4:"name";s:16:"Christian Weiske";s:4:"user";s:7:"cweiske";s:5:"email";s:15:"cweiske@php.net";s:6:"active";s:2:"no";}i:6;a:4:{s:4:"name";s:13:"Chuck Burgess";s:4:"user";s:7:"ashnazg";s:5:"email";s:15:"ashnazg@php.net";s:6:"active";s:3:"yes";}}s:9:"developer";a:4:{s:4:"name";s:9:"Tias Guns";s:4:"user";s:4:"tias";s:5:"email";s:12:"tias@php.net";s:6:"active";s:2:"no";}s:6:"helper";a:3:{i:0;a:4:{s:4:"name";s:11:"Tim Jackson";s:4:"user";s:4:"timj";s:5:"email";s:12:"timj@php.net";s:6:"active";s:2:"no";}i:1;a:4:{s:4:"name";s:15:"Bertrand Gugger";s:4:"user";s:5:"toggg";s:5:"email";s:13:"toggg@php.net";s:6:"active";s:2:"no";}i:2;a:4:{s:4:"name";s:13:"Martin Jansen";s:4:"user";s:2:"mj";s:5:"email";s:10:"mj@php.net";s:6:"active";s:2:"no";}}s:4:"date";s:10:"2026-01-25";s:4:"time";s:8:"17:16:16";s:7:"version";a:2:{s:7:"release";s:7:"1.10.18";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:46:"* PR #164: don't use report_memleaks with 8.5+";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:105:{i:0;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"710f2fc4aeb9527399c825413c2f04ce";s:4:"name";s:12:"OS/Guess.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:1;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1bfedc46c9ddf33d4c06a6c43c4c6e64";s:4:"name";s:27:"PEAR/ChannelFile/Parser.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8fd87e64002e11fd86eb2f3fbfee6599";s:4:"name";s:21:"PEAR/Command/Auth.xml";s:4:"role";s:3:"php";}}i:3;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4613f7743eb91fd7f58b91393286bea0";s:4:"name";s:21:"PEAR/Command/Auth.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ce6bb5b6fdc02e0f50e7676403fd84a4";s:4:"name";s:22:"PEAR/Command/Build.xml";s:4:"role";s:3:"php";}}i:5;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c7c4c929113d4bbd8c52bbfdcc980e40";s:4:"name";s:22:"PEAR/Command/Build.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"6d5aab4d4308c3005b5f584c7783a031";s:4:"name";s:25:"PEAR/Command/Channels.xml";s:4:"role";s:3:"php";}}i:7;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e07497190ca5a4cb55b89bb6afa35bc1";s:4:"name";s:25:"PEAR/Command/Channels.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:8;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8458be827f99e753b2d023fcf2c28836";s:4:"name";s:23:"PEAR/Command/Common.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:9;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"91f189cb9423b5e87ee0abc5ea1a2be3";s:4:"name";s:23:"PEAR/Command/Config.xml";s:4:"role";s:3:"php";}}i:10;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"412f3bd8f6b004c85297cbdc46f6b113";s:4:"name";s:23:"PEAR/Command/Config.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:11;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"24d05213cae7faa3880bbb5e40998867";s:4:"name";s:24:"PEAR/Command/Install.xml";s:4:"role";s:3:"php";}}i:12;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"da531a58113be03c3ca4b3d6316a5465";s:4:"name";s:24:"PEAR/Command/Install.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:13;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5cb62a04c0a268f4edd64a49a3895c92";s:4:"name";s:23:"PEAR/Command/Mirror.xml";s:4:"role";s:3:"php";}}i:14;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ff1c2425c6c9da87e4796296c86f78cb";s:4:"name";s:23:"PEAR/Command/Mirror.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:15;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9367dcd7e4dbdde423f9c4c7d3f3a919";s:4:"name";s:24:"PEAR/Command/Package.xml";s:4:"role";s:3:"php";}}i:16;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"57521ff1e89bcd23a853134f30836990";s:4:"name";s:24:"PEAR/Command/Package.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:2:{i:0;a:1:{s:7:"attribs";a:3:{s:4:"from";s:10:"@DATA-DIR@";s:2:"to";s:8:"data_dir";s:4:"type";s:11:"pear-config";}}i:1;a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}}i:17;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"28dc842ea725d8787b9f9c3dbca5aa22";s:4:"name";s:23:"PEAR/Command/Pickle.xml";s:4:"role";s:3:"php";}}i:18;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"994bad38e47de38540ab2612512951f9";s:4:"name";s:23:"PEAR/Command/Pickle.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:19;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"49b046cfc14747f0365e02e9c3f0e6dc";s:4:"name";s:25:"PEAR/Command/Registry.xml";s:4:"role";s:3:"php";}}i:20;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1dcd16290ef855fb61e5f050ae42b943";s:4:"name";s:25:"PEAR/Command/Registry.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:21;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"29c02e823879b4e3e291f6b36fb339f1";s:4:"name";s:23:"PEAR/Command/Remote.xml";s:4:"role";s:3:"php";}}i:22;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"40c25d700ef1253cc05964fe8c3a9b2b";s:4:"name";s:23:"PEAR/Command/Remote.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:23;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a50c32015005e0761cc3b04679b29ed0";s:4:"name";s:21:"PEAR/Command/Test.xml";s:4:"role";s:3:"php";}}i:24;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c1b78cf129b78c891ae38434bcf616f4";s:4:"name";s:21:"PEAR/Command/Test.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:25;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e8c257e98945ba4fd138f2afa9d958be";s:4:"name";s:27:"PEAR/Downloader/Package.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:10:"@PEAR-VER@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:26;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1c16b9b7db915fbaecdb79f708bb63b2";s:4:"name";s:21:"PEAR/Frontend/CLI.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:27;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a272d31bbbc4ed39f9a2fcaffabe0221";s:4:"name";s:30:"PEAR/Installer/Role/Common.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:28;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d8c62e6275e3aaa7784290912406092c";s:4:"name";s:27:"PEAR/Installer/Role/Cfg.xml";s:4:"role";s:3:"php";}}i:29;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8298fbda287b9335fd65a54c17610aa1";s:4:"name";s:27:"PEAR/Installer/Role/Cfg.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:30;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"89a4a2a286e842d45a98974f40a0565c";s:4:"name";s:28:"PEAR/Installer/Role/Data.xml";s:4:"role";s:3:"php";}}i:31;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7fb06acd4c4a0ca51473c373a5ea25bc";s:4:"name";s:28:"PEAR/Installer/Role/Data.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:32;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b1ce0fe105251c3b75209d6518ee69ac";s:4:"name";s:27:"PEAR/Installer/Role/Doc.xml";s:4:"role";s:3:"php";}}i:33;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d1ff8118c5591425ccce01f2e4422f1f";s:4:"name";s:27:"PEAR/Installer/Role/Doc.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:34;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"af71c0ad42d16a323afe24a4f884ef15";s:4:"name";s:27:"PEAR/Installer/Role/Ext.xml";s:4:"role";s:3:"php";}}i:35;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"28e48624af3751cfccba41c7bfa721e9";s:4:"name";s:27:"PEAR/Installer/Role/Ext.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:36;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"da6743f1e45cce72ea13aef5cdb14867";s:4:"name";s:27:"PEAR/Installer/Role/Man.xml";s:4:"role";s:3:"php";}}i:37;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"172ff6e36139cf5d93a49547fe170c6b";s:4:"name";s:27:"PEAR/Installer/Role/Man.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:38;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ef88f0321d3e481c2130c95122cf76d8";s:4:"name";s:27:"PEAR/Installer/Role/Php.xml";s:4:"role";s:3:"php";}}i:39;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"88ecaccdbfc4442bc3a0b9ce743b1451";s:4:"name";s:27:"PEAR/Installer/Role/Php.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:40;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"746461dc3b48af6d24094cb0211608f2";s:4:"name";s:30:"PEAR/Installer/Role/Script.xml";s:4:"role";s:3:"php";}}i:41;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3c6367165a123612b2e59350358ceb56";s:4:"name";s:30:"PEAR/Installer/Role/Script.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:42;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e147d63f168ea156fc2be38caaa63804";s:4:"name";s:27:"PEAR/Installer/Role/Src.xml";s:4:"role";s:3:"php";}}i:43;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"036f7426c9dceab48fd2aaaedfbe4dcc";s:4:"name";s:27:"PEAR/Installer/Role/Src.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:44;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a24b596ec987aa5688fc19e8ed4e97ea";s:4:"name";s:28:"PEAR/Installer/Role/Test.xml";s:4:"role";s:3:"php";}}i:45;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"df03e84842af8752ba45337a99d3f27b";s:4:"name";s:28:"PEAR/Installer/Role/Test.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:46;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7641e71c5785bb33a4261ebe25ed0fd7";s:4:"name";s:27:"PEAR/Installer/Role/Www.xml";s:4:"role";s:3:"php";}}i:47;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"fc588d30fa49c881edc2051117aeecb3";s:4:"name";s:27:"PEAR/Installer/Role/Www.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:48;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5324e20d3c00a9a4f32aaa0087935931";s:4:"name";s:23:"PEAR/Installer/Role.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:49;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"852fe270e5840c1802102cfa70adbc65";s:4:"name";s:33:"PEAR/PackageFile/Generator/v1.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:10:"@PEAR-VER@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:50;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e51e162c786b1a1c01a00e9e0ba0f788";s:4:"name";s:33:"PEAR/PackageFile/Generator/v2.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:10:"@PEAR-VER@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:51;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a2206e0e32ad2ba2f4e2a0c1797f295c";s:4:"name";s:30:"PEAR/PackageFile/Parser/v1.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:52;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3857f4b60878d64551a7cdae783437f7";s:4:"name";s:30:"PEAR/PackageFile/Parser/v2.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:53;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d27ad5d011c82d0ef28546af1f086793";s:4:"name";s:26:"PEAR/PackageFile/v2/rw.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:54;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e20989993e6f2cb4e1243e695323325e";s:4:"name";s:33:"PEAR/PackageFile/v2/Validator.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:55;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e22777d62e365061fd9bd1a621f4dc71";s:4:"name";s:23:"PEAR/PackageFile/v1.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:56;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"864f1cdd3b687b21529af36c2bf63a9a";s:4:"name";s:23:"PEAR/PackageFile/v2.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:57;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"36810652a94aff3a723340a37c050c47";s:4:"name";s:16:"PEAR/REST/10.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:58;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"dd6740e44c406ae6845350181ec77b72";s:4:"name";s:16:"PEAR/REST/11.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:59;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"beb6efb630741b52b20e96fce33ae303";s:4:"name";s:16:"PEAR/REST/13.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:60;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c0131a4918d440d38f4ea4c93a5cd62f";s:4:"name";s:34:"PEAR/Task/Postinstallscript/rw.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:61;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"15ec3dfa927b8c93c634c2df446e3a71";s:4:"name";s:24:"PEAR/Task/Replace/rw.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:62;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f3bb8f7a3cf88fab739322675874f78e";s:4:"name";s:24:"PEAR/Task/Unixeol/rw.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:63;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"fb5ce8025259d3849c69924279190c24";s:4:"name";s:27:"PEAR/Task/Windowseol/rw.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:64;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9241b55c944587eb0582f03e337f6948";s:4:"name";s:20:"PEAR/Task/Common.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:65;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f3c27b9aed2d674df4496130621f4ba5";s:4:"name";s:31:"PEAR/Task/Postinstallscript.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:66;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3d120d9e0a1662522d19bdd86b035b34";s:4:"name";s:21:"PEAR/Task/Replace.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:67;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3c43bf148b6a1304d429f8a0366315de";s:4:"name";s:21:"PEAR/Task/Unixeol.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:68;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a5f8761e52cf9021656b47ba7516d304";s:4:"name";s:24:"PEAR/Task/Windowseol.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:69;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e356da2309b2e9a94bead0d436ab620b";s:4:"name";s:23:"PEAR/Validator/PECL.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:70;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e2990ea082ae4d608c2e1c8229be0312";s:4:"name";s:16:"PEAR/Builder.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:10:"@PEAR-VER@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:71;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a671c1f8a68e8e35e0fd8e7cbc197eb0";s:4:"name";s:20:"PEAR/ChannelFile.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:72;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e7ff5118db3fc067dfb877d85b56b4e5";s:4:"name";s:16:"PEAR/Command.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:73;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"94a4a15cbbded5d3a459e69c9da0b5f9";s:4:"name";s:15:"PEAR/Common.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:74;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a4f77a000088f10a90e88e2f74ef7aca";s:4:"name";s:15:"PEAR/Config.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:75;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"20f6136fc2c05e05fc90c66ca06f98b8";s:4:"name";s:21:"PEAR/DependencyDB.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:76;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0d64741dd4792a31caf0b7eff82fc94b";s:4:"name";s:20:"PEAR/Dependency2.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:10:"@PEAR-VER@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:77;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2c1a3d1ce93da76a0f9df47b6f9e4378";s:4:"name";s:19:"PEAR/Downloader.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:78;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4028882af59da2f771396d80357a4c0a";s:4:"name";s:19:"PEAR/ErrorStack.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:79;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d0af85a0b030d935d902a150b6c286a2";s:4:"name";s:18:"PEAR/Exception.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:80;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e6df94ed230c78ef0901d5f1462aac94";s:4:"name";s:17:"PEAR/Frontend.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:81;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"cb26ac2890573449bffd216bee8af7c0";s:4:"name";s:18:"PEAR/Installer.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:82;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b3a3879466c1a8ad088a0cb065fb8b20";s:4:"name";s:20:"PEAR/PackageFile.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:10:"@PEAR-VER@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:83;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9bca9c2527fd31f946f71b6464916346";s:4:"name";s:17:"PEAR/Packager.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:84;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ef9d00adaeccff7516f08170096026d3";s:4:"name";s:14:"PEAR/Proxy.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:85;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"45bb095c0e21e4acd6b2bba15a299aa4";s:4:"name";s:17:"PEAR/Registry.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:86;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7a77064229a52a0bb129ad0e7091c289";s:4:"name";s:13:"PEAR/REST.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:87;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ab6768aa6fad56237abb4b0da461bf58";s:4:"name";s:16:"PEAR/RunTest.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:88;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a3fa972624a98a3bd001fd8bb4d0c150";s:4:"name";s:17:"PEAR/Validate.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:89;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7b14f5fc171f7c48964867eae88b432c";s:4:"name";s:18:"PEAR/XMLParser.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:90;a:3:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"d888d06143e3cac0dae78bbb2e761366";s:4:"name";s:16:"scripts/pear.bat";s:4:"role";s:6:"script";}s:13:"tasks:replace";a:3:{i:0;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@bin_dir@";s:2:"to";s:7:"bin_dir";s:4:"type";s:11:"pear-config";}}i:1;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_bin@";s:2:"to";s:7:"php_bin";s:4:"type";s:11:"pear-config";}}i:2;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@include_path@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}}s:16:"tasks:windowseol";s:0:"";}i:91;a:3:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"17d7d08ce2c6c476eeaae4763f69efcc";s:4:"name";s:19:"scripts/peardev.bat";s:4:"role";s:6:"script";}s:13:"tasks:replace";a:3:{i:0;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@bin_dir@";s:2:"to";s:7:"bin_dir";s:4:"type";s:11:"pear-config";}}i:1;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_bin@";s:2:"to";s:7:"php_bin";s:4:"type";s:11:"pear-config";}}i:2;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@include_path@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}}s:16:"tasks:windowseol";s:0:"";}i:92;a:3:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"1c5819d67da59739e6298d6094c58f7b";s:4:"name";s:16:"scripts/pecl.bat";s:4:"role";s:6:"script";}s:13:"tasks:replace";a:3:{i:0;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@bin_dir@";s:2:"to";s:7:"bin_dir";s:4:"type";s:11:"pear-config";}}i:1;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_bin@";s:2:"to";s:7:"php_bin";s:4:"type";s:11:"pear-config";}}i:2;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@include_path@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}}s:16:"tasks:windowseol";s:0:"";}i:93;a:3:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"8ac139504e80bede470aef6d405100b6";s:4:"name";s:15:"scripts/pear.sh";s:4:"role";s:6:"script";}s:13:"tasks:replace";a:4:{i:0;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_bin@";s:2:"to";s:7:"php_bin";s:4:"type";s:11:"pear-config";}}i:1;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_dir@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}i:2;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@pear_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}i:3;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@include_path@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}}s:13:"tasks:unixeol";s:0:"";}i:94;a:3:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"08ea03525b4ba914dfd9ec69c4238cf4";s:4:"name";s:18:"scripts/peardev.sh";s:4:"role";s:6:"script";}s:13:"tasks:replace";a:4:{i:0;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_bin@";s:2:"to";s:7:"php_bin";s:4:"type";s:11:"pear-config";}}i:1;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_dir@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}i:2;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@pear_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}i:3;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@include_path@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}}s:13:"tasks:unixeol";s:0:"";}i:95;a:3:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"bde09b17fa816d58bb136375a13119c3";s:4:"name";s:15:"scripts/pecl.sh";s:4:"role";s:6:"script";}s:13:"tasks:replace";a:4:{i:0;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_bin@";s:2:"to";s:7:"php_bin";s:4:"type";s:11:"pear-config";}}i:1;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_dir@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}i:2;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@pear_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}i:3;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@include_path@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}}s:13:"tasks:unixeol";s:0:"";}i:96;a:2:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"9b5d5e5bd017c50df00c6b34ef32652e";s:4:"name";s:19:"scripts/pearcmd.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:4:{i:0;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_bin@";s:2:"to";s:7:"php_bin";s:4:"type";s:11:"pear-config";}}i:1;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_dir@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}i:2;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@pear_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}i:3;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@include_path@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}}}i:97;a:2:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"48867dfbb41f2532d034f56a79565893";s:4:"name";s:19:"scripts/peclcmd.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:4:{i:0;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_bin@";s:2:"to";s:7:"php_bin";s:4:"type";s:11:"pear-config";}}i:1;a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_dir@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}i:2;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@pear_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}i:3;a:1:{s:7:"attribs";a:3:{s:4:"from";s:14:"@include_path@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}}}i:98;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"45b44486d8090de17b2a8b4211fab247";s:4:"name";s:7:"LICENSE";s:4:"role";s:3:"doc";}}i:99;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"eaac3d33068c6e67573ed44155b149ae";s:4:"name";s:7:"INSTALL";s:4:"role";s:3:"doc";}}i:100;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"69341ea97af9c88956568f8e7e41d4c6";s:4:"name";s:11:"package.dtd";s:4:"role";s:4:"data";}}i:101;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"23579a5555774b6f6a6405294a404dfc";s:4:"name";s:8:"PEAR.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:102;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"cd10521cc4054923a3d2b6e15b4df493";s:4:"name";s:10:"README.rst";s:4:"role";s:3:"doc";}}i:103;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4f62391952fe4b3097c73d16dae5b2ab";s:4:"name";s:10:"System.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:104;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"acd010e3bc43c0f72df584acde7b9158";s:4:"name";s:13:"template.spec";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:2:{s:8:"required";a:4:{s:3:"php";a:1:{s:3:"min";s:5:"5.4.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:6:"1.10.1";}s:7:"package";a:4:{i:0;a:4:{s:4:"name";s:11:"Archive_Tar";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"1.4.9";s:11:"recommended";s:5:"1.4.4";}i:1;a:4:{s:4:"name";s:16:"Structures_Graph";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"1.1.0";s:11:"recommended";s:5:"1.1.1";}i:2;a:4:{s:4:"name";s:14:"Console_Getopt";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"1.4.1";s:11:"recommended";s:5:"1.4.3";}i:3;a:4:{s:4:"name";s:8:"XML_Util";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"1.4.0";s:11:"recommended";s:5:"1.4.5";}}s:9:"extension";a:2:{i:0;a:1:{s:4:"name";s:3:"xml";}i:1;a:1:{s:4:"name";s:4:"pcre";}}}s:5:"group";a:3:{i:0;a:2:{s:7:"attribs";a:2:{s:4:"hint";s:26:"PEAR's web-based installer";s:4:"name";s:12:"webinstaller";}s:7:"package";a:3:{s:4:"name";s:17:"PEAR_Frontend_Web";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"0.5.1";}}i:1;a:2:{s:7:"attribs";a:2:{s:4:"hint";s:30:"PEAR's PHP-GTK-based installer";s:4:"name";s:12:"gtkinstaller";}s:7:"package";a:3:{s:4:"name";s:17:"PEAR_Frontend_Gtk";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"0.4.0";}}i:2;a:2:{s:7:"attribs";a:2:{s:4:"hint";s:31:"PEAR's PHP-GTK2-based installer";s:4:"name";s:13:"gtk2installer";}s:7:"package";a:2:{s:4:"name";s:18:"PEAR_Frontend_Gtk2";s:7:"channel";s:12:"pear.php.net";}}}}s:10:"phprelease";a:2:{i:0;a:2:{s:17:"installconditions";a:1:{s:2:"os";a:1:{s:4:"name";s:7:"windows";}}s:8:"filelist";a:2:{s:7:"install";a:5:{i:0;a:1:{s:7:"attribs";a:2:{s:2:"as";s:8:"pear.bat";s:4:"name";s:16:"scripts/pear.bat";}}i:1;a:1:{s:7:"attribs";a:2:{s:2:"as";s:11:"peardev.bat";s:4:"name";s:19:"scripts/peardev.bat";}}i:2;a:1:{s:7:"attribs";a:2:{s:2:"as";s:8:"pecl.bat";s:4:"name";s:16:"scripts/pecl.bat";}}i:3;a:1:{s:7:"attribs";a:2:{s:2:"as";s:11:"pearcmd.php";s:4:"name";s:19:"scripts/pearcmd.php";}}i:4;a:1:{s:7:"attribs";a:2:{s:2:"as";s:11:"peclcmd.php";s:4:"name";s:19:"scripts/peclcmd.php";}}}s:6:"ignore";a:3:{i:0;a:1:{s:7:"attribs";a:1:{s:4:"name";s:18:"scripts/peardev.sh";}}i:1;a:1:{s:7:"attribs";a:1:{s:4:"name";s:15:"scripts/pear.sh";}}i:2;a:1:{s:7:"attribs";a:1:{s:4:"name";s:15:"scripts/pecl.sh";}}}}}i:1;a:1:{s:8:"filelist";a:2:{s:7:"install";a:5:{i:0;a:1:{s:7:"attribs";a:2:{s:2:"as";s:4:"pear";s:4:"name";s:15:"scripts/pear.sh";}}i:1;a:1:{s:7:"attribs";a:2:{s:2:"as";s:7:"peardev";s:4:"name";s:18:"scripts/peardev.sh";}}i:2;a:1:{s:7:"attribs";a:2:{s:2:"as";s:4:"pecl";s:4:"name";s:15:"scripts/pecl.sh";}}i:3;a:1:{s:7:"attribs";a:2:{s:2:"as";s:11:"pearcmd.php";s:4:"name";s:19:"scripts/pearcmd.php";}}i:4;a:1:{s:7:"attribs";a:2:{s:2:"as";s:11:"peclcmd.php";s:4:"name";s:19:"scripts/peclcmd.php";}}}s:6:"ignore";a:3:{i:0;a:1:{s:7:"attribs";a:1:{s:4:"name";s:16:"scripts/pear.bat";}}i:1;a:1:{s:7:"attribs";a:1:{s:4:"name";s:19:"scripts/peardev.bat";}}i:2;a:1:{s:7:"attribs";a:1:{s:4:"name";s:16:"scripts/pecl.bat";}}}}}}s:9:"changelog";a:1:{s:7:"release";a:37:{i:0;a:5:{s:7:"version";a:2:{s:7:"release";s:11:"1.8.0alpha1";s:3:"api";s:5:"1.8.0";}s:9:"stability";a:2:{s:7:"release";s:5:"alpha";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2009-03-09";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:4876:"* Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] * Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] * Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] * Implement Request #11170: script to generate Command/[command].xml [dufuz] * Implement Request #11176: improve channel ... has updated its protocols message [dufuz] * Implement Request #12706: pear list -a hard to read [dufuz] * Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] * Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] * Implement Request #13927: install-pear.php should have option to set www_dir [timj] * Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] * Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate better what other package managers are doing. upgrade-all will still work as intended. * Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for channel specific upgrades * Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] * Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] * Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] * Fix PHP Bug #47323: strotime warnings in make install [dufuz] * Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] * Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] * Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] * Fix Bug #13953: config-set/config-show with channel alias fail [cellog] * Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] * Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] * Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] * Fix Bug #14210: pear list -ia brings warnings [dufuz] * Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] * Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] * Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] * Fix Bug #14437: openbasedir warning when loading config [dufuz] * Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] * Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] * Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] * Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] * Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] * Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] NOTE! Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment to migrate over to one of the alternatives that have ben provided: * PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) * PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) * PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) * PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) * PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) * PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) * PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) * PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) * PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) * PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or PEAR_PackageFile_v2_Validator->_buildProvidesArray) PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls pear upgrade -f PEAR will allow people with lower versions to upgrade to this release but no guarantees will be made that it will work properly. Support for XML RPC channels has been dropped - The only ones that used it (pear.php.net and pecl.php.net) have used the REST interface for years now. SOAP support also removed as it was only proof of concept. Move codebase from the PHP License to New BSD 2 clause license";}i:1;a:5:{s:4:"date";s:10:"2009-03-27";s:7:"version";a:2:{s:7:"release";s:8:"1.8.0RC1";s:3:"api";s:5:"1.8.0";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:347:"* Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] * Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] * Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] * Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz]";}i:2;a:5:{s:4:"date";s:10:"2009-04-10";s:7:"version";a:2:{s:7:"release";s:5:"1.8.0";s:3:"api";s:5:"1.8.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:5737:"Changes since RC1: * Fix Bug #14792: Bad md5sum for files with replaced content [dufuz] * Fix Bug #16057:-r is limited to 4 directories in depth [dufuz] * Fix Bug #16077: PEAR5::getStaticProperty does not return a reference to the property [dufuz] Remove custom XML_Util class in favor of using upstream XML_Util package as dependency RC1 Release Notes: * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] * Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] * Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] * Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz] Alpha1 Release Notes: * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] * Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] * Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] * Implement Request #11170: script to generate Command/[command].xml [dufuz] * Implement Request #11176: improve channel ... has updated its protocols message [dufuz] * Implement Request #12706: pear list -a hard to read [dufuz] * Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] * Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] * Implement Request #13927: install-pear.php should have option to set www_dir [timj] * Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] * Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate better what other package managers are doing. upgrade-all will still work as intended. * Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for channel specific upgrades * Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] * Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] * Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] * Fix PHP Bug #47323: strotime warnings in make install [dufuz] * Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] * Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] * Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] * Fix Bug #13953: config-set/config-show with channel alias fail [cellog] * Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] * Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] * Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] * Fix Bug #14210: pear list -ia brings warnings [dufuz] * Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] * Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] * Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] * Fix Bug #14437: openbasedir warning when loading config [dufuz] * Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] * Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] * Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] * Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] * Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] * Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] NOTE! Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment to migrate over to one of the alternatives that have ben provided: * PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) * PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) * PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) * PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) * PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) * PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) * PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) * PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) * PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) * PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or PEAR_PackageFile_v2_Validator->_buildProvidesArray) PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls pear upgrade -f PEAR will allow people with lower versions to upgrade to this release but no guarantees will be made that it will work properly. Support for XML RPC channels has been dropped - The only ones that used it (pear.php.net and pecl.php.net) have used the REST interface for years now. SOAP support also removed as it was only proof of concept. Move codebase from the PHP License to New BSD 2 clause license";}i:3;a:5:{s:4:"date";s:10:"2009-04-15";s:7:"version";a:2:{s:7:"release";s:5:"1.8.1";s:3:"api";s:5:"1.8.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:58:"* Fix Bug #16099 PEAR crash on PHP4 (parse error) [dufuz]";}i:4;a:5:{s:4:"date";s:10:"2009-08-18";s:7:"version";a:2:{s:7:"release";s:8:"1.9.0RC1";s:3:"api";s:8:"1.9.0RC1";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:1106:"* Implement Request #16213: add alias to list-channels output [dufuz] * Implement Request #16378: pear svntag [dufuz] * Implement Request #16386: PEAR_Config::remove() does not support specifying a channel [timj] * Implement Request #16396: package-dependencies should allow package names [dufuz] * Fix Bug #11181: pear requests channel.xml from main server instead from mirror [dufuz] * Fix Bug #14493: pear install --offline doesn't print out errors [dufuz] * Fix Bug #11348: pear package-dependencies isn't well explained [dufuz] * Fix Bug #16108: PEAR_PackageFile_Generator_v2 PHP4 parse error when running upgrade-all [dufuz] * Fix Bug #16113: Installing certain packages fails due incorrect encoding handling [dufuz] * Fix Bug #16122: PEAR RunTest failed to run as expected [dufuz] * Fix Bug #16366: compiling 5.2.10 leads to non-functioning pear [dufuz] * Fix Bug #16387: channel-logout does not support logging out from a non-default channel [timj] * Fix Bug #16444: Setting preferred mirror fails [dufuz] * Fix the shutdown functions where a index might not exist and thus raise a notice [derick]";}i:5;a:5:{s:4:"date";s:10:"2009-08-20";s:7:"version";a:2:{s:7:"release";s:8:"1.9.0RC2";s:3:"api";s:8:"1.9.0RC2";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:107:"* REST 1.4 file was occasionally being included but REST 1.4 is not intended for this release cycle [dufuz]";}i:6;a:5:{s:4:"date";s:10:"2009-08-21";s:7:"version";a:2:{s:7:"release";s:8:"1.9.0RC3";s:3:"api";s:8:"1.9.0RC3";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:70:"* Improved svntag support to handle packages like PEAR it self [dufuz]";}i:7;a:5:{s:4:"date";s:10:"2009-08-23";s:7:"version";a:2:{s:7:"release";s:8:"1.9.0RC4";s:3:"api";s:8:"1.9.0RC4";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:244:"* Fixed a problem where the original channel could not be set as a preferred_mirror again [dufuz] * Make sure channel aliases can't be made to start with - [dufuz] * Output issues with pear search [dufuz] * Fixed couple of stray notices [dufuz]";}i:8;a:5:{s:4:"date";s:10:"2009-09-03";s:7:"version";a:2:{s:7:"release";s:5:"1.9.0";s:3:"api";s:5:"1.9.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:86:"* Fix Bug #16547: The phar for PEAR installer uses ereg() which is deprecated [dufuz]";}i:9;a:5:{s:4:"date";s:10:"2010-05-26";s:7:"version";a:2:{s:7:"release";s:5:"1.9.1";s:3:"api";s:5:"1.9.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:1111:"* svntag improvements, tag package files passed into the command and better directory checks [dufuz] * rely on Structures_Graph minimum version instead of recommended version [saltybeagle] * Fix Bug #12613: running go-pear.phar from C:\ fails [dufuz] * Fix Bug #14841: Installing pear into directory with space fails [dufuz] * Fix Bug #16644: pear.bat returns syntax error when parenthesis are in install path. [dufuz] [patch by bwaters (Bryan Waters)] * Fix Bug #16767: Use of Depreciated HTML Attributes in the Exception class [dufuz] [patch by fuhrysteve (Stephen J. Fuhry)] * Fix Bug #16864: "pear list-upgrades -i" issues E_WARNINGS [dufuz] [patch by rquadling (Richard Quadling)] * Fix Bug #17220: command `pear help` outputs to stderr instead of stdout [dufuz] * Fix Bug #17234: channel-discover adds port to HTTP Host header [dufuz] * Fix Bug #17292: Code Coverage in PEAR_RunTest does not work with namespaces [sebastian] * Fix Bug #17359: loadExtension() fails over missing dl() when used in multithread env [dufuz] * Fix Bug #17378: pear info $package fails if directory with that name exists [dufuz]";}i:10;a:6:{s:4:"date";s:10:"2011-02-28";s:4:"time";s:8:"18:30:00";s:7:"version";a:2:{s:7:"release";s:5:"1.9.2";s:3:"api";s:5:"1.9.2";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:1258:"Important! This is a security fix release. The advisory can be found at http://pear.php.net/advisory-20110228.txt Bugs: * Fixed Bug #17463: Regression: On Windows, svntag [patch by doconnor] * Fixed Bug #17641: pecl-list doesn't sort packages by name [dufuz] * Fixed Bug #17781: invalid argument warning on foreach due to an empty optional dependencie [dufuz] * Fixed Bug #17801: PEAR run-tests wrongly detects php-cgi [patch by David Jean Louis (izi)] * Fixed Bug #17839: pear svntag does not tag package.xml file [dufuz] * Fixed Bug #17986: PEAR Installer cannot handle files moved between packages [dufuz] * Fixed Bug #17997: Strange output if directories are not writeable [dufuz] * Fixed Bug #18001: PEAR/RunTest coverage fails [dufuz] * Fixed Bug #18056 [SECURITY]: Symlink attack in PEAR install [dufuz] * Fixed Bug #18218: "pear package" does not allow the use of late static binding [dufuz and Christer Edvartsen] * Fixed Bug #18238: Wrong return code from "pear help" [till] * Fixed Bug #18308: Broken error message about missing channel validator [yunosh] This feature is implemented as a result of #18056 * Implemented Request #16648: Use TMPDIR for builds instead of /var/tmp [dufuz]";}i:11;a:6:{s:4:"date";s:10:"2011-06-04";s:4:"time";s:8:"15:30:00";s:7:"version";a:2:{s:7:"release";s:5:"1.9.3";s:3:"api";s:5:"1.9.2";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:820:"* Fixed Bug #17744: Empty changelog causes fatal error in setChangelogentry [dufuz] * Fixed Bug #18340: raiseErro typo [doconnor] * Fixed Bug #18349: package.xml version not recognized when single quoted [dufuz] * Fixed Bug #18364: date.timezone errors for sh/bat files when TZ is not set in php.ini [dufuz] * Fixed Bug #18388: Parentheses error in REST.php line 232 [dufuz] * Fixed Bug #18428: invalid preg_match patterns [glen] * Fixed Bug #18486: REST/10.php does not check error condition [dufuz] * Fixed a problem in RunTest and code coverage. Correctly register the code coverage shutdown function in case we are inside a namespace. [sebastian] * Fixed a bug with extensions not providing their config.m4 and co in the root directory of their pecl package but rather in a sub directory, such as xhprof. [dufuz]";}i:12;a:6:{s:4:"date";s:10:"2011-07-06";s:4:"time";s:8:"15:30:00";s:7:"version";a:2:{s:7:"release";s:5:"1.9.4";s:3:"api";s:5:"1.9.4";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:705:"Bug Fixes: * Bug #17350: "pear install --force" doesn't uninstall files from previous pkg versions [dufuz] * Bug #18362: A whitespace TEMP_DIR path breaks install/upgrade functionality [dufuz] * Bug #18440: bad tmp folder path on install : Unable to create path for C:/Program/tmp [dufuz] * Bug #18581: "config-get -c" not returning channel's configuration when using alias [dufuz] * Bug #18639: regression: installing xdebug fails most likely due to another fix [dufuz] Features * All System (the class) functions can now take in spaced paths as long as they are surrounded in quotes. Prior to this it was possible to do that by passing all values in as an array (by product of #18362, #18440) [dufuz]";}i:13;a:6:{s:4:"date";s:10:"2014-06-27";s:4:"time";s:8:"18:17:00";s:7:"version";a:2:{s:7:"release";s:9:"1.9.5dev1";s:3:"api";s:5:"1.9.5";}s:9:"stability";a:2:{s:7:"release";s:5:"devel";s:3:"api";s:5:"devel";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:1093:"Bug fixes: * Fix bug #18343: Entities in file names decoded during packaging [cweiske] * Fix bug #18665: pecl extensions not enabled in empty php.ini files [Louis Opter] * Fix bug #18834: Do not truncate cache file if it is a symlink [avb] * Fix bug #18892: Parse error in Installer.php [ashnazg] * Fix bug #19482: fix pearcmd for include paths with trailing backslash [cweiske] * Fix bug #19793: PHP Notice about ob_end_clean() [cweiske] * Fix bug #20086: Invalid regexp in PEAR_Builder::build() [avb] * Fix bug #20203: split content-type and get real mime type [Samu Voutilainen] * Fix bug #20283: use full path for "zend_extension=..." [cweiske] * Fix bug #20284: Reset interpreter before running --CLEAN-- section php-cgi run [Mats Lindh] * Fix bug #20285: fix spelling mistakes [Veres Lajos] * Fix bug #20286: Support access of static variables on objects in validator [cweiske] * Fix bug #20321: Correctly detect name of current user during installation [cweiske] * Fix bug: let pear run-tests fail when there are failed tests [cweiske] * Prepare a test for bug #18056 / bug #18834 [avb]";}i:14;a:6:{s:4:"date";s:10:"2014-07-12";s:4:"time";s:8:"14:22:23";s:7:"version";a:2:{s:7:"release";s:5:"1.9.5";s:3:"api";s:5:"1.9.5";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:1137:"No changes since 1.9.5.dev1. Bug fixes in 1.9.5.dev1: * Fix bug #18343: Entities in file names decoded during packaging [cweiske] * Fix bug #18665: pecl extensions not enabled in empty php.ini files [Louis Opter] * Fix bug #18834: Do not truncate cache file if it is a symlink [avb] * Fix bug #18892: Parse error in Installer.php [ashnazg] * Fix bug #19482: fix pearcmd for include paths with trailing backslash [cweiske] * Fix bug #19793: PHP Notice about ob_end_clean() [cweiske] * Fix bug #20086: Invalid regexp in PEAR_Builder::build() [avb] * Fix bug #20203: split content-type and get real mime type [Samu Voutilainen] * Fix bug #20283: use full path for "zend_extension=..." [cweiske] * Fix bug #20284: Reset interpreter before running --CLEAN-- section php-cgi run [Mats Lindh] * Fix bug #20285: fix spelling mistakes [Veres Lajos] * Fix bug #20286: Support access of static variables on objects in validator [cweiske] * Fix bug #20321: Correctly detect name of current user during installation [cweiske] * Fix bug: let pear run-tests fail when there are failed tests [cweiske] * Prepare a test for bug #18056 / bug #18834 [avb]";}i:15;a:6:{s:4:"date";s:10:"2015-07-25";s:4:"time";s:8:"13:42:42";s:7:"version";a:2:{s:7:"release";s:10:"1.10.0dev1";s:3:"api";s:6:"1.10.0";}s:9:"stability";a:2:{s:7:"release";s:5:"devel";s:3:"api";s:5:"devel";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:444:"* Implement #20488: Add support for PHP 7 [cweiske] * Drop support for PHP 4 and 5.0 - 5.3 [cweiske] * Remove deprecated methods [cweiske] * Fix static warnings [cweiske] * Fix #17045: avoid overwriting include path [glen] * Fix #17399: "pear help" doesn't mention the "version" command [kguest] * Add --showdiff to "pear run-tests" to print diff for failed tests [tyrael] * Fix channel.xml downloading from https if it did not change [cweiske]";}i:16;a:6:{s:4:"date";s:10:"2015-07-31";s:4:"time";s:8:"09:42:42";s:7:"version";a:2:{s:7:"release";s:10:"1.10.0dev2";s:3:"api";s:6:"1.10.0";}s:9:"stability";a:2:{s:7:"release";s:5:"devel";s:3:"api";s:5:"devel";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:328:"* Fix #18638 and #18405: Make PEAR::loadExtension static [cweiske] * Fix #20319: allow pear to work when cache_dir is not writable [remicollet] * Implement #20333: New role=man for man pages [bjori] * Implement #20334: add "metadata_dir" configuration option [remicollet] * Add long option names to install-pear.php [remicollet]";}i:17;a:6:{s:4:"date";s:10:"2015-09-28";s:4:"time";s:8:"09:42:42";s:7:"version";a:2:{s:7:"release";s:10:"1.10.0dev3";s:3:"api";s:6:"1.10.0";}s:9:"stability";a:2:{s:7:"release";s:5:"devel";s:3:"api";s:5:"devel";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:227:"* Fix #20507: pear list-upgrades does not take PHP version into account [cweiske] * Fix #20927: Use correct php-config [cweiske] * Fix #20946: PEAR_Builder::log() declaration [remicollet] * Remove PEAR/ErrorStack5.php [cweiske]";}i:18;a:6:{s:4:"date";s:10:"2015-10-07";s:4:"time";s:8:"11:22:42";s:7:"version";a:2:{s:7:"release";s:6:"1.10.0";s:3:"api";s:6:"1.10.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:1068:"No changes since version 1.10.0dev3. Changes since version 1.9.5: * Implement #20488: Add support for PHP 7 [cweiske] * Drop support for PHP 4 and 5.0 - 5.3 [cweiske] * Remove deprecated methods [cweiske] * Add --showdiff to "pear run-tests" to print diff for failed tests [tyrael] * Implement #20333: New role=man for man pages [bjori] * Implement #20334: add "metadata_dir" configuration option [remicollet] * Add long option names to install-pear.php [remicollet] * Remove PEAR/ErrorStack5.php [cweiske] * Fix #17045: avoid overwriting include path [glen] * Fix #17399: "pear help" doesn't mention the "version" command [kguest] * Fix #18638 and #18405: Make PEAR::loadExtension static [cweiske] * Fix #20319: allow pear to work when cache_dir is not writable [remicollet] * Fix #20507: pear list-upgrades does not take PHP version into account [cweiske] * Fix #20927: Use correct php-config [cweiske] * Fix #20946: PEAR_Builder::log() declaration [remicollet] * Fix channel.xml downloading from https if it did not change [cweiske] * Fix static warnings [cweiske]";}i:19;a:6:{s:4:"date";s:10:"2015-10-17";s:4:"time";s:8:"13:22:42";s:7:"version";a:2:{s:7:"release";s:6:"1.10.1";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:229:"* Fix bug #20959: Crash on channel discovery with channel.xml redirect [cweiske] * Fix bug #20968: Incorrect call to __construct() from PEAR() [edlman] * Add legacy constructor for PEAR_Error for backwards compatibility [cweiske]";}i:20;a:6:{s:4:"date";s:10:"2017-02-28";s:4:"time";s:8:"07:40:00";s:7:"version";a:2:{s:7:"release";s:6:"1.10.2";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:544:"* Fix Bug #4426: PEAR_Autoloader __call() must take only 2 arguments [kna] * Fix Bug #20989: fatal error/bug in the postinstallscript task [kguest] * Fix Bug #20991: Strict Standards: startSession and run methods in PEAR_Task_Postinstallscript [kguest] * Fix Bug #21001: PEAR_ERROR_DIE exit code is 0 [danielc] * Pull Request #52: Channel's _lastmodified is an int and not a string [sathieu] * Pull Request #53: Add proper HTTPS proxy support through the CONNECT verb [youknow0] * Pull Request #58: Make method signatures compatible. [yunosh]";}i:21;a:6:{s:4:"date";s:10:"2017-02-28";s:4:"time";s:8:"10:15:00";s:7:"version";a:2:{s:7:"release";s:6:"1.10.3";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:42:"* Bug #21188: Class 'PEAR_Proxy' not found";}i:22;a:5:{s:4:"date";s:10:"2017-04-25";s:7:"version";a:2:{s:7:"release";s:6:"1.10.4";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:50:"* Bug #18102: pear install does not fail on error";}i:23;a:5:{s:4:"date";s:10:"2017-06-27";s:7:"version";a:2:{s:7:"release";s:6:"1.10.5";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:73:"* Bug #21222: PHP 7.2 compatibility: Upgrade to Archive_Tar 1.4.3 needed";}i:24;a:5:{s:4:"date";s:10:"2018-08-22";s:7:"version";a:2:{s:7:"release";s:6:"1.10.6";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:544:"* PR #70: Fix notice undefined variable metadata_dir * PR #71: fix Warning: count(): Parameter must be an array or an object * PR #74: Bug #23744 Remove is_executable check * Bug #23744: The is_executable check in the Which method when run on Windows is unnecessary * PR #75: Migrate old while(list() = each()) constructs to foreach * PR #76: Fix PHP Warning: "continue" targeting switch is equivalent to "break" * PR #77: proxy server auth * PR #72: Correctly authenticate at proxy server * PR #78: array or Countable error in 7.2";}i:25;a:5:{s:4:"date";s:10:"2018-12-05";s:7:"version";a:2:{s:7:"release";s:6:"1.10.7";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:238:"* PR #79: Prevent Unable to find the wrapper "channel" Warning * PR #80: fix Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2" * PR #81: Add flags to PECL shell script for shared extensions";}i:26;a:5:{s:4:"date";s:10:"2019-02-07";s:7:"version";a:2:{s:7:"release";s:6:"1.10.8";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:83:"* PR #83: Drop track_errors from options * PR #84: Fix PHP 8 compatibility issues";}i:27;a:5:{s:4:"date";s:10:"2019-03-13";s:7:"version";a:2:{s:7:"release";s:6:"1.10.9";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:191:"* PR #85: Fixes static calls for PHP 8 * PR #86: Adjust silencing check for PHP 8 * PR #87: Comparison fixes * PR #88: Only add bin_dir to PATH if not already there (fixes PHP Bug #75852)";}i:28;a:5:{s:4:"date";s:10:"2019-11-19";s:7:"version";a:2:{s:7:"release";s:7:"1.10.10";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:672:"* PR #89: Fix scripts/* include paths * PR #90: Non-interactive configureoption answers * PR #91: Added missing preg quote * PR #92: handle "lib64" case for glibc detection * PR #93: Fix PHP Notice: Trying to access array offset on value of type bool with 7.4 * PR #94: Updated logic in useLocalCache to reuse getCacheId * PR #95: Fix manpage warning * PR #96: Implement the SOURCE_DATE_EPOCH specification * PR #97: Fix PHP 7.4 deprecation: array/string curly braces access * PR #98: Fix use of null/false as array * PR #99: Fix Travis builds on PHP 5.4 and 5.5 * PR #100: Honor PHP temp directory config * PR #101: Fix documentation: the `--force` is required";}i:29;a:5:{s:4:"date";s:10:"2020-04-10";s:7:"version";a:2:{s:7:"release";s:7:"1.10.11";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:230:"* PR #102: Fix logging error for urls not in cache * PR #103: Fix undefined constant name * PR #105: Sort list of packages * PR #106: Update REST.php * PR #107: Update .travis.yml to include PHP 7.4 * PR #108: Remove unneeded code";}i:30;a:5:{s:4:"date";s:10:"2020-04-19";s:7:"version";a:2:{s:7:"release";s:7:"1.10.12";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:43:"* adjust dependencies based on new releases";}i:31;a:5:{s:4:"date";s:10:"2021-08-10";s:7:"version";a:2:{s:7:"release";s:7:"1.10.13";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:116:"* PR #114: unsupported protocol - use --force to continue * PR #117: Add $this operator to _determineIfPowerpc calls";}i:32;a:5:{s:4:"date";s:10:"2023-11-26";s:7:"version";a:2:{s:7:"release";s:7:"1.10.14";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:583:"* PR #112: Put glue and pieces parameters to implode in correct order for PHP 7.4+ * PR #121: Fix PHP bug 81653: Typo in install-pear-nozlib.phar * PR #122: add %S EXPECTF capability * PR #124: Fix: Creation of dynamic property PEAR_Error::$callback is deprecated * PR #125: Fixed extension loaded check for pecl binaries * PR #126: Remove -n option from pecl.bat for shared extensions * PR #127: fix Using ${var} in strings is deprecated * PR #128: fix lingering license references to PHP license * PR #129: Exclude tests from composer classmap * PR #131: fix private lastError name";}i:33;a:5:{s:4:"date";s:10:"2024-03-09";s:7:"version";a:2:{s:7:"release";s:7:"1.10.15";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:100:"* PR #132: cleanup uneeded test * PR #135: Fix PHP Deprecated: Calling get_class() without arguments";}i:34;a:5:{s:4:"date";s:10:"2024-11-24";s:7:"version";a:2:{s:7:"release";s:7:"1.10.16";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:164:"* PR #141: Fix bug #27796: "Array to string" conversion warnings on installs/other actions * PR #145: Never reference E_STRICT on PHP 8.4+ * PR #147: Fix tests 8.1+";}i:35;a:5:{s:4:"date";s:10:"2025-12-14";s:7:"version";a:2:{s:7:"release";s:7:"1.10.17";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:268:"* PR #152: Fix HTTP chunked encoding handling * PR #153: fix composer.json: typo in replace for pear_exception package * PR #154: switch to https by default * PR #156: Throw new Error instead of E_USER_ERROR on PHP 7.0+ * PR #159: update tests for https-first behavior";}i:36;a:5:{s:4:"date";s:10:"2026-01-25";s:7:"version";a:2:{s:7:"release";s:7:"1.10.18";s:3:"api";s:6:"1.10.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:15:"New BSD License";}s:5:"notes";s:46:"* PR #164: don't use report_memleaks with 8.5+";}}}s:8:"filelist";a:102:{s:12:"OS/Guess.php";a:4:{s:6:"md5sum";s:32:"710f2fc4aeb9527399c825413c2f04ce";s:4:"name";s:12:"OS/Guess.php";s:4:"role";s:3:"php";s:12:"installed_as";s:53:"/opt/cpanel/ea-php84/root/usr/share/pear/OS/Guess.php";}s:27:"PEAR/ChannelFile/Parser.php";a:4:{s:6:"md5sum";s:32:"1bfedc46c9ddf33d4c06a6c43c4c6e64";s:4:"name";s:27:"PEAR/ChannelFile/Parser.php";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/ChannelFile/Parser.php";}s:21:"PEAR/Command/Auth.xml";a:4:{s:6:"md5sum";s:32:"8fd87e64002e11fd86eb2f3fbfee6599";s:4:"name";s:21:"PEAR/Command/Auth.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:62:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Auth.xml";}s:21:"PEAR/Command/Auth.php";a:4:{s:6:"md5sum";s:32:"4613f7743eb91fd7f58b91393286bea0";s:4:"name";s:21:"PEAR/Command/Auth.php";s:4:"role";s:3:"php";s:12:"installed_as";s:62:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Auth.php";}s:22:"PEAR/Command/Build.xml";a:4:{s:6:"md5sum";s:32:"ce6bb5b6fdc02e0f50e7676403fd84a4";s:4:"name";s:22:"PEAR/Command/Build.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:63:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Build.xml";}s:22:"PEAR/Command/Build.php";a:4:{s:6:"md5sum";s:32:"c7c4c929113d4bbd8c52bbfdcc980e40";s:4:"name";s:22:"PEAR/Command/Build.php";s:4:"role";s:3:"php";s:12:"installed_as";s:63:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Build.php";}s:25:"PEAR/Command/Channels.xml";a:4:{s:6:"md5sum";s:32:"6d5aab4d4308c3005b5f584c7783a031";s:4:"name";s:25:"PEAR/Command/Channels.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:66:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Channels.xml";}s:25:"PEAR/Command/Channels.php";a:4:{s:6:"md5sum";s:32:"e07497190ca5a4cb55b89bb6afa35bc1";s:4:"name";s:25:"PEAR/Command/Channels.php";s:4:"role";s:3:"php";s:12:"installed_as";s:66:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Channels.php";}s:23:"PEAR/Command/Common.php";a:4:{s:6:"md5sum";s:32:"8458be827f99e753b2d023fcf2c28836";s:4:"name";s:23:"PEAR/Command/Common.php";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Common.php";}s:23:"PEAR/Command/Config.xml";a:4:{s:6:"md5sum";s:32:"91f189cb9423b5e87ee0abc5ea1a2be3";s:4:"name";s:23:"PEAR/Command/Config.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Config.xml";}s:23:"PEAR/Command/Config.php";a:4:{s:6:"md5sum";s:32:"412f3bd8f6b004c85297cbdc46f6b113";s:4:"name";s:23:"PEAR/Command/Config.php";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Config.php";}s:24:"PEAR/Command/Install.xml";a:4:{s:6:"md5sum";s:32:"24d05213cae7faa3880bbb5e40998867";s:4:"name";s:24:"PEAR/Command/Install.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:65:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Install.xml";}s:24:"PEAR/Command/Install.php";a:4:{s:6:"md5sum";s:32:"da531a58113be03c3ca4b3d6316a5465";s:4:"name";s:24:"PEAR/Command/Install.php";s:4:"role";s:3:"php";s:12:"installed_as";s:65:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Install.php";}s:23:"PEAR/Command/Mirror.xml";a:4:{s:6:"md5sum";s:32:"5cb62a04c0a268f4edd64a49a3895c92";s:4:"name";s:23:"PEAR/Command/Mirror.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Mirror.xml";}s:23:"PEAR/Command/Mirror.php";a:4:{s:6:"md5sum";s:32:"ff1c2425c6c9da87e4796296c86f78cb";s:4:"name";s:23:"PEAR/Command/Mirror.php";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Mirror.php";}s:24:"PEAR/Command/Package.xml";a:4:{s:6:"md5sum";s:32:"9367dcd7e4dbdde423f9c4c7d3f3a919";s:4:"name";s:24:"PEAR/Command/Package.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:65:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Package.xml";}s:24:"PEAR/Command/Package.php";a:4:{s:6:"md5sum";s:32:"ea4c774e43e8600f707a2d7ea683a52f";s:4:"name";s:24:"PEAR/Command/Package.php";s:4:"role";s:3:"php";s:12:"installed_as";s:65:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Package.php";}s:23:"PEAR/Command/Pickle.xml";a:4:{s:6:"md5sum";s:32:"28dc842ea725d8787b9f9c3dbca5aa22";s:4:"name";s:23:"PEAR/Command/Pickle.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Pickle.xml";}s:23:"PEAR/Command/Pickle.php";a:4:{s:6:"md5sum";s:32:"994bad38e47de38540ab2612512951f9";s:4:"name";s:23:"PEAR/Command/Pickle.php";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Pickle.php";}s:25:"PEAR/Command/Registry.xml";a:4:{s:6:"md5sum";s:32:"49b046cfc14747f0365e02e9c3f0e6dc";s:4:"name";s:25:"PEAR/Command/Registry.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:66:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Registry.xml";}s:25:"PEAR/Command/Registry.php";a:4:{s:6:"md5sum";s:32:"1dcd16290ef855fb61e5f050ae42b943";s:4:"name";s:25:"PEAR/Command/Registry.php";s:4:"role";s:3:"php";s:12:"installed_as";s:66:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Registry.php";}s:23:"PEAR/Command/Remote.xml";a:4:{s:6:"md5sum";s:32:"29c02e823879b4e3e291f6b36fb339f1";s:4:"name";s:23:"PEAR/Command/Remote.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Remote.xml";}s:23:"PEAR/Command/Remote.php";a:4:{s:6:"md5sum";s:32:"40c25d700ef1253cc05964fe8c3a9b2b";s:4:"name";s:23:"PEAR/Command/Remote.php";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Remote.php";}s:21:"PEAR/Command/Test.xml";a:4:{s:6:"md5sum";s:32:"a50c32015005e0761cc3b04679b29ed0";s:4:"name";s:21:"PEAR/Command/Test.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:62:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Test.xml";}s:21:"PEAR/Command/Test.php";a:4:{s:6:"md5sum";s:32:"c1b78cf129b78c891ae38434bcf616f4";s:4:"name";s:21:"PEAR/Command/Test.php";s:4:"role";s:3:"php";s:12:"installed_as";s:62:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command/Test.php";}s:27:"PEAR/Downloader/Package.php";a:4:{s:6:"md5sum";s:32:"e8c257e98945ba4fd138f2afa9d958be";s:4:"name";s:27:"PEAR/Downloader/Package.php";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Downloader/Package.php";}s:21:"PEAR/Frontend/CLI.php";a:4:{s:6:"md5sum";s:32:"1c16b9b7db915fbaecdb79f708bb63b2";s:4:"name";s:21:"PEAR/Frontend/CLI.php";s:4:"role";s:3:"php";s:12:"installed_as";s:62:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Frontend/CLI.php";}s:30:"PEAR/Installer/Role/Common.php";a:4:{s:6:"md5sum";s:32:"a272d31bbbc4ed39f9a2fcaffabe0221";s:4:"name";s:30:"PEAR/Installer/Role/Common.php";s:4:"role";s:3:"php";s:12:"installed_as";s:71:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Common.php";}s:27:"PEAR/Installer/Role/Cfg.xml";a:4:{s:6:"md5sum";s:32:"d8c62e6275e3aaa7784290912406092c";s:4:"name";s:27:"PEAR/Installer/Role/Cfg.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Cfg.xml";}s:27:"PEAR/Installer/Role/Cfg.php";a:4:{s:6:"md5sum";s:32:"8298fbda287b9335fd65a54c17610aa1";s:4:"name";s:27:"PEAR/Installer/Role/Cfg.php";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Cfg.php";}s:28:"PEAR/Installer/Role/Data.xml";a:4:{s:6:"md5sum";s:32:"89a4a2a286e842d45a98974f40a0565c";s:4:"name";s:28:"PEAR/Installer/Role/Data.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:69:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Data.xml";}s:28:"PEAR/Installer/Role/Data.php";a:4:{s:6:"md5sum";s:32:"7fb06acd4c4a0ca51473c373a5ea25bc";s:4:"name";s:28:"PEAR/Installer/Role/Data.php";s:4:"role";s:3:"php";s:12:"installed_as";s:69:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Data.php";}s:27:"PEAR/Installer/Role/Doc.xml";a:4:{s:6:"md5sum";s:32:"b1ce0fe105251c3b75209d6518ee69ac";s:4:"name";s:27:"PEAR/Installer/Role/Doc.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Doc.xml";}s:27:"PEAR/Installer/Role/Doc.php";a:4:{s:6:"md5sum";s:32:"d1ff8118c5591425ccce01f2e4422f1f";s:4:"name";s:27:"PEAR/Installer/Role/Doc.php";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Doc.php";}s:27:"PEAR/Installer/Role/Ext.xml";a:4:{s:6:"md5sum";s:32:"af71c0ad42d16a323afe24a4f884ef15";s:4:"name";s:27:"PEAR/Installer/Role/Ext.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Ext.xml";}s:27:"PEAR/Installer/Role/Ext.php";a:4:{s:6:"md5sum";s:32:"28e48624af3751cfccba41c7bfa721e9";s:4:"name";s:27:"PEAR/Installer/Role/Ext.php";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Ext.php";}s:27:"PEAR/Installer/Role/Man.xml";a:4:{s:6:"md5sum";s:32:"da6743f1e45cce72ea13aef5cdb14867";s:4:"name";s:27:"PEAR/Installer/Role/Man.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Man.xml";}s:27:"PEAR/Installer/Role/Man.php";a:4:{s:6:"md5sum";s:32:"172ff6e36139cf5d93a49547fe170c6b";s:4:"name";s:27:"PEAR/Installer/Role/Man.php";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Man.php";}s:27:"PEAR/Installer/Role/Php.xml";a:4:{s:6:"md5sum";s:32:"ef88f0321d3e481c2130c95122cf76d8";s:4:"name";s:27:"PEAR/Installer/Role/Php.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Php.xml";}s:27:"PEAR/Installer/Role/Php.php";a:4:{s:6:"md5sum";s:32:"88ecaccdbfc4442bc3a0b9ce743b1451";s:4:"name";s:27:"PEAR/Installer/Role/Php.php";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Php.php";}s:30:"PEAR/Installer/Role/Script.xml";a:4:{s:6:"md5sum";s:32:"746461dc3b48af6d24094cb0211608f2";s:4:"name";s:30:"PEAR/Installer/Role/Script.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:71:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Script.xml";}s:30:"PEAR/Installer/Role/Script.php";a:4:{s:6:"md5sum";s:32:"3c6367165a123612b2e59350358ceb56";s:4:"name";s:30:"PEAR/Installer/Role/Script.php";s:4:"role";s:3:"php";s:12:"installed_as";s:71:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Script.php";}s:27:"PEAR/Installer/Role/Src.xml";a:4:{s:6:"md5sum";s:32:"e147d63f168ea156fc2be38caaa63804";s:4:"name";s:27:"PEAR/Installer/Role/Src.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Src.xml";}s:27:"PEAR/Installer/Role/Src.php";a:4:{s:6:"md5sum";s:32:"036f7426c9dceab48fd2aaaedfbe4dcc";s:4:"name";s:27:"PEAR/Installer/Role/Src.php";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Src.php";}s:28:"PEAR/Installer/Role/Test.xml";a:4:{s:6:"md5sum";s:32:"a24b596ec987aa5688fc19e8ed4e97ea";s:4:"name";s:28:"PEAR/Installer/Role/Test.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:69:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Test.xml";}s:28:"PEAR/Installer/Role/Test.php";a:4:{s:6:"md5sum";s:32:"df03e84842af8752ba45337a99d3f27b";s:4:"name";s:28:"PEAR/Installer/Role/Test.php";s:4:"role";s:3:"php";s:12:"installed_as";s:69:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Test.php";}s:27:"PEAR/Installer/Role/Www.xml";a:4:{s:6:"md5sum";s:32:"7641e71c5785bb33a4261ebe25ed0fd7";s:4:"name";s:27:"PEAR/Installer/Role/Www.xml";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Www.xml";}s:27:"PEAR/Installer/Role/Www.php";a:4:{s:6:"md5sum";s:32:"fc588d30fa49c881edc2051117aeecb3";s:4:"name";s:27:"PEAR/Installer/Role/Www.php";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role/Www.php";}s:23:"PEAR/Installer/Role.php";a:4:{s:6:"md5sum";s:32:"5324e20d3c00a9a4f32aaa0087935931";s:4:"name";s:23:"PEAR/Installer/Role.php";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role.php";}s:33:"PEAR/PackageFile/Generator/v1.php";a:4:{s:6:"md5sum";s:32:"852fe270e5840c1802102cfa70adbc65";s:4:"name";s:33:"PEAR/PackageFile/Generator/v1.php";s:4:"role";s:3:"php";s:12:"installed_as";s:74:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile/Generator/v1.php";}s:33:"PEAR/PackageFile/Generator/v2.php";a:4:{s:6:"md5sum";s:32:"e51e162c786b1a1c01a00e9e0ba0f788";s:4:"name";s:33:"PEAR/PackageFile/Generator/v2.php";s:4:"role";s:3:"php";s:12:"installed_as";s:74:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile/Generator/v2.php";}s:30:"PEAR/PackageFile/Parser/v1.php";a:4:{s:6:"md5sum";s:32:"a2206e0e32ad2ba2f4e2a0c1797f295c";s:4:"name";s:30:"PEAR/PackageFile/Parser/v1.php";s:4:"role";s:3:"php";s:12:"installed_as";s:71:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile/Parser/v1.php";}s:30:"PEAR/PackageFile/Parser/v2.php";a:4:{s:6:"md5sum";s:32:"3857f4b60878d64551a7cdae783437f7";s:4:"name";s:30:"PEAR/PackageFile/Parser/v2.php";s:4:"role";s:3:"php";s:12:"installed_as";s:71:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile/Parser/v2.php";}s:26:"PEAR/PackageFile/v2/rw.php";a:4:{s:6:"md5sum";s:32:"d27ad5d011c82d0ef28546af1f086793";s:4:"name";s:26:"PEAR/PackageFile/v2/rw.php";s:4:"role";s:3:"php";s:12:"installed_as";s:67:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile/v2/rw.php";}s:33:"PEAR/PackageFile/v2/Validator.php";a:4:{s:6:"md5sum";s:32:"e20989993e6f2cb4e1243e695323325e";s:4:"name";s:33:"PEAR/PackageFile/v2/Validator.php";s:4:"role";s:3:"php";s:12:"installed_as";s:74:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile/v2/Validator.php";}s:23:"PEAR/PackageFile/v1.php";a:4:{s:6:"md5sum";s:32:"e22777d62e365061fd9bd1a621f4dc71";s:4:"name";s:23:"PEAR/PackageFile/v1.php";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile/v1.php";}s:23:"PEAR/PackageFile/v2.php";a:4:{s:6:"md5sum";s:32:"864f1cdd3b687b21529af36c2bf63a9a";s:4:"name";s:23:"PEAR/PackageFile/v2.php";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile/v2.php";}s:16:"PEAR/REST/10.php";a:4:{s:6:"md5sum";s:32:"36810652a94aff3a723340a37c050c47";s:4:"name";s:16:"PEAR/REST/10.php";s:4:"role";s:3:"php";s:12:"installed_as";s:57:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/REST/10.php";}s:16:"PEAR/REST/11.php";a:4:{s:6:"md5sum";s:32:"dd6740e44c406ae6845350181ec77b72";s:4:"name";s:16:"PEAR/REST/11.php";s:4:"role";s:3:"php";s:12:"installed_as";s:57:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/REST/11.php";}s:16:"PEAR/REST/13.php";a:4:{s:6:"md5sum";s:32:"beb6efb630741b52b20e96fce33ae303";s:4:"name";s:16:"PEAR/REST/13.php";s:4:"role";s:3:"php";s:12:"installed_as";s:57:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/REST/13.php";}s:34:"PEAR/Task/Postinstallscript/rw.php";a:4:{s:6:"md5sum";s:32:"c0131a4918d440d38f4ea4c93a5cd62f";s:4:"name";s:34:"PEAR/Task/Postinstallscript/rw.php";s:4:"role";s:3:"php";s:12:"installed_as";s:75:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Postinstallscript/rw.php";}s:24:"PEAR/Task/Replace/rw.php";a:4:{s:6:"md5sum";s:32:"15ec3dfa927b8c93c634c2df446e3a71";s:4:"name";s:24:"PEAR/Task/Replace/rw.php";s:4:"role";s:3:"php";s:12:"installed_as";s:65:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Replace/rw.php";}s:24:"PEAR/Task/Unixeol/rw.php";a:4:{s:6:"md5sum";s:32:"f3bb8f7a3cf88fab739322675874f78e";s:4:"name";s:24:"PEAR/Task/Unixeol/rw.php";s:4:"role";s:3:"php";s:12:"installed_as";s:65:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Unixeol/rw.php";}s:27:"PEAR/Task/Windowseol/rw.php";a:4:{s:6:"md5sum";s:32:"fb5ce8025259d3849c69924279190c24";s:4:"name";s:27:"PEAR/Task/Windowseol/rw.php";s:4:"role";s:3:"php";s:12:"installed_as";s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Windowseol/rw.php";}s:20:"PEAR/Task/Common.php";a:4:{s:6:"md5sum";s:32:"9241b55c944587eb0582f03e337f6948";s:4:"name";s:20:"PEAR/Task/Common.php";s:4:"role";s:3:"php";s:12:"installed_as";s:61:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Common.php";}s:31:"PEAR/Task/Postinstallscript.php";a:4:{s:6:"md5sum";s:32:"f3c27b9aed2d674df4496130621f4ba5";s:4:"name";s:31:"PEAR/Task/Postinstallscript.php";s:4:"role";s:3:"php";s:12:"installed_as";s:72:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Postinstallscript.php";}s:21:"PEAR/Task/Replace.php";a:4:{s:6:"md5sum";s:32:"3d120d9e0a1662522d19bdd86b035b34";s:4:"name";s:21:"PEAR/Task/Replace.php";s:4:"role";s:3:"php";s:12:"installed_as";s:62:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Replace.php";}s:21:"PEAR/Task/Unixeol.php";a:4:{s:6:"md5sum";s:32:"3c43bf148b6a1304d429f8a0366315de";s:4:"name";s:21:"PEAR/Task/Unixeol.php";s:4:"role";s:3:"php";s:12:"installed_as";s:62:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Unixeol.php";}s:24:"PEAR/Task/Windowseol.php";a:4:{s:6:"md5sum";s:32:"a5f8761e52cf9021656b47ba7516d304";s:4:"name";s:24:"PEAR/Task/Windowseol.php";s:4:"role";s:3:"php";s:12:"installed_as";s:65:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Windowseol.php";}s:23:"PEAR/Validator/PECL.php";a:4:{s:6:"md5sum";s:32:"e356da2309b2e9a94bead0d436ab620b";s:4:"name";s:23:"PEAR/Validator/PECL.php";s:4:"role";s:3:"php";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Validator/PECL.php";}s:16:"PEAR/Builder.php";a:4:{s:6:"md5sum";s:32:"e2990ea082ae4d608c2e1c8229be0312";s:4:"name";s:16:"PEAR/Builder.php";s:4:"role";s:3:"php";s:12:"installed_as";s:57:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Builder.php";}s:20:"PEAR/ChannelFile.php";a:4:{s:6:"md5sum";s:32:"a671c1f8a68e8e35e0fd8e7cbc197eb0";s:4:"name";s:20:"PEAR/ChannelFile.php";s:4:"role";s:3:"php";s:12:"installed_as";s:61:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/ChannelFile.php";}s:16:"PEAR/Command.php";a:4:{s:6:"md5sum";s:32:"e7ff5118db3fc067dfb877d85b56b4e5";s:4:"name";s:16:"PEAR/Command.php";s:4:"role";s:3:"php";s:12:"installed_as";s:57:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command.php";}s:15:"PEAR/Common.php";a:4:{s:6:"md5sum";s:32:"94a4a15cbbded5d3a459e69c9da0b5f9";s:4:"name";s:15:"PEAR/Common.php";s:4:"role";s:3:"php";s:12:"installed_as";s:56:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Common.php";}s:15:"PEAR/Config.php";a:4:{s:6:"md5sum";s:32:"a4f77a000088f10a90e88e2f74ef7aca";s:4:"name";s:15:"PEAR/Config.php";s:4:"role";s:3:"php";s:12:"installed_as";s:56:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Config.php";}s:21:"PEAR/DependencyDB.php";a:4:{s:6:"md5sum";s:32:"20f6136fc2c05e05fc90c66ca06f98b8";s:4:"name";s:21:"PEAR/DependencyDB.php";s:4:"role";s:3:"php";s:12:"installed_as";s:62:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/DependencyDB.php";}s:20:"PEAR/Dependency2.php";a:4:{s:6:"md5sum";s:32:"0d64741dd4792a31caf0b7eff82fc94b";s:4:"name";s:20:"PEAR/Dependency2.php";s:4:"role";s:3:"php";s:12:"installed_as";s:61:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Dependency2.php";}s:19:"PEAR/Downloader.php";a:4:{s:6:"md5sum";s:32:"2c1a3d1ce93da76a0f9df47b6f9e4378";s:4:"name";s:19:"PEAR/Downloader.php";s:4:"role";s:3:"php";s:12:"installed_as";s:60:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Downloader.php";}s:19:"PEAR/ErrorStack.php";a:4:{s:6:"md5sum";s:32:"4028882af59da2f771396d80357a4c0a";s:4:"name";s:19:"PEAR/ErrorStack.php";s:4:"role";s:3:"php";s:12:"installed_as";s:60:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/ErrorStack.php";}s:18:"PEAR/Exception.php";a:4:{s:6:"md5sum";s:32:"d0af85a0b030d935d902a150b6c286a2";s:4:"name";s:18:"PEAR/Exception.php";s:4:"role";s:3:"php";s:12:"installed_as";s:59:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Exception.php";}s:17:"PEAR/Frontend.php";a:4:{s:6:"md5sum";s:32:"e6df94ed230c78ef0901d5f1462aac94";s:4:"name";s:17:"PEAR/Frontend.php";s:4:"role";s:3:"php";s:12:"installed_as";s:58:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Frontend.php";}s:18:"PEAR/Installer.php";a:4:{s:6:"md5sum";s:32:"cb26ac2890573449bffd216bee8af7c0";s:4:"name";s:18:"PEAR/Installer.php";s:4:"role";s:3:"php";s:12:"installed_as";s:59:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer.php";}s:20:"PEAR/PackageFile.php";a:4:{s:6:"md5sum";s:32:"b3a3879466c1a8ad088a0cb065fb8b20";s:4:"name";s:20:"PEAR/PackageFile.php";s:4:"role";s:3:"php";s:12:"installed_as";s:61:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile.php";}s:17:"PEAR/Packager.php";a:4:{s:6:"md5sum";s:32:"9bca9c2527fd31f946f71b6464916346";s:4:"name";s:17:"PEAR/Packager.php";s:4:"role";s:3:"php";s:12:"installed_as";s:58:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Packager.php";}s:14:"PEAR/Proxy.php";a:4:{s:6:"md5sum";s:32:"ef9d00adaeccff7516f08170096026d3";s:4:"name";s:14:"PEAR/Proxy.php";s:4:"role";s:3:"php";s:12:"installed_as";s:55:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Proxy.php";}s:17:"PEAR/Registry.php";a:4:{s:6:"md5sum";s:32:"45bb095c0e21e4acd6b2bba15a299aa4";s:4:"name";s:17:"PEAR/Registry.php";s:4:"role";s:3:"php";s:12:"installed_as";s:58:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Registry.php";}s:13:"PEAR/REST.php";a:4:{s:6:"md5sum";s:32:"7a77064229a52a0bb129ad0e7091c289";s:4:"name";s:13:"PEAR/REST.php";s:4:"role";s:3:"php";s:12:"installed_as";s:54:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/REST.php";}s:16:"PEAR/RunTest.php";a:4:{s:6:"md5sum";s:32:"ab6768aa6fad56237abb4b0da461bf58";s:4:"name";s:16:"PEAR/RunTest.php";s:4:"role";s:3:"php";s:12:"installed_as";s:57:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/RunTest.php";}s:17:"PEAR/Validate.php";a:4:{s:6:"md5sum";s:32:"a3fa972624a98a3bd001fd8bb4d0c150";s:4:"name";s:17:"PEAR/Validate.php";s:4:"role";s:3:"php";s:12:"installed_as";s:58:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Validate.php";}s:18:"PEAR/XMLParser.php";a:4:{s:6:"md5sum";s:32:"7b14f5fc171f7c48964867eae88b432c";s:4:"name";s:18:"PEAR/XMLParser.php";s:4:"role";s:3:"php";s:12:"installed_as";s:59:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/XMLParser.php";}s:15:"scripts/pear.sh";a:6:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"6a436173e8de64c0932c5e9371d11f27";s:4:"name";s:15:"scripts/pear.sh";s:4:"role";s:6:"script";s:10:"install-as";s:4:"pear";s:12:"installed_as";s:38:"/opt/cpanel/ea-php84/root/usr/bin/pear";}s:18:"scripts/peardev.sh";a:6:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"c5432397552a7ff5fa2d47f780b936e8";s:4:"name";s:18:"scripts/peardev.sh";s:4:"role";s:6:"script";s:10:"install-as";s:7:"peardev";s:12:"installed_as";s:41:"/opt/cpanel/ea-php84/root/usr/bin/peardev";}s:15:"scripts/pecl.sh";a:6:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"5b80e5b4d4e157aaae02cf79db7224f9";s:4:"name";s:15:"scripts/pecl.sh";s:4:"role";s:6:"script";s:10:"install-as";s:4:"pecl";s:12:"installed_as";s:38:"/opt/cpanel/ea-php84/root/usr/bin/pecl";}s:19:"scripts/pearcmd.php";a:6:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"653ea842090f92531b5f6b4ed2949adb";s:4:"name";s:19:"scripts/pearcmd.php";s:4:"role";s:3:"php";s:10:"install-as";s:11:"pearcmd.php";s:12:"installed_as";s:52:"/opt/cpanel/ea-php84/root/usr/share/pear/pearcmd.php";}s:19:"scripts/peclcmd.php";a:6:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"7e1e061cc525325994bf43c8fae53725";s:4:"name";s:19:"scripts/peclcmd.php";s:4:"role";s:3:"php";s:10:"install-as";s:11:"peclcmd.php";s:12:"installed_as";s:52:"/opt/cpanel/ea-php84/root/usr/share/pear/peclcmd.php";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"45b44486d8090de17b2a8b4211fab247";s:4:"name";s:7:"LICENSE";s:4:"role";s:3:"doc";s:12:"installed_as";s:57:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/PEAR/LICENSE";}s:7:"INSTALL";a:4:{s:6:"md5sum";s:32:"eaac3d33068c6e67573ed44155b149ae";s:4:"name";s:7:"INSTALL";s:4:"role";s:3:"doc";s:12:"installed_as";s:57:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/PEAR/INSTALL";}s:11:"package.dtd";a:4:{s:6:"md5sum";s:32:"69341ea97af9c88956568f8e7e41d4c6";s:4:"name";s:11:"package.dtd";s:4:"role";s:4:"data";s:12:"installed_as";s:62:"/opt/cpanel/ea-php84/root/usr/share/pear-data/PEAR/package.dtd";}s:8:"PEAR.php";a:4:{s:6:"md5sum";s:32:"23579a5555774b6f6a6405294a404dfc";s:4:"name";s:8:"PEAR.php";s:4:"role";s:3:"php";s:12:"installed_as";s:49:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR.php";}s:10:"README.rst";a:4:{s:6:"md5sum";s:32:"cd10521cc4054923a3d2b6e15b4df493";s:4:"name";s:10:"README.rst";s:4:"role";s:3:"doc";s:12:"installed_as";s:60:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/PEAR/README.rst";}s:10:"System.php";a:4:{s:6:"md5sum";s:32:"4f62391952fe4b3097c73d16dae5b2ab";s:4:"name";s:10:"System.php";s:4:"role";s:3:"php";s:12:"installed_as";s:51:"/opt/cpanel/ea-php84/root/usr/share/pear/System.php";}s:13:"template.spec";a:4:{s:6:"md5sum";s:32:"acd010e3bc43c0f72df584acde7b9158";s:4:"name";s:13:"template.spec";s:4:"role";s:4:"data";s:12:"installed_as";s:64:"/opt/cpanel/ea-php84/root/usr/share/pear-data/PEAR/template.spec";}}s:12:"_lastversion";N;s:7:"dirtree";a:23:{s:43:"/opt/cpanel/ea-php84/root/usr/share/pear/OS";b:1;s:57:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/ChannelFile";b:1;s:45:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR";b:1;s:53:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Command";b:1;s:56:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Downloader";b:1;s:54:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Frontend";b:1;s:60:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer/Role";b:1;s:55:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Installer";b:1;s:67:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile/Generator";b:1;s:57:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile";b:1;s:64:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile/Parser";b:1;s:60:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/PackageFile/v2";b:1;s:50:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/REST";b:1;s:68:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Postinstallscript";b:1;s:50:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task";b:1;s:58:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Replace";b:1;s:58:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Unixeol";b:1;s:61:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Task/Windowseol";b:1;s:55:"/opt/cpanel/ea-php84/root/usr/share/pear/PEAR/Validator";b:1;s:33:"/opt/cpanel/ea-php84/root/usr/bin";b:1;s:40:"/opt/cpanel/ea-php84/root/usr/share/pear";b:1;s:49:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/PEAR";b:1;s:50:"/opt/cpanel/ea-php84/root/usr/share/pear-data/PEAR";b:1;}s:3:"old";a:7:{s:7:"version";s:7:"1.10.18";s:12:"release_date";s:10:"2026-01-25";s:13:"release_state";s:6:"stable";s:15:"release_license";s:15:"New BSD License";s:13:"release_notes";s:46:"* PR #164: don't use report_memleaks with 8.5+";s:12:"release_deps";a:8:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.4.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:6:"1.10.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:11:"Archive_Tar";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.9";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:16:"Structures_Graph";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:4;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:14:"Console_Getopt";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:5;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:8:"XML_Util";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.0";s:8:"optional";s:2:"no";}i:6;a:4:{s:4:"type";s:3:"ext";s:4:"name";s:3:"xml";s:3:"rel";s:3:"has";s:8:"optional";s:2:"no";}i:7;a:4:{s:4:"type";s:3:"ext";s:4:"name";s:4:"pcre";s:3:"rel";s:3:"has";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:11:{i:0;a:5:{s:4:"name";s:11:"Greg Beaver";s:5:"email";s:14:"cellog@php.net";s:6:"active";s:2:"no";s:6:"handle";s:6:"cellog";s:4:"role";s:4:"lead";}i:1;a:5:{s:4:"name";s:17:"Pierre-Alain Joye";s:5:"email";s:14:"pierre@php.net";s:6:"active";s:2:"no";s:6:"handle";s:6:"pajoye";s:4:"role";s:4:"lead";}i:2;a:5:{s:4:"name";s:11:"Stig Bakken";s:5:"email";s:12:"stig@php.net";s:6:"active";s:2:"no";s:6:"handle";s:3:"ssb";s:4:"role";s:4:"lead";}i:3;a:5:{s:4:"name";s:13:"Tomas V.V.Cox";s:5:"email";s:15:"cox@idecnet.com";s:6:"active";s:2:"no";s:6:"handle";s:3:"cox";s:4:"role";s:4:"lead";}i:4;a:5:{s:4:"name";s:13:"Helgi Thormar";s:5:"email";s:13:"dufuz@php.net";s:6:"active";s:2:"no";s:6:"handle";s:5:"dufuz";s:4:"role";s:4:"lead";}i:5;a:5:{s:4:"name";s:16:"Christian Weiske";s:5:"email";s:15:"cweiske@php.net";s:6:"active";s:2:"no";s:6:"handle";s:7:"cweiske";s:4:"role";s:4:"lead";}i:6;a:5:{s:4:"name";s:13:"Chuck Burgess";s:5:"email";s:15:"ashnazg@php.net";s:6:"active";s:3:"yes";s:6:"handle";s:7:"ashnazg";s:4:"role";s:4:"lead";}i:7;a:5:{s:4:"name";s:9:"Tias Guns";s:5:"email";s:12:"tias@php.net";s:6:"active";s:2:"no";s:6:"handle";s:4:"tias";s:4:"role";s:9:"developer";}i:8;a:5:{s:4:"name";s:11:"Tim Jackson";s:5:"email";s:12:"timj@php.net";s:6:"active";s:2:"no";s:6:"handle";s:4:"timj";s:4:"role";s:6:"helper";}i:9;a:5:{s:4:"name";s:15:"Bertrand Gugger";s:5:"email";s:13:"toggg@php.net";s:6:"active";s:2:"no";s:6:"handle";s:5:"toggg";s:4:"role";s:6:"helper";}i:10;a:5:{s:4:"name";s:13:"Martin Jansen";s:5:"email";s:10:"mj@php.net";s:6:"active";s:2:"no";s:6:"handle";s:2:"mj";s:4:"role";s:6:"helper";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1770291810;}pear/.registry/structures_graph.reg000064400000025723152231651300013533 0ustar00a:24:{s:7:"attribs";a:6:{s:15:"packagerversion";s:7:"1.10.14";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:159:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:16:"Structures_Graph";s:7:"channel";s:12:"pear.php.net";s:7:"summary";s:40:"Graph datastructure manipulation library";s:11:"description";s:293:"Structures_Graph is a package for creating and manipulating graph datastructures. It allows building of directed and undirected graphs, with data and metadata stored in nodes. The library provides functions for graph traversing as well as for characteristic extraction from the graph topology.";s:4:"lead";a:4:{s:4:"name";s:16:"Sérgio Carvalho";s:4:"user";s:9:"sergiosgc";s:5:"email";s:32:"sergio.carvalho@portugalmail.com";s:6:"active";s:3:"yes";}s:6:"helper";a:4:{s:4:"name";s:12:"Brett Bieber";s:4:"user";s:11:"saltybeagle";s:5:"email";s:22:"brett.bieber@gmail.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2024-06-02";s:4:"time";s:8:"15:10:44";s:7:"version";a:2:{s:7:"release";s:5:"1.2.0";s:3:"api";s:5:"1.2.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";s:9:"LGPL-3.0+";s:5:"notes";s:97:"* update composer info (adds PHP/PEAR deps) * update phpunit tests * composer shows wrong license";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:2:{s:14:"baseinstalldir";s:1:"/";s:4:"name";s:1:"/";}s:4:"file";a:11:{i:0;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"628eb6532a8047bf5962fe24c1c245df";s:4:"name";s:52:"docs/tutorials/Structures_Graph/Structures_Graph.pkg";s:4:"role";s:3:"doc";}}i:1;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"4b26eecd30f8695fc3739b1a5b59518e";s:4:"name";s:44:"Structures/Graph/Manipulator/AcyclicTest.php";s:4:"role";s:3:"php";}}i:2;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"1f857de1fbbaace54b857ed9712f399f";s:4:"name";s:50:"Structures/Graph/Manipulator/TopologicalSorter.php";s:4:"role";s:3:"php";}}i:3;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"f8e969f0b45d3859408901c8350bb701";s:4:"name";s:25:"Structures/Graph/Node.php";s:4:"role";s:3:"php";}}i:4;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"88ae1ad8bcd74d4b74ad845f55611cdd";s:4:"name";s:20:"Structures/Graph.php";s:4:"role";s:3:"php";}}i:5;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"bfc441ea8614afed0f1e9074616a429b";s:4:"name";s:24:"tests/BasicGraphTest.php";s:4:"role";s:4:"test";}}i:6;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"8192d7b593d807191bf4aa9207bfbab5";s:4:"name";s:31:"tests/TopologicalSorterTest.php";s:4:"role";s:4:"test";}}i:7;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"8003f415d040b250e9e9c22c76b1cb59";s:4:"name";s:25:"tests/AcyclicTestTest.php";s:4:"role";s:4:"test";}}i:8;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"bfc441ea8614afed0f1e9074616a429b";s:4:"name";s:24:"tests/BasicGraphTest.php";s:4:"role";s:4:"test";}}i:9;a:2:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"c891580ee21a7aa863ac32566c979fc5";s:4:"name";s:16:"tests/helper.inc";s:4:"role";s:4:"test";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@php_dir@";s:2:"to";s:7:"php_dir";s:4:"type";s:11:"pear-config";}}}i:10;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"b52f2d57d10c4f7ee67a7eb9615d5d24";s:4:"name";s:7:"LICENSE";s:4:"role";s:3:"doc";}}}}}s:10:"compatible";a:4:{s:4:"name";s:4:"PEAR";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:8:"1.5.0RC3";s:3:"max";s:5:"1.9.1";}s:12:"dependencies";a:1:{s:8:"required";a:2:{s:3:"php";a:1:{s:3:"min";s:5:"5.3.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.3";}}}s:10:"phprelease";s:0:"";s:9:"changelog";a:1:{s:7:"release";a:6:{i:0;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.0.2";s:3:"api";s:5:"1.0.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2007-01-07";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:47:"http://opensource.org/licenses/lgpl-license.php";}s:8:"_content";s:4:"LGPL";}s:5:"notes";s:130:"- Bug #9682 only variables can be returned by reference - fix Bug #9661 notice in Structures_Graph_Manipulator_Topological::sort()";}i:1;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.0.3";s:3:"api";s:5:"1.0.3";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2009-10-11";s:7:"license";s:12:"LGPL License";s:5:"notes";s:258:"Bugfix Release: Version 1.0.3 is functionally equivalent to 1.0.2 but with an updated package.xml file. * Correct invalid md5 sum preventing installation with pyrus [saltybeagle] * Add compatible tag for PEAR 1.5.0RC3-1.9.0 [saltybeagle] * Update package.xml";}i:2;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.0.4";s:3:"api";s:5:"1.0.3";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2010-10-25";s:7:"license";s:12:"LGPL License";s:5:"notes";s:88:"Bugfix Release: * Bug #17108 BasicGraph::test_directed_degree fails on PHP 5 [clockwerx]";}i:3;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.1.0";s:3:"api";s:5:"1.1.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2015-02-26";s:7:"license";s:9:"LGPL-3.0+";s:5:"notes";s:128:"* Set minimum PHP version to 5.3 * Fix bug #19367: Incorrect FSF address in LICENSE * Change license from LGPL-2.1+ to LGPL-3.0+";}i:4;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.1.1";s:3:"api";s:5:"1.1.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2015-07-20";s:7:"license";s:9:"LGPL-3.0+";s:5:"notes";s:55:"* Fix deprecated constructor warning on PHP 7 [cweiske]";}i:5;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.2.0";s:3:"api";s:5:"1.2.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2024-06-02";s:7:"license";s:9:"LGPL-3.0+";s:5:"notes";s:97:"* update composer info (adds PHP/PEAR deps) * update phpunit tests * composer shows wrong license";}}}s:8:"filelist";a:10:{s:52:"docs/tutorials/Structures_Graph/Structures_Graph.pkg";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"628eb6532a8047bf5962fe24c1c245df";s:4:"name";s:52:"docs/tutorials/Structures_Graph/Structures_Graph.pkg";s:4:"role";s:3:"doc";s:12:"installed_as";s:114:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/Structures_Graph/docs/tutorials/Structures_Graph/Structures_Graph.pkg";}s:44:"Structures/Graph/Manipulator/AcyclicTest.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"4b26eecd30f8695fc3739b1a5b59518e";s:4:"name";s:44:"Structures/Graph/Manipulator/AcyclicTest.php";s:4:"role";s:3:"php";s:12:"installed_as";s:85:"/opt/cpanel/ea-php84/root/usr/share/pear/Structures/Graph/Manipulator/AcyclicTest.php";}s:50:"Structures/Graph/Manipulator/TopologicalSorter.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"1f857de1fbbaace54b857ed9712f399f";s:4:"name";s:50:"Structures/Graph/Manipulator/TopologicalSorter.php";s:4:"role";s:3:"php";s:12:"installed_as";s:91:"/opt/cpanel/ea-php84/root/usr/share/pear/Structures/Graph/Manipulator/TopologicalSorter.php";}s:25:"Structures/Graph/Node.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"f8e969f0b45d3859408901c8350bb701";s:4:"name";s:25:"Structures/Graph/Node.php";s:4:"role";s:3:"php";s:12:"installed_as";s:66:"/opt/cpanel/ea-php84/root/usr/share/pear/Structures/Graph/Node.php";}s:20:"Structures/Graph.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"88ae1ad8bcd74d4b74ad845f55611cdd";s:4:"name";s:20:"Structures/Graph.php";s:4:"role";s:3:"php";s:12:"installed_as";s:61:"/opt/cpanel/ea-php84/root/usr/share/pear/Structures/Graph.php";}s:24:"tests/BasicGraphTest.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"bfc441ea8614afed0f1e9074616a429b";s:4:"name";s:24:"tests/BasicGraphTest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:88:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/Structures_Graph/tests/BasicGraphTest.php";}s:31:"tests/TopologicalSorterTest.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"8192d7b593d807191bf4aa9207bfbab5";s:4:"name";s:31:"tests/TopologicalSorterTest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:95:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/Structures_Graph/tests/TopologicalSorterTest.php";}s:25:"tests/AcyclicTestTest.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"8003f415d040b250e9e9c22c76b1cb59";s:4:"name";s:25:"tests/AcyclicTestTest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:89:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/Structures_Graph/tests/AcyclicTestTest.php";}s:16:"tests/helper.inc";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"eef568ada49feace967da90447f09a1b";s:4:"name";s:16:"tests/helper.inc";s:4:"role";s:4:"test";s:12:"installed_as";s:80:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/Structures_Graph/tests/helper.inc";}s:7:"LICENSE";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"b52f2d57d10c4f7ee67a7eb9615d5d24";s:4:"name";s:7:"LICENSE";s:4:"role";s:3:"doc";s:12:"installed_as";s:69:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/Structures_Graph/LICENSE";}}s:12:"_lastversion";N;s:7:"dirtree";a:9:{s:93:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/Structures_Graph/docs/tutorials/Structures_Graph";b:1;s:76:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/Structures_Graph/docs/tutorials";b:1;s:66:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/Structures_Graph/docs";b:1;s:61:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/Structures_Graph";b:1;s:69:"/opt/cpanel/ea-php84/root/usr/share/pear/Structures/Graph/Manipulator";b:1;s:57:"/opt/cpanel/ea-php84/root/usr/share/pear/Structures/Graph";b:1;s:51:"/opt/cpanel/ea-php84/root/usr/share/pear/Structures";b:1;s:69:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/Structures_Graph/tests";b:1;s:63:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/Structures_Graph";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.2.0";s:12:"release_date";s:10:"2024-06-02";s:13:"release_state";s:6:"stable";s:15:"release_license";s:9:"LGPL-3.0+";s:13:"release_notes";s:97:"* update composer info (adds PHP/PEAR deps) * update phpunit tests * composer shows wrong license";s:12:"release_deps";a:2:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.3.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.3";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:2:{i:0;a:5:{s:4:"name";s:16:"Sérgio Carvalho";s:5:"email";s:32:"sergio.carvalho@portugalmail.com";s:6:"active";s:3:"yes";s:6:"handle";s:9:"sergiosgc";s:4:"role";s:4:"lead";}i:1;a:5:{s:4:"name";s:12:"Brett Bieber";s:5:"email";s:22:"brett.bieber@gmail.com";s:6:"active";s:3:"yes";s:6:"handle";s:11:"saltybeagle";s:4:"role";s:6:"helper";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1770291810;}pear/.registry/xml_util.reg000064400000073727152231651300011773 0ustar00a:23:{s:7:"attribs";a:6:{s:15:"packagerversion";s:6:"1.10.5";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:159:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:8:"XML_Util";s:7:"channel";s:12:"pear.php.net";s:7:"summary";s:17:"XML utility class";s:11:"description";s:192:"Selection of methods that are often needed when working with XML documents. Functionality includes creating of attribute lists from arrays, creation of tags, validation of XML names and more.";s:4:"lead";a:2:{i:0;a:4:{s:4:"name";s:13:"Chuck Burgess";s:4:"user";s:7:"ashnazg";s:5:"email";s:15:"ashnazg@php.net";s:6:"active";s:3:"yes";}i:1;a:4:{s:4:"name";s:15:"Stephan Schmidt";s:4:"user";s:5:"schst";s:5:"email";s:19:"schst@php-tools.net";s:6:"active";s:2:"no";}}s:6:"helper";a:4:{s:4:"name";s:12:"Davey Shafik";s:4:"user";s:5:"davey";s:5:"email";s:13:"davey@php.net";s:6:"active";s:2:"no";}s:4:"date";s:10:"2020-04-19";s:4:"time";s:8:"14:54:10";s:7:"version";a:2:{s:7:"release";s:5:"1.4.5";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:64:"* PR #12: fix Trying to access array offset on value of type int";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:2:{s:14:"baseinstalldir";s:1:"/";s:4:"name";s:1:"/";}s:4:"file";a:25:{i:0;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"af2746028ae4395f549855a5e444ada7";s:4:"name";s:20:"examples/example.php";s:4:"role";s:3:"doc";}}i:1;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"b9e52f4aa372c4067c609f49c2285b8f";s:4:"name";s:21:"examples/example2.php";s:4:"role";s:3:"doc";}}i:2;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"d0af9354df0962e70e9e2215b5611b9c";s:4:"name";s:27:"tests/AbstractUnitTests.php";s:4:"role";s:4:"test";}}i:3;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"57ce547d64d6e1f2986c313407deffef";s:4:"name";s:25:"tests/ApiVersionTests.php";s:4:"role";s:4:"test";}}i:4;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"2d0427db94790df7ada24a744547edf5";s:4:"name";s:33:"tests/AttributesToStringTests.php";s:4:"role";s:4:"test";}}i:5;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"673d1438c4718a70c5da3fe019027db4";s:4:"name";s:32:"tests/CollapseEmptyTagsTests.php";s:4:"role";s:4:"test";}}i:6;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"46b981f91edd163f1cd021cfef5d1bb1";s:4:"name";s:33:"tests/CreateCDataSectionTests.php";s:4:"role";s:4:"test";}}i:7;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"6aa925b879572e9b3f1885b7cdbb223b";s:4:"name";s:28:"tests/CreateCommentTests.php";s:4:"role";s:4:"test";}}i:8;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"dbc083b62a020fa245fde5a7828a4806";s:4:"name";s:31:"tests/CreateEndElementTests.php";s:4:"role";s:4:"test";}}i:9;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"f58e38343ecf60811c842d4cfc8194ae";s:4:"name";s:33:"tests/CreateStartElementTests.php";s:4:"role";s:4:"test";}}i:10;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"9385fba272f4ebccf4c95d43d16dcff4";s:4:"name";s:24:"tests/CreateTagTests.php";s:4:"role";s:4:"test";}}i:11;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"51e7ba1390e6dadc3c0be0c960bf171d";s:4:"name";s:33:"tests/CreateTagFromArrayTests.php";s:4:"role";s:4:"test";}}i:12;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"6bbb54ef4cf56dc2c0b558b295de5668";s:4:"name";s:36:"tests/GetDocTypeDeclarationTests.php";s:4:"role";s:4:"test";}}i:13;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"825b440b0ee8abd10b4df017c08bf15f";s:4:"name";s:32:"tests/GetXmlDeclarationTests.php";s:4:"role";s:4:"test";}}i:14;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"e6783bb330f8f2ae7225f02d56f194e4";s:4:"name";s:26:"tests/IsValidNameTests.php";s:4:"role";s:4:"test";}}i:15;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"b273525b905ae6d5fc53adcb3ce0b8d9";s:4:"name";s:25:"tests/RaiseErrorTests.php";s:4:"role";s:4:"test";}}i:16;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"20befbef5e55639539336761a17c64f3";s:4:"name";s:30:"tests/ReplaceEntitiesTests.php";s:4:"role";s:4:"test";}}i:17;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"a3ceff3302e31f90130be01c312b33b3";s:4:"name";s:30:"tests/ReverseEntitiesTests.php";s:4:"role";s:4:"test";}}i:18;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"aeb95108896180ef77a7dce3c310a3b8";s:4:"name";s:33:"tests/SplitQualifiedNameTests.php";s:4:"role";s:4:"test";}}i:19;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"e93010b1eff68f889fefcb006bf20b63";s:4:"name";s:22:"tests/Bug4950Tests.php";s:4:"role";s:4:"test";}}i:20;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"748ffb640e13e7b960385c7e12413782";s:4:"name";s:22:"tests/Bug5392Tests.php";s:4:"role";s:4:"test";}}i:21;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"01e68b66e27a6fdb197d572c67ae6bc5";s:4:"name";s:23:"tests/Bug18343Tests.php";s:4:"role";s:4:"test";}}i:22;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"d945220c38344bc773b18244439bb0cc";s:4:"name";s:23:"tests/Bug21177Tests.php";s:4:"role";s:4:"test";}}i:23;a:1:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"af2672bb90875c2e00f93f563bfafe70";s:4:"name";s:23:"tests/Bug21184Tests.php";s:4:"role";s:4:"test";}}i:24;a:2:{s:7:"attribs";a:4:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"0db6fa9c169bf6904aa7e588c2325a13";s:4:"name";s:12:"XML/Util.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:9:"@version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.4.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.9.0";}s:9:"extension";a:1:{s:4:"name";s:4:"pcre";}}}s:10:"phprelease";s:0:"";s:9:"changelog";a:1:{s:7:"release";a:31:{i:0;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"0.1";s:3:"api";s:3:"0.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2003-08-01";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:14:"inital release";}i:1;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"0.1.1";s:3:"api";s:5:"0.1.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2003-08-02";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:41:"bugfix: removed bug in createTagFromArray";}i:2;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"0.2";s:3:"api";s:3:"0.2";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2003-08-12";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:39:"added XML_Util::getDocTypeDeclaration()";}i:3;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"0.2.1";s:3:"api";s:5:"0.2.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2003-09-05";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:70:"fixed bug with zero as tag content in createTagFromArray and createTag";}i:4;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"0.3";s:3:"api";s:3:"0.3";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2003-09-12";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:49:"added createStartElement() and createEndElement()";}i:5;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"0.4";s:3:"api";s:3:"0.4";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2003-09-21";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:132:"added createCDataSection(), added support for CData sections in createTag* methods, fixed bug #23, fixed bug in splitQualifiedName()";}i:6;a:5:{s:7:"version";a:2:{s:7:"release";s:3:"0.5";s:3:"api";s:3:"0.5";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2003-09-23";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:170:"added support for multiline attributes in attributesToString(), createTag*() and createStartElement (requested by Yavor Shahpasov for XML_Serializer), added createComment";}i:7;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"0.5.1";s:3:"api";s:5:"0.5.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2003-09-26";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:102:"added default namespace parameter (optional) in splitQualifiedName() (requested by Sebastian Bergmann)";}i:8;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"0.5.2";s:3:"api";s:5:"0.5.2";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2003-11-22";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:78:"now creates XHTML compliant empty tags (Davey), minor whitespace fixes (Davey)";}i:9;a:5:{s:7:"version";a:2:{s:7:"release";s:10:"0.6.0beta1";s:3:"api";s:10:"0.6.0beta1";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:4:"date";s:10:"2004-05-24";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:567:"- Fixed bug 1438 (namespaces not accepted for isValidName()) (thanks to davey) - added optional parameter to replaceEntities() to define the set of entities to replace - added optional parameter to attributesToString() to define, whether entities should be replaced (requested by Sebastian Bergmann) - allowed second parameter to XML_Util::attributesToString() to be an array containing options (easier to use, if you only need to set the last parameter) - introduced XML_Util::raiseError() to avoid the necessity of including PEAR.php, will only be included on error";}i:10;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"0.6.0";s:3:"api";s:5:"0.6.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2004-06-07";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:567:"- Fixed bug 1438 (namespaces not accepted for isValidName()) (thanks to davey) - added optional parameter to replaceEntities() to define the set of entities to replace - added optional parameter to attributesToString() to define, whether entities should be replaced (requested by Sebastian Bergmann) - allowed second parameter to XML_Util::attributesToString() to be an array containing options (easier to use, if you only need to set the last parameter) - introduced XML_Util::raiseError() to avoid the necessity of including PEAR.php, will only be included on error";}i:11;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"0.6.1";s:3:"api";s:5:"0.6.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2004-10-28";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:103:"- Added check for tag name (either as local part or qualified name) in createTagFromArray() (bug #1083)";}i:12;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.0.0";s:3:"api";s:5:"1.0.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2004-10-28";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:41:"- Added reverseEntities() (request #2639)";}i:13;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.1.0";s:3:"api";s:5:"1.1.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2004-11-19";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:73:"- Added collapseEmptyTags (patch by Sebastian Bergmann and Thomas Duffey)";}i:14;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.1.1";s:3:"api";s:5:"1.1.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2004-12-23";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:306:"- fixed bug in replaceEntities() and reverseEntities() in conjunction with XML_UTIL_ENTITIES_HTML - createTag() and createTagFromArray() now accept XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML, XML_UTIL_ENTITIES_NONE and XML_UTIL_CDATA_SECTION as $replaceEntities parameter";}i:15;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.1.2";s:3:"api";s:5:"1.1.2";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2006-12-01";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:207:"- fixed bug #5419: isValidName() now checks for character classes - implemented request #8196: added optional parameter to influence array sorting to createTag() createTagFromArray() and createStartElement()";}i:16;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.1.4";s:3:"api";s:5:"1.1.4";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2006-12-16";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}s:5:"notes";s:61:"- Fixed bug #9561: Not allowing underscores in middle of tags";}i:17;a:5:{s:7:"version";a:2:{s:7:"release";s:7:"1.2.0a1";s:3:"api";s:5:"1.2.0";}s:9:"stability";a:2:{s:7:"release";s:5:"alpha";s:3:"api";s:5:"alpha";}s:4:"date";s:10:"2008-05-04";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:208:"Changed license to New BSD License (Req #13826 [ashnazg]) Added a test suite against all API methods [ashnazg] Switch to package.xml v2 [ashnazg] Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|ja.doma]";}i:18;a:5:{s:7:"version";a:2:{s:7:"release";s:7:"1.2.0a2";s:3:"api";s:5:"1.2.0";}s:9:"stability";a:2:{s:7:"release";s:5:"alpha";s:3:"api";s:5:"alpha";}s:4:"date";s:10:"2008-05-22";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:403:"Changed license to New BSD License (Req #13826 [ashnazg]) Added a test suite against all API methods [ashnazg] Switch to package.xml v2 [ashnazg] Added Req #13839: Missing XHTML empty tags to collapse [ashnazg|drry] Fixed Bug #5392: encoding of ISO-8859-1 is the only supported encoding [ashnazg] Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|drry] -- (this fix differs from the one in v1.2.0a1)";}i:19;a:5:{s:7:"version";a:2:{s:7:"release";s:8:"1.2.0RC1";s:3:"api";s:5:"1.2.0";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:4:"date";s:10:"2008-07-12";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:403:"Changed license to New BSD License (Req #13826 [ashnazg]) Added a test suite against all API methods [ashnazg] Switch to package.xml v2 [ashnazg] Added Req #13839: Missing XHTML empty tags to collapse [ashnazg|drry] Fixed Bug #5392: encoding of ISO-8859-1 is the only supported encoding [ashnazg] Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|drry] -- (this fix differs from the one in v1.2.0a1)";}i:20;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.2.0";s:3:"api";s:5:"1.2.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2008-07-26";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:403:"Changed license to New BSD License (Req #13826 [ashnazg]) Added a test suite against all API methods [ashnazg] Switch to package.xml v2 [ashnazg] Added Req #13839: Missing XHTML empty tags to collapse [ashnazg|drry] Fixed Bug #5392: encoding of ISO-8859-1 is the only supported encoding [ashnazg] Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|drry] -- (this fix differs from the one in v1.2.0a1)";}i:21;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.2.1";s:3:"api";s:5:"1.2.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2011-12-31";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:68:"Fixed Bug #14760: Bug in getDocTypeDeclaration() [ashnazg|fpospisil]";}i:22;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.2.2";s:3:"api";s:5:"1.2.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2014-06-07";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:194:"QA release Bug #18343 Entities in file names decoded during packaging Bug #19174 upgrade PHPUnit require statements & other fixes (for PEAR QA Team) Request #19750 examples/example.php encoding";}i:23;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.2.3";s:3:"api";s:5:"1.2.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2014-06-07";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:40:"Bug #20293 Broken installation for 1.2.2";}i:24;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.3.0";s:3:"api";s:5:"1.3.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2015-02-27";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:76:"* Set minimum PHP version to 5.3.0 * Mark static methods with static keyword";}i:25;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.0";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2017-02-03";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:203:"* Set minimum PHP version to 5.4.0 * Set minimum PEAR version to 1.10.1 * Adds a new XML_UTIL_COLLAPSE_NONE option for preventing empty tag collapsing. * Request #15467 CDATA sections and blank nodes";}i:26;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.1";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2017-02-07";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:58:"* Bug #21177 XML_Util::collapseEmptyTags() can return NULL";}i:27;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.2";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2017-02-22";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:27:"* Bug #21184 Collapse issue";}i:28;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.3";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2017-06-28";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:63:"* Decrease minimum PEAR version to 1.9.0 to allow PEAR upgrades";}i:29;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.4";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2019-12-05";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:29:"* PR #11: fix phplint warning";}i:30;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.4.5";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:4:"date";s:10:"2020-04-19";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:42:"http://opensource.org/licenses/bsd-license";}s:8:"_content";s:11:"BSD License";}s:5:"notes";s:64:"* PR #12: fix Trying to access array offset on value of type int";}}}s:8:"filelist";a:25:{s:20:"examples/example.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"af2746028ae4395f549855a5e444ada7";s:4:"name";s:20:"examples/example.php";s:4:"role";s:3:"doc";s:12:"installed_as";s:74:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/XML_Util/examples/example.php";}s:21:"examples/example2.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"b9e52f4aa372c4067c609f49c2285b8f";s:4:"name";s:21:"examples/example2.php";s:4:"role";s:3:"doc";s:12:"installed_as";s:75:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/XML_Util/examples/example2.php";}s:27:"tests/AbstractUnitTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"d0af9354df0962e70e9e2215b5611b9c";s:4:"name";s:27:"tests/AbstractUnitTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:83:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/AbstractUnitTests.php";}s:25:"tests/ApiVersionTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"57ce547d64d6e1f2986c313407deffef";s:4:"name";s:25:"tests/ApiVersionTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:81:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/ApiVersionTests.php";}s:33:"tests/AttributesToStringTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"2d0427db94790df7ada24a744547edf5";s:4:"name";s:33:"tests/AttributesToStringTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:89:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/AttributesToStringTests.php";}s:32:"tests/CollapseEmptyTagsTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"673d1438c4718a70c5da3fe019027db4";s:4:"name";s:32:"tests/CollapseEmptyTagsTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:88:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/CollapseEmptyTagsTests.php";}s:33:"tests/CreateCDataSectionTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"46b981f91edd163f1cd021cfef5d1bb1";s:4:"name";s:33:"tests/CreateCDataSectionTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:89:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/CreateCDataSectionTests.php";}s:28:"tests/CreateCommentTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"6aa925b879572e9b3f1885b7cdbb223b";s:4:"name";s:28:"tests/CreateCommentTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:84:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/CreateCommentTests.php";}s:31:"tests/CreateEndElementTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"dbc083b62a020fa245fde5a7828a4806";s:4:"name";s:31:"tests/CreateEndElementTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:87:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/CreateEndElementTests.php";}s:33:"tests/CreateStartElementTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"f58e38343ecf60811c842d4cfc8194ae";s:4:"name";s:33:"tests/CreateStartElementTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:89:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/CreateStartElementTests.php";}s:24:"tests/CreateTagTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"9385fba272f4ebccf4c95d43d16dcff4";s:4:"name";s:24:"tests/CreateTagTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:80:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/CreateTagTests.php";}s:33:"tests/CreateTagFromArrayTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"51e7ba1390e6dadc3c0be0c960bf171d";s:4:"name";s:33:"tests/CreateTagFromArrayTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:89:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/CreateTagFromArrayTests.php";}s:36:"tests/GetDocTypeDeclarationTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"6bbb54ef4cf56dc2c0b558b295de5668";s:4:"name";s:36:"tests/GetDocTypeDeclarationTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:92:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/GetDocTypeDeclarationTests.php";}s:32:"tests/GetXmlDeclarationTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"825b440b0ee8abd10b4df017c08bf15f";s:4:"name";s:32:"tests/GetXmlDeclarationTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:88:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/GetXmlDeclarationTests.php";}s:26:"tests/IsValidNameTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"e6783bb330f8f2ae7225f02d56f194e4";s:4:"name";s:26:"tests/IsValidNameTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:82:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/IsValidNameTests.php";}s:25:"tests/RaiseErrorTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"b273525b905ae6d5fc53adcb3ce0b8d9";s:4:"name";s:25:"tests/RaiseErrorTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:81:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/RaiseErrorTests.php";}s:30:"tests/ReplaceEntitiesTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"20befbef5e55639539336761a17c64f3";s:4:"name";s:30:"tests/ReplaceEntitiesTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:86:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/ReplaceEntitiesTests.php";}s:30:"tests/ReverseEntitiesTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"a3ceff3302e31f90130be01c312b33b3";s:4:"name";s:30:"tests/ReverseEntitiesTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:86:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/ReverseEntitiesTests.php";}s:33:"tests/SplitQualifiedNameTests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"aeb95108896180ef77a7dce3c310a3b8";s:4:"name";s:33:"tests/SplitQualifiedNameTests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:89:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/SplitQualifiedNameTests.php";}s:22:"tests/Bug4950Tests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"e93010b1eff68f889fefcb006bf20b63";s:4:"name";s:22:"tests/Bug4950Tests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:78:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/Bug4950Tests.php";}s:22:"tests/Bug5392Tests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"748ffb640e13e7b960385c7e12413782";s:4:"name";s:22:"tests/Bug5392Tests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:78:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/Bug5392Tests.php";}s:23:"tests/Bug18343Tests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"01e68b66e27a6fdb197d572c67ae6bc5";s:4:"name";s:23:"tests/Bug18343Tests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:79:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/Bug18343Tests.php";}s:23:"tests/Bug21177Tests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"d945220c38344bc773b18244439bb0cc";s:4:"name";s:23:"tests/Bug21177Tests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:79:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/Bug21177Tests.php";}s:23:"tests/Bug21184Tests.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"af2672bb90875c2e00f93f563bfafe70";s:4:"name";s:23:"tests/Bug21184Tests.php";s:4:"role";s:4:"test";s:12:"installed_as";s:79:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests/Bug21184Tests.php";}s:12:"XML/Util.php";a:5:{s:14:"baseinstalldir";s:1:"/";s:6:"md5sum";s:32:"0db6fa9c169bf6904aa7e588c2325a13";s:4:"name";s:12:"XML/Util.php";s:4:"role";s:3:"php";s:12:"installed_as";s:53:"/opt/cpanel/ea-php84/root/usr/share/pear/XML/Util.php";}}s:12:"_lastversion";N;s:7:"dirtree";a:5:{s:62:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/XML_Util/examples";b:1;s:53:"/opt/cpanel/ea-php84/root/usr/share/doc/pear/XML_Util";b:1;s:61:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util/tests";b:1;s:55:"/opt/cpanel/ea-php84/root/usr/share/tests/pear/XML_Util";b:1;s:44:"/opt/cpanel/ea-php84/root/usr/share/pear/XML";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.4.5";s:12:"release_date";s:10:"2020-04-19";s:13:"release_state";s:6:"stable";s:15:"release_license";s:11:"BSD License";s:13:"release_notes";s:64:"* PR #12: fix Trying to access array offset on value of type int";s:12:"release_deps";a:3:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.4.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.9.0";s:8:"optional";s:2:"no";}i:2;a:4:{s:4:"type";s:3:"ext";s:4:"name";s:4:"pcre";s:3:"rel";s:3:"has";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:3:{i:0;a:5:{s:4:"name";s:13:"Chuck Burgess";s:5:"email";s:15:"ashnazg@php.net";s:6:"active";s:3:"yes";s:6:"handle";s:7:"ashnazg";s:4:"role";s:4:"lead";}i:1;a:5:{s:4:"name";s:15:"Stephan Schmidt";s:5:"email";s:19:"schst@php-tools.net";s:6:"active";s:2:"no";s:6:"handle";s:5:"schst";s:4:"role";s:4:"lead";}i:2;a:5:{s:4:"name";s:12:"Davey Shafik";s:5:"email";s:13:"davey@php.net";s:6:"active";s:2:"no";s:6:"handle";s:5:"davey";s:4:"role";s:6:"helper";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1770291810;}pear/pkgxml/Archive_Tar.xml000064400000051362152231651300011713 0ustar00 Archive_Tar pear.php.net Tar file management class This class provides handling of tar files in PHP. It supports creating, listing, extracting and adding to tar files. Gzip support is available if PHP has the zlib extension built-in or loaded. Bz2 compression is also supported with the bz2 extension loaded. Also Lzma2 compressed archives are supported with xz extension. Vincent Blavet vblavet vincent@phpconcept.net no Greg Beaver cellog greg@chiaraquartet.net no Michiel Rook mrook mrook@php.net no Drew Webber mcdruid drew@mcdruid.co.uk yes Stig Bakken ssb stig@php.net no 2025-07-19 1.6.0 1.6.0 stable stable New BSD License This release drops support for PHP 5.4 and 5.5. * PR #51: big file support * PR #53: Fix return value of _writeBlock * PR #58: Remove gzopen/gztell/gzseek shim PEAR pear.php.net 1.8.0 1.10.10 5.6.0 1.10.0 1.6.0 1.6.0 stable stable 2025-07-19 New BSD License This release drops support for PHP 5.4 and 5.5. * PR #51: big file support * PR #53: Fix return value of _writeBlock * PR #58: Remove gzopen/gztell/gzseek shim 1.5.0 1.5.0 stable stable 2024-03-16 New BSD License * PR #42: fix @return true... to @return bool true... on some functions * PR #46: use 775 default for mkdirs, to avoid world-write 1.4.14 1.4.0 stable stable 2021-02-16 New BSD License * Properly fix symbolic link path traversal (CVE-2021-32610) 1.4.13 1.4.0 stable stable 2021-02-16 New BSD License * Fix Bug #27010: Relative symlinks failing (out-of path file extraction) [mrook] 1.4.12 1.4.0 stable stable 2021-01-18 New BSD License * Fix Bug #27008: Symlink out-of-path write vulnerability (CVE-2020-36193) [mrook] 1.4.11 1.4.0 stable stable 2020-11-19 New BSD License * Fix Bug #27002: Filename manipulation vulnerabilities (CVE-2020-28948 / CVE-2020-28949) [mrook] 1.4.10 1.4.0 stable stable 2020-09-15 New BSD License * Fix block padding when the file buffer length is a multiple of 512 and smaller than Archive_Tar buffer length * Don't try to copy username/groupname in chroot jail 1.4.9 1.4.0 stable stable 2019-12-04 New BSD License * Implement Feature #23861: Add option to disallow symlinks [mrook] 1.4.8 1.4.0 stable stable 2019-10-21 New BSD License * Fix Bug #23852: PHP 7.4 - Archive_Tar->_readHeader throws deprecation [mrook] 1.4.7 1.4.0 stable stable 2019-04-08 New BSD License * Improved performance by increasing read buffer size 1.4.6 1.4.0 stable stable 2019-02-01 New BSD License * Improve path traversal detection for forward and backward slashes 1.4.5 1.4.0 stable stable 2019-01-02 New BSD License * Fix Bug #23788: Relative symlinks are broken [mrook] 1.4.4 1.4.0 stable stable 2018-12-20 New BSD License * Fix Bug #21058: Long symlinks are not supported [mrook] * Fix Bug #23782: Prevent phar:// files from being extracted [mrook] 1.4.3 1.4.0 stable stable 2017-06-11 New BSD License * Fix Bug #21218: Cannot use result of built-in function in write context in PHP 7.2.0alpha1 [mrook] 1.4.2 1.4.0 stable stable 2016-02-25 New BSD License * Fix reading of archives with files > 8GB * Performance optimizations * Do not try to call require_once on PEAR.php if it has already been loaded by the autoloader 1.4.1 1.4.0 stable stable 2015-08-05 New BSD License * Update composer.json to use pear-core-minimal 1.10.0alpha2 1.4.0 1.4.0 stable stable 2015-07-20 New BSD License * Add support for PHP 7 * Drop support for PHP 4 * Add visibility declarations to methods and properties 1.3.16 1.3.1 stable stable 2015-04-14 New BSD License * Fix Bug #20514: invalid package.xml; not installable with pyrus [mrook] 1.3.15 1.3.1 stable stable 2015-03-05 New BSD License * Fixes composer.json parse error 1.3.14 1.3.1 stable stable 2015-02-26 New BSD License * Fix Bug #18505: Possible incorrect handling of file names in TAR [mrook] 1.3.13 1.3.1 stable stable 2014-09-02 New BSD License * Fix Bug #20382: gzopen fix [mrook] 1.3.12 1.3.1 stable stable 2014-08-04 New BSD License * Fix Bug #19964: Memory leaking in Archive_Tar [mrook] * Fix Bug #20246: Broken with php 5.5.9 [mrook] * Fix Bug #20275: "pax_global_header" looks like a regular file * [mrook] * Implement Feature #19827: pass filename to _addFile function - downstream * patch [mrook] * Implement Feature #20132: Add custom mode/uid/gid to addString() [mrook] 1.3.11 1.3.1 stable stable 2013-02-09 New BSD License * Fix Bug #19746: Broken with PHP 5.5 [mrook] * Implement Feature #11258: Custom date/time in files added on-the-fly * [mrook] 1.3.10 1.3.1 stable stable 2012-04-10 New BSD License * Fix Bug #13361: Unable to add() some files (ex. mp3) [mrook] * Fix Bug #19330: Class creates incorrect (non-readable) tar.gz file * [mrook] 1.3.9 1.3.1 stable stable 2012-02-27 New BSD License * Fix Bug #16759: No error thrown from missing PHP zlib functions [mrook] * Fix Bug #18877: Incorrect handling of backslashes in filenames on Linux [mrook] * Fix Bug #19085: Error while packaging [mrook] * Fix Bug #19289: Invalid tar file generated [mrook] 1.3.8 1.3.1 stable stable 2011-10-14 New BSD License * Fix Bug #17853: Test failure: dirtraversal.phpt [mrook] * Fix Bug #18512: dead links are not saved in tar file [mrook] * Fix Bug #18702: Unpacks incorrectly on long file names using header prefix [mrook] * Implement Feature #10145: Patch to return a Pear Error Object on failure [mrook] * Implement Feature #17491: Option to preserve permissions [mrook] * Implement Feature #17813: Prevent PHP notice when extracting corrupted archive [mrook] 1.3.7 1.3.1 stable stable 2010-04-26 New BSD License PEAR compatibility update 1.3.6 1.3.1 stable stable 2010-03-09 New BSD License * Fix Bug #16963: extractList can't extract zipped files from big tar [mrook] * Implement Feature #4013: Ignoring files and directories on creating an archive. [mrook] 1.3.5 1.3.1 stable stable 2009-12-31 New BSD License * Fix Bug #16958: Update 'compatible' tag in package.xml [mrook] 1.3.4 1.3.1 stable stable 2009-12-30 New BSD License * Fix Bug #11871: wrong result of ::listContent() if filename begins or ends with space [mrook] * Fix Bug #12462: invalid tar magic [mrook] * Fix Bug #13918: Long filenames may get up to 511 0x00 bytes appended on read [mrook] * Fix Bug #16202: Bogus modification times [mrook] * Implement Feature #16212: Die is not exception [mrook] 1.3.3 1.3.1 stable stable 2009-03-27 New BSD License Change the license to New BSD license minor bugfix release * fix Bug #9921 compression with bzip2 fails [cellog] * fix Bug #11594 _readLongHeader leaves 0 bytes in filename [jamessas] * fix Bug #11769 Incorrect symlink handing [fajar99] 1.3.2 1.3.1 stable stable 2007-01-03 PHP License Correct Bug #4016 Remove duplicate remove error display with '@' Correct Bug #3909 : Check existence of OS_WINDOWS constant Correct Bug #5452 fix for "lone zero block" when untarring packages Change filemode (from pear-core/Archive/Tar.php v.1.21) Correct Bug #6486 Can not extract symlinks Correct Bug #6933 Archive_Tar (Tar file management class) Directory traversal Correct Bug #8114 Files added on-the-fly not storing date Correct Bug #9352 Bug on _dirCheck function over nfs path 1.3.1 1.3.1 stable stable 2005-03-17 PHP License Correct Bug #3855 1.3.0 1.3.0 stable stable 2005-03-06 PHP License Bugs correction (2475, 2488, 2135, 2176) 1.2 1.2 stable stable 2004-05-08 PHP License Add support for other separator than the space char and bug correction 1.1 1.1 stable stable 2003-05-28 PHP License * Add support for BZ2 compression * Add support for add and extract without using temporary files : methods addString() and extractInString() 1.0 1.0 stable stable 2003-01-24 PHP License Change status to stable 0.10-b1 0.10-b1 beta beta 2003-01-08 PHP License Add support for long filenames (greater than 99 characters) 0.9 0.9 stable stable 2002-05-27 PHP License Auto-detect gzip'ed files 0.4 0.4 stable stable 2002-05-20 PHP License Windows bugfix: use forward slashes inside archives 0.2 0.2 stable stable 2002-02-18 PHP License From initial commit to stable 0.3 0.3 stable stable 2002-04-13 PHP License Windows bugfix: used wrong directory separators pear/pkgxml/Console_Getopt.xml000064400000016655152231651300012456 0ustar00 Console_Getopt pear.php.net Command-line option parser This is a PHP implementation of "getopt" supporting both short and long options. Andrei Zmievski andrei andrei@php.net no Stig Bakken ssb stig@php.net no Greg Beaver cellog cellog@php.net no 2019-11-20 1.4.3 1.4.0 stable stable BSD-2-Clause * PR #4: Fix PHP 7.4 deprecation: array/string curly braces access * PR #5: fix phplint warnings PEAR pear.php.net 1.4.0 1.999.999 5.4.0 1.8.0 2019-11-20 1.4.3 1.4.0 stable stable BSD-2-Clause * PR #4: Fix PHP 7.4 deprecation: array/string curly braces access * PR #5: fix phplint warnings 2019-02-06 1.4.2 1.4.0 stable stable BSD-2-Clause * Remove use of each(), which is removed in PHP 8 2015-07-20 1.4.1 1.4.0 stable stable BSD-2-Clause * Fix unit test on PHP 7 [cweiske] 2015-02-22 1.4.0 1.4.0 stable stable BSD-2-Clause * Change license to BSD-2-Clause * Set minimum PHP version to 5.4.0 * Mark static methods with "static" keyword 2011-03-07 1.3.1 1.3.0 stable stable PHP License * Change the minimum PEAR installer dep to be lower 2010-12-11 1.3.0 1.3.0 stable stable PHP License * Implement Request #13140: [PATCH] to skip unknown parameters. [patch by rquadling, improved on by dufuz] 2007-06-12 1.2.3 1.2.1 stable stable PHP License * fix Bug #11068: No way to read plain "-" option [cardoe] 1.2.2 1.2.1 stable stable 2007-02-17 PHP License * fix Bug #4475: An ambiguous error occurred when specifying similar longoption name. * fix Bug #10055: Not failing properly on short options missing required values 1.2.1 1.2.1 stable stable 2006-12-08 PHP License Fixed bugs #4448 (Long parameter values truncated with longoption parameter) and #7444 (Trailing spaces after php closing tag) 1.2 1.2 stable stable 2003-12-11 PHP License Fix to preserve BC with 1.0 and allow correct behaviour for new users 1.0 1.0 stable stable 2002-09-13 PHP License Stable release 0.11 0.11 beta beta 2002-05-26 PHP License POSIX getopt compatibility fix: treat first element of args array as command name 0.10 0.10 beta beta 2002-05-12 PHP License Packaging fix 0.9 0.9 beta beta 2002-05-12 PHP License Initial release pear/pkgxml/PEAR.xml000064400000172247152231651300010261 0ustar00 PEAR pear.php.net PEAR Base System The PEAR package contains: * the PEAR installer, for creating, distributing and installing packages * the PEAR_Exception PHP5 error handling mechanism * the PEAR_ErrorStack advanced error handling mechanism * the PEAR_Error error handling mechanism * the OS_Guess class for retrieving info about the OS where PHP is running on * the System class for quick handling of common operations with files and directories * the PEAR base class Features in a nutshell: * full support for channels * pre-download dependency validation * new package.xml 2.0 format allows tremendous flexibility while maintaining BC * support for optional dependency groups and limited support for sub-packaging * robust dependency support * full dependency validation on uninstall * remote install for hosts with only ftp access - no more problems with restricted host installation * full support for mirroring * support for bundling several packages into a single tarball * support for static dependencies on a url-based package * support for custom file roles and installation tasks Greg Beaver cellog cellog@php.net no Pierre-Alain Joye pajoye pierre@php.net no Stig Bakken ssb stig@php.net no Tomas V.V.Cox cox cox@idecnet.com no Helgi Thormar dufuz dufuz@php.net no Christian Weiske cweiske cweiske@php.net no Chuck Burgess ashnazg ashnazg@php.net yes Tias Guns tias tias@php.net no Tim Jackson timj timj@php.net no Bertrand Gugger toggg toggg@php.net no Martin Jansen mj mj@php.net no 2026-01-25 1.10.18 1.10.1 stable stable New BSD License * PR #164: don't use report_memleaks with 8.5+ 5.4.0 1.10.1 Archive_Tar pear.php.net 1.4.9 1.4.4 Structures_Graph pear.php.net 1.1.0 1.1.1 Console_Getopt pear.php.net 1.4.1 1.4.3 XML_Util pear.php.net 1.4.0 1.4.5 xml pcre PEAR_Frontend_Web pear.php.net 0.5.1 PEAR_Frontend_Gtk pear.php.net 0.4.0 PEAR_Frontend_Gtk2 pear.php.net windows 1.8.0alpha1 1.8.0 alpha stable 2009-03-09 New BSD License * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] * Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] * Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] * Implement Request #11170: script to generate Command/[command].xml [dufuz] * Implement Request #11176: improve channel ... has updated its protocols message [dufuz] * Implement Request #12706: pear list -a hard to read [dufuz] * Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] * Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] * Implement Request #13927: install-pear.php should have option to set www_dir [timj] * Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] * Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate better what other package managers are doing. upgrade-all will still work as intended. * Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for channel specific upgrades * Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] * Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] * Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] * Fix PHP Bug #47323: strotime warnings in make install [dufuz] * Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] * Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] * Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] * Fix Bug #13953: config-set/config-show with channel alias fail [cellog] * Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] * Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] * Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] * Fix Bug #14210: pear list -ia brings warnings [dufuz] * Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] * Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] * Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] * Fix Bug #14437: openbasedir warning when loading config [dufuz] * Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] * Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] * Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] * Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] * Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] * Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] NOTE! Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment to migrate over to one of the alternatives that have ben provided: * PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) * PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) * PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) * PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) * PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) * PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) * PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) * PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) * PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) * PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or PEAR_PackageFile_v2_Validator->_buildProvidesArray) PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls pear upgrade -f PEAR will allow people with lower versions to upgrade to this release but no guarantees will be made that it will work properly. Support for XML RPC channels has been dropped - The only ones that used it (pear.php.net and pecl.php.net) have used the REST interface for years now. SOAP support also removed as it was only proof of concept. Move codebase from the PHP License to New BSD 2 clause license 2009-03-27 1.8.0RC1 1.8.0 beta stable New BSD License * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] * Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] * Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] * Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz] 2009-04-10 1.8.0 1.8.0 stable stable New BSD License Changes since RC1: * Fix Bug #14792: Bad md5sum for files with replaced content [dufuz] * Fix Bug #16057:-r is limited to 4 directories in depth [dufuz] * Fix Bug #16077: PEAR5::getStaticProperty does not return a reference to the property [dufuz] Remove custom XML_Util class in favor of using upstream XML_Util package as dependency RC1 Release Notes: * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] * Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] * Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] * Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz] Alpha1 Release Notes: * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] * Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] * Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] * Implement Request #11170: script to generate Command/[command].xml [dufuz] * Implement Request #11176: improve channel ... has updated its protocols message [dufuz] * Implement Request #12706: pear list -a hard to read [dufuz] * Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] * Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] * Implement Request #13927: install-pear.php should have option to set www_dir [timj] * Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] * Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate better what other package managers are doing. upgrade-all will still work as intended. * Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for channel specific upgrades * Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] * Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] * Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] * Fix PHP Bug #47323: strotime warnings in make install [dufuz] * Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] * Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] * Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] * Fix Bug #13953: config-set/config-show with channel alias fail [cellog] * Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] * Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] * Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] * Fix Bug #14210: pear list -ia brings warnings [dufuz] * Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] * Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] * Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] * Fix Bug #14437: openbasedir warning when loading config [dufuz] * Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] * Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] * Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] * Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] * Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] * Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] NOTE! Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment to migrate over to one of the alternatives that have ben provided: * PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) * PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) * PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) * PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) * PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) * PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) * PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) * PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) * PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) * PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or PEAR_PackageFile_v2_Validator->_buildProvidesArray) PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls pear upgrade -f PEAR will allow people with lower versions to upgrade to this release but no guarantees will be made that it will work properly. Support for XML RPC channels has been dropped - The only ones that used it (pear.php.net and pecl.php.net) have used the REST interface for years now. SOAP support also removed as it was only proof of concept. Move codebase from the PHP License to New BSD 2 clause license 2009-04-15 1.8.1 1.8.1 stable stable New BSD License * Fix Bug #16099 PEAR crash on PHP4 (parse error) [dufuz] 2009-08-18 1.9.0RC1 1.9.0RC1 beta stable New BSD License * Implement Request #16213: add alias to list-channels output [dufuz] * Implement Request #16378: pear svntag [dufuz] * Implement Request #16386: PEAR_Config::remove() does not support specifying a channel [timj] * Implement Request #16396: package-dependencies should allow package names [dufuz] * Fix Bug #11181: pear requests channel.xml from main server instead from mirror [dufuz] * Fix Bug #14493: pear install --offline doesn't print out errors [dufuz] * Fix Bug #11348: pear package-dependencies isn't well explained [dufuz] * Fix Bug #16108: PEAR_PackageFile_Generator_v2 PHP4 parse error when running upgrade-all [dufuz] * Fix Bug #16113: Installing certain packages fails due incorrect encoding handling [dufuz] * Fix Bug #16122: PEAR RunTest failed to run as expected [dufuz] * Fix Bug #16366: compiling 5.2.10 leads to non-functioning pear [dufuz] * Fix Bug #16387: channel-logout does not support logging out from a non-default channel [timj] * Fix Bug #16444: Setting preferred mirror fails [dufuz] * Fix the shutdown functions where a index might not exist and thus raise a notice [derick] 2009-08-20 1.9.0RC2 1.9.0RC2 beta stable New BSD License * REST 1.4 file was occasionally being included but REST 1.4 is not intended for this release cycle [dufuz] 2009-08-21 1.9.0RC3 1.9.0RC3 beta stable New BSD License * Improved svntag support to handle packages like PEAR it self [dufuz] 2009-08-23 1.9.0RC4 1.9.0RC4 beta stable New BSD License * Fixed a problem where the original channel could not be set as a preferred_mirror again [dufuz] * Make sure channel aliases can't be made to start with - [dufuz] * Output issues with pear search [dufuz] * Fixed couple of stray notices [dufuz] 2009-09-03 1.9.0 1.9.0 stable stable New BSD License * Fix Bug #16547: The phar for PEAR installer uses ereg() which is deprecated [dufuz] 2010-05-26 1.9.1 1.9.1 stable stable New BSD License * svntag improvements, tag package files passed into the command and better directory checks [dufuz] * rely on Structures_Graph minimum version instead of recommended version [saltybeagle] * Fix Bug #12613: running go-pear.phar from C:\ fails [dufuz] * Fix Bug #14841: Installing pear into directory with space fails [dufuz] * Fix Bug #16644: pear.bat returns syntax error when parenthesis are in install path. [dufuz] [patch by bwaters (Bryan Waters)] * Fix Bug #16767: Use of Depreciated HTML Attributes in the Exception class [dufuz] [patch by fuhrysteve (Stephen J. Fuhry)] * Fix Bug #16864: "pear list-upgrades -i" issues E_WARNINGS [dufuz] [patch by rquadling (Richard Quadling)] * Fix Bug #17220: command `pear help` outputs to stderr instead of stdout [dufuz] * Fix Bug #17234: channel-discover adds port to HTTP Host header [dufuz] * Fix Bug #17292: Code Coverage in PEAR_RunTest does not work with namespaces [sebastian] * Fix Bug #17359: loadExtension() fails over missing dl() when used in multithread env [dufuz] * Fix Bug #17378: pear info $package fails if directory with that name exists [dufuz] 2011-02-28 1.9.2 1.9.2 stable stable New BSD License Important! This is a security fix release. The advisory can be found at http://pear.php.net/advisory-20110228.txt Bugs: * Fixed Bug #17463: Regression: On Windows, svntag [patch by doconnor] * Fixed Bug #17641: pecl-list doesn't sort packages by name [dufuz] * Fixed Bug #17781: invalid argument warning on foreach due to an empty optional dependencie [dufuz] * Fixed Bug #17801: PEAR run-tests wrongly detects php-cgi [patch by David Jean Louis (izi)] * Fixed Bug #17839: pear svntag does not tag package.xml file [dufuz] * Fixed Bug #17986: PEAR Installer cannot handle files moved between packages [dufuz] * Fixed Bug #17997: Strange output if directories are not writeable [dufuz] * Fixed Bug #18001: PEAR/RunTest coverage fails [dufuz] * Fixed Bug #18056 [SECURITY]: Symlink attack in PEAR install [dufuz] * Fixed Bug #18218: "pear package" does not allow the use of late static binding [dufuz and Christer Edvartsen] * Fixed Bug #18238: Wrong return code from "pear help" [till] * Fixed Bug #18308: Broken error message about missing channel validator [yunosh] This feature is implemented as a result of #18056 * Implemented Request #16648: Use TMPDIR for builds instead of /var/tmp [dufuz] 2011-06-04 1.9.3 1.9.2 stable stable New BSD License * Fixed Bug #17744: Empty changelog causes fatal error in setChangelogentry [dufuz] * Fixed Bug #18340: raiseErro typo [doconnor] * Fixed Bug #18349: package.xml version not recognized when single quoted [dufuz] * Fixed Bug #18364: date.timezone errors for sh/bat files when TZ is not set in php.ini [dufuz] * Fixed Bug #18388: Parentheses error in REST.php line 232 [dufuz] * Fixed Bug #18428: invalid preg_match patterns [glen] * Fixed Bug #18486: REST/10.php does not check error condition [dufuz] * Fixed a problem in RunTest and code coverage. Correctly register the code coverage shutdown function in case we are inside a namespace. [sebastian] * Fixed a bug with extensions not providing their config.m4 and co in the root directory of their pecl package but rather in a sub directory, such as xhprof. [dufuz] 2011-07-06 1.9.4 1.9.4 stable stable New BSD License Bug Fixes: * Bug #17350: "pear install --force" doesn't uninstall files from previous pkg versions [dufuz] * Bug #18362: A whitespace TEMP_DIR path breaks install/upgrade functionality [dufuz] * Bug #18440: bad tmp folder path on install : Unable to create path for C:/Program/tmp [dufuz] * Bug #18581: "config-get -c" not returning channel's configuration when using alias [dufuz] * Bug #18639: regression: installing xdebug fails most likely due to another fix [dufuz] Features * All System (the class) functions can now take in spaced paths as long as they are surrounded in quotes. Prior to this it was possible to do that by passing all values in as an array (by product of #18362, #18440) [dufuz] 2014-06-27 1.9.5dev1 1.9.5 devel devel New BSD License Bug fixes: * Fix bug #18343: Entities in file names decoded during packaging [cweiske] * Fix bug #18665: pecl extensions not enabled in empty php.ini files [Louis Opter] * Fix bug #18834: Do not truncate cache file if it is a symlink [avb] * Fix bug #18892: Parse error in Installer.php [ashnazg] * Fix bug #19482: fix pearcmd for include paths with trailing backslash [cweiske] * Fix bug #19793: PHP Notice about ob_end_clean() [cweiske] * Fix bug #20086: Invalid regexp in PEAR_Builder::build() [avb] * Fix bug #20203: split content-type and get real mime type [Samu Voutilainen] * Fix bug #20283: use full path for "zend_extension=..." [cweiske] * Fix bug #20284: Reset interpreter before running --CLEAN-- section php-cgi run [Mats Lindh] * Fix bug #20285: fix spelling mistakes [Veres Lajos] * Fix bug #20286: Support access of static variables on objects in validator [cweiske] * Fix bug #20321: Correctly detect name of current user during installation [cweiske] * Fix bug: let pear run-tests fail when there are failed tests [cweiske] * Prepare a test for bug #18056 / bug #18834 [avb] 2014-07-12 1.9.5 1.9.5 stable stable New BSD License No changes since 1.9.5.dev1. Bug fixes in 1.9.5.dev1: * Fix bug #18343: Entities in file names decoded during packaging [cweiske] * Fix bug #18665: pecl extensions not enabled in empty php.ini files [Louis Opter] * Fix bug #18834: Do not truncate cache file if it is a symlink [avb] * Fix bug #18892: Parse error in Installer.php [ashnazg] * Fix bug #19482: fix pearcmd for include paths with trailing backslash [cweiske] * Fix bug #19793: PHP Notice about ob_end_clean() [cweiske] * Fix bug #20086: Invalid regexp in PEAR_Builder::build() [avb] * Fix bug #20203: split content-type and get real mime type [Samu Voutilainen] * Fix bug #20283: use full path for "zend_extension=..." [cweiske] * Fix bug #20284: Reset interpreter before running --CLEAN-- section php-cgi run [Mats Lindh] * Fix bug #20285: fix spelling mistakes [Veres Lajos] * Fix bug #20286: Support access of static variables on objects in validator [cweiske] * Fix bug #20321: Correctly detect name of current user during installation [cweiske] * Fix bug: let pear run-tests fail when there are failed tests [cweiske] * Prepare a test for bug #18056 / bug #18834 [avb] 2015-07-25 1.10.0dev1 1.10.0 devel devel New BSD License * Implement #20488: Add support for PHP 7 [cweiske] * Drop support for PHP 4 and 5.0 - 5.3 [cweiske] * Remove deprecated methods [cweiske] * Fix static warnings [cweiske] * Fix #17045: avoid overwriting include path [glen] * Fix #17399: "pear help" doesn't mention the "version" command [kguest] * Add --showdiff to "pear run-tests" to print diff for failed tests [tyrael] * Fix channel.xml downloading from https if it did not change [cweiske] 2015-07-31 1.10.0dev2 1.10.0 devel devel New BSD License * Fix #18638 and #18405: Make PEAR::loadExtension static [cweiske] * Fix #20319: allow pear to work when cache_dir is not writable [remicollet] * Implement #20333: New role=man for man pages [bjori] * Implement #20334: add "metadata_dir" configuration option [remicollet] * Add long option names to install-pear.php [remicollet] 2015-09-28 1.10.0dev3 1.10.0 devel devel New BSD License * Fix #20507: pear list-upgrades does not take PHP version into account [cweiske] * Fix #20927: Use correct php-config [cweiske] * Fix #20946: PEAR_Builder::log() declaration [remicollet] * Remove PEAR/ErrorStack5.php [cweiske] 2015-10-07 1.10.0 1.10.0 stable stable New BSD License No changes since version 1.10.0dev3. Changes since version 1.9.5: * Implement #20488: Add support for PHP 7 [cweiske] * Drop support for PHP 4 and 5.0 - 5.3 [cweiske] * Remove deprecated methods [cweiske] * Add --showdiff to "pear run-tests" to print diff for failed tests [tyrael] * Implement #20333: New role=man for man pages [bjori] * Implement #20334: add "metadata_dir" configuration option [remicollet] * Add long option names to install-pear.php [remicollet] * Remove PEAR/ErrorStack5.php [cweiske] * Fix #17045: avoid overwriting include path [glen] * Fix #17399: "pear help" doesn't mention the "version" command [kguest] * Fix #18638 and #18405: Make PEAR::loadExtension static [cweiske] * Fix #20319: allow pear to work when cache_dir is not writable [remicollet] * Fix #20507: pear list-upgrades does not take PHP version into account [cweiske] * Fix #20927: Use correct php-config [cweiske] * Fix #20946: PEAR_Builder::log() declaration [remicollet] * Fix channel.xml downloading from https if it did not change [cweiske] * Fix static warnings [cweiske] 2015-10-17 1.10.1 1.10.1 stable stable New BSD License * Fix bug #20959: Crash on channel discovery with channel.xml redirect [cweiske] * Fix bug #20968: Incorrect call to __construct() from PEAR() [edlman] * Add legacy constructor for PEAR_Error for backwards compatibility [cweiske] 2017-02-28 1.10.2 1.10.1 stable stable New BSD License * Fix Bug #4426: PEAR_Autoloader __call() must take only 2 arguments [kna] * Fix Bug #20989: fatal error/bug in the postinstallscript task [kguest] * Fix Bug #20991: Strict Standards: startSession and run methods in PEAR_Task_Postinstallscript [kguest] * Fix Bug #21001: PEAR_ERROR_DIE exit code is 0 [danielc] * Pull Request #52: Channel's _lastmodified is an int and not a string [sathieu] * Pull Request #53: Add proper HTTPS proxy support through the CONNECT verb [youknow0] * Pull Request #58: Make method signatures compatible. [yunosh] 2017-02-28 1.10.3 1.10.1 stable stable New BSD License * Bug #21188: Class 'PEAR_Proxy' not found 2017-04-25 1.10.4 1.10.1 stable stable New BSD License * Bug #18102: pear install does not fail on error 2017-06-27 1.10.5 1.10.1 stable stable New BSD License * Bug #21222: PHP 7.2 compatibility: Upgrade to Archive_Tar 1.4.3 needed 2018-08-22 1.10.6 1.10.1 stable stable New BSD License * PR #70: Fix notice undefined variable metadata_dir * PR #71: fix Warning: count(): Parameter must be an array or an object * PR #74: Bug #23744 Remove is_executable check * Bug #23744: The is_executable check in the Which method when run on Windows is unnecessary * PR #75: Migrate old while(list() = each()) constructs to foreach * PR #76: Fix PHP Warning: "continue" targeting switch is equivalent to "break" * PR #77: proxy server auth * PR #72: Correctly authenticate at proxy server * PR #78: array or Countable error in 7.2 2018-12-05 1.10.7 1.10.1 stable stable New BSD License * PR #79: Prevent Unable to find the wrapper "channel" Warning * PR #80: fix Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2" * PR #81: Add flags to PECL shell script for shared extensions 2019-02-07 1.10.8 1.10.1 stable stable New BSD License * PR #83: Drop track_errors from options * PR #84: Fix PHP 8 compatibility issues 2019-03-13 1.10.9 1.10.1 stable stable New BSD License * PR #85: Fixes static calls for PHP 8 * PR #86: Adjust silencing check for PHP 8 * PR #87: Comparison fixes * PR #88: Only add bin_dir to PATH if not already there (fixes PHP Bug #75852) 2019-11-19 1.10.10 1.10.1 stable stable New BSD License * PR #89: Fix scripts/* include paths * PR #90: Non-interactive configureoption answers * PR #91: Added missing preg quote * PR #92: handle "lib64" case for glibc detection * PR #93: Fix PHP Notice: Trying to access array offset on value of type bool with 7.4 * PR #94: Updated logic in useLocalCache to reuse getCacheId * PR #95: Fix manpage warning * PR #96: Implement the SOURCE_DATE_EPOCH specification * PR #97: Fix PHP 7.4 deprecation: array/string curly braces access * PR #98: Fix use of null/false as array * PR #99: Fix Travis builds on PHP 5.4 and 5.5 * PR #100: Honor PHP temp directory config * PR #101: Fix documentation: the `--force` is required 2020-04-10 1.10.11 1.10.1 stable stable New BSD License * PR #102: Fix logging error for urls not in cache * PR #103: Fix undefined constant name * PR #105: Sort list of packages * PR #106: Update REST.php * PR #107: Update .travis.yml to include PHP 7.4 * PR #108: Remove unneeded code 2020-04-19 1.10.12 1.10.1 stable stable New BSD License * adjust dependencies based on new releases 2021-08-10 1.10.13 1.10.1 stable stable New BSD License * PR #114: unsupported protocol - use --force to continue * PR #117: Add $this operator to _determineIfPowerpc calls 2023-11-26 1.10.14 1.10.1 stable stable New BSD License * PR #112: Put glue and pieces parameters to implode in correct order for PHP 7.4+ * PR #121: Fix PHP bug 81653: Typo in install-pear-nozlib.phar * PR #122: add %S EXPECTF capability * PR #124: Fix: Creation of dynamic property PEAR_Error::$callback is deprecated * PR #125: Fixed extension loaded check for pecl binaries * PR #126: Remove -n option from pecl.bat for shared extensions * PR #127: fix Using ${var} in strings is deprecated * PR #128: fix lingering license references to PHP license * PR #129: Exclude tests from composer classmap * PR #131: fix private lastError name 2024-03-09 1.10.15 1.10.1 stable stable New BSD License * PR #132: cleanup uneeded test * PR #135: Fix PHP Deprecated: Calling get_class() without arguments 2024-11-24 1.10.16 1.10.1 stable stable New BSD License * PR #141: Fix bug #27796: "Array to string" conversion warnings on installs/other actions * PR #145: Never reference E_STRICT on PHP 8.4+ * PR #147: Fix tests 8.1+ 2025-12-14 1.10.17 1.10.1 stable stable New BSD License * PR #152: Fix HTTP chunked encoding handling * PR #153: fix composer.json: typo in replace for pear_exception package * PR #154: switch to https by default * PR #156: Throw new Error instead of E_USER_ERROR on PHP 7.0+ * PR #159: update tests for https-first behavior 2026-01-25 1.10.18 1.10.1 stable stable New BSD License * PR #164: don't use report_memleaks with 8.5+ pear/pkgxml/Structures_Graph.xml000064400000013142152231651300013022 0ustar00 Structures_Graph pear.php.net Graph datastructure manipulation library Structures_Graph is a package for creating and manipulating graph datastructures. It allows building of directed and undirected graphs, with data and metadata stored in nodes. The library provides functions for graph traversing as well as for characteristic extraction from the graph topology. Sérgio Carvalho sergiosgc sergio.carvalho@portugalmail.com yes Brett Bieber saltybeagle brett.bieber@gmail.com yes 2024-06-02 1.2.0 1.2.0 stable stable LGPL-3.0+ * update composer info (adds PHP/PEAR deps) * update phpunit tests * composer shows wrong license PEAR pear.php.net 1.5.0RC3 1.9.1 5.3.0 1.4.3 1.0.2 1.0.0 stable stable 2007-01-07 LGPL - Bug #9682 only variables can be returned by reference - fix Bug #9661 notice in Structures_Graph_Manipulator_Topological::sort() 1.0.3 1.0.3 stable stable 2009-10-11 LGPL License Bugfix Release: Version 1.0.3 is functionally equivalent to 1.0.2 but with an updated package.xml file. * Correct invalid md5 sum preventing installation with pyrus [saltybeagle] * Add compatible tag for PEAR 1.5.0RC3-1.9.0 [saltybeagle] * Update package.xml 1.0.4 1.0.3 stable stable 2010-10-25 LGPL License Bugfix Release: * Bug #17108 BasicGraph::test_directed_degree fails on PHP 5 [clockwerx] 1.1.0 1.1.0 stable stable 2015-02-26 LGPL-3.0+ * Set minimum PHP version to 5.3 * Fix bug #19367: Incorrect FSF address in LICENSE * Change license from LGPL-2.1+ to LGPL-3.0+ 1.1.1 1.1.0 stable stable 2015-07-20 LGPL-3.0+ * Fix deprecated constructor warning on PHP 7 [cweiske] 1.2.0 1.2.0 stable stable 2024-06-02 LGPL-3.0+ * update composer info (adds PHP/PEAR deps) * update phpunit tests * composer shows wrong license pear/pkgxml/XML_Util.xml000064400000045621152231651300011162 0ustar00 XML_Util pear.php.net XML utility class Selection of methods that are often needed when working with XML documents. Functionality includes creating of attribute lists from arrays, creation of tags, validation of XML names and more. Chuck Burgess ashnazg ashnazg@php.net yes Stephan Schmidt schst schst@php-tools.net no Davey Shafik davey davey@php.net no 2020-04-19 1.4.5 1.4.0 stable stable BSD License * PR #12: fix Trying to access array offset on value of type int 5.4.0 1.9.0 pcre 0.1 0.1 stable stable 2003-08-01 PHP License inital release 0.1.1 0.1.1 stable stable 2003-08-02 PHP License bugfix: removed bug in createTagFromArray 0.2 0.2 stable stable 2003-08-12 PHP License added XML_Util::getDocTypeDeclaration() 0.2.1 0.2.1 stable stable 2003-09-05 PHP License fixed bug with zero as tag content in createTagFromArray and createTag 0.3 0.3 stable stable 2003-09-12 PHP License added createStartElement() and createEndElement() 0.4 0.4 stable stable 2003-09-21 PHP License added createCDataSection(), added support for CData sections in createTag* methods, fixed bug #23, fixed bug in splitQualifiedName() 0.5 0.5 stable stable 2003-09-23 PHP License added support for multiline attributes in attributesToString(), createTag*() and createStartElement (requested by Yavor Shahpasov for XML_Serializer), added createComment 0.5.1 0.5.1 stable stable 2003-09-26 PHP License added default namespace parameter (optional) in splitQualifiedName() (requested by Sebastian Bergmann) 0.5.2 0.5.2 stable stable 2003-11-22 PHP License now creates XHTML compliant empty tags (Davey), minor whitespace fixes (Davey) 0.6.0beta1 0.6.0beta1 beta beta 2004-05-24 PHP License - Fixed bug 1438 (namespaces not accepted for isValidName()) (thanks to davey) - added optional parameter to replaceEntities() to define the set of entities to replace - added optional parameter to attributesToString() to define, whether entities should be replaced (requested by Sebastian Bergmann) - allowed second parameter to XML_Util::attributesToString() to be an array containing options (easier to use, if you only need to set the last parameter) - introduced XML_Util::raiseError() to avoid the necessity of including PEAR.php, will only be included on error 0.6.0 0.6.0 stable stable 2004-06-07 PHP License - Fixed bug 1438 (namespaces not accepted for isValidName()) (thanks to davey) - added optional parameter to replaceEntities() to define the set of entities to replace - added optional parameter to attributesToString() to define, whether entities should be replaced (requested by Sebastian Bergmann) - allowed second parameter to XML_Util::attributesToString() to be an array containing options (easier to use, if you only need to set the last parameter) - introduced XML_Util::raiseError() to avoid the necessity of including PEAR.php, will only be included on error 0.6.1 0.6.1 stable stable 2004-10-28 PHP License - Added check for tag name (either as local part or qualified name) in createTagFromArray() (bug #1083) 1.0.0 1.0.0 stable stable 2004-10-28 PHP License - Added reverseEntities() (request #2639) 1.1.0 1.1.0 stable stable 2004-11-19 PHP License - Added collapseEmptyTags (patch by Sebastian Bergmann and Thomas Duffey) 1.1.1 1.1.1 stable stable 2004-12-23 PHP License - fixed bug in replaceEntities() and reverseEntities() in conjunction with XML_UTIL_ENTITIES_HTML - createTag() and createTagFromArray() now accept XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML, XML_UTIL_ENTITIES_NONE and XML_UTIL_CDATA_SECTION as $replaceEntities parameter 1.1.2 1.1.2 stable stable 2006-12-01 PHP License - fixed bug #5419: isValidName() now checks for character classes - implemented request #8196: added optional parameter to influence array sorting to createTag() createTagFromArray() and createStartElement() 1.1.4 1.1.4 stable stable 2006-12-16 PHP License - Fixed bug #9561: Not allowing underscores in middle of tags 1.2.0a1 1.2.0 alpha alpha 2008-05-04 BSD License Changed license to New BSD License (Req #13826 [ashnazg]) Added a test suite against all API methods [ashnazg] Switch to package.xml v2 [ashnazg] Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|ja.doma] 1.2.0a2 1.2.0 alpha alpha 2008-05-22 BSD License Changed license to New BSD License (Req #13826 [ashnazg]) Added a test suite against all API methods [ashnazg] Switch to package.xml v2 [ashnazg] Added Req #13839: Missing XHTML empty tags to collapse [ashnazg|drry] Fixed Bug #5392: encoding of ISO-8859-1 is the only supported encoding [ashnazg] Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|drry] -- (this fix differs from the one in v1.2.0a1) 1.2.0RC1 1.2.0 beta beta 2008-07-12 BSD License Changed license to New BSD License (Req #13826 [ashnazg]) Added a test suite against all API methods [ashnazg] Switch to package.xml v2 [ashnazg] Added Req #13839: Missing XHTML empty tags to collapse [ashnazg|drry] Fixed Bug #5392: encoding of ISO-8859-1 is the only supported encoding [ashnazg] Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|drry] -- (this fix differs from the one in v1.2.0a1) 1.2.0 1.2.0 stable stable 2008-07-26 BSD License Changed license to New BSD License (Req #13826 [ashnazg]) Added a test suite against all API methods [ashnazg] Switch to package.xml v2 [ashnazg] Added Req #13839: Missing XHTML empty tags to collapse [ashnazg|drry] Fixed Bug #5392: encoding of ISO-8859-1 is the only supported encoding [ashnazg] Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|drry] -- (this fix differs from the one in v1.2.0a1) 1.2.1 1.2.0 stable stable 2011-12-31 BSD License Fixed Bug #14760: Bug in getDocTypeDeclaration() [ashnazg|fpospisil] 1.2.2 1.2.0 stable stable 2014-06-07 BSD License QA release Bug #18343 Entities in file names decoded during packaging Bug #19174 upgrade PHPUnit require statements & other fixes (for PEAR QA Team) Request #19750 examples/example.php encoding 1.2.3 1.2.0 stable stable 2014-06-07 BSD License Bug #20293 Broken installation for 1.2.2 1.3.0 1.3.0 stable stable 2015-02-27 BSD License * Set minimum PHP version to 5.3.0 * Mark static methods with static keyword 1.4.0 1.4.0 stable stable 2017-02-03 BSD License * Set minimum PHP version to 5.4.0 * Set minimum PEAR version to 1.10.1 * Adds a new XML_UTIL_COLLAPSE_NONE option for preventing empty tag collapsing. * Request #15467 CDATA sections and blank nodes 1.4.1 1.4.0 stable stable 2017-02-07 BSD License * Bug #21177 XML_Util::collapseEmptyTags() can return NULL 1.4.2 1.4.0 stable stable 2017-02-22 BSD License * Bug #21184 Collapse issue 1.4.3 1.4.0 stable stable 2017-06-28 BSD License * Decrease minimum PEAR version to 1.9.0 to allow PEAR upgrades 1.4.4 1.4.0 stable stable 2019-12-05 BSD License * PR #11: fix phplint warning 1.4.5 1.4.0 stable stable 2020-04-19 BSD License * PR #12: fix Trying to access array offset on value of type int pear/.depdb000064400000004040152231651300006546 0ustar00a:3:{s:8:"_version";s:3:"1.0";s:12:"dependencies";a:1:{s:12:"pear.php.net";a:1:{s:4:"pear";a:7:{i:0;a:3:{s:3:"dep";a:4:{s:4:"name";s:11:"Archive_Tar";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"1.4.9";s:11:"recommended";s:5:"1.4.4";}s:4:"type";s:8:"required";s:5:"group";b:0;}i:1;a:3:{s:3:"dep";a:4:{s:4:"name";s:16:"Structures_Graph";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"1.1.0";s:11:"recommended";s:5:"1.1.1";}s:4:"type";s:8:"required";s:5:"group";b:0;}i:2;a:3:{s:3:"dep";a:4:{s:4:"name";s:14:"Console_Getopt";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"1.4.1";s:11:"recommended";s:5:"1.4.3";}s:4:"type";s:8:"required";s:5:"group";b:0;}i:3;a:3:{s:3:"dep";a:4:{s:4:"name";s:8:"XML_Util";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"1.4.0";s:11:"recommended";s:5:"1.4.5";}s:4:"type";s:8:"required";s:5:"group";b:0;}i:4;a:3:{s:3:"dep";a:3:{s:4:"name";s:17:"PEAR_Frontend_Web";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"0.5.1";}s:4:"type";s:8:"optional";s:5:"group";s:12:"webinstaller";}i:5;a:3:{s:3:"dep";a:3:{s:4:"name";s:17:"PEAR_Frontend_Gtk";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"0.4.0";}s:4:"type";s:8:"optional";s:5:"group";s:12:"gtkinstaller";}i:6;a:3:{s:3:"dep";a:2:{s:4:"name";s:18:"PEAR_Frontend_Gtk2";s:7:"channel";s:12:"pear.php.net";}s:4:"type";s:8:"optional";s:5:"group";s:13:"gtk2installer";}}}}s:8:"packages";a:1:{s:12:"pear.php.net";a:7:{s:11:"archive_tar";a:1:{i:0;a:2:{s:7:"channel";s:12:"pear.php.net";s:7:"package";s:4:"pear";}}s:16:"structures_graph";a:1:{i:0;a:2:{s:7:"channel";s:12:"pear.php.net";s:7:"package";s:4:"pear";}}s:14:"console_getopt";a:1:{i:0;a:2:{s:7:"channel";s:12:"pear.php.net";s:7:"package";s:4:"pear";}}s:8:"xml_util";a:1:{i:0;a:2:{s:7:"channel";s:12:"pear.php.net";s:7:"package";s:4:"pear";}}s:17:"pear_frontend_web";a:1:{i:0;a:2:{s:7:"channel";s:12:"pear.php.net";s:7:"package";s:4:"pear";}}s:17:"pear_frontend_gtk";a:1:{i:0;a:2:{s:7:"channel";s:12:"pear.php.net";s:7:"package";s:4:"pear";}}s:18:"pear_frontend_gtk2";a:1:{i:0;a:2:{s:7:"channel";s:12:"pear.php.net";s:7:"package";s:4:"pear";}}}}}pear/.depdblock000064400000000000152231651300007407 0ustar00pear/.filemap000064400000015356152231651300007121 0ustar00a:5:{s:3:"php";a:101:{s:15:"Archive/Tar.php";s:11:"archive_tar";s:18:"Console/Getopt.php";s:14:"console_getopt";s:12:"OS/Guess.php";s:4:"pear";s:27:"PEAR/ChannelFile/Parser.php";s:4:"pear";s:21:"PEAR/Command/Auth.xml";s:4:"pear";s:21:"PEAR/Command/Auth.php";s:4:"pear";s:22:"PEAR/Command/Build.xml";s:4:"pear";s:22:"PEAR/Command/Build.php";s:4:"pear";s:25:"PEAR/Command/Channels.xml";s:4:"pear";s:25:"PEAR/Command/Channels.php";s:4:"pear";s:23:"PEAR/Command/Common.php";s:4:"pear";s:23:"PEAR/Command/Config.xml";s:4:"pear";s:23:"PEAR/Command/Config.php";s:4:"pear";s:24:"PEAR/Command/Install.xml";s:4:"pear";s:24:"PEAR/Command/Install.php";s:4:"pear";s:23:"PEAR/Command/Mirror.xml";s:4:"pear";s:23:"PEAR/Command/Mirror.php";s:4:"pear";s:24:"PEAR/Command/Package.xml";s:4:"pear";s:24:"PEAR/Command/Package.php";s:4:"pear";s:23:"PEAR/Command/Pickle.xml";s:4:"pear";s:23:"PEAR/Command/Pickle.php";s:4:"pear";s:25:"PEAR/Command/Registry.xml";s:4:"pear";s:25:"PEAR/Command/Registry.php";s:4:"pear";s:23:"PEAR/Command/Remote.xml";s:4:"pear";s:23:"PEAR/Command/Remote.php";s:4:"pear";s:21:"PEAR/Command/Test.xml";s:4:"pear";s:21:"PEAR/Command/Test.php";s:4:"pear";s:27:"PEAR/Downloader/Package.php";s:4:"pear";s:21:"PEAR/Frontend/CLI.php";s:4:"pear";s:30:"PEAR/Installer/Role/Common.php";s:4:"pear";s:27:"PEAR/Installer/Role/Cfg.xml";s:4:"pear";s:27:"PEAR/Installer/Role/Cfg.php";s:4:"pear";s:28:"PEAR/Installer/Role/Data.xml";s:4:"pear";s:28:"PEAR/Installer/Role/Data.php";s:4:"pear";s:27:"PEAR/Installer/Role/Doc.xml";s:4:"pear";s:27:"PEAR/Installer/Role/Doc.php";s:4:"pear";s:27:"PEAR/Installer/Role/Ext.xml";s:4:"pear";s:27:"PEAR/Installer/Role/Ext.php";s:4:"pear";s:27:"PEAR/Installer/Role/Man.xml";s:4:"pear";s:27:"PEAR/Installer/Role/Man.php";s:4:"pear";s:27:"PEAR/Installer/Role/Php.xml";s:4:"pear";s:27:"PEAR/Installer/Role/Php.php";s:4:"pear";s:30:"PEAR/Installer/Role/Script.xml";s:4:"pear";s:30:"PEAR/Installer/Role/Script.php";s:4:"pear";s:27:"PEAR/Installer/Role/Src.xml";s:4:"pear";s:27:"PEAR/Installer/Role/Src.php";s:4:"pear";s:28:"PEAR/Installer/Role/Test.xml";s:4:"pear";s:28:"PEAR/Installer/Role/Test.php";s:4:"pear";s:27:"PEAR/Installer/Role/Www.xml";s:4:"pear";s:27:"PEAR/Installer/Role/Www.php";s:4:"pear";s:23:"PEAR/Installer/Role.php";s:4:"pear";s:33:"PEAR/PackageFile/Generator/v1.php";s:4:"pear";s:33:"PEAR/PackageFile/Generator/v2.php";s:4:"pear";s:30:"PEAR/PackageFile/Parser/v1.php";s:4:"pear";s:30:"PEAR/PackageFile/Parser/v2.php";s:4:"pear";s:26:"PEAR/PackageFile/v2/rw.php";s:4:"pear";s:33:"PEAR/PackageFile/v2/Validator.php";s:4:"pear";s:23:"PEAR/PackageFile/v1.php";s:4:"pear";s:23:"PEAR/PackageFile/v2.php";s:4:"pear";s:16:"PEAR/REST/10.php";s:4:"pear";s:16:"PEAR/REST/11.php";s:4:"pear";s:16:"PEAR/REST/13.php";s:4:"pear";s:34:"PEAR/Task/Postinstallscript/rw.php";s:4:"pear";s:24:"PEAR/Task/Replace/rw.php";s:4:"pear";s:24:"PEAR/Task/Unixeol/rw.php";s:4:"pear";s:27:"PEAR/Task/Windowseol/rw.php";s:4:"pear";s:20:"PEAR/Task/Common.php";s:4:"pear";s:31:"PEAR/Task/Postinstallscript.php";s:4:"pear";s:21:"PEAR/Task/Replace.php";s:4:"pear";s:21:"PEAR/Task/Unixeol.php";s:4:"pear";s:24:"PEAR/Task/Windowseol.php";s:4:"pear";s:23:"PEAR/Validator/PECL.php";s:4:"pear";s:16:"PEAR/Builder.php";s:4:"pear";s:20:"PEAR/ChannelFile.php";s:4:"pear";s:16:"PEAR/Command.php";s:4:"pear";s:15:"PEAR/Common.php";s:4:"pear";s:15:"PEAR/Config.php";s:4:"pear";s:21:"PEAR/DependencyDB.php";s:4:"pear";s:20:"PEAR/Dependency2.php";s:4:"pear";s:19:"PEAR/Downloader.php";s:4:"pear";s:19:"PEAR/ErrorStack.php";s:4:"pear";s:18:"PEAR/Exception.php";s:4:"pear";s:17:"PEAR/Frontend.php";s:4:"pear";s:18:"PEAR/Installer.php";s:4:"pear";s:20:"PEAR/PackageFile.php";s:4:"pear";s:17:"PEAR/Packager.php";s:4:"pear";s:14:"PEAR/Proxy.php";s:4:"pear";s:17:"PEAR/Registry.php";s:4:"pear";s:13:"PEAR/REST.php";s:4:"pear";s:16:"PEAR/RunTest.php";s:4:"pear";s:17:"PEAR/Validate.php";s:4:"pear";s:18:"PEAR/XMLParser.php";s:4:"pear";s:19:"scripts/pearcmd.php";s:4:"pear";s:19:"scripts/peclcmd.php";s:4:"pear";s:8:"PEAR.php";s:4:"pear";s:10:"System.php";s:4:"pear";s:44:"Structures/Graph/Manipulator/AcyclicTest.php";s:16:"structures_graph";s:50:"Structures/Graph/Manipulator/TopologicalSorter.php";s:16:"structures_graph";s:25:"Structures/Graph/Node.php";s:16:"structures_graph";s:20:"Structures/Graph.php";s:16:"structures_graph";s:12:"XML/Util.php";s:8:"xml_util";}s:3:"doc";a:8:{s:32:"archive_tar/docs/Archive_Tar.txt";s:11:"archive_tar";s:12:"pear/LICENSE";s:4:"pear";s:12:"pear/INSTALL";s:4:"pear";s:15:"pear/README.rst";s:4:"pear";s:69:"structures_graph/docs/tutorials/Structures_Graph/Structures_Graph.pkg";s:16:"structures_graph";s:24:"structures_graph/LICENSE";s:16:"structures_graph";s:29:"xml_util/examples/example.php";s:8:"xml_util";s:30:"xml_util/examples/example2.php";s:8:"xml_util";}s:4:"test";a:30:{s:36:"console_getopt/tests/001-getopt.phpt";s:14:"console_getopt";s:34:"console_getopt/tests/bug10557.phpt";s:14:"console_getopt";s:34:"console_getopt/tests/bug11068.phpt";s:14:"console_getopt";s:34:"console_getopt/tests/bug13140.phpt";s:14:"console_getopt";s:41:"structures_graph/tests/BasicGraphTest.php";s:16:"structures_graph";s:48:"structures_graph/tests/TopologicalSorterTest.php";s:16:"structures_graph";s:42:"structures_graph/tests/AcyclicTestTest.php";s:16:"structures_graph";s:33:"structures_graph/tests/helper.inc";s:16:"structures_graph";s:36:"xml_util/tests/AbstractUnitTests.php";s:8:"xml_util";s:34:"xml_util/tests/ApiVersionTests.php";s:8:"xml_util";s:42:"xml_util/tests/AttributesToStringTests.php";s:8:"xml_util";s:41:"xml_util/tests/CollapseEmptyTagsTests.php";s:8:"xml_util";s:42:"xml_util/tests/CreateCDataSectionTests.php";s:8:"xml_util";s:37:"xml_util/tests/CreateCommentTests.php";s:8:"xml_util";s:40:"xml_util/tests/CreateEndElementTests.php";s:8:"xml_util";s:42:"xml_util/tests/CreateStartElementTests.php";s:8:"xml_util";s:33:"xml_util/tests/CreateTagTests.php";s:8:"xml_util";s:42:"xml_util/tests/CreateTagFromArrayTests.php";s:8:"xml_util";s:45:"xml_util/tests/GetDocTypeDeclarationTests.php";s:8:"xml_util";s:41:"xml_util/tests/GetXmlDeclarationTests.php";s:8:"xml_util";s:35:"xml_util/tests/IsValidNameTests.php";s:8:"xml_util";s:34:"xml_util/tests/RaiseErrorTests.php";s:8:"xml_util";s:39:"xml_util/tests/ReplaceEntitiesTests.php";s:8:"xml_util";s:39:"xml_util/tests/ReverseEntitiesTests.php";s:8:"xml_util";s:42:"xml_util/tests/SplitQualifiedNameTests.php";s:8:"xml_util";s:31:"xml_util/tests/Bug4950Tests.php";s:8:"xml_util";s:31:"xml_util/tests/Bug5392Tests.php";s:8:"xml_util";s:32:"xml_util/tests/Bug18343Tests.php";s:8:"xml_util";s:32:"xml_util/tests/Bug21177Tests.php";s:8:"xml_util";s:32:"xml_util/tests/Bug21184Tests.php";s:8:"xml_util";}s:6:"script";a:3:{s:15:"scripts/pear.sh";s:4:"pear";s:18:"scripts/peardev.sh";s:4:"pear";s:15:"scripts/pecl.sh";s:4:"pear";}s:4:"data";a:2:{s:16:"pear/package.dtd";s:4:"pear";s:18:"pear/template.spec";s:4:"pear";}}pear/.lock000064400000000000152231651300006410 0ustar00