1var crypto = require('crypto') 2var resolve = require('path').resolve 3 4var lockfile = require('lockfile') 5var log = require('npmlog') 6 7var npm = require('../npm.js') 8var correctMkdir = require('../utils/correct-mkdir.js') 9 10var installLocks = {} 11 12function lockFileName (base, name) { 13 var c = name.replace(/[^a-zA-Z0-9]+/g, '-').replace(/^-+|-+$/g, '') 14 var p = resolve(base, name) 15 var h = crypto.createHash('sha1').update(p).digest('hex') 16 var l = resolve(npm.cache, '_locks') 17 18 return resolve(l, c.substr(0, 24) + '-' + h.substr(0, 16) + '.lock') 19} 20 21function lock (base, name, cb) { 22 var lockDir = resolve(npm.cache, '_locks') 23 correctMkdir(lockDir, function (er) { 24 if (er) return cb(er) 25 26 var opts = { 27 stale: npm.config.get('cache-lock-stale'), 28 retries: npm.config.get('cache-lock-retries'), 29 wait: npm.config.get('cache-lock-wait') 30 } 31 var lf = lockFileName(base, name) 32 lockfile.lock(lf, opts, function (er) { 33 if (er) log.warn('locking', lf, 'failed', er) 34 35 if (!er) { 36 log.verbose('lock', 'using', lf, 'for', resolve(base, name)) 37 installLocks[lf] = true 38 } 39 40 cb(er) 41 }) 42 }) 43} 44 45function unlock (base, name, cb) { 46 var lf = lockFileName(base, name) 47 var locked = installLocks[lf] 48 if (locked === false) { 49 return process.nextTick(cb) 50 } else if (locked === true) { 51 lockfile.unlock(lf, function (er) { 52 if (er) { 53 log.warn('unlocking', lf, 'failed', er) 54 } else { 55 installLocks[lf] = false 56 log.verbose('unlock', 'done using', lf, 'for', resolve(base, name)) 57 } 58 59 cb(er) 60 }) 61 } else { 62 var notLocked = new Error( 63 'Attempt to unlock ' + resolve(base, name) + ", which hasn't been locked" 64 ) 65 notLocked.code = 'ENOTLOCKED' 66 throw notLocked 67 } 68} 69 70module.exports = { 71 lock: lock, 72 unlock: unlock 73} 74