7
7
# See https://aboutcode.org for more information about nexB OSS projects.
8
8
#
9
9
10
+ import logging
10
11
import os
11
12
import uuid
12
- from fnmatch import fnmatchcase
13
- import logging
14
13
import sys
15
14
15
+ from fnmatch import fnmatchcase
16
+
16
17
import attr
17
- from packageurl import normalize_qualifiers
18
- from packageurl import PackageURL
19
18
import saneyaml
20
19
21
20
from commoncode import filetype
21
+ from commoncode .fileutils import as_posixpath
22
22
from commoncode .datautils import choices
23
23
from commoncode .datautils import Boolean
24
24
from commoncode .datautils import Date
25
25
from commoncode .datautils import Integer
26
26
from commoncode .datautils import List
27
27
from commoncode .datautils import Mapping
28
28
from commoncode .datautils import String
29
- from commoncode .fileutils import as_posixpath
30
29
from commoncode .resource import Resource
31
30
from license_expression import combine_expressions
32
31
from license_expression import Licensing
32
+ from packageurl import normalize_qualifiers
33
+ from packageurl import PackageURL
33
34
34
35
try :
35
36
from typecode import contenttype
41
42
except ImportError :
42
43
licensing = None
43
44
45
+ # FIXME: what if licensing is not importable?
44
46
from packagedcode .licensing import get_declared_license_expression_spdx
45
47
46
48
"""
@@ -963,7 +965,7 @@ def get_license_detections_and_expression(self):
963
965
return [], None
964
966
965
967
if self .datasource_id :
966
- default_relation_license = get_default_relation_license (
968
+ default_relation_license = get_default_relation_license (
967
969
datasource_id = self .datasource_id ,
968
970
)
969
971
else :
@@ -1020,12 +1022,11 @@ def add_to_package(package_uid, resource, codebase):
1020
1022
1021
1023
class DatafileHandler :
1022
1024
"""
1023
- A base handler class to handle any package manifests, lockfiles and data
1024
- files. Each subclass handles a package datafile format to parse datafiles
1025
- and assemble Package and Depdencies from these:
1025
+ A base handler class to handle any package manifest, lockfile, package database
1026
+ and related data files. Each subclass handles a package datafile format to parse
1027
+ datafiles and assemble Package and Dependencies from these:
1026
1028
1027
1029
- parses a datafile format and yields package data.
1028
-
1029
1030
- assembles this datafile package data in top-level packages and dependencies
1030
1031
- assigns package files to their package
1031
1032
"""
@@ -1036,6 +1037,16 @@ class DatafileHandler:
1036
1037
# can only contain ASCII letters, digits and underscore. Must be lowercase
1037
1038
datasource_id = None
1038
1039
1040
+ # style of package data processed by this handler, either app for application package like npm,
1041
+ # sys for system packages like rpm, or info for informational data file that provides hints but
1042
+ # is not a package manifest, like with a README file
1043
+ # possible values are app, sys and info
1044
+ datasource_type = 'app'
1045
+
1046
+ # tuple of specifically supported operating systems. If None or empty, all platforms are supported
1047
+ # possible values are win, mac, linux, freebsd
1048
+ supported_oses = tuple ()
1049
+
1039
1050
# Sequence of known fnmatch-style case-insensitive glob patterns (e.g., Unix
1040
1051
# shell style patterns) that apply on the whole POSIX path for package
1041
1052
# datafiles recognized and parsed by this parser. See fnmatch.fnmatch().
@@ -1056,7 +1067,7 @@ class DatafileHandler:
1056
1067
# Informational: Default primary language for this parser.
1057
1068
default_primary_language = None
1058
1069
1059
- # If the datafilehandler contains only resolved dependencies
1070
+ # If the handler is for a lockfile that contains locked/pinned, pre- resolved dependencies
1060
1071
is_lockfile = False
1061
1072
1062
1073
# Informational: Description of this parser
@@ -1065,7 +1076,9 @@ class DatafileHandler:
1065
1076
# Informational: URL that documents this file format
1066
1077
documentation_url = None
1067
1078
1068
- # Default Relation between license elements detected in an `extracted_license_statement`
1079
+ # Default license expression relation between the license detected in an
1080
+ # `extracted_license_statement` for this data file.
1081
+ # This may vary for each data file based on conventions and specifications.
1069
1082
default_relation_license = None
1070
1083
1071
1084
@classmethod
@@ -1494,11 +1507,44 @@ def get_top_level_resources(cls, manifest_resource, codebase):
1494
1507
"""
1495
1508
pass
1496
1509
1510
+ @classmethod
1511
+ def validate (cls ):
1512
+ """
1513
+ Validate this class.
1514
+ Raise ImproperlyConfiguredDatafileHandler exception on errors.
1515
+ """
1516
+
1517
+ did = cls .datasource_id
1518
+ if not did :
1519
+ raise ImproperlyConfiguredDatafileHandler (
1520
+ f'The handler { cls !r} has an empty datasource_id { did !r} .' )
1521
+
1522
+ DATASOURCE_TYPES = 'app' , 'sys' , 'info' ,
1523
+ dfs = cls .datasource_type
1524
+ if dfs not in DATASOURCE_TYPES :
1525
+ raise ImproperlyConfiguredDatafileHandler (
1526
+ f'The handler { did !r} : { cls !r} has an invalid '
1527
+ f'datasource_type: { dfs !r} : must be one of { DATASOURCE_TYPES !r} .'
1528
+ )
1529
+
1530
+ oses = 'linux' , 'win' , 'max' , 'freebsd' ,
1531
+ soses = cls .supported_oses
1532
+ if soses and not all (s in oses for s in soses ):
1533
+ raise ImproperlyConfiguredDatafileHandler (
1534
+ f'The handler { cls .datasource_id !r} : { cls !r} has invalid '
1535
+ f'supported_oses: { soses !r} : must be empty or among { oses !r} '
1536
+ )
1537
+
1538
+
1539
+ class ImproperlyConfiguredDatafileHandler (Exception ):
1540
+ """ScanCode Package Datafile Handler is not properly configured"""
1541
+ pass
1542
+
1497
1543
1498
1544
class NonAssemblableDatafileHandler (DatafileHandler ):
1499
1545
"""
1500
- A handler that has no default implmentation for the assemble method, e.g.,
1501
- it will not alone trigger the creation of a top-level Pacakge .
1546
+ A handler with a default implementation of an assemble method doing nothing , e.g.,
1547
+ it will not alone trigger the creation of a top-level Package .
1502
1548
"""
1503
1549
1504
1550
@classmethod
@@ -1531,8 +1577,8 @@ def build_purl(mapping):
1531
1577
subpath = mapping .get ('subpath' )
1532
1578
return PackageURL (
1533
1579
type = ptype ,
1534
- name = name ,
1535
1580
namespace = namespace ,
1581
+ name = name ,
1536
1582
version = version ,
1537
1583
qualifiers = qualifiers ,
1538
1584
subpath = subpath ,
@@ -1769,7 +1815,7 @@ def refresh_license_expressions(self, default_relation='AND'):
1769
1815
self .declared_license_expression_spdx = get_declared_license_expression_spdx (
1770
1816
declared_license_expression = self .declared_license_expression ,
1771
1817
)
1772
-
1818
+
1773
1819
if self .other_license_detections :
1774
1820
self .other_license_expression = str (combine_expressions (
1775
1821
expressions = [
0 commit comments