fosslight-util 2.0.0__tar.gz → 2.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/PKG-INFO +1 -1
  2. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/requirements.txt +1 -1
  3. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/setup.py +1 -1
  4. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/oss_item.py +2 -0
  5. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/output_format.py +86 -12
  6. fosslight_util-2.0.1/src/fosslight_util/write_spdx.py +259 -0
  7. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util.egg-info/PKG-INFO +1 -1
  8. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util.egg-info/requires.txt +1 -1
  9. fosslight_util-2.0.0/src/fosslight_util/write_spdx.py +0 -222
  10. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/LICENSE +0 -0
  11. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/MANIFEST.in +0 -0
  12. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/README.md +0 -0
  13. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/setup.cfg +0 -0
  14. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/__init__.py +0 -0
  15. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/_get_downloadable_url.py +0 -0
  16. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/compare_yaml.py +0 -0
  17. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/constant.py +0 -0
  18. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/convert_excel_to_yaml.py +0 -0
  19. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/correct.py +0 -0
  20. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/cover.py +0 -0
  21. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/download.py +0 -0
  22. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/help.py +0 -0
  23. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/parsing_yaml.py +0 -0
  24. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/read_excel.py +0 -0
  25. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/resources/frequentLicenselist.json +0 -0
  26. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/resources/frequent_license_nick_list.json +0 -0
  27. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/resources/licenses.json +0 -0
  28. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/set_log.py +0 -0
  29. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/spdx_licenses.py +0 -0
  30. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/timer_thread.py +0 -0
  31. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/write_excel.py +0 -0
  32. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/write_opossum.py +0 -0
  33. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/write_scancodejson.py +0 -0
  34. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/write_txt.py +0 -0
  35. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util/write_yaml.py +0 -0
  36. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util.egg-info/SOURCES.txt +0 -0
  37. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util.egg-info/dependency_links.txt +0 -0
  38. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util.egg-info/entry_points.txt +0 -0
  39. {fosslight_util-2.0.0 → fosslight_util-2.0.1}/src/fosslight_util.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fosslight_util
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: FOSSLight Util
5
5
  Home-page: https://github.com/fosslight/fosslight_util
6
6
  Author: LG Electronics
@@ -8,7 +8,7 @@ coloredlogs
8
8
  python3-wget
9
9
  beautifulsoup4
10
10
  jsonmerge
11
- spdx-tools==0.7.0rc0
11
+ spdx-tools
12
12
  setuptools>=65.5.1 # not directly required, pinned by Snyk to avoid a vulnerability
13
13
  numpy; python_version < '3.8'
14
14
  numpy>=1.22.2; python_version >= '3.8'
@@ -14,7 +14,7 @@ with open('requirements.txt', 'r', 'utf-8') as f:
14
14
  if __name__ == "__main__":
