/[formed]/trunk/contrib/diff_formed.py
ViewVC logotype

Contents of /trunk/contrib/diff_formed.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 395 - (show annotations)
Thu Aug 12 10:03:17 2010 UTC (14 years, 6 months ago) by torsten
File MIME type: text/x-python
File size: 8772 byte(s)
Updated help

1 # -*- coding: utf-8 -*-
2 #!/usr/bin/python
3 """\n
4 Diffs to given formedtrees. Note that currently no checks on external choice
5 lists are done. Furter checks on Repeatgroups are very simple for now.
6 Warning: If a field with the same name is moved from master_tbl into a RG, it will not be
7 noticed, as we do not diff strutural changes.
8
9 Usage: diff_formed.py old new
10
11 Options:
12 -h / --help Print this message and exit.
13 -e / --elements comma-seperated list of elements to check
14 -s / --subtree Define subtree as root for checks
15 -f / --fields comma-seperated list of element-name to check
16 --check-attributes Check changes in attributes (changed descriptions, target...)
17
18 """
19 # 20100810 Torsten Irlaender <[email protected]>
20 #
21 # This program is free software under the GNU GPL (>=v2)
22 # Read the file COPYING coming with the software for details.
23
24
25 import sys
26 import getopt
27 import logging
28
29 from lxml import etree
30
31 logging.basicConfig(level=logging.ERROR)
32 log = logging.getLogger('diff_formed')
33
34 class AttributeChangeException(Exception):
35 def __init__(self, n, c, d):
36 self.new = n
37 self.changed = c
38 self.deleted = d
39
40 msg = []
41 if self.new:
42 msg.append('New: %s' % ",".join(self.new))
43 if self.changed:
44 msg.append('Changed: %s' % ",".join(self.changed))
45 if self.deleted:
46 msg.append('Deleted: %s' % ",".join(self.deleted))
47 self.message = " | ".join(msg)
48
49 class Inspector():
50
51 def __init__(self, filename_old, filename_new):
52
53 self.old_xml_doc = None
54 self.new_xml_doc = None
55 self.elements_old = {}
56 self.elements_new = {}
57 self.elements = ['choice', 'text', 'textarea', 'repeat']
58
59 # Open files and load xml
60 try:
61 f1 = None
62 f2 = None
63 log.debug('Old: %s'% filename_old)
64 f1 = open(filename_old, "r")
65 log.debug('New: %s'% filename_new)
66 f2 = open(filename_new, "r")
67 self.old_xml_doc = etree.parse(f1)
68 self.new_xml_doc = etree.parse(f2)
69 except:
70 log.exception('Error while opening file')
71 finally:
72 if f1 is not None:
73 f1.close()
74 if f2 is not None:
75 f2.close()
76
77 def perform(self, elements=None, subtree=None, fields=None, check_attributes=False):
78 log.info('Only checking %s elements' % ",".join(elements or ['all']))
79 for element in self.elements:
80 if elements is not None:
81 if element not in elements: continue
82 self.elements_old[element] = []
83 self.elements_new[element] = []
84 if subtree:
85 needle = '//*[@name="%s"]//%s' % (subtree, element)
86 else:
87 needle = '//%s' % (element)
88 log.debug("Searching for %s" % needle)
89 for e in self.old_xml_doc.findall(needle):
90 if fields is not None:
91 name = e.attrib.get('name')
92 if str(name ) not in fields:
93 log.debug('Old: Not found %s in %s' % (name, fields))
94 continue
95 self.elements_old[element].append(e)
96 for e in self.new_xml_doc.findall(needle):
97 if fields is not None:
98 name = e.attrib.get('name')
99 if str(name )not in fields:
100 log.debug('New: Not found %s in %s' % (name, fields))
101 continue
102 self.elements_new[element].append(e)
103 self.diff_element(element, check_attributes)
104
105 def diff_element(self, element, check_attributes):
106 log.debug('Checking %s elements' % element)
107 out = []
108
109 # Search for old field in new
110 for o in self.elements_old.get(element):
111 error = []
112 name = o.attrib.get('name')
113 found = False
114 for n in self.elements_new.get(element):
115 if name == n.attrib.get('name'):
116 found = True
117 try:
118 if check_attributes:
119 self.diff_attributes(o, n)
120 except AttributeChangeException, e:
121 error.append("Attributes changed for '%s': %s" % (name, e.message))
122 if element == 'choice':
123 error.extend(self.diff_choicelist(o, n, check_attributes))
124 break
125 if not found:
126 error.append("Deleted")
127
128 if error:
129 out.append("Field: %s (%s)" % (name, element))
130 out.append('---')
131 out.append('Changes:')
132 for num, err in enumerate(error):
133 out.append('%s. %s' % (num, err))
134 out.append('===')
135
136 # Searching for new fields in old
137 for o in self.elements_new.get(element):
138 error = []
139 name = o.attrib.get('name')
140 # Search for element in new
141 found = False
142 for n in self.elements_old.get(element):
143 if name == n.attrib.get('name'):
144 found = True
145 break
146 if not found:
147 error.append("New")
148 if element == 'choice':
149 error.extend(self.diff_choicelist(None, o, check_attributes))
150
151 if error:
152 out.append("Field: %s (%s)" % (name, element))
153 out.append('---')
154 out.append('Changes:')
155 for num, err in enumerate(error):
156 out.append('%s. %s' % (num, err))
157 out.append('===')
158
159 for o in out:
160 print unicode(o).encode("utf-8")
161
162 def diff_choicelist(self, o, n, check_attributes):
163 old = {}
164 new = {}
165 errors = []
166 if o is not None:
167 for c in o.findall('.//bool'):
168 old[c.attrib.get('value')] = c
169 if n is not None:
170 for c in n.findall('.//bool'):
171 new[c.attrib.get('value')] = c
172
173 for key in old.keys():
174 if new.has_key(key):
175 try:
176 if check_attributes:
177 self.diff_attributes(old.get(key), new.get(key))
178 except AttributeChangeException, e:
179 errors.append("Attributes changed for '%s': %s " % (key, e.message) )
180 else:
181 errors.append("Deleted option: '%s' value: '%s'" % (old.get(key).attrib.get('description'), key))
182 for key in new.keys():
183 if not old.has_key(key):
184 errors.append("New option: '%s' value: '%s'" % (new.get(key).attrib.get('description'), key))
185
186 return errors
187
188 def diff_attributes(self, o, n):
189 ok = False
190 new = []
191 changed = []
192 deleted = []
193 for key, value in o.attrib.iteritems():
194 if n.attrib.has_key(key):
195 if n.get(key) == value:
196 pass #Ok
197 else:
198 changed.append(key)
199 else:
200 deleted.append(key)
201 for key, value in n.attrib.iteritems():
202 if not o.attrib.has_key(key):
203 new.append(key)
204
205 if len(new) > 0 or len(changed) > 0 or len(deleted) > 0:
206 raise AttributeChangeException(new, changed, deleted)
207
208 def usage(code, msg=''):
209 print >> sys.stderr, __doc__
210 if msg:
211 print >> sys.stderr, msg
212 sys.exit(code)
213
214 def main():
215 try:
216 opts, args = getopt.getopt(sys.argv[1:], 'hvVe:s:f:',
217 ['elements=', 'check-attributes', 'subtree=', 'fields='])
218
219 except getopt.error, msg:
220 usage(1, msg)
221
222 elements = None
223 subtree = None
224 fields = None
225 check_attributes = False
226 for opt, arg in opts:
227 if opt in ('-v'):
228 log.setLevel(logging.INFO)
229 if opt in ('-V'):
230 log.setLevel(logging.DEBUG)
231 if opt in ('-h', '--help'):
232 usage(0)
233 if opt in ('-e', '--elements'):
234 elements = arg.split(',')
235 log.debug('Elements: %s' % elements)
236 if opt in ('-s', '--subtree'):
237 subtree = arg
238 log.debug('Subtree: %s' % subtree)
239 if opt in ('-f', '--fields'):
240 fields = arg.split(',')
241 log.debug('Fields: %s' % fields)
242 if opt in ('--check-attributes'):
243 check_attributes = True
244 if len(args) < 2:
245 usage(1)
246
247 ins = Inspector(args[0], args[1])
248 ins.perform(elements, subtree, fields, check_attributes)
249
250 if __name__ == '__main__':
251 main()

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26