Skip to content

Commit ac783a4

Browse files
committed
wip
1 parent 6653554 commit ac783a4

File tree

1 file changed

+162
-0
lines changed

1 file changed

+162
-0
lines changed

pygit2/blame.py

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# Copyright 2010-2014 The pygit2 contributors
4+
#
5+
# This file is free software; you can redistribute it and/or modify
6+
# it under the terms of the GNU General Public License, version 2,
7+
# as published by the Free Software Foundation.
8+
#
9+
# In addition to the permissions in the GNU General Public License,
10+
# the authors give you unlimited permission to link the compiled
11+
# version of this file into combinations with other programs,
12+
# and to distribute those combinations without any restriction
13+
# coming from the use of this file. (The General Public License
14+
# restrictions do apply in other respects; for example, they cover
15+
# modification of the file, and distribution when not linked into
16+
# a combined executable.)
17+
#
18+
# This file is distributed in the hope that it will be useful, but
19+
# WITHOUT ANY WARRANTY; without even the implied warranty of
20+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21+
# General Public License for more details.
22+
#
23+
# You should have received a copy of the GNU General Public License
24+
# along with this program; see the file COPYING. If not, write to
25+
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
26+
# Boston, MA 02110-1301, USA.
27+
28+
# Import from the future
29+
from __future__ import absolute_import, unicode_literals
30+
31+
# Import from pygit2
32+
from .errors import check_error
33+
from .ffi import ffi, C
34+
from .utils import to_bytes, is_string, to_str
35+
from _pygit2 import Signature, Oid
36+
37+
def wrap_signature(csig):
38+
if not csig:
39+
return None
40+
41+
return Signature(ffi.string(csig.name).decode('utf-8'),
42+
ffi.string(csig.email).decode('utf-8'),
43+
csig.when.time, csig.when.offset, 'utf-8')
44+
45+
class BlameHunk(object):
46+
47+
@classmethod
48+
def _from_c(cls, blame, ptr):
49+
hunk = cls.__new__(cls)
50+
hunk._blame = blame
51+
hunk._hunk = ptr
52+
return hunk
53+
54+
@property
55+
def lines_in_hunk(self):
56+
"""Number of lines"""
57+
return self._hunk.lines_in_hunk
58+
59+
@property
60+
def boundary(self):
61+
"""Tracked to a boundary commit"""
62+
63+
# Casting directly to bool via cffi does not seem to work
64+
return int(ffi.cast('int', self._hunk.boundary)) != 0
65+
66+
@property
67+
def final_start_line_number(self):
68+
"""Final start line number"""
69+
return self._hunk.final_start_line_number
70+
71+
@property
72+
def final_committer(self):
73+
"""Final committer"""
74+
return wrap_signature(self._hunk.final_signature)
75+
76+
@property
77+
def final_commit_id(self):
78+
return Oid(raw=bytes(ffi.buffer(ffi.addressof(self._hunk, 'final_commit_id'))[:]))
79+
80+
@property
81+
def orig_start_line_number(self):
82+
"""Origin start line number"""
83+
return self._hunk.orig_start_line_number
84+
85+
@property
86+
def orig_committer(self):
87+
"""Original committer"""
88+
return wrap_signature(self._hunk.orig_signature)
89+
90+
@property
91+
def orig_commit_id(self):
92+
return Oid(raw=bytes(ffi.buffer(ffi.addressof(self._hunk, 'orig_commit_id'))[:]))
93+
94+
@property
95+
def orig_path(self):
96+
"""Original path"""
97+
path = self._hunk.orig_path
98+
if not path:
99+
return None
100+
101+
return ffi.string(path).decode()
102+
103+
104+
class Blame(object):
105+
106+
@classmethod
107+
def _from_c(cls, repo, ptr):
108+
blame = cls.__new__(cls)
109+
blame._repo = repo
110+
blame._blame = ptr
111+
return blame
112+
113+
def __del__(self):
114+
C.git_blame_free(self._blame)
115+
116+
def __len__(self):
117+
return C.git_blame_get_hunk_count(self._blame)
118+
119+
def __getitem__(self, index):
120+
chunk = C.git_blame_get_hunk_byindex(self._blame, index)
121+
if not chunk:
122+
raise IndexError
123+
124+
return BlameHunk._from_c(self, chunk)
125+
126+
def for_line(self, line_no):
127+
"""for_line(line_no) -> BlameHunk
128+
129+
Returns the blame hunk data for a given line given its number
130+
in the current Blame.
131+
132+
Arguments:
133+
134+
line_no
135+
Line number, starts at 1.
136+
"""
137+
if line_no < 0:
138+
raise IndexError
139+
140+
chunk = C.git_blame_get_hunk_byline(self._blame, line_no)
141+
if not chunk:
142+
raise IndexError
143+
144+
return BlameHunk._from_c(self, chunk)
145+
146+
class BlameIterator(object):
147+
def __init__(self, blame):
148+
self._count = len(blame)
149+
self._index = 0
150+
self._blame = blame
151+
152+
def __next__(self):
153+
if self._index >= self._count:
154+
raise StopIteration
155+
156+
hunk = self._blame[self._blame]
157+
self._index += 1
158+
159+
return hunk
160+
161+
def next(self):
162+
return self.__next__()

0 commit comments

Comments
 (0)