Skip to content

Commit 7ac7bed

Browse files
committed
Merge pull request #7 from lpetre/plugin_restructure
Large restructure of s3-index plugin
2 parents 2d51449 + 54ce6e6 commit 7ac7bed

File tree

2 files changed

+114
-167
lines changed

2 files changed

+114
-167
lines changed

index.js

Lines changed: 42 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
/* jshint node: true */
22
'use strict';
33
var path = require('path');
4-
var fs = require('fs');
54
var Promise = require('ember-cli/lib/ext/promise');
65
var DeployPluginBase = require('ember-cli-deploy-plugin');
76
var S3 = require('./lib/s3');
87

9-
var readFile = Promise.denodeify(fs.readFile);
10-
118
module.exports = {
129
name: 'ember-cli-deploy-s3-index',
1310

@@ -18,13 +15,10 @@ module.exports = {
1815
defaultConfig: {
1916
region: 'us-east-1',
2017
filePattern: 'index.html',
21-
currentRevisionIdentifier: "current.json",
18+
prefix: '',
2219
distDir: function(context) {
2320
return context.distDir;
2421
},
25-
keyPrefix: function(context) {
26-
return context.project.name() + ':index';
27-
},
2822
revisionKey: function(context) {
2923
var revisionKey = context.revisionData && context.revisionData.revisionKey;
3024
return context.commandOptions.revision || revisionKey;
@@ -36,88 +30,63 @@ module.exports = {
3630
requiredConfig: ['accessKeyId', 'secretAccessKey', 'bucket'],
3731

3832
upload: function(context) {
39-
var distDir = this.readConfig('distDir');
40-
var filePattern = this.readConfig('filePattern');
41-
var indexUploadKey = this._buildIndexUploadKey();
42-
var filePath = path.join(distDir, filePattern);
33+
var bucket = this.readConfig('bucket');
34+
var prefix = this.readConfig('prefix');
35+
var revisionKey = this.readConfig('revisionKey');
36+
var distDir = this.readConfig('distDir');
37+
var filePattern = this.readConfig('filePattern');
38+
var filePath = path.join(distDir, filePattern);
4339

44-
this.log('trying to upload index to S3! ' + indexUploadKey);
45-
var s3 = new S3({ plugin: this });
40+
var options = {
41+
bucket: bucket,
42+
prefix: prefix,
43+
filePattern: filePattern,
44+
filePath: filePath,
45+
revisionKey: revisionKey,
46+
};
4647

47-
return this._readFileContents(filePath)
48-
.then(s3.upload.bind(s3, indexUploadKey));
48+
this.log('preparing to upload revision to S3 bucket `' + bucket + '`');
49+
50+
var s3 = new S3({ plugin: this });
51+
return s3.upload(options);
4952
},
5053

5154
activate: function(context) {
55+
var bucket = this.readConfig('bucket');
56+
var prefix = this.readConfig('prefix');
5257
var revisionKey = this.readConfig('revisionKey');
53-
var keyPrefix = this.readConfig('keyPrefix');
58+
var filePattern = this.readConfig('filePattern');
5459

55-
if (revisionKey.indexOf(keyPrefix) === -1) {
56-
revisionKey = this._buildIndexUploadKey();
57-
}
60+
var options = {
61+
bucket: bucket,
62+
prefix: prefix,
63+
filePattern: filePattern,
64+
revisionKey: revisionKey,
65+
};
66+
67+
this.log('preparing to activate `' + revisionKey + '`');
5868

59-
return this._fetchRevisionsData()
60-
.then(this._createRevisionsList)
61-
.then(this._activateRevision.bind(this, revisionKey));
69+
var s3 = new S3({ plugin: this });
70+
return s3.activate(options);
6271
},
6372

6473
fetchRevisions: function(context) {
65-
return this._fetchRevisionsData();
66-
},
74+
var bucket = this.readConfig('bucket');
75+
var prefix = this.readConfig('prefix');
76+
var filePattern = this.readConfig('filePattern');
6777

68-
_fetchRevisionsData: function() {
69-
var s3 = new S3({ plugin: this })
78+
var options = {
79+
bucket: bucket,
80+
prefix: prefix,
81+
filePattern: filePattern,
82+
};
7083

71-
return s3.fetchRevisions()
84+
var s3 = new S3({ plugin: this });
85+
return s3.fetchRevisions(options)
7286
.then(function(revisions) {
73-
return { revisions: revisions };
74-
});
75-
},
76-
77-
_createRevisionsList: function(revisionsData) {
78-
var revisions = revisionsData.revisions;
79-
80-
return revisions.map(function(r) { return r.revision; });
81-
},
82-
83-
_activateRevision: function(revisionKey, availableRevisions) {
84-
this.log('Activating revision `' + revisionKey + '`');
85-
86-
if (availableRevisions.indexOf(revisionKey) > -1) {
87-
return this._overwriteCurrentIndex(revisionKey)
88-
.then(this._updateCurrentRevisionPointer.bind(this, revisionKey));
89-
} else {
90-
return Promise.reject("REVISION NOT FOUND!"); // see how we should handle a pipeline failure
91-
}
92-
},
93-
94-
_buildIndexUploadKey: function() {
95-
var keyPrefix = this.readConfig('keyPrefix');
96-
var revisionKey = this.readConfig('revisionKey');
97-
98-
return keyPrefix+':'+revisionKey;
99-
},
100-
101-
_readFileContents: function(path) {
102-
return readFile(path)
103-
.then(function(buffer) {
104-
return buffer.toString();
87+
context.revisions = revisions;
10588
});
10689
},
107-
108-
_updateCurrentRevisionPointer: function(newRevisionKey) {
109-
var s3 = new S3({ plugin: this })
110-
var currentRevisionIdentifier = this.readConfig('currentRevisionIdentifier');
111-
112-
return s3.upload(currentRevisionIdentifier, JSON.stringify({ revision: newRevisionKey }));
113-
},
114-
115-
_overwriteCurrentIndex: function(newRevisionKey) {
116-
var s3 = new S3({ plugin: this });
117-
var bucket = this.readConfig('bucket');
118-
119-
return s3.overwriteCurrentIndex(newRevisionKey, bucket);
120-
}
12190
});
12291

12392
return new DeployPlugin();

lib/s3.js

Lines changed: 72 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,107 @@
11
var AWS = require('aws-sdk');
22
var CoreObject = require('core-object');
33
var Promise = require('ember-cli/lib/ext/promise');
4+
var fs = require('fs');
5+
var path = require('path');
6+
var readFile = Promise.denodeify(fs.readFile);
7+
8+
var headObject = function(client, params) {
9+
return new Promise(function(resolve, reject) {
10+
client.headObject(params, function(err, data) {
11+
if (err && err.code === 'NotFound') {
12+
return resolve();
13+
}
14+
else if (err) {
15+
return reject(err);
16+
}
17+
else {
18+
return resolve(data);
19+
}
20+
});
21+
});
22+
}
423

524
module.exports = CoreObject.extend({
625
init: function(options) {
726
var plugin = options.plugin;
827
var config = plugin.pluginConfig;
9-
var readConfig = plugin.readConfig;
1028

11-
this._client = plugin.readConfig('s3Client') || new AWS.S3(config);
12-
this._bucket = plugin.readConfig('bucket');
13-
this._keyPrefix = plugin.readConfig('keyPrefix');
14-
this._filePattern = plugin.readConfig('filePattern');
15-
this._currentRevisionIdentifier = plugin.readConfig('currentRevisionIdentifier');
29+
this._plugin = plugin;
30+
this._client = plugin.readConfig('s3Client') || new AWS.S3(config);
1631
},
1732

18-
fetchRevisions: function() {
19-
return Promise.hash({
20-
revisions: this._getBucketContents(),
21-
current: this._getCurrentData()
22-
})
23-
.then(this._createRevisionDataFromList.bind(this));
24-
},
25-
26-
upload: function(key, fileContent) {
27-
var client = this._client;
33+
upload: function(options) {
34+
var client = this._client;
35+
var plugin = this._plugin;
36+
var bucket = options.bucket;
37+
var acl = options.acl || 'public-read';
38+
var key = path.join(options.prefix, options.filePattern + ":" + options.revisionKey);
39+
var putObject = Promise.denodeify(client.putObject.bind(client));
2840

2941
var params = {
30-
Bucket: this._bucket,
42+
Bucket: bucket,
3143
Key: key,
32-
Body: fileContent,
44+
ACL: acl,
3345
ContentType: 'text/html',
3446
CacheControl: 'max-age=0, no-cache'
3547
}
3648

37-
return new Promise(function(resolve, reject) {
38-
client.putObject(params, function(err, data) {
39-
if (err) {
40-
return reject(err);
41-
} else {
42-
return resolve(data);
43-
}
44-
});
49+
return readFile(options.filePath).then(function(fileContents) {
50+
params.Body = fileContents;
51+
return putObject(params).then(function() {
52+
plugin.log('✔ ' + key);
53+
})
4554
});
4655
},
4756

48-
overwriteCurrentIndex: function(newRevisionKey) {
49-
var client = this._client;
50-
var bucket = this._bucket;
51-
var copySource = encodeURIComponent(bucket+'/'+newRevisionKey);
57+
activate: function(options) {
58+
var plugin = this._plugin;
59+
var client = this._client;
60+
var bucket = options.bucket;
61+
var acl = options.acl || 'public-read';
62+
var revisionKey = path.join(options.prefix, options.filePattern + ":" + options.revisionKey);
63+
var indexKey = path.join(options.prefix, options.filePattern);
64+
var copySource = encodeURIComponent(path.join(bucket, revisionKey));
65+
var copyObject = Promise.denodeify(client.copyObject.bind(client));
5266

5367
var params = {
5468
Bucket: bucket,
5569
CopySource: copySource,
56-
Key: this._filePattern
70+
Key: indexKey,
71+
ACL: acl,
5772
};
5873

59-
return new Promise(function(resolve, reject) {
60-
client.copyObject(params, function(err, data) {
61-
if (err) {
62-
return reject(err);
63-
} else {
64-
return resolve(data);
65-
}
66-
});
67-
});
68-
},
69-
70-
_createRevisionDataFromList: function(data) {
71-
const revisionsData = this._sortBucketContents(data.revisions).Contents;
72-
const currentRevision = data.current;
73-
74-
return revisionsData.map(function(d) {
75-
var revision = d.Key;
76-
77-
return { revision: revision, active: revision === currentRevision };
74+
return this.fetchRevisions(options).then(function(revisions) {
75+
var found = revisions.map(function(element) { return element.revision; }).indexOf(options.revisionKey);
76+
if (found >= 0) {
77+
return copyObject(params).then(function() {
78+
plugin.log('✔ ' + revisionKey + " => " + indexKey);
79+
})
80+
} else {
81+
return Promise.reject("REVISION NOT FOUND!"); // see how we should handle a pipeline failure
82+
}
7883
});
7984
},
8085

81-
_sortBucketContents: function(data) {
82-
data.Contents = data.Contents.sort(function(a, b) {
83-
return new Date(b.LastModified) - new Date(a.LastModified);
84-
});
85-
return data;
86-
},
87-
88-
_getBucketContents: function() {
89-
var client = this._client;
90-
var keyPrefix = this._keyPrefix;
91-
var bucket = this._bucket;
86+
fetchRevisions: function(options) {
87+
var client = this._client;
88+
var bucket = options.bucket;
89+
var revisionPrefix = path.join(options.prefix, options.filePattern + ":");
90+
var indexKey = path.join(options.prefix, options.filePattern);
91+
var listObjects = Promise.denodeify(client.listObjects.bind(client));
9292

93-
return new Promise(function(resolve, reject) {
94-
var params = { Bucket: bucket, Prefix: keyPrefix };
95-
96-
client.listObjects(params, function(err, data) {
97-
if (err) {
98-
return reject(err);
99-
} else {
100-
return resolve(data);
101-
}
93+
return Promise.hash({
94+
revisions: listObjects({ Bucket: bucket, Prefix: revisionPrefix }),
95+
current: headObject(client, { Bucket: bucket, Key: indexKey }),
96+
})
97+
.then(function(data) {
98+
return data.revisions.Contents.sort(function(a, b) {
99+
return new Date(b.LastModified) - new Date(a.LastModified);
100+
}).map(function(d) {
101+
var revision = d.Key.substr(revisionPrefix.length);
102+
var active = data.current && d.ETag === data.current.ETag;
103+
return { revision: revision, timestamp: d.LastModified, active: active };
102104
});
103105
});
104106
},
105-
106-
_getCurrentData: function() {
107-
var client = this._client;
108-
var bucket = this._bucket;
109-
var currentRevisionIdentifier = this._currentRevisionIdentifier;
110-
111-
return new Promise(function(resolve, reject) {
112-
var params = { Bucket: bucket, Key: currentRevisionIdentifier };
113-
114-
client.getObject(params, function(err, data) {
115-
if (err && err.code === 'NoSuchKey') {
116-
return resolve();
117-
}
118-
else if (err) {
119-
return reject(err);
120-
}
121-
else {
122-
var json = JSON.parse(data.Body.toString('utf8'));
123-
124-
return resolve(json.revision);
125-
}
126-
});
127-
});
128-
}
129107
});

0 commit comments

Comments
 (0)