fosslight-source 2.1.14__tar.gz → 2.1.16__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.
Files changed (24) hide show
  1. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/PKG-INFO +25 -2
  2. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/requirements.txt +1 -1
  3. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/setup.py +1 -1
  4. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source/_parsing_scancode_file_item.py +56 -3
  5. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source/_scan_item.py +7 -2
  6. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source.egg-info/PKG-INFO +26 -3
  7. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source.egg-info/SOURCES.txt +2 -1
  8. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source.egg-info/requires.txt +1 -1
  9. fosslight_source-2.1.16/tests/test_tox.py +161 -0
  10. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/LICENSE +0 -0
  11. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/MANIFEST.in +0 -0
  12. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/README.md +0 -0
  13. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/setup.cfg +0 -0
  14. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source/__init__.py +0 -0
  15. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source/_help.py +0 -0
  16. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source/_license_matched.py +0 -0
  17. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source/_parsing_scanoss_file.py +0 -0
  18. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source/cli.py +0 -0
  19. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source/run_scancode.py +0 -0
  20. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source/run_scanoss.py +0 -0
  21. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source/run_spdx_extractor.py +0 -0
  22. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source.egg-info/dependency_links.txt +0 -0
  23. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source.egg-info/entry_points.txt +0 -0
  24. {fosslight_source-2.1.14 → fosslight_source-2.1.16}/src/fosslight_source.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: fosslight_source
3
- Version: 2.1.14
3
+ Version: 2.1.16
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
@@ -14,6 +14,29 @@ Classifier: Programming Language :: Python :: 3.12
14
14
  Requires-Python: >=3.10, <3.13
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
+ Requires-Dist: pyparsing
18
+ Requires-Dist: scanoss>=1.18.0
19
+ Requires-Dist: XlsxWriter
20
+ Requires-Dist: fosslight_util>=2.1.30
21
+ Requires-Dist: PyYAML
22
+ Requires-Dist: wheel>=0.38.1
23
+ Requires-Dist: intbitset
24
+ Requires-Dist: fosslight_binary>=5.0.0
25
+ Requires-Dist: scancode-toolkit>=32.0.2
26
+ Requires-Dist: fingerprints==1.2.3
27
+ Requires-Dist: normality==2.6.1
28
+ Requires-Dist: click==8.2.1
29
+ Dynamic: author
30
+ Dynamic: classifier
31
+ Dynamic: description
32
+ Dynamic: description-content-type
33
+ Dynamic: download-url
34
+ Dynamic: home-page
35
+ Dynamic: license
36
+ Dynamic: license-file
37
+ Dynamic: requires-dist
38
+ Dynamic: requires-python
39
+ Dynamic: summary
17
40
 
18
41
  <!--
19
42
  Copyright (c) 2021 LG Electronics
@@ -1,7 +1,7 @@
1
1
  pyparsing
2
2
  scanoss>=1.18.0
3
3
  XlsxWriter
4
- fosslight_util>=2.1.10
4
+ fosslight_util>=2.1.30
5
5
  PyYAML
6
6
  wheel>=0.38.1
7
7
  intbitset
@@ -14,7 +14,7 @@ with open('requirements.txt', 'r', 'utf-8') as f:
14
14
  if __name__ == "__main__":