15
15
  setup(
16
16
  name='fosslight_util',
17
- version='2.0.0',
17
+ version='2.0.1',
18
18
  package_dir={"": "src"},
19
19
  packages=find_packages(where='src'),
20
20
  description='FOSSLight Util',
@@ -10,6 +10,7 @@ from fosslight_util.cover import CoverItem
10
10
  from typing import List, Dict
11
11
 
12
12
  _logger = logging.getLogger(LOGGER_NAME)
13
+ CHECKSUM_NULL = "0"
13
14
 
14
15
 
15
16
  class OssItem:
@@ -98,6 +99,7 @@ class FileItem:
98
99
  self._comment = ""
99
100
  self.is_binary = False
100
101
  self.oss_items: List[OssItem] = []
102
+ self.checksum = CHECKSUM_NULL
101
103
 
102
104
  def __del__(self):
103
105
  pass
@@ -3,12 +3,16 @@
3
3
  # Copyright (c) 2021 LG Electronics Inc.
4
4
  # SPDX-License-Identifier: Apache-2.0
5
5
  import os
6
+ import platform
6
7
  from fosslight_util.write_excel import write_result_to_excel, write_result_to_csv
7
8
  from fosslight_util.write_opossum import write_opossum
8
9
  from fosslight_util.write_yaml import write_yaml
10
+ from fosslight_util.write_spdx import write_spdx
9
11
  from typing import Tuple
10
12
 
11
- SUPPORT_FORMAT = {'excel': '.xlsx', 'csv': '.csv', 'opossum': '.json', 'yaml': '.yaml'}
13
+ SUPPORT_FORMAT = {'excel': '.xlsx', 'csv': '.csv', 'opossum': '.json', 'yaml': '.yaml',
14
+ 'spdx-yaml': '.yaml', 'spdx-json': '.json', 'spdx-xml': '.xml',
15
+ 'spdx-tag': '.tag'}
12
16
 
13
17
 
14
18
  def check_output_format(output='', format='', customized_format={}):
@@ -106,8 +110,62 @@ def check_output_formats(output='', formats=[], customized_format={}):
106
110
  return success, msg, output_path, output_files, output_extensions
107
111
 
108
112
 
113
+ def check_output_formats_v2(output='', formats=[], customized_format={}):
114
+ success = True
115
+ msg = ''
116
+ output_path = ''
117
+ output_files = []
118
+ output_extensions = []
119
+
120
+ if customized_format:
121
+ support_format = customized_format
122
+ else:
123
+ support_format = SUPPORT_FORMAT
124
+
125
+ if formats:
126
+ # If -f option exist
127
+ formats = [format.lower() for format in formats]
128
+ for format in formats:
129
+ if format not in list(support_format.keys()):
130
+ success = False
131
+ msg = 'Enter the supported format with -f option: ' + ', '.join(list(support_format.keys()))
132
+ else:
133
+ output_extensions.append(support_format[format])
134
+
135
+ if success:
136
+ if output != '':
137
+ basename_extension = ''
138
+ if not os.path.isdir(output):
139
+ output_path = os.path.dirname(output)
140
+
141
+ basename = os.path.basename(output)
142
+ basename_file, basename_extension = os.path.splitext(basename)
143
+ if basename_extension:
144
+ if formats:
145
+ if basename_extension not in output_extensions:
146
+ success = False
147
+ msg = f"The format of output file(-o:'{output}') should be in the format list(-f:'{formats}')."
148
+ else:
149
+ if basename_extension not in support_format.values():
150
+ success = False
151
+ msg = 'Enter the supported file extension: ' + ', '.join(list(support_format.values()))
152
+ output_extensions.append(basename_extension)
153
+ output_files = [basename_file for _ in range(len(output_extensions))]
154
+ else:
155
+ output_path = output
156
+ if not output_extensions:
157
+ output_extensions = ['.xlsx']
158
+ if not formats:
159
+ for ext in output_extensions:
160
+ for key, value in support_format.items():
161
+ if value == ext:
162
+ formats.append(key)
163
+ break
164
+ return success, msg, output_path, output_files, output_extensions, formats
165
+
166
+
109
167
  def write_output_file(output_file_without_ext: str, file_extension: str, scan_item, extended_header: dict = {},
110
- hide_header: dict = {}) -> Tuple[bool, str, str]:
168
+ hide_header: dict = {}, format: str = '', spdx_version: str = '2.3') -> Tuple[bool, str, str]:
111
169
  success = True
112
170
  msg = ''
113
171
 
