"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/npm/lib/cache/add-named.js" (8 Mar 2017, 9202 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 var path = require('path')
    2 var assert = require('assert')
    3 var fs = require('graceful-fs')
    4 var http = require('http')
    5 var log = require('npmlog')
    6 var semver = require('semver')
    7 var readJson = require('read-package-json')
    8 var url = require('url')
    9 var npm = require('../npm.js')
   10 var deprCheck = require('../utils/depr-check.js')
   11 var inflight = require('inflight')
   12 var addRemoteTarball = require('./add-remote-tarball.js')
   13 var cachedPackageRoot = require('./cached-package-root.js')
   14 var mapToRegistry = require('../utils/map-to-registry.js')
   15 var pulseTillDone = require('../utils/pulse-till-done.js')
   16 var packageId = require('../utils/package-id.js')
   17 
   18 module.exports = addNamed
   19 
   20 function getOnceFromRegistry (name, from, next, done) {
   21   function fixName (err, data, json, resp) {
   22     // this is only necessary until npm/npm-registry-client#80 is fixed
   23     if (err && err.pkgid && err.pkgid !== name) {
   24       err.message = err.message.replace(
   25         new RegExp(': ' + err.pkgid.replace(/(\W)/g, '\\$1') + '$'),
   26         ': ' + name
   27       )
   28       err.pkgid = name
   29     }
   30     next(err, data, json, resp)
   31   }
   32 
   33   mapToRegistry(name, npm.config, function (er, uri, auth) {
   34     if (er) return done(er)
   35 
   36     var key = 'registry:' + uri
   37     next = inflight(key, next)
   38     if (!next) return log.verbose(from, key, 'already in flight; waiting')
   39     else log.verbose(from, key, 'not in flight; fetching')
   40 
   41     npm.registry.get(uri, { auth: auth }, pulseTillDone('fetchRegistry', fixName))
   42   })
   43 }
   44 
   45 function addNamed (name, version, data, cb_) {
   46   assert(typeof name === 'string', 'must have module name')
   47   assert(typeof cb_ === 'function', 'must have callback')
   48 
   49   var key = name + '@' + version
   50   log.silly('addNamed', key)
   51 
   52   function cb (er, data) {
   53     if (data && !data._fromHosted) data._from = key
   54     cb_(er, data)
   55   }
   56 
   57   if (semver.valid(version, true)) {
   58     log.verbose('addNamed', JSON.stringify(version), 'is a plain semver version for', name)
   59     addNameVersion(name, version, data, cb)
   60   } else if (semver.validRange(version, true)) {
   61     log.verbose('addNamed', JSON.stringify(version), 'is a valid semver range for', name)
   62     addNameRange(name, version, data, cb)
   63   } else {
   64     log.verbose('addNamed', JSON.stringify(version), 'is being treated as a dist-tag for', name)
   65     addNameTag(name, version, data, cb)
   66   }
   67 }
   68 
   69 function addNameTag (name, tag, data, cb) {
   70   log.info('addNameTag', [name, tag])
   71   var explicit = true
   72   if (!tag) {
   73     explicit = false
   74     tag = npm.config.get('tag')
   75   }
   76 
   77   getOnceFromRegistry(name, 'addNameTag', next, cb)
   78 
   79   function next (er, data, json, resp) {
   80     if (!er) er = errorResponse(name, resp)
   81     if (er) return cb(er)
   82 
   83     log.silly('addNameTag', 'next cb for', name, 'with tag', tag)
   84 
   85     engineFilter(data)
   86     if (data['dist-tags'] && data['dist-tags'][tag] &&
   87         data.versions[data['dist-tags'][tag]]) {
   88       var ver = data['dist-tags'][tag]
   89       return addNamed(name, ver, data.versions[ver], cb)
   90     }
   91     if (!explicit && Object.keys(data.versions).length) {
   92       return addNamed(name, '*', data, cb)
   93     }
   94 
   95     er = installTargetsError(tag, data)
   96     return cb(er)
   97   }
   98 }
   99 
  100 function engineFilter (data) {
  101   var npmv = npm.version
  102   var nodev = npm.config.get('node-version')
  103   var strict = npm.config.get('engine-strict')
  104 
  105   if (!nodev || npm.config.get('force')) return data
  106 
  107   Object.keys(data.versions || {}).forEach(function (v) {
  108     var eng = data.versions[v].engines
  109     if (!eng) return
  110     if (!strict) return
  111     if (eng.node && !semver.satisfies(nodev, eng.node, true) ||
  112         eng.npm && !semver.satisfies(npmv, eng.npm, true)) {
  113       delete data.versions[v]
  114     }
  115   })
  116 }
  117 
  118 function addNameVersion (name, v, data, cb) {
  119   var ver = semver.valid(v, true)
  120   if (!ver) return cb(new Error('Invalid version: ' + v))
  121 
  122   var response
  123 
  124   if (data) {
  125     response = null
  126     return next()
  127   }
  128 
  129   getOnceFromRegistry(name, 'addNameVersion', setData, cb)
  130 
  131   function setData (er, d, json, resp) {
  132     if (!er) {
  133       er = errorResponse(name, resp)
  134     }
  135     if (er) return cb(er)
  136     data = d && d.versions[ver]
  137     if (!data) {
  138       er = new Error('version not found: ' + name + '@' + ver)
  139       er.package = name
  140       er.statusCode = 404
  141       return cb(er)
  142     }
  143     response = resp
  144     next()
  145   }
  146 
  147   function next () {
  148     deprCheck(data)
  149     var dist = data.dist
  150 
  151     if (!dist) return cb(new Error('No dist in ' + packageId(data) + ' package'))
  152 
  153     if (!dist.tarball) {
  154       return cb(new Error(
  155       'No dist.tarball in ' + packageId(data) + ' package'
  156       ))
  157     }
  158 
  159     if ((response && response.statusCode !== 304) || npm.config.get('force')) {
  160       return fetchit()
  161     }
  162 
  163     // we got cached data, so let's see if we have a tarball.
  164     var pkgroot = cachedPackageRoot({ name: name, version: ver })
  165     var pkgtgz = path.join(pkgroot, 'package.tgz')
  166     var pkgjson = path.join(pkgroot, 'package', 'package.json')
  167     fs.stat(pkgtgz, function (er) {
  168       if (!er) {
  169         readJson(pkgjson, function (er, data) {
  170           if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
  171 
  172           if (data) {
  173             if (!data.name) return cb(new Error('No name provided'))
  174             if (!data.version) return cb(new Error('No version provided'))
  175 
  176             // check the SHA of the package we have, to ensure it wasn't installed
  177             // from somewhere other than the registry (eg, a fork)
  178             if (data._shasum && dist.shasum && data._shasum !== dist.shasum) {
  179               return fetchit()
  180             }
  181           }
  182 
  183           if (er) return fetchit()
  184             else return cb(null, data)
  185         })
  186       } else return fetchit()
  187     })
  188 
  189     function fetchit () {
  190       mapToRegistry(name, npm.config, function (er, _, auth, ruri) {
  191         if (er) return cb(er)
  192 
  193         // Use the same protocol as the registry.  https registry --> https
  194         // tarballs, but only if they're the same hostname, or else detached
  195         // tarballs may not work.
  196         var tb = url.parse(dist.tarball)
  197         var rp = url.parse(ruri)
  198         if (tb.hostname === rp.hostname && tb.protocol !== rp.protocol) {
  199           tb.protocol = rp.protocol
  200           // If a different port is associated with the other protocol
  201           // we need to update that as well
  202           if (rp.port !== tb.port) {
  203             tb.port = rp.port
  204             delete tb.host
  205           }
  206           delete tb.href
  207         }
  208         tb = url.format(tb)
  209 
  210         // Only add non-shasum'ed packages if --forced. Only ancient things
  211         // would lack this for good reasons nowadays.
  212         if (!dist.shasum && !npm.config.get('force')) {
  213           return cb(new Error('package lacks shasum: ' + packageId(data)))
  214         }
  215 
  216         addRemoteTarball(tb, data, dist.shasum, auth, cb)
  217       })
  218     }
  219   }
  220 }
  221 
  222 function addNameRange (name, range, data, cb) {
  223   range = semver.validRange(range, true)
  224   if (range === null) {
  225     return cb(new Error(
  226       'Invalid version range: ' + range
  227     ))
  228   }
  229 
  230   log.silly('addNameRange', { name: name, range: range, hasData: !!data })
  231 
  232   if (data) return next()
  233 
  234   getOnceFromRegistry(name, 'addNameRange', setData, cb)
  235 
  236   function setData (er, d, json, resp) {
  237     if (!er) {
  238       er = errorResponse(name, resp)
  239     }
  240     if (er) return cb(er)
  241     data = d
  242     next()
  243   }
  244 
  245   function next () {
  246     log.silly(
  247       'addNameRange',
  248       'number 2', { name: name, range: range, hasData: !!data }
  249     )
  250     engineFilter(data)
  251 
  252     log.silly('addNameRange', 'versions'
  253              , [data.name, Object.keys(data.versions || {})])
  254 
  255     // if the tagged version satisfies, then use that.
  256     var tagged = data['dist-tags'][npm.config.get('tag')]
  257     if (tagged &&
  258         data.versions[tagged] &&
  259         semver.satisfies(tagged, range, true)) {
  260       return addNamed(name, tagged, data.versions[tagged], cb)
  261     }
  262 
  263     // find the max satisfying version.
  264     var versions = Object.keys(data.versions || {})
  265     var ms = semver.maxSatisfying(versions, range, true)
  266     if (!ms) {
  267       if (range === '*' && versions.length) {
  268         return addNameTag(name, 'latest', data, cb)
  269       } else {
  270         return cb(installTargetsError(range, data))
  271       }
  272     }
  273 
  274     // if we don't have a registry connection, try to see if
  275     // there's a cached copy that will be ok.
  276     addNamed(name, ms, data.versions[ms], cb)
  277   }
  278 }
  279 
  280 function installTargetsError (requested, data) {
  281   var targets = Object.keys(data['dist-tags']).filter(function (f) {
  282     return (data.versions || {}).hasOwnProperty(f)
  283   }).concat(Object.keys(data.versions || {}))
  284 
  285   requested = data.name + (requested ? "@'" + requested + "'" : '')
  286 
  287   targets = targets.length
  288           ? 'Valid install targets:\n' + targets.join(', ') + '\n'
  289           : 'No valid targets found.\n' +
  290             'Perhaps not compatible with your version of node?'
  291 
  292   var er = new Error('No compatible version found: ' + requested + '\n' + targets)
  293   er.code = 'ETARGET'
  294   return er
  295 }
  296 
  297 function errorResponse (name, response) {
  298   var er
  299   if (response.statusCode >= 400) {
  300     er = new Error(http.STATUS_CODES[response.statusCode])
  301     er.statusCode = response.statusCode
  302     er.code = 'E' + er.statusCode
  303     er.pkgid = name
  304   }
  305   return er
  306 }