diff options
author | Forrest L Norvell <forrest@npmjs.com> | 2014-04-29 04:43:54 +0400 |
---|---|---|
committer | Forrest L Norvell <forrest@npmjs.com> | 2014-05-08 04:37:11 +0400 |
commit | cc8dd4e63294443be8798bae881ef9ebb4b728c7 (patch) | |
tree | da0240d97eac85d6b8d61aac36732b6199c09a32 | |
parent | 0de64345a7ee94b60121ab9685d9468ab0146b3b (diff) |
split out cache locking into separate file
-rw-r--r-- | lib/cache.js | 111 | ||||
-rw-r--r-- | lib/cache/get-stat.js | 62 | ||||
-rw-r--r-- | lib/utils/locker.js | 54 | ||||
-rw-r--r-- | lib/utils/tar.js | 6 |
4 files changed, 131 insertions, 102 deletions
diff --git a/lib/cache.js b/lib/cache.js index 32fb9f832..88aff8038 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -1,3 +1,6 @@ +'use strict'; +/* jshint node: true */ + // XXX lib/utils/tar.js and this file need to be rewritten. // URL-to-cache folder mapping: @@ -54,8 +57,6 @@ exports = module.exports = cache cache.read = read cache.clean = clean cache.unpack = unpack -cache.lock = lock -cache.unlock = unlock var mkdir = require("mkdirp") , spawn = require("child_process").spawn @@ -76,7 +77,6 @@ var mkdir = require("mkdirp") , fileCompletion = require("./utils/completion/file-completion.js") , url = require("url") , chownr = require("chownr") - , lockFile = require("lockfile") , crypto = require("crypto") , retry = require("retry") , zlib = require("zlib") @@ -85,6 +85,10 @@ var mkdir = require("mkdirp") , isGitUrl = require("./utils/is-git-url.js") , pathIsInside = require("path-is-inside") , http = require("http") + , getCacheStat = require("./cache/get-stat.js") + , locker = require("./utils/locker.js") + , lock = locker.lock + , unlock = locker.unlock cache.usage = "npm cache add <tarball file>" + "\nnpm cache add <folder>" @@ -346,7 +350,7 @@ function fetchAndShaCheck (u, tmp, shasum, cb) { // validate that the url we just downloaded matches the expected shasum. sha.check(tmp, shasum, function (er) { - if (er != null && er.message) { + if (er && er.message) { // add original filename for better debuggability er.message = er.message + '\n' + 'From: ' + u } @@ -502,7 +506,7 @@ function checkGitDir (p, u, co, origUrl, silent, cb) { return cb(err) } exec(git, args, {cwd: p, env: env}, function (er, stdout, stderr) { - stdoutTrimmed = (stdout + "\n" + stderr).trim() + var stdoutTrimmed = (stdout + "\n" + stderr).trim() if (er || u !== stdout.trim()) { log.warn( "`git config --get remote.origin.url` returned " + "wrong result ("+u+")", stdoutTrimmed ) @@ -1041,59 +1045,6 @@ function addLocalTarball (p, name, version, shasum, cb_) { }) } -// to maintain the cache dir's permissions consistently. -var cacheStat = null -function getCacheStat (cb) { - if (cacheStat) return cb(null, cacheStat) - fs.stat(npm.cache, function (er, st) { - if (er) return makeCacheDir(cb) - if (!st.isDirectory()) { - log.error("getCacheStat", "invalid cache dir %j", npm.cache) - return cb(er) - } - return cb(null, cacheStat = st) - }) -} - -function makeCacheDir (cb) { - if (!process.getuid) return mkdir(npm.cache, cb) - - var uid = +process.getuid() - , gid = +process.getgid() - - if (uid === 0) { - if (process.env.SUDO_UID) uid = +process.env.SUDO_UID - if (process.env.SUDO_GID) gid = +process.env.SUDO_GID - } - if (uid !== 0 || !process.env.HOME) { - cacheStat = {uid: uid, gid: gid} - return mkdir(npm.cache, afterMkdir) - } - - fs.stat(process.env.HOME, function (er, st) { - if (er) { - log.error("makeCacheDir", "homeless?") - return cb(er) - } - cacheStat = st - log.silly("makeCacheDir", "cache dir uid, gid", [st.uid, st.gid]) - return mkdir(npm.cache, afterMkdir) - }) - - function afterMkdir (er, made) { - if (er || !cacheStat || isNaN(cacheStat.uid) || isNaN(cacheStat.gid)) { - return cb(er, cacheStat) - } - - if (!made) return cb(er, cacheStat) - - // ensure that the ownership is correct. - chownr(made, cacheStat.uid, cacheStat.gid, function (er) { - return cb(er, cacheStat) - }) - } -} - @@ -1307,10 +1258,11 @@ function addTmpTarball (tgz, name, version, shasum, cb) { tmp = true name = 'tmp_' + crypto.randomBytes(6).toString('hex') } + var pdir if (!tmp) { - var pdir = path.resolve(npm.cache, name, version, "package") + pdir = path.resolve(npm.cache, name, version, "package") } else { - var pdir = path.resolve(npm.cache, name + version + "package") + pdir = path.resolve(npm.cache, name + version + "package") } getCacheStat(function (er, cs) { @@ -1396,45 +1348,6 @@ function deprCheck (data) { } } -function lockFileName (u) { - var c = u.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "") - , h = crypto.createHash("sha1").update(u).digest("hex") - h = h.substr(0, 8) - c = c.substr(-32) - log.silly("lockFile", h + "-" + c, u) - return path.resolve(npm.config.get("cache"), h + "-" + c + ".lock") -} - -var myLocks = {} -function lock (u, cb) { - // the cache dir needs to exist already for this. - getCacheStat(function (er, cs) { - 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(u) - log.verbose("lock", u, lf) - lockFile.lock(lf, opts, function(er) { - if (!er) myLocks[lf] = true - cb(er) - }) - }) -} - -function unlock (u, cb) { - var lf = lockFileName(u) - , locked = myLocks[lf] - if (locked === false) { - return process.nextTick(cb) - } else if (locked === true) { - myLocks[lf] = false - lockFile.unlock(lockFileName(u), cb) - } else { - throw new Error("Attempt to unlock " + u + ", which hasn't been locked") - } -} - function needName(er, data) { return er ? er : (data && !data.name) ? new Error("No name provided") diff --git a/lib/cache/get-stat.js b/lib/cache/get-stat.js new file mode 100644 index 000000000..5e9709731 --- /dev/null +++ b/lib/cache/get-stat.js @@ -0,0 +1,62 @@ +'use strict'; +/* jshint node: true */ + +var fs = require("fs") + +var npm = require("../npm.js") +var log = require("npmlog") +var mkdir = require("mkdirp") +var chownr = require("chownr") + +function makeCacheDir (cb) { + if (!process.getuid) return mkdir(npm.cache, cb) + + var uid = +process.getuid() + , gid = +process.getgid() + + if (uid === 0) { + if (process.env.SUDO_UID) uid = +process.env.SUDO_UID + if (process.env.SUDO_GID) gid = +process.env.SUDO_GID + } + if (uid !== 0 || !process.env.HOME) { + cacheStat = {uid: uid, gid: gid} + return mkdir(npm.cache, afterMkdir) + } + + fs.stat(process.env.HOME, function (er, st) { + if (er) { + log.error("makeCacheDir", "homeless?") + return cb(er) + } + cacheStat = st + log.silly("makeCacheDir", "cache dir uid, gid", [st.uid, st.gid]) + return mkdir(npm.cache, afterMkdir) + }) + + function afterMkdir (er, made) { + if (er || !cacheStat || isNaN(cacheStat.uid) || isNaN(cacheStat.gid)) { + return cb(er, cacheStat) + } + + if (!made) return cb(er, cacheStat) + + // ensure that the ownership is correct. + chownr(made, cacheStat.uid, cacheStat.gid, function (er) { + return cb(er, cacheStat) + }) + } +} + +// to maintain the cache dir's permissions consistently. +var cacheStat = null +module.exports = function getCacheStat (cb) { + if (cacheStat) return cb(null, cacheStat) + fs.stat(npm.cache, function (er, st) { + if (er) return makeCacheDir(cb) + if (!st.isDirectory()) { + log.error("getCacheStat", "invalid cache dir %j", npm.cache) + return cb(er) + } + return cb(null, cacheStat = st) + }) +} diff --git a/lib/utils/locker.js b/lib/utils/locker.js new file mode 100644 index 000000000..e3c8f2e80 --- /dev/null +++ b/lib/utils/locker.js @@ -0,0 +1,54 @@ +'use strict'; +/* jshint node: true */ +var crypto = require("crypto") +var path = require("path") + +var npm = require("../npm.js") +var lockFile = require("lockfile") +var log = require("npmlog") +var getCacheStat = require("../cache/get-stat.js") + +function lockFileName (u) { + var c = u.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "") + , h = crypto.createHash("sha1").update(u).digest("hex") + h = h.substr(0, 8) + c = c.substr(-32) + log.silly("lockFile", h + "-" + c, u) + return path.resolve(npm.config.get("cache"), h + "-" + c + ".lock") +} + +var myLocks = {} +function lock (u, cb) { + // the cache dir needs to exist already for this. + getCacheStat(function (er, cs) { + 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(u) + log.verbose("lock", u, lf) + lockFile.lock(lf, opts, function(er) { + if (!er) myLocks[lf] = true + cb(er) + }) + }) +} + +function unlock (u, cb) { + var lf = lockFileName(u) + , locked = myLocks[lf] + if (locked === false) { + return process.nextTick(cb) + } else if (locked === true) { + myLocks[lf] = false + lockFile.unlock(lockFileName(u), cb) + } else { + throw new Error("Attempt to unlock " + u + ", which hasn't been locked") + } +} + +module.exports = { + lock: lock, + unlock: unlock, + _lockFileName: lockFileName +} diff --git a/lib/utils/tar.js b/lib/utils/tar.js index b73c134e4..3121bb028 100644 --- a/lib/utils/tar.js +++ b/lib/utils/tar.js @@ -8,7 +8,6 @@ var npm = require("../npm.js") , uidNumber = require("uid-number") , rm = require("./gently-rm.js") , readJson = require("read-package-json") - , cache = require("../cache.js") , myUid = process.getuid && process.getuid() , myGid = process.getgid && process.getgid() , tar = require("tar") @@ -16,13 +15,14 @@ var npm = require("../npm.js") , fstream = require("fstream") , Packer = require("fstream-npm") , lifecycle = require("./lifecycle.js") + , locker = require("./locker.js") function lock(path, cb) { - return cache.lock('tar://' + path, cb) + return locker.lock('tar://' + path, cb) } function unlock(path, cb) { - return cache.unlock('tar://' + path, cb) + return locker.unlock('tar://' + path, cb) } if (process.env.SUDO_UID && myUid === 0) { |