Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 78 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ class Assets {

this.config = Object.assign({}, {
auto: false,

// TODO: how to configure this level?
// Mode of processing targets:
// - 'parallel': targets are processed in parallel
// - 'sequence': targets are processed one by one
mode: 'parallel',
targets: [],
}, config);

Expand Down Expand Up @@ -66,17 +72,68 @@ class Assets {
}
}

/**
* Creates promise that resolves then all promises returned by
* promiseFactories resolve.
*
* @param {Array.<function(): Promise.<*>>} promiseFactories
* @return {Promise<Array.<*>>}
*/
promiseParallel(promiseFactories) {
return Promise.all(
promiseFactories.map(factory => Promise.resolve(factory()))
);
}

/**
* Creates promise that resolves when a promise returned by last elelement of
* `promiseFactories` gets settled. Each element of promiseFactories is called
* only after promise returned by previous settled.
*
* @param {Array.<function(): Promise.<*>>} promiseFactories
* @return {Promise<Array.<*>>}
*/
promiseSequence(promiseFactories) {
const sequence = Promise.resolve();

return promiseFactories.reduce((sequence, promiseFactory) => {
const next = () => promiseFactory();

return sequence
.then(next)
.catch(error => {
this.log(error);

return next();
});
}, sequence);
}

/**
* @param {string} mode
*/
getModeMethodName(mode) {
return mode === 'sequence' ?
'promiseSequence' :
'promiseParallel';
}

deployS3() {
let assetSets = this.config.targets;

// glob
return new Promise(resolve => {
assetSets.forEach(assets => {
const bucket = assets.bucket;
const prefix = assets.prefix || '';
assets.files.forEach(opt => {
this.log(`Bucket: ${bucket}:${prefix}`);
// Note: this.config.mode can't be expressed in config
// It would mean: process targets/assetSets in parallel or sequentially.
return this[this.getModeMethodName(this.config.mode)](assetSets.map(assets => {
const bucket = assets.bucket;
const prefix = assets.prefix || '';

return () => {
this.log(`Bucket: ${bucket}:${prefix}`);

// Note: assets.mode can be expressed in config by passing `mode` key
// next to `bucket`.
// It will mean: process file groups in parallel or sequentially
return this[this.getModeMethodName(assets.mode)](assets.files.map(opt => {
if(this.options.bucket && this.options.bucket !== bucket) {
this.log('Skipping');
return;
Expand All @@ -85,8 +142,11 @@ class Assets {
this.log(`Path: ${opt.source}`);

const cfg = Object.assign({}, globOpts, {cwd: opt.source});
glob.sync(opt.globs, cfg).forEach(filename => {

// Note: opt.mode can be expressed in config by passing `mode` key
// next to `source`/`globs`.
// It will mean: process files in group in parallel or sequentially
return () => this[this.getModeMethodName(opt.mode)](glob.sync(opt.globs, cfg).map(filename => {
const body = fs.readFileSync(path.join(opt.source, filename));
const type = mime.lookup(filename) || opt.defaultContentType || 'application/octet-stream';

Expand All @@ -100,12 +160,16 @@ class Assets {
ContentType: type
}, opt.headers || {});

this.provider.request('S3', 'putObject', details, this.options.stage, this.options.region);
});
});
});
resolve();
});
return () => this
.provider
.request('S3', 'putObject', details, this.options.stage, this.options.region)
.then(() => {
this.log(`\tDONE: ${ filename } (${type})`);
});
}, []));
}, []));
};
}, []));
}
}

Expand Down