| 
									
										
										
										
											2015-12-14 23:07:04 -08:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var fs = require('fs'); | 
					
						
							|  |  |  | var sfs = require('safe-replace').create(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function snakeCase(key) { | 
					
						
							| 
									
										
										
										
											2016-02-11 12:46:08 -05:00
										 |  |  |   // TODO let user supply list of exceptions
 | 
					
						
							| 
									
										
										
										
											2015-12-14 23:07:04 -08:00
										 |  |  |   if ('tlsSni01Port' === key) { | 
					
						
							|  |  |  |     return 'tls_sni_01_port'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   /* | 
					
						
							|  |  |  |   else if ('http01Port' === key) { | 
					
						
							|  |  |  |     return 'http01-port'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     return key.replace(/([A-Z])/g, '_$1').toLowerCase(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function uc(match, c) { | 
					
						
							|  |  |  |   return c.toUpperCase(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function camelCase(key) { | 
					
						
							|  |  |  |   return key.replace(/_([a-z0-9])/g, uc); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function parsePythonConf(str, cb) { | 
					
						
							|  |  |  |   var keys = {}; | 
					
						
							|  |  |  |   var obj = {}; | 
					
						
							|  |  |  |   var lines = str.split('\n'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   lines.forEach(function (line, i) { | 
					
						
							|  |  |  |     line = line.replace(/#.*/, '').trim(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!line) { return; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-30 06:37:16 -06:00
										 |  |  |     var parts = line.split('='); | 
					
						
							| 
									
										
										
										
											2015-12-14 23:07:04 -08:00
										 |  |  |     var pykey = parts.shift().trim(); | 
					
						
							|  |  |  |     var key = camelCase(pykey); | 
					
						
							|  |  |  |     var val = parts.join('=').trim(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ('True' === val) { | 
					
						
							|  |  |  |       val = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if ('False' === val) { | 
					
						
							|  |  |  |       val = false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-30 06:37:16 -06:00
										 |  |  |     else if ('None' === val || '' === val) { | 
					
						
							| 
									
										
										
										
											2015-12-14 23:07:04 -08:00
										 |  |  |       val = null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (/,/.test(val) && !/^"[^"]*"$/.test(val)) { | 
					
						
							| 
									
										
										
										
											2017-10-30 06:37:16 -06:00
										 |  |  |       val = val.split(',').map(function(x) { return x.trim(); }); | 
					
						
							| 
									
										
										
										
											2015-12-14 23:07:04 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-30 06:37:16 -06:00
										 |  |  |     else if (/^-?[0-9]+$/.test(val)) { | 
					
						
							| 
									
										
										
										
											2015-12-14 23:07:04 -08:00
										 |  |  |       val = parseInt(val, 10); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     obj[key] = val; | 
					
						
							|  |  |  |     if ('undefined' !== typeof keys[key]) { | 
					
						
							|  |  |  |       console.warn("unexpected duplicate key '" + key + "': '" + val + "'"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     keys[key] = i; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // we want to be able to rewrite the file with comments, etc
 | 
					
						
							|  |  |  |   obj.__keys = keys; | 
					
						
							|  |  |  |   obj.__lines = lines; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cb(null, obj); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function toPyVal(val) { | 
					
						
							| 
									
										
										
										
											2017-10-30 07:56:40 -06:00
										 |  |  |   if (null === val || '' === val) { | 
					
						
							| 
									
										
										
										
											2015-12-14 23:07:04 -08:00
										 |  |  |     return 'None'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (true === val) { | 
					
						
							|  |  |  |     return 'True'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (false === val) { | 
					
						
							|  |  |  |     return 'False'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if ('string' === typeof val) { | 
					
						
							|  |  |  |     return val; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if ('number' === typeof val) { | 
					
						
							|  |  |  |     return val; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (Array.isArray(val)) { | 
					
						
							| 
									
										
										
										
											2015-12-19 19:09:32 -08:00
										 |  |  |     val = val.join(','); | 
					
						
							|  |  |  |     if (-1 === val.indexOf(',')) { | 
					
						
							| 
									
										
										
										
											2017-10-30 06:37:16 -06:00
										 |  |  |       val += ','; // disambiguates value from array with one element
 | 
					
						
							| 
									
										
										
										
											2015-12-19 19:09:32 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-02-11 12:46:08 -05:00
										 |  |  |     return val; | 
					
						
							| 
									
										
										
										
											2015-12-14 23:07:04 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return val && JSON.stringify(val); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function stringifyPythonConf(obj, cb) { | 
					
						
							|  |  |  |   var endline; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // nix the final newline
 | 
					
						
							|  |  |  |   if (!obj.__lines[obj.__lines.length - 1].trim()) { | 
					
						
							|  |  |  |     endline = obj.__lines.pop(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Object.keys(obj).forEach(function (key) { | 
					
						
							|  |  |  |     if ('__' === key.slice(0, 2)) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var pykey = snakeCase(key); | 
					
						
							|  |  |  |     var pyval = toPyVal(obj[key]); | 
					
						
							|  |  |  |     var num = obj.__keys[key]; | 
					
						
							|  |  |  |     var comment = ''; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-11 13:34:40 -05:00
										 |  |  |     if ('undefined' === typeof pyval) { | 
					
						
							|  |  |  |       if ('number' === typeof num) { | 
					
						
							| 
									
										
										
										
											2017-10-30 07:56:40 -06:00
										 |  |  |         pyval = 'None'; | 
					
						
							| 
									
										
										
										
											2017-10-30 06:37:16 -06:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2016-02-11 13:34:40 -05:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-12-14 23:07:04 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if ('number' !== typeof num) { | 
					
						
							|  |  |  |       obj.__lines.push(pykey + ' = ' + pyval); | 
					
						
							| 
									
										
										
										
											2015-12-19 21:07:46 -08:00
										 |  |  |       obj.__keys[key] = obj.__lines.length - 1; | 
					
						
							| 
									
										
										
										
											2015-12-14 23:07:04 -08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 19:08:26 -08:00
										 |  |  |     if ('[' === pykey[0]) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-11 12:46:08 -05:00
										 |  |  |     if (!obj.__lines[num] || !obj.__lines[num].indexOf) { | 
					
						
							|  |  |  |       console.warn('[pyconf] WARN index past array length:'); | 
					
						
							|  |  |  |       console.log(obj.__lines.length, num, obj.__lines[num]); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 23:07:04 -08:00
										 |  |  |     // restore comments
 | 
					
						
							|  |  |  |     if (-1 !== obj.__lines[num].indexOf('#')) { | 
					
						
							|  |  |  |       comment = obj.__lines[num].replace(/.*?(\s*#.*)/, '$1'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-30 06:37:16 -06:00
										 |  |  |     obj.__lines[num] = pykey + ' = ' + pyval + comment; | 
					
						
							| 
									
										
										
										
											2015-12-14 23:07:04 -08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ('string' === typeof endline) { | 
					
						
							|  |  |  |     obj.__lines.push(endline); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cb(null, obj.__lines.join('\n')); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function writePythonConfFile(pathname, obj, cb) { | 
					
						
							|  |  |  |   // TODO re-read file?
 | 
					
						
							|  |  |  |   stringifyPythonConf(obj, function (err, text) { | 
					
						
							|  |  |  |     sfs.writeFileAsync(pathname, text, 'utf8').then(function () { | 
					
						
							|  |  |  |       cb(null, null); | 
					
						
							|  |  |  |     }, function (err) { | 
					
						
							|  |  |  |       cb(err); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function parsePythonConfFile(pathname, cb) { | 
					
						
							|  |  |  |   fs.readFile(pathname, 'utf8', function (err, text) { | 
					
						
							|  |  |  |     if (err) { | 
					
						
							|  |  |  |       cb(err); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parsePythonConf(text, cb); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports.parse = parsePythonConf; | 
					
						
							|  |  |  | module.exports.readFile = parsePythonConfFile; | 
					
						
							|  |  |  | module.exports.stringify = stringifyPythonConf; | 
					
						
							|  |  |  | module.exports.writeFile = writePythonConfFile; |