1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16  """ 
 17  Differ classes 
 18  """ 
 19  __author__    = "André Malo" 
 20  __docformat__ = "epytext en" 
 21  __all__       = ["InternalDiffer", "ExternalDiffer"] 
 22   
 23   
 25      """ Differ without an external program call (uses difflib) """ 
 26   
 28          """ Initialization """ 
 29          pass 
  30   
 31   
 32 -    def getStringDiff(self, string1, string2, label1, label2 = None, 
 33                        date1 = "", date2 = ""): 
  34          """ creates a diff of two line based strings 
 35   
 36              If a string is C{None}, it's treated as "" 
 37   
 38              @param string1: First string 
 39              @type string1: C{str} 
 40   
 41              @param string2: Second string 
 42              @type string2: C{str} 
 43   
 44              @param label1: Label for first data 
 45              @type label1: C{str} 
 46   
 47              @param label2: Label for second data 
 48              @type label2: C{str} 
 49   
 50              @param date1: Date description for first data 
 51              @type date1: C{str} 
 52   
 53              @param date2: Date description for second data 
 54              @type date2: C{str} 
 55   
 56              @return: unified diff lines (maybe a generator) 
 57              @rtype: iterable 
 58          """ 
 59          import difflib 
 60   
 61          list1 = (string1 or "").splitlines(True) 
 62          list2 = (string2 or "").splitlines(True) 
 63          if not (list1 or list2): 
 64              list1 = list2 = [""] 
 65   
 66          return difflib.unified_diff( 
 67              list1, list2, label1, label2 or label1, date1, date2, 
 68          ) 
  69   
 70   
 71 -    def getFileDiff(self, name1, name2, label1, label2 = None, 
 72                      date1 = "", date2 = ""): 
  73          """ creates a diff of two line based files 
 74   
 75              @param name1: First file name 
 76              @type name1: C{str} 
 77   
 78              @param name2: Second file name 
 79              @type name2: C{str} 
 80   
 81              @param label1: Label for first data 
 82              @type label1: C{str} 
 83   
 84              @param label2: Label for second data 
 85              @type label2: C{str} 
 86   
 87              @param date1: Date description for first data 
 88              @type date1: C{str} 
 89   
 90              @param date2: Date description for second data 
 91              @type date2: C{str} 
 92   
 93              @return: unified diff lines (maybe a generator) 
 94              @rtype: iterable 
 95          """ 
 96          import difflib 
 97   
 98          list1 = file(name1, "rb").readlines() 
 99          list2 = file(name2, "rb").readlines() 
100          if not (list1 or list2): 
101              list1 = list2 = [""] 
102   
103          return difflib.unified_diff( 
104              list1, list2, label1, label2 or label1, date1, date2, 
105          ) 
  106   
107   
109      """ Differ which calls an external program (e.g. diff) 
110   
111          @ivar _diff_command: The diff command line 
112          @type _diff_command: C{list} 
113   
114          @ivar _tempdir: The tempdir to use for string diffs 
115          @type _tempdir: C{str} 
116      """ 
117   
118 -    def __init__(self, diff_command, tempdir = None): 
 119          """ Initialization 
120   
121              @param diff_command: The diff command to call 
122              @type diff_command: C{list} 
123   
124              @param tempdir: The tempdir to use for string diffs 
125              @type tempdir: C{str} 
126          """ 
127          self._diff_command = diff_command 
128          self._tempdir = tempdir 
 129   
130   
131 -    def getStringDiff(self, string1, string2, label1, label2 = None, 
132                        date1 = "", date2 = ""): 
 133          """ creates a diff of two line based strings 
134   
135              If a string is C{None}, it's treated as "" 
136   
137              @param string1: First string 
138              @type string1: C{str} 
139   
140              @param string2: Second string 
141              @type string2: C{str} 
142   
143              @param label1: Label for first data 
144              @type label1: C{str} 
145   
146              @param label2: Label for second data 
147              @type label2: C{str} 
148   
149              @param date1: Date description for first data 
150              @type date1: C{str} 
151   
152              @param date2: Date description for second data 
153              @type date2: C{str} 
154   
155              @return: unified diff lines (maybe a generator) 
156              @rtype: iterable 
157          """ 
158          from svnmailer import util 
159   
160          string1 = string1 or "" 
161          string2 = string2 or "" 
162   
163          file1 = util.TempFile(self._tempdir) 
164          file1.fp.write(string1) 
165          file1.close() 
166   
167          file2 = util.TempFile(self._tempdir) 
168          file2.fp.write(string2) 
169          file2.close() 
170   
171          pipe = self._getPipe( 
172              file1.name, file2.name, label1, label2, date1, date2 
173          ) 
174   
175           
176          line = pipe.fromchild.readline() 
177          while line: 
178              yield line 
179              line = pipe.fromchild.readline() 
180   
181          pipe.fromchild.close() 
182          pipe.wait() 
 183   
184   
185 -    def getFileDiff(self, name1, name2, label1, label2 = None, 
186                      date1 = "", date2 = ""): 
 187          """ creates a diff of two line based files 
188   
189              @param name1: First file name 
190              @type name1: C{str} 
191   
192              @param name2: Second file name 
193              @type name2: C{str} 
194   
195              @param label1: Label for first data 
196              @type label1: C{str} 
197   
198              @param label2: Label for second data 
199              @type label2: C{str} 
200   
201              @param date1: Date description for first data 
202              @type date1: C{str} 
203   
204              @param date2: Date description for second data 
205              @type date2: C{str} 
206   
207              @return: unified diff lines (maybe a generator) 
208              @rtype: iterable 
209          """ 
210          pipe = self._getPipe(name1, name2, label1, label2, date1, date2) 
211   
212           
213          line = pipe.fromchild.readline() 
214          while line: 
215              yield line 
216              line = pipe.fromchild.readline() 
217   
218          pipe.fromchild.close() 
219          pipe.wait() 
 220   
221   
222 -    def _getPipe(self, name1, name2, label1, label2, date1, date2): 
 223          """ Returns a pipe from the diff program 
224   
225              @param name1: First file name 
226              @type name1: C{str} 
227   
228              @param name2: Second file name 
229              @type name2: C{str} 
230   
231              @param label1: Label for first data 
232              @type label1: C{str} 
233   
234              @param label2: Label for second data 
235              @type label2: C{str} 
236   
237              @param date1: Date description for first data 
238              @type date1: C{str} 
239   
240              @param date2: Date description for second data 
241              @type date2: C{str} 
242   
243              @return: The pipe object 
244              @rtype: see: C{util.getPipe4} 
245          """ 
246          from svnmailer import util 
247   
248          params = { 
249              "label_from": "%s %s" % (label1, date1 or ""), 
250              "label_to"  : "%s %s" % (label2 or label1, date2 or ""), 
251              "from"      : name1, 
252              "to"        : name2, 
253          } 
254   
255           
256          for key, value in params.items(): 
257              if isinstance(value, unicode): 
258                  params[key] = value.encode("utf-8") 
259   
260          cmd = list(self._diff_command) 
261          cmd[1:] = [(isinstance(arg, unicode) and 
262              [arg.encode("utf-8")] or [arg])[0] % params for arg in cmd[1:] 
263          ] 
264   
265          pipe = util.getPipe4(cmd) 
266          pipe.tochild.close() 
267   
268          return pipe 
  269