Skip to content

Commit

Permalink
Merge pull request #33 from OpenRailAssociation/use-purl-tools
Browse files Browse the repository at this point in the history
Replace purl -> coordinates logic with purl-tools
  • Loading branch information
mxmehl authored Feb 7, 2025
2 parents 8c46067 + d4d3bd8 commit 1ff24d6
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 95 deletions.
63 changes: 3 additions & 60 deletions complassist/_clearlydefined.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,70 +5,13 @@
"""Functions concerning working with ClearlyDefined"""

import logging
import sys
from os.path import join as pathjoin
from urllib.parse import urljoin

from packageurl import PackageURL
from purltools import purl2clearlydefined
from requests.exceptions import JSONDecodeError

from ._helpers import make_request_with_retry, replacer


def purl_to_cd_coordinates(purl: str) -> str:
"""
Converts a Package URL (purl) to ClearlyDefined coordinates.
Parses the purl and translates it into a coordinate format compatible with
ClearlyDefined, handling necessary type conversions and provider mappings.
Args:
purl (str): The Package URL to be converted.
Returns:
str: The ClearlyDefined coordinates derived from the purl.
Raises:
SystemExit: If the provided purl is not valid, the function logs a
critical error and exits.
"""
try:
purl_obj = PackageURL.from_string(purl)
except ValueError as exc:
logging.critical("Package URL '%s' does not seem to be a valid purl: %s", purl, exc)
sys.exit(1)

logging.debug("purl string '%s' converted to purl object '%s'", purl, repr(purl_obj))

# Convert to dict, replacing empty values with "-"
p = purl_obj.to_dict(empty="-")

# Fix types that are different in purl and CD
type_fix = {"cargo": "crate", "github": "git"}

coordinates: dict = {
"type": replacer(p.get("type", ""), type_fix),
"provider": "",
"namespace": p.get("namespace"),
"name": p.get("name"),
"version": p.get("version"),
}

# Update coordinates with provider, based on type
type_to_provider = {
"crate": "cratesio",
"git": "github",
"maven": "mavencentral",
"npm": "npmjs",
"pypi": "pypi",
}
coordinates["provider"] = replacer(coordinates["type"], type_to_provider)

coordinates_string = "/".join([v for _, v in coordinates.items()])

logging.debug("Converted '%s' to '%s'", purl, coordinates_string)

return coordinates_string
from ._helpers import make_request_with_retry


def _cdapi_call(
Expand Down Expand Up @@ -255,7 +198,7 @@ def get_clearlydefined_license_and_copyright_in_batches(
ClearlyDefined API did not return valid data.
"""
# Create connections between coordinates <-> purl
coordinates_purls = {purl_to_cd_coordinates(purl): purl for purl in purls}
coordinates_purls = {purl2clearlydefined(purl): purl for purl in purls}
# Request the CD API for the coordinates
api_return = _cdapi_call(
path="", method="POST", json_dict=list(coordinates_purls.keys()), expand="-files"
Expand Down
24 changes: 0 additions & 24 deletions complassist/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,6 @@ def dict_to_json(data: dict) -> str:
return json.dumps(data, indent=2, sort_keys=False)


def replacer(string: str, replacement_dict: dict) -> str:
"""
Replaces a string based on a replacement dictionary.
If the string matches a key in the replacement dictionary, it is replaced by
the corresponding value. If no match is found, the original string is
returned.
Args:
string (str): The string to be checked and possibly replaced.
replacement_dict (dict): A dictionary where keys are strings to be
replaced and values are their replacements.
Returns:
str: The replaced string if a match is found, otherwise the original
string.
"""
if string in replacement_dict:
replacement = replacement_dict.get(string, "")
return replacement

return string


def read_json_file(path: str) -> dict:
"""Open a JSON file and return it as dict"""
with open(path, "r", encoding="UTF-8") as jsonfile:
Expand Down
5 changes: 3 additions & 2 deletions complassist/_sbom_enrich.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
import logging
from datetime import datetime

from purltools import purl2clearlydefined

from . import __version__
from ._clearlydefined import (
get_clearlydefined_license_and_copyright,
get_clearlydefined_license_and_copyright_in_batches,
purl_to_cd_coordinates,
)
from ._helpers import extract_excerpt, read_json_file, write_json_file
from ._sbom_parse import (
Expand Down Expand Up @@ -291,7 +292,7 @@ def enrich_sbom_with_clearlydefined(
for purl in all_purls:
logging.info("Getting ClearlyDefined data for %s", purl)
cd_license, cd_copyright = get_clearlydefined_license_and_copyright(
coordinates=purl_to_cd_coordinates(purl)
coordinates=purl2clearlydefined(purl)
)
clearlydefined_data[purl] = {"license": cd_license, "copyright": cd_copyright}

Expand Down
7 changes: 4 additions & 3 deletions complassist/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
import logging
import sys

from purltools import purl2clearlydefined

from . import __version__
from ._clearlydefined import (
get_clearlydefined_license_and_copyright,
print_clearlydefined_result,
purl_to_cd_coordinates,
)
from ._helpers import dict_to_json
from ._licensing import get_outbound_candidate, list_all_licenses
Expand Down Expand Up @@ -306,11 +307,11 @@ def main(): # pylint: disable=too-many-branches, too-many-statements
elif args.command == "clearlydefined":
# ClearlyDefined conversion
if args.clearlydefined_command == "convert":
print(purl_to_cd_coordinates(purl=args.purl))
print(purl2clearlydefined(purl=args.purl))

elif args.clearlydefined_command == "fetch":
if args.purl:
coordinates = purl_to_cd_coordinates(purl=args.purl)
coordinates = purl2clearlydefined(purl=args.purl)
else:
coordinates = args.coordinates

Expand Down
25 changes: 20 additions & 5 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ compliance-assistant = 'complassist.main:main'

[tool.poetry.dependencies]
python = "^3.10"
packageurl-python = "^0.15.1"
requests = "^2.32.3"
flict = "^1.2.14"
docker = "^7.1.0"
license-expression = "^30.3.0"
purl-tools = "^0.1.0"


[tool.poetry.group.dev.dependencies]
Expand Down

0 comments on commit 1ff24d6

Please sign in to comment.