fosslight-util 1.4.48__py3-none-any.whl → 2.0.1__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.
@@ -3,11 +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
11
+ from typing import Tuple
9
12
 
10
- 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'}
11
16
 
12
17
 
13
18
  def check_output_format(output='', format='', customized_format={}):
@@ -105,7 +110,62 @@ def check_output_formats(output='', formats=[], customized_format={}):
105
110
  return success, msg, output_path, output_files, output_extensions
106
111
 
107
112
 
108
- def write_output_file(output_file_without_ext, file_extension, sheet_list, extended_header={}, hide_header={}, cover=""):
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
+
167
+ def write_output_file(output_file_without_ext: str, file_extension: str, scan_item, extended_header: dict = {},
168
+ hide_header: dict = {}, format: str = '', spdx_version: str = '2.3') -> Tuple[bool, str, str]:
109
169
  success = True
110
170
  msg = ''
111
171
 
@@ -113,16 +173,32 @@ def write_output_file(output_file_without_ext, file_extension, sheet_list, exten
113
173
  file_extension = '.xlsx'
114
174
  result_file = output_file_without_ext + file_extension
115
175
 
116
- if file_extension == '.xlsx':
117
- success, msg = write_result_to_excel(result_file, sheet_list, extended_header, hide_header, cover)
118
- elif file_extension == '.csv':
119
- success, msg, result_file = write_result_to_csv(result_file, sheet_list, False, extended_header)
120
- elif file_extension == '.json':
121
- success, msg = write_opossum(result_file, sheet_list)
122
- elif file_extension == '.yaml':
123
- success, msg, result_file = write_yaml(result_file, sheet_list, 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.'
124
191
  else:
125
- success = False
126
- 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})'
127
203
 
128
204
  return success, msg, result_file
@@ -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
- oss_list = []
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 oss_list, license_list, err_reason
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
- item = OssItem(relative_path)
52
- if not is_old_format:
53
- item.name = root_element
54
- for key, value in oss.items():
55
- if key:
56
- key = key.lower().strip()
57
- set_value_switch(item, key, value, yaml_file)
58
- oss_list.append(item)
59
- license_list.extend(item.license)
60
- idx += 1
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
- oss_list = []
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
- oss_list = []
79
+ fileitems = []
70
80
  err_reason = "yaml_error"
71
- return oss_list, set(license_list), err_reason
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")
@@ -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 xlrd
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[OssItem]:
22
- oss_report_items: List[OssItem] = []
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 = xlrd.open_workbook(excel_file)
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 = xl_workbook.sheet_by_name(sheet_name)
50
- if sheet:
51
- xl_sheets[sheet_name] = sheet
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
- if len([key for key, value in _item_idx.items() if value != IDX_CANNOT_FOUND]) > 3:
96
- DATA_START_ROW_IDX = row_idx + 1
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 range(DATA_START_ROW_IDX, xl_sheet.nrows):
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.cell(row_idx, column_idx)
113
- cell_value = cell_obj.value
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(item, column_key, cell_value)
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
- oss_report_items.append(item)
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 oss_report_items
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
- file_log_level=logging.DEBUG, main_package_name="", path_to_analyze="", path_to_exclude=[]):
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": platform.system()+" "+platform.release(),
90
+ "OS": get_os_version(),
74
91
  }
75
92
  if main_package_name != "":
76
93
  pkg_info = main_package_name
@@ -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 = ''