Comparing version 0.1.0 to 0.2.0-alpha
@@ -0,1 +1,2 @@ | ||
var path = require("path"); | ||
@@ -5,14 +6,30 @@ module.exports = function(grunt) { | ||
grunt.initConfig({ | ||
jshint : ['tasks/*.js'], | ||
jshint : ['tasks/**/*.js'], | ||
nodeunit: { | ||
all: ['test/upload.js', 'test/download.js'] | ||
all: ['test/upload.js', 'test/download.js', 'test/s3Task.js'] | ||
}, | ||
s3: { | ||
key: 'abc', | ||
secret: 'def', | ||
bucket: 'test', | ||
endpoint: '127.0.0.1', | ||
port: 1337, | ||
secure: false, | ||
access: 'public-read' | ||
options: { | ||
key: 'abc', | ||
secret: 'def', | ||
bucket: 'test', | ||
endpoint: '127.0.0.1', | ||
port: 1337, | ||
secure: false, | ||
access: 'public-read' | ||
}, | ||
test: { | ||
options: {} | ||
}, | ||
test_options: { | ||
options: { | ||
key: "custom" | ||
} | ||
}, | ||
test_S3Task: { | ||
upload: [{ | ||
src: path.join(process.cwd(), "test", "files", "**", "*.txt"), | ||
rel: path.join(process.cwd(), "test", "files") | ||
}] | ||
} | ||
} | ||
@@ -23,4 +40,4 @@ }); | ||
grunt.loadNpmTasks('grunt-contrib-nodeunit'); | ||
grunt.registerTask('test', ['nodeunit']); | ||
grunt.registerTask('test', ['jshint', 'nodeunit']); | ||
grunt.loadTasks(__dirname + '/tasks'); | ||
}; |
{ | ||
"name": "grunt-s3", | ||
"description": "A grunt task to automate moving files to/from Amazon S3.", | ||
"version": "0.1.0", | ||
"version": "0.2.0-alpha", | ||
"author": "Aaron Forsander (https://github.com/pifantastic)", | ||
@@ -20,3 +20,3 @@ "homepage": "https://github.com/pifantastic/grunt-s3", | ||
], | ||
"main": "Gruntfile.js", | ||
"main": "tasks/s3", | ||
"bin": "bin/grunt-s3", | ||
@@ -37,3 +37,3 @@ "scripts": { | ||
"underscore.deferred": "~0.1.4", | ||
"knox": "0.4.1", | ||
"knox": "0.6.x", | ||
"mime": "~1.2.5" | ||
@@ -40,0 +40,0 @@ }, |
109
README.md
[![Build Status](https://secure.travis-ci.org/pifantastic/grunt-s3.png?branch=master)](https://travis-ci.org/pifantastic/grunt-s3) | ||
*NOTE*: This is the README for `grunt-s3` `v0.2.0-alpha`. For `v0.1.0`, [go here](https://github.com/pifantastic/grunt-s3/blob/0.1.X/README.md). | ||
# Grunt 0.4.x + Amazon S3 | ||
@@ -31,7 +33,12 @@ | ||
## Configuration | ||
## Options | ||
The grunt-s3 task is now a [multi-task](https://github.com/gruntjs/grunt/wiki/Creating-tasks); meaning you can specify different targets for this task to run as. | ||
The following are the default options available to each target. | ||
* **key** - (*string*) An Amazon S3 credentials key | ||
* **secret** - (*string*) An Amazon S3 credentials secret | ||
* **bucket** - (*string*) An Amazon S3 bucket | ||
* **region** - (*string*) An Amazon AWS region (see http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region) | ||
* **maxOperations** - (*number*) max number of concurrent transfers - if not specified or set to 0, will be unlimited. | ||
@@ -44,2 +51,3 @@ * **encodePaths** - (*boolean*) if set to true, will encode the uris of destinations to prevent 505 errors. Default: false | ||
* **gzip** - (*boolean*) If true, uploads will be gzip-encoded. | ||
* **gzipExclude** - (*array*) Define extensions of files you don't want to run gzip on, an array of strings ie: `['.jpg', '.jpeg', '.png']`. | ||
* **upload** - (*array*) An array of objects, each object representing a file upload and containing a `src` | ||
@@ -59,52 +67,61 @@ and a `dest`. Any of the above values may also be overriden. | ||
s3: { | ||
key: 'YOUR KEY', | ||
secret: 'YOUR SECRET', | ||
bucket: 'my-bucket', | ||
access: 'public-read', | ||
// Files to be uploaded. | ||
upload: [ | ||
{ | ||
src: 'important_document.txt', | ||
dest: 'documents/important.txt', | ||
gzip: true | ||
options: { | ||
key: 'YOUR KEY', | ||
secret: 'YOUR SECRET', | ||
bucket: 'my-bucket', | ||
access: 'public-read' | ||
}, | ||
dev: { | ||
// These options override the defaults | ||
options: { | ||
encodePaths: true, | ||
maxOperations: 20 | ||
}, | ||
{ | ||
src: 'passwords.txt', | ||
dest: 'documents/ignore.txt', | ||
// Files to be uploaded. | ||
upload: [ | ||
{ | ||
src: 'important_document.txt', | ||
dest: 'documents/important.txt', | ||
gzip: true | ||
}, | ||
{ | ||
src: 'passwords.txt', | ||
dest: 'documents/ignore.txt', | ||
// These values will override the above settings. | ||
bucket: 'some-specific-bucket', | ||
access: 'authenticated-read' | ||
}, | ||
{ | ||
// Wildcards are valid *for uploads only* until I figure out a good implementation | ||
// for downloads. | ||
src: 'documents/*.txt', | ||
// These values will override the above settings. | ||
bucket: 'some-specific-bucket', | ||
access: 'authenticated-read' | ||
}, | ||
{ | ||
// Wildcards are valid *for uploads only* until I figure out a good implementation | ||
// for downloads. | ||
src: 'documents/*.txt', | ||
// But if you use wildcards, make sure your destination is a directory. | ||
dest: 'documents/' | ||
} | ||
], | ||
// But if you use wildcards, make sure your destination is a directory. | ||
dest: 'documents/' | ||
} | ||
], | ||
// Files to be downloaded. | ||
download: [ | ||
{ | ||
src: 'documents/important.txt', | ||
dest: 'important_document_download.txt' | ||
}, | ||
{ | ||
src: 'garbage/IGNORE.txt', | ||
dest: 'passwords_download.txt' | ||
} | ||
], | ||
// Files to be downloaded. | ||
download: [ | ||
{ | ||
src: 'documents/important.txt', | ||
dest: 'important_document_download.txt' | ||
}, | ||
{ | ||
src: 'garbage/IGNORE.txt', | ||
dest: 'passwords_download.txt' | ||
} | ||
], | ||
del: [ | ||
{ | ||
src: 'documents/launch_codes.txt' | ||
}, | ||
{ | ||
src: 'documents/backup_plan.txt' | ||
} | ||
] | ||
del: [ | ||
{ | ||
src: 'documents/launch_codes.txt' | ||
}, | ||
{ | ||
src: 'documents/backup_plan.txt' | ||
} | ||
] | ||
} | ||
} | ||
@@ -111,0 +128,0 @@ |
@@ -12,11 +12,2 @@ | ||
return crypto.createHash('md5').update(fs.readFileSync(path)).digest('hex'); | ||
} | ||
/** | ||
* Clone an object. | ||
* | ||
* @returns {Object} A clone of the original object. | ||
*/ | ||
exports.clone = function(obj) { | ||
return JSON.parse(JSON.stringify(obj || {})); | ||
} | ||
}; |
@@ -0,1 +1,3 @@ | ||
/*jshint esnext:true*/ | ||
/*globals module:true, require:true, process:true*/ | ||
@@ -64,31 +66,5 @@ /** | ||
return new Error(msg); | ||
} | ||
}; | ||
/** | ||
* Get the grunt s3 configuration options, filling in options from | ||
* environment variables if present. Also supports grunt template strings. | ||
* | ||
* @returns {Object} The s3 configuration. | ||
*/ | ||
var getConfig = exports.getConfig = function () { | ||
var config = grunt.config('s3') || {}; | ||
// Look for and process grunt template stings | ||
var keys = ['key', 'secret', 'bucket', 'maxOperations', 'encodePaths']; | ||
keys.forEach(function(key) { | ||
if (config.hasOwnProperty(key) && typeof config[key] == 'string') { | ||
config[key] = grunt.template.process(config[key]); | ||
} | ||
}); | ||
// Default to environment variables for s3 key/secret. | ||
return common.clone(_.defaults(config, { | ||
key : process.env.AWS_ACCESS_KEY_ID, | ||
secret : process.env.AWS_SECRET_ACCESS_KEY, | ||
maxOperations : 0, | ||
encodePaths : false | ||
})); | ||
} | ||
/** | ||
* Publishes the local file at src to the s3 dest. | ||
@@ -107,3 +83,3 @@ * | ||
var dfd = new _.Deferred(); | ||
var options = common.clone(opts); | ||
var options = _.clone(opts, true); | ||
@@ -115,3 +91,3 @@ // Make sure the local file exists. | ||
var config = _.defaults(options, getConfig()); | ||
var config = options; | ||
var headers = options.headers || {}; | ||
@@ -125,3 +101,3 @@ | ||
var client = knox.createClient(_(config).pick([ | ||
'endpoint', 'port', 'key', 'secret', 'access', 'bucket' | ||
'region', 'endpoint', 'port', 'key', 'secret', 'access', 'bucket', 'secure' | ||
])); | ||
@@ -135,3 +111,3 @@ | ||
// necesssary. | ||
function upload(cb) { | ||
var upload = function (cb) { | ||
cb = cb || function () {}; | ||
@@ -171,7 +147,14 @@ | ||
}); | ||
}; | ||
// prepare gzip exclude option | ||
var gzipExclude = options.gzipExclude || []; | ||
if (!_.isArray(gzipExclude)) { | ||
gzipExclude = []; | ||
} | ||
// If gzip is enabled, gzip the file into a temp file and then perform the | ||
// upload. | ||
if (options.gzip) { | ||
// If gzip is enabled and file not in gzip exclude array, | ||
// gzip the file into a temp file and then perform the upload. | ||
if (options.gzip && gzipExclude.indexOf(path.extname(src)) === -1) { | ||
headers['Content-Encoding'] = 'gzip'; | ||
@@ -245,8 +228,8 @@ headers['Content-Type'] = mime.lookup(src); | ||
var dfd = new _.Deferred(); | ||
var options = common.clone(opts); | ||
var config = _.defaults(options, getConfig()); | ||
var options = _.clone(opts); | ||
var config = options; | ||
// Pick out the configuration options we need for the client. | ||
var client = knox.createClient(_(config).pick([ | ||
'endpoint', 'port', 'key', 'secret', 'access', 'bucket' | ||
'region', 'endpoint', 'port', 'key', 'secret', 'access', 'bucket' | ||
])); | ||
@@ -319,3 +302,3 @@ | ||
var dfd = new _.Deferred(); | ||
var options = common.clone(opts); | ||
var options = _.clone(opts); | ||
var config = _.defaults(options, getConfig()); | ||
@@ -325,3 +308,3 @@ | ||
var client = knox.createClient(_(config).pick([ | ||
'endpoint', 'port', 'key', 'secret', 'access', 'bucket' | ||
'region', 'endpoint', 'port', 'key', 'secret', 'access', 'bucket' | ||
])); | ||
@@ -368,3 +351,3 @@ | ||
var dfd = new _.Deferred(); | ||
var options = common.clone(opts); | ||
var options = _.clone(opts); | ||
var config = _.defaults(options, getConfig()); | ||
@@ -374,3 +357,3 @@ | ||
var client = knox.createClient(_(config).pick([ | ||
'endpoint', 'port', 'key', 'secret', 'access', 'bucket' | ||
'region', 'endpoint', 'port', 'key', 'secret', 'access', 'bucket' | ||
])); | ||
@@ -377,0 +360,0 @@ |
103
tasks/s3.js
@@ -16,12 +16,15 @@ /*jshint esnext:true*/ | ||
const path = require('path'); | ||
const s3 = require('./lib/s3').init(grunt); | ||
var s3 = require('./lib/s3'); | ||
const S3Task = require('./lib/S3Task'); | ||
/** | ||
* Grunt aliases. | ||
*/ | ||
const _ = grunt.util._; | ||
const async = grunt.util.async; | ||
const log = grunt.log; | ||
// if grunt is not provided, then expose internal API | ||
if ('object' !== typeof(grunt)) { | ||
return { | ||
s3: s3, | ||
S3Task: S3Task | ||
}; | ||
} | ||
s3 = s3.init(grunt); | ||
/** | ||
@@ -32,85 +35,7 @@ * Transfer files to/from s3. | ||
*/ | ||
grunt.registerTask('s3', 'Publishes files to s3.', function () { | ||
var done = this.async(); | ||
var config = _.defaults(s3.getConfig(), { | ||
upload: [], | ||
download: [], | ||
del: [], | ||
copy: [] | ||
}); | ||
grunt.registerMultiTask('s3', 'Publishes files to s3.', function () { | ||
var task = new S3Task(this, s3); | ||
var transfers = []; | ||
if (config.debug) { | ||
log.writeln("Running in debug mode, no transfers will be made".yellow); | ||
log.writeln(); | ||
} | ||
config.upload.forEach(function(upload) { | ||
// Expand list of files to upload. | ||
var files = grunt.file.expand({ filter: "isFile" }, upload.src), | ||
destPath = grunt.template.process(upload.dest); | ||
files.forEach(function(file) { | ||
file = path.resolve(file); | ||
upload.src = path.resolve(grunt.template.process(upload.src)); | ||
// If there is only 1 file and it matches the original file wildcard, | ||
// we know this is a single file transfer. Otherwise, we need to build | ||
// the destination. | ||
var dest; | ||
if (files.length === 1 && file === upload.src) { | ||
dest = destPath; | ||
} | ||
else { | ||
if (upload.rel) { | ||
dest = path.join(destPath, path.relative(grunt.file.expand({ filter: "isDirectory" }, upload.rel)[0], file)); | ||
} | ||
else { | ||
dest = path.join(destPath, path.basename(file)); | ||
} | ||
} | ||
if(config.encodePaths === true) dest = encodeURIComponent(dest) | ||
transfers.push(s3.upload.bind(s3,file, dest, upload)); | ||
}); | ||
}); | ||
config.download.forEach(function(download) { | ||
transfers.push(s3.download.bind(s3,download.src, download.dest, download)); | ||
}); | ||
config.del.forEach(function(del) { | ||
transfers.push(s3.del.bind(s3,del.src, del)); | ||
}); | ||
config.copy.forEach(function(copy) { | ||
transfers.push(s3.copy.bind(s3,copy.src, copy.dest, copy)); | ||
}); | ||
var errors = 0; | ||
var eachTransfer = config.maxOperations > 0 | ||
? async.forEachLimit.bind(async,transfers,config.maxOperations) | ||
: async.forEach.bind(async,transfers) | ||
eachTransfer(function(transferFn,completed){ | ||
var transfer = transferFn() | ||
transfer.done(function(msg) { | ||
log.ok(msg); | ||
completed() | ||
}) | ||
transfer.fail(function(msg) { | ||
log.error(msg); | ||
++errors; | ||
completed() | ||
}) | ||
},function(){ | ||
// we're all done. | ||
done(!errors); | ||
}) | ||
task.run(); | ||
}); | ||
}; |
@@ -6,2 +6,7 @@ | ||
var _ = grunt.util._; | ||
var s3Config = grunt.config("s3"), | ||
config = _.extend({}, s3Config.options, s3Config.test.options); | ||
module.exports = { | ||
@@ -14,3 +19,3 @@ testDownload : function (test) { | ||
s3.download('a.txt', dest) | ||
s3.download('a.txt', dest, config) | ||
.done(function () { | ||
@@ -30,3 +35,5 @@ test.ok(hashFile(src) === hashFile(dest), 'File downloaded successfully.'); | ||
s3.download('b.txt', dest, { debug: true }) | ||
var debugConfig = _.defaults({}, config, {debug: true}); | ||
s3.download('b.txt', dest, debugConfig) | ||
.done(function () { | ||
@@ -33,0 +40,0 @@ test.throws(function () { |
@@ -7,4 +7,8 @@ | ||
var _ = grunt.util._; | ||
var async = grunt.util.async; | ||
var s3Config = grunt.config("s3"), | ||
config = _.extend({}, s3Config.options, s3Config.test.options); | ||
module.exports = { | ||
@@ -19,3 +23,3 @@ testUpload : function (test) { | ||
s3.upload(src, 'a.txt') | ||
s3.upload(src, 'a.txt', config) | ||
.done(function () { | ||
@@ -50,3 +54,5 @@ test.ok(hashFile(src) === hashFile(dest), 'File uploaded successfully.'); | ||
s3.upload(src, 'b.txt', { headers : {'Content-Type' : '<3'} }) | ||
var headerConfig = _.defaults({}, config, { headers : {'Content-Type' : '<3'} }); | ||
s3.upload(src, 'b.txt', headerConfig) | ||
.always(function () { | ||
@@ -69,3 +75,5 @@ var meta = yaml.parse(grunt.file.read(dest)) | ||
s3.upload(src, "c.txt", { debug: true }) | ||
var debugConfig = _.defaults({}, config, { debug: true }); | ||
s3.upload(src, "c.txt", debugConfig) | ||
.always(function () { | ||
@@ -72,0 +80,0 @@ test.throws(function () { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
37248
19
729
263
0
10
+ Addeddebug@0.7.4(transitive)
+ Addedknox@0.6.0(transitive)
- Removedknox@0.4.1(transitive)
Updatedknox@0.6.x