Skip to content

Commit 1adf955

Browse files
authored
Merge pull request #83 from fosslight/develop
Support to comment direct/transitive type
2 parents 78e1012 + fab7d31 commit 1adf955

File tree

25 files changed

+1104
-77
lines changed

25 files changed

+1104
-77
lines changed

.reuse/dep5

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,8 @@ License: Apache-2.0
9292

9393
Files: tests/test_swift2/*
9494
Copyright: 2022 LG Electronics
95-
License: Apache-2.0
95+
License: Apache-2.0
96+
97+
Files: tests/test_gradle2/*
98+
Copyright: 2014 Netflix
99+
License: Apache-2.0

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ pyyaml
66
lastversion
77
fosslight_util>=1.3.12
88
PyGithub
9+
requirements-parser

src/fosslight_dependency/_analyze_dependency.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222

2323

2424
def analyze_dependency(package_manager_name, input_dir, output_dir, pip_activate_cmd='', pip_deactivate_cmd='',
25-
output_custom_dir='', app_name=const.default_app_name, github_token='', manifest_file_name=[]):
25+
output_custom_dir='', app_name=const.default_app_name, github_token='', manifest_file_name=[],
26+
direct=True):
2627
ret = True
2728
package_sheet_list = []
2829

@@ -53,8 +54,14 @@ def analyze_dependency(package_manager_name, input_dir, output_dir, pip_activate
5354

5455
if manifest_file_name:
5556
package_manager.set_manifest_file(manifest_file_name)
57+
58+
if direct:
59+
package_manager.set_direct_dependencies(direct)
5660
ret = package_manager.run_plugin()
5761
if ret:
62+
if direct:
63+
package_manager.parse_direct_dependencies()
64+
5865
for f_name in package_manager.input_package_list_file:
5966
logger.info(f"Parse oss information with file: {f_name}")
6067

@@ -69,4 +76,6 @@ def analyze_dependency(package_manager_name, input_dir, output_dir, pip_activate
6976
else:
7077
logger.error(f"### Fail to analyze: {package_manager_name}")
7178

79+
del package_manager
80+
7281
return ret, package_sheet_list

src/fosslight_dependency/_package_manager.py

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import platform
1010
import re
1111
import base64
12+
import subprocess
13+
import shutil
14+
import copy
1215
import fosslight_util.constant as constant
1316
import fosslight_dependency.constant as const
1417

@@ -27,9 +30,15 @@
2730

2831
class PackageManager:
2932
input_package_list_file = []
33+
direct_dep = False
34+
total_dep_list = []
35+
direct_dep_list = []
3036

3137
def __init__(self, package_manager_name, dn_url, input_dir, output_dir):
3238
self.input_package_list_file = []
39+
self.direct_dep = False
40+
self.total_dep_list = []
41+
self.direct_dep_list = []
3342
self.package_manager_name = package_manager_name
3443
self.input_dir = input_dir
3544
self.output_dir = output_dir
@@ -39,8 +48,22 @@ def __init__(self, package_manager_name, dn_url, input_dir, output_dir):
3948
self.platform = platform.system()
4049
self.license_scanner_bin = check_license_scanner(self.platform)
4150

51+
def __del__(self):
52+
self.input_package_list_file = []
53+
self.direct_dep = False
54+
self.total_dep_list = []
55+
self.direct_dep_list = []
56+
self.package_manager_name = ''
57+
self.input_dir = ''
58+
self.output_dir = ''
59+
self.dn_url = ''
60+
self.manifest_file_name = []
61+
4262
def run_plugin(self):
43-
logger.info(f"This package manager({self.package_manager_name}) skips the step to run plugin.")
63+
if self.package_manager_name == const.GRADLE or self.package_manager_name == const.ANDROID:
64+
self.run_gradle_task()
65+
else:
66+
logger.info(f"This package manager({self.package_manager_name}) skips the step to run plugin.")
4467
return True
4568

4669
def append_input_package_list_file(self, input_package_file):
@@ -49,6 +72,86 @@ def append_input_package_list_file(self, input_package_file):
4972
def set_manifest_file(self, manifest_file_name):
5073
self.manifest_file_name = manifest_file_name
5174

75+
def set_direct_dependencies(self, direct):
76+
self.direct_dep = direct
77+
78+
def parse_direct_dependencies(self):
79+
pass
80+
81+
def run_gradle_task(self):
82+
dependency_tree_fname = 'tmp_dependency_tree.txt'
83+
if os.path.isfile(const.SUPPORT_PACKAE.get(self.package_manager_name)):
84+
gradle_backup = f'{const.SUPPORT_PACKAE.get(self.package_manager_name)}_bk'
85+
86+
shutil.copy(const.SUPPORT_PACKAE.get(self.package_manager_name), gradle_backup)
87+
ret = self.add_allDeps_in_gradle()
88+
if not ret:
89+
return
90+
91+
ret = self.exeucte_gradle_task(dependency_tree_fname)
92+
if ret != 0:
93+
self.set_direct_dependencies(False)
94+
logger.warning("Failed to run allDeps task.")
95+
else:
96+
self.parse_dependency_tree(dependency_tree_fname)
97+
98+
if os.path.isfile(dependency_tree_fname):
99+
os.remove(dependency_tree_fname)
100+
101+
if os.path.isfile(gradle_backup):
102+
os.remove(const.SUPPORT_PACKAE.get(self.package_manager_name))
103+
shutil.move(gradle_backup, const.SUPPORT_PACKAE.get(self.package_manager_name))
104+
105+
def add_allDeps_in_gradle(self):
106+
ret = False
107+
configuration = 'project.configurations.runtimeClasspath, project.configurations.runtime'
108+
if self.package_manager_name == 'android':
109+
configuration = 'project.configurations.releaseRuntimeClasspath'
110+
111+
allDeps = f'''allprojects {{
112+
task allDeps(type: DependencyReportTask) {{
113+
doFirst{{
114+
try {{
115+
configurations = [{configuration}] as Set }}
116+
catch(UnknownConfigurationException) {{}}
117+
}}
118+
}}
119+
}}'''
120+
try:
121+
with open(const.SUPPORT_PACKAE.get(self.package_manager_name), 'a', encoding='utf8') as f:
122+
f.write(allDeps)
123+
ret = True
124+
except Exception as e:
125+
logging.warning(f"Cannot add the allDeps task in build.gradle: {e}")
126+
127+
return ret
128+
129+
def exeucte_gradle_task(self, dependency_tree_fname):
130+
if os.path.isfile('gradlew') or os.path.isfile('gradlew.bat'):
131+
if self.platform == const.WINDOWS:
132+
cmd_gradle = "gradlew.bat"
133+
else:
134+
cmd_gradle = "./gradlew"
135+
else:
136+
return 1
137+
cmd = f"{cmd_gradle} allDeps > {dependency_tree_fname}"
138+
139+
ret = subprocess.call(cmd, shell=True)
140+
return ret
141+
142+
def parse_dependency_tree(self, f_name):
143+
with open(f_name, 'r', encoding='utf8') as input_fp:
144+
for i, line in enumerate(input_fp.readlines()):
145+
try:
146+
line_bk = copy.deepcopy(line)
147+
re_result = re.findall(r'\-\-\-\s([^\:\s]+\:[^\:\s]+)\:([^\:\s]+)', line)
148+
if re_result:
149+
self.total_dep_list.append(re_result[0][0])
150+
if re.match(r'^[\+|\\]\-\-\-\s([^\:\s]+\:[^\:\s]+)\:([^\:\s]+)', line_bk):
151+
self.direct_dep_list.append(re_result[0][0])
152+
except Exception as e:
153+
logger.error(f"Failed to parse dependency tree: {e}")
154+
52155

53156
def version_refine(oss_version):
54157
version_cmp = oss_version.upper()

src/fosslight_dependency/package_manager/Android.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def parse_oss_information(self, f_name):
3838
sheet_list = []
3939

4040
for i, line in enumerate(input_fp.readlines()):
41+
comment = ''
4142
split_str = line.strip().split("\t")
4243
if i < 2:
4344
continue
@@ -48,6 +49,17 @@ def parse_oss_information(self, f_name):
4849
idx, manifest_file, oss_name, oss_version, license_name, dn_loc, homepage = split_str
4950
else:
5051
continue
51-
sheet_list.append([manifest_file, oss_name, oss_version, license_name, dn_loc, homepage, '', '', ''])
52+
53+
if self.total_dep_list:
54+
if oss_name not in self.total_dep_list:
55+
continue
56+
57+
if self.direct_dep:
58+
if oss_name in self.direct_dep_list:
59+
comment = 'direct'
60+
else:
61+
comment = 'transitive'
62+
63+
sheet_list.append([manifest_file, oss_name, oss_version, license_name, dn_loc, homepage, '', '', comment])
5264

5365
return sheet_list

src/fosslight_dependency/package_manager/Carthage.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def __init__(self, input_dir, output_dir, github_token):
3636
def parse_oss_information(self, f_name):
3737
github = "github"
3838
checkout_dir_list = get_checkout_dirname()
39+
comment = ''
3940
with open(f_name, 'r', encoding='utf8') as input_fp:
4041
sheet_list = []
4142
g = ''
@@ -89,14 +90,36 @@ def parse_oss_information(self, f_name):
8990
logger.warning(f"Failed to get license with github api: {e}")
9091
license_name == ''
9192

93+
if self.direct_dep_list:
94+
if oss_origin_name in self.direct_dep_list:
95+
comment = 'direct'
96+
else:
97+
comment = 'transitive'
98+
9299
sheet_list.append([const.SUPPORT_PACKAE.get(self.package_manager_name),
93-
oss_name, oss_version, license_name, dn_loc, homepage, '', '', ''])
100+
oss_name, oss_version, license_name, dn_loc, homepage, '', '', comment])
94101

95102
except Exception as e:
96103
logger.warning(f"Failed to parse oss information: {e}")
97104

98105
return sheet_list
99106

107+
def parse_direct_dependencies(self):
108+
self.direct_dep = True
109+
cartfile = 'Cartfile'
110+
if os.path.exists(cartfile):
111+
with open(cartfile, 'r', encoding='utf8') as input_fp:
112+
for i, line in enumerate(input_fp.readlines()):
113+
re_result = re.findall(r'(github|git)[\s]\"(\S*)\"[\s]\"(\S*)\"', line)
114+
try:
115+
oss_path = re_result[0][1]
116+
if oss_path.endswith('.git'):
117+
oss_path = oss_path[:-4]
118+
oss_origin_name = oss_path.split('/')[-1]
119+
self.direct_dep_list.append(oss_origin_name)
120+
except Exception as e:
121+
logger.warning(f"Failed to parse Cartfile: {e}")
122+
100123

101124
def get_checkout_dirname():
102125
checkout_dir_list = []

src/fosslight_dependency/package_manager/Cocoapods.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
_spec_repos = 'SPEC REPOS'
1919
_external_sources = 'EXTERNAL SOURCES'
20+
_dependencies = 'DEPENDENCIES'
2021
_source_type = ['git', 'http', 'svn', 'hg']
2122

2223

@@ -38,6 +39,7 @@ def parse_oss_information(self, f_name):
3839
pod_not_in_spec_list = []
3940
spec_repo_list = []
4041
external_source_list = []
42+
comment = ''
4143

4244
if _spec_repos in podfile_yaml:
4345
for spec_item_key in podfile_yaml[_spec_repos]:
@@ -51,6 +53,13 @@ def parse_oss_information(self, f_name):
5153
logger.error("Cannot fint SPEC REPOS or EXTERNAL SOURCES in Podfile.lock.")
5254
return ''
5355

56+
for dep_key in podfile_yaml[_dependencies]:
57+
dep_key_re = re.findall(r'(^\S*)', dep_key)
58+
dep_name = dep_key_re[0]
59+
if '/' in dep_name:
60+
dep_name = dep_name.split('/')[0]
61+
self.direct_dep_list.append(dep_name)
62+
5463
for pods_list in podfile_yaml['PODS']:
5564
if not isinstance(pods_list, str):
5665
for pods_list_key, pods_list_item in pods_list.items():
@@ -71,6 +80,11 @@ def parse_oss_information(self, f_name):
7180

7281
for pod_oss in pod_in_sepc_list:
7382
try:
83+
if self.direct_dep:
84+
if pod_oss[0] in self.direct_dep_list:
85+
comment = 'direct'
86+
else:
87+
comment = 'transitive'
7488
if pod_oss[0] in external_source_list:
7589
podspec_filename = pod_oss[0] + '.podspec.json'
7690
spec_file_path = os.path.join("Pods", "Local Podspecs", podspec_filename)
@@ -98,7 +112,7 @@ def parse_oss_information(self, f_name):
98112
oss_name, oss_version, license_name, dn_loc, homepage = self.get_oss_in_podspec(spec_file_path)
99113

100114
sheet_list.append([const.SUPPORT_PACKAE.get(self.package_manager_name),
101-
oss_name, oss_version, license_name, dn_loc, homepage, '', '', ''])
115+
oss_name, oss_version, license_name, dn_loc, homepage, '', '', comment])
102116
except Exception as e:
103117
logger.warning(f"It failed to get {pod_oss[0]}:{e}")
104118
logger.warning(traceback.format_exc())
@@ -131,6 +145,9 @@ def get_oss_in_podspec(self, spec_file_path):
131145

132146
return oss_name, oss_version, license_name, dn_loc, homepage
133147

148+
def parse_direct_dependencies(self):
149+
self.direct_dep = True
150+
134151

135152
def compile_pods_item(pods_item, spec_repo_list, pod_in_sepc_list, pod_not_in_spec_list):
136153
pods_item_re = re.findall(r'(\S*)\s{1}\((.*)\)', pods_item)

0 commit comments

Comments
 (0)