var path = require('path'); var crypto = require('crypto'); module.exports = { createFromFile: function (filePath, useChecksum){ var fname = path.basename(filePath); var dir = path.dirname(filePath); return this.create(fname, dir, useChecksum); } , create: function (cacheId, _path, useChecksum){ var fs = require('fs'); var flatCache = require('flat-cache'); var cache = _AN_Call_load('load', flatCache, cacheId, _path); var normalizedEntries = { } ; var removeNotFoundFiles = function removeNotFoundFiles(){ var cachedEntriescache.keys(); cachedEntries.forEach(function remover(fPath){ try { fs.statSync(fPath); } catch (err) { if (err.code === 'ENOENT') { cache.removeKey(fPath); } } } ); } ; removeNotFoundFiles(); return { cache: cache, getHash: function (buffer){ return crypto.createHash('md5').update(buffer).digest('hex'); } , hasFileChanged: function (file){ return this.getFileDescriptor(file).changed; } , analyzeFiles: function (files){ var me = this; files = files || [] ; var res = { changedFiles: [] , notFoundFiles: [] , notChangedFiles: [] } ; me.normalizeEntries(files).forEach(function (entry){ if (entry.changed) { res.changedFiles.push(entry.key); return ; } if (entry.notFound) { res.notFoundFiles.push(entry.key); return ; } res.notChangedFiles.push(entry.key); } ); return res; } , getFileDescriptor: function (file){ var fstat; try { fstat = fs.statSync(file); } catch (ex) { this.removeEntry(file); return { key: file, notFound: true , err: ex} ; } if (useChecksum) { return this._getFileDescriptorUsingChecksum(file); } return this._getFileDescriptorUsingMtimeAndSize(file, fstat); } , _getFileDescriptorUsingMtimeAndSize: function (file, fstat){ var meta = cache.getKey(file); var cacheExists = !!meta; var cSize = fstat.size; var cTime = fstat.mtime.getTime(); var isDifferentDate; var isDifferentSize; if (!meta) { meta = { size: cSize, mtime: cTime} ; } else { isDifferentDate = cTime !== meta.mtime; isDifferentSize = cSize !== meta.size; } var nEntry = (normalizedEntries[file] = { key: file, changed: !cacheExists || isDifferentDate || isDifferentSize, meta: meta} ); return nEntry; } , _getFileDescriptorUsingChecksum: function (file){ var meta = cache.getKey(file); var cacheExists = !!meta; var contentBuffer; try { contentBuffer = fs.readFileSync(file); } catch (ex) { contentBuffer = ''; } var isDifferent = true ; var hash = this.getHash(contentBuffer); if (!meta) { meta = { hash: hash} ; } else { isDifferent = hash !== _AN_Read_hash('hash', meta); } var nEntry = (normalizedEntries[file] = { key: file, changed: !cacheExists || isDifferent, meta: meta} ); return nEntry; } , getUpdatedFiles: function (files){ var me = this; files = files || [] ; return me.normalizeEntries(files).filter(function (entry){ return entry.changed; } ).map(function (entry){ return entry.key; } ); } , normalizeEntries: function (files){ files = files || [] ; var me = this; var nEntries = files.map(function (file){ return me.getFileDescriptor(file); } ); return nEntries; } , removeEntry: function (entryName){ delete normalizedEntries[entryName]; cache.removeKey(entryName); } , deleteCacheFile: function (){ cache.removeCacheFile(); } , destroy: function (){ normalizedEntries = { } ; cache.destroy(); } , _getMetaForFileUsingCheckSum: function (cacheEntry){ var contentBuffer = fs.readFileSync(cacheEntry.key); var hash = this.getHash(contentBuffer); var meta = _AN_Call_assign('assign', Object, cacheEntry.meta, { hash: hash} ); delete meta.size; delete meta.mtime; return meta; } , _getMetaForFileUsingMtimeAndSize: function (cacheEntry){ var stat = fs.statSync(cacheEntry.key); var meta = _AN_Call_assign('assign', Object, cacheEntry.meta, { size: stat.size, mtime: stat.mtime.getTime()} ); delete meta.hash; return meta; } , reconcile: function (noPrune){ removeNotFoundFiles(); noPrune = typeof noPrune === 'undefined'? true : noPrune; var entries = normalizedEntries; var keys = Object.keys(entries); if (_AN_Read_length('length', keys) === 0) { return ; } var me = this; keys.forEach(function (entryName){ var cacheEntry = entries[entryName]; try { var meta = useChecksum? me._getMetaForFileUsingCheckSum(cacheEntry): me._getMetaForFileUsingMtimeAndSize(cacheEntry); cache.setKey(entryName, meta); } catch (err) { if (err.code !== 'ENOENT') { throw err } } } ); cache.save(noPrune); } } ; } } ;