Skip to content

Commit 156bf8f

Browse files
authored
Add dependencies of cocoapods, go, nuget package in comment (#130)
* Add dependencies of cocoapods, go, nuget package in comment * Fix the android gradle allDeps task exception bug --------- Signed-off-by: Jiyeong Seok <[email protected]>
1 parent 24d3a70 commit 156bf8f

File tree

5 files changed

+153
-78
lines changed

5 files changed

+153
-78
lines changed

.github/workflows/publish-release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ jobs:
8585
asset_content_type: application/octet-stream
8686

8787
deploy:
88-
runs-on: ubuntu-18.04
88+
runs-on: ubuntu-latest
8989
needs: build
9090
steps:
9191
- uses: actions/checkout@v3

src/fosslight_dependency/_package_manager.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,24 @@ def run_gradle_task(self):
9191
shutil.copy(const.SUPPORT_PACKAE.get(self.package_manager_name), gradle_backup)
9292
ret = self.add_allDeps_in_gradle()
9393
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.")
94+
try:
95+
if os.path.isfile('gradlew') or os.path.isfile('gradlew.bat'):
96+
if self.platform == const.WINDOWS:
97+
cmd_gradle = "gradlew.bat"
98+
else:
99+
cmd_gradle = "./gradlew"
100+
101+
cmd = f"{cmd_gradle} allDeps"
102+
ret = subprocess.check_output(cmd, shell=True, encoding='utf-8')
103+
if ret != 0:
104+
self.parse_dependency_tree(ret)
105+
else:
106+
self.set_direct_dependencies(False)
107+
logger.warning("Failed to run allDeps task.")
108+
except Exception as e:
109+
self.set_direct_dependencies(False)
110+
logger.error(f'Fail to run allDeps: {e}')
111+
logger.warning('It cannot print the direct/transitive dependencies relationship.')
107112

108113
if os.path.isfile(gradle_backup):
109114
os.remove(const.SUPPORT_PACKAE.get(self.package_manager_name))

src/fosslight_dependency/package_manager/Cocoapods.py

Lines changed: 54 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ def parse_oss_information(self, f_name):
3434
with open(f_name, 'r', encoding='utf8') as input_fp:
3535
podfile_yaml = yaml.load(input_fp, Loader=yaml.FullLoader)
3636

37-
pod_in_sepc_list = []
38-
pod_not_in_spec_list = []
3937
spec_repo_list = []
4038
external_source_list = []
4139
comment = ''
@@ -49,47 +47,64 @@ def parse_oss_information(self, f_name):
4947
external_source_list.append(external_sources_key)
5048
spec_repo_list.append(external_sources_key)
5149
if len(spec_repo_list) == 0:
52-
logger.error("Cannot fint SPEC REPOS or EXTERNAL SOURCES in Podfile.lock.")
50+
logger.error("Cannot find SPEC REPOS or EXTERNAL SOURCES in Podfile.lock.")
5351
return ''
5452

5553
for dep_key in podfile_yaml[_dependencies]:
5654
dep_key_re = re.findall(r'(^\S*)', dep_key)
57-
dep_name = dep_key_re[0]
58-
if '/' in dep_name:
59-
dep_name = dep_name.split('/')[0]
60-
self.direct_dep_list.append(dep_name)
61-
62-
for pods_list in podfile_yaml['PODS']:
63-
if not isinstance(pods_list, str):
64-
for pods_list_key, pods_list_item in pods_list.items():
65-
pod_in_sepc_list, spec_repo_list, pod_not_in_spec_list = \
66-
compile_pods_item(pods_list_key, spec_repo_list, pod_in_sepc_list, pod_not_in_spec_list)
55+
self.direct_dep_list.append(dep_key_re[0])
56+
57+
pod_item_list = {}
58+
for pods_i in podfile_yaml['PODS']:
59+
if not isinstance(pods_i, str):
60+
for key, items in pods_i.items():
61+
k_name, k_ver = get_pods_info(key)
62+
pod_item_list[k_name] = k_ver
63+
self.relation_tree[f'{k_name}({k_ver})'] = []
64+
for item in items:
65+
i_name, _ = get_pods_info(item)
66+
self.relation_tree[f'{k_name}({k_ver})'].append(i_name)
6767
else:
68-
pod_in_sepc_list, spec_repo_list, pod_not_in_spec_list = \
69-
compile_pods_item(pods_list, spec_repo_list, pod_in_sepc_list, pod_not_in_spec_list)
68+
oss_name, oss_version = get_pods_info(pods_i)
69+
pod_item_list[oss_name] = oss_version
7070

71-
if len(spec_repo_list) != 0:
72-
for spec_in_item in spec_repo_list:
73-
spec_oss_name_adding_core = spec_in_item + "/Core"
74-
for pod_not_item in pod_not_in_spec_list:
75-
if spec_oss_name_adding_core == pod_not_item[0]:
76-
pod_in_sepc_list.append([spec_in_item, pod_not_item[1]])
71+
for rel_key in self.relation_tree:
72+
try:
73+
tmp_item_list = []
74+
for ri in self.relation_tree[rel_key]:
75+
ri_version = pod_item_list[ri]
76+
tmp_item_list.append(f'{ri}({ri_version})')
77+
self.relation_tree[rel_key] = []
78+
self.relation_tree[rel_key].extend(tmp_item_list)
79+
except Exception as e:
80+
logger.warning(f'Fail to check packages of {rel_key}: {e}')
81+
if rel_key in self.relation_tree:
82+
self.relation_tree[rel_key] = []
7783

7884
sheet_list = []
79-
80-
for pod_oss in pod_in_sepc_list:
85+
for pod_oss_name_origin, pod_oss_version in pod_item_list.items():
8186
try:
87+
comment_list = []
8288
if self.direct_dep:
83-
if pod_oss[0] in self.direct_dep_list:
84-
comment = 'direct'
89+
if pod_oss_name_origin in self.direct_dep_list:
90+
comment_list.append('direct')
8591
else:
86-
comment = 'transitive'
87-
if pod_oss[0] in external_source_list:
88-
podspec_filename = pod_oss[0] + '.podspec.json'
92+
comment_list.append('transitive')
93+
if f'{pod_oss_name_origin}({oss_version})' in self.relation_tree:
94+
rel_items = [f'{self.package_manager_name}:{ri}'
95+
for ri in self.relation_tree[f'{pod_oss_name_origin}({oss_version})']]
96+
comment_list.extend(rel_items)
97+
comment = ', '.join(comment_list)
98+
99+
pod_oss_name = pod_oss_name_origin
100+
if '/' in pod_oss_name_origin:
101+
pod_oss_name = pod_oss_name_origin.split('/')[0]
102+
if pod_oss_name in external_source_list:
103+
podspec_filename = pod_oss_name + '.podspec.json'
89104
spec_file_path = os.path.join("Pods", "Local Podspecs", podspec_filename)
90105
else:
91106
search_oss_name = ""
92-
for alphabet_oss in pod_oss[0]:
107+
for alphabet_oss in pod_oss_name:
93108
if not alphabet_oss.isalnum():
94109
search_oss_name += f"\\\\{alphabet_oss}"
95110
else:
@@ -106,16 +121,19 @@ def parse_oss_information(self, f_name):
106121
file_path_without_version = os.path.join(os.sep, *file_path[:-2])
107122
else:
108123
file_path_without_version = os.path.join(*file_path[:-2])
109-
spec_file_path = os.path.join(file_path_without_version, pod_oss[1], file_path[-1])
124+
spec_file_path = os.path.join(file_path_without_version, pod_oss_version, file_path[-1])
110125

111126
oss_name, oss_version, license_name, dn_loc, homepage = self.get_oss_in_podspec(spec_file_path)
112127
if oss_name == '':
113128
continue
114-
129+
if pod_oss_version != oss_version:
130+
logger.warning(f'{pod_oss_name_origin} has different version({pod_oss_version})\
131+
with spec version({oss_version})')
115132
sheet_list.append([const.SUPPORT_PACKAE.get(self.package_manager_name),
116-
oss_name, oss_version, license_name, dn_loc, homepage, '', '', comment])
133+
f'{self.package_manager_name}:{pod_oss_name_origin}',
134+
pod_oss_version, license_name, dn_loc, homepage, '', '', comment])
117135
except Exception as e:
118-
logger.warning(f"Fail to get {pod_oss[0]}:{e}")
136+
logger.warning(f"Fail to get {pod_oss_name_origin}:{e}")
119137

