Skip to content

Commit

Permalink
Refactor task like other contrib tasks. Fix gzip. Fixes GH-26.
Browse files Browse the repository at this point in the history
  • Loading branch information
shama committed Mar 13, 2013
1 parent fc5ee9c commit c1c21e5
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 197 deletions.
23 changes: 13 additions & 10 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,35 +38,38 @@ module.exports = function(grunt) {

// Configuration to be run (and then tested).
compress: {
mainZip: {
zip: {
options: {
archive: 'tmp/compress_test_files.zip'
},
files: [
{expand: true, cwd: 'test/fixtures', src: ['*']}
{expand: true, cwd: 'test/fixtures/', src: ['**/*']}
]
},
mainTar: {
tar: {
options: {
archive: 'tmp/compress_test_files.tar'
},
files: [
{expand: true, cwd: 'test/fixtures', src: ['*']}
{expand: true, cwd: 'test/fixtures', src: ['**/*']}
]
},
mainTarGz: {
tgz: {
options: {
archive: 'tmp/compress_test_files.tgz'
},
files: [
{expand: true, cwd: 'test/fixtures', src: ['*']}
{expand: true, cwd: 'test/fixtures', src: ['**/*']}
]
},
mainGz: {
gzip: {
expand: true,
cwd: 'test/fixtures/',
src: ['**/*.{css,html,js}'],
dest: 'tmp/gzip/',
options: {
archive: 'tmp/compress_test_file.js.gz'
},
src: ['test/fixtures/test.js']
mode: 'gzip'
}
}
},

Expand Down
169 changes: 12 additions & 157 deletions tasks/compress.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,178 +2,33 @@
* grunt-contrib-compress
* http://gruntjs.com/
*
* Copyright (c) 2012 Chris Talkington, contributors
* Copyright (c) 2013 Chris Talkington, contributors
* Licensed under the MIT license.
*/

'use strict';

module.exports = function(grunt) {
var fs = require('fs');
var path = require('path');
var prettySize = require('prettysize');
var compress = require('./lib/compress')(grunt);

grunt.registerMultiTask('compress', 'Compress files.', function() {
var archiver = require('archiver');
var zlib = require('zlib');

var kindOf = grunt.util.kindOf;

var done = this.async();

var options = this.options({
compress.options = this.options({
archive: null,
mode: null,
level: 1
level: 1,
});

var pretty = function(size) {
if (!options.pretty) {
return size + ' bytes';
}
return prettySize(size);
};

var archiverOptions = options;

var supportedModes = ['zip', 'tar', 'tgz', 'gzip'];

var shouldGzipTar = false;

grunt.verbose.writeflags(options, 'Options');

if (kindOf(options.archive) !== 'string' || options.archive.length === 0) {
grunt.fail.warn('Unable to compress; no valid archive file was specified.');
}

var archiveFile = options.archive;
var archiveDir = path.dirname(archiveFile);

var mode = options.mode || autoDetectMode(archiveFile);

if (mode === 'tgz') {
shouldGzipTar = true;
mode = 'tar';
}

if (grunt.util._.include(supportedModes, mode) === false) {
grunt.fail.warn('Mode ' + mode.cyan + ' not supported.');
}
compress.options.mode = compress.options.mode || compress.autoDetectMode(compress.options.archive);
grunt.verbose.writeflags(compress.options, 'Options');

if (this.filesSrc.length === 0) {
grunt.fail.warn('Unable to compress; no valid source files were found.');
if (grunt.util._.include(['zip', 'tar', 'tgz', 'gzip'], compress.options.mode) === false) {
grunt.fail.warn('Mode ' + String(compress.options.mode).cyan + ' not supported.');
}

if (grunt.file.exists(archiveDir) === false) {
grunt.file.mkdir(archiveDir);
}

var archiveStream = fs.createWriteStream(archiveFile);

var internalFileName;
var srcFile;

var filePairSrc;
var isExpandedPair;

var archive;

if (mode === 'gzip') {
// this needs to be evaluated as it doesn't fit new flow
var srcFiles = this.filesSrc;

srcFiles = srcFiles.filter(function(src) {
return grunt.file.isFile(src);
});

if (srcFiles.length > 1) {
grunt.fail.warn('Cannot specify multiple input files for gzip compression.');
}

var srcStream = fs.createReadStream(srcFiles[0]);

srcStream.pipe(zlib.createGzip()).pipe(archiveStream);

archiveStream.on('close', function() {
grunt.log.writeln('File ' + archiveFile.cyan + ' created (' + pretty(getSize(archiveFile)) + ').');
done();
});
} else if (mode === 'tar' || mode === 'zip') {
archive = archiver.create(mode, archiverOptions);

if (shouldGzipTar) {
archive.pipe(zlib.createGzip()).pipe(archiveStream);
} else {
archive.pipe(archiveStream);
}

archive.on('error', function(err) {
grunt.log.error(err);
grunt.fail.warn('archiver failed');
});

grunt.util.async.forEachSeries(this.files, function(filePair, nextPair) {
isExpandedPair = filePair.orig.expand || false;
filePairSrc = filePair.src;

filePairSrc = filePairSrc.filter(function(src) {
return grunt.file.isFile(src);
});

grunt.util.async.forEachSeries(filePairSrc, function(srcFile, nextFile) {
internalFileName = (isExpandedPair) ? filePair.dest : unixifyPath(path.join(filePair.dest || '', srcFile));

archive.addFile(fs.createReadStream(srcFile), { name: internalFileName }, function(err) {
grunt.verbose.writeln('Archiving ' + srcFile.cyan + ' -> ' + archiveFile.cyan + '/'.cyan + internalFileName.cyan);
nextFile(err);
});
}, nextPair);
}, function(err) {
if (err) {
grunt.fail.warn(err);
}

archive.finalize(function(err, written) {
if (shouldGzipTar) {
grunt.log.writeln('Created ' + archiveFile.cyan + ' (' + pretty(getSize(archiveFile)) + ')');
} else {
grunt.log.writeln('Created ' + archiveFile.cyan + ' (' + pretty(written) + ')');
}

done(err);
});
});

}
});

var getSize = function(filename) {
try {
return fs.statSync(filename).size;
} catch (e) {
return 0;
}
};

var autoDetectMode = function(dest) {
if (grunt.util._.endsWith(dest, '.tar.gz')) {
return 'tgz';
}

var ext = path.extname(dest).replace('.', '');

if (ext === 'gz') {
return 'gzip';
if (compress.options.mode === 'gzip') {
compress.gzip(this.files, this.async());
} else {
return ext;
compress.tar(this.files, this.async());
}
};

var unixifyPath = function(filepath) {
if (process.platform === 'win32') {
return filepath.replace(/\\/g, '/');
} else {
return filepath;
}
};
});
};
151 changes: 151 additions & 0 deletions tasks/lib/compress.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* grunt-contrib-compress
* http://gruntjs.com/
*
* Copyright (c) 2013 Chris Talkington, contributors
* Licensed under the MIT license.
*/

'use strict';

var fs = require('fs');
var path = require('path');
var prettySize = require('prettysize');
var zlib = require('zlib');
var archiver = require('archiver');

module.exports = function(grunt) {

var exports = {
options: {}
};

// 1 to 1 gziping of files
exports.gzip = function(files, done) {
grunt.util.async.forEachSeries(files, function(file, next) {
var src = file.src.filter(grunt.file.isFile).map(grunt.file.read).join('');
if (src.length < 1) { return; }

This comment has been minimized.

Copy link
@evanworley

evanworley Mar 14, 2013

You need a next() call here before returning or the iteration will be aborted.

This comment has been minimized.

Copy link
@shama

shama Mar 14, 2013

Author Member

Nice catch, fixed and published as 0.4.3. Thanks!

This comment has been minimized.

Copy link
@evanworley

evanworley Mar 14, 2013

Thanks! When will 0.4.3 be available at http://registry.npmjs.org/grunt-contrib-compress/? I'm still seeing 0.4.2

This comment has been minimized.

Copy link
@shama

shama Mar 14, 2013

Author Member

Sorry got held up, actually published now.

This comment has been minimized.

Copy link
@evanworley

evanworley Mar 14, 2013

Got it, thanks!


// Append ext if the specified one isnt there
var ext = file.orig.ext || '.gz';
if (String(file.dest).slice(-ext.length) !== ext) {
file.dest += ext;
}

// Ensure the dest folder exists
grunt.file.mkdir(path.dirname(file.dest));

var gz = zlib.createGzip();
gz.pipe(fs.createWriteStream(file.dest));
gz.write(src);
gz.end();
gz.on('end', function() {
grunt.log.writeln('File ' + String(file.dest).cyan + ' created (' + exports.getSize(file.dest) + ').');
next();
});
}, done);
};

// Compress with tar, tgz and zip
exports.tar = function(files, done) {
if (typeof exports.options.archive !== 'string' || exports.options.archive.length === 0) {
grunt.fail.warn('Unable to compress; no valid archive file was specified.');
}

var mode = exports.options.mode;
var shouldGzip = false;
if (mode === 'tgz') {
shouldGzip = true;
mode = 'tar';
}

var archive = archiver.create(mode, exports.options);
var dest = exports.options.archive;

// Ensure dest folder exists
grunt.file.mkdir(path.dirname(dest));

archive.on('error', function(err) {
grunt.log.error(err);
grunt.fail.warn('Archiving failed.');
});

// Whether to gzip the tar before writing the file
if (shouldGzip) {
archive.pipe(zlib.createGzip()).pipe(fs.createWriteStream(dest));
} else {
archive.pipe(fs.createWriteStream(dest));
}

grunt.util.async.forEachSeries(files, function(file, next) {
var isExpandedPair = file.orig.expand || false;
var src = file.src.filter(grunt.file.isFile);

grunt.util.async.forEachSeries(src, function(srcFile, nextFile) {
var internalFileName = (isExpandedPair) ? file.dest : exports.unixifyPath(path.join(file.dest || '', srcFile));

archive.addFile(fs.createReadStream(srcFile), { name: internalFileName }, function(err) {
grunt.verbose.writeln('Archiving ' + srcFile.cyan + ' -> ' + String(dest).cyan + '/'.cyan + internalFileName.cyan);
nextFile(err);
});
}, next);
}, function(err) {
if (err) { grunt.fail.warn(err); }

archive.finalize(function(err, written) {
if (shouldGzip) {
grunt.log.writeln('Created ' + String(dest).cyan + ' (' + exports.getSize(dest) + ')');
} else {
grunt.log.writeln('Created ' + String(dest).cyan + ' (' + exports.getSize(Number(written)) + ')');
}
done();
});
});
};

exports.getSize = function(filename, pretty) {
var size = 0;
if (typeof filename === 'string') {
try {
size = fs.statSync(filename).size;
} catch (e) {}
} else {
size = filename;
}
if (pretty !== false) {
if (!exports.options.pretty) {
return size + ' bytes';
}
return prettySize(size);
}
return Number(size);
};

exports.autoDetectMode = function(dest) {
if (exports.options.mode) {
return exports.options.mode;
}
if (!dest) {
return 'gzip';
}
if (grunt.util._.endsWith(dest, '.tar.gz')) {
return 'tgz';
}
var ext = path.extname(dest).replace('.', '');
if (ext === 'gz') {
return 'gzip';
} else {
return ext;
}
};

exports.unixifyPath = function(filepath) {
if (process.platform === 'win32') {
return filepath.replace(/\\/g, '/');
} else {
return filepath;
}
};

return exports;
};
Loading

1 comment on commit c1c21e5

@tkellen
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<3

Please sign in to comment.