fosslight-dependency 4.1.7__tar.gz → 4.1.9__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 (40) hide show
  1. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/PKG-INFO +3 -3
  2. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/setup.py +5 -8
  3. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/_analyze_dependency.py +7 -1
  4. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/_help.py +2 -1
  5. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/_package_manager.py +21 -95
  6. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/constant.py +2 -0
  7. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Carthage.py +4 -6
  8. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Npm.py +1 -1
  9. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Nuget.py +6 -10
  10. fosslight_dependency-4.1.9/src/fosslight_dependency/package_manager/Pnpm.py +155 -0
  11. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Pub.py +2 -5
  12. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Pypi.py +3 -8
  13. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Swift.py +1 -1
  14. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Unity.py +3 -6
  15. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/run_dependency_scanner.py +55 -31
  16. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency.egg-info/PKG-INFO +3 -3
  17. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency.egg-info/SOURCES.txt +1 -0
  18. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/LICENSE +0 -0
  19. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/LICENSES/Apache-2.0.txt +0 -0
  20. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/LICENSES/LicenseRef-3rd_party_licenses.txt +0 -0
  21. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/LICENSES/MIT.txt +0 -0
  22. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/MANIFEST.in +0 -0
  23. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/README.md +0 -0
  24. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/requirements.txt +0 -0
  25. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/setup.cfg +0 -0
  26. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/__init__.py +0 -0
  27. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/_graph_convertor.py +0 -0
  28. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/dependency_item.py +0 -0
  29. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Android.py +0 -0
  30. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Cargo.py +0 -0
  31. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Cocoapods.py +0 -0
  32. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Go.py +0 -0
  33. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Gradle.py +0 -0
  34. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Helm.py +0 -0
  35. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/Maven.py +0 -0
  36. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency/package_manager/__init__.py +0 -0
  37. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency.egg-info/dependency_links.txt +0 -0
  38. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency.egg-info/entry_points.txt +0 -0
  39. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency.egg-info/requires.txt +0 -0
  40. {fosslight_dependency-4.1.7 → fosslight_dependency-4.1.9}/src/fosslight_dependency.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fosslight_dependency
3
- Version: 4.1.7
3
+ Version: 4.1.9
4
4
  Summary: FOSSLight Dependency Scanner
5
5
  Home-page: https://github.com/fosslight/fosslight_dependency_scanner
6
6
  Author: LG Electronics
@@ -164,8 +164,8 @@ Description: <!--
164
164
  Platform: UNKNOWN
165
165
  Classifier: License :: OSI Approved :: Apache Software License
166
166
  Classifier: Programming Language :: Python :: 3
167
- Classifier: Programming Language :: Python :: 3.6
168
- Classifier: Programming Language :: Python :: 3.7
169
167
  Classifier: Programming Language :: Python :: 3.8
170
168
  Classifier: Programming Language :: Python :: 3.9
169
+ Classifier: Programming Language :: Python :: 3.10
170
+ Classifier: Programming Language :: Python :: 3.11
171
171
  Description-Content-Type: text/markdown
@@ -35,7 +35,7 @@ if __name__ == "__main__":
35
35
 
36
36
  setup(
37
37
  name=_PACKAEG_NAME,
38
- version='4.1.7',
38
+ version='4.1.9',
39
39
  package_dir={"": "src"},
40
40
  packages=find_namespace_packages(where='src'),
41
41
  description='FOSSLight Dependency Scanner',
@@ -47,15 +47,12 @@ if __name__ == "__main__":
47
47
  download_url='https://github.com/fosslight/fosslight_dependency_scanner',
48
48
  classifiers=['License :: OSI Approved :: Apache Software License',
49
49
  "Programming Language :: Python :: 3",
50
- "Programming Language :: Python :: 3.6",
51
- "Programming Language :: Python :: 3.7",
52
50
  "Programming Language :: Python :: 3.8",
53
- "Programming Language :: Python :: 3.9", ],
51
+ "Programming Language :: Python :: 3.9",
52
+ "Programming Language :: Python :: 3.10",
53
+ "Programming Language :: Python :: 3.11", ],
54
54
  install_requires=required,
55
- package_data={_PACKAEG_NAME: [os.path.join('third_party', 'nomos', 'nomossa'),
56
- os.path.join('third_party', 'askalono', 'askalono.exe'),
57
- os.path.join('third_party', 'askalono', 'askalono_macos'),
58
- os.path.join(_LICENSE_DIR, '*')]},
55
+ package_data={_PACKAEG_NAME: [os.path.join(_LICENSE_DIR, '*')]},
59
56
  include_package_data=True,
