Skip to content

Commit 2e824e1

Browse files
authored
Merge pull request #180 from nexB/fix-filter-by-checksums
Fix filter by checksums
2 parents 3b820dd + f814dd8 commit 2e824e1

8 files changed

Lines changed: 264 additions & 11 deletions

File tree

matchcode-toolkit/CHANGELOG.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
Changelog
22
=========
33

4+
v1.1.3
5+
------
6+
7+
*2023-08-31* -- Do not fingerprint empty directories.
8+
*2023-08-31* -- Track fingerprints to ignore in ``matchcode_toolkit.fingerprinting.IGNORED_DIRECTORY_FINGERPRINTS``.
9+
410
v1.1.2
511
------
612

matchcode-toolkit/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "matchcode-toolkit"
3-
version = "1.1.1"
3+
version = "1.1.3"
44

55
[build-system]
66
requires = ["setuptools >= 50", "wheel", "setuptools_scm[toml] >= 6"]

matchcode-toolkit/setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = matchcode-toolkit
3-
version = 1.1.2
3+
version = 1.1.3
44
license = Apache-2.0
55

66
# description must be on ONE line https://github.com/pypa/setuptools/issues/1390

matchcode-toolkit/src/matchcode_toolkit/fingerprinting.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212
from matchcode_toolkit.halohash import BitAverageHaloHash
1313

1414

15+
# A collection of directory fingerprints that we want to avoid
16+
IGNORED_DIRECTORY_FINGERPRINTS = [
17+
# This is both the directory content and directory structure fingerprint for
18+
# an empty directory.
19+
'0000000000000000000000000000000000000000',
20+
]
21+
22+
1523
def _create_directory_fingerprint(inputs):
1624
"""
1725
Return a 128-bit BitAverageHaloHash fingerprint in hex from `inputs`
@@ -75,7 +83,7 @@ def _compute_directory_fingerprints(directory, codebase):
7583
"""
7684
# We do not want to add empty files to our fingerprint
7785
children = [r for r in directory.walk(codebase) if r.is_file and r.size]
78-
if len(children) == 1:
86+
if len(children) <= 1:
7987
return
8088

8189
directory_content_fingerprint = create_content_fingerprint(children)