15
15
  setup(
16
16
  name='fosslight_source',
17
- version='2.1.14',
17
+ version='2.1.16',
18
18
  package_dir={"": "src"},
19
19
  packages=find_packages(where='src'),
20
20
  description='FOSSLight Source Scanner',
@@ -7,6 +7,7 @@ import os
7
7
  import logging
8
8
  import re
9
9
  import fosslight_util.constant as constant
10
+ from fosslight_util.get_pom_license import get_license_from_pom
10
11
  from ._license_matched import MatchedLicense
11
12
  from ._scan_item import SourceItem
12
13
  from ._scan_item import is_exclude_dir
@@ -192,8 +193,34 @@ def parsing_scancode_32_earlier(scancode_file_list: list, has_error: bool = Fals
192
193
  if len(license_detected) > 0:
193
194
  result_item.licenses = license_detected
194
195
 
195
- if is_manifest_file(file_path):
196
+ detected_without_pom = []
197
+ if is_manifest_file(file_path) and len(license_detected) > 0:
196
198
  result_item.is_manifest_file = True
199
+ if file_path.endswith('.pom'):
200
+ try:
201
+ pom_licenses = get_license_from_pom(pom_path=file_path, check_parent=False)
202
+ normalize_pom_licenses = []
203
+ if pom_licenses:
204
+ pom_license_list = pom_licenses.split(', ')
205
+ for pom_license in pom_license_list:
206
+ if pom_license not in license_detected:
207
+ for lic_matched_key, lic_info in license_list.items():
208
+ if hasattr(lic_info, 'matched_text') and lic_info.matched_text:
209
+ matched_txt = str(lic_info.matched_text).replace(',', '')
210
+ if pom_license in matched_txt:
211
+ normalize_pom_licenses.append(lic_info.license)
212
+ break
213
+ else:
214
+ normalize_pom_licenses.append(pom_license)
215
+ detected_without_pom = list(set(license_detected) - set(normalize_pom_licenses))
216
+ if detected_without_pom:
217
+ result_item.comment = f"Detected: {', '.join(detected_without_pom)}"
218
+ result_item.licenses = []
219
+ result_item.licenses = normalize_pom_licenses
220
+ if not normalize_pom_licenses:
221
+ result_item.exclude = True
222
+ except Exception as ex:
223
+ logger.info(f"Failed to extract license from POM {file_path}: {ex}")
197
224
 
198
225
  # Remove copyright info for license text file of GPL family
199
226
  if should_remove_copyright_for_gpl_license_text(license_detected, result_item.is_license_text):
@@ -202,7 +229,7 @@ def parsing_scancode_32_earlier(scancode_file_list: list, has_error: bool = Fals
202
229
  else:
203
230
  result_item.copyright = copyright_value_list
204
231
 
205
- if len(license_expression_list) > 0:
232
+ if len(license_expression_list) > 0 and not detected_without_pom:
206
233
  license_expression_list = list(
207
234
  set(license_expression_list))
208
235
  result_item.comment = ','.join(license_expression_list)
@@ -307,8 +334,34 @@ def parsing_scancode_32_later(
307
334
  result_item.exclude = is_exclude_file(file_path)
308
335
  result_item.is_license_text = file.get("percentage_of_license_text", 0) > 90 or is_notice_file(file_path)
309
336
 
337
+ detected_without_pom = []
310
338
  if is_manifest_file(file_path) and len(license_detected) > 0:
311
339
  result_item.is_manifest_file = True
340
+ if file_path.endswith('.pom'):
341
+ try:
342
+ pom_licenses = get_license_from_pom(pom_path=file_path, check_parent=False)
343
+ normalize_pom_licenses = []
344
+ if pom_licenses:
345
+ pom_license_list = pom_licenses.split(', ')
346
+ for pom_license in pom_license_list:
347
+ if pom_license not in license_detected:
348
+ for lic_matched_key, lic_info in license_list.items():
349
+ if hasattr(lic_info, 'matched_text') and lic_info.matched_text:
350
+ matched_txt = str(lic_info.matched_text).replace(',', '')
351
+ if pom_license in matched_txt:
352
+ normalize_pom_licenses.append(lic_info.license)
353
+ break
354
+ else:
355
+ normalize_pom_licenses.append(pom_license)
356
+ detected_without_pom = list(set(license_detected) - set(normalize_pom_licenses))
357
+ if detected_without_pom:
358
+ result_item.comment = f"Detected: {', '.join(detected_without_pom)}"
359
+ result_item.licenses = []
360
+ result_item.licenses = normalize_pom_licenses
361
+ if not normalize_pom_licenses:
362
+ result_item.exclude = True
363
+ except Exception as ex:
364
+ logger.info(f"Failed to extract license from POM {file_path}: {ex}")
312
365
 
313
366
  # Remove copyright info for license text file of GPL family
314
367
  if should_remove_copyright_for_gpl_license_text(license_detected, result_item.is_license_text):
@@ -317,7 +370,7 @@ def parsing_scancode_32_later(
317
370
  else:
318
371
  result_item.copyright = copyright_value_list
319
372
 
320
- if len(license_detected) > 1:
373
+ if len(license_detected) > 1 and not detected_without_pom:
321
374
  license_expression_spdx = file.get("detected_license_expression_spdx", "")
322
375
  license_expression = file.get("detected_license_expression", "")
323
376
  if license_expression_spdx:
@@ -74,6 +74,8 @@ class SourceItem(FileItem):
74
74
  break
75
75
  if max_length_exceed and (SUBSTRING_LICENSE_COMMENT not in self.comment):
76
76
  self.comment = f"{self.comment}/ {SUBSTRING_LICENSE_COMMENT}" if self.comment else SUBSTRING_LICENSE_COMMENT
77
+ else:
78
+ self._licenses = value
77
79
 
78
80
  def set_oss_item(self) -> None:
79
81
  self.oss_items = []
@@ -151,10 +153,13 @@ def is_manifest_file(file_path: str) -> bool:
151
153
 
152
154
 
153
155
  def is_package_dir(dir_path: str) -> bool:
154
- path_parts = dir_path.split(os.path.sep)
156
+ # scancode and scanoss use '/' as path separator regardless of OS
157
+ dir_path = dir_path.replace('\\', '/')
158
+ path_parts = dir_path.split('/')
159
+
155
160
  for pkg_dir in _package_directory:
156
161
  if pkg_dir in path_parts:
157
162
  pkg_index = path_parts.index(pkg_dir)
158
- pkg_path = os.path.sep.join(path_parts[:pkg_index + 1])
163
+ pkg_path = '/'.join(path_parts[:pkg_index + 1])
159
164
  return True, pkg_path
160
165
  return False, ""
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
2
- Name: fosslight-source
3
- Version: 2.1.14
1
+ Metadata-Version: 2.4
2
+ Name: fosslight_source
3
+ Version: 2.1.16
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
@@ -14,6 +14,29 @@ Classifier: Programming Language :: Python :: 3.12
14
14
  Requires-Python: >=3.10, <3.13
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
+ Requires-Dist: pyparsing
18
+ Requires-Dist: scanoss>=1.18.0
19
+ Requires-Dist: XlsxWriter
20
+ Requires-Dist: fosslight_util>=2.1.30
21
+ Requires-Dist: PyYAML
22
+ Requires-Dist: wheel>=0.38.1
23
+ Requires-Dist: intbitset
24
+ Requires-Dist: fosslight_binary>=5.0.0
25
+ Requires-Dist: scancode-toolkit>=32.0.2
26
+ Requires-Dist: fingerprints==1.2.3
27
+ Requires-Dist: normality==2.6.1
28
+ Requires-Dist: click==8.2.1
29
+ Dynamic: author
30
+ Dynamic: classifier
31
+ Dynamic: description
32
+ Dynamic: description-content-type
33
+ Dynamic: download-url
34
+ Dynamic: home-page
35
+ Dynamic: license
36
+ Dynamic: license-file
37
+ Dynamic: requires-dist
38
+ Dynamic: requires-python
39
+ Dynamic: summary
17
40
 
18
41
  <!--
19
42
  Copyright (c) 2021 LG Electronics
@@ -18,4 +18,5 @@ src/fosslight_source.egg-info/SOURCES.txt
18
18
  src/fosslight_source.egg-info/dependency_links.txt
19
19
  src/fosslight_source.egg-info/entry_points.txt
20
20
  src/fosslight_source.egg-info/requires.txt
21
- src/fosslight_source.egg-info/top_level.txt
21
+ src/fosslight_source.egg-info/top_level.txt
22
+ tests/test_tox.py
@@ -1,7 +1,7 @@
1
1
  pyparsing
2
2
  scanoss>=1.18.0
3
3
  XlsxWriter
4
- fosslight_util>=2.1.10
4
+ fosslight_util>=2.1.30
5
5
  PyYAML
6
6
  wheel>=0.38.1
7
7
  intbitset
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # Copyright (c) 2020 LG Electronics Inc.
4
+ # SPDX-License-Identifier: Apache-2.0
5
+ import os
6
+ import subprocess
7
+ import pytest
8
+ import shutil
9
+ import sys
10
+
11
+ # Add project root to sys.path for importing FL Source modules
12
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
13
+
14
+ # Import after sys.path modification to access our custom GPL license functions
15
+ # flake8: noqa E402
16
+ from fosslight_source._parsing_scancode_file_item import (
17
+ is_gpl_family_license, should_remove_copyright_for_gpl_license_text
18
+ )
19
+
20
+ remove_directories = ["test_scan", "test_scan2", "test_scan3"]
21
+
22
+
23
+ @pytest.fixture(scope="module", autouse=True)
24
+ def setup_test_result_dir():
25
+ print("==============setup==============")
26
+ for dir in remove_directories:
27
+ if os.path.exists(dir):
28
+ shutil.rmtree(dir)
29
+
30
+ yield
31
+
32
+
33
+ def run_command(command):
34
+ process = subprocess.run(command, shell=True, capture_output=True, text=True)
35
+ success = (process.returncode == 0)
36
+ return success, process.stdout if success else process.stderr
37
+
38
+
39
+ def test_is_gpl_family_license():
40
+ gpl_licenses = [
41
+ ["gpl-2.0"],
42
+ ["gpl-3.0"],
43
+ ["lgpl-2.1"],
44
+ ["lgpl-3.0"],
45
+ ["agpl-3.0"],
46
+ ["GPL-2.0"],
47
+ ["LGPL-2.1"],
48
+ ["AGPL-3.0"],
49
+ ["gpl-2.0-only"],
50
+ ["lgpl-2.1-only"],
51
+ ["agpl-3.0-only"],
52
+ ["gfdl-1.3"],
53
+ ["gpl-2.0", "mit"],
54
+ ["mit", "lgpl-3.0"]
55
+ ]
56
+
57
+ non_gpl_licenses = [
58
+ ["mit"],
59
+ ["apache-2.0"],
60
+ ["bsd-3-clause"],
61
+ ["mozilla-2.0"],
62
+ ["isc"],
63
+ [],
64
+ ["mit", "apache-2.0"]
65
+ ]
66
+
67
+ for licenses in gpl_licenses:
68
+ assert is_gpl_family_license(licenses), \
69
+ f"Should detect GPL family license: {licenses}"
70
+
71
+ for licenses in non_gpl_licenses:
72
+ assert not is_gpl_family_license(licenses), \
73
+ f"Should not detect GPL family license: {licenses}"
74
+
75
+
76
+ def test_should_remove_copyright_for_gpl_license_text():
77
+ assert should_remove_copyright_for_gpl_license_text(["gpl-2.0"], True), \
78
+ "Should remove copyright for GPL license text file"
79
+ assert should_remove_copyright_for_gpl_license_text(["lgpl-3.0"], True), \
80
+ "Should remove copyright for LGPL license text file"
81
+ assert should_remove_copyright_for_gpl_license_text(["agpl-3.0"], True), \
82
+ "Should remove copyright for AGPL license text file"
83
+
84
+ assert not should_remove_copyright_for_gpl_license_text(["gpl-2.0"], False), \
85
+ "Should NOT remove copyright for GPL source file"
86
+ assert not should_remove_copyright_for_gpl_license_text(["lgpl-3.0"], False), \
87
+ "Should NOT remove copyright for LGPL source file"
88
+
89
+ assert not should_remove_copyright_for_gpl_license_text(["mit"], True), \
90
+ "Should NOT remove copyright for MIT license text file"
91
+ assert not should_remove_copyright_for_gpl_license_text(["apache-2.0"], True), \
92
+ "Should NOT remove copyright for Apache license text file"
93
+
94
+ assert not should_remove_copyright_for_gpl_license_text(["mit"], False), \
95
+ "Should NOT remove copyright for MIT source file"
96
+
97
+ assert not should_remove_copyright_for_gpl_license_text([], True), \
98
+ "Should NOT remove copyright for empty license list"
99
+ assert not should_remove_copyright_for_gpl_license_text([], False), \
100
+ "Should NOT remove copyright for empty license list"
101
+
102
+
103
+ def test_run():
104
+ scan_success, _ = run_command("fosslight_source -p tests/test_files -j -m -o test_scan")
105
+ scan_exclude_success, _ = run_command("fosslight_source -p tests -e test_files/test cli_test.py -j -m -o test_scan2")
106
+ scan_files = os.listdir("test_scan")
107
+ scan2_files = os.listdir('test_scan2')
108
+
109
+ assert scan_success is True, "Test Run: Scan command failed"
110
+ assert scan_exclude_success is True, "Test Run: Exclude command failed"
111
+ assert len(scan_files) > 0, "Test Run: No scan files created in test_scan directory"
112
+ assert len(scan2_files) > 0, "Test Run: No scan files created in test_scan2 directory"
113
+
114
+
115
+ def test_help_command():
116
+ success, msg = run_command("fosslight_source -h")
117
+ assert success is True, f"Test Release: Help command failed :{msg}"
118
+
119
+
120
+ def test_scan_command():
121
+ success, _ = run_command("fosslight_source -p tests/test_files -o test_scan/scan_result.csv")
122
+ assert success is True, "Test Release: Failed to generate scan result CSV file"
123
+
124
+ assert os.path.exists("test_scan/scan_result.csv"), "Test Release: scan_result.csv file not generated"
125
+
126
+ with open("test_scan/scan_result.csv", 'r') as file:
127
+ content = file.read()
128
+
129
+ assert len(content) > 0, "Test Release: scan_result.csv is empty"
130
+ print(f"Content of scan_result.csv:\n{content}")
131
+
132
+
133
+ def test_exclude_command():
134
+ success, _ = run_command(
135
+ "fosslight_source -p tests -e test_files/test cli_test.py -j -m -o test_scan2/scan_exclude_result.csv"
136
+ )
137
+ assert success is True, "Test release: Exclude scan failded"
138
+
139
+ assert os.path.exists("test_scan2/scan_exclude_result.csv"), "Test Release: scan_exclude_result.csv file not generated"
140
+
141
+ with open("test_scan2/scan_exclude_result.csv", 'r') as file:
142
+ content = file.read()
143
+
144
+ assert len(content) > 0, "Test Release: scan_exclude_result.csv is empty"
145
+ print(f"Content of scan_exclude_result.csv:\n{content}")
146
+
147
+
148
+ def test_json_command():
149
+ success, _ = run_command("fosslight_source -p tests/test_files -m -j -o test_scan3/")
150
+ assert success is True, "Test release: Failed to generate JSON files"
151
+
152
+
153
+ def test_ls_test_scan3_command():
154
+ files_in_test_scan3 = os.listdir("test_scan3")
155
+ assert len(files_in_test_scan3) > 0, "Test Release: test_scan3 is empty"
156
+ print(f"Files in test_scan3: {files_in_test_scan3}")
157
+
158
+
159
+ def test_flake8():
160
+ success, _ = run_command("flake8 -j 4")
161
+ assert success is True, "Flake8: Style check failed"