Skip to content

Commit 2aa3e98

Browse files
committed
Add initial code
Signed-off-by: Jono Yang <jyang@nexb.com>
1 parent 7a971d7 commit 2aa3e98

4 files changed

Lines changed: 116 additions & 5 deletions

File tree

setup.cfg

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
[metadata]
2-
name = skeleton
2+
name = purl-validator
33
license = Apache-2.0
44

55
# description must be on ONE line https://github.com/pypa/setuptools/issues/1390
6-
description = skeleton
6+
description = purl-validator
77
long_description = file:README.rst
88
long_description_content_type = text/x-rst
9-
url = https://github.com/aboutcode-org/skeleton
9+
url = https://github.com/aboutcode-org/purl-validator
1010

1111
author = nexB. Inc. and others
1212
author_email = info@aboutcode.org
@@ -43,6 +43,8 @@ setup_requires = setuptools_scm[toml] >= 4
4343

4444

4545
install_requires =
46+
commoncode
47+
ducer
4648

4749

4850
[options.packages.find]

src/README.rst

Lines changed: 0 additions & 2 deletions
This file was deleted.

src/__init__.py

Whitespace-only changes.

src/purl_validator/__init__.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#
2+
# Copyright (c) nexB Inc. and others.
3+
# SPDX-License-Identifier: Apache-2.0
4+
#
5+
# Visit https://aboutcode.org and https://github.com/aboutcode-org/ for support and download.
6+
# ScanCode is a trademark of nexB Inc.
7+
#
8+
# Licensed under the Apache License, Version 2.0 (the "License");
9+
# you may not use this file except in compliance with the License.
10+
# You may obtain a copy of the License at
11+
#
12+
# http://www.apache.org/licenses/LICENSE-2.0
13+
#
14+
# Unless required by applicable law or agreed to in writing, software
15+
# distributed under the License is distributed on an "AS IS" BASIS,
16+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
# See the License for the specific language governing permissions and
18+
# limitations under the License.
19+
#
20+
21+
from pathlib import Path
22+
import mmap
23+
24+
from commoncode import fileutils
25+
from packageurl import PackageURL
26+
import ducer
27+
28+
29+
PURLS = """
30+
pkg:maven/be.sweetmustard.vinegar/vinegar-pattern-matcher@0.1.1
31+
pkg:maven/be.sweetmustard.vinegar/vinegar-pattern-matcher@0.1.1?classifier=sources
32+
pkg:maven/be.sweetmustard.vinegar/vinegar-pattern-matcher@0.1.0
33+
pkg:maven/be.sweetmustard.vinegar/vinegar-pattern-matcher@0.1.0?classifier=sources
34+
""".split()
35+
36+
37+
def create_purl_map(purls):
38+
# Ensure elements of `purls` are strings:
39+
purl_strs = []
40+
for purl in purls:
41+
if not isinstance(purl, (PackageURL, str)):
42+
raise ValueError(f"invalid purl in `purls`: {purl}")
43+
if isinstance(purl, PackageURL):
44+
purl_str = purl.to_string()
45+
else:
46+
purl_str = purl
47+
purl_strs.append(purl_str)
48+
49+
# purl strs must be sorted and converted to bytes before going into the Map
50+
prepared_purl_strs = [(bytes(purl_str, "utf-8"), 1) for purl_str in sorted(purl_strs)]
51+
52+
# create map
53+
temp_dir = fileutils.get_temp_dir()
54+
map_loc = Path(temp_dir) / "purls.map"
55+
ducer.Map.build(map_loc, prepared_purl_strs)
56+
57+
return map_loc
58+
59+
60+
class PurlValidator:
61+
def __init__(self, purl_map_loc=None):
62+
self.created_maps = []
63+
64+
if purl_map_loc:
65+
if not isinstance(purl_map_loc, (Path, str)):
66+
raise ValueError("`purl_map_loc` must be a Path or path string")
67+
if not isinstance(purl_map_loc, Path):
68+
# Ensure purl_map_loc is a Path
69+
purl_map_loc = Path(purl_map_loc)
70+
else:
71+
# Create purl map from PURLS
72+
purl_map_loc = self.create_purl_map(purls=PURLS)
73+
74+
self.purl_map = self.load_purl_map(location=purl_map_loc)
75+
76+
def __del__(self):
77+
for loc in self.created_maps:
78+
fileutils.delete(loc.parent)
79+
80+
def create_purl_map(self, purls):
81+
purl_map_loc = create_purl_map(purls)
82+
self.created_maps.append(purl_map_loc)
83+
return purl_map_loc
84+
85+
def load_purl_map(self, location):
86+
with open(location, "rb") as f:
87+
mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
88+
m = ducer.Map(mm)
89+
return m
90+
91+
def validate_purl(self, purl):
92+
if not isinstance(purl, (PackageURL, str)):
93+
raise ValueError("`purl` must be a PackageURL or purl string")
94+
95+
# Ensure `purl` is a PackageURL
96+
if isinstance(purl, str):
97+
purl = PackageURL.from_string(purl)
98+
99+
# Convert purl to bytes
100+
purl_bytes = bytes(purl.to_string(), "utf-8")
101+
102+
return bool(self.purl_map.get(purl_bytes))
103+
104+
105+
if __name__ == "__main__":
106+
purl_validator = PurlValidator()
107+
print(
108+
purl_validator.validate_purl(
109+
"pkg:maven/be.sweetmustard.vinegar/vinegar-pattern-matcher@0.1.1"
110+
)
111+
)

0 commit comments

Comments
 (0)