summaryrefslogtreecommitdiff
path: root/lib/git/diff.py
blob: e16d5b074001a2624d75f84e5655e87a66859d29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# diff.py
# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
#
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php

import re
import objects.blob as blob

class Diff(object):
	"""
	A Diff contains diff information between two Trees.
	
	It contains two sides a and b of the diff, members are prefixed with 
	"a" and "b" respectively to inidcate that.
	
	Diffs keep information about the changed blob objects, the file mode, renames, 
	deletions and new files.
	
	There are a few cases where None has to be expected as member variable value:
	
	``New File``::
	
		a_mode is None
		a_blob is None
		
	``Deleted File``::
	
		b_mode is None
		b_blob is NOne
	"""
	
	# precompiled regex
	re_header = re.compile(r"""
								#^diff[ ]--git
									[ ]a/(?P<a_path>\S+)[ ]b/(?P<b_path>\S+)\n
								(?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n
								   ^rename[ ]from[ ](?P<rename_from>\S+)\n
								   ^rename[ ]to[ ](?P<rename_to>\S+)(?:\n|$))?
								(?:^old[ ]mode[ ](?P<old_mode>\d+)\n
								   ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
								(?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
								(?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
								(?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
									\.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
							""", re.VERBOSE | re.MULTILINE)
	re_is_null_hexsha = re.compile( r'^0{40}$' )
	__slots__ = ("a_blob", "b_blob", "a_mode", "b_mode", "new_file", "deleted_file", 
				 "rename_from", "rename_to", "renamed", "diff")

	def __init__(self, repo, a_path, b_path, a_blob_id, b_blob_id, a_mode,
				 b_mode, new_file, deleted_file, rename_from,
				 rename_to, diff):
		if not a_blob_id or self.re_is_null_hexsha.search(a_blob_id):
			self.a_blob = None
		else:
			self.a_blob = blob.Blob(repo, id=a_blob_id, mode=a_mode, path=a_path)
		if not b_blob_id or self.re_is_null_hexsha.search(b_blob_id):
			self.b_blob = None
		else:
			self.b_blob = blob.Blob(repo, id=b_blob_id, mode=b_mode, path=b_path)

		self.a_mode = a_mode
		self.b_mode = b_mode
		if self.a_mode:
			self.a_mode = blob.Blob._mode_str_to_int( self.a_mode )
		if self.b_mode:
			self.b_mode = blob.Blob._mode_str_to_int( self.b_mode )
		self.new_file = new_file
		self.deleted_file = deleted_file
		self.rename_from = rename_from
		self.rename_to = rename_to
		self.renamed = rename_from != rename_to
		self.diff = diff

	@classmethod
	def _index_from_patch_format(cls, repo, stream):
		"""
		Create a new DiffIndex from the given text which must be in patch format
		``repo``
			is the repository we are operating on - it is required 
		
		``stream``
			result of 'git diff' as a stream (supporting file protocol)
		
		Returns
			git.DiffIndex
		"""
		# for now, we have to bake the stream
		text = stream.read()
		diffs = []

		diff_header = cls.re_header.match
		for diff in ('\n' + text).split('\ndiff --git')[1:]:
			header = diff_header(diff)

			a_path, b_path, similarity_index, rename_from, rename_to, \
				old_mode, new_mode, new_file_mode, deleted_file_mode, \
				a_blob_id, b_blob_id, b_mode = header.groups()
			new_file, deleted_file = bool(new_file_mode), bool(deleted_file_mode)

			diffs.append(Diff(repo, a_path, b_path, a_blob_id, b_blob_id,
				old_mode or deleted_file_mode, new_mode or new_file_mode or b_mode,
				new_file, deleted_file, rename_from, rename_to, diff[header.end():]))

		return diffs
		
	@classmethod
	def _index_from_raw_format(cls, repo, stream):
		"""
		Create a new DiffIndex from the given stream which must be in raw format.
		
		Returns
			git.DiffIndex
		"""
		raise NotImplementedError("")