@@ -115,16 +173,32 @@ def write_output_file(output_file_without_ext: str, file_extension: str, scan_it
115
173
  file_extension = '.xlsx'
116
174
  result_file = output_file_without_ext + file_extension
117
175
 
118
- if file_extension == '.xlsx':
119
- success, msg = write_result_to_excel(result_file, scan_item, extended_header, hide_header)
120
- elif file_extension == '.csv':
121
- success, msg, result_file = write_result_to_csv(result_file, scan_item, False, extended_header)
122
- elif file_extension == '.json':
123
- success, msg = write_opossum(result_file, scan_item)
124
- elif file_extension == '.yaml':
125
- success, msg, result_file = write_yaml(result_file, scan_item, False)
176
+ if format:
177
+ if format == 'excel':
178
+ success, msg = write_result_to_excel(result_file, scan_item, extended_header, hide_header)
179
+ elif format == 'csv':
180
+ success, msg, _ = write_result_to_csv(result_file, scan_item, False, extended_header)
181
+ elif format == 'opossum':
182
+ success, msg = write_opossum(result_file, scan_item)
183
+ elif format == 'yaml':
184
+ success, msg, _ = write_yaml(result_file, scan_item, False)
185
+ elif format.startswith('spdx'):
186
+ if platform.system() != 'Windows':
187
+ success, msg, _ = write_spdx(output_file_without_ext, file_extension, scan_item, spdx_version)
188
+ else:
189
+ success = False
190
+ msg = 'Windows not support spdx format.'
126
191
  else:
127
- success = False
128
- msg = f'Not supported file extension({file_extension})'
192
+ if file_extension == '.xlsx':
193
+ success, msg = write_result_to_excel(result_file, scan_item, extended_header, hide_header)
194
+ elif file_extension == '.csv':
195
+ success, msg, result_file = write_result_to_csv(result_file, scan_item, False, extended_header)
196
+ elif file_extension == '.json':
197
+ success, msg = write_opossum(result_file, scan_item)
198
+ elif file_extension == '.yaml':
199
+ success, msg, result_file = write_yaml(result_file, scan_item, False)
200
+ else:
201
+ success = False
202
+ msg = f'Not supported file extension({file_extension})'
129
203
 
130
204
  return success, msg, result_file
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # Copyright (c) 2022 LG Electronics Inc.
4
+ # SPDX-License-Identifier: Apache-2.0
5
+
6
+ import os
7
+ import uuid
8
+ import logging
9
+ import re
10
+ from pathlib import Path
11
+ from spdx_tools.common.spdx_licensing import spdx_licensing
12
+ from spdx_tools.spdx.model import (
13
+ Actor,
14
+ ActorType,
15
+ Checksum,
16
+ ChecksumAlgorithm,
17
+ CreationInfo,
18
+ Document,
19
+ File,
20
+ Package,
21
+ Relationship,
22
+ RelationshipType,
23
+ SpdxNoAssertion,
24
+ SpdxNone
25
+ )
26
+ from spdx_tools.spdx.validation.document_validator import validate_full_spdx_document
27
+ from spdx_tools.spdx.writer.write_anything import write_file
28
+ from datetime import datetime
29
+ from fosslight_util.spdx_licenses import get_spdx_licenses_json, get_license_from_nick
30
+ from fosslight_util.constant import (LOGGER_NAME, FOSSLIGHT_DEPENDENCY, FOSSLIGHT_SCANNER,
31
+ FOSSLIGHT_BINARY, FOSSLIGHT_SOURCE)
32
+ import traceback
33
+
34
+ logger = logging.getLogger(LOGGER_NAME)
35
+
36
+
37
+ def get_license_list_version():
38
+ version = 'N/A'
39
+ success, error_msg, licenses = get_spdx_licenses_json()
40
+ if success:
41
+ version = licenses['licenseListVersion']
42
+ else:
43
+ logger.info(f'Fail to get spdx license list version:{error_msg}')
44
+ return version
45
+
46
+
47
+ def write_spdx(output_file_without_ext, output_extension, scan_item, spdx_version='2.3'):
48
+ success = True
49
+ error_msg = ''
50
+
51
+ if scan_item:
52
+ try:
53
+ cover_name = scan_item.cover.get_print_json()["Tool information"].split('(').pop(0).strip()
54
+ match = re.search(r"(.+) v([0-9.]+)", cover_name)
55
+ if match:
56
+ scanner_name = match.group(1)
57
+ else:
58
+ scanner_name = FOSSLIGHT_SCANNER
59
+ except Exception:
60
+ cover_name = FOSSLIGHT_SCANNER
61
+ scanner_name = FOSSLIGHT_SCANNER
62
+ creation_info = CreationInfo(spdx_version=f'SPDX-{spdx_version}',
63
+ spdx_id='SPDXRef-DOCUMENT',
64
+ name=f'SPDX Document by {scanner_name.upper()}',
65
+ data_license='CC0-1.0',
66
+ document_namespace=f'http://spdx.org/spdxdocs/{scanner_name.lower()}-{uuid.uuid4()}',
67
+ creators=[Actor(name=cover_name, actor_type=ActorType.TOOL)],
68
+ created=datetime.now())
69
+ doc = Document(creation_info=creation_info)
70
+
71
+ relation_tree = {}
72
+ spdx_id_packages = []
73
+
74
+ output_dir = os.path.dirname(output_file_without_ext)
75
+ Path(output_dir).mkdir(parents=True, exist_ok=True)
76
+ try:
77
+ file_id = 0
78
+ package_id = 0
79
+ root_package = False
80
+ for scanner_name, file_items in scan_item.file_items.items():
81
+ for file_item in file_items:
82
+ file = '' # file의 license, copyright은 oss item에서 append
83
+ if scanner_name in [FOSSLIGHT_BINARY, FOSSLIGHT_SOURCE]:
84
+ file_id += 1
85
+ file = File(name=file_item.source_name_or_path,
86
+ spdx_id=f'SPDXRef-File{file_id}',
87
+ checksums=[Checksum(ChecksumAlgorithm.SHA1, file_item.checksum)])
88
+ file_license = []
89
+ file_copyright = []
90
+ for oss_item in file_item.oss_items:
91
+ oss_licenses = []
92
+ declared_oss_licenses = []
93
+ lic_comment = []
94
+ for oi in oss_item.license:
95
+ oi = check_input_license_format(oi)
96
+ try:
97
+ oi_spdx = spdx_licensing.parse(oi, validate=True)
98
+ oss_licenses.append(oi_spdx)
99
+ declared_oss_licenses.append(oi)
100
+ except Exception:
101
+ logger.debug(f'No spdx license name: {oi}')
102
+ lic_comment.append(oi)
103
+ if oss_licenses:
104
+ file_license.extend(oss_licenses)
105
+ if oss_item.copyright != '':
106
+ file_copyright.append(oss_item.copyright)
107
+
108
+ if oss_item.download_location == '':
109
+ if scanner_name == FOSSLIGHT_DEPENDENCY:
110
+ download_location = SpdxNone()
111
+ else:
112
+ continue
113
+ else:
114
+ download_location = oss_item.download_location
115
+ if scanner_name != FOSSLIGHT_DEPENDENCY and oss_item.name == '':
116
+ continue
117
+ package_id += 1
118
+ package = Package(name=oss_item.name,
119
+ spdx_id=f'SPDXRef-Package{package_id}',
120
+ download_location=download_location)
121
+
122
+ if oss_item.version != '':
123
+ package.version = oss_item.version
124
+
125
+ if scanner_name == FOSSLIGHT_DEPENDENCY:
126
+ package.files_analyzed = False # If omitted, the default value of true is assumed.
127
+ else:
128
+ package.files_analyzed = True
129
+ if oss_item.copyright != '':
130
+ package.cr_text = oss_item.copyright
131
+ if oss_item.homepage != '':
132
+ package.homepage = oss_item.homepage
133
+
134
+ if declared_oss_licenses:
135
+ package.license_declared = spdx_licensing.parse(' AND '.join(declared_oss_licenses))
136
+ if lic_comment:
137
+ package.license_comment = ' '.join(lic_comment)
138
+
139
+ doc.packages.append(package)
140
+
141
+ if scanner_name == FOSSLIGHT_DEPENDENCY:
142
+ purl = file_item.purl
143
+ spdx_id_packages.append([purl, package.spdx_id])
144
+ relation_tree[purl] = {}
145
+ relation_tree[purl]['id'] = package.spdx_id
146
+ relation_tree[purl]['dep'] = []
147
+ if 'root package' in oss_item.comment:
148
+ root_package = True
149
+ relationship = Relationship(doc.creation_info.spdx_id,
150
+ RelationshipType.DESCRIBES,
151
+ package.spdx_id)
152
+ doc.relationships.append(relationship)
153
+ relation_tree[purl]['dep'].extend(file_item.depends_on)
154
+
155
+ if scanner_name in [FOSSLIGHT_BINARY, FOSSLIGHT_SOURCE]:
156
+ if file_license:
157
+ file.license_info_in_file = file_license
158
+ if file_copyright:
159
+ file.copyright_text = '\n'.join(file_copyright)
160
+ if lic_comment:
161
+ file.license_comment = ' '.join(lic_comment)
162
+ doc.files.append(file)
163
+
164
+ if len(doc.packages) > 0:
165
+ for pkg in relation_tree:
166
+ if len(relation_tree[pkg]['dep']) > 0:
167
+ pkg_spdx_id = relation_tree[pkg]['id']
168
+ if len(relation_tree[pkg]['dep']) > 0:
169
+ for pname in relation_tree[pkg]['dep']:
170
+ ans = next(filter(lambda x: x[0] == pname, spdx_id_packages), None)
171
+ if ans is None:
172
+ continue
173
+ rel_pkg_spdx_id = ans[1]
174
+ relationship = Relationship(pkg_spdx_id, RelationshipType.DEPENDS_ON, rel_pkg_spdx_id)
175
+ doc.relationships.append(relationship)
176
+ if not root_package:
177
+ root_package = Package(name='root package',
178
+ spdx_id='SPDXRef-ROOT-PACKAGE',
179
+ download_location=SpdxNoAssertion())
180
+ root_package.files_analyzed = False
181
+ root_package.license_declared = SpdxNoAssertion()
182
+ doc.packages.append(root_package)
183
+ relationship = Relationship(doc.creation_info.spdx_id, RelationshipType.DESCRIBES, root_package.spdx_id)
184
+ doc.relationships.append(relationship)
185
+
186
+ except Exception as e:
187
+ success = False
188
+ error_msg = f'Failed to create spdx document object:{e}, {traceback.format_exc()}'
189
+ else:
190
+ success = False
191
+ error_msg = 'No item to write in output file.'
192
+
193
+ validation_messages = validate_full_spdx_document(doc)
194
+ for message in validation_messages:
195
+ logger.warning(message.validation_message)
196
+ logger.warning(message.context)
197
+
198
+ # assert validation_messages == []
199
+
200
+ result_file = ''
201
+ if success:
202
+ result_file = output_file_without_ext + output_extension
203
+ try:
204
+ write_file(doc, result_file)
205
+ except Exception as e:
206
+ success = False
207
+ error_msg = f'Failed to write spdx document: {e}'
208
+ if os.path.exists(result_file):
209
+ os.remove(result_file)
210
+
211
+ return success, error_msg, result_file
212
+
213
+
214
+ def convert_to_spdx_style(input_string):
215
+ input_string = re.sub(r'[^\w\s\.\-]', '', input_string)
216
+ input_string = re.sub(r'[\s\_]', '-', input_string)
217
+ input_converted = f"LicenseRef-{input_string}"
218
+ return input_converted
219
+
220
+
221
+ def check_input_license_format(input_license):
222
+ spdx_licenses = get_spdx_licensename()
223
+ for spdx in spdx_licenses:
224
+ if input_license.casefold() == spdx.casefold():
225
+ return spdx
226
+
227
+ if input_license.startswith('LicenseRef-'):
228
+ return input_license
229
+
230
+ licensesfromJson = get_license_from_nick()
231
+ if licensesfromJson == "":
232
+ logger.warning(" Error - Return Value to get license from Json is none")
233
+
234
+ try:
235
+ converted_license = licensesfromJson.get(input_license.casefold())
236
+ if converted_license is None:
237
+ converted_license = convert_to_spdx_style(input_license)
238
+ except Exception as ex:
239
+ logger.warning(f"Error - Get frequetly used license : {ex}")
240
+
241
+ return converted_license
242
+
243
+
244
+ def get_spdx_licensename():
245
+ spdx_licenses = []
246
+ try:
247
+ success, error_msg, licenses = get_spdx_licenses_json()
248
+ if success is False:
249
+ logger.warning(f"Error to get SPDX Licesens : {error_msg}")
250
+
251
+ licenseInfo = licenses.get("licenses")
252
+ for info in licenseInfo:
253
+ shortID = info.get("licenseId")
254
+ isDeprecated = info.get("isDeprecatedLicenseId")
255
+ if isDeprecated is False:
256
+ spdx_licenses.append(shortID)
257
+ except Exception as ex:
258
+ logger.warning(f"Error access to get_spdx_licenses_json : {ex}")
259
+ return spdx_licenses
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fosslight-util
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: FOSSLight Util
5
5
  Home-page: https://github.com/fosslight/fosslight_util
6
6
  Author: LG Electronics
@@ -8,7 +8,7 @@ coloredlogs
8
8
  python3-wget
9
9
  beautifulsoup4
10
10
  jsonmerge
11
- spdx-tools==0.7.0rc0
11
+ spdx-tools
12
12
  setuptools>=65.5.1
13
13
  npm
14
14
  requests
@@ -1,222 +0,0 @@
1
- #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
- # Copyright (c) 2022 LG Electronics Inc.
4
- # SPDX-License-Identifier: Apache-2.0
5
-
6
- import os
7
- import uuid
8
- import logging
9
- import re
10
- from pathlib import Path
11
- from spdx.creationinfo import Tool
12
- from spdx.document import Document
13
- from spdx.package import Package
14
- from spdx.relationship import Relationship
15
- from spdx.license import License, LicenseConjunction
16
- from spdx.utils import SPDXNone
17
- from spdx.utils import NoAssert
18
- from spdx.version import Version
19
- from spdx.writers import json
20
- from spdx.writers import yaml
21
- from spdx.writers import xml
22
- from spdx.writers import tagvalue
23
- from fosslight_util.spdx_licenses import get_spdx_licenses_json, get_license_from_nick
24
- from fosslight_util.constant import LOGGER_NAME, FOSSLIGHT_DEPENDENCY
25
- import traceback
26
-
27
- logger = logging.getLogger(LOGGER_NAME)
28
-
29
-
30
- def get_license_list_version():
31
- version = 'N/A'
32
- success, error_msg, licenses = get_spdx_licenses_json()
33
- if success:
34
- version = licenses['licenseListVersion']
35
- else:
36
- logger.info(f'Fail to get spdx license list version:{error_msg}')
37
- return version
38
-
39
-
40
- def write_spdx(output_file_without_ext, output_extension, scan_item,
41
- scanner_name, scanner_version, spdx_version=(2, 3)):
42
- success = True
43
- error_msg = ''
44
- if scan_item:
45
- doc = Document(version=Version(*spdx_version),
46
- data_license=License.from_identifier('CC0-1.0'),
47
- namespace=f'http://spdx.org/spdxdocs/{scanner_name.lower()}-{uuid.uuid4()}',
48
- name=f'SPDX Document by {scanner_name.upper()}',
49
- spdx_id='SPDXRef-DOCUMENT')
50
-
51
- doc.creation_info.set_created_now()
52
- doc.creation_info.add_creator(Tool(f'{scanner_name.upper()} {scanner_version}'))
53
- doc.creation_info.license_list_version = Version(*tuple(get_license_list_version().split('.')))
54
-
55
- relation_tree = {}
56
- spdx_id_packages = []
57
-
58
- output_dir = os.path.dirname(output_file_without_ext)
59
- Path(output_dir).mkdir(parents=True, exist_ok=True)
60
- try:
61
- package_id = 0
62
- root_package = False
63
- for scanner_name, _ in scan_item.file_items.items():
64
- json_contents = scan_item.get_print_json(scanner_name)
65
- for oss_item in json_contents:
66
- package_id += 1
67
- package = Package(spdx_id=f'SPDXRef-{package_id}')
68
-
69
- if oss_item.get('name', '') != '':
70
- package.name = oss_item.get('name', '') # required
71
- else:
72
- package.name = SPDXNone()
73
-
74
- if oss_item.get('version', '') != '':
75
- package.version = oss_item.get('version', '') # no required
76
-
77
- if oss_item.get('download location', '') != '':
78
- package.download_location = oss_item.get('download location', '') # required
79
- else:
80
- package.download_location = SPDXNone()
81
-
82
- if scanner_name == FOSSLIGHT_DEPENDENCY:
83
- package.files_analyzed = False # If omitted, the default value of true is assumed.
84
- else:
85
- package.files_analyzed = True
86
-
87
- if oss_item.get('homepage', '') != '':
88
- package.homepage = oss_item.get('homepage', '') # no required
89
-
90
- if oss_item.get('copyright text', '') != '':
91
- package.cr_text = oss_item.get('copyright text', '') # required
92
- else:
93
- package.cr_text = SPDXNone()
94
- if oss_item.get('license', []) != '':
95
- lic_list = [check_input_license_format(lic.strip()) for lic in oss_item.get('license', [])]
96
- first_lic = License.from_identifier(lic_list.pop(0))
97
- while lic_list:
98
- next_lic = License.from_identifier(lic_list.pop(0))
99
- license_conjunction = LicenseConjunction(first_lic, next_lic)
100
- first_lic = license_conjunction
101
- package.license_declared = first_lic
102
- else:
103
- package.license_declared = NoAssert() # required
104
-
105
- doc.add_package(package)
106
-
107
- if scanner_name == FOSSLIGHT_DEPENDENCY:
108
- purl = oss_item.get('package url', '')
109
- spdx_id_packages.append([purl, package.spdx_id])
110
- comment = oss_item.get('comment', '')
111
- relation_tree[purl] = {}
112
- relation_tree[purl]['id'] = package.spdx_id
113
- relation_tree[purl]['dep'] = []
114
-
115
- if 'root package' in comment.split(','):
116
- root_package = True
117
- relationship = Relationship(f"{doc.spdx_id} DESCRIBES {package.spdx_id}")
118
- doc.add_relationship(relationship)
119
- deps = oss_item.get('depends on', '')
120
- relation_tree[purl]['dep'].extend([di.strip().split('(')[0] for di in deps])
121
- if scanner_name == FOSSLIGHT_DEPENDENCY and len(relation_tree) > 0:
122
- for pkg in relation_tree:
123
- if len(relation_tree[pkg]['dep']) > 0:
124
- pkg_spdx_id = relation_tree[pkg]['id']
125
- if len(relation_tree[pkg]['dep']) > 0:
126
- for pname in relation_tree[pkg]['dep']:
127
- ans = next(filter(lambda x: x[0] == pname, spdx_id_packages), None)
128
- if ans is None:
129
- continue
130
- rel_pkg_spdx_id = ans[1]
131
- relationship = Relationship(f'{pkg_spdx_id} DEPENDS_ON {rel_pkg_spdx_id}')
132
- doc.add_relationship(relationship)
133
- if not root_package:
134
- root_package = Package(spdx_id='SPDXRef-ROOT-PACKAGE')
135
- root_package.name = 'root package'
136
- root_package.download_location = NoAssert()
137
- root_package.files_analyzed = False
138
- root_package.cr_text = SPDXNone()
139
- root_package.license_declared = NoAssert()
140
- doc.add_package(root_package)
141
- relationship = Relationship(f"{doc.spdx_id} DESCRIBES {root_package.spdx_id}")
142
- doc.add_relationship(relationship)
143
- except Exception as e:
144
- success = False
145
- error_msg = f'Failed to create spdx document object:{e}, {traceback.format_exc()}'
146
- else:
147
- success = False
148
- error_msg = 'No item to write in output file.'
149
-
150
- result_file = ''
151
- if success:
152
- result_file = output_file_without_ext + output_extension
153
- try:
154
- out_mode = "w"
155
- if result_file.endswith(".tag"):
156
- writer_module = tagvalue
157
- elif result_file.endswith(".json"):
158
- writer_module = json
159
- elif result_file.endswith(".xml"):
160
- writer_module = xml
161
- elif result_file.endswith(".yaml"):
162
- writer_module = yaml
163
- else:
164
- raise Exception("FileType Not Supported")
165
-
166
- with open(result_file, out_mode) as out:
167
- writer_module.write_document(doc, out, True)
168
- except Exception as e:
169
- success = False
170
- error_msg = f'Failed to write spdx document: {e}'
171
- if os.path.exists(result_file):
172
- os.remove(result_file)
173
-
174
- return success, error_msg, result_file
175
-
176
-
177
- def convert_to_spdx_style(input_string):
178
- input_string = re.sub(r'[^\w\s\.\-]', '', input_string)
179
- input_string = re.sub(r'[\s\_]', '-', input_string)
180
- input_converted = f"LicenseRef-{input_string}"
181
- return input_converted
182
-
183
-
184
- def check_input_license_format(input_license):
185
- spdx_licenses = get_spdx_licensename()
186
- for spdx in spdx_licenses:
187
- if input_license.casefold() == spdx.casefold():
188
- return spdx
189
-
190
- if input_license.startswith('LicenseRef-'):
191
- return input_license
192
-
193
- licensesfromJson = get_license_from_nick()
194
- if licensesfromJson == "":
195
- logger.warning(" Error - Return Value to get license from Json is none")
196
-
197
- try:
198
- converted_license = licensesfromJson.get(input_license.casefold())
199
- if converted_license is None:
200
- converted_license = convert_to_spdx_style(input_license)
201
- except Exception as ex:
202
- logger.warning(f"Error - Get frequetly used license : {ex}")
203
-
204
- return converted_license
205
-
206
-
207
- def get_spdx_licensename():
208
- spdx_licenses = []
209
- try:
210
- success, error_msg, licenses = get_spdx_licenses_json()
211
- if success is False:
212
- logger.warning(f"Error to get SPDX Licesens : {error_msg}")
213
-
214
- licenseInfo = licenses.get("licenses")
215
- for info in licenseInfo:
216
- shortID = info.get("licenseId")
217
- isDeprecated = info.get("isDeprecatedLicenseId")
218
- if isDeprecated is False:
219
- spdx_licenses.append(shortID)
220
- except Exception as ex:
221
- logger.warning(f"Error access to get_spdx_licenses_json : {ex}")
222
- return spdx_licenses
File without changes
File without changes
File without changes