Move Cache into DependencyGraph

Reviewed By: martinbigio

Differential Revision: D2758776

fb-gh-sync-id: 15fb232e00267698e386d5422cb70e2091dabcdd
This commit is contained in:
Christoph Pojer 2015-12-18 16:13:25 -08:00 committed by facebook-github-bot-9
parent 3f81ea5844
commit 90d1b6ee62
10 changed files with 90 additions and 127 deletions

View File

@ -14,7 +14,7 @@ const path = require('path');
const Promise = require('promise');
const ProgressBar = require('progress');
const BundlesLayout = require('../BundlesLayout');
const Cache = require('../Cache');
const Cache = require('../DependencyResolver/Cache');
const Transformer = require('../JSTransformer');
const Resolver = require('../Resolver');
const Bundle = require('./Bundle');
@ -23,6 +23,7 @@ const Activity = require('../Activity');
const ModuleTransport = require('../lib/ModuleTransport');
const declareOpts = require('../lib/declareOpts');
const imageSize = require('image-size');
const version = require('../../../../package.json').version;
const sizeOf = Promise.denodeify(imageSize);
const readFile = Promise.denodeify(fs.readFile);
@ -88,11 +89,23 @@ class Bundler {
opts.projectRoots.forEach(verifyRootExists);
let mtime;
try {
({mtime} = fs.statSync(opts.transformModulePath));
mtime = String(mtime.getTime());
} catch (error) {
mtime = '';
}
this._cache = new Cache({
resetCache: opts.resetCache,
cacheVersion: opts.cacheVersion,
projectRoots: opts.projectRoots,
transformModulePath: opts.transformModulePath,
cacheKey: [
'react-packager-cache',
version,
opts.cacheVersion,
opts.projectRoots.join(',').split(path.sep).join('-'),
mtime
].join('$'),
});
this._resolver = new Resolver({
@ -365,7 +378,7 @@ class Bundler {
generateAssetModule(bundle, module, platform = null) {
const relPath = getPathRelativeToRoot(this._projectRoots, module.path);
var assetUrlPath = path.join('/assets', path.dirname(relPath));
// On Windows, change backslashes to slashes to get proper URL path from file path.
if (path.sep === '\\') {
assetUrlPath = assetUrlPath.replace(/\\/g, '/');

View File

@ -14,7 +14,7 @@ jest.dontMock('../index')
var Promise = require('promise');
var BundlesLayout = require('../index');
var Resolver = require('../../Resolver');
var loadCacheSync = require('../../lib/loadCacheSync');
var loadCacheSync = require('../../DependencyResolver/Cache/lib/loadCacheSync');
describe('BundlesLayout', () => {
function newBundlesLayout(options) {

View File

@ -10,7 +10,7 @@
jest
.autoMockOff()
.mock('../../Cache')
.mock('../../DependencyResolver/Cache')
.mock('../../Activity');
const Promise = require('promise');
@ -19,7 +19,7 @@ const path = require('path');
jest.mock('fs');
var BundlesLayout = require('../index');
var Cache = require('../../Cache');
var Cache = require('../../DependencyResolver/Cache');
var Resolver = require('../../Resolver');
var fs = require('fs');

View File

@ -13,10 +13,11 @@ const Activity = require('../Activity');
const _ = require('underscore');
const declareOpts = require('../lib/declareOpts');
const fs = require('fs');
const getCacheFilePath = require('../lib/getCacheFilePath');
const loadCacheSync = require('../lib/loadCacheSync');
const getCacheFilePath = require('../DependencyResolver/Cache/lib/getCacheFilePath');
const loadCacheSync = require('../DependencyResolver/Cache/lib/loadCacheSync');
const version = require('../../../../package.json').version;
const path = require('path');
const tmpdir = require('os').tmpDir();
const validateOpts = declareOpts({
dependencyResolver: {
@ -189,6 +190,7 @@ class BundlesLayout {
_getCacheFilePath(options) {
return getCacheFilePath(
tmpdir,
'react-packager-bundles-cache-',
version,
options.projectRoots.join(',').split(path.sep).join('-'),

View File

@ -9,38 +9,35 @@
'use strict';
jest
.dontMock('underscore')
.dontMock('absolute-path')
.dontMock('../')
.dontMock('../../lib/loadCacheSync')
.dontMock('../../lib/getCacheFilePath');
.dontMock('../lib/loadCacheSync')
.dontMock('../lib/getCacheFilePath');
jest
.mock('fs')
.setMock('os', {
tmpDir() { return 'tmpDir'; }
tmpDir() { return 'tmpDir'; },
});
var Promise = require('promise');
var fs = require('fs');
var _ = require('underscore');
var Cache = require('../');
describe('JSTransformer Cache', () => {
describe('Cache', () => {
describe('getting/setting', () => {
pit('calls loader callback for uncached file', () => {
fs.stat.mockImpl((file, callback) => {
callback(null, {
mtime: {
getTime: () => {}
}
getTime: () => {},
},
});
});
var cache = new Cache({
projectRoots: ['/rootDir'],
transformModulePath: 'x.js',
cacheKey: 'cache',
});
var loaderCb = jest.genMockFn().mockImpl(() => Promise.resolve());
@ -55,14 +52,13 @@ describe('JSTransformer Cache', () => {
fs.stat.mockImpl((file, callback) => {
callback(null, {
mtime: {
getTime: () => {}
}
getTime: () => {},
},
});
});
var cache = new Cache({
projectRoots: ['/rootDir'],
transformModulePath: 'x.js',
cacheKey: 'cache',
});
var index = 0;
var loaderCb = jest.genMockFn().mockImpl(() =>
@ -83,14 +79,13 @@ describe('JSTransformer Cache', () => {
fs.stat.mockImpl((file, callback) =>
callback(null, {
mtime: {
getTime: () => {}
}
getTime: () => {},
},
})
);
var cache = new Cache({
projectRoots: ['/rootDir'],
transformModulePath: 'x.js',
cacheKey: 'cache',
});
var loaderCb = jest.genMockFn().mockImpl(() =>
Promise.resolve('lol')
@ -105,14 +100,13 @@ describe('JSTransformer Cache', () => {
fs.stat.mockImpl((file, callback) => {
callback(null, {
mtime: {
getTime: () => {}
}
getTime: () => {},
},
});
});
var cache = new Cache({
projectRoots: ['/rootDir'],
transformModulePath: 'x.js',
cacheKey: 'cache',
});
var loaderCb = jest.genMockFn().mockImpl(() =>
Promise.resolve('lol')
@ -135,14 +129,13 @@ describe('JSTransformer Cache', () => {
fs.stat.mockImpl((file, callback) => {
callback(null, {
mtime: {
getTime: () => mtime++
}
getTime: () => mtime++,
},
});
});
var cache = new Cache({
projectRoots: ['/rootDir'],
transformModulePath: 'x.js',
cacheKey: 'cache',
});
var loaderCb = jest.genMockFn().mockImpl(() =>
Promise.resolve('lol' + mtime)
@ -167,14 +160,14 @@ describe('JSTransformer Cache', () => {
fileStats = {
'/rootDir/someFile': {
mtime: {
getTime: () => 22
}
getTime: () => 22,
},
},
'/rootDir/foo': {
mtime: {
getTime: () => 11
}
}
getTime: () => 11,
},
},
};
fs.existsSync.mockImpl(() => true);
@ -189,14 +182,13 @@ describe('JSTransformer Cache', () => {
'/rootDir/foo': {
metadata: {mtime: 11},
data: {field: 'lol wat'},
}
},
}));
});
pit('should load cache from disk', () => {
var cache = new Cache({
projectRoots: ['/rootDir'],
transformModulePath: 'x.js',
cacheKey: 'cache',
});
var loaderCb = jest.genMockFn();
@ -219,16 +211,15 @@ describe('JSTransformer Cache', () => {
fs.stat.mockImpl((file, callback) =>
callback(null, {
mtime: {
getTime: () => {}
}
getTime: () => {},
},
})
);
fileStats['/rootDir/foo'].mtime.getTime = () => 123;
var cache = new Cache({
projectRoots: ['/rootDir'],
transformModulePath: 'x.js',
cacheKey: 'cache',
});
var loaderCb = jest.genMockFn().mockImpl(() =>
Promise.resolve('new value')
@ -254,26 +245,17 @@ describe('JSTransformer Cache', () => {
it('should write cache to disk', () => {
var index = 0;
var mtimes = [10, 20, 30];
var debounceIndex = 0;
_.debounce = callback => {
return () => {
if (++debounceIndex === 3) {
callback();
}
};
};
fs.stat.mockImpl((file, callback) =>
callback(null, {
mtime: {
getTime: () => mtimes[index++]
}
getTime: () => mtimes[index++],
},
})
);
var cache = new Cache({
projectRoots: ['/rootDir'],
transformModulePath: 'x.js',
cacheKey: 'cache',
});
cache.get('/rootDir/bar', 'field', () =>
@ -286,7 +268,10 @@ describe('JSTransformer Cache', () => {
Promise.resolve('baz value')
);
jest.runAllTicks();
// jest has some trouble with promises and timeouts within promises :(
jest.runAllTimers();
jest.runAllTimers();
expect(fs.writeFile).toBeCalled();
});
});

View File

@ -9,50 +9,37 @@
'use strict';
const Promise = require('promise');
const _ = require('underscore');
const declareOpts = require('../lib/declareOpts');
const fs = require('fs');
const getCacheFilePath = require('../lib/getCacheFilePath');
const getCacheFilePath = require('./lib/getCacheFilePath');
const isAbsolutePath = require('absolute-path');
const loadCacheSync = require('../lib/loadCacheSync');
const path = require('path');
const version = require('../../../../package.json').version;
const loadCacheSync = require('./lib/loadCacheSync');
const tmpdir = require('os').tmpDir();
const validateOpts = declareOpts({
resetCache: {
type: 'boolean',
default: false,
},
cacheVersion: {
type: 'string',
default: '1.0',
},
projectRoots: {
type: 'array',
required: true,
},
transformModulePath: {
type:'string',
required: true,
},
});
function getObjectValues(object) {
return Object.keys(object).map(key => object[key]);
}
function debounce(fn, delay) {
var timeout;
return () => {
clearTimeout(timeout);
timeout = setTimeout(fn, delay);
};
}
// TODO: move to Packager directory
class Cache {
constructor(options) {
var opts = validateOpts(options);
this._cacheFilePath = this._getCacheFilePath(opts);
var data;
if (!opts.resetCache) {
data = this._loadCacheSync(this._cacheFilePath);
constructor({
resetCache,
cacheKey,
}) {
this._cacheFilePath = getCacheFilePath(tmpdir, cacheKey);
if (!resetCache) {
this._data = this._loadCacheSync(this._cacheFilePath);
} else {
data = Object.create(null);
this._data = Object.create(null);
}
this._data = data;
this._persistEventually = _.debounce(
this._persistEventually = debounce(
this._persistCache.bind(this),
2000,
);
@ -124,10 +111,10 @@ class Cache {
var data = this._data;
var cacheFilepath = this._cacheFilePath;
var allPromises = _.values(data)
var allPromises = getObjectValues(data)
.map(record => {
var fieldNames = Object.keys(record.data);
var fieldValues = _.values(record.data);
var fieldValues = getObjectValues(record.data);
return Promise
.all(fieldValues)
@ -187,25 +174,6 @@ class Cache {
return ret;
}
_getCacheFilePath(options) {
let mtime;
try {
({mtime} = fs.statSync(options.transformModulePath));
mtime = String(mtime.getTime());
} catch (error) {
mtime = '';
}
return getCacheFilePath(
'react-packager-cache-',
version,
options.projectRoots.join(',').split(path.sep).join('-'),
options.cacheVersion || '0',
options.transformModulePath,
mtime
);
}
}
module.exports = Cache;

View File

@ -10,16 +10,11 @@
const crypto = require('crypto');
const path = require('path');
const tmpdir = require('os').tmpDir();
function getCacheFilePath(...args) {
args = Array.prototype.slice.call(args);
const prefix = args.shift();
let hash = crypto.createHash('md5');
function getCacheFilePath(tmpdir, ...args) {
const hash = crypto.createHash('md5');
args.forEach(arg => hash.update(arg));
return path.join(tmpdir, prefix + hash.digest('hex'));
return path.join(tmpdir, hash.digest('hex'));
}
module.exports = getCacheFilePath;

View File

@ -14,7 +14,7 @@ jest
jest.mock('fs');
var Cache = require('../../Cache');
var Cache = require('../../DependencyResolver/Cache');
var Transformer = require('../');
var fs = require('fs');