Skip to content

Commit 753eb2d

Browse files
authored
Print the dependencies of each package in comment (#128)
Signed-off-by: Jiyeong Seok <[email protected]>
1 parent bb3bb43 commit 753eb2d

File tree

14 files changed

+1445
-558
lines changed

14 files changed

+1445
-558
lines changed

src/fosslight_dependency/_package_manager.py

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import base64
1212
import subprocess
1313
import shutil
14-
import copy
1514
import fosslight_util.constant as constant
1615
import fosslight_dependency.constant as const
1716

@@ -47,6 +46,8 @@ def __init__(self, package_manager_name, dn_url, input_dir, output_dir):
4746
self.output_dir = output_dir
4847
self.dn_url = dn_url
4948
self.manifest_file_name = []
49+
self.relation_tree = {}
50+
self.package_name = ''
5051

5152
self.platform = platform.system()
5253
self.license_scanner_bin = check_license_scanner(self.platform)
@@ -61,6 +62,8 @@ def __del__(self):
6162
self.output_dir = ''
6263
self.dn_url = ''
6364
self.manifest_file_name = []
65+
self.relation_tree = {}
66+
self.package_name = ''
6467

6568
def run_plugin(self):
6669
if self.package_manager_name == const.GRADLE or self.package_manager_name == const.ANDROID:
@@ -87,23 +90,20 @@ def run_gradle_task(self):
8790

8891
shutil.copy(const.SUPPORT_PACKAE.get(self.package_manager_name), gradle_backup)
8992
ret = self.add_allDeps_in_gradle()
90-
if not ret:
91-
return
92-
93-
if os.path.isfile('gradlew') or os.path.isfile('gradlew.bat'):
94-
if self.platform == const.WINDOWS:
95-
cmd_gradle = "gradlew.bat"
96-
else:
97-
cmd_gradle = "./gradlew"
98-
else:
99-
return 1
100-
cmd = f"{cmd_gradle} allDeps"
101-
ret = subprocess.check_output(cmd, shell=True, encoding='utf-8')
102-
if ret != 0:
103-
self.parse_dependency_tree(ret)
104-
else:
105-
self.set_direct_dependencies(False)
106-
logger.warning("Failed to run allDeps task.")
93+
if ret:
94+
if os.path.isfile('gradlew') or os.path.isfile('gradlew.bat'):
95+
if self.platform == const.WINDOWS:
96+
cmd_gradle = "gradlew.bat"
97+
else:
98+
cmd_gradle = "./gradlew"
99+
100+
cmd = f"{cmd_gradle} allDeps"
101+
ret = subprocess.check_output(cmd, shell=True, encoding='utf-8')
102+
if ret != 0:
103+
self.parse_dependency_tree(ret)
104+
else:
105+
self.set_direct_dependencies(False)
106+
logger.warning("Failed to run allDeps task.")
107107

108108
if os.path.isfile(gradle_backup):
109109
os.remove(const.SUPPORT_PACKAE.get(self.package_manager_name))
@@ -132,26 +132,55 @@ def add_allDeps_in_gradle(self):
132132

133133
return ret
134134

135-
def parse_dependency_tree(self, dependency_tree_fname):
136-
config = android_config if self.package_manager_name == 'android' else gradle_config
135+
def create_dep_stack(self, dep_line, config):
137136
packages_in_config = False
138-
for line in dependency_tree_fname.split('\n'):
137+
dep_stack = []
138+
cur_flag = ''
139+
dep_level = -1
140+
dep_level_plus = False
141+
for line in dep_line.split('\n'):
139142
try:
140-
line_bk = copy.deepcopy(line)
141143
if not packages_in_config:
142144
filtered = next(filter(lambda c: re.findall(rf'^{c}\s\-', line), config), None)
143145
if filtered:
144146
packages_in_config = True
145147
else:
146148
if line == '':
147149
packages_in_config = False
148-
re_result = re.findall(r'\-\-\-\s([^\:\s]+\:[^\:\s]+)\:([^\:\s]+)', line)
150+
prev_flag = cur_flag
151+
prev_dep_level = dep_level
152+
dep_level = line.count("|")
153+
154+
re_result = re.findall(r'([\+|\\])\-\-\-\s([^\:\s]+\:[^\:\s]+)\:([^\:\s]+)', line)
149155
if re_result:
150-
self.total_dep_list.append(re_result[0][0])
151-
if re.match(r'^[\+|\\]\-\-\-\s([^\:\s]+\:[^\:\s]+)\:([^\:\s]+)', line_bk):
152-
self.direct_dep_list.append(re_result[0][0])
156+
cur_flag = re_result[0][0]
157+
if (prev_flag == '\\') and (prev_dep_level == dep_level):
158+
dep_level_plus = True
159+
if dep_level_plus and (prev_flag == '\\') and (prev_dep_level != dep_level):
160+
dep_level_plus = False
161+
if dep_level_plus:
162+
dep_level += 1
163+
dep_name = f'{re_result[0][1]}({re_result[0][2]})'
164+
dep_stack = dep_stack[:dep_level] + [dep_name]
165+
yield dep_stack[:dep_level], dep_name
166+
else:
167+
cur_flag = ''
153168
except Exception as e:
154-
logger.error(f"Failed to parse dependency tree: {e}")
169+
logger.warning(f"Failed to parse dependency tree: {e}")
170+
171+
def parse_dependency_tree(self, f_name):
172+
config = android_config if self.package_manager_name == 'android' else gradle_config
173+
try:
174+
for stack, name in self.create_dep_stack(f_name, config):
175+
self.total_dep_list.append(name)
176+
if len(stack) == 0:
177+
self.direct_dep_list.append(name)
178+
else:
179+
if stack[-1] not in self.relation_tree:
180+
self.relation_tree[stack[-1]] = []
181+
self.relation_tree[stack[-1]].append(name)
182+
except Exception as e:
183+
logger.warning(f'Fail to parse gradle dependency tree:{e}')
155184

156185

157186
def version_refine(oss_version):

src/fosslight_dependency/package_manager/Android.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,22 @@ def parse_oss_information(self, f_name):
5050
else:
5151
continue
5252

53-
if self.total_dep_list:
54-
if oss_name not in self.total_dep_list:
55-
continue
56-
53+
comment_list = []
5754
if self.direct_dep:
58-
if oss_name in self.direct_dep_list:
59-
comment = 'direct'
55+
dep_key = f"{oss_name}({oss_version})"
56+
if self.total_dep_list:
57+
if dep_key not in self.total_dep_list:
58+
continue
59+
if dep_key in self.direct_dep_list:
60+
comment_list.append('direct')
6061
else:
61-
comment = 'transitive'
62+
comment_list.append('transitive')
63+
try:
64+
if dep_key in self.relation_tree:
65+
comment_list.extend(self.relation_tree[dep_key])
66+
except Exception as e:
67+
logger.error(f"Fail to find oss scope in dependency tree: {e}")
68+
comment = ', '.join(comment_list)
6269

6370
sheet_list.append([manifest_file, oss_name, oss_version, license_name, dn_loc, homepage, '', '', comment])
6471

src/fosslight_dependency/package_manager/Gradle.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ def parse_oss_information(self, f_name):
5151
oss_name, oss_ini_version = parse_oss_name_version_in_filename(filename)
5252
used_filename = True
5353

54+
dep_key = f"{oss_name}({oss_ini_version})"
5455
if self.total_dep_list:
55-
if oss_name not in self.total_dep_list:
56+
if dep_key not in self.total_dep_list:
5657
continue
5758

5859
oss_version = version_refine(oss_ini_version)
@@ -73,11 +74,19 @@ def parse_oss_information(self, f_name):
7374
dn_loc = f"{self.dn_url}{group_id}/{artifact_id}/{oss_ini_version}"
7475
homepage = f"{self.dn_url}{group_id}/{artifact_id}"
7576

77+
comment_list = []
7678
if self.direct_dep:
77-
if oss_name in self.direct_dep_list:
78-
comment = 'direct'
79-
else:
80-
comment = 'transitive'
79+
if len(self.direct_dep_list) > 0:
80+
if dep_key in self.direct_dep_list:
81+
comment_list.append('direct')
82+
else:
83+
comment_list.append('transitive')
84+
try:
85+
if dep_key in self.relation_tree:
86+
comment_list.extend(self.relation_tree[dep_key])
87+
except Exception as e:
88+
logger.error(f"Fail to find oss scope in dependency tree: {e}")
89+
comment = ', '.join(comment_list)
8190

8291
sheet_list.append([const.SUPPORT_PACKAE.get(self.package_manager_name),
8392
oss_name, oss_version, license_name, dn_loc, homepage, '', '', comment])

src/fosslight_dependency/package_manager/Maven.py

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from bs4 import BeautifulSoup as bs
1111
from xml.etree.ElementTree import parse
1212
import re
13-
import copy
1413
import fosslight_util.constant as constant
1514
import fosslight_dependency.constant as const
1615
from fosslight_dependency._package_manager import PackageManager
@@ -26,12 +25,10 @@ class Maven(PackageManager):
2625
input_file_name = os.path.join('target', 'generated-resources', 'licenses.xml')
2726
is_run_plugin = False
2827
output_custom_dir = ''
29-
dependency_tree = {}
3028

3129
def __init__(self, input_dir, output_dir, output_custom_dir):
3230
super().__init__(self.package_manager_name, self.dn_url, input_dir, output_dir)
3331
self.is_run_plugin = False
34-
self.dependency_tree = {}
3532

3633
if output_custom_dir:
3734
self.output_custom_dir = output_custom_dir
@@ -154,26 +151,60 @@ def run_maven_plugin(self):
154151
ret = subprocess.call(cmd, shell=True)
155152
if ret != 0:
156153
logger.error(f"Failed to run: {cmd}")
157-
self.set_direct_dependencies(True)
154+
self.set_direct_dependencies(False)
158155
else:
159156
self.parse_dependency_tree(dependency_tree_fname)
160157
self.set_direct_dependencies(True)
161158
os.remove(dependency_tree_fname)
162159

160+
def create_dep_stack(self, dep_line):
161+
dep_stack = []
162+
cur_flag = ''
163+
dep_level = -1
164+
dep_level_plus = False
165+
for line in dep_line.readlines():
166+
try:
167+
if not line.startswith('[INFO]'):
168+
continue
169+
if len(line) <= 7:
170+
continue
171+
line = line[7:]
172+
173+
prev_flag = cur_flag
174+
prev_dep_level = dep_level
175+
dep_level = line.count("|")
176+
177+
re_result = re.findall(r'([\+|\\]\-)\s([^\:\s]+\:[^\:\s]+)\:(?:[^\:\s]+)\:([^\:\s]+)\:([^\:\s]+)', line)
178+
if re_result:
179+
cur_flag = re_result[0][0]
180+
if (prev_flag == '\\-') and (prev_dep_level == dep_level):
181+
dep_level_plus = True
182+
if dep_level_plus and (prev_flag == '\\-') and (prev_dep_level != dep_level):
183+
dep_level_plus = False
184+
if dep_level_plus:
185+
dep_level += 1
186+
if re_result[0][3] == 'test':
187+
continue
188+
dep_name = f'{re_result[0][1]}({re_result[0][2]})'
189+
dep_stack = dep_stack[:dep_level] + [dep_name]
190+
yield dep_stack[:dep_level], dep_name
191+
else:
192+
cur_flag = ''
193+
except Exception as e:
194+
logger.warning(f"Failed to parse dependency tree: {e}")
195+
163196
def parse_dependency_tree(self, f_name):
164197
with open(f_name, 'r', encoding='utf8') as input_fp:
165-
for i, line in enumerate(input_fp.readlines()):
166-
try:
167-
line_bk = copy.deepcopy(line)
168-
re_result = re.findall(r'[\+|\\]\-\s([^\:\s]+\:[^\:\s]+)\:(?:[^\:\s]+)\:([^\:\s]+)\:([^\:\s]+)', line)
169-
if re_result:
170-
dependency_key = re_result[0][0] + ':' + re_result[0][1]
171-
if self.direct_dep:
172-
if re.match(r'^\[\w+\]\s[\+\\]\-', line_bk):
173-
self.direct_dep_list.append(re_result[0][0])
174-
self.dependency_tree[dependency_key] = re_result[0][2]
175-
except Exception as e:
176-
logger.error(f"Failed to parse dependency tree: {e}")
198+
try:
199+
for stack, name in self.create_dep_stack(input_fp):
200+
if len(stack) == 0:
201+
self.direct_dep_list.append(name)
202+
else:
203+
if stack[-1] not in self.relation_tree:
204+
self.relation_tree[stack[-1]] = []
205+
self.relation_tree[stack[-1]].append(name)
206+
except Exception as e:
207+
logger.warning(f'Fail to parse maven dependency tree:{e}')
177208

178209
def parse_oss_information(self, f_name):
179210
with open(f_name, 'r', encoding='utf8') as input_fp:
@@ -183,6 +214,7 @@ def parse_oss_information(self, f_name):
183214
dependencies = root.find("dependencies")
184215

185216
sheet_list = []
217+
comment = ''
186218

187219
for d in dependencies.iter("dependency"):
188220
groupid = d.findtext("groupId")
@@ -205,20 +237,18 @@ def parse_oss_information(self, f_name):
205237
# Case that doesn't include License tag value.
206238
license_name = ''
207239

240+
dep_key = f"{oss_name}({version})"
208241
comment_list = []
209-
try:
210-
dependency_tree_key = f"{oss_name}:{version}"
211-
if dependency_tree_key in self.dependency_tree.keys():
212-
comment_list.append(self.dependency_tree[dependency_tree_key])
213-
except Exception as e:
214-
logger.error(f"Fail to find oss scope in dependency tree: {e}")
215-
216242
if self.direct_dep:
217-
if oss_name in self.direct_dep_list:
243+
if dep_key in self.direct_dep_list:
218244
comment_list.append('direct')
219245
else:
220246
comment_list.append('transitive')
221-
247+
try:
248+
if dep_key in self.relation_tree:
249+
comment_list.extend(self.relation_tree[dep_key])
250+
except Exception as e:
251+
logger.error(f"Fail to find oss scope in dependency tree: {e}")
222252
comment = ', '.join(comment_list)
223253

224254
sheet_list.append([const.SUPPORT_PACKAE.get(self.package_manager_name),

0 commit comments

Comments
 (0)