summaryrefslogtreecommitdiffstats
path: root/crmsh/template.py
diff options
context:
space:
mode:
Diffstat (limited to 'crmsh/template.py')
-rw-r--r--crmsh/template.py183
1 files changed, 183 insertions, 0 deletions
diff --git a/crmsh/template.py b/crmsh/template.py
new file mode 100644
index 0000000..376f64b
--- /dev/null
+++ b/crmsh/template.py
@@ -0,0 +1,183 @@
+# Copyright (C) 2008-2011 Dejan Muhamedagic <dmuhamedagic@suse.de>
+# See COPYING for license information.
+
+import os
+import re
+from . import config
+from . import userdir
+from . import log
+
+
+logger = log.setup_logger(__name__)
+
+
+def get_var(l, key):
+ for s in l:
+ a = s.split()
+ if len(a) == 2 and a[0] == key:
+ return a[1]
+ return ''
+
+
+def chk_var(l, key):
+ for s in l:
+ a = s.split()
+ if len(a) == 2 and a[0] == key and a[1]:
+ return True
+ return False
+
+
+def chk_key(l, key):
+ for s in l:
+ a = s.split()
+ if len(a) >= 1 and a[0] == key:
+ return True
+ return False
+
+
+def validate_template(l):
+ 'Test for required stuff in a template.'
+ if not chk_var(l, '%name'):
+ logger.error("invalid template: missing '%name'")
+ return False
+ if not chk_key(l, '%generate'):
+ logger.error("invalid template: missing '%generate'")
+ return False
+ g = l.index('%generate')
+ if not (chk_key(l[0:g], '%required') or chk_key(l[0:g], '%optional')):
+ logger.error("invalid template: missing '%required' or '%optional'")
+ return False
+ return True
+
+
+def fix_tmpl_refs(l, ident, pfx):
+ for i, tmpl in enumerate(l):
+ l[i] = tmpl.replace(ident, pfx)
+
+
+def fix_tmpl_refs_re(l, regex, repl):
+ for i, tmpl in enumerate(l):
+ l[i] = re.sub(regex, repl, tmpl)
+
+
+class LoadTemplate(object):
+ '''
+ Load a template and its dependencies, generate a
+ configuration file which should be relatively easy and
+ straightforward to parse.
+ '''
+ edit_instructions = '''# Edit instructions:
+#
+# Add content only at the end of lines starting with '%%'.
+# Only add content, don't remove or replace anything.
+# The parameters following '%required' are not optional,
+# unlike those following '%optional'.
+# You may also add comments for future reference.'''
+ no_more_edit = '''# Don't edit anything below this line.'''
+
+ def __init__(self, name):
+ self.name = name
+ self.all_pre_gen = []
+ self.all_post_gen = []
+ self.all_pfx = []
+
+ def new_pfx(self, name):
+ i = 1
+ pfx = name
+ while pfx in self.all_pfx:
+ pfx = "%s_%d" % (name, i)
+ i += 1
+ self.all_pfx.append(pfx)
+ return pfx
+
+ def generate(self):
+ return '\n'.join(
+ ["# Configuration: %s" % self.name,
+ '',
+ self.edit_instructions,
+ '',
+ '\n'.join(self.all_pre_gen),
+ self.no_more_edit,
+ '',
+ '%generate',
+ '\n'.join(self.all_post_gen)])
+
+ def write_config(self, name):
+ try:
+ f = open("%s/%s" % (userdir.CRMCONF_DIR, name), "w")
+ except IOError as msg:
+ logger.error("open: %s", msg)
+ return False
+ print(self.generate(), file=f)
+ f.close()
+ return True
+
+ def load_template(self, tmpl):
+ try:
+ l = open(os.path.join(config.path.sharedir, 'templates', tmpl)).read().split('\n')
+ except IOError as msg:
+ logger.error("open: %s", msg)
+ return ''
+ if not validate_template(l):
+ return ''
+ logger.info("pulling in template %s", tmpl)
+ g = l.index('%generate')
+ pre_gen = l[0:g]
+ post_gen = l[g+1:]
+ name = get_var(pre_gen, '%name')
+ for s in l[0:g]:
+ if s.startswith('%depends_on'):
+ a = s.split()
+ if len(a) != 2:
+ logger.warning("%s: wrong usage", s)
+ continue
+ tmpl_id = a[1]
+ tmpl_pfx = self.load_template(a[1])
+ if tmpl_pfx:
+ fix_tmpl_refs(post_gen, '%'+tmpl_id, '%'+tmpl_pfx)
+ pfx = self.new_pfx(name)
+ fix_tmpl_refs(post_gen, '%_:', '%'+pfx+':')
+ # replace remaining %_, it may be useful at times
+ fix_tmpl_refs(post_gen, '%_', pfx)
+ v_idx = pre_gen.index('%required') or pre_gen.index('%optional')
+ pre_gen.insert(v_idx, '%pfx ' + pfx)
+ self.all_pre_gen += pre_gen
+ self.all_post_gen += post_gen
+ return pfx
+
+ def post_process(self, params):
+ pfx_re = '(%s)' % '|'.join(self.all_pfx)
+ for n in params:
+ fix_tmpl_refs(self.all_pre_gen, '%% '+n, "%% "+n+" "+params[n])
+ fix_tmpl_refs_re(self.all_post_gen,
+ '%' + pfx_re + '([^:]|$)', r'\1\2')
+ # process %if ... [%else] ... %fi
+ rmidx_l = []
+ if_seq = False
+ outcome = False # unnecessary, but to appease lints
+ for i in range(len(self.all_post_gen)):
+ s = self.all_post_gen[i]
+ if if_seq:
+ a = s.split()
+ if len(a) >= 1 and a[0] == '%fi':
+ if_seq = False
+ rmidx_l.append(i)
+ elif len(a) >= 1 and a[0] == '%else':
+ outcome = not outcome
+ rmidx_l.append(i)
+ else:
+ if not outcome:
+ rmidx_l.append(i)
+ continue
+ if not s:
+ continue
+ a = s.split()
+ if len(a) == 2 and a[0] == '%if':
+ outcome = not a[1].startswith('%') # not replaced -> false
+ if_seq = True
+ rmidx_l.append(i)
+ rmidx_l.reverse()
+ for i in rmidx_l:
+ del self.all_post_gen[i]
+
+# vim:ts=4:sw=4:et: