Belle II Software light-2406-ragdoll
test_light_dependencies.py
1#!/usr/bin/env python3
2
3
10
11import os
12import glob
13import re
14import sys
15import subprocess
16import basf2
17from time import time
18
19"""
20Check that no light-release-breaking dependencies have been added.
21
22If you are failing this test you have managed to break light builds, please
23check with the light release manager for more information.
24"""
25
26
27def get_sconscripts(package):
28 """glob to get the path to all sconscript files
29
30 Parameters:
31 package (str): the name of the package directory
32
33 Returns:
34 list(str): a list of all SConscript files
35 """
36 path_to_package = basf2.find_file(package)
37 return glob.glob(f"{path_to_package}/**/SConscript", recursive=True)
38
39
40def get_dependencies(sconscript_filename):
41 """grab all of the LIBS in the sconscript file
42
43 Parameters:
44 sconscript_filename (str): the path to the sconscript file
45
46 Returns:
47 set(str): a set of packages in the env['LIBS'] in this file
48 """
49 # get the " env['LIBS'] " line in the file
50 # (if no LIBS are in the SConscript file then ignore)
51 with open(sconscript_filename) as fi:
52 file_data = fi.read()
53 dependencies = re.search(
54 r"env\['LIBS'\] *= *\[\n*((?:.*?|\n)*?)\n*\]", file_data
55 )
56 if dependencies:
57 dependencies = dependencies.group(1)
58 else:
59 dependencies = ""
60
61 # clean up the list returned from the regex: only want the names of the
62 # basf2 libs (i.e. strings of the form: packagename_module)
63 dependencies = [
64 lb.replace("'", "").replace('"', "").strip()
65 for lb in re.split(",|\n", dependencies)
66 if not lb.count("#") and not lb == ''
67 ]
68 # now just trim only the packagename's from the library names
69 # and make a python set of them
70 package_dependencies = {lb.split("_")[0] for lb in dependencies}
71
72 return package_dependencies
73
74
75def check_dependencies(forbidden, sconscript_files, error=""):
76 """Check that there are no dependencies that are forbidden.
77
78 Parameters:
79 forbidden set(str): a set of packages we don't want to depend on sconscript_files list(str): a list of paths to sconscript files
80 error str: optionally specify the error message
81
82 Returns:
83 int: count of the number of forbidden dependencies found
84 """
85 n_forbidden = 0
86 for sconscript_filename in sconscript_files:
87
88 # get the dependencies from this SConscript file
89 this_dependencies = get_dependencies(sconscript_filename)
90
91 # using the nice and cool and mathsy python set syntax: figure out if
92 # we depend on anything in the forbidden packages list
93 forbidden_packages_dependencies = forbidden.intersection(this_dependencies)
94
95 # if so then throw the error
96 if len(forbidden_packages_dependencies) != 0:
97 print(
98 f"The sconscript file {sconscript_filename} depends on",
99 forbidden_packages_dependencies,
100 error,
101 )
102 n_forbidden += 1
103 return n_forbidden
104
105
106if __name__ == "__main__":
107
108 # grab all of the light release packages
109 # (defined by the .light file for the sparse checkout)
110 light_file = basf2.find_file(".light")
111 with open(light_file) as fi:
112 light_packages = [li.strip().replace("/", "") for li in fi if li.strip().endswith("/")]
113
114 # we also need all packages (to compare), for this use b2code-package-list.
115 # note that b2code-package-list has to be executed from the top basf2 directory,
116 # since it requires the presence of the .release file: we use cwd for this.
117 all_packages = subprocess.check_output(
118 ["b2code-package-list"], cwd=os.path.dirname(light_file),
119 )
120 all_packages = all_packages.decode("utf-8").strip().split(" ")
121
122 # the forbidden packages
123 non_light_packages = set(all_packages).difference(set(light_packages))
124
125 # sum up the return codes
126 return_code_sum = 0
127
128 # run the check over all packages - just a dumb nested loop
129 start = time()
130 for package in light_packages:
131 sconscript_files = get_sconscripts(package)
132 return_code_sum += check_dependencies(
133 non_light_packages, sconscript_files, "This breaks light releases! Sorry."
134 )
135
136 # test finished, now report
137 print("Test of light dependencies, the loop took:", time() - start, "seconds to run")
138 print("There were", return_code_sum, "forbidden dependencies")
139
140 sys.exit(return_code_sum)
141