60
57
  entry_points={
61
58
  "console_scripts": [
@@ -20,6 +20,7 @@ from fosslight_dependency.package_manager.Nuget import Nuget
20
20
  from fosslight_dependency.package_manager.Helm import Helm
21
21
  from fosslight_dependency.package_manager.Unity import Unity
22
22
  from fosslight_dependency.package_manager.Cargo import Cargo
23
+ from fosslight_dependency.package_manager.Pnpm import Pnpm
23
24
  import fosslight_util.constant as constant
24
25
 
25
26
  logger = logging.getLogger(constant.LOGGER_NAME)
@@ -60,6 +61,8 @@ def analyze_dependency(package_manager_name, input_dir, output_dir, pip_activate
60
61
  package_manager = Unity(input_dir, output_dir)
61
62
  elif package_manager_name == const.CARGO:
62
63
  package_manager = Cargo(input_dir, output_dir)
64
+ elif package_manager_name == const.PNPM:
65
+ package_manager = Pnpm(input_dir, output_dir)
63
66
  else:
64
67
  logger.error(f"Not supported package manager name: {package_manager_name}")
65
68
  ret = False
@@ -84,7 +87,10 @@ def analyze_dependency(package_manager_name, input_dir, output_dir, pip_activate
84
87
  else:
85
88
  logger.error(f"Failed to open input file: {f_name}")
86
89
  ret = False
87
-
90
+ if package_manager_name == const.PNPM:
91
+ logger.info("Parse oss information for pnpm")
92
+ package_manager.parse_oss_information_for_pnpm()
93
+ package_dep_item_list.extend(package_manager.dep_items)
88
94
  if ret:
89
95
  logger.warning(f"### Complete to analyze: {package_manager_name}")
90
96
  if package_manager.cover_comment:
@@ -15,6 +15,7 @@ _HELP_MESSAGE_DEPENDENCY = """
15
15
  Gradle (Java)
16
16
  Maven (Java)
17
17
  NPM (Node.js)
18
+ PNPM (Node.js)
18
19
  PIP (Python)
19
20
  Pub (Dart with flutter)
20
21
  Cocoapods (Swift/Obj-C)
@@ -32,7 +33,7 @@ _HELP_MESSAGE_DEPENDENCY = """
32
33
  -v\t\t\t\t Print the version of the script.
33
34
  -m <package_manager>\t Enter the package manager.
34
35
  \t(npm, maven, gradle, pypi, pub, cocoapods, android, swift, carthage,
35
- \t go, nuget, helm, unity, cargo)
36
+ \t go, nuget, helm, unity, cargo, pnpm)
36
37
  -p <input_path>\t\t Enter the path where the script will be run.
37
38
  -e <exclude_path>\t\t Enter the path where the analysis will not be performed.
38
39
  -o <output_path>\t\t Output path
@@ -4,7 +4,6 @@
4
4
  # SPDX-License-Identifier: Apache-2.0
5
5
 
6
6
  import os
7
- import sys
8
7
  import logging
9
8
  import platform
10
9
  import re
@@ -12,9 +11,10 @@ import base64
12
11
  import subprocess
13
12
  import shutil
14
13
  import stat
14
+ from packageurl.contrib import url2purl
15
+ from askalono import identify
15
16
  import fosslight_util.constant as constant
16
17
  import fosslight_dependency.constant as const
17
- from packageurl.contrib import url2purl
18
18
 
19
19
  try:
20
20
  from github import Github
@@ -23,13 +23,9 @@ except Exception:
23
23
 
24
24
  logger = logging.getLogger(constant.LOGGER_NAME)
25
25
 
26
- # binary url to check license text
27
- _license_scanner_linux = os.path.join('third_party', 'nomos', 'nomossa')
28
- _license_scanner_macos = os.path.join('third_party', 'askalono', 'askalono_macos')
29
- _license_scanner_windows = os.path.join('third_party', 'askalono', 'askalono.exe')
30
-
31
26
  gradle_config = ['runtimeClasspath', 'runtime']
32
27
  android_config = ['releaseRuntimeClasspath']
28
+ ASKALONO_THRESHOLD = 0.7
33
29
 
34
30
 
35
31
  class PackageManager:
@@ -54,7 +50,6 @@ class PackageManager:
54
50
  self.dep_items = []
55
51
 
56
52
  self.platform = platform.system()
57
- self.license_scanner_bin = check_license_scanner(self.platform)
58
53
 
59
54
  def __del__(self):
60
55
  self.input_package_list_file = []
@@ -113,7 +108,7 @@ class PackageManager:
113
108
  cmd_gradle = "./gradlew"
114
109
  else:
115
110
  ret_task = False
116
- logger.warning('No gradlew file exists. (skip to find dependencies relationship.')
111
+ logger.warning('No gradlew file exists (Skip to find dependencies relationship.).')
117
112
  if ret_plugin:
118
113
  logger.warning('Also it cannot run android-dependency-scanning plugin.')
119
114
  if ret_task:
@@ -126,11 +121,10 @@ class PackageManager:
126
121
  self.parse_dependency_tree(ret)
127
122
  else:
128
123
  self.set_direct_dependencies(False)
129
- logger.warning("Failed to run allDeps task.")
124
+ logger.warning(f"Fail to run {cmd}")
130
125
  except Exception as e:
131
126
  self.set_direct_dependencies(False)
132
- logger.error(f'Fail to run {cmd}: {e}')
133
- logger.warning('It cannot print the direct/transitive dependencies relationship.')
127
+ logger.warning(f"Cannot print 'depends on' information. (fail {cmd}: {e})")
134
128
 
135
129
  if ret_plugin:
136
130
  cmd = f"{cmd_gradle} generateLicenseTxt"
@@ -157,6 +151,9 @@ class PackageManager:
157
151
  if os.path.isfile(module_gradle_backup):
158
152
  os.remove(module_build_gradle)
159
153
  shutil.move(module_gradle_backup, module_build_gradle)
154
+ if os.path.isfile(self.input_file_name):
155
+ logger.info(f'Found {self.input_file_name}, skip to run plugin.')
156
+ ret_task = True
160
157
  return ret_task
161
158
 
162
159
  def add_android_plugin_in_gradle(self, module_build_gradle):
@@ -316,9 +313,8 @@ def connect_github(github_token):
316
313
  return g
317
314
 
318
315
 
319
- def get_github_license(g, github_repo, platform, license_scanner_bin):
316
+ def get_github_license(g, github_repo):
320
317
  license_name = ''
321
- tmp_license_txt_file_name = 'tmp_license.txt'
322
318
 
323
319
  try:
324
320
  repository = g.get_repo(github_repo)
@@ -334,96 +330,26 @@ def get_github_license(g, github_repo, platform, license_scanner_bin):
334
330
  if license_name == "" or license_name == "NOASSERTION":
335
331
  try:
336
332
  license_txt_data = base64.b64decode(repository.get_license().content).decode('utf-8')
337
- tmp_license_txt = open(tmp_license_txt_file_name, 'w', encoding='utf-8')
338
- tmp_license_txt.write(license_txt_data)
339
- tmp_license_txt.close()
340
- license_name = check_and_run_license_scanner(platform, license_scanner_bin, tmp_license_txt_file_name)
333
+ license_name = check_license_name(license_txt_data)
341
334
  except Exception:
342
- logger.info("Cannot find the license name with license scanner binary.")
343
-
344
- if os.path.isfile(tmp_license_txt_file_name):
345
- os.remove(tmp_license_txt_file_name)
335
+ logger.info("Cannot find the license name with askalono.")
346
336
  except Exception:
347
337
  logger.info("Cannot find the license name with github api.")
348
338
 
349
339
  return license_name
350
340
 
351
341
 
352
- def check_license_scanner(platform):
353
- license_scanner_bin = ''
354
-
355
- if platform == const.LINUX:
356
- license_scanner = _license_scanner_linux
357
- elif platform == const.MACOS:
358
- license_scanner = _license_scanner_macos
359
- elif platform == const.WINDOWS:
360
- license_scanner = _license_scanner_windows
361
- else:
362
- logger.debug("Not supported OS to analyze license text with binary.")
363
-
364
- if license_scanner:
365
- try:
366
- base_path = sys._MEIPASS
367
- except Exception:
368
- base_path = os.path.dirname(__file__)
369
-
370
- data_path = os.path.join(base_path, license_scanner)
371
- license_scanner_bin = data_path
372
-
373
- return license_scanner_bin
374
-
375
-
376
- def check_and_run_license_scanner(platform, license_scanner_bin, file_dir):
342
+ def check_license_name(license_txt, is_filepath=False):
377
343
  license_name = ''
344
+ if is_filepath:
345
+ with open(license_txt, 'r', encoding='utf-8') as f:
346
+ license_content = f.read()
347
+ else:
348
+ license_content = license_txt
378
349
 
379
- if not license_scanner_bin:
380
- logger.error('Not supported OS for license scanner binary.')
381
-
382
- try:
383
- tmp_output_file_name = "tmp_license_scanner_output.txt"
384
-
385
- if file_dir == "UNKNOWN":
386
- license_name = ""
387
- else:
388
- if platform == const.LINUX:
389
- run_license_scanner = f"{license_scanner_bin} {file_dir} > {tmp_output_file_name}"
390
- elif platform == const.MACOS:
391
- run_license_scanner = f"{license_scanner_bin} identify {file_dir} > {tmp_output_file_name}"
392
- elif platform == const.WINDOWS:
393
- run_license_scanner = f"{license_scanner_bin} identify {file_dir} > {tmp_output_file_name}"
394
- else:
395
- run_license_scanner = ''
396
-
397
- if run_license_scanner is None:
398
- license_name = ""
399
- return license_name
400
- else:
401
- ret = subprocess.run(run_license_scanner, shell=True, stderr=subprocess.PIPE)
402
- if ret.returncode != 0 or ret.stderr:
403
- os.remove(tmp_output_file_name)
404
- return ""
405
-
406
- fp = open(tmp_output_file_name, "r", encoding='utf8')
407
- license_output = fp.read()
408
- fp.close()
409
-
410
- if platform == const.LINUX:
411
- license_output_re = re.findall(r'.*contains license\(s\)\s(.*)', license_output)
412
- else:
413
- license_output_re = re.findall(r"License:\s{1}(\S*)\s{1}", license_output)
414
-
415
- if len(license_output_re) == 1:
416
- license_name = license_output_re[0]
417
- if license_name == "No_license_found":
418
- license_name = ""
419
- else:
420
- license_name = ""
421
- os.remove(tmp_output_file_name)
422
-
423
- except Exception as ex:
424
- logger.error(f"Failed to run license scan binary. {ex}")
425
- license_name = ""
426
-
350
+ detect_askalono = identify(license_content)
351
+ if detect_askalono.score > ASKALONO_THRESHOLD:
352
+ license_name = detect_askalono.name
427
353
  return license_name
428
354
 
429
355
 
@@ -24,10 +24,12 @@ NUGET = 'nuget'
24
24
  HELM = 'helm'
25
25
  UNITY = 'unity'
26
26
  CARGO = 'cargo'
27
+ PNPM = 'pnpm'
27
28
 
28
29
  # Supported package name and manifest file
29
30
  SUPPORT_PACKAE = {
30
31
  PYPI: ['requirements.txt', 'setup.py', 'pyproject.toml'],
32
+ PNPM: 'pnpm-lock.yaml',
31
33
  NPM: 'package.json',
32
34
  MAVEN: 'pom.xml',
33
35
  GRADLE: 'build.gradle',
@@ -9,8 +9,8 @@ import os
9
9
  import fosslight_util.constant as constant
10
10
  import fosslight_dependency.constant as const
11
11
  from fosslight_dependency._package_manager import PackageManager
12
- from fosslight_dependency._package_manager import connect_github, get_github_license, check_and_run_license_scanner
13
- from fosslight_dependency._package_manager import get_url_to_purl
12
+ from fosslight_dependency._package_manager import connect_github, get_github_license
13
+ from fosslight_dependency._package_manager import get_url_to_purl, check_license_name
14
14
  from fosslight_dependency.dependency_item import DependencyItem
15
15
  from fosslight_util.oss_item import OssItem
16
16
 
@@ -79,9 +79,7 @@ class Carthage(PackageManager):
79
79
  for license_file_reg in license_file_regs:
80
80
  match_result = re.match(license_file_reg, filename_in_dir.lower())
81
81
  if match_result is not None:
82
- license_name = check_and_run_license_scanner(self.platform,
83
- self.license_scanner_bin,
84
- filename_with_checkout_path)
82
+ license_name = check_license_name(filename_with_checkout_path, True)
85
83
  find_license = True
86
84
  break
87
85
  if license_name == '':
@@ -89,7 +87,7 @@ class Carthage(PackageManager):
89
87
  try:
90
88
  if not g:
91
89
  g = connect_github(self.github_token)
92
- license_name = get_github_license(g, oss_path, self.platform, self.license_scanner_bin)
90
+ license_name = get_github_license(g, oss_path)
93
91
  except Exception as e:
94
92
  logger.warning(f"Failed to get license with github api: {e}")
95
93
  license_name == ''
@@ -46,7 +46,7 @@ class Npm(PackageManager):
46
46
  ret = True
47
47
  license_checker_cmd = f'license-checker --production --json --out {self.input_file_name}'
48
48
  custom_path_option = ' --customPath '
49
- npm_install_cmd = 'npm install --production'
49
+ npm_install_cmd = 'npm install --production --ignore-scripts'
50
50
 
51
51
  if os.path.isdir(node_modules) != 1:
52
52
  logger.info(f"node_modules directory is not existed. So it executes '{npm_install_cmd}'.")
@@ -12,7 +12,7 @@ import requests
12
12
  import fosslight_util.constant as constant
13
13
  import fosslight_dependency.constant as const
14
14
  from fosslight_dependency._package_manager import PackageManager
15
- from fosslight_dependency._package_manager import check_and_run_license_scanner, get_url_to_purl
15
+ from fosslight_dependency._package_manager import check_license_name, get_url_to_purl
16
16
  from fosslight_dependency.dependency_item import DependencyItem, change_dependson_to_purl
17
17
  from fosslight_util.oss_item import OssItem
18
18
 
@@ -54,7 +54,8 @@ class Nuget(PackageManager):
54
54
  oss_item.version = oss_version
55
55
 
56
56
  license_name = ''
57
- response = requests.get(f'{self.nuget_api_url}{oss_origin_name}/{oss_item.version}/{oss_origin_name}.nuspec')
57
+ response = requests.get(f'{self.nuget_api_url.lower()}{oss_origin_name.lower()}/ \
58
+ {oss_item.version.lower()}/{oss_origin_name.lower()}.nuspec')
58
59
  if response.status_code == 200:
59
60
  root = fromstring(response.text)
60
61
  xmlns = ''
@@ -73,14 +74,9 @@ class Nuget(PackageManager):
73
74
  if license_url is not None:
74
75
  url_res = requests.get(license_url.text)
75
76
  if url_res.status_code == 200:
76
- tmp_license_txt = open(tmp_license_txt_file_name, 'w', encoding='utf-8')
77
- tmp_license_txt.write(url_res.text)
78
- tmp_license_txt.close()
79
- license_name_with_license_scanner = check_and_run_license_scanner(self.platform,
80
- self.license_scanner_bin,
81
- tmp_license_txt_file_name)
82
- if license_name_with_license_scanner != "":
83
- license_name = license_name_with_license_scanner
77
+ license_name_with_scanner = check_license_name(url_res.text)
78
+ if license_name_with_scanner != "":
79
+ license_name = license_name_with_scanner
84
80
  else:
85
81
  license_name = license_url.text
86
82
  oss_item.license = license_name
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # Copyright (c) 2025 LG Electronics Inc.
4
+ # SPDX-License-Identifier: Apache-2.0
5
+
6
+ import os
7
+ import logging
8
+ import subprocess
9
+ import json
10
+ import shutil
11
+ import fosslight_util.constant as constant
12
+ import fosslight_dependency.constant as const
13
+ from fosslight_dependency._package_manager import PackageManager, get_url_to_purl
14
+ from fosslight_dependency.dependency_item import DependencyItem, change_dependson_to_purl
15
+ from fosslight_dependency.package_manager.Npm import check_multi_license
16
+ from fosslight_util.oss_item import OssItem
17
+
18
+ logger = logging.getLogger(constant.LOGGER_NAME)
19
+ node_modules = 'node_modules'
20
+
21
+
22
+ class Pnpm(PackageManager):
23
+ package_manager_name = const.PNPM
24
+
25
+ dn_url = 'https://www.npmjs.com/package/'
26
+ input_file_name = 'tmp_pnpm_license_output.json'
27
+ flag_tmp_node_modules = False
28
+ project_name_list = []
29
+ pkg_list = {}
30
+
31
+ def __init__(self, input_dir, output_dir):
32
+ super().__init__(self.package_manager_name, self.dn_url, input_dir, output_dir)
33
+
34
+ def __del__(self):
35
+ if os.path.isfile(self.input_file_name):
36
+ os.remove(self.input_file_name)
37
+ if self.flag_tmp_node_modules:
38
+ shutil.rmtree(node_modules, ignore_errors=True)
39
+
40
+ def run_plugin(self):
41
+ ret = True
42
+
43
+ pnpm_install_cmd = 'pnpm install --prod --ignore-scripts --ignore-pnpmfile'
44
+ if os.path.isdir(node_modules) != 1:
45
+ logger.info(f"node_modules directory is not existed. So it executes '{pnpm_install_cmd}'.")
46
+ self.flag_tmp_node_modules = True
47
+ cmd_ret = subprocess.call(pnpm_install_cmd, shell=True)
48
+ if cmd_ret != 0:
49
+ logger.error(f"{pnpm_install_cmd} returns an error")
50
+ ret = False
51
+ if ret:
52
+ project_cmd = 'pnpm ls -r --depth -1 -P --json'
53
+ ret_txt = subprocess.check_output(project_cmd, text=True, shell=True)
54
+ if ret_txt is not None:
55
+ deps_l = json.loads(ret_txt)
56
+ for items in deps_l:
57
+ self.project_name_list.append(items["name"])
58
+ return ret
59
+
60
+ def parse_direct_dependencies(self):
61
+ if not self.direct_dep:
62
+ return
63
+ try:
64
+ direct_cmd = 'pnpm ls -r --depth 0 -P --json'
65
+ ret_txt = subprocess.check_output(direct_cmd, text=True, shell=True)
66
+ if ret_txt is not None:
67
+ deps_l = json.loads(ret_txt)
68
+ for item in deps_l:
69
+ if 'dependencies' in item and isinstance(item['dependencies'], dict):
70
+ self.direct_dep_list.extend(item['dependencies'].keys())
71
+ else:
72
+ self.direct_dep = False
73
+ logger.warning('Cannot print direct/transitive dependency')
74
+ except Exception as e:
75
+ logger.warning(f'Fail to print direct/transitive dependency: {e}')
76
+ self.direct_dep = False
77
+ if self.direct_dep:
78
+ self.direct_dep_list = list(filter(lambda dep: dep not in self.project_name_list, self.direct_dep_list))
79
+
80
+ def extract_dependencies(self, dependencies, purl_dict):
81
+ dep_item_list = []
82
+ for dep_name, dep_info in dependencies.items():
83
+ if dep_name not in self.project_name_list:
84
+ if dep_name in self.pkg_list.keys():
85
+ if dep_info.get('version') in self.pkg_list[dep_name]:
86
+ continue
87
+ self.pkg_list.setdefault(dep_name, []).append(dep_info.get('version'))
88
+ dep_item = DependencyItem()
89
+ oss_item = OssItem()
90
+ oss_item.name = f'npm:{dep_name}'
91
+ oss_item.version = dep_info.get('version')
92
+
93
+ license_name = dep_info.get('license')
94
+ if license_name:
95
+ multi_license, license_comment, multi_flag = check_multi_license(license_name, '')
96
+ if multi_flag:
97
+ oss_item.comment = license_comment
98
+ license_name = multi_license
99
+ else:
100
+ license_name = license_name.replace(",", "")
101
+ oss_item.license = license_name
102
+
103
+ oss_item.homepage = f'{self.dn_url}{dep_name}'
104
+ oss_item.download_location = dep_info.get('repository')
105
+ if oss_item.download_location:
106
+ if oss_item.download_location.endswith('.git'):
107
+ oss_item.download_location = oss_item.download_location[:-4]
108
+ if oss_item.download_location.startswith('git://'):
109
+ oss_item.download_location = 'https://' + oss_item.download_location[6:]
110
+ elif oss_item.download_location.startswith('git+https://'):
111
+ oss_item.download_location = 'https://' + oss_item.download_location[12:]
112
+ elif oss_item.download_location.startswith('git+ssh://git@'):
113
+ oss_item.download_location = 'https://' + oss_item.download_location[14:]
114
+ else:
115
+ oss_item.download_location = f'{self.dn_url}{dep_name}/v/{oss_item.version}'
116
+
117
+ dn_loc = f'{oss_item.homepage}/v/{oss_item.version}'
118
+ dep_item.purl = get_url_to_purl(dn_loc, 'npm')
119
+ purl_dict[f'{dep_name}({oss_item.version})'] = dep_item.purl
120
+
121
+ if dep_name in self.direct_dep_list:
122
+ oss_item.comment = 'direct'
123
+ else:
124
+ oss_item.comment = 'transitive'
125
+
126
+ if 'dependencies' in dep_info:
127
+ for dn, di in dep_info.get('dependencies').items():
128
+ if dn not in self.project_name_list:
129
+ dep_item.depends_on_raw.append(f"{dn}({di['version']})")
130
+
131
+ dep_item.oss_items.append(oss_item)
132
+ dep_item_list.append(dep_item)
133
+
134
+ if 'dependencies' in dep_info:
135
+ dep_item_list_inner, purl_dict_inner = self.extract_dependencies(dep_info['dependencies'], purl_dict)
136
+ dep_item_list.extend(dep_item_list_inner)
137
+ purl_dict.update(purl_dict_inner)
138
+
139
+ return dep_item_list, purl_dict
140
+
141
+ def parse_oss_information_for_pnpm(self):
142
+ project_cmd = 'pnpm ls --json -r --depth Infinity -P --long'
143
+ ret_txt = subprocess.check_output(project_cmd, text=True, shell=True)
144
+ if ret_txt is not None:
145
+ deps_l = json.loads(ret_txt)
146
+ purl_dict = {}
147
+ for items in deps_l:
148
+ if 'dependencies' in items:
149
+ dep_item_list_inner, purl_dict_inner = self.extract_dependencies(items['dependencies'], purl_dict)
150
+ self.dep_items.extend(dep_item_list_inner)
151
+ purl_dict.update(purl_dict_inner)
152
+ if self.direct_dep:
153
+ self.dep_items = change_dependson_to_purl(purl_dict, self.dep_items)
154
+ else:
155
+ logger.warning(f'No output for {project_cmd}')
@@ -10,11 +10,10 @@ import re
10
10
  import shutil
11
11
  import yaml
12
12
  import subprocess
13
- from askalono import identify
14
13
  import fosslight_util.constant as constant
15
14
  import fosslight_dependency.constant as const
16
15
  from fosslight_dependency._package_manager import PackageManager
17
- from fosslight_dependency._package_manager import get_url_to_purl
16
+ from fosslight_dependency._package_manager import get_url_to_purl, check_license_name
18
17
  from fosslight_dependency.dependency_item import DependencyItem, change_dependson_to_purl
19
18
  from fosslight_util.oss_item import OssItem
20
19
 
@@ -135,9 +134,7 @@ class Pub(PackageManager):
135
134
  purl_dict[f'{oss_origin_name}({oss_item.version})'] = dep_item.purl
136
135
  license_txt = json_data['license']
137
136
  if license_txt is not None:
138
- detect_askalono = identify(license_txt)
139
- if detect_askalono.score > 0.7:
140
- oss_item.license = detect_askalono.name
137
+ oss_item.license = check_license_name(license_txt)
141
138
 
142
139
  if self.direct_dep:
143
140
  if oss_origin_name not in self.total_dep_list:
@@ -13,7 +13,7 @@ import re
13
13
  import fosslight_util.constant as constant
14
14
  import fosslight_dependency.constant as const
15
15
  from fosslight_dependency._package_manager import PackageManager
16
- from fosslight_dependency._package_manager import check_and_run_license_scanner, get_url_to_purl
16
+ from fosslight_dependency._package_manager import check_license_name, get_url_to_purl
17
17
  from fosslight_dependency.dependency_item import DependencyItem, change_dependson_to_purl
18
18
  from fosslight_util.oss_item import OssItem
19
19
 
@@ -111,7 +111,7 @@ class Pypi(PackageManager):
111
111
  install_cmd = cmd_separator.join(install_cmd_list)
112
112
  else:
113
113
  logger.error(const.SUPPORT_PACKAE[self.package_manager_name])
114
- logger.error('Cannot create virtualenv becuase it cannot find: '
114
+ logger.error('Cannot create virtualenv because it cannot find: '
115
115
  + ', '.join(const.SUPPORT_PACKAE[self.package_manager_name]))
116
116
  logger.error("Please run with '-a' and '-d' option.")
117
117
  return False
@@ -302,12 +302,7 @@ class Pypi(PackageManager):
302
302
  if license_name is not None:
303
303
  license_name = license_name.replace(';', ',')
304
304
  else:
305
- license_file_dir = d['LicenseFile']
306
- license_name_with_lic_scanner = check_and_run_license_scanner(self.platform,
307
- self.license_scanner_bin,
308
- license_file_dir)
309
- if license_name_with_lic_scanner != "":
310
- license_name = license_name_with_lic_scanner
305
+ license_name = check_license_name(d['LicenseFile'], True)
311
306
  oss_item.license = license_name
312
307
 
313
308
  if oss_init_name == self.package_name:
@@ -140,7 +140,7 @@ class Swift(PackageManager):
140
140
  github_repo = "/".join(oss_item.homepage.split('/')[-2:])
141
141
  dep_item.purl = get_url_to_purl(oss_item.download_location, self.package_manager_name, github_repo, oss_item.version)
142
142
  purl_dict[f'{oss_origin_name}({oss_item.version})'] = dep_item.purl
143
- oss_item.license = get_github_license(g, github_repo, self.platform, self.license_scanner_bin)
143
+ oss_item.license = get_github_license(g, github_repo)
144
144
 
145
145
  if self.direct_dep and len(self.direct_dep_list) > 0:
146
146
  if oss_origin_name in self.direct_dep_list:
@@ -11,13 +11,12 @@ import requests
11
11
  import fosslight_util.constant as constant
12
12
  import fosslight_dependency.constant as const
13
13
  from fosslight_dependency._package_manager import PackageManager
14
- from fosslight_dependency._package_manager import check_and_run_license_scanner, get_url_to_purl
14
+ from fosslight_dependency._package_manager import check_license_name, get_url_to_purl
15
15
  from fosslight_dependency.dependency_item import DependencyItem
16
16
  from fosslight_util.oss_item import OssItem
17
17
 
18
18
  logger = logging.getLogger(constant.LOGGER_NAME)
19
19
  proprietary_license = 'Proprietary License'
20
- unclassifed_license = 'UnclassifiedLicense'
21
20
  license_md = 'LICENSE.md'
22
21
  third_party_md = 'Third Party Notices.md'
23
22
 
@@ -50,10 +49,8 @@ class Unity(PackageManager):
50
49
  oss_packagecache_dir = os.path.join(self.packageCache_dir, f'{oss_item.name}@{oss_item.version}')
51
50
  license_f = os.path.join(oss_packagecache_dir, license_md)
52
51
  if os.path.isfile(license_f):
53
- license_name = check_and_run_license_scanner(self.platform,
54
- self.license_scanner_bin,
55
- license_f)
56
- if license_name == unclassifed_license or license_name == '':
52
+ license_name = check_license_name(license_f, True)
53
+ if license_name == '':
57
54
  with open(license_f, 'r', encoding='utf-8') as f:
58
55
  for line in f:
59
56
  matched_l = re.search(r'Unity\s[\s\w]*\sLicense', line)
@@ -51,17 +51,17 @@ def paginate_file(file_path):
51
51
  input("Press Enter to see the next page...")
52
52
 
53
53
 
54
- def find_package_manager(input_dir, abs_path_to_exclude=[]):
54
+ def find_package_manager(input_dir, abs_path_to_exclude=[], manifest_file_name=[]):
55
55
  ret = True
56
- manifest_file_name = []
57
- for value in const.SUPPORT_PACKAE.values():
58
- if isinstance(value, list):
59
- manifest_file_name.extend(value)
60
- else:
61
- manifest_file_name.append(value)
56
+ if not manifest_file_name:
57
+ for value in const.SUPPORT_PACKAE.values():
58
+ if isinstance(value, list):
59
+ manifest_file_name.extend(value)
60
+ else:
61
+ manifest_file_name.append(value)
62
62
 
63
63
  found_manifest_file = []
64
- for (parent, _, files) in os.walk(input_dir):
64
+ for parent, dirs, files in os.walk(input_dir):
65
65
  if len(files) < 1:
66
66
  continue
67
67
  if os.path.basename(parent) in _exclude_dir:
@@ -76,6 +76,13 @@ def find_package_manager(input_dir, abs_path_to_exclude=[]):
76
76
  continue
77
77
  if file in manifest_file_name:
78
78
  found_manifest_file.append(file)
79
+ for dir in dirs:
80
+ for manifest_f in manifest_file_name:
81
+ manifest_l = manifest_f.split(os.path.sep)
82
+ if len(manifest_l) > 1:
83
+ if manifest_l[0] == dir:
84
+ if os.path.exists(os.path.join(parent, manifest_f)):
85
+ found_manifest_file.append(manifest_f)
79
86
  if len(found_manifest_file) > 0:
80
87
  input_dir = parent
81
88
  break
@@ -93,13 +100,16 @@ def find_package_manager(input_dir, abs_path_to_exclude=[]):
93
100
  if value == f_idx:
94
101
  found_package_manager[key] = [f_idx]
95
102
 
103
+ # both npm and pnpm are detected, remove npm.
104
+ if 'npm' in found_package_manager and 'pnpm' in found_package_manager:
105
+ del found_package_manager['npm']
96
106
  if len(found_package_manager) >= 1:
97
- manifest_file_w_path = map(lambda x: os.path.join(input_dir, x), found_manifest_file)
107
+ manifest_file_w_path = [os.path.join(input_dir, file) for pkg, files in found_package_manager.items() for file in files]
98
108
  logger.info(f"Found the manifest file({','.join(manifest_file_w_path)}) automatically.")
99
109
  logger.warning(f"### Set Package Manager = {', '.join(found_package_manager.keys())}")
100
110
  else:
101
111
  ret = False
102
- logger.info("It cannot find the manifest file.")
112
+ logger.info("Cannot find the manifest file.")
103
113
 
104
114
  return ret, found_package_manager, input_dir
105
115
 
@@ -168,17 +178,6 @@ def run_dependency_scanner(package_manager='', input_dir='', output_dir_file='',
168
178
  logger.error(msg)
169
179
  return False, scan_item
170
180
 
171
- autodetect = True
172
- if package_manager:
173
- autodetect = False
174
- support_packagemanager = list(const.SUPPORT_PACKAE.keys())
175
-
176
- if package_manager not in support_packagemanager:
177
- logger.error(f"(-m option) You entered the unsupported package manager({package_manager}).")
178
- logger.error("Please enter the supported package manager({0}) with '-m' option."
179
- .format(", ".join(support_packagemanager)))
180
- return False, scan_item
181
-
182
181
  if input_dir:
183
182
  if os.path.isdir(input_dir):
184
183
  os.chdir(input_dir)
@@ -192,20 +191,44 @@ def run_dependency_scanner(package_manager='', input_dir='', output_dir_file='',
192
191
  os.chdir(input_dir)
193
192
  scan_item.set_cover_pathinfo(input_dir, path_to_exclude)
194
193
 
194
+ autodetect = True
195
195
  found_package_manager = {}
196
- if autodetect:
197
- try:
198
- ret, found_package_manager, input_dir = find_package_manager(input_dir, abs_path_to_exclude)
196
+ if package_manager:
197
+ autodetect = False
198
+ support_packagemanager = list(const.SUPPORT_PACKAE.keys())
199
+
200
+ if package_manager not in support_packagemanager:
201
+ logger.error(f"(-m option) You entered the unsupported package manager({package_manager}).")
202
+ logger.error("Please enter the supported package manager({0}) with '-m' option."
203
+ .format(", ".join(support_packagemanager)))
204
+ return False, scan_item
205
+ manifest_file_name = []
206
+ value = const.SUPPORT_PACKAE[package_manager]
207
+ if isinstance(value, list):
208
+ manifest_file_name.extend(value)
209
+ else:
210
+ manifest_file_name.append(value)
211
+ scan_item.set_cover_comment(f"Manual detect mode (-m {package_manager})")
212
+ else:
213
+ manifest_file_name = []
214
+
215
+ try:
216
+ ret, found_package_manager, input_dir = find_package_manager(input_dir, abs_path_to_exclude, manifest_file_name)
217
+ if ret:
199
218
  os.chdir(input_dir)
200
- except Exception as e:
219
+ except Exception as e:
220
+ if autodetect:
201
221
  logger.error(f'Fail to find package manager: {e}')
202
222
  ret = False
203
- finally:
204
- if not ret:
205
- logger.warning("Dependency scanning terminated because the package manager was not found.")
223
+ finally:
224
+ if not ret:
225
+ if not autodetect:
226
+ logger.info('Try to analyze dependency without manifest file. (Manual mode)')
227
+ found_package_manager[package_manager] = []
228
+ else:
229
+ logger.error("Terminated: package manager could not be found.")
206
230
  ret = False
207
- else:
208
- found_package_manager[package_manager] = ["manual detect ('-m option')"]
231
+ return False, scan_item
209
232
 
210
233
  pass_key = 'PASS'
211
234
  success_pm = []
@@ -242,7 +265,8 @@ def run_dependency_scanner(package_manager='', input_dir='', output_dir_file='',
242
265
  'and https://fosslight.org/fosslight-guide-en/scanner/3_dependency.html#-prerequisite.'
243
266
  scan_item.set_cover_comment(f"Analysis failed Package manager: {', '.join(fail_pm)} ({info_msg})")
244
267
  else:
245
- scan_item.set_cover_comment("No Package manager detected.")
268
+ if autodetect:
269
+ scan_item.set_cover_comment("No Package manager detected.")
246
270
 
247
271
  if ret and graph_path:
248
272
  graph_path = os.path.abspath(graph_path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fosslight-dependency
3
- Version: 4.1.7
3
+ Version: 4.1.9
4
4
  Summary: FOSSLight Dependency Scanner
5
5
  Home-page: https://github.com/fosslight/fosslight_dependency_scanner
6
6
  Author: LG Electronics
@@ -164,8 +164,8 @@ Description: <!--
164
164
  Platform: UNKNOWN
165
165
  Classifier: License :: OSI Approved :: Apache Software License
166
166
  Classifier: Programming Language :: Python :: 3
167
- Classifier: Programming Language :: Python :: 3.6
168
- Classifier: Programming Language :: Python :: 3.7
169
167
  Classifier: Programming Language :: Python :: 3.8
170
168
  Classifier: Programming Language :: Python :: 3.9
169
+ Classifier: Programming Language :: Python :: 3.10
170
+ Classifier: Programming Language :: Python :: 3.11
171
171
  Description-Content-Type: text/markdown
@@ -31,6 +31,7 @@ src/fosslight_dependency/package_manager/Helm.py
31
31
  src/fosslight_dependency/package_manager/Maven.py
32
32
  src/fosslight_dependency/package_manager/Npm.py
33
33
  src/fosslight_dependency/package_manager/Nuget.py
34
+ src/fosslight_dependency/package_manager/Pnpm.py
34
35
  src/fosslight_dependency/package_manager/Pub.py
35
36
  src/fosslight_dependency/package_manager/Pypi.py
36
37
  src/fosslight_dependency/package_manager/Swift.py