@0x4447/potato
Version:
🥔 Upload a static page to AWS S3 while automatically configuring CloudFront.
277 lines (225 loc) • 5.94 kB
JavaScript
let fs = require('fs');
let read = require('fs-readdir-recursive')
let mime = require('mime-types')
let path = require('path');
let term = require('terminal-kit').terminal;
//
// This variable allows the progress bar to be drawn
//
let progress_bar;
//
// This Promises is responsible for just uploading files to S3.
//
module.exports = function(container) {
return new Promise(function(resolve, reject) {
read_all_files(container)
.then(function(container) {
return proxy_uploader(container)
}).then(function(container) {
return resolve(container)
}).catch(function(error) {
return reject(error);
});
});
}
// _____ _____ ____ __ __ _____ _____ ______ _____
// | __ \ | __ \ / __ \ | \/ | |_ _| / ____| | ____| / ____|
// | |__) | | |__) | | | | | | \ / | | | | (___ | |__ | (___
// | ___/ | _ / | | | | | |\/| | | | \___ \ | __| \___ \
// | | | | \ \ | |__| | | | | | _| |_ ____) | | |____ ____) |
// |_| |_| \_\ \____/ |_| |_| |_____| |_____/ |______| |_____/
//
//
// Read all the files in the directory while skipping some that we don't
// need on S3
//
function read_all_files(container)
{
return new Promise(function(resolve, reject) {
//
// 1. Read all file recursively
//
let files = read(container.dir, function(name) {
if(name == '.git') return false;
if(name == '.gitignore') return false;
if(name == '.DS_Store') return false;
if(name == 'README.md') return false;
return true;
});
//
// 2. Save all the files path that we got
//
container.files = files;
//
// -> Move to the next chain
//
return resolve(container);
});
}
//
// This promises is responsible for drawing on the screen the progress bar
// the first time and then start the upload process in a way that we wait
// for the upload process to finish.
//
function proxy_uploader(container)
{
return new Promise(function(resolve, reject) {
//
// 1. Upload to S3 only if we actually have files to be uploaded.
//
if(container.files.length === 0)
{
//
// -> Move to the next chain
//
return resolve(container);
}
//
// 2. Draw on the screen a message letting the user know
// what to expect from this upload process
//
term.clear();
term("\n");
term.brightWhite("\tUpload process begun...");
term("\n");
term.brightWhite("\tFrom this point on, you won't be needed.");
term("\n");
term.brightWhite("\tTake a brake...");
term("\n");
term("\n");
//
// 3. Draw the progress bar with default options
//
progress_bar = term.progressBar({
width: 80,
title: '\tUploading:',
percent: true,
eta: true,
items: container.files.length
});
//
// 4. Call the function responsible for uploading files to S3 in
// a way where its wait for the upload process to finish.
//
uploader(container, function(error) {
//
// 1. Check if there was an error
//
if(error)
{
return reject(error);
}
//
// -> Move to the next chain
//
return resolve(container);
});
});
}
// ______ _ _ _ _ _____ _______ _____ ____ _ _ _____
// | ____|| | | || \ | | / ____||__ __||_ _|/ __ \ | \ | | / ____|
// | |__ | | | || \| || | | | | | | | | || \| || (___
// | __| | | | || . ` || | | | | | | | | || . ` | \___ \
// | | | |__| || |\ || |____ | | _| |_| |__| || |\ | ____) |
// |_| \____/ |_| \_| \_____| |_| |_____|\____/ |_| \_||_____/
//
//
// The main upload function that will loop over all the files that
// we read and stop only once there are no more files to be uploaded.
//
function uploader(container, callback)
{
//
// 1. Take out a file path from the array
//
let path_with_file = container.files.shift();
//
// 2. Check if we got anything from the previous operation.
//
if(!path_with_file)
{
//
// -> Exit this function and return to the promise chain
//
return callback();
}
//
// 3. Construct the full path to the file so S3 knows the exact location
// of the file and can read the content of it.
//
let full_path_file = container.dir + '/' + path_with_file
//
// 4. Figure out the Mime type of the file so we can tell S3
// what file is it dealing with. This way the page will be
// displayed, if not the site will be downloaded instead of
// displayed.
//
let mime_type = mime.lookup(path_with_file);
//
// 5. If we weren't able to get a mime type then we set a default one
// of just plain text.
//
if(!mime_type)
{
mime_type = 'text/plain';
}
//
// 6. Split open the path and get out all the individual elements
//
let parsed_path = path.parse(path_with_file);
//
// 7. Check if the are dealing with a HTML file and remove the format
// from the name
//
if(parsed_path.ext == '.html')
{
//
// 1. By default we assume that the .html file is in the root
// directory
//
path_with_file = parsed_path.name;
//
// 2. Check to see if the .html file is in a directory
//
if(parsed_path.dir)
{
//
// 1. Add the full path
//
path_with_file = parsed_path.dir + "/" + parsed_path.name;
}
}
//
// 8. Tell the progress bar the name of the first item
//
progress_bar.startItem(parsed_path.base);
//
// 9. Prepare the options for S3
//
let params = {
Bucket: container.bucket,
Key: path_with_file,
ContentType: mime_type,
Body: fs.createReadStream(full_path_file)
};
//
// 10. Upload the file to S3 as a Stream
//
container.s3.upload(params, function(error, data) {
//
// 1. Check if there was an error
//
if(error)
{
return callback(error);
}
//
// 2. Tell the progress bar which item is done
//
progress_bar.itemDone(parsed_path.base);
//
// -> Restart the function to see if we can upload another file
//
uploader(container, callback)
});
}