matchcode-toolkit/tests/test_fingerprinting.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,22 @@ def test_compute_codebase_directory_fingerprints(self):
105105
expected_directory_structure = '000000034f9bf110673bdf06197cd514a799a66c'
106106
self.assertEqual(expected_directory_content, directory_content)
107107
self.assertEqual(expected_directory_structure, directory_structure)
108+
109+
def test_do_not_compute_fingerprint_for_empty_dirs(self):
110+
scan_loc = self.get_test_loc('test.json')
111+
vc = VirtualCodebase(location=scan_loc)
112+
vc = compute_codebase_directory_fingerprints(vc)
113+
directory_content = vc.root.extra_data['directory_content']
114+
directory_structure = vc.root.extra_data['directory_structure']
115+
expected_directory_content = '000000032a5fa8d01922536b53e8fc6e3d43766f'
116+
expected_directory_structure = '000000030a399ce2b947a6f611821965a4fcc577'
117+
self.assertEqual(expected_directory_content, directory_content)
118+
self.assertEqual(expected_directory_structure, directory_structure)
119+
# These directories should not have fingerprints generated or stored in
120+
# extra_data
121+
empty_dir_1 = vc.get_resource('test/test')
122+
empty_dir_2 = vc.get_resource('test/test/test2')
123+
self.assertEqual({}, empty_dir_1.extra_data)
124+
self.assertEqual({}, empty_dir_1.extra_data)
125+
self.assertEqual({}, empty_dir_2.extra_data)
126+
self.assertEqual({}, empty_dir_2.extra_data)
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
{
2+
"headers": [
3+
{
4+
"tool_name": "scancode-toolkit",
5+
"tool_version": "32.0.6",
6+
"options": {
7+
"input": [
8+
"/home/jono/Desktop/test"
9+
],
10+
"--info": true,
11+
"--json-pp": "/home/jono/test.json"
12+
},
13+
"notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.",
14+
"start_timestamp": "2023-08-31T215533.874398",
15+
"end_timestamp": "2023-08-31T215533.977407",
16+
"output_format_version": "3.0.0",
17+
"duration": 0.10302162170410156,
18+
"message": null,
19+
"errors": [],
20+
"warnings": [],
21+
"extra_data": {
22+
"system_environment": {
23+
"operating_system": "linux",
24+
"cpu_architecture": "64",
25+
"platform": "Linux-5.4.0-150-generic-x86_64-with-glibc2.27",
26+
"platform_version": "#167~18.04.1-Ubuntu SMP Wed May 24 00:51:42 UTC 2023",
27+
"python_version": "3.10.8 (main, Nov 20 2022, 18:43:48) [GCC 7.5.0]"
28+
},
29+
"spdx_license_list_version": "3.21",
30+
"files_count": 3
31+
}
32+
}
33+
],
34+
"files": [
35+
{
36+
"path": "test",
37+
"type": "directory",
38+
"name": "test",
39+
"base_name": "test",
40+
"extension": "",
41+
"size": 0,
42+
"date": null,
43+
"sha1": null,
44+
"md5": null,
45+
"sha256": null,
46+
"mime_type": null,
47+
"file_type": null,
48+
"programming_language": null,
49+
"is_binary": false,
50+
"is_text": false,
51+
"is_archive": false,
52+
"is_media": false,
53+
"is_source": false,
54+
"is_script": false,
55+
"files_count": 3,
56+
"dirs_count": 3,
57+
"size_count": 55,
58+
"scan_errors": []
59+
},
60+
{
61+
"path": "test/package.json",
62+
"type": "file",
63+
"name": "package.json",
64+
"base_name": "package",
65+
"extension": ".json",
66+
"size": 3,
67+
"date": "2023-08-31",
68+
"sha1": "f10e2821bbbea527ea02200352313bc059445190",
69+
"md5": "7815696ecbf1c96e6894b779456d330e",
70+
"sha256": "688787d8ff144c502c7f5cffaafe2cc588d86079f9de88304c26b0cb99ce91c6",
71+
"mime_type": "text/plain",
72+
"file_type": "ASCII text, with no line terminators",
73+
"programming_language": null,
74+
"is_binary": false,
75+
"is_text": true,
76+
"is_archive": false,
77+
"is_media": false,
78+
"is_source": false,
79+
"is_script": false,
80+
"files_count": 0,
81+
"dirs_count": 0,
82+
"size_count": 0,
83+
"scan_errors": []
84+
},
85+
{
86+
"path": "test/src",
87+
"type": "directory",
88+
"name": "src",
89+
"base_name": "src",
90+
"extension": "",
91+
"size": 0,
92+
"date": null,
93+
"sha1": null,
94+
"md5": null,
95+
"sha256": null,
96+
"mime_type": null,
97+
"file_type": null,
98+
"programming_language": null,
99+
"is_binary": false,
100+
"is_text": false,
101+
"is_archive": false,
102+
"is_media": false,
103+
"is_source": false,
104+
"is_script": false,
105+
"files_count": 2,
106+
"dirs_count": 0,
107+
"size_count": 52,
108+
"scan_errors": []
109+
},
110+
{
111+
"path": "test/src/bar.txt",
112+
"type": "file",
113+
"name": "bar.txt",
114+
"base_name": "bar",
115+
"extension": ".txt",
116+
"size": 3,
117+
"date": "2023-08-31",
118+
"sha1": "62cdb7020ff920e5aa642c3d4066950dd1f01f4d",
119+
"md5": "37b51d194a7513e45b56f6524f2d51f2",
120+
"sha256": "fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9",
121+
"mime_type": "text/plain",
122+
"file_type": "ASCII text, with no line terminators",
123+
"programming_language": null,
124+
"is_binary": false,
125+
"is_text": true,
126+
"is_archive": false,
127+
"is_media": false,
128+
"is_source": false,
129+
"is_script": false,
130+
"files_count": 0,
131+
"dirs_count": 0,
132+
"size_count": 0,
133+
"scan_errors": []
134+
},
135+
{
136+
"path": "test/src/foo.js",
137+
"type": "file",
138+
"name": "foo.js",
139+
"base_name": "foo",
140+
"extension": ".js",
141+
"size": 49,
142+
"date": "2023-07-26",
143+
"sha1": "fef9e8e1746b8f2175b500c57a9c6d250623885b",
144+
"md5": "54149367c4c4523241c945701eee1a02",
145+
"sha256": "8ab7888ffceb5004ff3d14417c71d7b56812e04d0ac86545e1592208c6d56d04",
146+
"mime_type": "text/plain",
147+
"file_type": "ASCII text",
148+
"programming_language": "JavaScript",
149+
"is_binary": false,
150+
"is_text": true,
151+
"is_archive": false,
152+
"is_media": false,
153+
"is_source": true,
154+
"is_script": false,
155+
"files_count": 0,
156+
"dirs_count": 0,
157+
"size_count": 0,
158+
"scan_errors": []
159+
},
160+
{
161+
"path": "test/test",
162+
"type": "directory",
163+
"name": "test",
164+
"base_name": "test",
165+
"extension": "",
166+
"size": 0,
167+
"date": null,
168+
"sha1": null,
169+
"md5": null,
170+
"sha256": null,
171+
"mime_type": null,
172+
"file_type": null,
173+
"programming_language": null,
174+
"is_binary": false,
175+
"is_text": false,
176+
"is_archive": false,
177+
"is_media": false,
178+
"is_source": false,
179+
"is_script": false,
180+
"files_count": 0,
181+
"dirs_count": 1,
182+
"size_count": 0,
183+
"scan_errors": []
184+
},
185+
{
186+
"path": "test/test/test2",
187+
"type": "directory",
188+
"name": "test2",
189+
"base_name": "test2",
190+
"extension": "",
191+
"size": 0,
192+
"date": null,
193+
"sha1": null,
194+
"md5": null,
195+
"sha256": null,
196+
"mime_type": null,
197+
"file_type": null,
198+
"programming_language": null,
199+
"is_binary": false,
200+
"is_text": false,
201+
"is_archive": false,
202+
"is_media": false,
203+
"is_source": false,
204+
"is_script": false,
205+
"files_count": 0,
206+
"dirs_count": 0,
207+
"size_count": 0,
208+
"scan_errors": []
209+
}
210+
]
211+
}

