2828import os
2929from collections import OrderedDict
3030
31- from deltacode .models import File
32- from deltacode .models import Scan
3331from deltacode import utils
32+ from deltacode .exceptions import FileError as FileError
3433from commoncode import paths
3534from commoncode .resource import VirtualCodebase
3635
36+
3737from pkg_resources import get_distribution , DistributionNotFound
3838
3939try :
@@ -55,38 +55,35 @@ class DeltaCode(object):
5555 def __init__ (self , new_path , old_path , options ):
5656 self .codebase1 = None
5757 self .codebase2 = None
58- self .new_files_fingerprint = (
59- dict ()
60- ) # map of { {new_file1:fingerprint},{new_file2:fingerprint},...} it will be needed when we need the fingerprints
61- self .old_files_fingerprint = (
62- dict ()
63- ) # map of { {old_file1:fingerprint},{old_file2:fingerprint},...}
6458 self .options = options
6559 self .deltas = []
6660 self .errors = []
6761
68- try :
62+ if os . path . isfile ( new_path ) and os . path . isfile ( old_path ) :
6963 self .codebase1 = VirtualCodebase (new_path )
7064 self .codebase2 = VirtualCodebase (old_path )
7165
72- except Exception as exception :
73- self .errors .append (str (exception ))
74-
75- if self .codebase1 is not None or self .codebase2 is not None :
76- self .stats = Stat (
77- self .codebase1 .compute_counts (), self .codebase2 .compute_counts ()
66+ else :
67+ error_message = (
68+ "{} is expected to be a file" .format (new_path )
69+ if not os .path .isfile (new_path )
70+ else "{} is expected to be a file" .format (old_path )
7871 )
79- self .new_files_errors = []
80- self .old_files_errors = []
81- self .determine_delta ()
82- self .license_diff ()
83- self .copyright_diff ()
84- self .stats .calculate_stats ()
85- self .similarity ()
86- # Sort deltas by score, descending, i.e., high > low, and then by
87- # factors, alphabetically. Run the least significant sort first.
88- self .deltas .sort (key = lambda Delta : Delta .factors , reverse = False )
89- self .deltas .sort (key = lambda Delta : Delta .score , reverse = True )
72+ raise FileError (error_message )
73+ self .stats = Stat (
74+ self .codebase1 .compute_counts (), self .codebase2 .compute_counts ()
75+ )
76+ self .new_files_errors = []
77+ self .old_files_errors = []
78+ self .determine_delta ()
79+ self .license_diff ()
80+ self .copyright_diff ()
81+ self .stats .calculate_stats ()
82+ self .similarity ()
83+ # Sort deltas by score, descending, i.e., high > low, and then by
84+ # factors, alphabetically. Run the least significant sort first.
85+ self .deltas .sort (key = lambda Delta : Delta .factors , reverse = False )
86+ self .deltas .sort (key = lambda Delta : Delta .score , reverse = True )
9087
9188 def similarity (self ):
9289 """
@@ -99,17 +96,21 @@ def similarity(self):
9996 for delta in self .deltas :
10097 if delta .new_file == None or delta .old_file == None :
10198 continue
102- new_fingerprint = self .new_files_fingerprint .get (delta .new_file .path , None )
103- old_fingerprint = self .old_files_fingerprint .get (delta .old_file .path , None )
99+ new_fingerprint = (
100+ delta .new_file .fingerprint
101+ if hasattr (delta .new_file , "fingerprint" )
102+ else None
103+ )
104+ old_fingerprint = (
105+ delta .old_file .fingerprint
106+ if hasattr (delta .old_file , "fingerprint" )
107+ else None
108+ )
104109
105110 if new_fingerprint == None or old_fingerprint == None :
106111 continue
107- new_fingerprint = utils .bitarray_from_hex (
108- self .new_files_fingerprint [delta .new_file .path ]
109- )
110- old_fingerprint = utils .bitarray_from_hex (
111- self .old_files_fingerprint [delta .old_file .path ]
112- )
112+ new_fingerprint = utils .bitarray_from_hex (delta .new_file .fingerprint )
113+ old_fingerprint = utils .bitarray_from_hex (delta .old_file .fingerprint )
113114
114115 hamming_distance = utils .hamming_distance (new_fingerprint , old_fingerprint )
115116 if hamming_distance > 0 and hamming_distance <= SIMILARITY_LIMIT :
@@ -119,13 +120,8 @@ def similarity(self):
119120 )
120121
121122 def create_deltas (
122- self , new_resource , old_resource , new_path , old_path , score , count , status
123+ self , new_resource , old_resource , new_path , old_path , score , status
123124 ):
124- count = count + 1
125- if new_resource :
126- new_resource .path = new_path
127- if old_resource :
128- old_resource .path = old_path
129125 delta = Delta (score , new_resource , old_resource )
130126 delta .status = status
131127 self .deltas .append (delta )
@@ -137,105 +133,107 @@ def determine_delta(self):
137133 from either scan.
138134 """
139135
140- old_files_sha1_considered_in_deltas = dict ()
141-
142- Delta .NEW_CODEBASE_OFFSET , Delta .OLD_CODEBASE_OFFSET = utils .align_trees (
143- self .codebase1 , self .codebase2
144- )
136+ old_resource_considered = dict ()
137+ try :
138+ Delta .NEW_CODEBASE_OFFSET , Delta .OLD_CODEBASE_OFFSET = utils .align_trees (
139+ self .codebase1 , self .codebase2
140+ )
141+ except utils .AlignmentException :
142+ Delta .NEW_CODEBASE_OFFSET , Delta .OLD_CODEBASE_OFFSET = 0 , 0
145143
146144 for new_resource in self .codebase1 .walk ():
147145 if new_resource .is_file :
148146 path_new = "/" .join (
149147 paths .split (new_resource .path )[Delta .NEW_CODEBASE_OFFSET :]
150148 )
149+
150+ old_resource = self .codebase2 .get_resource_from_path (path_new )
151+
152+ if old_resource and old_resource .sha1 == new_resource .sha1 :
153+ old_resource_considered [old_resource .path ] = 1
154+ path_old = "/" .join (
155+ paths .split (old_resource .path )[Delta .OLD_CODEBASE_OFFSET :]
156+ )
157+ self .create_deltas (
158+ new_resource , old_resource , path_new , path_old , 0 , "unmodified" ,
159+ )
160+ self .stats .num_unmodified += 1
161+
162+ continue
163+
151164 ADDED = True
152165 for old_resource in self .codebase2 .walk ():
166+ if old_resource .path in old_resource_considered .keys ():
167+ continue
168+ path_old = "/" .join (
169+ paths .split (old_resource .path )[Delta .OLD_CODEBASE_OFFSET :]
170+ )
153171 if (
154172 old_resource .is_file
155- and not old_resource .sha1
156- in old_files_sha1_considered_in_deltas .keys ()
173+ and not old_resource .path in old_resource_considered .keys ()
157174 ):
158- path_old = "/" .join (
159- paths .split (old_resource .path )[Delta .OLD_CODEBASE_OFFSET :]
160- )
175+
161176 if path_new == path_old :
162177 ADDED = False
163178 if new_resource .sha1 == old_resource .sha1 :
164- old_files_sha1_considered_in_deltas [
165- old_resource .sha1
166- ] = 1
179+ old_resource_considered [old_resource .path ] = 1
167180 self .create_deltas (
168181 new_resource ,
169182 old_resource ,
170183 path_new ,
171184 path_old ,
172185 0 ,
173- self .stats .num_unmodified ,
174186 "unmodified" ,
175187 )
188+ self .stats .num_unmodified += 1
176189 break
177190 else :
178- old_files_sha1_considered_in_deltas [
179- old_resource .sha1
180- ] = 1
191+ old_resource_considered [old_resource .path ] = 1
181192 self .create_deltas (
182193 new_resource ,
183194 old_resource ,
184195 path_new ,
185196 path_old ,
186197 20 ,
187- self .stats .num_modified ,
188198 "modified" ,
189199 )
200+ self .stats .num_modified += 1
190201 break
191202 else :
192203 if new_resource .sha1 == old_resource .sha1 :
193- old_files_sha1_considered_in_deltas [
194- old_resource .sha1
195- ] = 1
204+ old_resource_considered [old_resource .path ] = 1
196205 ADDED = False
197206 self .create_deltas (
198207 new_resource ,
199208 old_resource ,
200209 path_new ,
201210 path_old ,
202211 0 ,
203- self .stats .num_moved ,
204212 "moved" ,
205213 )
214+ self .stats .num_moved += 1
206215 break
207216
208217 if ADDED :
209218 self .create_deltas (
210- new_resource ,
211- None ,
212- path_new ,
213- None ,
214- 100 ,
215- self .stats .num_added ,
216- "added" ,
219+ new_resource , None , path_new , None , 100 , "added" ,
217220 )
221+ self .stats .num_added += 1
218222
219223 for old_resource_remaining in self .codebase2 .walk ():
220224 if (
221225 old_resource_remaining .is_file
222- and old_resource_remaining .sha1
223- not in old_files_sha1_considered_in_deltas .keys ()
226+ and old_resource_remaining .path not in old_resource_considered .keys ()
224227 ):
225228 path_old = "/" .join (
226229 paths .split (old_resource_remaining .path )[
227230 Delta .OLD_CODEBASE_OFFSET :
228231 ]
229232 )
230233 self .create_deltas (
231- None ,
232- old_resource_remaining ,
233- None ,
234- path_old ,
235- 0 ,
236- self .stats .num_removed ,
237- "removed" ,
234+ None , old_resource_remaining , None , path_old , 0 , "removed" ,
238235 )
236+ self .stats .num_removed += 1
239237
240238 def license_diff (self ):
241239 """
@@ -376,19 +374,23 @@ def licenses_to_dict(self, file):
376374 return []
377375
378376 def file_to_dict (self , deltacode , file , new_file = True ):
377+
379378 path_offset = (
380379 Delta .NEW_CODEBASE_OFFSET if new_file else Delta .OLD_CODEBASE_OFFSET
381380 )
382381 if file :
383382 return OrderedDict (
384383 [
385- ("path" , file .path ),
384+ ("path" , "/" . join ( paths . split ( file .path )[ path_offset :]) ),
386385 ("type" , file .type ),
387386 ("name" , file .name ),
388387 ("size" , file .size ),
389388 ("sha1" , file .sha1 ),
390- ("fingerprint" , deltacode .old_files_fingerprint .get (file .path , "" )),
391- ("original_path" , "/" .join (paths .split (file .path )[path_offset :])),
389+ (
390+ "fingerprint" ,
391+ file .fingerprint if hasattr (file , "fingerprint" ) else "" ,
392+ ),
393+ ("original_path" , file .path ),
392394 ("licenses" , self .licenses_to_dict (file )),
393395 ("copyrights" , self .copyrights_to_dict (file )),
394396 ]
@@ -399,6 +401,11 @@ def to_dict(self, deltacode):
399401 Return an OrderedDict comprising the 'factors', 'score' and new and old
400402 'path' attributes of the object.
401403 """
404+ if (
405+ not deltacode .options .get ("--all-delta-types" , "" ) == True
406+ and self .status == "unmodified"
407+ ):
408+ return
402409 if self .new_file :
403410 new_file = self .new_file .to_dict ()
404411 else :
0 commit comments