Belle II Software  light-2403-persian
test_light_dependencies.py
1 #!/usr/bin/env python3
2 
3 
10 
11 import os
12 import glob
13 import re
14 import sys
15 import subprocess
16 import basf2
17 from time import time
18 
19 """
20 Check that no light-release-breaking dependencies have been added.
21 
22 If you are failing this test you have managed to break light builds, please
23 check with the light release manager for more information.
24 """
25 
26 
27 def 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 
40 def 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 
75 def 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
80  sconscript_files list(str): a list of paths to sconscript files
81  error str: optionally specify the error message
82 
83  Returns:
84  int: count of the number of forbidden dependencies found
85  """
86  n_forbidden = 0
87  for sconscript_filename in sconscript_files:
88 
89  # get the dependencies from this SConscript file
90  this_dependencies = get_dependencies(sconscript_filename)
91 
92  # using the nice and cool and mathsy python set syntax: figure out if
93  # we depend on anything in the forbidden packages list
94  forbidden_packages_dependencies = forbidden.intersection(this_dependencies)
95 
96  # if so then throw the error
97  if len(forbidden_packages_dependencies) != 0:
98  print(
99  f"The sconscript file {sconscript_filename} depends on",
100  forbidden_packages_dependencies,
101  error,
102  )
103  n_forbidden += 1
104  return n_forbidden
105 
106 
107 if __name__ == "__main__":
108 
109  # grab all of the light release packages
110  # (defined by the .light file for the sparse checkout)
111  light_file = basf2.find_file(".light")
112  with open(light_file) as fi:
113  light_packages = [li.strip().replace("/", "") for li in fi if li.strip().endswith("/")]
114 
115  # we also need all packages (to compare), for this use b2code-package-list.
116  # note that b2code-package-list has to be executed from the top basf2 directory,
117  # since it requires the presence of the .release file: we use cwd for this.
118  all_packages = subprocess.check_output(
119  ["b2code-package-list"], cwd=os.path.dirname(light_file),
120  )
121  all_packages = all_packages.decode("utf-8").strip().split(" ")
122 
123  # the forbidden packages
124  non_light_packages = set(all_packages).difference(set(light_packages))
125 
126  # sum up the return codes
127  return_code_sum = 0
128 
129  # run the check over all packages - just a dumb nested loop
130  start = time()
131  for package in light_packages:
132  sconscript_files = get_sconscripts(package)
133  return_code_sum += check_dependencies(
134  non_light_packages, sconscript_files, "This breaks light releases! Sorry."
135  )
136 
137  # test finished, now report
138  print("Test of light dependencies, the loop took:", time() - start, "seconds to run")
139  print("There were", return_code_sum, "forbidden dependencies")
140 
141  sys.exit(return_code_sum)