From 366b5234d05dfa2c926ad2d979b3c5099d504ee1 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 14 Dec 2015 22:42:59 -0800 Subject: [PATCH] read and write python-style config files --- lib/pyconf.js | 104 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/lib/pyconf.js b/lib/pyconf.js index e2c4c3d..103edc6 100644 --- a/lib/pyconf.js +++ b/lib/pyconf.js @@ -1,6 +1,7 @@ 'use strict'; var fs = require('fs'); +var sfs = require('safe-replace').create(); function snakeCase(key) { if ('tlsSni01Port' === key) { @@ -37,7 +38,7 @@ function parsePythonConf(str, cb) { var parts = line.trim().split('='); var pykey = parts.shift().trim(); var key = camelCase(pykey); - var val = parts.join('='); + var val = parts.join('=').trim(); if ('True' === val) { val = true; @@ -70,6 +71,94 @@ function parsePythonConf(str, cb) { cb(null, obj); } +function toPyVal(val) { + if (null === val) { + 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)) { + return val.join(','); + } + + 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 = ''; + + + if ('number' !== typeof num) { + obj.__lines.push(pykey + ' = ' + pyval); + return; + } + + // restore comments + if (-1 !== obj.__lines[num].indexOf('#')) { + comment = obj.__lines[num].replace(/.*?(\s*#.*)/, '$1'); + } + + if ('[' === pykey[0]) { + return; + } + + if ('undefined' === typeof pyval) { + obj.__lines[num] = "___DELETE_ME___"; + } + }); + + obj.__lines = obj.__lines.filter(function (line) { + if ("___DELETE_ME___" !== line) { + return true; + } + }); + + 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.writeFile(pathname, text, 'utf8', function (err) { + if (err) { + cb(err); + return; + } + + cb(); + }); + }); +} + function parsePythonConfFile(pathname, cb) { fs.readFile(pathname, 'utf8', function (err, text) { if (err) { @@ -82,7 +171,9 @@ function parsePythonConfFile(pathname, cb) { } module.exports.parse = parsePythonConf; -module.exports.parseFile = parsePythonConfFile; +module.exports.readFile = parsePythonConfFile; +module.exports.stringify = stringifyPythonConf; +module.exports.writeFile = writePythonConfFile; parsePythonConfFile('examples/renewal-example.com.conf', function (err, obj) { if (err) { @@ -90,5 +181,12 @@ parsePythonConfFile('examples/renewal-example.com.conf', function (err, obj) { return; } - console.log(obj); + writePythonConfFile('examples/renewal-example.com.conf.new', obj, function (err, obj) { + if (err) { + console.error(err.stack); + return; + } + + console.log(obj); + }); });