Skip to content

Add support for .properties for expand_key mode #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 73 additions & 19 deletions lib/consul/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var _ = require('underscore');
var fs = require('fs');
var path = require('path');
var utils = require('../utils.js');

var logger = require('../logging.js');

Expand All @@ -21,7 +22,7 @@ exports.setToken = function(tok) {

var write_content_to_consul = function(key_name, content, cb) {
logger.trace('Adding key %s, value:\n%s', key_name, content);
consul.kv.set({'key': key_name, value: content, token: token}, function(err) {
consul.kv.set({'key': key_name, value: content !== null ? String(content) : null, token: token}, function(err) {
if (err) {
return cb('Failed to write key ' + key_name + ' due to ' + err);
}
Expand Down Expand Up @@ -54,7 +55,7 @@ var create_key_name = function(branch, file, ref) {
/**
* Given an obj, recurse into it, populating the parts array with all of the key->value
* relationships, prefixed by parent objs.
*
*
* For example, the obj { 'first': { 'second': { 'third' : 'whee' }}} should yield a
* parts array with a single entry: 'first/second/third' with value 'whee'.
*/
Expand All @@ -74,7 +75,7 @@ var render_obj = function(parts, prefix, obj) {
* as parents of subtrees. Arrays are ignored since they add annoying problems (multiple array
* entries can have the same value, so what do we do then?).
*/
var populate_kvs_from_json = function(branch, prefix, obj, cb) {
var populate_kvs_from_object = function(branch, prefix, obj, cb) {

var writes = [];

Expand All @@ -89,41 +90,94 @@ var populate_kvs_from_json = function(branch, prefix, obj, cb) {
});
};


/**
* If a file was modified, read its new value and update consul's KV store.
*/
var file_modified = function(branch, file, cb) {

var fqf = branch.branch_directory + path.sep + file;

logger.trace('Attempting to read "%s"', fqf);

if (branch.expand_keys && file.endsWith('.json')) {
// Delete current tree. Yeah, I know this is kinda the coward's way out, but it's a hell of a lot
// easier to get provably correct than diffing the file against the contents of the KV store.
file_deleted(branch, file, function(err) {
if (err) return cb('Failed to delete key ' + key_name + ' due to ' + err);

fs.readFile(fqf, {encoding:'utf8'}, function(err, body) {
var handle_json_kv_file = function(file_path, cb) {
fs.readFile(file_path, {encoding: 'utf8'}, function (err, body) {
/* istanbul ignore if */
if (err) return cb('Failed to read key ' + fqf + ' due to ' + err);
if (err) return cb('Failed to read key ' + file_path + ' due to ' + err);
var body = body ? body.trim() : '';
try {
var obj = JSON.parse(body);
populate_kvs_from_json(branch, create_key_name(branch, file), obj, cb);
} catch(e) {
populate_kvs_from_object(branch, create_key_name(branch, file), obj, cb);
} catch (e) {
logger.warn("Failed to parse .json file. Using body string as a KV.");
write_content_to_consul(create_key_name(branch, file), body, cb);
}
});
};

var handle_properties_kv_file = function(file_path, common_properties_relative_path, cb) {

function extract_and_populate_properties(file_body, common_body, cb) {
utils.load_properties(file_body, common_body, function (error, obj) {
if (error) {
logger.warn('Failed to load properties for : ' + file + ' due to : ' + error + '.' + ' Using body string as a KV.');
handle_as_flat_file(file_path, branch, file, cb);
} else {
populate_kvs_from_object(branch, create_key_name(branch, file), obj, cb);
}
});
}

fs.readFile(file_path, {encoding: 'utf8'}, function (err, file_body) {
/* istanbul ignore if */
if (err) return cb('Failed to read key ' + file_path + ' due to ' + err);

if(common_properties_relative_path) {
var path_to_common_properties_file = branch.branch_directory + path.sep + common_properties_relative_path;
fs.readFile(path_to_common_properties_file, {encoding: 'utf8'}, function (err, common_body) {
if (err) {
logger.warn('Failed to read common variables for ' + path_to_common_properties_file + ' due to ' + err);
common_body = '';
}
extract_and_populate_properties(file_body, common_body, cb);
});
}
else {
extract_and_populate_properties(file_body, '', cb);
}
});
} else {
fs.readFile(fqf, {encoding:'utf8'}, function(err, body) {
};

var handle_as_flat_file = function(fqf, branch, file, cb) {
fs.readFile(fqf, {encoding: 'utf8'}, function (err, body) {
/* istanbul ignore if */
if (err) return cb('Failed to read key ' + fqf + ' due to ' + err);
var body = body ? body.trim() : '';
write_content_to_consul(create_key_name(branch, file), body, cb);
});
};

var handle_expanded_keys_with_different_file_types = function() {
if (file.endsWith('.json')) {
// Delete current tree. Yeah, I know this is kinda the coward's way out, but it's a hell of a lot
// easier to get provably correct than diffing the file against the contents of the KV store.
file_deleted(branch, file, function (err) {
if (err) return cb('Failed to delete key ' + key_name + ' due to ' + err);
handle_json_kv_file(fqf, cb);
});
} else if (file.endsWith('.properties')) {
file_deleted(branch, file, function (err) {
if (err) return cb('Failed to delete key ' + key_name + ' due to ' + err);
handle_properties_kv_file(fqf, branch.common_properties, cb);
});
} else {
handle_as_flat_file(fqf, branch, file, cb);
}
};

var fqf = branch.branch_directory + path.sep + file;
logger.trace('Attempting to read "%s"', fqf);

if (branch.expand_keys) {
handle_expanded_keys_with_different_file_types();
} else {
handle_as_flat_file(fqf, branch, file, cb);
}
};

Expand Down
1 change: 1 addition & 0 deletions lib/git/branch.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function Branch(repo_config, name) {
Object.defineProperty(this, 'branch_parent', {value: repo_config.local_store + path.sep + repo_config.name});
Object.defineProperty(this, 'branch_directory', {value: this.branch_parent + path.sep + name});
Object.defineProperty(this, 'expand_keys', { value: repo_config['expand_keys'] === true });
Object.defineProperty(this, 'common_properties', { value: repo_config['common_properties']});
Object.defineProperty(this, 'include_branch_name', {
// If include_branch_name is not set, assume true. Otherwise, identity check the value against true.
value: repo_config['include_branch_name'] == undefined || repo_config['include_branch_name'] === true
Expand Down
17 changes: 17 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var fs = require('fs');
var properties = require ("properties");

/**
* Check to make sure the provided path is a writeable directory. Throw an exception if not.
Expand All @@ -23,3 +24,19 @@ module.exports.validate_writeable_directory = function(dir) {
throw new Error(dir + ' is not a directory');
}
};

var options = {
path: false,
variables: true
};

module.exports.load_properties = function (specific_file, common_file, cb){
properties.parse (common_file, options,
function (error, env){
if (error) return cb (error);
//Pass the common properties as external variables
options.vars = env;

properties.parse (specific_file, options, cb);
});
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"express": "~4.6.1",
"mkdirp": "0.5.0",
"rimraf": "2.2.8",
"underscore": "^1.8.0"
"underscore": "^1.8.0",
"properties": "1.2.1"
},
"devDependencies": {
"istanbul": "0.2.11",
Expand Down
Loading