fosslight-source 2.2.2__py3-none-any.whl → 2.2.4__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_source/_help.py CHANGED
@@ -6,33 +6,56 @@ from fosslight_util.help import PrintHelpMsg, print_package_version
6
6
  from fosslight_util.output_format import SUPPORT_FORMAT
7
7
 
8
8
  _HELP_MESSAGE_SOURCE_SCANNER = f"""
9
- FOSSLight Source Scanner Usage: fosslight_source [option1] <arg1> [option2] <arg2>...
10
-
11
- FOSSLight Source Scanner uses ScanCode and SCANOSS, the source code scanners, to detect
12
- the copyright and license phrases contained in the file.
13
- Some files (ex- build script), binary files, directory and files in specific
14
- directories (ex-test) are excluded from the result.
15
-
16
- Options:
17
- Optional
18
- -p <source_path>\t Path to analyze source (Default: current directory)
19
- -h\t\t\t Print help message
20
- -v\t\t\t Print FOSSLight Source Scanner version
21
- -m\t\t\t Print additional information for scan result on separate sheets
22
- -e <path>\t\t Path to exclude from analysis (files and directories)
23
- \t\t\t * IMPORTANT: Always wrap patterns in double quotes ("") to avoid shell expansion.
24
- \t\t\t Example) fosslight_source -e "dev/" "tests/"
25
- -o <output_path>\t Output path (Path or file name)
26
- -f <format>\t\t Output file formats
27
- \t\t\t ({', '.join(SUPPORT_FORMAT)})
28
- \t\t\t Multiple formats can be specified separated by space.
29
- Options only for FOSSLight Source Scanner
30
- -s <scanner>\t Select which scanner to be run (scancode, scanoss, kb, all)
31
- -j\t\t\t Generate raw result of scanners in json format
32
- -t <float>\t\t Stop scancode scanning if scanning takes longer than a timeout in seconds.
33
- -c <core>\t\t Select the number of cores to be scanned with ScanCode or threads with SCANOSS.
34
- --no_correction\t Enter if you don't want to correct OSS information with sbom-info.yaml
35
- --correct_fpath <path> Path to the sbom-info.yaml file"""
9
+ 📖 Usage
10
+ ────────────────────────────────────────────────────────────────────
11
+ fosslight_source [options] <arguments>
12
+
13
+ 📝 Description
14
+ ────────────────────────────────────────────────────────────────────
15
+ FOSSLight Source Scanner analyzes source code to detect copyright and
16
+ license information using several modes.
17
+
18
+ Note: Build scripts, binary files, and test directories are automatically
19
+ excluded from analysis.
20
+
21
+ 📚 Guide: https://fosslight.org/fosslight-guide/scanner/2_source.html
22
+
23
+ ⚙️ General Options
24
+ ────────────────────────────────────────────────────────────────────
25
+ -p <path> Source path to analyze (default: current directory)
26
+ -o <path> Output file path or directory
27
+ -f <format> Output formats: {', '.join(SUPPORT_FORMAT)}
28
+ (multiple formats can be specified, separated by space)
29
+ -e <pattern> Exclude paths from analysis (files and directories)
30
+ ⚠️ IMPORTANT: Always wrap in quotes to avoid shell expansion
31
+ Example: fosslight_source -e "dev/" "tests/" "*.jar"
32
+ -m Generate detailed scan results on separate sheets
33
+ -h Show this help message
34
+ -v Show version information
35
+
36
+ 🔍 Scanner-Specific Options
37
+ ────────────────────────────────────────────────────────────────────
38
+ -s <mode> Choose mode: scancode, scanoss, kb, or all(default)
39
+ -c <number> Number of CPU cores/threads to use for scanning
40
+ -t <seconds> Timeout in seconds for ScanCode scanning
41
+ -j Generate raw scanner results in JSON format
42
+ --no_correction Skip OSS information correction with sbom-info.yaml
43
+ --correct_fpath <path> Path to custom sbom-info.yaml file
44
+
45
+ 💡 Examples
46
+ ────────────────────────────────────────────────────────────────────
47
+ # Scan current directory
48
+ fosslight_source
49
+
50
+ # Scan specific path with exclusions
51
+ fosslight_source -p /path/to/source -e "test/" "node_modules/"
52
+
53
+ # Generate output in specific format
54
+ fosslight_source -f excel -o results/
55
+
56
+ # Generate raw scanner results in JSON format
57
+ fosslight_source -p /path/to/source -j
58
+ """
36
59
 
37
60
 
38
61
  def print_version(pkg_name: str) -> None:
fosslight_source/cli.py CHANGED
@@ -30,6 +30,7 @@ from ._scan_item import SourceItem, KB_URL
30
30
  from fosslight_util.oss_item import ScannerItem
31
31
  from typing import Tuple
32
32
  from ._scan_item import is_manifest_file
33
+ import shutil
33
34
 
34
35
 
35
36
  SRC_SHEET_NAME = 'SRC_FL_Source'
@@ -40,9 +41,7 @@ MERGED_HEADER = {SRC_SHEET_NAME: ['ID', 'Source Path', 'OSS Name',
40
41
  'OSS Version', 'License', 'Download Location',
41
42
  'Homepage', 'Copyright Text', 'Exclude', 'Comment', 'license_reference']}
42
43
  SCANNER_TYPE = ['kb', 'scancode', 'scanoss', 'all']
43
- EXCLUDE_FILENAME = ["changelog", "config.guess", "config.sub", "changes", "ltmain.sh",
44
- "configure", "configure.ac", "depcomp", "compile", "missing", "Makefile"]
45
- EXCLUDE_FILE_EXTENSION = [".m4", ".in", ".po"]
44
+
46
45
 
47
46
  logger = logging.getLogger(constant.LOGGER_NAME)
48
47
  warnings.filterwarnings("ignore", category=FutureWarning)
@@ -138,7 +137,7 @@ def create_report_file(
138
137
  output_path: str = "", output_files: list = [],
139
138
  output_extensions: list = [], correct_mode: bool = True,
140
139
  correct_filepath: str = "", path_to_scan: str = "", path_to_exclude: list = [],
141
- formats: list = [], api_limit_exceed: bool = False, files_count: int = 0
140
+ formats: list = [], api_limit_exceed: bool = False, files_count: int = 0, final_output_path: str = ""
142
141
  ) -> 'ScannerItem':
143
142
  """
