summaryrefslogtreecommitdiff
path: root/deps/npm/lib/utils/npm-registry-client/get.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/lib/utils/npm-registry-client/get.js')
-rw-r--r--deps/npm/lib/utils/npm-registry-client/get.js171
1 files changed, 171 insertions, 0 deletions
diff --git a/deps/npm/lib/utils/npm-registry-client/get.js b/deps/npm/lib/utils/npm-registry-client/get.js
new file mode 100644
index 0000000000..062244df3a
--- /dev/null
+++ b/deps/npm/lib/utils/npm-registry-client/get.js
@@ -0,0 +1,171 @@
+
+module.exports = get
+
+var GET = require("./request.js").GET
+ , fs = require("graceful-fs")
+ , npm = require("../../npm.js")
+ , path = require("path")
+ , log = require("../log.js")
+ , mkdir = require("../mkdir-p.js")
+ , cacheStat = null
+
+function get (project, version, timeout, nofollow, staleOk, cb) {
+ if (typeof cb !== "function") cb = staleOk, staleOk = false
+ if (typeof cb !== "function") cb = nofollow, nofollow = false
+ if (typeof cb !== "function") cb = timeout, timeout = -1
+ if (typeof cb !== "function") cb = version, version = null
+ if (typeof cb !== "function") cb = project, project = null
+ if (typeof cb !== "function") {
+ throw new Error("No callback provided to registry.get")
+ }
+
+ if ( process.env.COMP_CWORD !== undefined
+ && process.env.COMP_LINE !== undefined
+ && process.env.COMP_POINT !== undefined
+ ) timeout = Math.max(timeout, 60000)
+
+ var uri = []
+ uri.push(project || "")
+ if (version) uri.push(version)
+ uri = uri.join("/")
+
+ // /-/all is special.
+ // It uses timestamp-based caching and partial updates,
+ // because it is a monster.
+ if (uri === "/-/all") {
+ return requestAll(cb)
+ }
+
+ var cache = path.join(npm.cache, uri, ".cache.json")
+ fs.stat(cache, function (er, stat) {
+ if (!er) fs.readFile(cache, function (er, data) {
+ try { data = JSON.parse(data) }
+ catch (ex) { data = null }
+ get_(uri, timeout, cache, stat, data, nofollow, staleOk, cb)
+ })
+ else get_(uri, timeout, cache, null, null, nofollow, staleOk, cb)
+ })
+}
+
+function requestAll (cb) {
+ var cache = path.join(npm.cache, "/-/all", ".cache.json")
+
+ mkdir(path.join(npm.cache, "-", "all"), function (er) {
+ fs.readFile(cache, function (er, data) {
+ if (er) return requestAll_(0, {}, cb)
+ try {
+ data = JSON.parse(data)
+ } catch (ex) {
+ fs.writeFile(cache, "{}", function (er) {
+ if (er) return cb(new Error("Broken cache. "
+ +"Please run 'npm cache clean' "
+ +"and try again."))
+ return requestAll_(0, {}, cb)
+ })
+ }
+ var t = +data._updated || 0
+ requestAll_(t, data, cb)
+ })
+ })
+}
+
+function requestAll_ (c, data, cb) {
+ // use the cache and update in the background if it's not too old
+ if (Date.now() - c < 60000) {
+ cb(null, data)
+ cb = function () {}
+ }
+
+ var uri = "/-/all/since?stale=update_after&startkey=" + c
+
+ if (c === 0) {
+ log.warn("Building the index for the first time, please be patient")
+ uri = "/-/all"
+ }
+
+ var cache = path.join(npm.cache, "-/all", ".cache.json")
+ GET(uri, function (er, updates, _, res) {
+ if (er) return cb(er, data)
+ var headers = res.headers
+ , updated = Date.parse(headers.date)
+ Object.keys(updates).forEach(function (p) {
+ data[p] = updates[p]
+ })
+ data._updated = updated
+ fs.writeFile( cache, JSON.stringify(data)
+ , function (er) {
+ delete data._updated
+ return cb(er, data)
+ })
+ })
+}
+
+function get_ (uri, timeout, cache, stat, data, nofollow, staleOk, cb) {
+ var etag
+ if (data && data._etag) etag = data._etag
+ if (timeout && timeout > 0 && stat && data) {
+ if ((Date.now() - stat.mtime.getTime())/1000 < timeout) {
+ log.verbose("not expired, no request", "registry.get " +uri)
+ delete data._etag
+ return cb(null, data, JSON.stringify(data), {statusCode:304})
+ }
+ if (staleOk) {
+ log.verbose("staleOk, background update", "registry.get " +uri)
+ delete data._etag
+ process.nextTick(cb.bind( null, null, data, JSON.stringify(data)
+ , {statusCode: 304} ))
+ cb = function () {}
+ }
+ }
+
+ GET(uri, etag, nofollow, function (er, remoteData, raw, response) {
+ if (response) {
+ log.silly([response.statusCode, response.headers], "get cb")
+ if (response.statusCode === 304 && etag) {
+ remoteData = data
+ log.verbose(uri+" from cache", "etag")
+ }
+ }
+
+ data = remoteData
+ if (er) return cb(er, data, raw, response)
+
+ // just give the write the old college try. if it fails, whatever.
+ function saved () {
+ delete data._etag
+ cb(er, data, raw, response)
+ }
+
+ saveToCache(cache, data, saved)
+ })
+}
+
+function saveToCache (cache, data, saved) {
+ if (cacheStat) {
+ return saveToCache_(cache, data, cacheStat.uid, cacheStat.gid, saved)
+ }
+ fs.stat(npm.cache, function (er, st) {
+ if (er) {
+ return fs.stat(process.env.HOME || "", function (er, st) {
+ // if this fails, oh well.
+ if (er) return saved()
+ cacheStat = st
+ return saveToCache(cache, data, saved)
+ })
+ }
+ cacheStat = st || { uid: null, gid: null }
+ return saveToCache(cache, data, saved)
+ })
+}
+
+function saveToCache_ (cache, data, uid, gid, saved) {
+ mkdir(path.dirname(cache), npm.modes.exec, uid, gid, function (er) {
+ if (er) return saved()
+ fs.writeFile(cache, JSON.stringify(data), function (er) {
+ if (er || uid === null || gid === null) {
+ return saved()
+ }
+ fs.chown(cache, uid, gid, saved)
+ })
+ })
+}