UNPKG

13.4 kBJavaScriptView Raw
1// Generated by CoffeeScript 1.10.0
2(function() {
3 var CoffeeScript, buildCfnPath, checkChar, coffinChar, colors, commandHelper, commander, compileCommand, compileTemplate, createStack, crossChar, decompileCfnTemplate, decompileCommand, exec, fs, generateOutputFileName, generateTempFileName, parseTemplate, path, pretty, printCommand, ref, showHelp, spawn, stackCommand, updateOrCreateStack, validateArgs, validateCommand, validateTemplate, writeJsonTemplate,
4 slice = [].slice;
5
6 fs = require('fs');
7
8 path = require('path');
9
10 colors = require('colors');
11
12 commander = require('commander');
13
14 CoffeeScript = require('coffee-script');
15
16 ref = require('child_process'), spawn = ref.spawn, exec = ref.exec;
17
18 parseTemplate = require('./parseTemplate');
19
20 commandHelper = require('./commandHelper');
21
22 coffinChar = '\u26B0'.grey;
23
24 checkChar = '\u2713'.green;
25
26 crossChar = '\u2717'.red;
27
28 validateArgs = function() {
29 var valid;
30 valid = true;
31 if (commander.args.length === 0) {
32 console.error("You need to specify a coffin template to act on.");
33 valid = false;
34 }
35 if ((commander.validate != null) || (commander.createStack != null) || (commander.updateStack != null)) {
36 if (commander.print != null) {
37 console.error("I can't run that command if you're just printing to the console.");
38 valid = false;
39 }
40 if (!process.env.AWS_CLOUDFORMATION_HOME && (commander['cfn-home'] == null)) {
41 console.error("Either an AWS_CLOUDFORMATION_HOME environment variable or a --cfnHome switch is required.");
42 valid = false;
43 }
44 }
45 if (!valid) {
46 process.stdout.write(commander.helpInformation());
47 return process.exit(0);
48 }
49 };
50
51 compileTemplate = (function(_this) {
52 return function(source, params, callback) {
53 var pre;
54 pre = "require('../lib/coffin') ->\n";
55 return fs.readFile(source, function(err, code) {
56 var compiled, i, len, line, ref1, tabbedLines, template, templateString;
57 if (err) {
58 console.error(source + " not found");
59 process.exit(1);
60 }
61 tabbedLines = [];
62 if (params == null) {
63 params = [];
64 }
65 tabbedLines.push(" @ARGV = " + (JSON.stringify(params)));
66 ref1 = code.toString().split('\n');
67 for (i = 0, len = ref1.length; i < len; i++) {
68 line = ref1[i];
69 tabbedLines.push(' ' + line);
70 }
71 tabbedLines.push(' return');
72 code = tabbedLines.join('\n');
73 code = pre + code;
74 compiled = CoffeeScript.compile(code, {
75 source: source,
76 bare: true
77 });
78 template = eval(compiled, source);
79 templateString = commander.pretty ? JSON.stringify(template, null, 2) : JSON.stringify(template);
80 return typeof callback === "function" ? callback(templateString) : void 0;
81 });
82 };
83 })(this);
84
85 decompileCfnTemplate = function(source, callback) {
86 return fs.readFile(source, "utf8", function(err, cfnTemp) {
87 var decompiled;
88 if (err) {
89 console.log(source + " not found");
90 process.exit(1);
91 }
92 decompiled = parseTemplate(JSON.parse(cfnTemp));
93 return callback(decompiled);
94 });
95 };
96
97 writeJsonTemplate = function(json, templatePath, callback) {
98 var base, write;
99 write = function() {
100 if (json.length <= 0) {
101 json = ' ';
102 }
103 return fs.writeFile(templatePath, json, function(err) {
104 if (err != null) {
105 console.error("failed to write to " + templatePath);
106 console.error(err.message);
107 process.exit(1);
108 }
109 return typeof callback === "function" ? callback() : void 0;
110 });
111 };
112 base = path.dirname(templatePath);
113 return path.exists(base, function(exists) {
114 if (exists) {
115 return write();
116 } else {
117 return exec("mkdir -p " + base, write);
118 }
119 });
120 };
121
122 generateTempFileName = function() {
123 var dateStamp, e, name, now, rand, tmpDir;
124 e = process.env;
125 tmpDir = e.TMPDIR || e.TMP || e.TEMP || '/tmp';
126 now = new Date();
127 dateStamp = now.getYear();
128 dateStamp <<= 4;
129 dateStamp |= now.getMonth();
130 dateStamp <<= 5;
131 dateStamp |= now.getDay();
132 rand = (Math.random() * 0x100000000 + 1).toString(36);
133 name = (dateStamp.toString(36)) + "-" + (process.pid.toString(36)) + "-" + rand + ".template";
134 return path.join(tmpDir, name);
135 };
136
137 generateOutputFileName = function(source, extension) {
138 var base, filename;
139 base = commander.output || path.dirname(source);
140 filename = path.basename(source, path.extname(source)) + extension;
141 return path.join(base, filename);
142 };
143
144 buildCfnPath = function() {
145 var cfnHome;
146 cfnHome = commander['cfn-home'] || process.env.AWS_CLOUDFORMATION_HOME;
147 return path.normalize(path.join(cfnHome, 'bin'));
148 };
149
150 validateTemplate = (function(_this) {
151 return function(templatePath, callback) {
152 var errorText, resultText, validateExec;
153 validateExec = spawn(path.join(buildCfnPath(), 'cfn-validate-template'), ['--template-file', templatePath]);
154 errorText = '';
155 resultText = '';
156 validateExec.stderr.on('data', function(data) {
157 return errorText += data.toString();
158 });
159 validateExec.stdout.on('data', function(data) {
160 return resultText += data.toString();
161 });
162 return validateExec.on('exit', function(code) {
163 if (code === 0) {
164 process.stdout.write(checkChar + "\n");
165 process.stdout.write(resultText);
166 } else {
167 process.stdout.write(crossChar + "\n");
168 process.stderr.write(errorText);
169 }
170 return typeof callback === "function" ? callback(code) : void 0;
171 });
172 };
173 })(this);
174
175 updateOrCreateStack = (function(_this) {
176 return function(name, templatePath, compiled, callback) {
177 var args, resultText, updateErrorText, updateExec;
178 args = ['--template-file', templatePath, '--stack-name', name];
179 if (commandHelper.doesTemplateReferenceIAM(compiled)) {
180 args.push('-c');
181 args.push('CAPABILITY_IAM');
182 }
183 updateExec = spawn((buildCfnPath()) + "/cfn-update-stack", args);
184 updateErrorText = '';
185 resultText = '';
186 updateExec.stderr.on('data', function(data) {
187 return updateErrorText += data.toString();
188 });
189 updateExec.stdout.on('data', function(data) {
190 return resultText += data.toString();
191 });
192 return updateExec.on('exit', function(code) {
193 var existsSyncFunc;
194 existsSyncFunc = fs.existsSync != null ? fs.existsSync : path.existsSync;
195 if (existsSyncFunc((buildCfnPath()) + "/cfn-update-stack")) {
196 if (code === 0) {
197 process.stdout.write("stack '" + name + "' (updated) " + checkChar + "\n");
198 process.stdout.write(resultText);
199 if (typeof callback === "function") {
200 callback(code);
201 }
202 return;
203 }
204 if (updateErrorText.match(/^cfn-update-stack: Malformed input-No updates are to be performed/) != null) {
205 process.stdout.write("stack '" + name + "' (no changes)\n");
206 process.stdout.write(resultText);
207 if (typeof callback === "function") {
208 callback(0);
209 }
210 return;
211 }
212 if (updateErrorText.match(/^cfn-update-stack: Malformed input-Stack with ID\/name/) == null) {
213 console.error(updateErrorText);
214 if (typeof callback === "function") {
215 callback(code);
216 }
217 return;
218 }
219 }
220 return createStack(name, templatePath, compiled, callback);
221 });
222 };
223 })(this);
224
225 createStack = (function(_this) {
226 return function(name, templatePath, compiled, callback) {
227 var args, createExec, errorText, resultText;
228 args = ['--template-file', templatePath, '--stack-name', name];
229 if (commandHelper.doesTemplateReferenceIAM(compiled)) {
230 args.push('-c');
231 args.push('CAPABILITY_IAM');
232 }
233 createExec = spawn((buildCfnPath()) + "/cfn-create-stack", args);
234 errorText = '';
235 resultText = '';
236 createExec.stdout.on('data', function(data) {
237 return resultText += data.toString();
238 });
239 createExec.stderr.on('data', function(data) {
240 return errorText += data.toString();
241 });
242 return createExec.on('exit', function(code) {
243 if (code !== 0) {
244 if (errorText.match(/^cfn-create-stack: Malformed input-AlreadyExistsException/) != null) {
245 process.stderr.write("stack '" + name + "' already exists " + crossChar + "\n");
246 return;
247 }
248 process.stderr.write(errorText);
249 return;
250 }
251 process.stdout.write("stack '" + name + "' (created) " + checkChar + "\n");
252 process.stdout.write(resultText);
253 return typeof callback === "function" ? callback(code) : void 0;
254 });
255 };
256 })(this);
257
258 pretty = {
259 "switch": '-p, --pretty',
260 text: 'Add spaces and newlines to the resulting json to make it a little prettier'
261 };
262
263 commander.version(require('./coffin').version);
264
265 commander.usage('[options] <coffin template>');
266
267 commander.option('-o, --output [dir]', 'Directory to output compiled file(s) to');
268
269 commander.option('--cfn-home [dir]', 'The home of your AWS Cloudformation tools. Defaults to your AWS_CLOUDFORMATION_HOME environment variable.');
270
271 commander.option(pretty["switch"], pretty.text);
272
273 printCommand = commander.command('print [template]');
274
275 printCommand.description('Print the compiled template.');
276
277 printCommand.action(function() {
278 var params, template;
279 template = arguments[0], params = 2 <= arguments.length ? slice.call(arguments, 1) : [];
280 validateArgs();
281 return compileTemplate(template, params, function(compiled) {
282 return console.log(compiled);
283 });
284 });
285
286 validateCommand = commander.command('validate [template]');
287
288 validateCommand.description('Validate the compiled template. Either an AWS_CLOUDFORMATION_HOME environment variable or a --cfn-home switch is required.');
289
290 validateCommand.action(function() {
291 var params, template;
292 template = arguments[0], params = 2 <= arguments.length ? slice.call(arguments, 1) : [];
293 validateArgs();
294 return compileTemplate(template, params, function(compiled) {
295 var tempFileName;
296 process.stdout.write(coffinChar + " " + template + " ");
297 tempFileName = generateTempFileName();
298 return writeJsonTemplate(compiled, tempFileName, function() {
299 return validateTemplate(tempFileName, function(resultCode) {});
300 });
301 });
302 });
303
304 stackCommand = commander.command('stack [name] [template]');
305
306 stackCommand.description('Create or update the named stack using the compiled template. Either an AWS_CLOUDFORMATION_HOME environment variable or a --cfn-home switch is required.');
307
308 stackCommand.action(function() {
309 var name, params, template;
310 name = arguments[0], template = arguments[1], params = 3 <= arguments.length ? slice.call(arguments, 2) : [];
311 validateArgs();
312 return compileTemplate(template, params, function(compiled) {
313 var tempFileName;
314 tempFileName = generateTempFileName();
315 return writeJsonTemplate(compiled, tempFileName, function() {
316 process.stdout.write(coffinChar + " " + template + " -> ");
317 return updateOrCreateStack(name, tempFileName, compiled, function(resultCode) {});
318 });
319 });
320 });
321
322 compileCommand = commander.command('compile [template]');
323
324 compileCommand.description('Compile and write the template. The output file will have the same name as the coffin template plus a shiny new ".template" extension.');
325
326 compileCommand.action(function() {
327 var params, template;
328 template = arguments[0], params = 2 <= arguments.length ? slice.call(arguments, 1) : [];
329 validateArgs();
330 return compileTemplate(template, params, function(compiled) {
331 var fileName;
332 process.stdout.write(coffinChar + " " + template + " -> ");
333 fileName = generateOutputFileName(template, ".template");
334 return writeJsonTemplate(compiled, fileName, function() {
335 return process.stdout.write(fileName + "\n");
336 });
337 });
338 });
339
340 decompileCommand = commander.command('decompile [cfn-template]');
341
342 decompileCommand.description('experimental - Convert the given cloud formation template to coffin (or as best as we can). It will output a file of the same name with ".coffin" extension.');
343
344 decompileCommand.action(function(cfnTemplate) {
345 validateArgs();
346 return decompileCfnTemplate(cfnTemplate, function(decompiled) {
347 var fileName;
348 process.stdout.write(coffinChar + " " + cfnTemplate + " -> ");
349 fileName = generateOutputFileName(cfnTemplate, ".coffin");
350 return writeJsonTemplate(decompiled, fileName, function() {
351 return process.stdout.write(fileName + "\n");
352 });
353 });
354 });
355
356 showHelp = function() {
357 process.stdout.write(commander.helpInformation());
358 return process.exit(1);
359 };
360
361 commander.command('').action(showHelp);
362
363 commander.command('*').action(showHelp);
364
365 if (process.argv.length <= 2) {
366 showHelp();
367 }
368
369 module.exports.run = function() {
370 return commander.parse(process.argv);
371 };
372
373}).call(this);