summaryrefslogtreecommitdiff
path: root/cloudinit/includer.py
diff options
context:
space:
mode:
Diffstat (limited to 'cloudinit/includer.py')
-rw-r--r--cloudinit/includer.py65
1 files changed, 65 insertions, 0 deletions
diff --git a/cloudinit/includer.py b/cloudinit/includer.py
new file mode 100644
index 00000000..d1022c5a
--- /dev/null
+++ b/cloudinit/includer.py
@@ -0,0 +1,65 @@
+import os
+import re
+
+from cloudinit import downloader as down
+from cloudinit import exceptions as excp
+from cloudinit import log as logging
+from cloudinit import shell as sh
+
+INCLUDE_PATT = re.compile("^#(opt_include|include)[ \t](.*)$", re.MULTILINE)
+OPT_PATS = ['opt_include']
+
+LOG = logging.getLogger(__name__)
+
+
+class Includer(object):
+
+ def __init__(self, root_fn, stack_limit=10):
+ self.root_fn = root_fn
+ self.stack_limit = stack_limit
+
+ def _read_file(self, fname):
+ return sh.read_file(fname)
+
+ def _read(self, fname, stack, rel):
+ if len(stack) >= self.stack_limit:
+ raise excp.StackExceeded("Stack limit of %s reached while including %s" % (self.stack_limit, fname))
+
+ canon_fname = self._canon_name(fname, rel)
+ if canon_fname in stack:
+ raise excp.RecursiveInclude("File %s recursively included" % (canon_fname))
+
+ stack.add(canon_fname)
+ new_rel = os.path.dirname(canon_fname)
+ contents = self._read_file(canon_fname)
+
+ def include_cb(match):
+ is_optional = (match.group(1).lower() in OPT_PATS)
+ fn = match.group(2).strip()
+ if not fn:
+ # Should we die??
+ return match.group(0)
+ else:
+ try:
+ LOG.debug("Including file %s", fn)
+ return self._read(fn, stack, new_rel)
+ except IOError:
+ if is_optional:
+ return ''
+ else:
+ raise
+
+ adjusted_contents = INCLUDE_PATT.sub(include_cb, contents)
+ stack.remove(fname)
+ return adjusted_contents
+
+ def _canon_name(self, fname, rel):
+ fname = fname.strip()
+ if not fname.startswith("/"):
+ fname = os.path.sep.join([rel, fname])
+ return os.path.realpath(fname)
+
+ def read(self, relative_to="."):
+ stack = set()
+ return self._read(self.root_fn, stack, rel=relative_to)
+