fosslight-dependency 3.0.7__py3-none-any.whl → 4.1.30__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.
Files changed (46) hide show
  1. fosslight_dependency/LICENSES/LICENSE +201 -0
  2. fosslight_dependency/LICENSES/LicenseRef-3rd_party_licenses.txt +1254 -0
  3. fosslight_dependency/__init__.py +0 -1
  4. fosslight_dependency/_analyze_dependency.py +130 -0
  5. fosslight_dependency/_graph_convertor.py +67 -0
  6. fosslight_dependency/_help.py +79 -0
  7. fosslight_dependency/_package_manager.py +397 -0
  8. fosslight_dependency/cli.py +127 -0
  9. fosslight_dependency/constant.py +57 -0
  10. fosslight_dependency/dependency_item.py +103 -0
  11. fosslight_dependency/package_manager/Android.py +90 -0
  12. fosslight_dependency/package_manager/Cargo.py +144 -0
  13. fosslight_dependency/package_manager/Carthage.py +130 -0
  14. fosslight_dependency/package_manager/Cocoapods.py +194 -0
  15. fosslight_dependency/package_manager/Go.py +179 -0
  16. fosslight_dependency/package_manager/Gradle.py +123 -0
  17. fosslight_dependency/package_manager/Helm.py +106 -0
  18. fosslight_dependency/package_manager/Maven.py +274 -0
  19. fosslight_dependency/package_manager/Npm.py +296 -0
  20. fosslight_dependency/package_manager/Nuget.py +368 -0
  21. fosslight_dependency/package_manager/Pnpm.py +155 -0
  22. fosslight_dependency/package_manager/Pub.py +241 -0
  23. fosslight_dependency/package_manager/Pypi.py +395 -0
  24. fosslight_dependency/package_manager/Swift.py +159 -0
  25. fosslight_dependency/package_manager/Unity.py +118 -0
  26. fosslight_dependency/package_manager/Yarn.py +231 -0
  27. fosslight_dependency/package_manager/__init__.py +0 -0
  28. fosslight_dependency/run_dependency_scanner.py +393 -0
  29. fosslight_dependency-4.1.30.dist-info/METADATA +213 -0
  30. fosslight_dependency-4.1.30.dist-info/RECORD +37 -0
  31. {fosslight_dependency-3.0.7.dist-info → fosslight_dependency-4.1.30.dist-info}/WHEEL +1 -1
  32. fosslight_dependency-4.1.30.dist-info/entry_points.txt +2 -0
  33. fosslight_dependency-4.1.30.dist-info/licenses/LICENSES/Apache-2.0.txt +201 -0
  34. fosslight_dependency-4.1.30.dist-info/licenses/LICENSES/LicenseRef-3rd_party_licenses.txt +1254 -0
  35. fosslight_dependency-4.1.30.dist-info/licenses/LICENSES/MIT.txt +21 -0
  36. fosslight_dependency/_version.py +0 -1
  37. fosslight_dependency/analyze_dependency.py +0 -1090
  38. fosslight_dependency/third_party/askalono/askalono.exe +0 -0
  39. fosslight_dependency/third_party/askalono/askalono_macos +0 -0
  40. fosslight_dependency/third_party/nomos/nomossa +0 -0
  41. fosslight_dependency-3.0.7.dist-info/3rd_party_licenses.txt +0 -726
  42. fosslight_dependency-3.0.7.dist-info/METADATA +0 -51
  43. fosslight_dependency-3.0.7.dist-info/RECORD +0 -13
  44. fosslight_dependency-3.0.7.dist-info/entry_points.txt +0 -3
  45. {fosslight_dependency-3.0.7.dist-info → fosslight_dependency-4.1.30.dist-info/licenses}/LICENSE +0 -0
  46. {fosslight_dependency-3.0.7.dist-info → fosslight_dependency-4.1.30.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # Copyright (c) 2021 LG Electronics Inc.
4
+ # SPDX-License-Identifier: Apache-2.0
5
+
6
+ import os
7
+ import logging
8
+ import json
9
+ import subprocess
10
+ import fosslight_util.constant as constant
11
+ import fosslight_dependency.constant as const
12
+ from fosslight_dependency._package_manager import PackageManager
13
+ from fosslight_dependency._package_manager import connect_github, get_github_license
14
+ from fosslight_dependency._package_manager import get_url_to_purl
15
+ from fosslight_dependency.dependency_item import DependencyItem, change_dependson_to_purl
16
+ from fosslight_util.oss_item import OssItem
17
+
18
+ logger = logging.getLogger(constant.LOGGER_NAME)
19
+
20
+
21
+ class Swift(PackageManager):
22
+ package_manager_name = const.SWIFT
23
+
24
+ input_file_name = const.SUPPORT_PACKAE.get(package_manager_name)
25
+ tmp_dep_tree_fname = 'show-dep.json'
26
+
27
+ def __init__(self, input_dir, output_dir, github_token):
28
+ super().__init__(self.package_manager_name, '', input_dir, output_dir)
29
+ self.github_token = github_token
30
+
31
+ self.check_input_file_path()
32
+ self.append_input_package_list_file(self.input_file_name)
33
+
34
+ def check_input_file_path(self):
35
+ if not os.path.isfile(self.input_file_name):
36
+ for file_in_swift in os.listdir("."):
37
+ if file_in_swift.endswith(".xcodeproj"):
38
+ input_file_name_in_xcodeproj = os.path.join(file_in_swift,
39
+ "project.xcworkspace/xcshareddata/swiftpm",
40
+ self.input_file_name)
41
+ if input_file_name_in_xcodeproj != self.input_file_name:
42
+ if os.path.isfile(input_file_name_in_xcodeproj):
43
+ self.input_file_name = input_file_name_in_xcodeproj
44
+ logger.info(f"It uses the manifest file: {self.input_file_name}")
45
+
46
+ def parse_direct_dependencies(self):
47
+ ret = False
48
+ if os.path.isfile('Package.swift') or os.path.isfile(self.tmp_dep_tree_fname):
49
+ if not os.path.isfile(self.tmp_dep_tree_fname):
50
+ cmd = "swift package show-dependencies --format json"
51
+ try:
52
+ ret_txt = subprocess.check_output(cmd, text=True, shell=True)
53
+ if ret_txt is not None:
54
+ deps_l = json.loads(ret_txt)
55
+ ret = self.parse_dep_tree_json(deps_l)
56
+ except Exception as e:
57
+ logger.warning(f'Fail to get swift dependency tree information: {e}')
58
+ else:
59
+ with open(self.tmp_dep_tree_fname) as f:
60
+ try:
61
+ deps_l = json.load(f)
62
+ ret = self.parse_dep_tree_json(deps_l)
63
+ except Exception as e:
64
+ logger.warning(f'Fail to load swift dependency tree json: {e}')
65
+ else:
66
+ logger.info(f"No Package.swift or {self.tmp_dep_tree_fname}, skip to print direct/transitive.")
67
+ if not ret:
68
+ self.direct_dep = False
69
+
70
+ def get_dependencies(self, dependencies, package):
71
+ package_name = 'name'
72
+ deps = 'dependencies'
73
+ version = 'version'
74
+
75
+ pkg_name = package[package_name]
76
+ pkg_ver = package[version]
77
+ dependency_list = package[deps]
78
+ dependencies[f"{pkg_name}({pkg_ver})"] = []
79
+ for dependency in dependency_list:
80
+ dep_name = dependency[package_name]
81
+ dep_version = dependency[version]
82
+ dependencies[f"{pkg_name}({pkg_ver})"].append(f"{dep_name}({dep_version})")
83
+ if dependency[deps] != []:
84
+ dependencies = self.get_dependencies(dependencies, dependency)
85
+ return dependencies
86
+
87
+ def parse_dep_tree_json(self, rel_json):
88
+ ret = True
89
+ try:
90
+ for p in rel_json['dependencies']:
91
+ self.direct_dep_list.append(p['name'])
92
+ if p['dependencies'] == []:
93
+ continue
94
+ self.relation_tree = self.get_dependencies(self.relation_tree, p)
95
+ except Exception as e:
96
+ logger.error(f'Failed to parse dependency tree: {e}')
97
+ ret = False
98
+ return ret
99
+
100
+ def parse_oss_information(self, f_name):
101
+ json_ver = 2
102
+ purl_dict = {}
103
+
104
+ with open(f_name, 'r', encoding='utf8') as json_file:
105
+ json_raw = json.load(json_file)
106
+ json_ver = json_raw['version']
107
+
108
+ if json_ver == 1:
109
+ json_data = json_raw["object"]["pins"]
110
+ elif json_ver == 2 or json_ver == 3:
111
+ json_data = json_raw["pins"]
112
+ else:
113
+ logger.warning(f'Not supported Package.resolved version {json_ver}')
114
+ logger.warning('Try to parse as version 2(or 3)')
115
+ json_data = json_raw["pins"]
116
+
117
+ g = connect_github(self.github_token)
118
+
119
+ for key in json_data:
120
+ dep_item = DependencyItem()
121
+ oss_item = OssItem()
122
+ if json_ver == 1:
123
+ oss_origin_name = key['package']
124
+ oss_item.homepage = key['repositoryURL']
125
+ else:
126
+ oss_origin_name = key['identity']
127
+ oss_item.homepage = key['location']
128
+
129
+ if oss_item.homepage.endswith('.git'):
130
+ oss_item.homepage = oss_item.homepage[:-4]
131
+
132
+ oss_item.name = f"{self.package_manager_name}:{oss_origin_name}"
133
+
134
+ oss_item.version = key['state'].get('version', None)
135
+ if oss_item.version is None:
136
+ oss_item.version = key['state'].get('revision', None)
137
+
138
+ oss_item.download_location = oss_item.homepage
139
+
140
+ github_repo = "/".join(oss_item.homepage.split('/')[-2:])
141
+ dep_item.purl = get_url_to_purl(oss_item.download_location, self.package_manager_name, github_repo, oss_item.version)
142
+ purl_dict[f'{oss_origin_name}({oss_item.version})'] = dep_item.purl
143
+ oss_item.license = get_github_license(g, github_repo)
144
+
145
+ if self.direct_dep and len(self.direct_dep_list) > 0:
146
+ if oss_origin_name in self.direct_dep_list:
147
+ oss_item.comment = 'direct'
148
+ else:
149
+ oss_item.comment = 'transitive'
150
+ if f'{oss_origin_name}({oss_item.version})' in self.relation_tree:
151
+ dep_item.depends_on_raw = self.relation_tree[f'{oss_origin_name}({oss_item.version})']
152
+
153
+ dep_item.oss_items.append(oss_item)
154
+ self.dep_items.append(dep_item)
155
+
156
+ if self.direct_dep:
157
+ self.dep_items = change_dependson_to_purl(purl_dict, self.dep_items)
158
+
159
+ return
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # Copyright (c) 2024 LG Electronics Inc.
4
+ # SPDX-License-Identifier: Apache-2.0
5
+
6
+ import os
7
+ import logging
8
+ import re
9
+ import yaml
10
+ import requests
11
+ import fosslight_util.constant as constant
12
+ import fosslight_dependency.constant as const
13
+ from fosslight_dependency._package_manager import PackageManager
14
+ from fosslight_dependency._package_manager import check_license_name, get_url_to_purl
15
+ from fosslight_dependency.dependency_item import DependencyItem
16
+ from fosslight_util.oss_item import OssItem
17
+
18
+ logger = logging.getLogger(constant.LOGGER_NAME)
19
+ proprietary_license = 'Proprietary License'
20
+ license_md = 'LICENSE.md'
21
+ third_party_md = 'Third Party Notices.md'
22
+
23
+
24
+ class Unity(PackageManager):
25
+ package_manager_name = const.UNITY
26
+
27
+ input_file_name = const.SUPPORT_PACKAE.get(package_manager_name)
28
+ packageCache_dir = os.path.join('Library', 'PackageCache')
29
+ mirror_url = 'https://github.com/needle-mirror/'
30
+ unity_internal_url = 'https://github.cds.internal.unity3d.com'
31
+ third_notice_txt = 'third_party_notice.txt'
32
+
33
+ def __init__(self, input_dir, output_dir):
34
+ super().__init__(self.package_manager_name, '', input_dir, output_dir)
35
+ self.append_input_package_list_file(self.input_file_name)
36
+
37
+ def parse_oss_information(self, f_name):
38
+ with open(f_name, 'r', encoding='utf8') as f:
39
+ f_yml = yaml.safe_load(f)
40
+ resolvedPkg = f_yml['m_ResolvedPackages']
41
+
42
+ try:
43
+ for pkg_data in resolvedPkg:
44
+ dep_item = DependencyItem()
45
+ oss_item = OssItem()
46
+ oss_item.name = pkg_data['name']
47
+ oss_item.version = pkg_data['version']
48
+
49
+ oss_packagecache_dir = os.path.join(self.packageCache_dir, f'{oss_item.name}@{oss_item.version}')
50
+ license_f = os.path.join(oss_packagecache_dir, license_md)
51
+ if os.path.isfile(license_f):
52
+ license_name = check_license_name(license_f, True)
53
+ if license_name == '':
54
+ with open(license_f, 'r', encoding='utf-8') as f:
55
+ for line in f:
56
+ matched_l = re.search(r'Unity\s[\s\w]*\sLicense', line)
57
+ if matched_l:
58
+ license_name = matched_l[0]
59
+ break
60
+ else:
61
+ license_name = proprietary_license
62
+ oss_item.license = license_name
63
+
64
+ third_f = os.path.join(oss_packagecache_dir, third_party_md)
65
+ if os.path.isfile(third_f):
66
+ with open(third_f, 'r', encoding='utf-8') as f:
67
+ third_notice = f.readlines()
68
+ with open(self.third_notice_txt, 'a+', encoding='utf-8') as tf:
69
+ for line in third_notice:
70
+ tf.write(line)
71
+ tf.flush()
72
+
73
+ oss_item.homepage = pkg_data['repository']['url']
74
+ if oss_item.homepage and oss_item.homepage.startswith('git@'):
75
+ oss_item.homepage = oss_item.homepage.replace('git@', 'https://')
76
+ if oss_item.homepage is None or oss_item.homepage.startswith(self.unity_internal_url):
77
+ if (license_name != proprietary_license) and license_name != '':
78
+ oss_item.homepage = f'{self.mirror_url}{oss_item.name}'
79
+ if oss_item.homepage is None:
80
+ oss_item.homepage = ''
81
+ else:
82
+ if not check_url_alive(oss_item.homepage):
83
+ minor_version = '.'.join(oss_item.version.split('.')[0:2])
84
+ oss_item.homepage = f'https://docs.unity3d.com/Packages/{oss_item.name}@{minor_version}'
85
+ oss_item.download_location = oss_item.homepage
86
+ dep_item.purl = get_url_to_purl(oss_item.download_location, self.package_manager_name)
87
+ if dep_item.purl == 'None':
88
+ dep_item.purl = ''
89
+ if dep_item.purl != '':
90
+ dep_item.purl = f'{dep_item.purl}@{oss_item.version}'
91
+
92
+ comment_list = []
93
+ if self.direct_dep:
94
+ if pkg_data['isDirectDependency']:
95
+ comment_list.append('direct')
96
+ else:
97
+ comment_list.append('transitive')
98
+
99
+ oss_item.comment = ','.join(comment_list)
100
+ dep_item.oss_items.append(oss_item)
101
+ self.dep_items.append(dep_item)
102
+ except Exception as e:
103
+ logger.error(f"Fail to parse unity oss information: {e}")
104
+
105
+ return
106
+
107
+
108
+ def check_url_alive(url):
109
+ alive = False
110
+ try:
111
+ response = requests.get(url)
112
+ if response.status_code == 200:
113
+ alive = True
114
+ else:
115
+ logger.debug(f"{url} returned status code {response.status_code}")
116
+ except requests.exceptions.RequestException as e:
117
+ logger.debug(f"Check if url({url})is alive err: {e}")
118
+ return alive
@@ -0,0 +1,231 @@
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 fosslight_util.constant as constant
11
+ import fosslight_dependency.constant as const
12
+ from fosslight_dependency.package_manager.Npm import Npm
13
+ from fosslight_dependency.dependency_item import DependencyItem, change_dependson_to_purl
14
+ from fosslight_util.oss_item import OssItem
15
+ from fosslight_dependency._package_manager import get_url_to_purl
16
+ from fosslight_dependency.package_manager.Npm import check_multi_license, check_unknown_license
17
+
18
+ logger = logging.getLogger(constant.LOGGER_NAME)
19
+
20
+
21
+ class Yarn(Npm):
22
+
23
+ def __init__(self, input_dir, output_dir):
24
+ super().__init__(input_dir, output_dir)
25
+ self.package_manager_name = const.YARN
26
+ self.yarn_version = None
27
+
28
+ def detect_yarn_version(self):
29
+ """Detect Yarn version (1.x = Classic, 2+ = Berry)"""
30
+ if self.yarn_version is not None:
31
+ return self.yarn_version
32
+
33
+ try:
34
+ result = subprocess.run('yarn -v', shell=True, capture_output=True, text=True, encoding='utf-8')
35
+ if result.returncode == 0:
36
+ version_str = result.stdout.strip()
37
+ major_version = int(version_str.split('.')[0])
38
+ self.yarn_version = major_version
39
+ logger.info(f"Detected Yarn version: {version_str} (major: {major_version})")
40
+ return major_version
41
+ except Exception as e:
42
+ logger.warning(f"Failed to detect Yarn version: {e}")
43
+ return None
44
+
45
+ def start_license_checker(self):
46
+ ret = True
47
+ license_checker_cmd = f'license-checker --production --json --out {self.input_file_name}'
48
+ custom_path_option = ' --customPath '
49
+ node_modules = 'node_modules'
50
+
51
+ self.detect_yarn_version()
52
+
53
+ # For Yarn Berry (2+), check if using PnP mode
54
+ is_pnp_mode = False
55
+ if self.yarn_version and self.yarn_version >= 2:
56
+ # Check if .pnp.cjs exists (PnP mode indicator)
57
+ if os.path.exists('.pnp.cjs') or os.path.exists('.pnp.js'):
58
+ is_pnp_mode = True
59
+ logger.info("Detected Yarn Berry with PnP mode")
60
+
61
+ if not os.path.isdir(node_modules):
62
+ logger.info("node_modules directory does not exist.")
63
+ self.flag_tmp_node_modules = True
64
+
65
+ # For PnP mode, try to force node_modules creation
66
+ if is_pnp_mode:
67
+ logger.info("Attempting to create node_modules for PnP project...")
68
+ yarn_install_cmd = 'YARN_NODE_LINKER=node-modules yarn install --production --ignore-scripts'
69
+ logger.info(f"Executing: {yarn_install_cmd}")
70
+ else:
71
+ yarn_install_cmd = 'yarn install --production --ignore-scripts'
72
+ logger.info(f"Executing: {yarn_install_cmd}")
73
+
74
+ cmd_ret = subprocess.call(yarn_install_cmd, shell=True)
75
+ if cmd_ret != 0:
76
+ logger.error(f"{yarn_install_cmd} failed")
77
+ if is_pnp_mode:
78
+ logger.error("Yarn Berry PnP mode detected. Consider setting 'nodeLinker: node-modules' in .yarnrc.yml")
79
+ return False
80
+ else:
81
+ logger.info(f"Successfully executed {yarn_install_cmd}")
82
+
83
+ self.make_custom_json(self.tmp_custom_json)
84
+
85
+ cmd = license_checker_cmd + custom_path_option + self.tmp_custom_json
86
+ cmd_ret = subprocess.call(cmd, shell=True)
87
+ if cmd_ret != 0:
88
+ logger.error(f"It returns the error: {cmd}")
89
+ logger.error("Please check if the license-checker is installed.(sudo npm install -g license-checker)")
90
+ ret = False
91
+ else:
92
+ self.append_input_package_list_file(self.input_file_name)
93
+ if os.path.exists(self.tmp_custom_json):
94
+ os.remove(self.tmp_custom_json)
95
+
96
+ return ret
97
+
98
+ def parse_oss_information(self, f_name):
99
+ with open(f_name, 'r', encoding='utf8') as json_file:
100
+ json_data = json.load(json_file)
101
+
102
+ _licenses = 'licenses'
103
+ _repository = 'repository'
104
+ _private = 'private'
105
+
106
+ keys = [key for key in json_data]
107
+ purl_dict = {}
108
+ for i in range(0, len(keys)):
109
+ dep_item = DependencyItem()
110
+ oss_item = OssItem()
111
+ d = json_data.get(keys[i - 1])
112
+ oss_init_name = d['name']
113
+ oss_item.name = f'{const.NPM}:{oss_init_name}'
114
+
115
+ if d[_licenses]:
116
+ license_name = d[_licenses]
117
+ else:
118
+ license_name = ''
119
+
120
+ oss_item.version = d['version']
121
+ package_path = d['path']
122
+
123
+ private_pkg = False
124
+ if _private in d and d[_private]:
125
+ private_pkg = True
126
+
127
+ oss_item.download_location = ''
128
+
129
+ npm_dl_url = f"{self.dn_url}{oss_init_name}/v/{oss_item.version}"
130
+ npm_home_url = f"{self.dn_url}{oss_init_name}"
131
+ dep_item.purl = get_url_to_purl(npm_dl_url, self.package_manager_name)
132
+ purl_dict[f'{oss_init_name}({oss_item.version})'] = dep_item.purl
133
+
134
+ repo_url = d[_repository] if d[_repository] else ''
135
+ if private_pkg:
136
+ oss_item.homepage = repo_url or ''
137
+ oss_item.download_location = oss_item.homepage
138
+ oss_item.comment = 'private'
139
+ else:
140
+ npm_url_exists = False
141
+ if self._network_available is True:
142
+ npm_url_exists = self._npm_url_exists(oss_init_name, oss_item.version)
143
+
144
+ if self._network_available and not npm_url_exists:
145
+ oss_item.homepage = repo_url or ""
146
+ oss_item.download_location = oss_item.homepage
147
+ else:
148
+ oss_item.homepage = repo_url or npm_home_url
149
+ oss_item.download_location = npm_dl_url
150
+
151
+ if self.package_name == f'{oss_init_name}({oss_item.version})':
152
+ oss_item.comment = 'root package'
153
+ elif self.direct_dep and len(self.relation_tree) > 0:
154
+ if f'{oss_init_name}({oss_item.version})' in self.relation_tree[self.package_name]:
155
+ oss_item.comment = 'direct'
156
+ else:
157
+ oss_item.comment = 'transitive'
158
+
159
+ if f'{oss_init_name}({oss_item.version})' in self.relation_tree:
160
+ dep_item.depends_on_raw = self.relation_tree[f'{oss_init_name}({oss_item.version})']
161
+
162
+ # For Yarn, use 'package.json' instead of yarn.lock for license info
163
+ manifest_file_path = os.path.join(package_path, 'package.json')
164
+ multi_license, license_comment, multi_flag = check_multi_license(license_name, manifest_file_path)
165
+
166
+ if multi_flag:
167
+ oss_item.comment = license_comment
168
+ license_name = multi_license
169
+ else:
170
+ license_name = license_name.replace(",", "")
171
+ license_name = check_unknown_license(license_name, manifest_file_path)
172
+ oss_item.license = license_name
173
+
174
+ dep_item.oss_items.append(oss_item)
175
+ self.dep_items.append(dep_item)
176
+
177
+ if self.direct_dep:
178
+ self.dep_items = change_dependson_to_purl(purl_dict, self.dep_items)
179
+ return
180
+
181
+ def parse_rel_dependencies(self, rel_name, rel_ver, rel_dependencies):
182
+ """Override to handle missing packages and packages without version"""
183
+ _dependencies = 'dependencies'
184
+ _version = 'version'
185
+ _peer = 'peerMissing'
186
+ _missing = 'missing'
187
+
188
+ for rel_dep_name in rel_dependencies.keys():
189
+ # Optional, non-installed dependencies are listed as empty objects
190
+ if rel_dependencies[rel_dep_name] == {}:
191
+ continue
192
+ if _peer in rel_dependencies[rel_dep_name]:
193
+ if rel_dependencies[rel_dep_name][_peer]:
194
+ continue
195
+ # Skip missing packages (not installed)
196
+ if _missing in rel_dependencies[rel_dep_name]:
197
+ if rel_dependencies[rel_dep_name][_missing]:
198
+ continue
199
+ # Skip if version key doesn't exist
200
+ if _version not in rel_dependencies[rel_dep_name]:
201
+ continue
202
+
203
+ if f'{rel_name}({rel_ver})' not in self.relation_tree:
204
+ self.relation_tree[f'{rel_name}({rel_ver})'] = []
205
+ elif f'{rel_dep_name}({rel_dependencies[rel_dep_name][_version]})' in self.relation_tree[f'{rel_name}({rel_ver})']:
206
+ continue
207
+ self.relation_tree[f'{rel_name}({rel_ver})'].append(f'{rel_dep_name}({rel_dependencies[rel_dep_name][_version]})')
208
+ if _dependencies in rel_dependencies[rel_dep_name]:
209
+ self.parse_rel_dependencies(rel_dep_name, rel_dependencies[rel_dep_name][_version],
210
+ rel_dependencies[rel_dep_name][_dependencies])
211
+
212
+ def parse_direct_dependencies(self):
213
+ if not self.direct_dep:
214
+ return
215
+ try:
216
+ # For Yarn, check if package.json exists (not yarn.lock)
217
+ # input_package_list_file[0] is the license-checker output file path
218
+ manifest_dir = os.path.dirname(self.input_package_list_file[0])
219
+ package_json_path = os.path.join(manifest_dir, 'package.json')
220
+
221
+ if os.path.isfile(package_json_path):
222
+ ret, err_msg = self.parse_transitive_relationship()
223
+ if not ret:
224
+ self.direct_dep = False
225
+ logger.warning(f'It cannot print direct/transitive dependency: {err_msg}')
226
+ else:
227
+ logger.info('Direct/transitive support is not possible because the package.json file does not exist.')
228
+ self.direct_dep = False
229
+ except Exception as e:
230
+ logger.warning(f'Cannot print direct/transitive dependency: {e}')
231
+ self.direct_dep = False
File without changes