diff --git a/lib/loaders/logger.js b/lib/loaders/logger.js index ccef754df1..b542f32159 100644 --- a/lib/loaders/logger.js +++ b/lib/loaders/logger.js @@ -7,7 +7,8 @@ module.exports = function(callback){ levels: { create: 5, update: 5, - delete: 5 + delete: 5, + skip: 7 } }); @@ -17,7 +18,8 @@ module.exports = function(callback){ colors: { create: 'green', update: 'yellow', - delete: 'red' + delete: 'red', + skip: 'grey' } }); diff --git a/lib/plugins/console/generate.js b/lib/plugins/console/generate.js new file mode 100644 index 0000000000..a565681b57 --- /dev/null +++ b/lib/plugins/console/generate.js @@ -0,0 +1,141 @@ +var async = require('async'), + fs = require('graceful-fs'), + _ = require('lodash'), + pathFn = require('path'), + util = require('../../util'), + file = util.file2, + HexoError = require('../../error'); + +module.exports = function(args, callback){ + var watchOption = args.w || args.watch, + start = Date.now(), + cache = {}, + isLoaded = false; + + var counter = { + create: 0, + update: 0, + skip: 0 + }; + + var log = hexo.log, + config = hexo.config, + route = hexo.route, + publicDir = hexo.public_dir, + sourceDir = hexo.source_dir; + + var cleanPublic = function(callback){ + fs.exists(publicDir, function(exist){ + if (!exist) return callback(); + + var exclude = _.map(Object.keys(route.routes), function(i){ + return pathFn.normalize(i); + }); + + file.emptyDir(publicDir, {exclude: exclude}, function(err){ + if (err) return callback(HexoError.wrap(err, 'Public folder clear failed')); + + log.d('Public folder cleared.'); + callback(); + }); + }); + }; + + var emit = function(type, path){ + counter[type]++; + log.log(type, 'Public: %s', path); + + if (isLoaded && Object.keys(route.routes).length === counter.create + counter.update + counter.skip){ + var elapsed = (Date.now() - start) / 1000; + + /** + * Fired after generation done. + * + * @event generateAfter + * @for Hexo + */ + + hexo.emit('generateAfter'); + log.i('%d files generated in %ss', counter.create, elapsed.toFixed(3)); + + if (watchOption){ + log.i('Start watching. Press Ctrl+C to stop.'); + } else { + if (args.d || args.deploy){ + hexo.call('deploy', callback); + } else { + callback(); + } + } + } + }; + + var itemCallback = function(err){ + if (err){ + throw HexoError.wrap(err, 'File generate failed: ' + this.path); + } + + emit(this.type, this.path); + }; + + route.on('update', function(path, item){ + if (!item.modified){ + emit('skip', path); + return; + } + + item(function(err, result){ + if (err) throw HexoError.wrap(err, 'File render failed: ' + path); + if (typeof result === 'undefined') return; + + var dest = pathFn.join(publicDir, path); + + if (result.readable){ + file.copyFile(result.path, dest, itemCallback.bind({ + path: path, + type: 'create' + })); + } else { + if (cache[path] === result){ + emit('skip', path); + } else { + file.writeFile(dest, result, itemCallback.bind({ + path: path, + type: cache[path] ? 'update' : 'create' + })); + + cache[path] = result; + } + } + }); + }).on('remove', function(path){ + fs.unlink(pathFn.join(publicDir, path), function(){ + log.log('delete', 'Public: %s', path); + cleanPublic(); + }); + }); + + /** + * Fired before generation started. + * + * @event generateBefore + * @for Hexo + */ + + hexo.emit('generateBefore'); + + hexo.post.load({watch: watchOption}, function(err){ + if (err) return callback(err); + + var elapsed = (Date.now() - start) / 1000; + + isLoaded = true; + start = Date.now(); + + log.i('Files loaded in %ss', elapsed.toFixed(3)); + + cleanPublic(function(err){ + if (err) return callback(err); + }); + }); +}; \ No newline at end of file diff --git a/lib/plugins/console/generate/index.js b/lib/plugins/console/generate/index.js deleted file mode 100644 index 05b7247498..0000000000 --- a/lib/plugins/console/generate/index.js +++ /dev/null @@ -1,216 +0,0 @@ -var async = require('async'), - fs = require('graceful-fs'), - _ = require('lodash'), - pathFn = require('path'), - util = require('../../../util'), - file = util.file2, - Pool = util.pool, - HexoError = require('../../../error'); - -module.exports = function(args, callback){ - var watchOption = args.w || args.watch, - start = Date.now(), - cache = {}, - count = 0; - - var log = hexo.log, - config = hexo.config, - route = hexo.route, - publicDir = hexo.public_dir, - sourceDir = hexo.source_dir, - q; - - if (config.multi_thread){ - var workerPath = require.resolve('./worker'); - - if (config.multi_thread === true){ - q = new Pool(workerPath); - } else { - q = new Pool(workerPath, config.multi_thread); - } - } else { - q = async.queue(function(data, next){ - if (data.type === 'copy'){ - file.copyFile(data.src, data.dest, next); - } else { - file.writeFile(data.dest, data.content, next); - } - }, config.max_open_file); - } - - var pushCallback = function(err){ - var data = this.data, - path = data.dest.substring(publicDir.length); - - if (err){ - if (err.code === 'EMFILE'){ - q.push(item, pushCallback); - } else { - callback(HexoError.wrap(err, 'File generate failed: ' + path)); - } - - return; - } - - count++; - log.log('create', 'Public: %s', path); - }; - - /** - * Fired before generation started. - * - * @event generateBefore - * @for Hexo - */ - - hexo.emit('generateBefore'); - - hexo.post.load({watch: watchOption}, function(err){ - if (err) return callback(err); - - var list = route.routes, - keys = Object.keys(list), - finish = Date.now(), - elapsed = (finish - start) / 1000; - - log.i('Files loaded in %ss', elapsed.toFixed(3)); - - async.auto({ - // Check if the public folder exists - exist: function(next){ - fs.exists(publicDir, function(exist){ - next(null, exist); - }); - }, - // Clear the public folder - clear: ['exist', function(next, results){ - if (!results.exist){ - log.d('Public folder not exists. No need to clear public folder.'); - return next(); - } - - var exclude = _.map(keys, function(item){ - return pathFn.normalize(item); - }); - - file.emptyDir(publicDir, {exclude: exclude}, function(err){ - if (err) return callback(HexoError.wrap(err, 'Public folder clear failed')); - - log.d('Public folder cleared:', exclude.join(',')); - next(); - }); - }], - // Generate files - generate: ['exist', function(next, results){ - var exist = results.exist; - - start = Date.now(); - - async.eachSeries(keys, function(i, next){ - var item = list[i], - dest = pathFn.join(publicDir, i); - - async.waterfall([ - function(next){ - if (!exist || item.modified) return next(null, true); - - fs.exists(dest, function(exist){ - next(null, !exist); - }); - }, - function(push, next){ - if (!push) return next(); - - item(function(err, result){ - if (err) return callback(HexoError.wrap(err, 'Render failed: ' + i)); - if (typeof result === 'undefined') return next(); - - if (result.readable){ - q.push({ - type: 'copy', - src: result.path, - dest: dest - }, pushCallback); - } else { - cache[i] = result; - - q.push({ - type: 'normal', - dest: dest, - content: result - }, pushCallback); - } - - next(); - }); - } - ], next); - }, function(err){ - if (err) return next(err); - - q.drain = next; - }); - }] - }, function(err){ - if (err) return callback(err); - - var finish = Date.now(), - elapsed = (finish - start) / 1000; - - /** - * Fired after generation done. - * - * @event generateAfter - * @for Hexo - */ - - hexo.emit('generateAfter'); - log.i('%d files generated in %ss', count, elapsed.toFixed(3)); - - if (watchOption){ - q.drain = function(){}; - - route.on('update', function(path, fn){ - if (!fn.modified) return; - - var dest = pathFn.join(publicDir, path); - - route.get(path)(function(err, result){ - if (err) return log.e(HexoError.wrap(err, 'File render failed: ' + path)); - if (typeof result === 'undefined') return; - - if (result.readable){ - q.push({ - type: 'copy', - src: result.path, - dest: dest - }, pushCallback); - } else { - if (cache[path] === result) return; - - cache[path] = result; - - q.push({ - type: 'normal', - dest: dest, - content: result - }, pushCallback); - } - }); - }).on('remove', function(path){ - fs.unlink(pathFn.join(publicDir, path), function(){ - log.log('delete', 'Public: %s', path); - }); - }); - } else { - if (config.multi_thread) q.end(); - - if (args.d || args.deploy){ - hexo.call('deploy', callback); - } else { - callback(); - } - } - }); - }); -}; \ No newline at end of file diff --git a/lib/plugins/console/generate/worker.js b/lib/plugins/console/generate/worker.js deleted file mode 100644 index 36a01ba77f..0000000000 --- a/lib/plugins/console/generate/worker.js +++ /dev/null @@ -1,14 +0,0 @@ -var util = require('../../../util'), - file = util.file2; - -var next = function(err){ - process.send(err || null); -}; - -process.on('message', function(data){ - if (data.type === 'copy'){ - file.copyFile(data.src, data.dest, next); - } else { - file.writeFile(data.dest, data.content, next); - } -}); \ No newline at end of file