120138
return sheet_list
121139

@@ -159,20 +177,10 @@ def parse_direct_dependencies(self):
159177
self.direct_dep = True
160178

161179

162-
def compile_pods_item(pods_item, spec_repo_list, pod_in_sepc_list, pod_not_in_spec_list):
163-
pods_item_re = re.findall(r'(\S*)\s{1}\((.*)\)', pods_item)
180+
def get_pods_info(pods_item):
181+
pods_item_re = re.findall(r'(\S*)(?:\s{1}\((.*)\))?', pods_item)
164182

165183
oss_name = pods_item_re[0][0]
166184
oss_version = pods_item_re[0][1]
167185

168-
oss_info = []
169-
oss_info.append(oss_name)
170-
oss_info.append(oss_version)
171-
172-
if oss_name in spec_repo_list:
173-
pod_in_sepc_list.append(oss_info)
174-
spec_repo_list.remove(oss_name)
175-
else:
176-
pod_not_in_spec_list.append(oss_info)
177-
178-
return pod_in_sepc_list, spec_repo_list, pod_not_in_spec_list
186+
return oss_name, oss_version

src/fosslight_dependency/package_manager/Go.py

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import json
1010
from bs4 import BeautifulSoup
1111
import urllib.request
12+
import re
1213
import fosslight_util.constant as constant
1314
import fosslight_dependency.constant as const
1415
from fosslight_dependency._package_manager import PackageManager
@@ -33,6 +34,18 @@ def __del__(self):
3334
if os.path.isfile(self.tmp_file_name):
3435
os.remove(self.tmp_file_name)
3536

