16 import xml.sax.saxutils
as XSS
17 from pathlib
import Path
18 from subprocess
import PIPE, Popen
19 from typing
import Any, Dict, List
28 return f
'<pre><code class="language-{self.language}">{XSS.escape(self.code)}</code></pre>'
33 return any(re.search(p, platform_id)
for p
in unsupported_platforms)
39 return dumper.represent_scalar(
"tag:yaml.org,2002:str", data, style=
"|")
40 return dumper.represent_scalar(
"tag:yaml.org,2002:str", data)
45 Send a signal to a process and all its child processes (starting from the
48 ps_cmd = [
"ps",
"--no-headers",
"-o",
"pid",
"--ppid", str(ppid)]
51 get_children = Popen(ps_cmd, stdout=PIPE, stderr=PIPE, env={})
52 children =
map(int, get_children.communicate()[0].split())
53 for child
in children:
57 except OSError
as err:
64 Locates an executable in the executables path ($PATH) and returns the full
65 path to it. An application is looked for with or without the '.exe' suffix.
66 If the executable cannot be found, None is returned
68 if os.path.isabs(executable):
69 if not os.path.isfile(executable):
70 if executable.endswith(
".exe"):
71 if os.path.isfile(executable[:-4]):
72 return executable[:-4]
74 executable = os.path.split(executable)[1]
77 for d
in os.environ.get(
"PATH").split(os.pathsep):
78 fullpath = os.path.join(d, executable)
79 if os.path.isfile(fullpath):
81 elif executable.endswith(
".exe")
and os.path.isfile(fullpath[:-4]):
88 Return the platform Id defined in CMTCONFIG or SCRAM_ARCH.
92 if "BINARY_TAG" in os.environ:
93 arch = os.environ[
"BINARY_TAG"]
94 elif "CMTCONFIG" in os.environ:
95 arch = os.environ[
"CMTCONFIG"]
96 elif "SCRAM_ARCH" in os.environ:
97 arch = os.environ[
"SCRAM_ARCH"]
98 elif os.environ.get(
"ENV_CMAKE_BUILD_TYPE",
"")
in (
105 elif os.environ.get(
"ENV_CMAKE_BUILD_TYPE",
"")
in (
120 def platform_split(p):
121 return set(re.split(
r"[-+]", p))
if p
else set()
124 dirname, basename = os.path.split(reference)
128 for suffix
in (
".yaml",
".yml"):
129 if basename.endswith(suffix):
130 prefix = f
"{basename[:-(len(suffix))]}."
134 prefix = f
"{basename}."
137 flags_slice = slice(len(prefix), -len(suffix)
if suffix
else None)
141 Extract the platform flags from a filename, return None if name does not match prefix and suffix
143 if name.startswith(prefix)
and name.endswith(suffix):
144 return platform_split(name[flags_slice])
148 if "do0" in platform:
153 (get_flags(name), name)
154 for name
in (os.listdir(dirname)
if os.path.isdir(dirname)
else [])
156 if flags
and platform.issuperset(flags)
162 return os.path.join(dirname, candidates[-1][1])
163 return os.path.join(dirname, basename)
166 def filter_dict(d: Dict[str, Any], ignore_re: re.Pattern) -> Dict[str, Any]:
168 Recursively filter out keys from the dictionary that match the ignore pattern.
171 for k, v
in d.items():
172 if not ignore_re.match(k):
173 if isinstance(v, dict):
180 def compare_dicts(d1: Dict[str, Any], d2: Dict[str, Any], ignore_re: str =
None) -> str:
182 Compare two dictionaries and return the diff as a string, ignoring keys that match the regex.
184 ignore_re = re.compile(ignore_re)
188 return "\n" +
"\n".join(
189 difflib.unified_diff(
190 pprint.pformat(filtered_d1).splitlines(),
191 pprint.pformat(filtered_d2).splitlines(),
197 h_count_re = re.compile(
198 r"^(.*)(?:SUCCESS|INFO)\s+Booked (\d+) Histogram\(s\) :\s+([\s\w=-]*)"
204 Parse the TTree summary table in lines, starting from pos.
205 Returns a tuple with the dictionary with the digested informations and the
206 position of the first line after the summary.
213 return [f.strip()
for f
in l.strip(
"*\n").split(
":", 2)]
218 cols = splitcols(ll[0])
222 r[
"Name"], r[
"Title"] = cols[1:]
227 r[
"Title"] = ll[1].strip(
"*\n").split(
"|")[1].strip()
231 cols = splitcols(ll[1 + delta_i])
232 r[
"Entries"] = int(cols[1])
234 sizes = cols[2].split()
235 r[
"Total size"] = int(sizes[2])
236 if sizes[-1] ==
"memory":
239 r[
"File size"] = int(sizes[-1])
241 cols = splitcols(ll[2 + delta_i])
242 sizes = cols[2].split()
243 if cols[0] ==
"Baskets":
244 r[
"Baskets"] = int(cols[1])
245 r[
"Basket size"] = int(sizes[2])
246 r[
"Compression"] = float(sizes[-1])
250 def nextblock(lines, i):
252 dots = re.compile(
r"^\.+$")
253 stars = re.compile(
r"^\*+$")
257 and not dots.match(lines[i + delta_i][1:-1])
258 and not stars.match(lines[i + delta_i])
263 if i < (count - 3)
and lines[i].startswith(
"*Tree"):
264 i_nextblock = nextblock(lines, i)
265 result = parseblock(lines[i:i_nextblock])
266 result[
"Branches"] = {}
268 while i < (count - 3)
and lines[i].startswith(
"*Br"):
269 if i < (count - 2)
and lines[i].startswith(
"*Branch "):
273 i_nextblock = nextblock(lines, i)
274 if i_nextblock >= count:
276 branch = parseblock(lines[i:i_nextblock])
277 result[
"Branches"][branch[
"Name"]] = branch
285 Extract the histograms infos from the lines starting at pos.
286 Returns the position of the first line after the summary block.
289 h_table_head = re.compile(
290 r'(?:SUCCESS|INFO)\s+(1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"'
292 h_short_summ = re.compile(
r"ID=([^\"]+)\s+\"([^\"]*)\"\s+(.*)")
297 m = h_count_re.search(lines[pos])
298 name = m.group(1).strip()
299 total = int(m.group(2))
301 for k, v
in [x.split(
"=")
for x
in m.group(3).split()]:
304 header[
"Total"] = total
308 m = h_table_head.search(lines[pos])
311 t = t.replace(
" profile",
"Prof")
318 if l.startswith(
" | ID"):
320 titles = [x.strip()
for x
in l.split(
"|")][1:]
322 while pos < nlines
and lines[pos].startswith(
" |"):
324 values = [x.strip()
for x
in l.split(
"|")][1:]
326 for i
in range(len(titles)):
327 hcont[titles[i]] = values[i]
328 cont[hcont[
"ID"]] = hcont
330 elif l.startswith(
" ID="):
331 while pos < nlines
and lines[pos].startswith(
" ID="):
333 x.strip()
for x
in h_short_summ.search(lines[pos]).groups()
335 cont[values[0]] = values
338 raise RuntimeError(
"Cannot understand line %d: '%s'" % (pos, l))
342 summ[d][
"header"] = header
347 summ[name] = {
"header": header}
353 Scan stdout to find ROOT Histogram summaries and digest them.
355 outlines = stdout.splitlines()
if hasattr(stdout,
"splitlines")
else stdout
356 nlines = len(outlines) - 1
364 match = h_count_re.search(outlines[pos])
365 while pos < nlines
and not match:
367 match = h_count_re.search(outlines[pos])
370 summaries.update(summ)
376 Scan stdout to find ROOT TTree summaries and digest them.
378 stars = re.compile(
r"^\*+$")
379 outlines = stdout.splitlines()
if hasattr(stdout,
"splitlines")
else stdout
380 nlines = len(outlines)
386 while i < nlines
and not stars.match(outlines[i]):
391 trees[tree[
"Name"]] = tree
397 return Path(sys.modules[cls.__module__].__file__)