fosslight-util 2.0.0__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.
@@ -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
@@ -8,20 +8,27 @@ import uuid
8
8
  import logging
9
9
  import re
10
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
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
23
29
  from fosslight_util.spdx_licenses import get_spdx_licenses_json, get_license_from_nick
24
- from fosslight_util.constant import LOGGER_NAME, FOSSLIGHT_DEPENDENCY
30
+ from fosslight_util.constant import (LOGGER_NAME, FOSSLIGHT_DEPENDENCY, FOSSLIGHT_SCANNER,
31
+ FOSSLIGHT_BINARY, FOSSLIGHT_SOURCE)
25
32
  import traceback
26
33
 
27
34
  logger = logging.getLogger(LOGGER_NAME)
@@ -37,20 +44,29 @@ def get_license_list_version():
37
44
  return version
38
45
 
39
46
 
40
- def write_spdx(output_file_without_ext, output_extension, scan_item,
41
- scanner_name, scanner_version, spdx_version=(2, 3)):
47
+ def write_spdx(output_file_without_ext, output_extension, scan_item, spdx_version='2.3'):
42
48
  success = True
43
49
  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
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('.')))
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)
54
70
 
55
71
  relation_tree = {}
56
72
  spdx_id_packages = []
@@ -58,67 +74,94 @@ def write_spdx(output_file_without_ext, output_extension, scan_item,
58
74
  output_dir = os.path.dirname(output_file_without_ext)
59
75
  Path(output_dir).mkdir(parents=True, exist_ok=True)
60
76
  try:
77
+ file_id = 0
61
78
  package_id = 0
62
79
  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:
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:
122
165
  for pkg in relation_tree:
123
166
  if len(relation_tree[pkg]['dep']) > 0:
124
167
  pkg_spdx_id = relation_tree[pkg]['id']
@@ -128,18 +171,18 @@ def write_spdx(output_file_without_ext, output_extension, scan_item,
128
171
  if ans is None:
129
172
  continue
130
173
  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)
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
+
143
186
  except Exception as e:
144
187
  success = False
145
188
  error_msg = f'Failed to create spdx document object:{e}, {traceback.format_exc()}'
@@ -147,24 +190,18 @@ def write_spdx(output_file_without_ext, output_extension, scan_item,
147
190
  success = False
148
191
  error_msg = 'No item to write in output file.'
149
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
+
150
200
  result_file = ''
151
201
  if success:
152
202
  result_file = output_file_without_ext + output_extension
153
203
  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)
204
+ write_file(doc, result_file)
168
205
  except Exception as e:
169
206
  success = False
170
207
  error_msg = f'Failed to write spdx document: {e}'
@@ -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
@@ -26,7 +26,7 @@ Requires-Dist: coloredlogs
26
26
  Requires-Dist: python3-wget
27
27
  Requires-Dist: beautifulsoup4
28
28
  Requires-Dist: jsonmerge
29
- Requires-Dist: spdx-tools==0.7.0rc0
29
+ Requires-Dist: spdx-tools
30
30
  Requires-Dist: setuptools>=65.5.1
31
31
  Requires-Dist: npm
32
32
  Requires-Dist: requests
@@ -7,8 +7,8 @@ fosslight_util/correct.py,sha256=3iUipan8ZX8sbyIIGAPtMkAGvZ4YucjeJwx1K1Bx_z4,389
7
7
  fosslight_util/cover.py,sha256=qqqKzxqFwKimal764FaugRUBcHWdeKt8af6xeK0mH8E,2040
8
8
  fosslight_util/download.py,sha256=X-R2RTWwmhx_LSIBZhIxzPTJZ2GwasZnhIsZ5m3hUig,14997
9
9
  fosslight_util/help.py,sha256=M3_XahUkP794US9Q0NS6ujmGvrFFnKBHsTU95Fg1KpA,2181
10
- fosslight_util/oss_item.py,sha256=TlTxBS98_eTOrZ1GifyTgi3lrUHa7edqVbgR4_8rGKw,6324
11
- fosslight_util/output_format.py,sha256=9O2IdhO3GRmrLvicvED-OXH1jPQpxXcLdwRm_lBo0rI,4983
10
+ fosslight_util/oss_item.py,sha256=lDbBzKDG0diId39Rk-kqtwGtTLpdATDPtkP47FhlkMA,6382
11
+ fosslight_util/output_format.py,sha256=je3oVrDDnA160jIkFGpCHlG9Fc4YDlkQGwor2LFSmb0,8173
12
12
  fosslight_util/parsing_yaml.py,sha256=2zx_N5lMkXT1dRmfJMpzlrru-y_2F_CkVbGlba6vQpU,5380
13
13
  fosslight_util/read_excel.py,sha256=-QvrdxaNqYOpIm1H7ZqIEh5NLvFPymZo6BAOZcQmQug,5263
14
14
  fosslight_util/set_log.py,sha256=Xpa94AiOyGEK8ucaYkvkAllvlen1Pq_d6UG6kPYBYBc,3780
@@ -17,15 +17,15 @@ fosslight_util/timer_thread.py,sha256=5VbZENQPD-N0NUmzEktqGr6Am-e7vxD79K05mmr29g
17
17
  fosslight_util/write_excel.py,sha256=G0fIslbWoOtWZCJxbBGLCpUKbhmwrrqhI5PHwRw8_44,9931
18
18
  fosslight_util/write_opossum.py,sha256=ltmo6SkugKWdAYupeCqwE4-3lua0GwLpix1XqFC-tT8,11678
19
19
  fosslight_util/write_scancodejson.py,sha256=81n7cWNYoyIKE_V4Kx5YtL2CgjMPIjoKdnSU3inkpJY,2163
20
- fosslight_util/write_spdx.py,sha256=MwR_OO9ua1Uvnk77etJXMHFUqnku2sZuuALdeIp7g4k,9478
20
+ fosslight_util/write_spdx.py,sha256=azAaZmkIeFhx9YlV644B59K7SYkLMxQbtAr2mwixwBs,11265
21
21
  fosslight_util/write_txt.py,sha256=BEFjYBppqk1CITx-fUN4vfvKv0XCs1GXWtc2Iu-etU4,629
22
22
  fosslight_util/write_yaml.py,sha256=QlEKoIPQsEaYERfbP53TeKgnllYzhLQWm5wYjnWtVjE,3238
23
23
  fosslight_util/resources/frequentLicenselist.json,sha256=GUhzK6tu7ok10fekOnmVmUgIGRC-acGABZKTNKfDyYA,4776157
24
24
  fosslight_util/resources/frequent_license_nick_list.json,sha256=ryU2C_6ZxHbz90_sUN9OvI9GXkCMLu7oGcmd9W79YYo,5005
25
25
  fosslight_util/resources/licenses.json,sha256=mK55z-bhY7Mjpj2KsO1crKGGL-X3F6MBFQJ0zLlx010,240843
26
- fosslight_util-2.0.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
27
- fosslight_util-2.0.0.dist-info/METADATA,sha256=GhApxdXkZnaERDjLepsy2WKvV1sJdt9B4FydaZqlHAk,6384
28
- fosslight_util-2.0.0.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
29
- fosslight_util-2.0.0.dist-info/entry_points.txt,sha256=bzXX5i7HZ13V8BLKvtu_9KO3ZjtRypH-XszOXT6I3bU,69
30
- fosslight_util-2.0.0.dist-info/top_level.txt,sha256=2qyYWGLakgBRy4BqoBNt-I5C29tBr_e93e5e1pbuTGA,15
31
- fosslight_util-2.0.0.dist-info/RECORD,,
26
+ fosslight_util-2.0.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
27
+ fosslight_util-2.0.1.dist-info/METADATA,sha256=ESvt6K7SJ-ft5Lgt-5eNBzNv9Ss8EeJ4c5aYGB8it6s,6374
28
+ fosslight_util-2.0.1.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
29
+ fosslight_util-2.0.1.dist-info/entry_points.txt,sha256=bzXX5i7HZ13V8BLKvtu_9KO3ZjtRypH-XszOXT6I3bU,69
30
+ fosslight_util-2.0.1.dist-info/top_level.txt,sha256=2qyYWGLakgBRy4BqoBNt-I5C29tBr_e93e5e1pbuTGA,15
31
+ fosslight_util-2.0.1.dist-info/RECORD,,