fosslight-util 1.4.48__py3-none-any.whl → 2.0.0__py3-none-any.whl
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/compare_yaml.py +18 -11
- fosslight_util/constant.py +11 -0
- fosslight_util/convert_excel_to_yaml.py +1 -1
- fosslight_util/correct.py +47 -91
- fosslight_util/help.py +3 -4
- fosslight_util/oss_item.py +148 -155
- fosslight_util/output_format.py +7 -5
- fosslight_util/parsing_yaml.py +45 -30
- fosslight_util/read_excel.py +29 -35
- fosslight_util/set_log.py +20 -3
- fosslight_util/spdx_licenses.py +2 -1
- fosslight_util/write_excel.py +88 -156
- fosslight_util/write_opossum.py +14 -20
- fosslight_util/write_scancodejson.py +31 -31
- fosslight_util/write_spdx.py +30 -35
- fosslight_util/write_txt.py +2 -1
- fosslight_util/write_yaml.py +43 -54
- {fosslight_util-1.4.48.dist-info → fosslight_util-2.0.0.dist-info}/METADATA +7 -8
- fosslight_util-2.0.0.dist-info/RECORD +31 -0
- {fosslight_util-1.4.48.dist-info → fosslight_util-2.0.0.dist-info}/WHEEL +1 -1
- fosslight_util-1.4.48.dist-info/RECORD +0 -31
- {fosslight_util-1.4.48.dist-info → fosslight_util-2.0.0.dist-info}/LICENSE +0 -0
- {fosslight_util-1.4.48.dist-info → fosslight_util-2.0.0.dist-info}/entry_points.txt +0 -0
- {fosslight_util-1.4.48.dist-info → fosslight_util-2.0.0.dist-info}/top_level.txt +0 -0
fosslight_util/output_format.py
CHANGED
|
@@ -6,6 +6,7 @@ import os
|
|
|
6
6
|
from fosslight_util.write_excel import write_result_to_excel, write_result_to_csv
|
|
7
7
|
from fosslight_util.write_opossum import write_opossum
|
|
8
8
|
from fosslight_util.write_yaml import write_yaml
|
|
9
|
+
from typing import Tuple
|
|
9
10
|
|
|
10
11
|
SUPPORT_FORMAT = {'excel': '.xlsx', 'csv': '.csv', 'opossum': '.json', 'yaml': '.yaml'}
|
|
11
12
|
|
|
@@ -105,7 +106,8 @@ def check_output_formats(output='', formats=[], customized_format={}):
|
|
|
105
106
|
return success, msg, output_path, output_files, output_extensions
|
|
106
107
|
|
|
107
108
|
|
|
108
|
-
def write_output_file(output_file_without_ext, file_extension,
|
|
109
|
+
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]:
|
|
109
111
|
success = True
|
|
110
112
|
msg = ''
|
|
111
113
|
|
|
@@ -114,13 +116,13 @@ def write_output_file(output_file_without_ext, file_extension, sheet_list, exten
|
|
|
114
116
|
result_file = output_file_without_ext + file_extension
|
|
115
117
|
|
|
116
118
|
if file_extension == '.xlsx':
|
|
117
|
-
success, msg = write_result_to_excel(result_file,
|
|
119
|
+
success, msg = write_result_to_excel(result_file, scan_item, extended_header, hide_header)
|
|
118
120
|
elif file_extension == '.csv':
|
|
119
|
-
success, msg, result_file = write_result_to_csv(result_file,
|
|
121
|
+
success, msg, result_file = write_result_to_csv(result_file, scan_item, False, extended_header)
|
|
120
122
|
elif file_extension == '.json':
|
|
121
|
-
success, msg = write_opossum(result_file,
|
|
123
|
+
success, msg = write_opossum(result_file, scan_item)
|
|
122
124
|
elif file_extension == '.yaml':
|
|
123
|
-
success, msg, result_file = write_yaml(result_file,
|
|
125
|
+
success, msg, result_file = write_yaml(result_file, scan_item, False)
|
|
124
126
|
else:
|
|
125
127
|
success = False
|
|
126
128
|
msg = f'Not supported file extension({file_extension})'
|
fosslight_util/parsing_yaml.py
CHANGED
|
@@ -8,8 +8,8 @@ import codecs
|
|
|
8
8
|
import os
|
|
9
9
|
import re
|
|
10
10
|
import sys
|
|
11
|
-
from .constant import LOGGER_NAME
|
|
12
|
-
from .oss_item import OssItem
|
|
11
|
+
from fosslight_util.constant import LOGGER_NAME
|
|
12
|
+
from fosslight_util.oss_item import OssItem, FileItem
|
|
13
13
|
|
|
14
14
|
_logger = logging.getLogger(LOGGER_NAME)
|
|
15
15
|
SUPPORT_OSS_INFO_FILES = [r"oss-pkg-info[\s\S]*.ya?ml", r"sbom(-|_)info[\s\S]*.ya?ml"]
|
|
@@ -17,7 +17,7 @@ EXAMPLE_OSS_PKG_INFO_LINK = "https://github.com/fosslight/fosslight_prechecker/b
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def parsing_yml(yaml_file, base_path, print_log=True):
|
|
20
|
-
|
|
20
|
+
fileitems = []
|
|
21
21
|
license_list = []
|
|
22
22
|
idx = 1
|
|
23
23
|
err_reason = ""
|
|
@@ -38,37 +38,65 @@ def parsing_yml(yaml_file, base_path, print_log=True):
|
|
|
38
38
|
err_reason = "empty"
|
|
39
39
|
if print_log:
|
|
40
40
|
_logger.warning(f"The yaml file is empty file: {yaml_file}")
|
|
41
|
-
return
|
|
41
|
+
return fileitems, license_list, err_reason
|
|
42
42
|
|
|
43
43
|
is_old_format = any(x in doc for x in OLD_YAML_ROOT_ELEMENT)
|
|
44
44
|
|
|
45
|
+
filepath_list = []
|
|
45
46
|
for root_element in doc:
|
|
46
47
|
oss_items = doc[root_element]
|
|
47
48
|
if oss_items:
|
|
48
49
|
if not isinstance(oss_items, list) or 'version' not in oss_items[0]:
|
|
49
50
|
raise AttributeError(f"- Ref. {EXAMPLE_OSS_PKG_INFO_LINK}")
|
|
50
51
|
for oss in oss_items:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
source_paths = get_source_name_or_path_in_yaml(oss)
|
|
53
|
+
for source_path in source_paths:
|
|
54
|
+
if os.path.join(relative_path, source_path) not in filepath_list:
|
|
55
|
+
filepath_list.append(os.path.join(relative_path, source_path))
|
|
56
|
+
fileitem = FileItem(relative_path)
|
|
57
|
+
fileitem.source_name_or_path = source_path
|
|
58
|
+
fileitems.append(fileitem)
|
|
59
|
+
else:
|
|
60
|
+
fileitem = next((i for i in fileitems if i.source_name_or_path == source_path), None)
|
|
61
|
+
ossitem = OssItem()
|
|
62
|
+
if not is_old_format:
|
|
63
|
+
ossitem.name = root_element
|
|
64
|
+
for key, value in oss.items():
|
|
65
|
+
if key:
|
|
66
|
+
key = key.lower().strip()
|
|
67
|
+
set_value_switch(ossitem, key, value, yaml_file)
|
|
68
|
+
fileitem.oss_items.append(ossitem)
|
|
69
|
+
license_list.extend(ossitem.license)
|
|
70
|
+
idx += 1
|
|
61
71
|
except AttributeError as ex:
|
|
62
72
|
if print_log:
|
|
63
73
|
_logger.warning(f"Not supported yaml file format: {yaml_file} {ex}")
|
|
64
|
-
|
|
74
|
+
fileitems = []
|
|
65
75
|
err_reason = "not_supported"
|
|
66
76
|
except yaml.YAMLError:
|
|
67
77
|
if print_log:
|
|
68
78
|
_logger.warning(f"Error to parse yaml - skip to parse yaml file: {yaml_file}")
|
|
69
|
-
|
|
79
|
+
fileitems = []
|
|
70
80
|
err_reason = "yaml_error"
|
|
71
|
-
|
|
81
|
+
|
|
82
|
+
return fileitems, set(license_list), err_reason
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def get_source_name_or_path_in_yaml(oss):
|
|
86
|
+
source_name_or_path = []
|
|
87
|
+
find = False
|
|
88
|
+
for key in oss.keys():
|
|
89
|
+
if key in ['file name or path', 'source name or path', 'source path',
|
|
90
|
+
'file', 'binary name', 'binary path']:
|
|
91
|
+
if isinstance(oss[key], list):
|
|
92
|
+
source_name_or_path = oss[key]
|
|
93
|
+
else:
|
|
94
|
+
source_name_or_path.append(oss[key])
|
|
95
|
+
find = True
|
|
96
|
+
break
|
|
97
|
+
if not find:
|
|
98
|
+
source_name_or_path.append('')
|
|
99
|
+
return source_name_or_path
|
|
72
100
|
|
|
73
101
|
|
|
74
102
|
def find_sbom_yaml_files(path_to_find):
|
|
@@ -101,9 +129,6 @@ def set_value_switch(oss, key, value, yaml_file=""):
|
|
|
101
129
|
oss.download_location = value
|
|
102
130
|
elif key in ['license', 'license text']:
|
|
103
131
|
oss.license = value
|
|
104
|
-
elif key in ['file name or path', 'source name or path', 'source path',
|
|
105
|
-
'file', 'binary name', 'binary path']:
|
|
106
|
-
oss.source_name_or_path = value
|
|
107
132
|
elif key in ['copyright text', 'copyright']:
|
|
108
133
|
oss.copyright = value
|
|
109
134
|
elif key == 'exclude':
|
|
@@ -112,16 +137,6 @@ def set_value_switch(oss, key, value, yaml_file=""):
|
|
|
112
137
|
oss.comment = value
|
|
113
138
|
elif key == 'homepage':
|
|
114
139
|
oss.homepage = value
|
|
115
|
-
elif key == 'yocto_package':
|
|
116
|
-
oss.yocto_package = value
|
|
117
|
-
elif key == 'yocto_recipe':
|
|
118
|
-
oss.yocto_recipe = value
|
|
119
|
-
elif key == 'vulnerability link':
|
|
120
|
-
oss.bin_vulnerability = value
|
|
121
|
-
elif key == 'tlsh':
|
|
122
|
-
oss.bin_tlsh = value
|
|
123
|
-
elif key == 'sha1':
|
|
124
|
-
oss.bin_sha1 = value
|
|
125
140
|
else:
|
|
126
141
|
if yaml_file != "":
|
|
127
142
|
_logger.debug(f"file:{yaml_file} - key:{key} cannot be parsed")
|
fosslight_util/read_excel.py
CHANGED
|
@@ -4,27 +4,24 @@
|
|
|
4
4
|
# SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
import logging
|
|
6
6
|
from typing import List, Dict, Any
|
|
7
|
-
import
|
|
7
|
+
import pandas as pd
|
|
8
8
|
import json
|
|
9
9
|
from fosslight_util.constant import LOGGER_NAME
|
|
10
|
-
from fosslight_util.oss_item import OssItem
|
|
10
|
+
from fosslight_util.oss_item import OssItem, FileItem
|
|
11
11
|
from fosslight_util.parsing_yaml import set_value_switch
|
|
12
12
|
|
|
13
13
|
logger = logging.getLogger(LOGGER_NAME)
|
|
14
14
|
IDX_CANNOT_FOUND = -1
|
|
15
15
|
PREFIX_BIN = "bin"
|
|
16
16
|
SHEET_PREFIX_TO_READ = ["bin", "bom", "src"]
|
|
17
|
-
xlrd.xlsx.ensure_elementtree_imported(False, None)
|
|
18
|
-
xlrd.xlsx.Element_has_iter = True
|
|
19
17
|
|
|
20
18
|
|
|
21
|
-
def read_oss_report(excel_file: str, sheet_names: str = "") -> List[
|
|
22
|
-
|
|
19
|
+
def read_oss_report(excel_file: str, sheet_names: str = "", basepath: str = "") -> List[FileItem]:
|
|
20
|
+
fileitems: List[FileItem] = []
|
|
23
21
|
xl_sheets: Dict[str, Any] = {}
|
|
24
22
|
all_sheet_to_read: List[str] = []
|
|
25
23
|
not_matched_sheet: List[str] = []
|
|
26
24
|
any_sheet_matched = False
|
|
27
|
-
|
|
28
25
|
if sheet_names:
|
|
29
26
|
sheet_name_prefix_match = False
|
|
30
27
|
sheet_name_to_read = sheet_names.split(",")
|
|
@@ -34,9 +31,8 @@ def read_oss_report(excel_file: str, sheet_names: str = "") -> List[OssItem]:
|
|
|
34
31
|
|
|
35
32
|
try:
|
|
36
33
|
logger.info(f"Read data from : {excel_file}")
|
|
37
|
-
xl_workbook =
|
|
38
|
-
all_sheet_in_excel = xl_workbook.sheet_names
|
|
39
|
-
|
|
34
|
+
xl_workbook = pd.ExcelFile(excel_file, engine='openpyxl')
|
|
35
|
+
all_sheet_in_excel = xl_workbook.sheet_names
|
|
40
36
|
for sheet_to_read in sheet_name_to_read:
|
|
41
37
|
try:
|
|
42
38
|
any_sheet_matched = False
|
|
@@ -46,10 +42,9 @@ def read_oss_report(excel_file: str, sheet_names: str = "") -> List[OssItem]:
|
|
|
46
42
|
sheet_name_lower = sheet_name.lower()
|
|
47
43
|
if (sheet_name_prefix_match and sheet_name_lower.startswith(sheet_to_read_lower)) \
|
|
48
44
|
or sheet_to_read_lower == sheet_name_lower:
|
|
49
|
-
sheet =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
any_sheet_matched = True
|
|
45
|
+
sheet = pd.read_excel(excel_file, sheet_name=sheet_name, engine='openpyxl', na_values='')
|
|
46
|
+
xl_sheets[sheet_name] = sheet.fillna('')
|
|
47
|
+
any_sheet_matched = True
|
|
53
48
|
if not any_sheet_matched:
|
|
54
49
|
not_matched_sheet.append(sheet_to_read)
|
|
55
50
|
except Exception as error:
|
|
@@ -62,6 +57,7 @@ def read_oss_report(excel_file: str, sheet_names: str = "") -> List[OssItem]:
|
|
|
62
57
|
elif (not sheet_name_prefix_match) and not_matched_sheet:
|
|
63
58
|
logger.warning(f"Not matched sheet name: {not_matched_sheet}")
|
|
64
59
|
|
|
60
|
+
filepath_list = []
|
|
65
61
|
for sheet_name, xl_sheet in xl_sheets.items():
|
|
66
62
|
_item_idx = {
|
|
67
63
|
"ID": IDX_CANNOT_FOUND,
|
|
@@ -82,46 +78,44 @@ def read_oss_report(excel_file: str, sheet_names: str = "") -> List[OssItem]:
|
|
|
82
78
|
"TLSH": IDX_CANNOT_FOUND,
|
|
83
79
|
"SHA1": IDX_CANNOT_FOUND
|
|
84
80
|
}
|
|
85
|
-
num_cols = xl_sheet.ncols
|
|
86
|
-
num_rows = xl_sheet.nrows
|
|
87
|
-
MAX_FIND_HEADER_COLUMN = 5 if num_rows > 5 else num_rows
|
|
88
|
-
DATA_START_ROW_IDX = 1
|
|
89
|
-
for row_idx in range(0, MAX_FIND_HEADER_COLUMN):
|
|
90
|
-
for col_idx in range(row_idx, num_cols):
|
|
91
|
-
cell_obj = xl_sheet.cell(row_idx, col_idx)
|
|
92
|
-
if cell_obj.value in _item_idx:
|
|
93
|
-
_item_idx[cell_obj.value] = col_idx
|
|
94
81
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
break
|
|
82
|
+
for index, value in enumerate(xl_sheet.columns.tolist()):
|
|
83
|
+
_item_idx[value] = index
|
|
98
84
|
|
|
99
85
|
# Get all values, iterating through rows and columns
|
|
100
86
|
column_keys = json.loads(json.dumps(_item_idx))
|
|
101
87
|
|
|
102
88
|
is_bin = True if sheet_name.lower().startswith(PREFIX_BIN) else False
|
|
103
89
|
|
|
104
|
-
for row_idx in
|
|
105
|
-
item = OssItem("")
|
|
106
|
-
item.is_binary = is_bin
|
|
90
|
+
for row_idx, row in xl_sheet.iterrows():
|
|
107
91
|
valid_row = True
|
|
108
92
|
load_data_cnt = 0
|
|
109
|
-
|
|
93
|
+
source_path = row[1]
|
|
94
|
+
if source_path not in filepath_list:
|
|
95
|
+
filepath_list.append(source_path)
|
|
96
|
+
fileitem = FileItem(basepath)
|
|
97
|
+
fileitem.source_name_or_path = source_path
|
|
98
|
+
fileitems.append(fileitem)
|
|
99
|
+
else:
|
|
100
|
+
fileitem = next((i for i in fileitems if i.source_name_or_path == source_path), None)
|
|
101
|
+
fileitem.is_binary = is_bin
|
|
102
|
+
ossitem = OssItem()
|
|
110
103
|
for column_key, column_idx in column_keys.items():
|
|
111
104
|
if column_idx != IDX_CANNOT_FOUND:
|
|
112
|
-
cell_obj = xl_sheet.
|
|
113
|
-
cell_value = cell_obj
|
|
105
|
+
cell_obj = xl_sheet.iloc[row_idx, column_idx]
|
|
106
|
+
cell_value = cell_obj
|
|
107
|
+
|
|
114
108
|
if cell_value != "":
|
|
115
109
|
if column_key != "ID":
|
|
116
110
|
if column_key:
|
|
117
111
|
column_key = column_key.lower().strip()
|
|
118
|
-
set_value_switch(
|
|
112
|
+
set_value_switch(ossitem, column_key, cell_value)
|
|
119
113
|
load_data_cnt += 1
|
|
120
114
|
else:
|
|
121
115
|
valid_row = False if cell_value == "-" else True
|
|
122
116
|
if valid_row and load_data_cnt > 0:
|
|
123
|
-
|
|
117
|
+
fileitem.oss_items.append(ossitem)
|
|
124
118
|
|
|
125
119
|
except Exception as error:
|
|
126
120
|
logger.error(f"Parsing a OSS Report: {error}")
|
|
127
|
-
return
|
|
121
|
+
return fileitems
|
fosslight_util/set_log.py
CHANGED
|
@@ -12,6 +12,8 @@ import platform
|
|
|
12
12
|
from . import constant as constant
|
|
13
13
|
from lastversion import lastversion
|
|
14
14
|
import coloredlogs
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from logging import Logger
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
def init_check_latest_version(pkg_version="", main_package_name=""):
|
|
@@ -32,6 +34,21 @@ def init_check_latest_version(pkg_version="", main_package_name=""):
|
|
|
32
34
|
logger.debug('Cannot check the latest version:' + str(error))
|
|
33
35
|
|
|
34
36
|
|
|
37
|
+
def get_os_version():
|
|
38
|
+
|
|
39
|
+
logger = logging.getLogger(constant.LOGGER_NAME)
|
|
40
|
+
|
|
41
|
+
os_version = platform.system() + " " + platform.release()
|
|
42
|
+
if os_version == "Windows 10":
|
|
43
|
+
try:
|
|
44
|
+
windows_build = sys.getwindowsversion().build
|
|
45
|
+
if windows_build >= 22000:
|
|
46
|
+
os_version = "Windows 11"
|
|
47
|
+
except Exception as error:
|
|
48
|
+
logger.debug(str(error))
|
|
49
|
+
return os_version
|
|
50
|
+
|
|
51
|
+
|
|
35
52
|
class CustomAdapter(logging.LoggerAdapter):
|
|
36
53
|
def __init__(self, logger, extra):
|
|
37
54
|
super(CustomAdapter, self).__init__(logger, {})
|
|
@@ -41,8 +58,8 @@ class CustomAdapter(logging.LoggerAdapter):
|
|
|
41
58
|
return '[%s] %s' % (self.extra, msg), kwargs
|
|
42
59
|
|
|
43
60
|
|
|
44
|
-
def init_log(log_file, create_file=True, stream_log_level=logging.INFO,
|
|
45
|
-
|
|
61
|
+
def init_log(log_file: str, create_file: bool = True, stream_log_level: int = logging.INFO, file_log_level: int = logging.DEBUG,
|
|
62
|
+
main_package_name: str = "", path_to_analyze: str = "", path_to_exclude: list = []) -> Tuple[Logger, dict]:
|
|
46
63
|
|
|
47
64
|
logger = logging.getLogger(constant.LOGGER_NAME)
|
|
48
65
|
|
|
@@ -70,7 +87,7 @@ def init_log(log_file, create_file=True, stream_log_level=logging.INFO,
|
|
|
70
87
|
_result_log = {
|
|
71
88
|
"Tool Info": main_package_name,
|
|
72
89
|
"Python version": _PYTHON_VERSION,
|
|
73
|
-
"OS":
|
|
90
|
+
"OS": get_os_version(),
|
|
74
91
|
}
|
|
75
92
|
if main_package_name != "":
|
|
76
93
|
pkg_info = main_package_name
|
fosslight_util/spdx_licenses.py
CHANGED
|
@@ -8,6 +8,7 @@ import os
|
|
|
8
8
|
import sys
|
|
9
9
|
import json
|
|
10
10
|
import traceback
|
|
11
|
+
from typing import Tuple
|
|
11
12
|
|
|
12
13
|
_resources_dir = 'resources'
|
|
13
14
|
_licenses_json_file = 'licenses.json'
|
|
@@ -34,7 +35,7 @@ def get_license_from_nick():
|
|
|
34
35
|
return licenses
|
|
35
36
|
|
|
36
37
|
|
|
37
|
-
def get_spdx_licenses_json():
|
|
38
|
+
def get_spdx_licenses_json() -> Tuple[bool, str, str]:
|
|
38
39
|
success = True
|
|
39
40
|
error_msg = ''
|
|
40
41
|
licenses = ''
|