Skip to content

Commit 17778de

Browse files
committed
integrated with Virtualcodebase of scancode
Signed-off-by: Pratikrocks <pratikrocks.dey11@gmail.com>
1 parent 6778882 commit 17778de

3 files changed

Lines changed: 294 additions & 110 deletions

File tree

src/deltacode/__init__.py

Lines changed: 171 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from deltacode.models import File
3131
from deltacode.models import Scan
3232
from deltacode import utils
33+
from scancode.resource import VirtualCodebase
3334

3435

3536
from pkg_resources import get_distribution, DistributionNotFound
@@ -48,14 +49,25 @@ class DeltaCode(object):
4849
the form of File objects) contained in those scans.
4950
"""
5051
def __init__(self, new_path, old_path, options):
51-
self.new = Scan(new_path)
52-
self.old = Scan(old_path)
52+
if new_path and old_path:
53+
self.codebase1 = VirtualCodebase(new_path)
54+
self.codebase2 = VirtualCodebase(old_path)
55+
self.new_files_count = 0 #keeps the count of the new file
56+
self.old_files_count = 0 #keeps the count of old files
57+
self.new_files = [] # a list of [[new file1:Original path],[new file2:Original Path],...]
58+
self.old_files = [] # a list of [[old file1:Original path],[old file2:Original Path],...]
59+
self.new_files_fingerprint = dict() # map of { {new_file1:fingerprint},{new_file2:fingerprint},...} it will be needed when we need the fingerprints
60+
self.old_files_fingerprint = dict() # map of { {old_file1:fingerprint},{old_file2:fingerprint},...}
5361
self.options = options
5462
self.deltas = []
5563
self.errors = []
56-
self.stats = Stat(self.new.files_count, self.old.files_count)
64+
self.enumerate_files_from_codebases()
65+
self.stats = Stat(self.new_files_count, self.old_files_count)
66+
67+
if new_path != None and old_path != None:
5768

58-
if self.new.path != '' and self.old.path != '':
69+
self.new_files_errors = []
70+
self.old_files_errors = []
5971
self.determine_delta()
6072
self.determine_moved()
6173
self.license_diff()
@@ -67,6 +79,46 @@ def __init__(self, new_path, old_path, options):
6779
self.deltas.sort(key=lambda Delta: Delta.factors, reverse=False)
6880
self.deltas.sort(key=lambda Delta: Delta.score, reverse=True)
6981

82+
def get_files(self,codebase,is_new):
83+
"""
84+
Walk through the codebase, then generate the resources it(including all files and its directories)
85+
then we enumerate over this generated codebase to get file, and directories as (obj)
86+
Now during the time of enumeration we append files in the self.new_files list and incremants out self.new_files_count
87+
Similarly for old_files.
88+
Now , we also maintain a map which maps from object path to its fingerprint.
89+
This map will be required when we calculate the hamming distances and compare similarity.
90+
"""
91+
resources = codebase.walk_filtered(topdown=True)
92+
for i,obj in enumerate(resources):
93+
if is_new:
94+
if obj.is_file:
95+
# append in the new_files
96+
self.new_files.append([obj,''])
97+
# increment the new files count
98+
self.new_files_count += 1
99+
try :
100+
self.new_files_fingerprint[obj.path] = obj.fingerprint
101+
except AttributeError:
102+
self.new_files_fingerprint[obj.path] = None
103+
else:
104+
if obj.is_file:
105+
# append in the old files
106+
self.old_files.append([obj,''])
107+
# increment the old files count
108+
self.old_files_count += 1
109+
try:
110+
self.old_files_fingerprint[obj.path] = obj.fingerprint
111+
except AttributeError:
112+
self.old_files_fingerprint[obj.path] = None
113+
114+
def enumerate_files_from_codebases(self):
115+
"""
116+
An method which call the utility function get_files for generating the codebase
117+
"""
118+
self.get_files(self.codebase1,is_new = True)
119+
self.get_files(self.codebase2,is_new = False)
120+
121+
70122
def align_scans(self):
71123
"""
72124
Seek to align the paths of a pair of files (File objects) in the pair
@@ -75,12 +127,15 @@ def align_scans(self):
75127
which calls utils.align_trees().
76128
"""
77129
try:
78-
utils.fix_trees(self.new.files, self.old.files)
130+
utils.fix_trees(self.new_files, self.old_files)
79131
except utils.AlignmentException:
80-
for f in self.new.files:
81-
f.original_path = f.path
82-
for f in self.old.files:
83-
f.original_path = f.path
132+
# self.new_files is a list of type [[ScannedResourceObject,originalPath],...]
133+
# initially all original path are set to empty string
134+
# so this part actually sets the original paths
135+
for f in self.new_files:
136+
f[1] = f[0].path
137+
for f in self.old_files:
138+
f[1] = f[0].path
84139

85140
def similarity(self):
86141
"""
@@ -93,12 +148,13 @@ def similarity(self):
93148
for delta in self.deltas:
94149
if delta.new_file == None or delta.old_file == None:
95150
continue
96-
new_fingerprint = delta.new_file.fingerprint
97-
old_fingerprint = delta.old_file.fingerprint
151+
# this extracts the fingerprint corresponding to the particular file path
152+
new_fingerprint = self.new_files_fingerprint[delta.new_file.path]
153+
old_fingerprint = self.old_files_fingerprint[delta.old_file.path]
98154
if new_fingerprint == None or old_fingerprint == None:
99155
continue
100-
new_fingerprint = utils.bitarray_from_hex(delta.new_file.fingerprint)
101-
old_fingerprint = utils.bitarray_from_hex(delta.old_file.fingerprint)
156+
new_fingerprint = utils.bitarray_from_hex(self.new_files_fingerprint[delta.new_file.path])
157+
old_fingerprint = utils.bitarray_from_hex(self.old_files_fingerprint[delta.old_file.path])
102158
hamming_distance = utils.hamming_distance(new_fingerprint, old_fingerprint)
103159
if hamming_distance > 0 and hamming_distance <= SIMILARITY_LIMIT:
104160
delta.score += hamming_distance
@@ -112,8 +168,9 @@ def determine_delta(self):
112168
"""
113169
# align scan and create our index
114170
self.align_scans()
115-
new_index = self.new.index_files()
116-
old_index = self.old.index_files()
171+
# returns file index wrt to old and new files
172+
new_index = utils.index_files(self.new_files)
173+
old_index = utils.index_files(self.old_files)
117174

118175
# gathering counts to ensure no files lost or missing from our 'deltas' set
119176
new_visited, old_visited = 0, 0
@@ -172,12 +229,12 @@ def determine_delta(self):
172229
continue
173230

174231
# make sure everything is accounted for
175-
if new_visited != self.new.files_count:
232+
if new_visited != self.new_files_count:
176233
self.errors.append(
177234
'DeltaCode Warning: new_visited({}) != new_total({}). Assuming old scancode format.'.format(new_visited, self.new.files_count)
178235
)
179236

180-
if old_visited != self.old.files_count:
237+
if old_visited != self.old_files_count:
181238
self.errors.append(
182239
'DeltaCode Warning: old_visited({}) != old_total({}). Assuming old scancode format.'.format(old_visited, self.old.files_count)
183240
)
@@ -323,7 +380,99 @@ def is_added(self):
323380
if self.new_file and not self.old_file:
324381
return True
325382

326-
def to_dict(self):
383+
def copyrights_to_dict(self,file):
384+
"""
385+
Given a Copyright object, return an OrderedDict with the full
386+
set of fields from the ScanCode 'copyrights' value.
387+
"""
388+
copyrightC = []
389+
try :
390+
copyrightC = file.copyrights
391+
except AttributeError:
392+
# arises when the ScannedResource do not have any license attribute
393+
return []
394+
if len(copyrightC) == 0:
395+
return []
396+
if isinstance(copyrightC[0],OrderedDict):
397+
# all the copyright are in correct format
398+
all_copyrights = []
399+
for i in range(len(copyrightC)):
400+
# we iterate over all the copyrights
401+
statements = copyrightC[i].get("statements")
402+
holders = copyrightC[i].get("holders")
403+
d = OrderedDict([
404+
('statements', statements),
405+
('holders', holders)
406+
])
407+
all_copyrights.append(d)
408+
409+
return all_copyrights
410+
411+
def licenses_to_dict(self,file):
412+
"""
413+
Given a License object, return an OrderedDict with the full
414+
set of fields from the ScanCode 'license' value.
415+
"""
416+
licenseL = []
417+
try:
418+
licenseL = file.license
419+
except AttributeError:
420+
# arises when the ScannedResource do not have any license attribute
421+
return []
422+
423+
if len(licenseL) == 0:
424+
return []
425+
if isinstance(licenseL[0],OrderedDict):
426+
# the licenses are in the correct format
427+
all_licenses = []
428+
for i in range(len(licenseL)):
429+
# we iterate over all the licenses
430+
d = OrderedDict([
431+
('key', licenseL[i]["key"]),
432+
('score', licenseL[i]["score"]),
433+
('short_name', licenseL[i]["short_name"]),
434+
('category', licenseL[i]["category"]),
435+
('owner', licenseL[i]["owner"])
436+
])
437+
all_licenses.append(d)
438+
return all_licenses
439+
440+
def new_file_to_dict(self,deltacode):
441+
# if self.new_file is not empty we return the new file attributes
442+
if self.new_file:
443+
return OrderedDict([
444+
("path",self.new_file.path),
445+
("type",self.new_file.type),
446+
("name",self.new_file.name),
447+
("size",self.new_file.size),
448+
("sha1",self.new_file.sha1),
449+
("fingerprint",deltacode.new_files_fingerprint[self.new_file.path]),
450+
("original_path",self.new_file.path),
451+
# since license itself has many sub fields so we obtain it from another utility function
452+
("licenses",self.licenses_to_dict(self.new_file)),
453+
# since copyright itself has many sub fields so we obtain it from another utility function
454+
("copyrights",self.copyrights_to_dict(self.new_file))
455+
])
456+
457+
458+
def old_file_to_dict(self,deltacode):
459+
if self.old_file :
460+
return OrderedDict([
461+
("path",self.old_file.path),
462+
("type",self.old_file.type),
463+
("name",self.old_file.name),
464+
("size",self.old_file.size),
465+
("sha1",self.old_file.sha1),
466+
("fingerprint",deltacode.old_files_fingerprint[self.old_file.path]),
467+
("original_path",self.old_file.path),
468+
# since license itself has many sub fields so we obtain it from another utility function
469+
("licenses",self.licenses_to_dict(self.old_file)),
470+
# since copyright itself has many sub fields so we obtain it from another utility function
471+
("copyrights",self.copyrights_to_dict(self.old_file))
472+
])
473+
474+
475+
def to_dict(self,deltacode):
327476
"""
328477
Return an OrderedDict comprising the 'factors', 'score' and new and old
329478
'path' attributes of the object.
@@ -342,8 +491,10 @@ def to_dict(self):
342491
('status', self.status),
343492
('factors', self.factors),
344493
('score', self.score),
345-
('new', new_file),
346-
('old', old_file),
494+
# receives the detail of the new file
495+
('new', self.new_file_to_dict(deltacode)),
496+
# receives the details of the old file
497+
('old', self.old_file_to_dict(deltacode)),
347498
])
348499

349500
class Stat(object):

0 commit comments

Comments
 (0)