From 47019946a4754e2e6e80102c3d791fb65c2205ec Mon Sep 17 00:00:00 2001 From: Evgeniy Gavryushin Date: Tue, 2 Sep 2014 18:29:22 +0400 Subject: [PATCH] Add configuration of archivers; refactor the code --- lib/config.js | 10 +++- lib/index.js | 154 ++++++++++++++++++++++++++++++++++++++++---------- lib/utils.js | 107 +++++++++++++++++++++++++++++------ package.json | 3 +- 4 files changed, 223 insertions(+), 51 deletions(-) diff --git a/lib/config.js b/lib/config.js index f752605..5efbc18 100644 --- a/lib/config.js +++ b/lib/config.js @@ -1,6 +1,7 @@ var path = require('path'), fs = require('fs'), - minimize = require('./utils').minimize; + minimize = require('./utils').minimize, + archive = require('./utils').archive; module.exports = { // each method is the imitation of the usage of some minimizer @@ -10,9 +11,14 @@ module.exports = { cssshrink: minimize(require('cssshrink'), 'shrink'), csswring: minimize(require('csswring'), 'wring') }, + // each method is the imitation of the usage of some archiver + archivers: { + gzip: archive('gzip -k [FILE_PATH] && mv [FILE_PATH].gz [TO_ARCH_CSS]', '.gz') + }, // input and output paths: { toRawCSS: path.join('css', 'raw'), - toMinCSS: path.join('css', 'min') + toMinCSS: path.join('css', 'min'), + toArchCSS: path.join('css', 'arch') } }; diff --git a/lib/index.js b/lib/index.js index 5dbfd31..d2f7b33 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,59 +1,153 @@ var fs = require('fs'), path = require('path'), + shell = require('shelljs'), bench = require('./config'), utils = require('./utils'), minimizers = bench.minimizers, + archivers = bench.archivers, toRawCSS = bench.paths.toRawCSS, - toMinCSS = bench.paths.toMinCSS; + toMinCSS = bench.paths.toMinCSS, + toArchCSS = bench.paths.toArchCSS; require('colors'); +shell.exec('ulimit -n 8192'); + // constants -var maxSize = Number.MAX_VALUE, - maxTime = Number.MAX_VALUE; +var MAX_TIME = Number.MAX_VALUE; -var listOfMinimizers = Object.keys(minimizers); +var listOfMinimizers = Object.keys(minimizers) || [], + listOfArchivers = Object.keys(archivers) || [], + listOfMinLen = listOfMinimizers.length, + listOfArchLen = listOfArchivers.length; // makes dirs -utils.mkdir(toMinCSS); -listOfMinimizers.forEach(function(minimizer) { +listOfMinimizers.forEach(function (minimizer) { utils.mkdir(path.join(toMinCSS, minimizer)); + listOfArchivers.forEach(function (archiver) { + utils.mkdir(path.join(toArchCSS, archiver, 'raw')); + utils.mkdir(path.join(toArchCSS, archiver, minimizer)); + }) }); // Ok! Let's GO! -var cssFiles = fs.readdirSync(toRawCSS); - -cssFiles.forEach(function(cssFile) { - var pathToFile = path.join(toRawCSS, cssFile); +var output = '\n' + 'Result:'.bold.green + '\n', + cssFiles = fs.readdirSync(toRawCSS); - // logs the test file - console.log( - '---> '.bold.green + cssFile + utils.addSpaces(cssFile, 40) + - ' --> ' + (fs.statSync(pathToFile).size + '').bold + ' b' - ); +cssFiles.forEach(function (cssFile) { + var pathToRawFile = path.join(toRawCSS, cssFile), + rawFileSize = fs.statSync(pathToRawFile).size; - // minimizes the file by different minimizers which are specified in 'config.js' + // minimizes and archives the file by tools which are specified in 'config.js' var res = {}; - listOfMinimizers.forEach(function(minimizer) { - res[minimizer] = minimizers[minimizer](pathToFile, path.join(toMinCSS, minimizer, cssFile)); + + if (listOfMinLen) { + res.min = {}; + } else { + console.log(utils.getCurrTime() + ' - ' + 'error'.red + ': [e] Spicify minimizers in \'lib/config.js\''); + process.exit(1); + } + listOfArchLen && (res.arch = {}); + + listOfMinimizers.forEach(function (minimizer) { + var pathToMinCSS = path.join(toMinCSS, minimizer, cssFile), + minimizeMethod = minimizers[minimizer]; + + res.min[minimizer] = minimizeMethod(minimizer, pathToRawFile, pathToMinCSS); + + listOfArchivers.forEach(function (archiver) { + var pathToArchCSS = path.join(toArchCSS, archiver), + pathToRawArchCSS = path.join(pathToArchCSS, 'raw'), + pathToMinArchCSS = path.join(pathToArchCSS, minimizer), + archiveScript = archivers[archiver]; + + if (!res.arch.hasOwnProperty(archiver)) { + res.arch[archiver] = {}; + } + if (!res.arch.hasOwnProperty('raw')) { + res.arch[archiver].raw = archiveScript(cssFile, pathToRawFile, pathToRawArchCSS); + } + res.arch[archiver][minimizer] = archiveScript(cssFile, pathToMinCSS, pathToMinArchCSS); + }); }); // gets the best and the fastest results - var minSize = maxSize, - minTime = maxTime; - listOfMinimizers.forEach(function(minimizer) { - minSize = Math.min(minSize, res[minimizer].size); - minTime = Math.min(minTime, res[minimizer].time); + var minSize = rawFileSize, + maxSize = rawFileSize, + minTime = MAX_TIME; + + listOfMinimizers.forEach(function (minimizer) { + var currMinSize = res.min[minimizer].size, + currMinTime = res.min[minimizer].time; + + minSize = Math.min(minSize, currMinSize); + maxSize = Math.max(maxSize, currMinSize); + minTime = Math.min(minTime, currMinTime); + }); + + var minArchSize = {}, + maxArchSize = {}; + + listOfArchivers.forEach(function (archiver) { + minArchSize[archiver] = res.arch[archiver].raw; + maxArchSize[archiver] = res.arch[archiver].raw; + listOfMinimizers.forEach(function (minimizer) { + var currArchSize = res.arch[archiver][minimizer]; + + minArchSize[archiver] = Math.min(minArchSize[archiver], currArchSize); + maxArchSize[archiver] = Math.max(maxArchSize[archiver], currArchSize); + }); }); + // logs the test file + var _output = + '\n---> '.bold.green + cssFile + utils.addSymbols(40, cssFile.length, ' ') + + ' --> ' + (rawFileSize + '').bold + ' b' + utils.addSymbols(listOfArchLen ? 22 - (rawFileSize + '').length : 2, 0, ' '), + + _outputLen = + ('\n---> ' + cssFile + utils.addSymbols(40, cssFile.length, ' ') + + ' --> ' + rawFileSize + ' b' + utils.addSymbols(listOfArchLen ? 22 - (rawFileSize + '').length : 2, 0, ' ')).length; + + listOfArchivers.forEach(function (archiver) { + var currArchSize = res.arch[archiver].raw; + + _output += + ' + ' + archiver + ' > ' + + (minArchSize[archiver] === currArchSize ? (currArchSize + '').green : currArchSize) + ' b' + + utils.addSymbols((maxArchSize[archiver] + '').length + 1, (currArchSize + '').length, ' ') + '|'; + + _outputLen += + (' + ' + archiver + ' > ' + currArchSize + ' b' + + utils.addSymbols((maxArchSize[archiver] + '').length + 1, (currArchSize + '').length, ' ') + '|').length; + }); + + _output += '\n' + utils.addSymbols(_outputLen - 1, 0, '-'); + + output += _output; + // logs the results of the test - listOfMinimizers.forEach(function(minimizer) { - console.log( - ' > was minimized by ' + minimizer + utils.addSpaces(minimizer, 20) + '--> ' + - (minSize === res[minimizer].size ? (res[minimizer].size + '').bold.green : res[minimizer].size) + ' b | ' + - (minTime === res[minimizer].time ? (res[minimizer].time + '').bold.green : res[minimizer].time) + ' ms' - ); + listOfMinimizers.forEach(function (minimizer) { + var currMinSize = res.min[minimizer].size, + currMinTime = res.min[minimizer].time; + + output += + '\n > was minimized by ' + minimizer + utils.addSymbols(20, minimizer.length, ' ') + '--> ' + + (minSize === currMinSize ? (currMinSize + '').bold.green : currMinSize) + ' b' + + utils.addSymbols((maxSize + '').length + 1, (currMinSize + '').length, ' ') + '| ' + + (minTime === currMinTime ? (currMinTime + '').bold.green : currMinTime) + ' ms' + + utils.addSymbols(19 - (rawFileSize + '').length, (currMinTime + ' ms').length, ' '); + + listOfArchivers.forEach(function (archiver) { + var currArchSize = res.arch[archiver][minimizer]; + + output += + ' + ' + archiver + ' > ' + + (minArchSize[archiver] === currArchSize ? (currArchSize + '').bold.green : currArchSize) + ' b' + + utils.addSymbols((maxArchSize[archiver] + '').length + 1, (currArchSize + '').length, ' ') + '|'; + }); }); - console.log() + output += '\n'; }); + +console.log(output + '\nDone!'.bold.green); diff --git a/lib/utils.js b/lib/utils.js index f68e681..f612164 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,36 +1,78 @@ -var fs = require('fs'); +var fs = require('fs'), + path = require('path'), + shell = require('shelljs'); + +require('colors'); + +/** + * Returns current time in an appropriate form + * @example 00:00:00.000 + */ +function getCurrTime() { + var now = new Date(), + _hours = now.getHours() + '', + _minutes = now.getMinutes() + '', + _seconds = now.getSeconds() + '', + _milliseconds = now.getMilliseconds() + '', + hours = (_hours.length < 2 ? '0' : '') + _hours, + minutes = (_minutes.length < 2 ? '0' : '') + _minutes, + seconds = (_seconds.length < 2 ? '0' : '') + _seconds, + milliSecLen = _milliseconds.length, + milliseconds = (milliSecLen < 3 ? (milliSecLen === 2 ? '0' : '00') : '') + _milliseconds; + + return (hours + ':' + minutes + ':' + seconds + '.' + milliseconds).grey; +} /** * Makes directories * @param {Array} - list of paths */ -function mkdir(path) { - try { - fs.mkdirSync(path); - } - catch(err) { - if (err && err.code !== 'EEXIST') throw err; - } +function mkdir(_path) { + var splitPath = _path.split(path.sep), + part = ''; + + splitPath.forEach(function (nextPart) { + part = path.join(part, nextPart) + try { + fs.mkdirSync(part); + } catch(err) { + if (err && err.code !== 'EEXIST') { + console.log(getCurrTime() + ' - ' + 'error'.red + ': [e] Can not create the folder --> ' + part); + throw err; + } + } + }); } /** * Adds spaces for pretty logging * @param {String} - string in the log * @param {Number} - interval - * @returns {String} - string of spaces + * @returns {String} */ -function addSpaces(name, interval) { - return new Array(interval - name.length).join(' '); +function addSymbols(interval, nameLen, symbol) { + return new Array(interval - nameLen + 1).join(symbol); } /** - * Returns a size of a minimized file and a time of a minimizer's work - * @param {Object} - required minimizer's module - * @param {String} - name of minimizer's method - * @returns {Object} + * Returns a function which can minimize CSS + * @param {Module} - a required module of a minimizer + * @param {String} - minimization method of a minimizer which receives CSS and minifies it + * @return {Function} */ function minimize(minimizer, minMethod) { - return function(inputFile, outputFile) { + /** + * Returns a size of a minimized file and time of a minimizer's work + * @param {Object} - required minimizer's module + * @param {String} - name of minimizer's method + * @returns {Object} + */ + return function (minimizerName, inputFile, outputFile) { + console.log( + getCurrTime() + ' - ' + 'info'.green + ': [m] Minimization by ' + minimizerName + ' --> ' + + (inputFile + ' -> ' + outputFile).grey + ); + var css = fs.readFileSync(inputFile, 'utf-8'), res = {}; @@ -46,8 +88,37 @@ function minimize(minimizer, minMethod) { }; } +/** + * Returns a function which can archive files + * @param {String} - bash scrit which archive files + * @param {String} - suffix which is added to archived file's name after archiving + * @return {Function} + */ +function archive(command, fileSuffix) { + /** + * Returns a size of an arhived file of an archiver's work + * @param {String} - file name + * @param {String} - file path + * @param {String} - path to archived CSS + * @returns {Number} + */ + return function (fileName, filePath, toArchCSS) { + var _command = command + .replace(/\[FILE_PATH\]/g, filePath) + .replace(/\[TO_ARCH_CSS\]/g, toArchCSS); + + console.log(getCurrTime() + ' - ' + 'info'.green + ': [a] ' + 'Exec bash script --> ' + _command.grey); + + shell.exec(_command); + + return fs.statSync(path.join(toArchCSS, fileName + fileSuffix)).size; + }; +} + module.exports = { + getCurrTime: getCurrTime, mkdir: mkdir, - addSpaces: addSpaces, - minimize: minimize + addSymbols: addSymbols, + minimize: minimize, + archive: archive } diff --git a/package.json b/package.json index 2a65ba1..e23fdce 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "csswring": "1.2.3" }, "devDependencies": { - "colors": "0.6.2" + "colors": "0.6.2", + "shelljs": "0.3.0" }, "engines": { "node": ">=0.8.0",