[Formed-commits] r393 - in trunk: . contrib
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Tue Aug 10 17:53:42 CEST 2010
Author: torsten
Date: 2010-08-10 17:53:42 +0200 (Tue, 10 Aug 2010)
New Revision: 393
Added:
trunk/contrib/diff_formed.py
Modified:
trunk/ChangeLog
Log:
Added helper script to diff to given formedtree files.
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2010-08-10 09:24:01 UTC (rev 392)
+++ trunk/ChangeLog 2010-08-10 15:53:42 UTC (rev 393)
@@ -1,3 +1,8 @@
+2010-08-10 Torsten Irländer <torsten.irlaender at intevation.de>
+
+ * contrib/diff_formed.py: New helperscript to diff to given
+ formedtrees
+
2010-08-09 Roland Geider <roland.geider at intevation.de>
* formed/model/exprtree.py: fixed typo
Added: trunk/contrib/diff_formed.py
===================================================================
--- trunk/contrib/diff_formed.py 2010-08-10 09:24:01 UTC (rev 392)
+++ trunk/contrib/diff_formed.py 2010-08-10 15:53:42 UTC (rev 393)
@@ -0,0 +1,222 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/python
+"""\n
+Diffs to given formedtrees. Note that currently no checks on external choice
+lists are done. Furter checks on Repeatgroups are very simple for now.
+Warning: If a field with the same name is moved from master_tbl into a RG, it will not be
+noticed, as we do not diff strutural changes.
+
+Usage: diff_formed.py old new
+
+Options:
+ -h / --help Print this message and exit.
+ -e / --elements comma-seperated list of elements to check
+ --check-attributes Check changes in attributes (changed descriptions, target...)
+
+"""
+# 20100810 Torsten Irlaender <torsten.irlaender at intevation.de>
+#
+# This program is free software under the GNU GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+
+import sys
+import getopt
+import logging
+
+from lxml import etree
+
+logging.basicConfig(level=logging.ERROR)
+log = logging.getLogger('diff_formed')
+
+class AttributeChangeException(Exception):
+ def __init__(self, n, c, d):
+ self.new = n
+ self.changed = c
+ self.deleted = d
+
+ msg = []
+ if self.new:
+ msg.append('New: %s' % ",".join(self.new))
+ if self.changed:
+ msg.append('Changed: %s' % ",".join(self.changed))
+ if self.deleted:
+ msg.append('Deleted: %s' % ",".join(self.deleted))
+ self.message = " | ".join(msg)
+
+class Inspector():
+
+ def __init__(self, filename_old, filename_new):
+
+ self.old_xml_doc = None
+ self.new_xml_doc = None
+ self.elements_old = {}
+ self.elements_new = {}
+ self.elements = ['choice', 'text', 'textarea', 'repeat']
+
+ # Open files and load xml
+ try:
+ f1 = None
+ f2 = None
+ log.debug('Old: %s'% filename_old)
+ f1 = open(filename_old, "r")
+ log.debug('New: %s'% filename_new)
+ f2 = open(filename_new, "r")
+ self.old_xml_doc = etree.parse(f1)
+ self.new_xml_doc = etree.parse(f2)
+ except:
+ log.exception('Error while opening file')
+ finally:
+ if f1 is not None:
+ f1.close()
+ if f2 is not None:
+ f2.close()
+
+ def perform(self, elements=None, check_attributes=False):
+ log.info('Only checking %s elements' % ",".join(elements))
+ for element in self.elements:
+ if elements is not None:
+ if element not in elements: continue
+ self.elements_old[element] = []
+ self.elements_new[element] = []
+ for e in self.old_xml_doc.findall("//%s" % element):
+ self.elements_old[element].append(e)
+ for e in self.new_xml_doc.findall("//%s" % element):
+ self.elements_new[element].append(e)
+ self.diff_element(element, check_attributes)
+
+ def diff_element(self, element, check_attributes):
+ log.debug('Checking %s elements' % element)
+ out = []
+
+ # Search for old field in new
+ for o in self.elements_old.get(element):
+ error = []
+ name = o.attrib.get('name')
+ found = False
+ for n in self.elements_new.get(element):
+ if name == n.attrib.get('name'):
+ found = True
+ try:
+ if check_attributes:
+ self.diff_attributes(o, n)
+ except AttributeChangeException, e:
+ error.append("Attributes changed for '%s': %s" % (name, e.message))
+ if element == 'choice':
+ error.extend(self.diff_choicelist(o, n, check_attributes))
+ break
+ if not found:
+ error.append("Deleted")
+
+ if error:
+ out.append("Field: %s (%s)" % (name, element))
+ out.append('---')
+ out.append('Changes:')
+ for num, err in enumerate(error):
+ out.append('%s. %s' % (num, err))
+ out.append('===')
+
+ # Searching for new fields in old
+ for o in self.elements_new.get(element):
+ error = []
+ name = o.attrib.get('name')
+ # Search for element in new
+ found = False
+ for n in self.elements_old.get(element):
+ if name == n.attrib.get('name'):
+ found = True
+ break
+ if not found:
+ error.append("New")
+
+ if error:
+ out.append("Field: %s (%s)" % (name, element))
+ out.append('---')
+ out.append('Changes:')
+ for num, err in enumerate(error):
+ out.append('%s. %s' % (num, err))
+ out.append('===')
+
+ for o in out:
+ print unicode(o).encode("utf-8")
+
+ def diff_choicelist(self, o, n, check_attributes):
+ old = {}
+ new = {}
+ errors = []
+ for c in o.getchildren():
+ old[c.attrib.get('value')] = c
+ for c in n.getchildren():
+ new[c.attrib.get('value')] = c
+
+ for key in old.keys():
+ if new.has_key(key):
+ try:
+ if check_attributes:
+ self.diff_attributes(old.get(key), new.get(key))
+ except AttributeChangeException, e:
+ errors.append("Attributes changed for '%s': %s " % (key, e.message) )
+ else:
+ errors.append("Deleted option: '%s' value: '%s'" % (old.get(key).attrib.get('description'), key))
+ for key in new.keys():
+ if not old.has_key(key):
+ errors.append("New option: '%s' value: '%s'" % (new.get(key).attrib.get('description'), key))
+
+ return errors
+
+ def diff_attributes(self, o, n):
+ ok = False
+ new = []
+ changed = []
+ deleted = []
+ for key, value in o.attrib.iteritems():
+ if n.attrib.has_key(key):
+ if n.get(key) == value:
+ pass #Ok
+ else:
+ changed.append(key)
+ else:
+ deleted.append(key)
+ for key, value in n.attrib.iteritems():
+ if not o.attrib.has_key(key):
+ new.append(key)
+
+ if len(new) > 0 or len(changed) > 0 or len(deleted) > 0:
+ raise AttributeChangeException(new, changed, deleted)
+
+def usage(code, msg=''):
+ print >> sys.stderr, __doc__
+ if msg:
+ print >> sys.stderr, msg
+ sys.exit(code)
+
+def main():
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'hvVe:',
+ ['elements=', 'check-attributes'])
+
+ except getopt.error, msg:
+ usage(1, msg)
+
+ elements = None
+ check_attributes = False
+ for opt, arg in opts:
+ if opt in ('-v'):
+ log.setLevel(logging.INFO)
+ if opt in ('-V'):
+ log.setLevel(logging.DEBUG)
+ if opt in ('-h', '--help'):
+ usage(0)
+ if opt in ('-e', '--elements'):
+ elements = arg.split(',')
+ log.debug('Elements: %s' % elements)
+ if opt in ('--check-attributes'):
+ check_attributes = True
+ if len(args) < 2:
+ usage(1)
+
+ ins = Inspector(args[0], args[1])
+ ins.perform(elements, check_attributes)
+
+if __name__ == '__main__':
+ main()
More information about the Formed-commits
mailing list