fosslight-dependency 4.1.25__py3-none-any.whl → 4.1.27__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_dependency/_analyze_dependency.py +6 -2
- fosslight_dependency/_help.py +3 -1
- fosslight_dependency/_package_manager.py +26 -0
- fosslight_dependency/constant.py +1 -1
- fosslight_dependency/package_manager/Maven.py +5 -4
- fosslight_dependency/package_manager/Npm.py +43 -12
- fosslight_dependency/package_manager/Nuget.py +204 -32
- fosslight_dependency/package_manager/Yarn.py +21 -12
- fosslight_dependency/run_dependency_scanner.py +48 -24
- {fosslight_dependency-4.1.25.dist-info → fosslight_dependency-4.1.27.dist-info}/METADATA +1 -1
- {fosslight_dependency-4.1.25.dist-info → fosslight_dependency-4.1.27.dist-info}/RECORD +18 -18
- {fosslight_dependency-4.1.25.dist-info → fosslight_dependency-4.1.27.dist-info}/WHEEL +0 -0
- {fosslight_dependency-4.1.25.dist-info → fosslight_dependency-4.1.27.dist-info}/entry_points.txt +0 -0
- {fosslight_dependency-4.1.25.dist-info → fosslight_dependency-4.1.27.dist-info}/licenses/LICENSE +0 -0
- {fosslight_dependency-4.1.25.dist-info → fosslight_dependency-4.1.27.dist-info}/licenses/LICENSES/Apache-2.0.txt +0 -0
- {fosslight_dependency-4.1.25.dist-info → fosslight_dependency-4.1.27.dist-info}/licenses/LICENSES/LicenseRef-3rd_party_licenses.txt +0 -0
- {fosslight_dependency-4.1.25.dist-info → fosslight_dependency-4.1.27.dist-info}/licenses/LICENSES/MIT.txt +0 -0
- {fosslight_dependency-4.1.25.dist-info → fosslight_dependency-4.1.27.dist-info}/top_level.txt +0 -0
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import os
|
|
7
7
|
import logging
|
|
8
8
|
import fosslight_dependency.constant as const
|
|
9
|
+
from fosslight_dependency._package_manager import deduplicate_dep_items
|
|
9
10
|
from fosslight_dependency.package_manager.Pypi import Pypi
|
|
10
11
|
from fosslight_dependency.package_manager.Npm import Npm
|
|
11
12
|
from fosslight_dependency.package_manager.Yarn import Yarn
|
|
@@ -104,16 +105,19 @@ def analyze_dependency(package_manager_name, input_dir, output_dir, pip_activate
|
|
|
104
105
|
for f_name in package_manager.input_package_list_file:
|
|
105
106
|
logger.info(f"Parse oss information with file: {f_name}")
|
|
106
107
|
|
|
107
|
-
if os.path.
|
|
108
|
+
file_path = os.path.join(input_dir, f_name) if not os.path.isabs(f_name) else f_name
|
|
109
|
+
if os.path.isfile(file_path):
|
|
108
110
|
package_manager.parse_oss_information(f_name)
|
|
109
111
|
package_dep_item_list.extend(package_manager.dep_items)
|
|
110
112
|
else:
|
|
111
|
-
logger.error(f"Failed to open input file: {
|
|
113
|
+
logger.error(f"Failed to open input file: {file_path}")
|
|
112
114
|
ret = False
|
|
113
115
|
if package_manager_name == const.PNPM:
|
|
114
116
|
logger.info("Parse oss information for pnpm")
|
|
115
117
|
package_manager.parse_oss_information_for_pnpm()
|
|
116
118
|
package_dep_item_list.extend(package_manager.dep_items)
|
|
119
|
+
if package_dep_item_list:
|
|
120
|
+
package_dep_item_list = deduplicate_dep_items(package_dep_item_list)
|
|
117
121
|
if ret:
|
|
118
122
|
logger.warning(f"### Complete to analyze: {package_manager_name}({input_dir}: {','.join(manifest_file_name)})")
|
|
119
123
|
if package_manager.cover_comment:
|
fosslight_dependency/_help.py
CHANGED
|
@@ -37,7 +37,9 @@ _HELP_MESSAGE_DEPENDENCY = f"""
|
|
|
37
37
|
\t(npm, maven, gradle, pypi, pub, cocoapods, android, swift, carthage,
|
|
38
38
|
\t go, nuget, helm, unity, cargo, pnpm, yarn)
|
|
39
39
|
-p <input_path>\t\t Enter the path where the script will be run.
|
|
40
|
-
-e <exclude_path>\t\t Enter the path where the analysis will not be performed.
|
|
40
|
+
-e <exclude_path>\t\t Enter the path where the analysis will not be performed (files and directories).
|
|
41
|
+
\t\t\t\t * IMPORTANT: Always wrap patterns in double quotes ("") to avoid shell expansion.
|
|
42
|
+
\t\t\t\t Example) fosslight_dependency -e "test/abc.py" "*.jar"
|
|
41
43
|
-o <output_path>\t\t Output path
|
|
42
44
|
\t\t\t\t\t(If you want to generate the specific file name, add the output path with file name.)
|
|
43
45
|
-f <format> [<format> ...]\t Output formats
|
|
@@ -369,3 +369,29 @@ def change_file_mode(filepath, mode=''):
|
|
|
369
369
|
os.chmod(filepath, new_mode)
|
|
370
370
|
logger.debug(f"File mode of {filepath} has been changed to {oct(new_mode)}.")
|
|
371
371
|
return current_mode
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def deduplicate_dep_items(dep_items):
|
|
375
|
+
if not dep_items:
|
|
376
|
+
return dep_items
|
|
377
|
+
|
|
378
|
+
unique_items = []
|
|
379
|
+
seen = set()
|
|
380
|
+
|
|
381
|
+
for item in dep_items:
|
|
382
|
+
first_oss = item.oss_items[0] if getattr(item, "oss_items", None) else None
|
|
383
|
+
oss_name = getattr(first_oss, "name", None) if first_oss else None
|
|
384
|
+
oss_ver = getattr(first_oss, "version", None) if first_oss else None
|
|
385
|
+
comment = getattr(first_oss, "comment", None) if first_oss else None
|
|
386
|
+
|
|
387
|
+
depends_on = None
|
|
388
|
+
if getattr(item, "depends_on", None):
|
|
389
|
+
depends_on = tuple(sorted(item.depends_on))
|
|
390
|
+
|
|
391
|
+
key = (getattr(item, "purl", None), oss_name, oss_ver, comment, depends_on)
|
|
392
|
+
if key in seen:
|
|
393
|
+
continue
|
|
394
|
+
seen.add(key)
|
|
395
|
+
unique_items.append(item)
|
|
396
|
+
|
|
397
|
+
return unique_items
|
fosslight_dependency/constant.py
CHANGED
|
@@ -41,7 +41,7 @@ SUPPORT_PACKAE = {
|
|
|
41
41
|
SWIFT: 'Package.resolved',
|
|
42
42
|
CARTHAGE: 'Cartfile.resolved',
|
|
43
43
|
GO: 'go.mod',
|
|
44
|
-
NUGET: ['packages.config', os.path.join('obj', 'project.assets.json')],
|
|
44
|
+
NUGET: ['packages.config', os.path.join('obj', 'project.assets.json'), 'Directory.Packages.props'],
|
|
45
45
|
HELM: 'Chart.yaml',
|
|
46
46
|
UNITY: os.path.join('Library', 'PackageManager', 'ProjectCache'),
|
|
47
47
|
CARGO: 'Cargo.toml'
|
|
@@ -255,10 +255,11 @@ class Maven(PackageManager):
|
|
|
255
255
|
dep_key = f"{oss_item.name}({version})"
|
|
256
256
|
|
|
257
257
|
if self.direct_dep:
|
|
258
|
-
if
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
258
|
+
if len(self.direct_dep_list) > 0:
|
|
259
|
+
if dep_key in self.direct_dep_list:
|
|
260
|
+
oss_item.comment = 'direct'
|
|
261
|
+
else:
|
|
262
|
+
oss_item.comment = 'transitive'
|
|
262
263
|
try:
|
|
263
264
|
if dep_key in self.relation_tree:
|
|
264
265
|
dep_item.depends_on_raw = self.relation_tree[dep_key]
|
|
@@ -9,6 +9,7 @@ import subprocess
|
|
|
9
9
|
import json
|
|
10
10
|
import shutil
|
|
11
11
|
import re
|
|
12
|
+
import requests
|
|
12
13
|
import fosslight_util.constant as constant
|
|
13
14
|
import fosslight_dependency.constant as const
|
|
14
15
|
from fosslight_dependency._package_manager import PackageManager, get_url_to_purl
|
|
@@ -26,9 +27,11 @@ class Npm(PackageManager):
|
|
|
26
27
|
input_file_name = 'tmp_npm_license_output.json'
|
|
27
28
|
tmp_custom_json = 'custom.json'
|
|
28
29
|
flag_tmp_node_modules = False
|
|
30
|
+
_network_available = False
|
|
29
31
|
|
|
30
32
|
def __init__(self, input_dir, output_dir):
|
|
31
33
|
super().__init__(self.package_manager_name, self.dn_url, input_dir, output_dir)
|
|
34
|
+
self._check_network_available()
|
|
32
35
|
|
|
33
36
|
def __del__(self):
|
|
34
37
|
if os.path.isfile(os.path.join(self.input_dir, self.input_file_name)):
|
|
@@ -174,24 +177,33 @@ class Npm(PackageManager):
|
|
|
174
177
|
package_path = d['path']
|
|
175
178
|
|
|
176
179
|
private_pkg = False
|
|
177
|
-
if _private in d:
|
|
178
|
-
|
|
179
|
-
private_pkg = True
|
|
180
|
+
if _private in d and d[_private]:
|
|
181
|
+
private_pkg = True
|
|
180
182
|
|
|
181
|
-
oss_item.download_location =
|
|
182
|
-
dn_loc = f"{self.dn_url}{oss_init_name}"
|
|
183
|
-
dep_item.purl = get_url_to_purl(oss_item.download_location, self.package_manager_name)
|
|
184
|
-
purl_dict[f'{oss_init_name}({oss_item.version})'] = dep_item.purl
|
|
185
|
-
if d[_repository]:
|
|
186
|
-
dn_loc = d[_repository]
|
|
187
|
-
elif private_pkg:
|
|
188
|
-
dn_loc = ''
|
|
183
|
+
oss_item.download_location = ''
|
|
189
184
|
|
|
190
|
-
|
|
185
|
+
npm_dl_url = f"{self.dn_url}{oss_init_name}/v/{oss_item.version}"
|
|
186
|
+
npm_home_url = f"{self.dn_url}{oss_init_name}"
|
|
187
|
+
dep_item.purl = get_url_to_purl(npm_dl_url, self.package_manager_name)
|
|
188
|
+
purl_dict[f'{oss_init_name}({oss_item.version})'] = dep_item.purl
|
|
191
189
|
|
|
190
|
+
repo_url = d[_repository] if d[_repository] else ''
|
|
192
191
|
if private_pkg:
|
|
192
|
+
oss_item.homepage = repo_url or ''
|
|
193
193
|
oss_item.download_location = oss_item.homepage
|
|
194
194
|
oss_item.comment = 'private'
|
|
195
|
+
else:
|
|
196
|
+
npm_url_exists = False
|
|
197
|
+
if self._network_available is True:
|
|
198
|
+
npm_url_exists = self._npm_url_exists(oss_init_name)
|
|
199
|
+
|
|
200
|
+
if self._network_available and not npm_url_exists:
|
|
201
|
+
oss_item.homepage = repo_url or ""
|
|
202
|
+
oss_item.download_location = oss_item.homepage
|
|
203
|
+
else:
|
|
204
|
+
oss_item.homepage = repo_url or npm_home_url
|
|
205
|
+
oss_item.download_location = npm_dl_url
|
|
206
|
+
|
|
195
207
|
if self.package_name == f'{oss_init_name}({oss_item.version})':
|
|
196
208
|
oss_item.comment = 'root package'
|
|
197
209
|
elif self.direct_dep and len(self.relation_tree) > 0:
|
|
@@ -221,6 +233,25 @@ class Npm(PackageManager):
|
|
|
221
233
|
self.dep_items = change_dependson_to_purl(purl_dict, self.dep_items)
|
|
222
234
|
return
|
|
223
235
|
|
|
236
|
+
def _check_network_available(self) -> bool:
|
|
237
|
+
test_url = 'https://registry.npmjs.org/'
|
|
238
|
+
try:
|
|
239
|
+
resp = requests.head(test_url, timeout=3, allow_redirects=True)
|
|
240
|
+
self._network_available = resp.status_code < 400
|
|
241
|
+
except Exception:
|
|
242
|
+
self._network_available = False
|
|
243
|
+
return self._network_available
|
|
244
|
+
|
|
245
|
+
def _npm_url_exists(self, package_name: str) -> bool:
|
|
246
|
+
url = f"https://registry.npmjs.org/{package_name}"
|
|
247
|
+
try:
|
|
248
|
+
resp = requests.head(url, timeout=3, allow_redirects=True)
|
|
249
|
+
if resp.status_code == 405:
|
|
250
|
+
resp = requests.get(url, timeout=3, allow_redirects=True)
|
|
251
|
+
return resp.status_code < 400
|
|
252
|
+
except Exception:
|
|
253
|
+
return False
|
|
254
|
+
|
|
224
255
|
|
|
225
256
|
def check_multi_license(license_name, manifest_file_path):
|
|
226
257
|
multi_license_list = []
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import logging
|
|
7
7
|
import re
|
|
8
8
|
import os
|
|
9
|
+
import subprocess
|
|
9
10
|
from defusedxml.ElementTree import parse, fromstring
|
|
10
11
|
import json
|
|
11
12
|
import requests
|
|
@@ -24,30 +25,132 @@ class Nuget(PackageManager):
|
|
|
24
25
|
|
|
25
26
|
dn_url = "https://nuget.org/packages/"
|
|
26
27
|
packageReference = False
|
|
28
|
+
directory_packages_props = 'Directory.Packages.props'
|
|
27
29
|
nuget_api_url = 'https://api.nuget.org/v3-flatcontainer/'
|
|
28
30
|
dotnet_ver = []
|
|
31
|
+
_exclude_dirs = {"test", "tests", "sample", "samples", "example", "examples"}
|
|
29
32
|
|
|
30
33
|
def __init__(self, input_dir, output_dir):
|
|
31
34
|
super().__init__(self.package_manager_name, self.dn_url, input_dir, output_dir)
|
|
32
35
|
|
|
33
36
|
for manifest_i in const.SUPPORT_PACKAE.get(self.package_manager_name):
|
|
34
|
-
if os.path.
|
|
35
|
-
self.append_input_package_list_file(manifest_i)
|
|
37
|
+
if os.path.exists(os.path.basename(manifest_i)):
|
|
38
|
+
self.append_input_package_list_file(os.path.basename(manifest_i))
|
|
36
39
|
if manifest_i != 'packages.config':
|
|
37
40
|
self.packageReference = True
|
|
38
41
|
|
|
42
|
+
def run_plugin(self):
|
|
43
|
+
ret = True
|
|
44
|
+
directory_packages_props_path = os.path.join(self.input_dir, self.directory_packages_props)
|
|
45
|
+
if not os.path.isfile(directory_packages_props_path):
|
|
46
|
+
return ret
|
|
47
|
+
|
|
48
|
+
logger.info(f"Found {self.directory_packages_props}. Using NuGet CPM flow.")
|
|
49
|
+
self.packageReference = True
|
|
50
|
+
|
|
51
|
+
restore_targets = self._find_restore_targets()
|
|
52
|
+
if restore_targets:
|
|
53
|
+
logger.info("Found .sln or .csproj files. Running 'dotnet restore'...")
|
|
54
|
+
for target_path, target_file in restore_targets:
|
|
55
|
+
logger.info(f"Restoring: {os.path.relpath(target_file, self.input_dir)}")
|
|
56
|
+
try:
|
|
57
|
+
result = subprocess.run(
|
|
58
|
+
['dotnet', 'restore', target_file, '/p:EnableWindowsTargeting=true'],
|
|
59
|
+
cwd=target_path,
|
|
60
|
+
capture_output=True,
|
|
61
|
+
text=True,
|
|
62
|
+
timeout=300
|
|
63
|
+
)
|
|
64
|
+
if result.returncode == 0:
|
|
65
|
+
logger.info(f"Successfully restored {os.path.relpath(target_file, self.input_dir)}")
|
|
66
|
+
else:
|
|
67
|
+
logger.warning(f"'dotnet restore' failed for {target_file} with return code {result.returncode}")
|
|
68
|
+
if result.stderr:
|
|
69
|
+
logger.warning(result.stderr)
|
|
70
|
+
except FileNotFoundError:
|
|
71
|
+
logger.error("'dotnet' command not found. Please install .NET SDK.")
|
|
72
|
+
except subprocess.TimeoutExpired:
|
|
73
|
+
logger.warning(f"'dotnet restore' timed out for {target_file}.")
|
|
74
|
+
except Exception as e:
|
|
75
|
+
logger.warning(f"Failed to run 'dotnet restore' for {target_file}: {e}")
|
|
76
|
+
else:
|
|
77
|
+
logger.warning("No .sln or .csproj files found to restore.")
|
|
78
|
+
|
|
79
|
+
self.project_dirs = []
|
|
80
|
+
found_projects = False
|
|
81
|
+
|
|
82
|
+
for root, dirs, files in os.walk(self.input_dir):
|
|
83
|
+
rel_root = os.path.relpath(root, self.input_dir)
|
|
84
|
+
parts = rel_root.split(os.sep) if rel_root != os.curdir else []
|
|
85
|
+
if any(p.lower() in self._exclude_dirs for p in parts):
|
|
86
|
+
continue
|
|
87
|
+
assets_json = os.path.join(root, 'obj', 'project.assets.json')
|
|
88
|
+
if os.path.isfile(assets_json):
|
|
89
|
+
found_projects = True
|
|
90
|
+
|
|
91
|
+
rel_path = os.path.relpath(assets_json, self.input_dir)
|
|
92
|
+
logger.info(f"Found project.assets.json at: {rel_path}")
|
|
93
|
+
|
|
94
|
+
if rel_path not in self.input_package_list_file:
|
|
95
|
+
self.append_input_package_list_file(rel_path)
|
|
96
|
+
|
|
97
|
+
project_dir = os.path.dirname(assets_json)
|
|
98
|
+
if project_dir.endswith(os.sep + 'obj'):
|
|
99
|
+
project_dir = project_dir[: -len(os.sep + 'obj')]
|
|
100
|
+
|
|
101
|
+
if project_dir and project_dir not in self.project_dirs:
|
|
102
|
+
self.project_dirs.append(project_dir)
|
|
103
|
+
|
|
104
|
+
if not found_projects:
|
|
105
|
+
logger.warning(
|
|
106
|
+
"Directory.Packages.props found and 'dotnet restore' completed, "
|
|
107
|
+
"but no obj/project.assets.json files were discovered."
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
return ret
|
|
111
|
+
|
|
39
112
|
def parse_oss_information(self, f_name):
|
|
40
113
|
tmp_license_txt_file_name = 'tmp_license.txt'
|
|
41
|
-
|
|
42
|
-
|
|
114
|
+
if f_name == self.directory_packages_props:
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
relation_tree = {}
|
|
118
|
+
direct_dep_list = []
|
|
119
|
+
if not hasattr(self, 'global_purl_dict'):
|
|
120
|
+
self.global_purl_dict = {}
|
|
121
|
+
if not hasattr(self, 'processed_packages'):
|
|
122
|
+
self.processed_packages = {}
|
|
123
|
+
|
|
124
|
+
file_path = os.path.join(self.input_dir, f_name) if not os.path.isabs(f_name) else f_name
|
|
125
|
+
with open(file_path, 'r', encoding='utf8') as input_fp:
|
|
43
126
|
package_list = []
|
|
44
127
|
if self.packageReference:
|
|
45
|
-
package_list = self.get_package_info_in_packagereference(input_fp)
|
|
128
|
+
package_list = self.get_package_info_in_packagereference(input_fp, relation_tree, direct_dep_list)
|
|
46
129
|
else:
|
|
47
130
|
package_list = self.get_package_list_in_packages_config(input_fp)
|
|
48
131
|
|
|
49
132
|
for oss_origin_name, oss_version in package_list:
|
|
50
133
|
try:
|
|
134
|
+
pkg_key = f'{oss_origin_name}({oss_version})'
|
|
135
|
+
if pkg_key in self.processed_packages:
|
|
136
|
+
existing_idx = self.processed_packages[pkg_key]
|
|
137
|
+
existing_dep_item = self.dep_items[existing_idx]
|
|
138
|
+
|
|
139
|
+
if pkg_key in relation_tree:
|
|
140
|
+
new_deps = relation_tree[pkg_key]
|
|
141
|
+
if existing_dep_item.depends_on_raw:
|
|
142
|
+
existing_deps_set = set(existing_dep_item.depends_on_raw)
|
|
143
|
+
new_deps_set = set(new_deps)
|
|
144
|
+
merged_deps = sorted(existing_deps_set | new_deps_set)
|
|
145
|
+
existing_dep_item.depends_on_raw = merged_deps
|
|
146
|
+
else:
|
|
147
|
+
existing_dep_item.depends_on_raw = new_deps
|
|
148
|
+
if self.direct_dep and self.packageReference:
|
|
149
|
+
if oss_origin_name in direct_dep_list:
|
|
150
|
+
if 'direct' not in existing_dep_item.oss_items[0].comment:
|
|
151
|
+
existing_dep_item.oss_items[0].comment = 'direct'
|
|
152
|
+
continue
|
|
153
|
+
|
|
51
154
|
dep_item = DependencyItem()
|
|
52
155
|
oss_item = OssItem()
|
|
53
156
|
oss_item.name = f'{self.package_manager_name}:{oss_origin_name}'
|
|
@@ -88,7 +191,7 @@ class Nuget(PackageManager):
|
|
|
88
191
|
if proj_url_id is not None:
|
|
89
192
|
oss_item.download_location = proj_url_id.text
|
|
90
193
|
oss_item.homepage = f'{self.dn_url}{oss_origin_name}'
|
|
91
|
-
if oss_item.download_location
|
|
194
|
+
if not oss_item.download_location:
|
|
92
195
|
oss_item.download_location = f'{oss_item.homepage}/{oss_item.version}'
|
|
93
196
|
else:
|
|
94
197
|
if oss_item.download_location.endswith('.git'):
|
|
@@ -97,24 +200,26 @@ class Nuget(PackageManager):
|
|
|
97
200
|
else:
|
|
98
201
|
oss_item.comment = 'Fail to response for nuget api'
|
|
99
202
|
dep_item.purl = f'pkg:nuget/{oss_origin_name}@{oss_item.version}'
|
|
100
|
-
|
|
203
|
+
self.global_purl_dict[f'{oss_origin_name}({oss_item.version})'] = dep_item.purl
|
|
101
204
|
|
|
102
205
|
if self.direct_dep and self.packageReference:
|
|
103
|
-
if oss_origin_name in
|
|
206
|
+
if oss_origin_name in direct_dep_list:
|
|
104
207
|
oss_item.comment = 'direct'
|
|
105
208
|
else:
|
|
106
209
|
oss_item.comment = 'transitive'
|
|
107
210
|
|
|
108
|
-
|
|
109
|
-
|
|
211
|
+
key = f'{oss_origin_name}({oss_item.version})'
|
|
212
|
+
if key in relation_tree:
|
|
213
|
+
dep_item.depends_on_raw = relation_tree[key]
|
|
110
214
|
|
|
111
215
|
dep_item.oss_items.append(oss_item)
|
|
112
216
|
self.dep_items.append(dep_item)
|
|
217
|
+
self.processed_packages[pkg_key] = len(self.dep_items) - 1
|
|
113
218
|
|
|
114
219
|
except Exception as e:
|
|
115
220
|
logger.warning(f"Failed to parse oss information: {e}")
|
|
116
221
|
if self.direct_dep:
|
|
117
|
-
self.dep_items = change_dependson_to_purl(
|
|
222
|
+
self.dep_items = change_dependson_to_purl(self.global_purl_dict, self.dep_items)
|
|
118
223
|
|
|
119
224
|
if os.path.isfile(tmp_license_txt_file_name):
|
|
120
225
|
os.remove(tmp_license_txt_file_name)
|
|
@@ -128,13 +233,14 @@ class Nuget(PackageManager):
|
|
|
128
233
|
package_list.append([p.get("id"), p.get("version")])
|
|
129
234
|
return package_list
|
|
130
235
|
|
|
131
|
-
def get_package_info_in_packagereference(self, input_fp):
|
|
236
|
+
def get_package_info_in_packagereference(self, input_fp, relation_tree, direct_dep_list):
|
|
132
237
|
json_f = json.load(input_fp)
|
|
133
238
|
|
|
134
|
-
self.get_dotnet_ver_list(json_f)
|
|
239
|
+
dotnet_ver = self.get_dotnet_ver_list(json_f)
|
|
135
240
|
package_list = self.get_package_list_in_packages_assets(json_f)
|
|
136
|
-
self.get_dependency_tree(json_f)
|
|
137
|
-
self.
|
|
241
|
+
self.get_dependency_tree(json_f, relation_tree, dotnet_ver)
|
|
242
|
+
self.get_direct_dependencies_from_assets_json(json_f, direct_dep_list)
|
|
243
|
+
self.get_direct_package_in_packagereference(direct_dep_list)
|
|
138
244
|
|
|
139
245
|
return package_list
|
|
140
246
|
|
|
@@ -147,14 +253,35 @@ class Nuget(PackageManager):
|
|
|
147
253
|
return package_list
|
|
148
254
|
|
|
149
255
|
def get_dotnet_ver_list(self, json_f):
|
|
256
|
+
dotnet_ver = []
|
|
150
257
|
json_project_group = json_f['projectFileDependencyGroups']
|
|
151
|
-
for
|
|
152
|
-
|
|
258
|
+
for ver in json_project_group:
|
|
259
|
+
dotnet_ver.append(ver)
|
|
260
|
+
return dotnet_ver
|
|
261
|
+
|
|
262
|
+
def get_direct_dependencies_from_assets_json(self, json_f, direct_dep_list):
|
|
263
|
+
try:
|
|
264
|
+
json_project_group = json_f.get('projectFileDependencyGroups', {})
|
|
265
|
+
for _, dependencies in json_project_group.items():
|
|
266
|
+
if not dependencies:
|
|
267
|
+
continue
|
|
268
|
+
for dep_string in dependencies:
|
|
269
|
+
package_name = dep_string.split()[0] if dep_string else ''
|
|
270
|
+
if package_name and package_name not in direct_dep_list:
|
|
271
|
+
direct_dep_list.append(package_name)
|
|
272
|
+
except Exception as e:
|
|
273
|
+
logger.warning(f"Failed to extract direct dependencies from project.assets.json: {e}")
|
|
274
|
+
|
|
275
|
+
def get_dependency_tree(self, json_f, relation_tree, dotnet_ver):
|
|
276
|
+
actual_versions = {}
|
|
277
|
+
for lib_key in json_f.get('libraries', {}):
|
|
278
|
+
if '/' in lib_key:
|
|
279
|
+
lib_name, lib_version = lib_key.split('/', 1)
|
|
280
|
+
actual_versions[lib_name.lower()] = lib_version
|
|
153
281
|
|
|
154
|
-
def get_dependency_tree(self, json_f):
|
|
155
282
|
json_target = json_f['targets']
|
|
156
283
|
for item in json_target:
|
|
157
|
-
if item not in
|
|
284
|
+
if item not in dotnet_ver:
|
|
158
285
|
continue
|
|
159
286
|
json_item = json_target[item]
|
|
160
287
|
for pkg in json_item:
|
|
@@ -166,21 +293,39 @@ class Nuget(PackageManager):
|
|
|
166
293
|
if json_pkg['type'] != 'package':
|
|
167
294
|
continue
|
|
168
295
|
oss_info = pkg.split('/')
|
|
169
|
-
|
|
296
|
+
relation_tree[f'{oss_info[0]}({oss_info[1]})'] = []
|
|
170
297
|
for dep in json_pkg['dependencies']:
|
|
171
298
|
oss_name = dep
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
299
|
+
dep_ver_in_spec = json_pkg['dependencies'][dep]
|
|
300
|
+
actual_ver = actual_versions.get(oss_name.lower(), dep_ver_in_spec)
|
|
301
|
+
relation_tree[f'{oss_info[0]}({oss_info[1]})'].append(f'{oss_name}({actual_ver})')
|
|
302
|
+
|
|
303
|
+
def get_direct_package_in_packagereference(self, direct_dep_list):
|
|
304
|
+
if hasattr(self, 'project_dirs') and self.project_dirs:
|
|
305
|
+
for project_dir in self.project_dirs:
|
|
306
|
+
for f in os.listdir(project_dir):
|
|
307
|
+
f_path = os.path.join(project_dir, f)
|
|
308
|
+
if os.path.isfile(f_path) and ((f.split('.')[-1] == 'csproj') or (f.split('.')[-1] == 'xproj')):
|
|
309
|
+
with open(f_path, 'r', encoding='utf8') as input_fp:
|
|
310
|
+
root = parse(input_fp).getroot()
|
|
311
|
+
itemgroups = root.findall('ItemGroup')
|
|
312
|
+
for itemgroup in itemgroups:
|
|
313
|
+
for item in itemgroup.findall('PackageReference'):
|
|
314
|
+
pkg_name = item.get('Include')
|
|
315
|
+
if pkg_name and pkg_name not in direct_dep_list:
|
|
316
|
+
direct_dep_list.append(pkg_name)
|
|
317
|
+
else:
|
|
318
|
+
for f in os.listdir(self.input_dir):
|
|
319
|
+
f_path = os.path.join(self.input_dir, f)
|
|
320
|
+
if os.path.isfile(f_path) and ((f.split('.')[-1] == 'csproj') or (f.split('.')[-1] == 'xproj')):
|
|
321
|
+
with open(f_path, 'r', encoding='utf8') as input_fp:
|
|
322
|
+
root = parse(input_fp).getroot()
|
|
323
|
+
itemgroups = root.findall('ItemGroup')
|
|
324
|
+
for itemgroup in itemgroups:
|
|
325
|
+
for item in itemgroup.findall('PackageReference'):
|
|
326
|
+
pkg_name = item.get('Include')
|
|
327
|
+
if pkg_name and pkg_name not in direct_dep_list:
|
|
328
|
+
direct_dep_list.append(pkg_name)
|
|
184
329
|
|
|
185
330
|
def check_multi_license(self, license_name):
|
|
186
331
|
multi_license = license_name
|
|
@@ -194,3 +339,30 @@ class Nuget(PackageManager):
|
|
|
194
339
|
logger.warning(f'Fail to parse multi license in npm: {e}')
|
|
195
340
|
|
|
196
341
|
return multi_license, license_comment
|
|
342
|
+
|
|
343
|
+
def _find_restore_targets(self):
|
|
344
|
+
sln_files = []
|
|
345
|
+
csproj_files = []
|
|
346
|
+
|
|
347
|
+
for root, dirs, files in os.walk(self.input_dir):
|
|
348
|
+
rel_root = os.path.relpath(root, self.input_dir)
|
|
349
|
+
parts = rel_root.split(os.sep) if rel_root != os.curdir else []
|
|
350
|
+
if any(p.lower() in self._exclude_dirs for p in parts):
|
|
351
|
+
continue
|
|
352
|
+
|
|
353
|
+
depth = len(parts) if parts and parts[0] != '.' else 0
|
|
354
|
+
|
|
355
|
+
for f in files:
|
|
356
|
+
if f.endswith('.sln'):
|
|
357
|
+
sln_files.append((depth, root, os.path.join(root, f)))
|
|
358
|
+
elif f.endswith('.csproj'):
|
|
359
|
+
csproj_files.append((depth, root, os.path.join(root, f)))
|
|
360
|
+
|
|
361
|
+
result = []
|
|
362
|
+
if sln_files:
|
|
363
|
+
result.extend([(d, f) for _, d, f in sln_files])
|
|
364
|
+
|
|
365
|
+
if csproj_files:
|
|
366
|
+
result.extend([(d, f) for _, d, f in csproj_files])
|
|
367
|
+
|
|
368
|
+
return result
|
|
@@ -121,24 +121,33 @@ class Yarn(Npm):
|
|
|
121
121
|
package_path = d['path']
|
|
122
122
|
|
|
123
123
|
private_pkg = False
|
|
124
|
-
if _private in d:
|
|
125
|
-
|
|
126
|
-
private_pkg = True
|
|
124
|
+
if _private in d and d[_private]:
|
|
125
|
+
private_pkg = True
|
|
127
126
|
|
|
128
|
-
oss_item.download_location =
|
|
129
|
-
dn_loc = f"{self.dn_url}{oss_init_name}"
|
|
130
|
-
dep_item.purl = get_url_to_purl(oss_item.download_location, self.package_manager_name)
|
|
131
|
-
purl_dict[f'{oss_init_name}({oss_item.version})'] = dep_item.purl
|
|
132
|
-
if d[_repository]:
|
|
133
|
-
dn_loc = d[_repository]
|
|
134
|
-
elif private_pkg:
|
|
135
|
-
dn_loc = ''
|
|
127
|
+
oss_item.download_location = ''
|
|
136
128
|
|
|
137
|
-
|
|
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
|
|
138
133
|
|
|
134
|
+
repo_url = d[_repository] if d[_repository] else ''
|
|
139
135
|
if private_pkg:
|
|
136
|
+
oss_item.homepage = repo_url or ''
|
|
140
137
|
oss_item.download_location = oss_item.homepage
|
|
141
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
|
+
|
|
142
151
|
if self.package_name == f'{oss_init_name}({oss_item.version})':
|
|
143
152
|
oss_item.comment = 'root package'
|
|
144
153
|
elif self.direct_dep and len(self.relation_tree) > 0:
|
|
@@ -60,6 +60,7 @@ def find_package_manager(input_dir, abs_path_to_exclude=[], manifest_file_name=[
|
|
|
60
60
|
manifest_file_name.append(value)
|
|
61
61
|
|
|
62
62
|
found_manifest_file = []
|
|
63
|
+
found_manifest_set = set()
|
|
63
64
|
suggested_files = []
|
|
64
65
|
for parent, dirs, files in os.walk(input_dir):
|
|
65
66
|
parent_parts = parent.split(os.sep)
|
|
@@ -74,17 +75,30 @@ def find_package_manager(input_dir, abs_path_to_exclude=[], manifest_file_name=[
|
|
|
74
75
|
for exclude_path in abs_path_to_exclude):
|
|
75
76
|
continue
|
|
76
77
|
if file in manifest_file_name:
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
candidate = os.path.join(parent, file)
|
|
79
|
+
norm_candidate = os.path.normpath(candidate)
|
|
80
|
+
if norm_candidate not in found_manifest_set:
|
|
81
|
+
found_manifest_set.add(norm_candidate)
|
|
82
|
+
found_manifest_file.append(candidate)
|
|
83
|
+
for manifest_f in manifest_file_name:
|
|
84
|
+
candidate = os.path.join(parent, manifest_f)
|
|
85
|
+
norm_candidate = os.path.normpath(candidate)
|
|
86
|
+
if os.path.exists(candidate) and norm_candidate not in found_manifest_set:
|
|
87
|
+
found_manifest_set.add(norm_candidate)
|
|
88
|
+
found_manifest_file.append(candidate)
|
|
79
89
|
if file in const.SUGGESTED_PACKAGE.keys():
|
|
80
90
|
suggested_files.append(os.path.join(parent, file))
|
|
91
|
+
|
|
81
92
|
for dir in dirs:
|
|
82
93
|
for manifest_f in manifest_file_name:
|
|
83
94
|
manifest_l = manifest_f.split(os.path.sep)
|
|
84
|
-
if len(manifest_l) > 1:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
if len(manifest_l) > 1 and manifest_l[0] == dir:
|
|
96
|
+
candidate = os.path.join(parent, manifest_f)
|
|
97
|
+
norm_candidate = os.path.normpath(candidate)
|
|
98
|
+
if os.path.exists(candidate) and norm_candidate not in found_manifest_set:
|
|
99
|
+
found_manifest_set.add(norm_candidate)
|
|
100
|
+
found_manifest_file.append(candidate)
|
|
101
|
+
|
|
88
102
|
if not recursive:
|
|
89
103
|
if len(found_manifest_file) > 0:
|
|
90
104
|
input_dir = parent
|
|
@@ -95,12 +109,22 @@ def find_package_manager(input_dir, abs_path_to_exclude=[], manifest_file_name=[
|
|
|
95
109
|
f_name = os.path.basename(f_with_path)
|
|
96
110
|
dir_path = os.path.dirname(f_with_path)
|
|
97
111
|
for key, value in const.SUPPORT_PACKAE.items():
|
|
98
|
-
if isinstance(value, list)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
112
|
+
manifest_patterns = value if isinstance(value, list) else [value]
|
|
113
|
+
|
|
114
|
+
for pattern in manifest_patterns:
|
|
115
|
+
if os.path.sep not in pattern:
|
|
116
|
+
if f_name == pattern:
|
|
117
|
+
if pattern not in found_package_manager[key][dir_path]:
|
|
118
|
+
found_package_manager[key][dir_path].append(pattern)
|
|
119
|
+
else:
|
|
120
|
+
rel_dir, rel_file = os.path.split(pattern)
|
|
121
|
+
expected_path = os.path.join(dir_path, rel_file)
|
|
122
|
+
|
|
123
|
+
if f_name == rel_file:
|
|
124
|
+
candidate = os.path.join(os.path.dirname(dir_path), rel_dir, rel_file) if rel_dir else expected_path
|
|
125
|
+
if os.path.normpath(candidate) == os.path.normpath(f_with_path):
|
|
126
|
+
if pattern not in found_package_manager[key][dir_path]:
|
|
127
|
+
found_package_manager[key][dir_path].append(pattern)
|
|
104
128
|
found_package_manager = {k: dict(v) for k, v in found_package_manager.items()}
|
|
105
129
|
|
|
106
130
|
# both npm and pnpm are detected, remove npm.
|
|
@@ -133,10 +157,12 @@ def find_package_manager(input_dir, abs_path_to_exclude=[], manifest_file_name=[
|
|
|
133
157
|
return ret, found_package_manager, input_dir, suggested_files
|
|
134
158
|
|
|
135
159
|
|
|
136
|
-
def print_package_info(
|
|
137
|
-
if
|
|
138
|
-
|
|
139
|
-
|
|
160
|
+
def print_package_info(pm, log_lines, status=''):
|
|
161
|
+
if pm:
|
|
162
|
+
if status:
|
|
163
|
+
status = f"[{status}] "
|
|
164
|
+
for pm, dir_dict in pm.items():
|
|
165
|
+
log_lines.append(f"- {status} {pm}:")
|
|
140
166
|
for path, files in dir_dict.items():
|
|
141
167
|
file_list = ', '.join(files)
|
|
142
168
|
log_lines.append(f" {path}: {file_list}")
|
|
@@ -318,16 +344,14 @@ def run_dependency_scanner(package_manager='', input_dir='', output_dir_file='',
|
|
|
318
344
|
success_pm = {k: dict(v) for k, v in success_pm.items()}
|
|
319
345
|
fail_pm = {k: dict(v) for k, v in fail_pm.items()}
|
|
320
346
|
if len(found_package_manager.keys()) > 0:
|
|
347
|
+
log_lines = ["Dependency Analysis Summary"]
|
|
321
348
|
if len(success_pm) > 0:
|
|
322
|
-
log_lines =
|
|
323
|
-
log_lines = print_package_info(success_pm, log_lines)
|
|
324
|
-
scan_item.set_cover_comment('\n'.join(log_lines))
|
|
349
|
+
log_lines = print_package_info(success_pm, log_lines, 'Success')
|
|
325
350
|
if len(fail_pm) > 0:
|
|
326
|
-
log_lines =
|
|
327
|
-
log_lines
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
'and https://fosslight.org/fosslight-guide-en/scanner/3_dependency.html#-prerequisite.')
|
|
351
|
+
log_lines = print_package_info(fail_pm, log_lines, 'Fail')
|
|
352
|
+
log_lines.append('If analysis fails, see fosslight_log*.txt and the prerequisite guide: '
|
|
353
|
+
'https://fosslight.org/fosslight-guide-en/scanner/3_dependency.html#-prerequisite.')
|
|
354
|
+
scan_item.set_cover_comment('\n'.join(log_lines))
|
|
331
355
|
|
|
332
356
|
if ret and graph_path:
|
|
333
357
|
graph_path = os.path.abspath(graph_path)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fosslight_dependency
|
|
3
|
-
Version: 4.1.
|
|
3
|
+
Version: 4.1.27
|
|
4
4
|
Summary: FOSSLight Dependency Scanner
|
|
5
5
|
Home-page: https://github.com/fosslight/fosslight_dependency_scanner
|
|
6
6
|
Download-URL: https://github.com/fosslight/fosslight_dependency_scanner
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
fosslight_dependency/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
fosslight_dependency/_analyze_dependency.py,sha256
|
|
2
|
+
fosslight_dependency/_analyze_dependency.py,sha256=-iETqo4DNu_d8iJtC7Of0waY6YHjJ8OB8Lf_m-9WZXw,5888
|
|
3
3
|
fosslight_dependency/_graph_convertor.py,sha256=D8GwmJfuj9Wg3_DeKRPLGGdyHSLcoU2Q0VzKQbkJG4g,2267
|
|
4
|
-
fosslight_dependency/_help.py,sha256=
|
|
5
|
-
fosslight_dependency/_package_manager.py,sha256
|
|
6
|
-
fosslight_dependency/constant.py,sha256=
|
|
4
|
+
fosslight_dependency/_help.py,sha256=1ER9CDiORhMdX1FYedPHcp2TRyvICPFGM1wxOOJ4PNE,3882
|
|
5
|
+
fosslight_dependency/_package_manager.py,sha256=-hEOG44AnBoSKjMM-WQAbZIXhD8kHc-EwkOl1aLu-CA,15824
|
|
6
|
+
fosslight_dependency/constant.py,sha256=zaLjZsk4r5Gv6puCbV_Crt9pWrX_FEYzgEh0UQVIE4g,1291
|
|
7
7
|
fosslight_dependency/dependency_item.py,sha256=wNLWcsNycf3HQ5Pib2WrMeo2dn0eHCRg20NLcL95Qew,3345
|
|
8
|
-
fosslight_dependency/run_dependency_scanner.py,sha256=
|
|
8
|
+
fosslight_dependency/run_dependency_scanner.py,sha256=9hbrrW_EfJ_6XeajrVFl-B59q5MlMHXsMRJ2BjjKu6o,22736
|
|
9
9
|
fosslight_dependency/LICENSES/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
10
10
|
fosslight_dependency/LICENSES/LicenseRef-3rd_party_licenses.txt,sha256=EcsFt7aE1rp3OXAdJgmXayfOZdpRdBMcmRnyoqWMCsw,95687
|
|
11
11
|
fosslight_dependency/package_manager/Android.py,sha256=SgQyVxEYvAcCN3EgP9p4QOQZpLIGDahXRm8ntgoCM3c,3666
|
|
@@ -15,22 +15,22 @@ fosslight_dependency/package_manager/Cocoapods.py,sha256=k_URV1ekMOU8l_y9_KIp_lu
|
|
|
15
15
|
fosslight_dependency/package_manager/Go.py,sha256=eEWvPoE3Jd0lMJAxWMNdFcoi21fJF0EwtRbjBDHF8KQ,7309
|
|
16
16
|
fosslight_dependency/package_manager/Gradle.py,sha256=zTMvospDpfabl2DRk1jW316lW9BJfGtf05TBcna6E8E,4640
|
|
17
17
|
fosslight_dependency/package_manager/Helm.py,sha256=ucx2Y0tWX37UHIzIGaRyTe7uQ2vlu2nUuO09hOMq9ZU,4223
|
|
18
|
-
fosslight_dependency/package_manager/Maven.py,sha256=
|
|
19
|
-
fosslight_dependency/package_manager/Npm.py,sha256=
|
|
20
|
-
fosslight_dependency/package_manager/Nuget.py,sha256=
|
|
18
|
+
fosslight_dependency/package_manager/Maven.py,sha256=F1KQxR_LjSxl7ZgRS_W1TbuDpRERLoAVGLIUWOpjLmk,11046
|
|
19
|
+
fosslight_dependency/package_manager/Npm.py,sha256=6DSsRnk8tj8NUTjG4qFfybi9x-GW1I3FRGYbNn9IJpk,12300
|
|
20
|
+
fosslight_dependency/package_manager/Nuget.py,sha256=Q_pDGxsNOboVcA6KCEt2rAdFvTB46Z5sOvY4pKwNiHo,17290
|
|
21
21
|
fosslight_dependency/package_manager/Pnpm.py,sha256=LDKooFGQHui_Q5U7XqSJ8KcCPiLVndXf5oGKTJExh5w,7056
|
|
22
22
|
fosslight_dependency/package_manager/Pub.py,sha256=g4jqA19vf3jBdlmPLVZiIYMAQHNn3Y2I-_oq3vtpfv0,10372
|
|
23
23
|
fosslight_dependency/package_manager/Pypi.py,sha256=Ae-mFl9jSgc1XrUdzAuKGuZA4nduSsWaC-u6VVjFNtg,17187
|
|
24
24
|
fosslight_dependency/package_manager/Swift.py,sha256=8fdbdAXTNlp2NDoSqQXm48JGAg9UhxA91M1-NhHkT40,6752
|
|
25
25
|
fosslight_dependency/package_manager/Unity.py,sha256=n1006GZ6Qrk8wAdO6wla1Q-JD7Evin7REVj-HDeTARc,5142
|
|
26
|
-
fosslight_dependency/package_manager/Yarn.py,sha256=
|
|
26
|
+
fosslight_dependency/package_manager/Yarn.py,sha256=ZSi7_O5tMmS80Z58YOZxvai84_KyDpP8plo0x80YtVc,10069
|
|
27
27
|
fosslight_dependency/package_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
-
fosslight_dependency-4.1.
|
|
29
|
-
fosslight_dependency-4.1.
|
|
30
|
-
fosslight_dependency-4.1.
|
|
31
|
-
fosslight_dependency-4.1.
|
|
32
|
-
fosslight_dependency-4.1.
|
|
33
|
-
fosslight_dependency-4.1.
|
|
34
|
-
fosslight_dependency-4.1.
|
|
35
|
-
fosslight_dependency-4.1.
|
|
36
|
-
fosslight_dependency-4.1.
|
|
28
|
+
fosslight_dependency-4.1.27.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
29
|
+
fosslight_dependency-4.1.27.dist-info/licenses/LICENSES/Apache-2.0.txt,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
30
|
+
fosslight_dependency-4.1.27.dist-info/licenses/LICENSES/LicenseRef-3rd_party_licenses.txt,sha256=EcsFt7aE1rp3OXAdJgmXayfOZdpRdBMcmRnyoqWMCsw,95687
|
|
31
|
+
fosslight_dependency-4.1.27.dist-info/licenses/LICENSES/MIT.txt,sha256=9cx4CbArgByWvkoEZNqpzbpJgA9TUe2D62rMocQpgfs,1082
|
|
32
|
+
fosslight_dependency-4.1.27.dist-info/METADATA,sha256=XwTKgyccmsXe73qGPmUTN-LCENc00_jKobN1AWyUP-s,5555
|
|
33
|
+
fosslight_dependency-4.1.27.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
|
34
|
+
fosslight_dependency-4.1.27.dist-info/entry_points.txt,sha256=AeU-9Bl8al8Sa-XvhitGHdT3ZTPIrlhqADcp7s5OLF8,90
|
|
35
|
+
fosslight_dependency-4.1.27.dist-info/top_level.txt,sha256=Jc0V7VcVCH0TEM8ksb8dwroTYz4AmRaQnlr3FB71Hcs,21
|
|
36
|
+
fosslight_dependency-4.1.27.dist-info/RECORD,,
|
|
File without changes
|
{fosslight_dependency-4.1.25.dist-info → fosslight_dependency-4.1.27.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{fosslight_dependency-4.1.25.dist-info → fosslight_dependency-4.1.27.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fosslight_dependency-4.1.25.dist-info → fosslight_dependency-4.1.27.dist-info}/top_level.txt
RENAMED
|
File without changes
|