UNPKG

docpad-plugin-sunny

Version:

DocPad plugin which adds the ability to output to Amazon S3, Google Storage or and other service supported by SunnyJS.

200 lines (167 loc) 7.87 kB
# Yay requires. sunny = require 'sunny' mime = require 'mime' http = require 'http' util = require 'util' {TaskGroup} = require('taskgroup') uploadData = (container, path, headers, data, retryLimit, retries, next)-> # Test for whether to retry the upload. retries = if retries? then retries else 0 retryLimit = if retryLimit? then retryLimit else 2 doIt = if not (retryLimit) or (retryLimit and (retries <= retryLimit)) or retryLimit is -1 then true else false if doIt if retries console.log "Retrying upload of #{path} to #{container.name}: Attempts: #{retries}" #Open the stream and do the write. writeStream = container.putBlob path, headers writeStream.on 'error', (err)-> console.log "Error uploading #{path} to #{container.name}" # Recall this function with the retry counter incremented. Yay recursion! uploadData container, path, headers, data, retryLimit, retries+1, next writeStream.on 'end', (results, meta)-> console.log "Uploaded #{path} to #{container.name}" next() writeStream.write data writeStream.end() else next("Upload for #{path} to #{container.name} has failed #{retries} times. Giving up.") # Does the upload after Sunny has been set up and such. doUpload = (docpad, container, acl, retryLimit, next)-> # Seems obvious enough. Sets files to public read in the cloud. if acl? if acl is false cloudHeaders = {} else cloudHeaders = {"acl": acl} else cloudHeaders = {"acl": 'public-read'} tasks = new TaskGroup().once 'complete', (err) -> return next(err) docpad.getFiles(write: true).forEach (file)-> path = file.attributes.relativeOutPath # Gets the correct data from Docpad. data = file.get('contentRendered') || file.get('content') || (file.getData && file.getData()) || file.getContent() || "" if !data return next("No data for file #{path}") length = data.length type = mime.lookup path #file.get('contentType') headers = { "Content-Length": length, "Content-Type": type } # Merge the headers with those Docpad has. try if file.get('headers')? #and file.get('headers').length? for key, value of file.get('headers') headers[key] = value catch err console.log err console.dir file tasks.addTask (complete) -> uploadData container, path, {headers: headers, cloudHeaders: cloudHeaders}, data, retryLimit, 0, complete tasks.run() handle = (docpad, sunnyConfig, sunnyContainer, defaultACL, retryLimit, next)-> # Test the configuration and try it. if sunnyConfig.provider? and sunnyConfig.account? and sunnyConfig.secretKey? and sunnyContainer? # Get a connection to the provider. connection = sunny.Configuration.fromObj(sunnyConfig).connection # Prepare a request to the provider for the container. Checks to make sure the container exists. containerReq = connection.getContainer sunnyContainer, {validate: true} containerReq.on 'error', (err)-> console.log "Received error trying to connect to provider: \n #{err}" containerReq.on 'end', (results, meta)-> if results # not sure exactly how, but the 'end' can get called more than once with null params on the second call container = results.container console.log "Got container #{container.name}." # Do the upload. doUpload docpad, container, defaultACL, retryLimit, next containerReq.end() else next(""" One of the config variables is missing. Printing config: #{util.inspect(sunnyConfig)} Container is #{sunnyContainer} """) handleEnvPrefix = (docpad, prefix, next)-> sunnyConfig = { provider: process.env["#{prefix}PROVIDER"], # Cloud provider: (aws|google) account: process.env["#{prefix}ACCOUNT"], secretKey: process.env["#{prefix}SECRETKEY"], ssl: process.env["#{prefix}SSL"] authUrl: process.env["#{prefix}AUTHURL"] } sunnyContainer = process.env["#{prefix}CONTAINER"] sunnyACL = process.env["#{prefix}ACL"] sunnyRetryLimit = process.env["#{prefix}RETRY_LIMIT"] # Parse the environment variable for ssl. sunnyConfig.ssl = ((typeof(sunnyConfig.ssl) is 'string') and (sunnyConfig.ssl.toLowerCase() is 'true')) handle docpad, sunnyConfig, sunnyContainer, sunnyACL, sunnyRetryLimit, next handleEnv = (docpad, config, next)-> if config.envPrefixes.length > 0 for prefix in config.envPrefixes handleEnvPrefix docpad, prefix, next else handleEnvPrefix docpad, "DOCPAD_SUNNY_", next module.exports = (BasePlugin) -> class docpadSunnyPlugin extends BasePlugin name: "sunny" config: defaultACL: 'public-read' onlyIfProduction: true configFromEnv: false envPrefixes: [] cloudConfigs: [ # { # sunny:{ # provider: undefined # account: undefined # secretKey: undefined # ssl: undefined # authUrl: undefined # }, # container: undefined, # acl: undefined # retryLimit: undefined # } ] deployWithSunny: (next)=> docpad = @docpad config = @getConfig() if config.cloudConfigs.length > 0 or config.configFromEnv docpad.log 'info', "Found #{config.cloudConfigs.length} configurations in file." @docpad.generate (err)-> return next(err) if err tasks = new TaskGroup().once 'complete', (err) -> return next(err) if config.configFromEnv docpad.log 'info', "Grabbing configs from environment." tasks.addTask (complete) -> handleEnv docpad, config, complete for cloudConfig in config.cloudConfigs tasks.addTask (complete) -> handle docpad, cloudConfig.sunny, cloudConfig.container, cloudConfig.acl, cloudConfig.retryLimit, complete tasks.run() else errMsg = 'No configs found' docpad.log 'warn', errMsg next(errMsg) consoleSetup: (opts)=> docpad = @docpad config = @getConfig() {consoleInterface, commander} = opts commander .command('deploy-sunny') .description("Deploys your website to any provider allowed by Sunny.") .action consoleInterface.wrapAction(@deployWithSunny) @ #writeAfter: (opts, next)-> # next?() # if (not @config.onlyIfProduction) or (process.env.NODE_ENV is "production") # if @config.configFromEnv # console.log "Sunny plugin getting config from environment..." # handleEnv @docpad, @config # # if @config.cloudConfigs.length > 0 # console.log "Found #{@config.cloudConfigs.length} configurations in config file." # for cloudConfig in @config.cloudConfigs # handle @docpad, cloudConfig.sunny, cloudConfig.container, cloudConfig.acl, cloudConfig.retryLimit