File: expand-matrices

package info (click to toggle)
charliecloud 0.43-1
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 3,084 kB
  • sloc: python: 6,021; sh: 4,284; ansic: 3,863; makefile: 598
file content (95 lines) | stat: -rwxr-xr-x 2,652 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/usr/bin/env python3

# Input on stdin; output on stdout.

# WARNING: This script assumes throughout that dictionaries retain their
# order, which is guaranteed as of Python 3.7.

import copy
import itertools
import os
import string
import sys

import yaml
import yaml.representer

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)) + "/../../lib")
import charliecloud as ch


def main():
   ch.INFO("starting")
   yin = yaml.safe_load(sys.stdin)
   yout = dict()
   assert(isinstance(yin, dict))
   ch.INFO("loaded top-level dictionary with %d keys" % len(yin))
   ch.INFO("expanding")
   for (name, job) in yin.items():
      ch.INFO("job: %s ... " % name, end="")
      if ("parallel" in job):
         ch.INFO("  expanding")
         yout |= expand_matrices(name, job)
      else:
         ch.INFO("  not matrixed")
         yout[name] = job
   ch.INFO("updating needs")
   for (name, job) in yout.items():
      ch.INFO("job: %s ..." % name, end="")
      if ("needs" in job):
         ch.INFO("  updating")
         needs_update(job)
      else:
         ch.INFO("  no needs")
   ch.INFO("outputting")
   yaml.dump(yout, sys.stdout, indent=2,
                               width=80,
                               allow_unicode=True)
   ch.INFO("done")


def expand_matrices(name, job):
   jobs = dict()
   for (i, g) in enumerate(job["parallel"]["matrix"], 1):
      ch.INFO("  group %d:" % i)
      group_ct = 0
      for vs in list(itertools.product(*g.values())):
         (name_sub, job_sub) = expand_one(name, job, dict(zip(g.keys(), vs)))
         assert (name_sub not in jobs)
         ch.INFO("    %s" % name_sub)
         jobs[name_sub] = job_sub
         group_ct += 1
      ch.INFO("    expanded to %d jobs" % group_ct)
   ch.INFO("  total jobs: %d" % len(jobs))
   return jobs


def expand_one(name, job, row):
   job = copy.deepcopy(job)
   del job["parallel"]
   job["variables"] = job.get("variables", dict()) | row
   return (name_expand(name, row), job)


def name_expand(name, row):
   assert (name[-1] == "@")
   return name + "/".join(row.values())


def needs_update(job):
   # this lets us use shell-style variable substitution
   job["needs"] = [string.Template(n).substitute(job["variables"])
                   for n in job["needs"]]


# Use block style for multi-line strings, default for other strings.
def multiline_block(dumper, data):
   if "\n" in data:
      return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
   else:
      return yaml.representer.SafeRepresenter.represent_str(dumper, data)
yaml.add_representer(str, multiline_block)


if (__name__ == "__main__"):
   main()