5858from dejacode_toolkit import spdx
5959from dejacode_toolkit .purldb import PurlDB
6060from dejacode_toolkit .purldb import pick_purldb_entry
61+ from dejacode_toolkit .purldb import pick_source_package
6162from dejacode_toolkit .scancodeio import ScanCodeIO
6263from dje import urn
6364from dje .copier import post_copy
@@ -1652,6 +1653,42 @@ def __str__(self):
16521653 return self .label
16531654
16541655
1656+ class PackageContentFieldMixin (models .Model ):
1657+ """
1658+ Field extracted from the `purldb.packagedb.models.Package` model.
1659+ It need to stay aligned with its upstream PurlDB implementation.
1660+ """
1661+
1662+ class PackageContentType (models .IntegerChoices ):
1663+ CURATION = 1 , "curation"
1664+ PATCH = 2 , "patch"
1665+ SOURCE_REPO = 3 , "source_repo"
1666+ SOURCE_ARCHIVE = 4 , "source_archive"
1667+ BINARY = 5 , "binary"
1668+ TEST = 6 , "test"
1669+ DOC = 7 , "doc"
1670+
1671+ package_content = models .IntegerField (
1672+ null = True ,
1673+ blank = True ,
1674+ choices = PackageContentType .choices ,
1675+ help_text = _ (
1676+ "Content of this Package as one of: {}" .format (", " .join (PackageContentType .labels ))
1677+ ),
1678+ )
1679+
1680+ class Meta :
1681+ abstract = True
1682+
1683+ @classmethod
1684+ def get_package_content_value_from_label (cls , label ):
1685+ """Convert a package_content string label to its integer value."""
1686+ try :
1687+ return cls .PackageContentType [label .upper ()].value
1688+ except (KeyError , AttributeError ):
1689+ return
1690+
1691+
16551692PACKAGE_URL_FIELDS = ["type" , "namespace" , "name" , "version" , "qualifiers" , "subpath" ]
16561693
16571694
@@ -1795,6 +1832,7 @@ class Package(
17951832 URLFieldsMixin ,
17961833 HashFieldsMixin ,
17971834 PackageURLMixin ,
1835+ PackageContentFieldMixin ,
17981836 DataspacedModel ,
17991837):
18001838 filename = models .CharField (
@@ -2504,7 +2542,7 @@ def create_from_url(cls, url, user):
25042542 package_for_match = cls (download_url = download_url )
25052543 package_for_match .set_package_url (package_url )
25062544 purldb_entries = package_for_match .get_purldb_entries (user )
2507- # Look for one ith the same exact purl in that case
2545+ # Look for one with the same exact purl in that case
25082546 if purldb_data := pick_purldb_entry (purldb_entries , purl = url ):
25092547 # The format from PurlDB is "2019-11-18T00:00:00Z" from DateTimeField
25102548 if release_date := purldb_data .get ("release_date" ):
@@ -2597,6 +2635,8 @@ def update_from_purldb(self, user):
25972635
25982636 - Retrieves matching entries from PurlDB using the given user.
25992637 - If exactly one match is found, its data is used directly.
2638+ - If multiple entries are found, leverage the package_content value when
2639+ available to select a "source" package.
26002640 - If multiple entries are found, only values that are non-empty and
26012641 common across all entries are merged and used to update the Package.
26022642 """
@@ -2607,6 +2647,8 @@ def update_from_purldb(self, user):
26072647 purldb_entries_count = len (purldb_entries )
26082648 if purldb_entries_count == 1 :
26092649 package_data = purldb_entries [0 ]
2650+ elif source_package := pick_source_package (purldb_entries ):
2651+ package_data = source_package
26102652 else :
26112653 package_data = merge_common_non_empty_values (purldb_entries )
26122654
@@ -2615,6 +2657,10 @@ def update_from_purldb(self, user):
26152657 package_data ["release_date" ] = release_date .split ("T" )[0 ]
26162658 package_data ["license_expression" ] = package_data .get ("declared_license_expression" )
26172659
2660+ if package_content := package_data .get ("package_content" ):
2661+ package_content_value = Package .get_package_content_value_from_label (package_content )
2662+ package_data ["package_content" ] = package_content_value
2663+
26182664 # Avoid raising an IntegrityError when the values in `package_data` for the
26192665 # identifier fields already exist on another Package instance.
26202666 #
@@ -2647,6 +2693,12 @@ def update_from_purldb(self, user):
26472693 override = False ,
26482694 override_unknown = True ,
26492695 )
2696+
2697+ if updated_fields :
2698+ msg = f"Automatically updated { ', ' .join (updated_fields )} from PurlDB."
2699+ logger .debug (f"PurlDB: { msg } " )
2700+ History .log_change (user , self , message = msg )
2701+
26502702 return updated_fields
26512703
26522704 def update_from_scan (self , user , update_products = False ):
0 commit comments