root/gaphor/tags/gaphor-0.12.3/utils/compare.py

Revision 1898, 6.7 kB (checked in by wrobe..@pld-linux.org, 1 year ago)

- move future declaratio at the begining of file (python 2.5

syntax requirement)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 #!/usr/bin/env python
2 # vim:sw=4:et:
3 """Report differences in two Gaphor models.
4
5 This can be called as:
6     python compare.py model1.gaphor model2.gaphor
7
8 This file is part of Gaphor.
9 """
10
11 from __future__ import generators
12
13 __all__ = ['Compare']
14
15 try:
16     import env
17 except ImportError:
18     pass
19
20 import gaphor.parser
21 import gaphor.storage
22 import gaphor.UML
23
24 class Compare(object):
25     """This class makes it possible to compare two files.
26     By default reports are printed to stdout in a diff-like syntax.
27     """
28
29     def __init__(self, filename1, filename2):
30         self.filename1 = filename1
31         self.filename2 = filename2
32
33         self.elements1, self.factory1 = self.load(self.filename1)
34         self.elements2, self.factory2 = self.load(self.filename2)
35
36         self.show_id = True
37
38     def out(self, msg):
39         """Print a message generated by report().
40         """
41         print msg
42    
43     def report(self, factory, element, name=None, value=None, isref=False):
44         """Report an element that has differences.
45         The attribute show_id can be set to False to suppress element ids.
46         A fancy diff message is send to method out(msg).
47         """
48         if factory is self.factory1:
49             msg = '-'
50         else:
51             msg = '+'
52        
53         if isinstance(element, gaphor.parser.canvas):
54             msg += ' <canvas>:'
55         else:
56             if self.show_id:
57                 msg += ' %s' % element.id
58             n = element.get('name')
59             if n:
60                 msg += ' (%s)' % n
61             if self.show_id or n:
62                 msg += ':'
63
64         msg += ' %s' % (isinstance(element, gaphor.parser.canvas) and 'Canvas' or element.type)
65
66         if name:
67             msg += '.%s' % name
68             if value:
69                 if isref:
70                     if self.show_id:
71                         msg += ' = %s' % value
72                     obj = factory.lookup(value)
73                     if hasattr(obj, 'name'):
74                         msg += ' (%s)' % obj.name
75                 else:
76                     msg += ' = %s' % value
77
78         self.out(msg)
79
80     def load(self, filename):
81         """Load the model file and create a factory.
82         A tuple (elements, factory) is returned.
83         """
84         elements = gaphor.parser.parse(filename)
85         factory = gaphor.UML.ElementFactory()
86         try:
87             gaphor.storage.load_elements(elements, factory)
88         except Exception, e:
89             self.out('! File %s could not be loaded completely.' % filename)
90             self.out('! Trying to diff on parsed elements only.')
91             self.out(e)
92         return elements, factory
93
94     def elements_in_both_files(self):
95         """Generator function that returns tuples (element1, element2) of
96         elements that exist in both files (they have the same id).
97         """
98         vals = []
99         for key1, val1 in self.elements1.iteritems():
100             val2 = self.elements2.get(key1)
101             if val2:
102                 yield (val1, val2)
103
104     def check_missing_elements(self):
105         """Report elements that exist in one factory, but not in the other.
106         """
107         keys1 = self.elements1.keys()
108         keys2 = self.elements2.keys()
109         for key in keys1:
110             if key not in keys2:
111                 self.report(self.factory1, self.elements1[key])
112
113         for key in keys2:
114             if key not in keys1:
115                 self.report(self.factory2, self.elements2[key])
116
117     def check_missing_references(self, element1, element2):
118         """Report references to other elements that are present in one
119         element and not in the other one.
120         """
121         keys1 = element1.references.keys()
122         keys2 = element2.references.keys()
123         for key in keys1:
124             if key not in keys2:
125                 self.report(self.factory1, element1, key)
126
127         for key in keys2:
128             if key not in keys1:
129                 self.report(self.factory2, element2, key)
130
131     def check_differences_references(self, element1, element2):
132         keys1 = element1.references.keys()
133         keys2 = element2.references.keys()
134         for key in keys1:
135             if key in keys2:
136                 val1 = element1.references.get(key)
137                 val2 = element2.references.get(key)
138                 try:
139                     for val in val1:
140                         if val not in val2:
141                             self.report(self.factory1, element1, key, val, True)
142
143                     for val in val2:
144                         if val not in val1:
145                             self.report(self.factory2, element2, key, val, True)
146                 except TypeError:
147                     if val1 != val2:
148                         self.report(self.factory1, element1, key, val1, True)
149                         self.report(self.factory2, element2, key, val2, True)
150
151     def check_missing_values(self, element1, element2):
152         keys1 = element1.values.keys()
153         keys2 = element2.values.keys()
154         for key in keys1:
155             if key not in keys2:
156                 self.report(self.factory1, element1, key)
157
158         for key in keys2:
159             if key not in keys1:
160                 self.report(self.factory2, element2, key)
161
162     def check_differences_values(self, element1, element2):
163         keys1 = element1.values.keys()
164         keys2 = element2.values.keys()
165         for key in keys1:
166             if key in keys2:
167                 val1 = element1.values.get(key)
168                 val2 = element2.values.get(key)
169                 if val1 != val2:
170                     self.report(self.factory1, element1, key, val1)
171                     self.report(self.factory2, element2, key, val2)
172
173
174     def compare(self):
175         """Start the comparison of the files provided to the constructor.
176         """
177         self.check_missing_elements()
178
179         for element1, element2 in self.elements_in_both_files():
180             self.check_missing_references(element1, element2)
181             self.check_differences_references(element1, element2)
182             self.check_missing_values(element1, element2)
183             self.check_differences_values(element1, element2)
184
185 if __name__ == '__main__':
186     import sys
187
188     usage = "usage: %s [-v][-h|--help] old_model new_model" % sys.argv[0]
189     files = []
190     show_id = False
191
192     # Parse command line arguments:
193     for arg in sys.argv[1:]:
194         if arg.startswith('-'):
195             if arg == '-v':
196                 show_id = True
197             elif arg in ('-h', '--help'):
198                 print usage
199                 sys.exit(0)
200             else:
201                 print '%s: invalid option "%s".' % (sys.argv[0], arg)
202                 print usage
203                 sys.exit(1)
204         else:
205             files.append(arg)
206
207     if len(files) != 2:
208         print usage
209         sys.exit(1)
210
211     c = Compare(files[0], files[1])
212     c.show_id = show_id
213     c.compare()
214
Note: See TracBrowser for help on using the browser.