CommitInfo.py
1 |
|
2 |
# formatted file in a commit. |
3 |
|
4 |
# The function returns a list |
5 |
|
6 |
# If one line is removed, and one line is added, and both have the same line |
7 |
# number, then that should be regarded as a changed line, not a removed+added line. |
8 |
# This holds for each non-broken list of removed+added lines. |
9 |
|
10 |
from pydriller.domain.commit import ModificationType |
11 |
from ..syntax import * |
12 |
|
13 |
""" It's a lot of annoying glue code to transform a modified file object into |
14 |
what we actually want: The data that needs to be passed to the Django template. |
15 |
This convenience function accepts the modified file object as given by |
16 |
Pydriller's Commit class, and returns a list of dicts, each dict representing |
17 |
the information needed to properly present a file diff in the template. |
18 |
""" |
19 |
def prepare_and_process(modified_file): |
20 |
#print(modified_file.source_code) |
21 |
result = dict() |
22 |
result["object"] = modified_file # Could come in handy |
23 |
result["change_type"] = modified_file.change_type |
24 |
result["html_code_after"] = code_to_HTML( |
25 |
modified_file.source_code, |
26 |
modified_file.filename) |
27 |
result["html_code_before"] = code_to_HTML( |
28 |
modified_file.source_code_before, |
29 |
modified_file.filename) |
30 |
|
31 |
if modified_file.change_type == ModificationType.ADD: |
32 |
result["path"] = modified_file.new_path |
33 |
elif modified_file.change_type == ModificationType.DELETE: |
34 |
result["path"] = modified_file.old_path |
35 |
elif modified_file.change_type == ModificationType.RENAME: |
36 |
result["path"] = modified_file.old_path +" → "+ modified_file.new_path |
37 |
elif modified_file.change_type == ModificationType.MODIFY: |
38 |
result["path"] = modified_file.old_path |
39 |
|
40 |
added = dict() |
41 |
deleted = dict() |
42 |
for number, line in modified_file.diff_parsed["added"]: |
43 |
added[number] = line |
44 |
for number, line in modified_file.diff_parsed["deleted"]: |
45 |
if result["path"] == "Challenge 4/Controller.java": |
46 |
#print("PING") |
47 |
pass |
48 |
deleted[number] = line |
49 |
if result["path"] == "Challenge 4/Controller.java": |
50 |
pass |
51 |
#print("NU CONTROLLER.jAVA") |
52 |
#print(modified_file.diff_parsed) |
53 |
#print(deleted) |
54 |
result["rows"] = process_file( |
55 |
result["html_code_before"], |
56 |
result["html_code_after"], |
57 |
added, |
58 |
deleted) |
59 |
|
60 |
# These three lists are going to be empty if the methods couldn't be detected |
61 |
deleted, transferred, new = process_methods(modified_file) |
62 |
if len(deleted) == len(transferred) == len(new) == 0: |
63 |
result["methods_available"] = False |
64 |
else: |
65 |
result["methods_available"] = True |
66 |
result["deleted_methods"] = deleted |
67 |
result["transferred_methods"] = transferred |
68 |
result["new_methods"] = new |
69 |
return result |
70 |
|
71 |
""" Sometimes, the methods in a file can be detected, which adds some nice |
72 |
information """ |
73 |
def process_methods(modified_file): |
74 |
before_methods = modified_file.methods_before |
75 |
after_methods = modified_file.methods |
76 |
deleted_methods = [] |
77 |
transferred_methods = [] |
78 |
new_methods = [] |
79 |
|
80 |
# Finding all transferred and deleted methods |
81 |
for before_method in before_methods: |
82 |
transferred = False |
83 |
for after_method in after_methods: |
84 |
if before_method.name == after_method.name: # Match found |
85 |
transferred_methods.append((before_method, after_method)) |
86 |
transferred = True |
87 |
break |
88 |
if not transferred: |
89 |
deleted_methods.append(before_method) |
90 |
# Finding all new methods |
91 |
for after_method in after_methods: |
92 |
transferred = False |
93 |
for _, am in transferred_methods: |
94 |
if after_method == am: |
95 |
transferred = True |
96 |
break |
97 |
if not transferred: |
98 |
new_methods.append(after_method) |
99 |
|
100 |
return deleted_methods, transferred_methods, new_methods |
101 |
|
102 |
|
103 |
def process_file(source_before, source_after, additions, deletions): |
104 |
rows = [] |
105 |
# Counting from 1, because source code lines are counted from there |
106 |
# NOTE: Deletions komen wel degelijk goed binnen |
107 |
#print("deletions:") |
108 |
#print(deletions) |
109 |
before_count = 1 |
110 |
after_count = 1 |
111 |
while True: |
112 |
row = dict() |
113 |
#print("PROCESS_FILE") |
114 |
#print(deletions) |
115 |
#print(additions) |
116 |
# We check the deletion lines first; if a line was "changed", the |
117 |
# 'deleted' line needs to be listed first, and after that, the 'added' |
118 |
# line |
119 |
#print(str(before_count) + " -- " + str(after_count)) |
120 |
if before_count in deletions: |
121 |
row["type"] = "deletion" |
122 |
row["old_num"] = before_count |
123 |
# Why source_before[] and not deletions[]? |
124 |
# Because source_before[] has been processed by Pygments, and thus |
125 |
# has the syntax highlighting in it. deletions[] is just plain text. |
126 |
|
127 |
|
128 |
# Look, I'm tired at the time of writing, and this line seems to be |
129 |
# kind of a dick so I'm just gonna try catch it and leave it like |
130 |
# that for now |
131 |
#try: |
132 |
#row["line"] = source_before[before_count] |
133 |
#print(len(source_before)) |
134 |
#print(before_count) |
135 |
if before_count == len(source_before): |
136 |
row["line"] = source_before[-1] |
137 |
else: |
138 |
row["line"] = source_before[before_count] |
139 |
#except: |
140 |
#pass |
141 |
|
142 |
before_count += 1 |
143 |
elif after_count in additions: |
144 |
row["type"] = "addition" |
145 |
row["new_num"] = after_count |
146 |
# Idem for additions[] |
147 |
if after_count == len(source_after): |
148 |
row["line"] = source_after[-1] |
149 |
else: |
150 |
row["line"] = source_after[after_count] |
151 |
after_count += 1 |
152 |
else: # No change to this particular line |
153 |
row["old_num"] = before_count |
154 |
row["new_num"] = after_count |
155 |
if len(source_before) > before_count: |
156 |
row["line"] = source_before[before_count] |
157 |
elif len(source_after) > after_count: |
158 |
row["line"] = source_after[after_count] |
159 |
else: # No lines left |
160 |
break |
161 |
# If not end of both files, increment both counters anyway |
162 |
before_count += 1 |
163 |
after_count += 1 |
164 |
# Adding the new row to the list of rows |
165 |
rows.append(row) |
166 |
return rows |
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |