fosslight-util 2.0.0__tar.gz → 2.0.2__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.
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/PKG-INFO +1 -1
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/requirements.txt +3 -2
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/setup.py +1 -1
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/download.py +25 -24
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/oss_item.py +2 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/output_format.py +86 -12
- fosslight_util-2.0.2/src/fosslight_util/write_spdx.py +265 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/PKG-INFO +1 -1
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/requires.txt +4 -1
- fosslight_util-2.0.0/src/fosslight_util/write_spdx.py +0 -222
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/LICENSE +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/MANIFEST.in +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/README.md +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/setup.cfg +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/__init__.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/_get_downloadable_url.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/compare_yaml.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/constant.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/convert_excel_to_yaml.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/correct.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/cover.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/help.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/parsing_yaml.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/read_excel.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/resources/frequentLicenselist.json +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/resources/frequent_license_nick_list.json +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/resources/licenses.json +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/set_log.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/spdx_licenses.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/timer_thread.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/write_excel.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/write_opossum.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/write_scancodejson.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/write_txt.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/write_yaml.py +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/SOURCES.txt +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/dependency_links.txt +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/entry_points.txt +0 -0
- {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/top_level.txt +0 -0
|
@@ -8,9 +8,10 @@ coloredlogs
|
|
|
8
8
|
python3-wget
|
|
9
9
|
beautifulsoup4
|
|
10
10
|
jsonmerge
|
|
11
|
-
spdx-tools
|
|
11
|
+
spdx-tools>=0.8.2;sys_platform!="win32"
|
|
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'
|
|
15
15
|
npm
|
|
16
|
-
requests
|
|
16
|
+
requests
|
|
17
|
+
GitPython
|
|
@@ -10,7 +10,7 @@ import zipfile
|
|
|
10
10
|
import logging
|
|
11
11
|
import argparse
|
|
12
12
|
import shutil
|
|
13
|
-
import
|
|
13
|
+
from git import Repo, GitCommandError
|
|
14
14
|
import bz2
|
|
15
15
|
import contextlib
|
|
16
16
|
from datetime import datetime
|
|
@@ -230,14 +230,10 @@ def get_github_token(git_url):
|
|
|
230
230
|
|
|
231
231
|
|
|
232
232
|
def download_git_clone(git_url, target_dir, checkout_to="", tag="", branch=""):
|
|
233
|
-
ref_to_checkout = decide_checkout(checkout_to, tag, branch)
|
|
234
|
-
msg = ""
|
|
235
233
|
oss_name = get_github_ossname(git_url)
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
if github_token != "":
|
|
240
|
-
callbacks = git.RemoteCallbacks(credentials=git.UserPass("foo", github_token)) # username is not used, so set to dummy
|
|
234
|
+
refs_to_checkout = decide_checkout(checkout_to, tag, branch)
|
|
235
|
+
clone_default_branch_flag = False
|
|
236
|
+
msg = ""
|
|
241
237
|
|
|
242
238
|
try:
|
|
243
239
|
if platform.system() != "Windows":
|
|
@@ -248,9 +244,26 @@ def download_git_clone(git_url, target_dir, checkout_to="", tag="", branch=""):
|
|
|
248
244
|
alarm.start()
|
|
249
245
|
|
|
250
246
|
Path(target_dir).mkdir(parents=True, exist_ok=True)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
247
|
+
if refs_to_checkout != "":
|
|
248
|
+
try:
|
|
249
|
+
# gitPython uses the branch argument the same whether you check out to a branch or a tag.
|
|
250
|
+
repo = Repo.clone_from(git_url, target_dir, branch=refs_to_checkout)
|
|
251
|
+
except GitCommandError as error:
|
|
252
|
+
error_msg = error.args[2].decode("utf-8")
|
|
253
|
+
if "Remote branch " + refs_to_checkout + " not found in upstream origin" in error_msg:
|
|
254
|
+
# clone default branch, when non-existent branch or tag entered
|
|
255
|
+
repo = Repo.clone_from(git_url, target_dir)
|
|
256
|
+
clone_default_branch_flag = True
|
|
257
|
+
else:
|
|
258
|
+
repo = Repo.clone_from(git_url, target_dir)
|
|
259
|
+
clone_default_branch_flag = True
|
|
260
|
+
|
|
261
|
+
if refs_to_checkout != tag or clone_default_branch_flag:
|
|
262
|
+
oss_version = repo.active_branch.name
|
|
263
|
+
else:
|
|
264
|
+
oss_version = repo.git.describe('--tags')
|
|
265
|
+
logger.info(f"git checkout: {oss_version}")
|
|
266
|
+
|
|
254
267
|
if platform.system() != "Windows":
|
|
255
268
|
signal.alarm(0)
|
|
256
269
|
else:
|
|
@@ -258,20 +271,8 @@ def download_git_clone(git_url, target_dir, checkout_to="", tag="", branch=""):
|
|
|
258
271
|
except Exception as error:
|
|
259
272
|
logger.warning(f"git clone - failed: {error}")
|
|
260
273
|
msg = str(error)
|
|
261
|
-
return False, msg, oss_name,
|
|
262
|
-
try:
|
|
263
|
-
if ref_to_checkout != "":
|
|
264
|
-
ref_list = [x for x in repo.references]
|
|
265
|
-
ref_to_checkout = get_ref_to_checkout(ref_to_checkout, ref_list)
|
|
266
|
-
logger.info(f"git checkout: {ref_to_checkout}")
|
|
267
|
-
repo.checkout(ref_to_checkout)
|
|
274
|
+
return False, msg, oss_name, refs_to_checkout
|
|
268
275
|
|
|
269
|
-
for prefix_ref in prefix_refs:
|
|
270
|
-
if ref_to_checkout.startswith(prefix_ref):
|
|
271
|
-
oss_version = ref_to_checkout[len(prefix_ref):]
|
|
272
|
-
|
|
273
|
-
except Exception as error:
|
|
274
|
-
logger.warning(f"git checkout to {ref_to_checkout} - failed: {error}")
|
|
275
276
|
return True, msg, oss_name, oss_version
|
|
276
277
|
|
|
277
278
|
|
|
@@ -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
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
128
|
-
|
|
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,265 @@
|
|
|
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 datetime import datetime
|
|
12
|
+
from fosslight_util.spdx_licenses import get_spdx_licenses_json, get_license_from_nick
|
|
13
|
+
from fosslight_util.constant import (LOGGER_NAME, FOSSLIGHT_DEPENDENCY, FOSSLIGHT_SCANNER,
|
|
14
|
+
FOSSLIGHT_BINARY, FOSSLIGHT_SOURCE)
|
|
15
|
+
import traceback
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(LOGGER_NAME)
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
from spdx_tools.common.spdx_licensing import spdx_licensing
|
|
21
|
+
from spdx_tools.spdx.model import (
|
|
22
|
+
Actor,
|
|
23
|
+
ActorType,
|
|
24
|
+
Checksum,
|
|
25
|
+
ChecksumAlgorithm,
|
|
26
|
+
CreationInfo,
|
|
27
|
+
Document,
|
|
28
|
+
File,
|
|
29
|
+
Package,
|
|
30
|
+
Relationship,
|
|
31
|
+
RelationshipType,
|
|
32
|
+
SpdxNoAssertion,
|
|
33
|
+
SpdxNone
|
|
34
|
+
)
|
|
35
|
+
from spdx_tools.spdx.validation.document_validator import validate_full_spdx_document
|
|
36
|
+
from spdx_tools.spdx.writer.write_anything import write_file
|
|
37
|
+
except Exception:
|
|
38
|
+
logger.info('No import spdx-tools')
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_license_list_version():
|
|
42
|
+
version = 'N/A'
|
|
43
|
+
success, error_msg, licenses = get_spdx_licenses_json()
|
|
44
|
+
if success:
|
|
45
|
+
version = licenses['licenseListVersion']
|
|
46
|
+
else:
|
|
47
|
+
logger.info(f'Fail to get spdx license list version:{error_msg}')
|
|
48
|
+
return version
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def write_spdx(output_file_without_ext, output_extension, scan_item, spdx_version='2.3'):
|
|
52
|
+
success = True
|
|
53
|
+
error_msg = ''
|
|
54
|
+
|
|
55
|
+
if scan_item:
|
|
56
|
+
try:
|
|
57
|
+
cover_name = scan_item.cover.get_print_json()["Tool information"].split('(').pop(0).strip()
|
|
58
|
+
match = re.search(r"(.+) v([0-9.]+)", cover_name)
|
|
59
|
+
if match:
|
|
60
|
+
scanner_name = match.group(1)
|
|
61
|
+
else:
|
|
62
|
+
scanner_name = FOSSLIGHT_SCANNER
|
|
63
|
+
except Exception:
|
|
64
|
+
cover_name = FOSSLIGHT_SCANNER
|
|
65
|
+
scanner_name = FOSSLIGHT_SCANNER
|
|
66
|
+
creation_info = CreationInfo(spdx_version=f'SPDX-{spdx_version}',
|
|
67
|
+
spdx_id='SPDXRef-DOCUMENT',
|
|
68
|
+
name=f'SPDX Document by {scanner_name.upper()}',
|
|
69
|
+
data_license='CC0-1.0',
|
|
70
|
+
document_namespace=f'http://spdx.org/spdxdocs/{scanner_name.lower()}-{uuid.uuid4()}',
|
|
71
|
+
creators=[Actor(name=cover_name, actor_type=ActorType.TOOL)],
|
|
72
|
+
created=datetime.now())
|
|
73
|
+
doc = Document(creation_info=creation_info)
|
|
74
|
+
|
|
75
|
+
relation_tree = {}
|
|
76
|
+
spdx_id_packages = []
|
|
77
|
+
|
|
78
|
+
output_dir = os.path.dirname(output_file_without_ext)
|
|
79
|
+
Path(output_dir).mkdir(parents=True, exist_ok=True)
|
|
80
|
+
try:
|
|
81
|
+
file_id = 0
|
|
82
|
+
package_id = 0
|
|
83
|
+
root_package = False
|
|
84
|
+
for scanner_name, file_items in scan_item.file_items.items():
|
|
85
|
+
for file_item in file_items:
|
|
86
|
+
file = '' # file의 license, copyright은 oss item에서 append
|
|
87
|
+
if scanner_name in [FOSSLIGHT_BINARY, FOSSLIGHT_SOURCE]:
|
|
88
|
+
file_id += 1
|
|
89
|
+
file = File(name=file_item.source_name_or_path,
|
|
90
|
+
spdx_id=f'SPDXRef-File{file_id}',
|
|
91
|
+
checksums=[Checksum(ChecksumAlgorithm.SHA1, file_item.checksum)])
|
|
92
|
+
file_license = []
|
|
93
|
+
file_copyright = []
|
|
94
|
+
file_comment = []
|
|
95
|
+
for oss_item in file_item.oss_items:
|
|
96
|
+
oss_licenses = []
|
|
97
|
+
declared_oss_licenses = []
|
|
98
|
+
lic_comment = []
|
|
99
|
+
for oi in oss_item.license:
|
|
100
|
+
oi = check_input_license_format(oi)
|
|
101
|
+
try:
|
|
102
|
+
oi_spdx = spdx_licensing.parse(oi, validate=True)
|
|
103
|
+
oss_licenses.append(oi_spdx)
|
|
104
|
+
declared_oss_licenses.append(oi)
|
|
105
|
+
except Exception:
|
|
106
|
+
logger.debug(f'No spdx license name: {oi}')
|
|
107
|
+
lic_comment.append(oi)
|
|
108
|
+
file_comment.append(oi)
|
|
109
|
+
if oss_licenses:
|
|
110
|
+
file_license.extend(oss_licenses)
|
|
111
|
+
if oss_item.copyright != '':
|
|
112
|
+
file_copyright.append(oss_item.copyright)
|
|
113
|
+
|
|
114
|
+
if oss_item.download_location == '':
|
|
115
|
+
if scanner_name == FOSSLIGHT_DEPENDENCY:
|
|
116
|
+
download_location = SpdxNone()
|
|
117
|
+
else:
|
|
118
|
+
continue
|
|
119
|
+
else:
|
|
120
|
+
download_location = oss_item.download_location
|
|
121
|
+
if scanner_name != FOSSLIGHT_DEPENDENCY and oss_item.name == '':
|
|
122
|
+
continue
|
|
123
|
+
package_id += 1
|
|
124
|
+
package = Package(name=oss_item.name,
|
|
125
|
+
spdx_id=f'SPDXRef-Package{package_id}',
|
|
126
|
+
download_location=download_location)
|
|
127
|
+
|
|
128
|
+
if oss_item.version != '':
|
|
129
|
+
package.version = oss_item.version
|
|
130
|
+
|
|
131
|
+
if scanner_name == FOSSLIGHT_DEPENDENCY:
|
|
132
|
+
package.files_analyzed = False # If omitted, the default value of true is assumed.
|
|
133
|
+
else:
|
|
134
|
+
package.files_analyzed = True
|
|
135
|
+
if oss_item.copyright != '':
|
|
136
|
+
package.cr_text = oss_item.copyright
|
|
137
|
+
if oss_item.homepage != '':
|
|
138
|
+
package.homepage = oss_item.homepage
|
|
139
|
+
|
|
140
|
+
if declared_oss_licenses:
|
|
141
|
+
package.license_declared = spdx_licensing.parse(' AND '.join(declared_oss_licenses))
|
|
142
|
+
if lic_comment:
|
|
143
|
+
package.license_comment = ' '.join(lic_comment)
|
|
144
|
+
|
|
145
|
+
doc.packages.append(package)
|
|
146
|
+
|
|
147
|
+
if scanner_name == FOSSLIGHT_DEPENDENCY:
|
|
148
|
+
purl = file_item.purl
|
|
149
|
+
spdx_id_packages.append([purl, package.spdx_id])
|
|
150
|
+
relation_tree[purl] = {}
|
|
151
|
+
relation_tree[purl]['id'] = package.spdx_id
|
|
152
|
+
relation_tree[purl]['dep'] = []
|
|
153
|
+
if 'root package' in oss_item.comment:
|
|
154
|
+
root_package = True
|
|
155
|
+
relationship = Relationship(doc.creation_info.spdx_id,
|
|
156
|
+
RelationshipType.DESCRIBES,
|
|
157
|
+
package.spdx_id)
|
|
158
|
+
doc.relationships.append(relationship)
|
|
159
|
+
relation_tree[purl]['dep'].extend(file_item.depends_on)
|
|
160
|
+
|
|
161
|
+
if scanner_name in [FOSSLIGHT_BINARY, FOSSLIGHT_SOURCE]:
|
|
162
|
+
if file_license:
|
|
163
|
+
file.license_info_in_file = file_license
|
|
164
|
+
if file_copyright:
|
|
165
|
+
file.copyright_text = '\n'.join(file_copyright)
|
|
166
|
+
if file_comment:
|
|
167
|
+
file.license_comment = ' '.join(file_comment)
|
|
168
|
+
doc.files.append(file)
|
|
169
|
+
|
|
170
|
+
if len(doc.packages) > 0:
|
|
171
|
+
for pkg in relation_tree:
|
|
172
|
+
if len(relation_tree[pkg]['dep']) > 0:
|
|
173
|
+
pkg_spdx_id = relation_tree[pkg]['id']
|
|
174
|
+
if len(relation_tree[pkg]['dep']) > 0:
|
|
175
|
+
for pname in relation_tree[pkg]['dep']:
|
|
176
|
+
ans = next(filter(lambda x: x[0] == pname, spdx_id_packages), None)
|
|
177
|
+
if ans is None:
|
|
178
|
+
continue
|
|
179
|
+
rel_pkg_spdx_id = ans[1]
|
|
180
|
+
relationship = Relationship(pkg_spdx_id, RelationshipType.DEPENDS_ON, rel_pkg_spdx_id)
|
|
181
|
+
doc.relationships.append(relationship)
|
|
182
|
+
if not root_package:
|
|
183
|
+
root_package = Package(name='root package',
|
|
184
|
+
spdx_id='SPDXRef-ROOT-PACKAGE',
|
|
185
|
+
download_location=SpdxNoAssertion())
|
|
186
|
+
root_package.files_analyzed = False
|
|
187
|
+
root_package.license_declared = SpdxNoAssertion()
|
|
188
|
+
doc.packages.append(root_package)
|
|
189
|
+
relationship = Relationship(doc.creation_info.spdx_id, RelationshipType.DESCRIBES, root_package.spdx_id)
|
|
190
|
+
doc.relationships.append(relationship)
|
|
191
|
+
|
|
192
|
+
except Exception as e:
|
|
193
|
+
success = False
|
|
194
|
+
error_msg = f'Failed to create spdx document object:{e}, {traceback.format_exc()}'
|
|
195
|
+
else:
|
|
196
|
+
success = False
|
|
197
|
+
error_msg = 'No item to write in output file.'
|
|
198
|
+
|
|
199
|
+
validation_messages = validate_full_spdx_document(doc)
|
|
200
|
+
for message in validation_messages:
|
|
201
|
+
logger.warning(message.validation_message)
|
|
202
|
+
logger.warning(message.context)
|
|
203
|
+
|
|
204
|
+
# assert validation_messages == []
|
|
205
|
+
|
|
206
|
+
result_file = ''
|
|
207
|
+
if success:
|
|
208
|
+
result_file = output_file_without_ext + output_extension
|
|
209
|
+
try:
|
|
210
|
+
write_file(doc, result_file)
|
|
211
|
+
except Exception as e:
|
|
212
|
+
success = False
|
|
213
|
+
error_msg = f'Failed to write spdx document: {e}'
|
|
214
|
+
if os.path.exists(result_file):
|
|
215
|
+
os.remove(result_file)
|
|
216
|
+
|
|
217
|
+
return success, error_msg, result_file
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def convert_to_spdx_style(input_string):
|
|
221
|
+
input_string = re.sub(r'[^\w\s\.\-]', '', input_string)
|
|
222
|
+
input_string = re.sub(r'[\s\_]', '-', input_string)
|
|
223
|
+
input_converted = f"LicenseRef-{input_string}"
|
|
224
|
+
return input_converted
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def check_input_license_format(input_license):
|
|
228
|
+
spdx_licenses = get_spdx_licensename()
|
|
229
|
+
for spdx in spdx_licenses:
|
|
230
|
+
if input_license.casefold() == spdx.casefold():
|
|
231
|
+
return spdx
|
|
232
|
+
|
|
233
|
+
if input_license.startswith('LicenseRef-'):
|
|
234
|
+
return input_license
|
|
235
|
+
|
|
236
|
+
licensesfromJson = get_license_from_nick()
|
|
237
|
+
if licensesfromJson == "":
|
|
238
|
+
logger.warning(" Error - Return Value to get license from Json is none")
|
|
239
|
+
|
|
240
|
+
try:
|
|
241
|
+
converted_license = licensesfromJson.get(input_license.casefold())
|
|
242
|
+
if converted_license is None:
|
|
243
|
+
converted_license = convert_to_spdx_style(input_license)
|
|
244
|
+
except Exception as ex:
|
|
245
|
+
logger.warning(f"Error - Get frequetly used license : {ex}")
|
|
246
|
+
|
|
247
|
+
return converted_license
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def get_spdx_licensename():
|
|
251
|
+
spdx_licenses = []
|
|
252
|
+
try:
|
|
253
|
+
success, error_msg, licenses = get_spdx_licenses_json()
|
|
254
|
+
if success is False:
|
|
255
|
+
logger.warning(f"Error to get SPDX Licesens : {error_msg}")
|
|
256
|
+
|
|
257
|
+
licenseInfo = licenses.get("licenses")
|
|
258
|
+
for info in licenseInfo:
|
|
259
|
+
shortID = info.get("licenseId")
|
|
260
|
+
isDeprecated = info.get("isDeprecatedLicenseId")
|
|
261
|
+
if isDeprecated is False:
|
|
262
|
+
spdx_licenses.append(shortID)
|
|
263
|
+
except Exception as ex:
|
|
264
|
+
logger.warning(f"Error access to get_spdx_licenses_json : {ex}")
|
|
265
|
+
return spdx_licenses
|
|
@@ -8,10 +8,10 @@ coloredlogs
|
|
|
8
8
|
python3-wget
|
|
9
9
|
beautifulsoup4
|
|
10
10
|
jsonmerge
|
|
11
|
-
spdx-tools==0.7.0rc0
|
|
12
11
|
setuptools>=65.5.1
|
|
13
12
|
npm
|
|
14
13
|
requests
|
|
14
|
+
GitPython
|
|
15
15
|
|
|
16
16
|
[:python_version < "3.8"]
|
|
17
17
|
numpy
|
|
@@ -24,3 +24,6 @@ pygit2==1.6.1
|
|
|
24
24
|
|
|
25
25
|
[:python_version>='3.7']
|
|
26
26
|
pygit2>=1.10.1
|
|
27
|
+
|
|
28
|
+
[:sys_platform != "win32"]
|
|
29
|
+
spdx-tools>=0.8.2
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/resources/frequentLicenselist.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|