summaryrefslogtreecommitdiff
path: root/reconfigure/includers
diff options
context:
space:
mode:
Diffstat (limited to 'reconfigure/includers')
-rw-r--r--reconfigure/includers/__init__.py14
-rw-r--r--reconfigure/includers/auto.py68
-rw-r--r--reconfigure/includers/base.py21
-rw-r--r--reconfigure/includers/bind9.py11
-rw-r--r--reconfigure/includers/nginx.py11
-rw-r--r--reconfigure/includers/supervisor.py11
6 files changed, 136 insertions, 0 deletions
diff --git a/reconfigure/includers/__init__.py b/reconfigure/includers/__init__.py
new file mode 100644
index 0000000..1128588
--- /dev/null
+++ b/reconfigure/includers/__init__.py
@@ -0,0 +1,14 @@
+from base import BaseIncluder
+from auto import AutoIncluder
+from bind9 import BIND9Includer
+from nginx import NginxIncluder
+from supervisor import SupervisorIncluder
+
+
+__all__ = [
+ 'BaseIncluder',
+ 'AutoIncluder',
+ 'BIND9Includer',
+ 'NginxIncluder',
+ 'SupervisorIncluder',
+]
diff --git a/reconfigure/includers/auto.py b/reconfigure/includers/auto.py
new file mode 100644
index 0000000..16844ca
--- /dev/null
+++ b/reconfigure/includers/auto.py
@@ -0,0 +1,68 @@
+from base import BaseIncluder
+from reconfigure.nodes import *
+import glob
+import os
+
+
+class AutoIncluder (BaseIncluder):
+ """
+ This base includer automatically walks the node tree and loads the include files from ``IncludeNode.files`` properties. ``files`` is supposed to contain absolute path, relative path or a shell wildcard.
+ """
+
+ def compose(self, origin, tree):
+ self.compose_rec(origin, origin, tree)
+ return tree
+
+ def compose_rec(self, root, origin, node):
+ if not node.origin:
+ node.origin = origin
+ for child in node.children:
+ self.compose_rec(root, origin, child)
+ for child in node.children:
+ spec = self.is_include(child)
+ if spec:
+ files = spec
+ if node.origin and not files.startswith('/'):
+ files = os.path.join(os.path.split(root)[0], files)
+ if '*' in files or '.' in files:
+ files = glob.glob(files)
+ else:
+ files = [files]
+ for file in files:
+ if file in self.content_map:
+ content = self.content_map[file]
+ else:
+ content = open(file, 'r').read()
+ subtree = self.parser.parse(content)
+ node.children.extend(subtree.children)
+ self.compose_rec(root, file, subtree)
+ node.children[node.children.index(child)] = IncludeNode(spec)
+
+ def decompose(self, tree):
+ result = {}
+ result[tree.origin] = self.decompose_rec(tree, result)
+ return result
+
+ def decompose_rec(self, node, result):
+ for child in node.children:
+ if child.__class__ == IncludeNode:
+ replacement = self.remove_include(child)
+ if replacement:
+ node.children[node.children.index(child)] = replacement
+ else:
+ if child.origin != node.origin:
+ node.children.remove(child)
+ result.setdefault(child.origin, RootNode()).children.append(self.decompose_rec(child, result))
+ else:
+ self.decompose_rec(child, result)
+ return node
+
+ def is_include(self, node):
+ """
+ Should return whether the node is an include node and return file pattern glob if it is
+ """
+
+ def remove_include(self, node):
+ """
+ Shoud transform :class:`reconfigure.nodes.IncludeNode` into a normal Node to be stringified into the file
+ """
diff --git a/reconfigure/includers/base.py b/reconfigure/includers/base.py
new file mode 100644
index 0000000..e0512bf
--- /dev/null
+++ b/reconfigure/includers/base.py
@@ -0,0 +1,21 @@
+class BaseIncluder (object): # pragma: no cover
+ """
+ A base includer class
+
+ :param parser: Parser instance that was used to parse the root config file
+ :param content_map: a dict that overrides config content for specific paths
+ """
+
+ def __init__(self, parser=None, content_map={}):
+ self.parser = parser
+ self.content_map = content_map
+
+ def compose(self, origin, tree):
+ """
+ Should locate the include nodes in the Node tree, replace them with :class:`reconfigure.nodes.IncludeNode`, parse the specified include files and append them to tree, with correct node ``origin`` attributes
+ """
+
+ def decompose(self, origin, tree):
+ """
+ Should detach the included subtrees from the Node tree and return a ``{ origin: content-node-tree }`` dict.
+ """
diff --git a/reconfigure/includers/bind9.py b/reconfigure/includers/bind9.py
new file mode 100644
index 0000000..6a1e08c
--- /dev/null
+++ b/reconfigure/includers/bind9.py
@@ -0,0 +1,11 @@
+from reconfigure.includers.auto import AutoIncluder
+from reconfigure.nodes import PropertyNode
+
+
+class BIND9Includer (AutoIncluder):
+ def is_include(self, node):
+ if isinstance(node, PropertyNode) and node.name == 'include':
+ return node.value.strip('"')
+
+ def remove_include(self, node):
+ return PropertyNode('include', '"%s"' % node.files)
diff --git a/reconfigure/includers/nginx.py b/reconfigure/includers/nginx.py
new file mode 100644
index 0000000..f9c1c9b
--- /dev/null
+++ b/reconfigure/includers/nginx.py
@@ -0,0 +1,11 @@
+from reconfigure.includers.auto import AutoIncluder
+from reconfigure.nodes import PropertyNode
+
+
+class NginxIncluder (AutoIncluder):
+ def is_include(self, node):
+ if isinstance(node, PropertyNode) and node.name == 'include':
+ return node.value
+
+ def remove_include(self, node):
+ return PropertyNode('include', node.files)
diff --git a/reconfigure/includers/supervisor.py b/reconfigure/includers/supervisor.py
new file mode 100644
index 0000000..2314cd9
--- /dev/null
+++ b/reconfigure/includers/supervisor.py
@@ -0,0 +1,11 @@
+from reconfigure.includers.auto import AutoIncluder
+from reconfigure.nodes import Node, PropertyNode
+
+
+class SupervisorIncluder (AutoIncluder):
+ def is_include(self, node):
+ if node.name == 'include':
+ return node.get('files').value
+
+ def remove_include(self, node):
+ return Node('include', children=[PropertyNode('files', node.files)])