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