37+
def parse_dependency_tree(self, go_deptree_txt):
38+
for line in go_deptree_txt.split('\n'):
39+
re_result = re.findall(r'(\S+)@v(\S+)\s(\S+)@v(\S+)', line)
40+
if len(re_result) > 0 and len(re_result[0]) >= 4:
41+
oss_name = re_result[0][0]
42+
oss_ver = re_result[0][1]
43+
pkg_name = re_result[0][2]
44+
pkg_ver = re_result[0][3]
45+
if f'{oss_name}({oss_ver})' not in self.relation_tree:
46+
self.relation_tree[f'{oss_name}({oss_ver})'] = []
47+
self.relation_tree[f'{oss_name}({oss_ver})'].append(f'{pkg_name}({pkg_ver})')
48+
3649
def run_plugin(self):
3750
ret = True
3851

@@ -46,6 +59,11 @@ def run_plugin(self):
4659

4760
self.append_input_package_list_file(self.tmp_file_name)
4861

62+
cmd_tree = "go mod graph"
63+
ret_cmd_tree = subprocess.check_output(cmd_tree, shell=True, text=True, encoding='utf-8')
64+
if ret_cmd_tree != 0:
65+
self.parse_dependency_tree(ret_cmd_tree)
66+
4967
return ret
5068

5169
def parse_oss_information(self, f_name):
@@ -67,40 +85,44 @@ def parse_oss_information(self, f_name):
6785
continue
6886
package_path = dep_item['Path']
6987
oss_name = f"{self.package_manager_name}:{package_path}"
70-
oss_version = dep_item['Version']
88+
oss_origin_version = dep_item['Version']
89+
if oss_origin_version.startswith('v'):
90+
oss_version = oss_origin_version[1:]
7191

72-
comment = []
92+
comment_list = []
7393
if self.direct_dep:
7494
if indirect in dep_item:
7595
if dep_item[indirect]:
76-
comment.append('transitive')
96+
comment_list.append('transitive')
7797
else:
78-
comment.append('direct')
98+
comment_list.append('direct')
7999
else:
80-
comment.append('direct')
100+
comment_list.append('direct')
101+
102+
if f'{package_path}({oss_version})' in self.relation_tree:
103+
rel_items = [f'{self.package_manager_name}:{ri}'
104+
for ri in self.relation_tree[f'{package_path}({oss_version})']]
105+
comment_list.extend(rel_items)
81106

82107
homepage_set = []
83108
homepage = self.dn_url + package_path
84109

85-
if oss_version:
86-
tmp_homepage = f"{homepage}@{oss_version}"
110+
if oss_origin_version:
111+
tmp_homepage = f"{homepage}@{oss_origin_version}"
87112
homepage_set.append(tmp_homepage)
88113
homepage_set.append(homepage)
89114

90115
license_name = ''
91116
dn_loc = ''
92117

93-
if oss_version.startswith('v'):
94-
oss_version = oss_version[1:]
95-
96118
for homepage_i in homepage_set:
97119
try:
98120
res = urllib.request.urlopen(homepage_i)
99121
if res.getcode() == 200:
100122
urlopen_success = True
101123
if homepage_i == homepage:
102124
if oss_version:
103-
comment.append(f'Cannot connect {tmp_homepage}, get info from the latest version.')
125+
comment_list.append(f'Cannot connect {tmp_homepage}, get info from the latest version.')
104126
break
105127
except Exception:
106128
continue
@@ -123,7 +145,7 @@ def parse_oss_information(self, f_name):
123145
logging.warning(f"Fail to parse {package_path} in go mod : {e}")
124146
continue
125147

