Merge pull request #1216 from benschwarz/master

Revert 1077, merge 1211
This commit is contained in:
Ben Schwarz
2014-04-07 10:53:39 +10:00
3 changed files with 40 additions and 74 deletions

View File

@@ -5,6 +5,7 @@ var Q = require('q');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var LRU = require('lru-cache');
var lockFile = require('lockfile');
var semver = require('../util/semver');
var readJson = require('../util/readJson');
var copy = require('../util/copy');
@@ -18,6 +19,9 @@ function ResolveCache(config) {
// - etc..
this._config = config;
this._dir = this._config.storage.packages;
this._lockDir = this._config.storage.packages;
mkdirp.sync(this._lockDir);
// Cache is stored/retrieved statically to ensure singularity
// among instances
@@ -97,6 +101,7 @@ ResolveCache.prototype.store = function (canonicalDir, pkgMeta) {
var sourceId;
var release;
var dir;
var pkgLock;
var promise;
var that = this;
@@ -107,57 +112,41 @@ ResolveCache.prototype.store = function (canonicalDir, pkgMeta) {
sourceId = md5(pkgMeta._source);
release = that._getPkgRelease(pkgMeta);
dir = path.join(that._dir, sourceId, release);
pkgLock = path.join(that._lockDir, sourceId + '-' + release + '.lock');
var checkExistingDirectory;
var key = 'moving:' + dir;
// Check if destination directory exists to prevent issuing lock at all times
return Q.nfcall(fs.stat, dir)
.fail(function (err) {
var lockParams = { wait: 250, retries: 25, stale: 60000 };
return Q.nfcall(lockFile.lock, pkgLock, lockParams).then(function () {
// Ensure other process didn't start copying files before lock was created
return Q.nfcall(fs.stat, dir)
.fail(function (err) {
// If stat fails, it is expected to return ENOENT
if (err.code !== 'ENOENT') {
throw err;
}
if (! that._cache.has(key)) {
// Check if directory exists
checkExistingDirectory = Q.nfcall(fs.stat, dir)
.then(function () {
// If it does exists, remove it
return Q.nfcall(rimraf, dir);
}, function (err) {
// If directory does not exists, ensure its basename
// is created
if (err.code === 'ENOENT') {
return Q.nfcall(mkdirp, path.dirname(dir));
}
// Create missing directory and copy files there
return Q.nfcall(mkdirp, path.dirname(dir)).then(function () {
return Q.nfcall(fs.rename, canonicalDir, dir)
.fail(function (err) {
// If error is EXDEV it means that we are trying to rename
// across different drives, so we copy and remove it instead
if (err.code !== 'EXDEV') {
throw err;
}
throw err;
});
}
else {
checkExistingDirectory = new Q();
}
return checkExistingDirectory
// Move the canonical to sourceId/target
.then(function () {
// We store the renaming in cache.
var promise;
if (that._cache.has(key)) {
promise = that._cache.get(key);
}
else {
promise = Q.nfcall(fs.rename, canonicalDir, dir);
that._cache.set(key, promise);
}
return promise
.fail(function (err) {
// If error is EXDEV it means that we are trying to rename
// across different drives, so we copy and remove it instead
if (err.code !== 'EXDEV') {
throw err;
}
return copy.copyDir(canonicalDir, dir);
})
// To match all case, we remove the directory.
.then(function () {
return Q.nfcall(rimraf, canonicalDir);
return copy.copyDir(canonicalDir, dir);
});
});
});
}).finally(function () {
lockFile.unlockSync(pkgLock);
});
}).finally(function () {
// Ensure no tmp dir is left on disk.
return Q.nfcall(rimraf, canonicalDir);
});
})
.then(function () {

View File

@@ -58,7 +58,8 @@
"p-throttler": "~0.0.1",
"insight": "~0.3.0",
"is-root": "~0.1.0",
"shell-quote": "~1.4.1"
"shell-quote": "~1.4.1",
"lockfile": "~0.4.2"
},
"devDependencies": {
"expect.js": "~0.2.0",

View File

@@ -138,30 +138,6 @@ describe('ResolveCache', function () {
.done();
});
it('should overwrite if the exact same package source/version exists', function (next) {
var cachePkgDir = path.join(cacheDir, md5('foo'), '1.0.0-rc.blehhh');
mkdirp.sync(cachePkgDir);
fs.writeFileSync(path.join(cachePkgDir, '_bleh'), 'w00t');
resolveCache.store(tempPackage, {
name: 'foo',
version: '1.0.0-rc.blehhh',
_source: 'foo',
_target: '*'
})
.then(function (dir) {
expect(dir).to.equal(cachePkgDir);
expect(fs.existsSync(dir)).to.be(true);
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
expect(fs.existsSync(tempPackage)).to.be(false);
expect(fs.existsSync(path.join(cachePkgDir, '_bleh'))).to.be(false);
next();
})
.done();
});
it('should read the package meta if not present', function (next) {
var pkgMeta = path.join(tempPackage, '.bower.json');
@@ -241,14 +217,14 @@ describe('ResolveCache', function () {
resolveCache.store(tempPackage, {
name: 'foo',
_source: 'foo',
_source: 'foobar',
_target: 'some-branch'
})
.then(function (dir) {
// Ensure mock was called
expect(hittedMock).to.be(true);
expect(dir).to.equal(path.join(cacheDir, md5('foo'), 'some-branch'));
expect(dir).to.equal(path.join(cacheDir, md5('foobar'), 'some-branch'));
expect(fs.existsSync(dir)).to.be(true);
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
expect(fs.existsSync(tempPackage)).to.be(false);