s3-website
Version:
Easily publish static websites on Amazon S3
204 lines (187 loc) • 8.35 kB
JavaScript
var AWS = require('aws-sdk')
var s3Website = require('./')
var program = require('commander')
var url = require('url')
var s3site = s3Website.s3site
var deploy = s3Website.deploy
var getConfig = s3Website.config
var templateConfig = s3Website.templateConfig
require('console.table')
require('colors')
/**
* Filter out commander specific properties from options hash, and merge command
* line parameters into single hash.
*/
function getCLArguments (params, options) {
var fromCL = {}
var fromCLKeys = Object.keys(options).filter(function (item) {
var toRemove = ['commands', 'parent', 'options']
if (item.startsWith('_')) return false
return toRemove.indexOf(item) < 0
})
var paramKeys = Object.keys(params)
fromCLKeys.forEach(function (key) { if (options[key]) fromCL[key] = options[key] })
paramKeys.forEach(function (key) { if (params[key]) fromCL[key] = params[key] })
return fromCL
}
function printDeployResults (err, website, results) {
if (err) {
console.error(err.message)
process.exit(1)
}
var numRows = Object.keys(results).reduce(function (prev, current) {
if (results[current].length > prev) { prev = results[current].length }
return prev
}, 0)
var values = new Array(numRows)
values.fill(0)
values = values.map(function (_, index) {
var row = {}
Object.keys(results).forEach(function (key) {
if (results[key][index]) {
row[key] = results[key][index]
} else {
row[key] = ' '
}
})
return row
})
if (values.length > 0) {
console.table('\n\nDeployment Report'.yellow, values)
}
var isEmpty = Object.keys(results).reduce(function (prev, current) {
if (results[current].length > 0) { return false }
return prev
}, true)
if (isEmpty) {
console.log('There were no changes to deploy'.yellow)
} else {
if (website.url) console.log(('Updated site: ' + website.url).green)
}
}
function exclude (val, excludedList) {
excludedList.push(val)
return excludedList
}
program
.usage('<command> [option]')
.description(
'Use one of commands below to create an s3-website or deploy content to an existing bucket.'
).on('--help', function () {
console.log(' Credentials:')
console.log('')
console.log(' Aws Credentials should either be supplied in a local .env file or in ~/.aws/credentials')
console.log(' Credentials should follow this format:')
console.log(' AWS_ACCESS_KEY_ID=MY_KEY_ID')
console.log(' AWS_SECRET_ACCESS_KEY=MY_SECRET_KEY')
console.log(' ')
console.log(' Config file: ')
console.log('')
console.log(' Should be specified using the -f flag. The default config file is .s3-website.json')
console.log(' Should contain only a JSON object containing at least the keys: region, domain, uploadDir')
console.log('')
console.log(' To see more information about a specific command:')
console.log(' s3-website <command> -h'.green)
})
.version(require('./package.json').version)
program
.command('create [domain]')
.usage('[domain [options]]')
.description('Will create and configure an s3 website')
.option('-r, --region <region>', 'Region [us-east-1].')
.option('-i, --index <index>', 'Index Document [index.html].')
.option('-e, --error <error>', 'Error Document.')
.option('-t, --routes <routes>', 'Path to routing rules file.')
.option('--json', 'Output JSON.')
.option('--cert-id <IAM ServerCertId>', 'The ID of your cert in IAM.')
.option('-c, --cert <cert>', 'Path to the public key certificate.')
.option('-k, --key <key>', 'Path to the private key.')
.option('-n, --cert-name <certificate name>', 'A unique name for the server certificate.')
.option('-u, --upload-dir <upload directory>', 'Set directory to upload when site is deployed.')
.option('-d, --deploy', 'Will upload uploadDir immediately after site creation')
.option('-p, --prefix <prefix>', 'Will upload files with the prefix [name/of/folder/to/sync/on/s3]')
.option('-l, --lock-config', 'Will prevent config file from being changed')
.option('--intermediate <intermediate certs>', 'Path to the concatenated intermediate certificates.')
.option('-f, --config-file <file>', 'Path to the config file to read. Default is .s3-website.json')
.option('--exclude <path-pattern>', 'Path pattern to excluded files from being created/updated/removed. This option is repeatable', exclude, [])
.action(function (domain, options) {
var fromCL = getCLArguments({domain: domain}, options)
if (fromCL.configFile == null) fromCL.configFile = '.s3-website.json'
getConfig(fromCL.configFile, fromCL, function (err, config) { // eslint-disable-line handle-callback-err
s3site(config, function (err, website, uploadResults) {
if (err) {
if (options.json) {
console.error(JSON.stringify({ code: err.code, message: err.message }))
} else {
console.error('Error:', err.message)
}
process.exit(1)
}
if (options.json) {
console.log(JSON.stringify(website))
} else {
console.log('Successfully created your website.\n'.green)
console.log(' URL:')
console.log(' ' + website.url)
console.log(' DNS:')
console.log(' ' + config.domain + '. CNAME ' + url.parse(website.url).host + '.\n')
if (website.certId) {
console.log(' Certificate ID:\n ' + website.certId + '\n')
}
printDeployResults(null, website, uploadResults)
}
})
})
})
program
.command('deploy [upload-dir]')
.usage('[dir] [options]')
.description('Will push contents of directory to specified s3 website')
.option('-r, --region <region>', 'Region [us-east-1].')
.option('-p, --prefix <prefix>', 'Will upload files with the prefix [name/of/folder/to/sync/on/s3]')
.option('-l, --lock-config', 'Will prevent config file from being changed')
.option('-d, --domain <domain>', 'Name of bucket [example.bucket] - put always this parameter last one')
.option(
'-f, --config-file <file>',
'Path to the config file to read. Default is .s3-website.json. Note: Using non-standard config file will require passing "-f myConfigFile" with subsequent operations'
)
.option('--exclude <path-pattern>', 'Path pattern to excluded files from being created/updated/removed. This option is repeatable', exclude, [])
.action(function (uploadDir, options) {
var fromCL = getCLArguments({uploadDir: uploadDir}, options)
if (fromCL.configFile == null) fromCL.configFile = '.s3-website.json'
getConfig(fromCL.configFile, fromCL, function (err, config) { // eslint-disable-line handle-callback-err
var s3 = new AWS.S3({ region: config.region })
deploy(s3, config, printDeployResults)
})
}).on('--help', function () {
console.log(' ')
console.log(' Successful deployment requires: '.yellow)
console.log('')
console.log(' Correct config: - passed from commandline or from config file specified with -f flag')
console.log(' region: the region where your bucket lives, can be set by commandline flag or in config file')
console.log(' domain: the name of your bucket, can be set by commandline flag or in config file')
console.log(' uploadDir: the name of the directory whose contents you want to upload,' +
'can be supplied as first argument to deploy or in config file')
console.log('')
console.log(' Valid AWS credentials: - run s3-website -h for more info')
console.log(' ')
console.log(' These can be supplied as command line arguments, or in a json config file specified with -f flag'.green)
})
program
.command('configTemplate')
.usage('')
.description('Creates a configuration file template, which can be used to create site by setting config details and running s3-website create')
.action(function () {
getConfig('.s3-website.json', templateConfig, function (err, config) { // eslint-disable-line handle-callback-er
if (err) { console.err(err) }
})
})
program
.command('*')
.description('Output usage message')
.action(function (env) {
program.help()
})
program.parse(process.argv)
if (!program.args.length) program.outputHelp()