| 
				
			 | 
			
			
				@@ -26,6 +26,8 @@ if sys.hexversion < 0x02050000: 
			 | 
		
	
		
			
			| 
				26
			 | 
			
				26
			 | 
			
			
				 import re 
			 | 
		
	
		
			
			| 
				27
			 | 
			
				27
			 | 
			
			
				 import subprocess 
			 | 
		
	
		
			
			| 
				28
			 | 
			
				28
			 | 
			
			
				 import errno 
			 | 
		
	
		
			
			| 
				
			 | 
			
				29
			 | 
			
			
				+import fcntl 
			 | 
		
	
		
			
			| 
				
			 | 
			
				30
			 | 
			
			
				+import os 
			 | 
		
	
		
			
			| 
				29
			 | 
			
				31
			 | 
			
			
				 import difflib 
			 | 
		
	
		
			
			| 
				30
			 | 
			
				32
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				31
			 | 
			
				33
			 | 
			
			
				  
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -429,10 +431,6 @@ class UnifiedDiff(Diff): 
			 | 
		
	
		
			
			| 
				429
			 | 
			
				431
			 | 
			
			
				         return re.match('^Binary files .* differ$', line.rstrip()) 
			 | 
		
	
		
			
			| 
				430
			 | 
			
				432
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				431
			 | 
			
				433
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				432
			 | 
			
				
			 | 
			
			
				-class ContextDiff(Diff): 
			 | 
		
	
		
			
			| 
				433
			 | 
			
				
			 | 
			
			
				-    pass 
			 | 
		
	
		
			
			| 
				434
			 | 
			
				
			 | 
			
			
				- 
			 | 
		
	
		
			
			| 
				435
			 | 
			
				
			 | 
			
			
				- 
			 | 
		
	
		
			
			| 
				436
			 | 
			
				434
			 | 
			
			
				 class PatchStream(object): 
			 | 
		
	
		
			
			| 
				437
			 | 
			
				435
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				438
			 | 
			
				436
			 | 
			
			
				     def __init__(self, diff_hdl): 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -469,13 +467,54 @@ class PatchStream(object): 
			 | 
		
	
		
			
			| 
				469
			 | 
			
				467
			 | 
			
			
				             yield line 
			 | 
		
	
		
			
			| 
				470
			 | 
			
				468
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				471
			 | 
			
				469
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				
			 | 
			
				470
			 | 
			
			
				+class PatchStreamForwarder(object): 
			 | 
		
	
		
			
			| 
				
			 | 
			
				471
			 | 
			
			
				+    """A non-block stream forwarder.  Note input stream is non-seekable, and 
			 | 
		
	
		
			
			| 
				
			 | 
			
				472
			 | 
			
			
				+    upstream has eaten some lines. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				473
			 | 
			
			
				+    """ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				474
			 | 
			
			
				+    def __init__(self, istream, translator): 
			 | 
		
	
		
			
			| 
				
			 | 
			
				475
			 | 
			
			
				+        assert isinstance(istream, PatchStream) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				476
			 | 
			
			
				+        self._istream = istream 
			 | 
		
	
		
			
			| 
				
			 | 
			
				477
			 | 
			
			
				+        self._translator = translator 
			 | 
		
	
		
			
			| 
				
			 | 
			
				478
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				479
			 | 
			
			
				+        self._istream_open = True 
			 | 
		
	
		
			
			| 
				
			 | 
			
				480
			 | 
			
			
				+        self._set_non_block(self._translator.stdin) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				481
			 | 
			
			
				+        self._set_non_block(self._translator.stdout) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				482
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				483
			 | 
			
			
				+        self._forward_until_block() 
			 | 
		
	
		
			
			| 
				
			 | 
			
				484
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				485
			 | 
			
			
				+    def _set_non_block(self, hdl): 
			 | 
		
	
		
			
			| 
				
			 | 
			
				486
			 | 
			
			
				+        fd = hdl.fileno() 
			 | 
		
	
		
			
			| 
				
			 | 
			
				487
			 | 
			
			
				+        fl = fcntl.fcntl(fd, fcntl.F_GETFL) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				488
			 | 
			
			
				+        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				489
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				490
			 | 
			
			
				+    def _forward_until_block(self): 
			 | 
		
	
		
			
			| 
				
			 | 
			
				491
			 | 
			
			
				+        for line in self._istream: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				492
			 | 
			
			
				+            try: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				493
			 | 
			
			
				+                self._translator.stdin.write(line.encode('utf-8')) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				494
			 | 
			
			
				+            except IOError: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				495
			 | 
			
			
				+                break       # EAGAIN 
			 | 
		
	
		
			
			| 
				
			 | 
			
				496
			 | 
			
			
				+        else: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				497
			 | 
			
			
				+            self._translator.stdin.close() 
			 | 
		
	
		
			
			| 
				
			 | 
			
				498
			 | 
			
			
				+            self._istream_open = False 
			 | 
		
	
		
			
			| 
				
			 | 
			
				499
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				500
			 | 
			
			
				+    def __iter__(self): 
			 | 
		
	
		
			
			| 
				
			 | 
			
				501
			 | 
			
			
				+        while True: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				502
			 | 
			
			
				+            try: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				503
			 | 
			
			
				+                line = self._translator.stdout.readline() 
			 | 
		
	
		
			
			| 
				
			 | 
			
				504
			 | 
			
			
				+                if not line: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				505
			 | 
			
			
				+                    return 
			 | 
		
	
		
			
			| 
				
			 | 
			
				506
			 | 
			
			
				+                yield line 
			 | 
		
	
		
			
			| 
				
			 | 
			
				507
			 | 
			
			
				+            except IOError: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				508
			 | 
			
			
				+                if self._istream_open: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				509
			 | 
			
			
				+                    self._forward_until_block() 
			 | 
		
	
		
			
			| 
				
			 | 
			
				510
			 | 
			
			
				+                continue    # EAGAIN 
			 | 
		
	
		
			
			| 
				
			 | 
			
				511
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				512
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				472
			 | 
			
				513
			 | 
			
			
				 class DiffParser(object): 
			 | 
		
	
		
			
			| 
				473
			 | 
			
				514
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				474
			 | 
			
				515
			 | 
			
			
				     def __init__(self, stream): 
			 | 
		
	
		
			
			| 
				475
			 | 
			
				
			 | 
			
			
				-        self._stream = stream 
			 | 
		
	
		
			
			| 
				476
			 | 
			
				516
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				477
			 | 
			
				
			 | 
			
			
				-        header = [decode(line) for line in 
			 | 
		
	
		
			
			| 
				478
			 | 
			
				
			 | 
			
			
				-                  self._stream.read_stream_header(100)] 
			 | 
		
	
		
			
			| 
				
			 | 
			
				517
			 | 
			
			
				+        header = [decode(line) for line in stream.read_stream_header(100)] 
			 | 
		
	
		
			
			| 
				479
			 | 
			
				518
			 | 
			
			
				         size = len(header) 
			 | 
		
	
		
			
			| 
				480
			 | 
			
				519
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				481
			 | 
			
				520
			 | 
			
			
				         if size >= 4 and (header[0].startswith('*** ') and 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -483,34 +522,37 @@ class DiffParser(object): 
			 | 
		
	
		
			
			| 
				483
			 | 
			
				522
			 | 
			
			
				                           header[2].rstrip() == '***************' and 
			 | 
		
	
		
			
			| 
				484
			 | 
			
				523
			 | 
			
			
				                           header[3].startswith('*** ') and 
			 | 
		
	
		
			
			| 
				485
			 | 
			
				524
			 | 
			
			
				                           header[3].rstrip().endswith(' ****')): 
			 | 
		
	
		
			
			| 
				486
			 | 
			
				
			 | 
			
			
				-            self._type = 'context' 
			 | 
		
	
		
			
			| 
				487
			 | 
			
				
			 | 
			
			
				- 
			 | 
		
	
		
			
			| 
				488
			 | 
			
				525
			 | 
			
			
				             # For context diff, try use `filterdiff` to translate it to unified 
			 | 
		
	
		
			
			| 
				489
			 | 
			
				526
			 | 
			
			
				             # format and provide a new stream 
			 | 
		
	
		
			
			| 
				490
			 | 
			
				527
			 | 
			
			
				             # 
			 | 
		
	
		
			
			| 
				491
			 | 
			
				
			 | 
			
			
				-            # TODO 
			 | 
		
	
		
			
			| 
				492
			 | 
			
				
			 | 
			
			
				- 
			 | 
		
	
		
			
			| 
				
			 | 
			
				528
			 | 
			
			
				+            self._type = 'context' 
			 | 
		
	
		
			
			| 
				
			 | 
			
				529
			 | 
			
			
				+            try: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				530
			 | 
			
			
				+                self._translator = subprocess.Popen( 
			 | 
		
	
		
			
			| 
				
			 | 
			
				531
			 | 
			
			
				+                    ['filterdiff', '--format=unified'], stdin=subprocess.PIPE, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				532
			 | 
			
			
				+                    stdout=subprocess.PIPE) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				533
			 | 
			
			
				+            except OSError: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				534
			 | 
			
			
				+                raise SystemExit('*** Context diff support depends on ' 
			 | 
		
	
		
			
			| 
				
			 | 
			
				535
			 | 
			
			
				+                                 'filterdiff') 
			 | 
		
	
		
			
			| 
				
			 | 
			
				536
			 | 
			
			
				+            self._stream = PatchStreamForwarder(stream, self._translator) 
			 | 
		
	
		
			
			| 
				493
			 | 
			
				537
			 | 
			
			
				             return 
			 | 
		
	
		
			
			| 
				494
			 | 
			
				538
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				495
			 | 
			
				539
			 | 
			
			
				         for n in range(size): 
			 | 
		
	
		
			
			| 
				496
			 | 
			
				540
			 | 
			
			
				             if header[n].startswith('--- ') and (n < size - 1) and \ 
			 | 
		
	
		
			
			| 
				497
			 | 
			
				541
			 | 
			
			
				                     header[n+1].startswith('+++ '): 
			 | 
		
	
		
			
			| 
				498
			 | 
			
				542
			 | 
			
			
				                 self._type = 'unified' 
			 | 
		
	
		
			
			| 
				
			 | 
			
				543
			 | 
			
			
				+                self._stream = stream 
			 | 
		
	
		
			
			| 
				499
			 | 
			
				544
			 | 
			
			
				                 break 
			 | 
		
	
		
			
			| 
				500
			 | 
			
				545
			 | 
			
			
				         else: 
			 | 
		
	
		
			
			| 
				501
			 | 
			
				
			 | 
			
			
				-            # `filterdiff` translate unknown diff to nothing, fall through to 
			 | 
		
	
		
			
			| 
				
			 | 
			
				546
			 | 
			
			
				+            # `filterdiff` translates unknown diff to nothing, fall through to 
			 | 
		
	
		
			
			| 
				502
			 | 
			
				547
			 | 
			
			
				             # unified diff give cdiff a chance to show everything as headers 
			 | 
		
	
		
			
			| 
				503
			 | 
			
				548
			 | 
			
			
				             # 
			 | 
		
	
		
			
			| 
				504
			 | 
			
				549
			 | 
			
			
				             sys.stderr.write("*** unknown format, fall through to 'unified'\n") 
			 | 
		
	
		
			
			| 
				505
			 | 
			
				550
			 | 
			
			
				             self._type = 'unified' 
			 | 
		
	
		
			
			| 
				
			 | 
			
				551
			 | 
			
			
				+            self._stream = stream 
			 | 
		
	
		
			
			| 
				506
			 | 
			
				552
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				507
			 | 
			
				553
			 | 
			
			
				     def get_diff_generator(self): 
			 | 
		
	
		
			
			| 
				508
			 | 
			
				554
			 | 
			
			
				         """parse all diff lines, construct a list of Diff objects""" 
			 | 
		
	
		
			
			| 
				509
			 | 
			
				
			 | 
			
			
				-        if self._type == 'unified': 
			 | 
		
	
		
			
			| 
				510
			 | 
			
				
			 | 
			
			
				-            difflet = UnifiedDiff(None, None, None, None) 
			 | 
		
	
		
			
			| 
				511
			 | 
			
				
			 | 
			
			
				-        else: 
			 | 
		
	
		
			
			| 
				512
			 | 
			
				
			 | 
			
			
				-            raise RuntimeError('unsupported diff format') 
			 | 
		
	
		
			
			| 
				513
			 | 
			
				
			 | 
			
			
				- 
			 | 
		
	
		
			
			| 
				
			 | 
			
				555
			 | 
			
			
				+        difflet = UnifiedDiff(None, None, None, None) 
			 | 
		
	
		
			
			| 
				514
			 | 
			
				556
			 | 
			
			
				         diff = Diff([], None, None, []) 
			 | 
		
	
		
			
			| 
				515
			 | 
			
				557
			 | 
			
			
				         headers = [] 
			 | 
		
	
		
			
			| 
				516
			 | 
			
				558
			 | 
			
			
				  
			 |