forked from bobobo1618/docpad-plugin-sunny
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsunny.plugin.coffee
199 lines (167 loc) · 7.68 KB
/
sunny.plugin.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# 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