packagedb/api.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -531,9 +531,11 @@ def filter_by_checksums(self, request, *args, **kwargs):
531531
This will return Packages whose sha1 or md5 matches those values.
532532
"""
533533
data = dict(request.data)
534+
534535
unsupported_fields = []
536+
supported_fields = ['md5', 'sha1', 'sha256', 'sha512', 'enhance_package_data']
535537
for field, value in data.items():
536-
if field not in ('md5', 'sha1', 'sha256', 'sha512', 'enhance_package_data'):
538+
if field not in supported_fields:
537539
unsupported_fields.append(field)
538540

539541
if unsupported_fields:
@@ -544,14 +546,21 @@ def filter_by_checksums(self, request, *args, **kwargs):
544546
return Response(response_data)
545547

546548
enhance_package_data = data.pop('enhance_package_data', False)
547-
q = Q()
549+
if not data:
550+
response_data = {
551+
'status': 'No values provided'
552+
}
553+
return Response(response_data)
554+
555+
lookups = Q()
548556
for field, value in data.items():
557+
value = value or []
549558
# We create this intermediate dictionary so we can modify the field
550559
# name to have __in at the end
551560
d = {f'{field}__in': value}
552-
q |= Q(**d)
561+
lookups |= Q(**d)
553562

554-
qs = Package.objects.filter(q)
563+
qs = Package.objects.filter(lookups)
555564
paginated_qs = self.paginate_queryset(qs)
556565
if enhance_package_data:
557566
serialized_package_data = [get_enhanced_package(package=package) for package in paginated_qs]
@@ -685,7 +694,7 @@ class PackageSetViewSet(viewsets.ReadOnlyModelViewSet):
685694
def get_resolved_purls(packages):
686695
"""
687696
Take a list of dict containing purl or version-less purl along with vers
688-
and return a list of resolved purls, a list of unsupported purls, and a
697+
and return a list of resolved purls, a list of unsupported purls, and a
689698
list of unsupported vers.
690699
"""
691700
unique_resolved_purls = set()
@@ -765,9 +774,9 @@ def get_all_versions(purl: PackageURL):
765774

766775
package_name = get_api_package_name(purl)
767776
versionAPI = get_version_fetcher(purl)
768-
777+
769778
if not package_name or not versionAPI:
770-
return
779+
return
771780

772781
all_versions = versionAPI().fetch(package_name)
773782
versionClass = VERSION_CLASS_BY_PACKAGE_TYPE.get(purl.type)

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ install_requires =
5555
rubymarshal == 1.0.3
5656
scancode-toolkit[full] == 32.0.6
5757
urlpy == 0.5
58-
matchcode-toolkit == 1.1.1
58+
matchcode-toolkit >= 1.1.1
5959
univers == 30.10.0
6060
setup_requires = setuptools_scm[toml] >= 4
6161

0 commit comments

Comments
 (0)