126-
comment = ', '.join(comment)
148+
comment = ', '.join(comment_list)
127149
sheet_list.append([const.SUPPORT_PACKAE.get(self.package_manager_name),
128150
oss_name, oss_version, license_name, dn_loc, homepage, '', '', comment])
129151

src/fosslight_dependency/package_manager/Nuget.py

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class Nuget(PackageManager):
2424
dn_url = "https://nuget.org/packages/"
2525
packageReference = False
2626
nuget_api_url = 'https://api.nuget.org/v3-flatcontainer/'
27+
dotnet_ver = []
2728

2829
def __init__(self, input_dir, output_dir):
2930
super().__init__(self.package_manager_name, self.dn_url, input_dir, output_dir)
@@ -40,14 +41,13 @@ def parse_oss_information(self, f_name):
4041
sheet_list = []
4142
package_list = []
4243
if self.packageReference:
43-
package_list = self.get_package_list_in_packages_assets(input_fp)
44-
self.get_direct_package_in_packagereference()
44+
package_list = self.get_package_info_in_packagereference(input_fp)
4545
else:
4646
package_list = self.get_package_list_in_packages_config(input_fp)
4747

4848
for oss_origin_name, oss_version in package_list:
4949
try:
50-
oss_name = self.package_manager_name + ":" + oss_origin_name
50+
oss_name = f'{self.package_manager_name}:{oss_origin_name}'
5151

5252
comment = []
5353
dn_loc = ''
@@ -105,8 +105,13 @@ def parse_oss_information(self, f_name):
105105
else:
106106
comment.append('transitive')
107107

108+
if f'{oss_origin_name}({oss_version})' in self.relation_tree:
109+
rel_items = [f'{self.package_manager_name}:{ri}'
110+
for ri in self.relation_tree[f'{oss_origin_name}({oss_version})']]
111+
comment.extend(rel_items)
112+
108113
sheet_list.append([','.join(self.input_package_list_file),
109-
oss_name, oss_version, license_name, dn_loc, homepage, '', '', ','.join(comment)])
114+
oss_name, oss_version, license_name, dn_loc, homepage, '', '', ', '.join(comment)])
110115

111116
except Exception as e:
112117
logger.warning(f"Failed to parse oss information: {e}")
@@ -123,15 +128,50 @@ def get_package_list_in_packages_config(self, input_fp):
123128
package_list.append([p.get("id"), p.get("version")])
124129
return package_list
125130

126-
def get_package_list_in_packages_assets(self, input_fp):
127-
package_list = []
131+
def get_package_info_in_packagereference(self, input_fp):
128132
json_f = json.load(input_fp)
133+
134+
self.get_dotnet_ver_list(json_f)
135+
package_list = self.get_package_list_in_packages_assets(json_f)
136+
self.get_dependency_tree(json_f)
137+
self.get_direct_package_in_packagereference()
138+
139+
return package_list
140+
141+
def get_package_list_in_packages_assets(self, json_f):
142+
package_list = []
129143
for item in json_f['libraries']:
130144
if json_f['libraries'][item]['type'] == 'package':
131145
oss_info = item.split('/')
132146
package_list.append([oss_info[0], oss_info[1]])
133147
return package_list
134148

149+
def get_dotnet_ver_list(self, json_f):
150+
json_project_group = json_f['projectFileDependencyGroups']
151+
for dotnet_ver in json_project_group:
152+
self.dotnet_ver.append(dotnet_ver)
153+
154+
def get_dependency_tree(self, json_f):
155+
json_target = json_f['targets']
156+
for item in json_target:
157+
if item not in self.dotnet_ver:
158+
continue
159+
json_item = json_target[item]
160+
for pkg in json_item:
161+
json_pkg = json_item[pkg]
162+
if 'type' not in json_pkg:
163+
continue
164+
if 'dependencies' not in json_pkg:
165+
continue
166+
if json_pkg['type'] != 'package':
167+
continue
168+
oss_info = pkg.split('/')
169+
self.relation_tree[f'{oss_info[0]}({oss_info[1]})'] = []
170+
for dep in json_pkg['dependencies']:
171+
oss_name = dep
172+
oss_ver = json_pkg['dependencies'][dep]
173+
self.relation_tree[f'{oss_info[0]}({oss_info[1]})'].append(f'{oss_name}({oss_ver})')
174+
135175
def get_direct_package_in_packagereference(self):
136176
for f in os.listdir(self.input_dir):
137177
if os.path.isfile(f) and ((f.split('.')[-1] == 'csproj') or (f.split('.')[-1] == 'xproj')):

0 commit comments

Comments
 (0)