The idea is from Kamesh. Attached is the patch which I think implements
the idea in a way but with an issue.

First, the patch:

Log

[[[

If diff command does not exist on the system then use
difflib.unified_diff() to generate diff contents.

* tools/hook-scripts/mailer/mailer.py: Fall back to
  difflib.unified_diff() if the script fails to execute native 'diff'
  command.

Patch by: Noorul Islam K M <noorul{_AT_}collab.net>
Suggested by: Kamesh Jayachandran <kamesh{_AT_}collab.net>

]]]

Now the issue:

difflib.unified_diff() produces a bit different output from that of
'diff' command. The attached python script can be used to generate diffs
using difflib. I did try different combinations of creating patches and
applying patches, all of them worked fine. I am not sure whether this
difference in output can be ignored.

Thanks and Regards
Noorul

Index: hook-scripts/mailer/mailer.py
===================================================================
--- hook-scripts/mailer/mailer.py       (revision 1031409)
+++ hook-scripts/mailer/mailer.py       (working copy)
@@ -866,12 +866,16 @@
           content = src_fname = dst_fname = None
         else:
           src_fname, dst_fname = diff.get_files()
-          content = DiffContent(self.cfg.get_diff_cmd(self.group, {
-            'label_from' : label1,
-            'label_to' : label2,
-            'from' : src_fname,
-            'to' : dst_fname,
-            }))
+          try:
+            content = DiffContent(self.cfg.get_diff_cmd(self.group, {
+              'label_from' : label1,
+              'label_to' : label2,
+              'from' : src_fname,
+              'to' : dst_fname,
+              }))
+          except OSError:
+            # diff command does not exist, try difflib.unified_diff()
+            content = DifflibDiffContent(label1, label2, src_fname, dst_fname)
 
       # return a data item for this diff
       return _data(
@@ -946,7 +950,57 @@
       type=ltype,
       )
 
+class DifflibDiffContent():
+  "This is a generator-like object returning annotated lines of a diff."
 
+  def __init__(self, label_from, label_to, from_file, to_file):
+    import difflib
+    self.seen_change = False
+    fromlines = open(from_file, 'U').readlines()
+    tolines = open(to_file, 'U').readlines()
+    self.diff = difflib.unified_diff(fromlines, tolines,
+                                     label_from, label_to)
+    
+  def __nonzero__(self):
+    # we always have some items
+    return True
+
+  def __getitem__(self, idx):
+
+    try:
+      line = self.diff.next()
+    except StopIteration:
+      raise IndexError
+
+    # classify the type of line.
+    first = line[:1]
+    if first == '@':
+      self.seen_change = True
+      ltype = 'H'
+    elif first == '-':
+      if self.seen_change:
+        ltype = 'D'
+      else:
+        ltype = 'F'
+    elif first == '+':
+      if self.seen_change:
+        ltype = 'A'
+      else:
+        ltype = 'T'
+    elif first == ' ':
+      ltype = 'C'
+    else:
+      ltype = 'U'
+
+    if line[-2] == '\r':
+      line=line[0:-2] + '\n' # remove carriage return
+
+    return _data(
+      raw=line,
+      text=line[1:-1],  # remove indicator and newline
+      type=ltype,
+      )
+
 class TextCommitRenderer:
   "This class will render the commit mail in plain text."
 
#!/usr/bin/python

import sys
from difflib import unified_diff

if len(sys.argv) < 3:
	sys.exit(1)

from_file = sys.argv[1]
to_file = sys.argv[2]

f1 = open(from_file, 'U').readlines()
f2 = open(to_file, 'U').readlines()

diff = unified_diff(f1, f2, from_file, to_file)

for line in diff:
	sys.stdout.write(line)

Reply via email to