144
143
  Create report files for given scanned result.
@@ -152,10 +151,7 @@ def create_report_file(
152
151
  sheet_list = {}
153
152
  _json_ext = ".json"
154
153
 
155
- if output_path == "":
156
- output_path = os.getcwd()
157
- else:
158
- output_path = os.path.abspath(output_path)
154
+ output_path = os.path.abspath(output_path)
159
155
 
160
156
  if not output_files:
161
157
  # If -o does not contains file name, set default name
@@ -199,15 +195,27 @@ def create_report_file(
199
195
  scan_item.set_cover_pathinfo(path_to_scan, path_to_exclude)
200
196
  scan_item.set_cover_comment(f"Scanned files: {files_count}")
201
197
 
202
- if api_limit_exceed:
203
- scan_item.set_cover_comment("(Some of) SCANOSS scan was skipped. (API limits being exceeded)")
204
-
205
- if not merged_result:
198
+ if merged_result:
199
+ scan_item.set_cover_comment(f"Detected source : {len(merged_result)}")
200
+ else:
206
201
  if files_count < 1:
207
202
  scan_item.set_cover_comment("(No file detected.)")
208
203
  else:
209
204
  scan_item.set_cover_comment("(No OSS detected.)")
210
205
 
206
+ if api_limit_exceed:
207
+ scan_item.set_cover_comment("SCANOSS skipped (API limits)")
208
+
209
+ run_kb = True if selected_scanner in ['kb', 'all'] else False
210
+ if run_kb:
211
+ scan_item.set_cover_comment("KB Enabled" if check_kb_server_reachable() else "KB Unreachable")
212
+ display_mode = selected_scanner
213
+ if selected_scanner == "kb":
214
+ display_mode += ", scancode"
215
+ elif selected_scanner == "all":
216
+ display_mode = "kb, scancode, scanoss"
217
+ scan_item.set_cover_comment(f"Mode : {display_mode}")
218
+
211
219
  if merged_result:
212
220
  sheet_list = {}
213
221
  scan_item.append_file_items(merged_result, PKG_NAME)
@@ -243,12 +251,13 @@ def create_report_file(
243
251
  # del sheet_list["scanoss_reference"]
244
252
  results.append(write_output_file(combined_path_and_file, output_extension, scan_item, extended_header, "", output_format))
245
253
  for success, msg, result_file in results:
254
+ final_result_file = result_file.replace(output_path, final_output_path)
246
255
  if success:
247
- logger.info(f"Output file: {result_file}")
256
+ logger.info(f"Output file: {final_result_file}")
248
257
  for row in scan_item.get_cover_comment():
249
258
  logger.info(row)
250
259
  else:
251
- logger.error(f"Fail to generate result file {result_file}. msg:({msg})")
260
+ logger.error(f"Fail to generate result file {final_result_file}. msg:({msg})")
252
261
  return scan_item
253
262
 
254
263
 
@@ -326,7 +335,8 @@ def run_scanners(
326
335
  called_by_cli: bool = True, print_matched_text: bool = False,
327
336
  formats: list = [], time_out: int = 120,
328
337
  correct_mode: bool = True, correct_filepath: str = "",
329
- selected_scanner: str = 'all', path_to_exclude: list = []
338
+ selected_scanner: str = 'all', path_to_exclude: list = [],
339
+ all_exclude_mode: tuple = ()
330
340
  ) -> Tuple[bool, str, 'ScannerItem', list, list]:
331
341
  """
332
342
  Run Scancode and scanoss.py for the given path.
@@ -357,6 +367,11 @@ def run_scanners(
357
367
 
358
368
  success, msg, output_path, output_files, output_extensions, formats = check_output_formats_v2(output_file_name, formats)
359
369
 
370
+ if output_path == "":
371
+ output_path = os.getcwd()
372
+ final_output_path = output_path
373
+ output_path = os.path.join(os.path.dirname(output_path), f'.fosslight_temp_{start_time}')
374
+
360
375
  logger, result_log = init_log(os.path.join(output_path, f"fosslight_log_src_{start_time}.txt"),
361
376
  True, logging.INFO, logging.DEBUG, PKG_NAME, path_to_scan, path_to_exclude)
362
377
 
@@ -365,10 +380,18 @@ def run_scanners(
365
380
  print_matched_text = False
366
381
 
367
382
  if success:
368
- path_to_exclude_with_filename = path_to_exclude + EXCLUDE_FILENAME
369
- excluded_path_with_default_exclusion, excluded_path_without_dot, excluded_files, cnt_file_except_skipped = (
370
- get_excluded_paths(path_to_scan, path_to_exclude_with_filename, EXCLUDE_FILE_EXTENSION))
371
- logger.debug(f"Skipped paths: {excluded_path_with_default_exclusion}")
383
+ if all_exclude_mode and len(all_exclude_mode) == 4:
384
+ (excluded_path_with_default_exclusion,
385
+ excluded_path_without_dot,
386
+ excluded_files,
387
+ cnt_file_except_skipped) = all_exclude_mode
388
+ else:
389
+ path_to_exclude_with_filename = path_to_exclude
390
+ (excluded_path_with_default_exclusion,
391
+ excluded_path_without_dot,
392
+ excluded_files,
393
+ cnt_file_except_skipped) = get_excluded_paths(path_to_scan, path_to_exclude_with_filename)
394
+ logger.debug(f"Skipped paths: {excluded_path_with_default_exclusion}")
372
395
 
373
396
  if not selected_scanner:
374
397
  selected_scanner = 'all'
@@ -381,8 +404,10 @@ def run_scanners(
381
404
  excluded_files)
382
405
  excluded_files = set(excluded_files) if excluded_files else set()
383
406
  if selected_scanner in ['scanoss', 'all']:
384
- scanoss_result, api_limit_exceed = run_scanoss_py(path_to_scan, output_file_name, formats, True, write_json_file,
385
- num_cores, excluded_path_with_default_exclusion, excluded_files)
407
+ scanoss_result, api_limit_exceed = run_scanoss_py(path_to_scan, output_path, formats, True, num_cores,
408
+ excluded_path_with_default_exclusion, excluded_files,
409
+ write_json_file)
410
+
386
411
  if selected_scanner in SCANNER_TYPE:
387
412
  run_kb = True if selected_scanner in ['kb', 'all'] else False
388
413
  spdx_downloads, manifest_licenses = metadata_collector(path_to_scan, excluded_files)
@@ -391,7 +416,7 @@ def run_scanners(
391
416
  scan_item = create_report_file(start_time, merged_result, license_list, scanoss_result, selected_scanner,
392
417
  print_matched_text, output_path, output_files, output_extensions, correct_mode,
393
418
  correct_filepath, path_to_scan, excluded_path_without_dot, formats,
394
- api_limit_exceed, cnt_file_except_skipped)
419
+ api_limit_exceed, cnt_file_except_skipped, final_output_path)
395
420
  else:
396
421
  print_help_msg_source_scanner()
397
422
  result_log[RESULT_KEY] = "Unsupported scanner"
@@ -399,6 +424,13 @@ def run_scanners(
399
424
  else:
400
425
  result_log[RESULT_KEY] = f"Format error. {msg}"
401
426
  success = False
427
+
428
+ try:
429
+ shutil.copytree(output_path, final_output_path, dirs_exist_ok=True)
430
+ shutil.rmtree(output_path)
431
+ except Exception as ex:
432
+ logger.debug(f"Failed to move temp files: {ex}")
433
+
402
434
  return success, result_log.get(RESULT_KEY, ""), scan_item, license_list, scanoss_result
403
435
 
404
436
 
@@ -42,8 +42,6 @@ def get_licenses_from_package_json(file_path: str) -> list[str]:
42
42
 
43
43
  if isinstance(license_field, str):
44
44
  value = license_field.strip()
45
- if value.upper() == 'UNLICENSED':
46
- return []
47
45
  if value.upper().startswith('SEE LICENSE IN'):
48
46
  return []
49
47
  licenses.extend(_split_spdx_expression(value))
@@ -51,7 +49,7 @@ def get_licenses_from_package_json(file_path: str) -> list[str]:
51
49
  type_val = license_field.get('type')
52
50
  if isinstance(type_val, str):
53
51
  type_val = type_val.strip()
54
- if type_val and type_val.upper() != 'UNLICENSED':
52
+ if type_val:
55
53
  licenses.append(type_val)
56
54
 
57
55
  if not licenses:
@@ -60,13 +58,13 @@ def get_licenses_from_package_json(file_path: str) -> list[str]:
60
58
  for item in legacy:
61
59
  if isinstance(item, str):
62
60
  token = item.strip()
63
- if token and token.upper() != 'UNLICENSED':
61
+ if token:
64
62
  licenses.append(token)
65
63
  elif isinstance(item, dict):
66
64
  t = item.get('type')
67
65
  if isinstance(t, str):
68
66
  t = t.strip()
69
- if t and t.upper() != 'UNLICENSED':
67
+ if t:
70
68
  licenses.append(t)
71
69
 
72
70
  unique: list[str] = []
@@ -8,14 +8,10 @@ import importlib_metadata
8
8
  import warnings
9
9
  import logging
10
10
  import json
11
- from datetime import datetime
11
+ from typing import Tuple
12
12
  import fosslight_util.constant as constant
13
- from fosslight_util.set_log import init_log
14
- from fosslight_util.output_format import check_output_formats_v2 # , write_output_file
15
13
  from ._parsing_scanoss_file import parsing_scan_result # scanoss
16
14
  from ._parsing_scanoss_file import parsing_extra_info # scanoss
17
- import shutil
18
- from pathlib import Path
19
15
  from scanoss.scanner import Scanner, ScanType
20
16
  import io
21
17
  import contextlib
@@ -23,7 +19,6 @@ import contextlib
23
19
  logger = logging.getLogger(constant.LOGGER_NAME)
24
20
  warnings.filterwarnings("ignore", category=FutureWarning)
25
21
  _PKG_NAME = "fosslight_source"
26
- SCANOSS_RESULT_FILE = "scanner_output.wfp"
27
22
  SCANOSS_OUTPUT_FILE = "scanoss_raw_result.json"
28
23
 
29
24
 
@@ -31,9 +26,10 @@ def get_scanoss_extra_info(scanned_result: dict) -> list:
31
26
  return parsing_extra_info(scanned_result)
32
27
 
33
28
 
34
- def run_scanoss_py(path_to_scan: str, output_file_name: str = "", format: list = [],
35
- called_by_cli: bool = False, write_json_file: bool = False, num_threads: int = -1,
36
- path_to_exclude: list = [], excluded_files: set = None) -> list:
29
+ def run_scanoss_py(path_to_scan: str, output_path: str = "", format: list = [],
30
+ called_by_cli: bool = False, num_threads: int = -1,
31
+ path_to_exclude: list = [], excluded_files: set = None,
32
+ write_json_file: bool = False) -> Tuple[list, bool]:
37
33
  """
38
34
  Run scanoss.py for the given path.
39
35
 
@@ -44,30 +40,18 @@ def run_scanoss_py(path_to_scan: str, output_file_name: str = "", format: list =
44
40
  :param write_json_file: if requested, keep the raw files.
45
41
  :return scanoss_file_list: list of ScanItem (scanned result by files).
46
42
  """
47
- success, msg, output_path, output_files, output_extensions, formats = check_output_formats_v2(output_file_name, format)
48
-
49
- if not called_by_cli:
50
- global logger
51
- _start_time = datetime.now().strftime('%y%m%d_%H%M')
52
- logger, _result_log = init_log(os.path.join(output_path, f"fosslight_log_src_{_start_time}.txt"),
53
- True, logging.INFO, logging.DEBUG, _PKG_NAME, path_to_scan, path_to_exclude)
54
43
 
55
44
  scanoss_file_list = []
45
+ api_limit_exceed = False
56
46
  try:
57
47
  importlib_metadata.distribution("scanoss")
58
48
  except Exception as error:
59
49
  logger.warning(f"{error}. Skipping scan with scanoss.")
60
50
  logger.warning("Please install scanoss and dataclasses before run fosslight_source with scanoss option.")
61
- return scanoss_file_list
62
-
63
- if output_path == "": # if json output with _write_json_file not used, output_path won't be needed.
64
- output_path = os.getcwd()
65
- else:
66
- output_path = os.path.abspath(output_path)
67
- if not os.path.isdir(output_path):
68
- Path(output_path).mkdir(parents=True, exist_ok=True)
51
+ return scanoss_file_list, api_limit_exceed
52
+
69
53
  output_json_file = os.path.join(output_path, SCANOSS_OUTPUT_FILE)
70
- if os.path.exists(output_json_file): # remove scanner_output.wfp file if exist
54
+ if os.path.exists(output_json_file):
71
55
  os.remove(output_json_file)
72
56
 
73
57
  try:
@@ -84,7 +68,6 @@ def run_scanoss_py(path_to_scan: str, output_file_name: str = "", format: list =
84
68
  scanner.scan_folder_with_options(scan_dir=path_to_scan)
85
69
  captured_output = output_buffer.getvalue()
86
70
  api_limit_exceed = "due to service limits being exceeded" in captured_output
87
- logger.debug(f"{captured_output}")
88
71
 
89
72
  if os.path.isfile(output_json_file):
90
73
  with open(output_json_file, "r") as st_json:
@@ -98,18 +81,13 @@ def run_scanoss_py(path_to_scan: str, output_file_name: str = "", format: list =
98
81
  st_python = json.load(st_json)
99
82
  scanoss_file_list = parsing_scan_result(st_python, excluded_files)
100
83
 
84
+ if not write_json_file:
85
+ if os.path.isfile(output_json_file):
86
+ os.remove(output_json_file)
87
+
101
88
  except Exception as error:
102
89
  logger.debug(f"SCANOSS Parsing {path_to_scan}: {error}")
103
90
 
104
91
  logger.info(f"|---Number of files detected with SCANOSS: {(len(scanoss_file_list))}")
105
92
 
106
- try:
107
- if write_json_file:
108
- shutil.move(SCANOSS_RESULT_FILE, output_path)
109
- else:
110
- os.remove(output_json_file)
111
- os.remove(SCANOSS_RESULT_FILE)
112
- except Exception as error:
113
- logger.debug(f"Moving scanoss raw files failed.: {error}")
114
-
115
93
  return scanoss_file_list, api_limit_exceed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fosslight_source
3
- Version: 2.2.2
3
+ Version: 2.2.4
4
4
  Summary: FOSSLight Source Scanner
5
5
  Home-page: https://github.com/fosslight/fosslight_source_scanner
6
6
  Download-URL: https://github.com/fosslight/fosslight_source_scanner
@@ -17,7 +17,7 @@ License-File: LICENSE
17
17
  Requires-Dist: pyparsing
18
18
  Requires-Dist: scanoss>=1.18.0
19
19
  Requires-Dist: XlsxWriter
20
- Requires-Dist: fosslight_util>=2.1.34
20
+ Requires-Dist: fosslight_util>=2.1.37
21
21
  Requires-Dist: PyYAML
22
22
  Requires-Dist: wheel>=0.38.1
23
23
  Requires-Dist: intbitset
@@ -1,17 +1,17 @@
1
1
  fosslight_source/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- fosslight_source/_help.py,sha256=Ge6g9GKWGza11E74PFnBMqsj40UCUz-a_xArDZ1FClU,2316
2
+ fosslight_source/_help.py,sha256=Zgc-66WakwuF2iPnoxQlRHx64kLabdiPemkVxKz9S7Y,3553
3
3
  fosslight_source/_license_matched.py,sha256=-3H881XQjFDafRttBsuboS3VbCPYEvPH1pwWXptknE4,2164
4
4
  fosslight_source/_parsing_scancode_file_item.py,sha256=9TjCwTTPaytqTlZzCKzaX-n20xJLy346xwp0Ee-rWWA,14951
5
5
  fosslight_source/_parsing_scanoss_file.py,sha256=L3iHqmQF2jeSpHYuYSre44doXKy-BoX0u1Lm2IfJSU8,3866
6
6
  fosslight_source/_scan_item.py,sha256=rWoC-jMc6Hf_dpiwVdQjATNhkzRgLVn966q3UA1TAxc,9412
7
- fosslight_source/cli.py,sha256=Ohsl9h4-9zS72pPQCf22Ij7LrUinhpioC_2DNro3bXQ,19385
8
- fosslight_source/run_manifest_extractor.py,sha256=oaCdfXDp0bRqeEq0U3Yaf6fiZ-xjOOGsZBVbAeMN2zI,9105
7
+ fosslight_source/cli.py,sha256=1Cc1vLESYHzb101OJb9ySgtfNZa0pQRNHxJ1XT1eUrg,20456
8
+ fosslight_source/run_manifest_extractor.py,sha256=8itu69eoriEnSskVDF9rnkLZ3d515KTaKy6tkZKWgBk,8940
9
9
  fosslight_source/run_scancode.py,sha256=TFyNLV6P9rSBo9royDoG6az4l7Tkpl8Gr66IFK1DBU8,9021
10
- fosslight_source/run_scanoss.py,sha256=_gdA4kOByI4saT4bDvMwIabpxtpH4f_yruHdBtb_g-o,4852
10
+ fosslight_source/run_scanoss.py,sha256=egy7he8TlJCUfeijLG7K0-Dxry7jpmzYVewUJVNgNFg,3692
11
11
  fosslight_source/run_spdx_extractor.py,sha256=wIdjDIpzglc2tfrh_YodkAQ0QqfgfmJBSuE2bf4w4Tg,862
12
- fosslight_source-2.2.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
13
- fosslight_source-2.2.2.dist-info/METADATA,sha256=Jw2ERDhSs7sfNrQuV3bLT5vnC4fMDYGV-EFmTak_yfc,3557
14
- fosslight_source-2.2.2.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
15
- fosslight_source-2.2.2.dist-info/entry_points.txt,sha256=G4bBRWqSrJ68g-2M-JtNDrSZsdym_M7_KohQ2qR1vG8,113
16
- fosslight_source-2.2.2.dist-info/top_level.txt,sha256=C2vw-0OIent84Vq-UEk1gt_kK1EL8dIItzBzp3WNyA4,17
17
- fosslight_source-2.2.2.dist-info/RECORD,,
12
+ fosslight_source-2.2.4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
13
+ fosslight_source-2.2.4.dist-info/METADATA,sha256=N2OOmBcIxEGfpXU-iveG-wmflo1XFpErsGDPhPp5ZIM,3557
14
+ fosslight_source-2.2.4.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
15
+ fosslight_source-2.2.4.dist-info/entry_points.txt,sha256=G4bBRWqSrJ68g-2M-JtNDrSZsdym_M7_KohQ2qR1vG8,113
16
+ fosslight_source-2.2.4.dist-info/top_level.txt,sha256=C2vw-0OIent84Vq-UEk1gt_kK1EL8dIItzBzp3WNyA4,17
17
+ fosslight_source-2.2.4.dist-info/RECORD,,