summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris West (Faux) <git@goeswhere.com>2015-10-01 20:31:42 +0100
committerChris West (Faux) <git@goeswhere.com>2015-10-01 20:31:42 +0100
commitf741591d203f59faf6e041cbc6b6974ad2246144 (patch)
tree837fab3395d7b7d5bbbd4e7040a344ac7e8faddd
downloadghetto-json-f741591d203f59faf6e041cbc6b6974ad2246144.tar.gz
ghetto-json-f741591d203f59faf6e041cbc6b6974ad2246144.tar.bz2
ghetto-json-f741591d203f59faf6e041cbc6b6974ad2246144.tar.xz
ghetto-json-f741591d203f59faf6e041cbc6b6974ad2246144.zip
initial commit
-rw-r--r--README.md79
-rwxr-xr-xghetto_json53
-rwxr-xr-xtest.sh8
3 files changed, 140 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a37640f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,79 @@
+ghetto_json
+===========
+
+Need a quick way to edit a JSON file in Ansible? Ansible has great built-in support for
+ ini files, but a number of more modern applications are using JSON for config files.
+
+ghetto_json lets you make some types of edits to JSON files, and remains simple enough that
+ it's hopefully easier just to extend than to switch to a different module, and you won't feel
+ too guilty just copy-pasting it into your codebase.
+
+
+Installation
+------------
+
+Drop ``ghetto_json`` into your playbook's ``library`` folder,
+ which can be [configured](https://docs.ansible.com/ansible/intro_configuration.html#library)
+ but defaults to ``./library`` inside a playbook.
+
+Synopsis
+--------
+
+Make in-place changes to simple JSON documents,
+ without having to resort to ``replace``.
+
+
+Requirements
+------------
+
+Python 2.7 may be required for some ``shlex`` functionality
+ (like working Unicode), which you probably don't care about.
+
+
+Options
+-------
+
+#### path:
+
+The file on the target to edit.
+
+#### all other options:
+
+A very simple object notation for the location of the property to edit,
+ and its new value.
+
+Mandatory automatic conversion will be applied. Supported values:
+
+ * integers (``5``, ``-17``)
+ * ``true`` / ``false``
+ * ``null``
+ * ``unset`` will delete the key
+
+
+Examples
+--------
+
+For the example JSON document ``/foo/bar.json`` containing:
+````
+{ "a": 5, "b": {"c": 6, "d": "hello" } }
+````
+
+...you can run an invocation like:
+````
+ - ghetto_json:
+ path=/foo/bar.json
+ a=7
+ b.c=yellow
+ b.d=unset
+````
+
+...and the file will be left looking like:
+
+````
+{
+ "a": 7,
+ "b": {
+ "c": "yellow"
+ }
+}
+````
diff --git a/ghetto_json b/ghetto_json
new file mode 100755
index 0000000..075accb
--- /dev/null
+++ b/ghetto_json
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+import json
+import sys
+import shlex
+
+
+def main(params_list):
+ params = dict(x.split("=", 2) for x in params_list)
+ path = params.pop('path')
+ changed = False
+
+ with open(path) as f:
+ obj = json.load(f)
+ for (key, target) in params.items():
+ parts = key.split('.')
+ ref = obj
+ for part in parts[:-1]:
+ if part not in ref:
+ ref[part] = {}
+ ref = ref[part]
+
+ last_part = parts[-1]
+ if target == 'unset':
+ if last_part in ref:
+ del ref[last_part]
+ changed = True
+ else:
+ if target.isdigit():
+ target = int(target)
+ if target == 'null':
+ target = None
+ if target == 'false':
+ target = False
+ if target == 'true':
+ target = True
+ if last_part not in ref or ref[last_part] != target:
+ ref[last_part] = target
+ changed = True
+
+ if changed:
+ with open(path, 'w') as f:
+ json.dump(obj, f, indent=2, separators=(',', ': '), sort_keys=True)
+
+ print(json.dumps({'changed': changed}))
+
+
+if __name__ == '__main__':
+ if len(sys.argv) == 2:
+ main(shlex.split(open(sys.argv[1]).read()))
+ else:
+ main(sys.argv[1:])
+
diff --git a/test.sh b/test.sh
new file mode 100755
index 0000000..76e4e12
--- /dev/null
+++ b/test.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -eu
+T=$(mktemp)
+trap "rm $T" EXIT
+echo '{ "a": 5, "b": {"c": 6, "d": "hello" } }' > $T
+python ghetto_json path=$T a=7 b.c=yellow b.d=unset
+diff -u <(printf '{\n "a": 7,\n "b": {\n "c": "yellow"\n }\n}') $T
+