|
| 1 | +import collections |
| 2 | +import json |
| 3 | +import sys |
| 4 | + |
| 5 | +class Key: |
| 6 | + def __init__(self, path): |
| 7 | + self.path = path |
| 8 | + def __hash__(self): |
| 9 | + result = 0 |
| 10 | + for id in self.path: |
| 11 | + result ^= hash(id) |
| 12 | + return result |
| 13 | + def __eq__(self, other): |
| 14 | + return type(self) is type(other) and self.path == other.path |
| 15 | + |
| 16 | +Option = collections.namedtuple('Option', ['name', 'value']) |
| 17 | + |
| 18 | +# pivot a dict of options keyed by their display name to a dict keyed by their path |
| 19 | +def pivot(options): |
| 20 | + result = dict() |
| 21 | + for (name, opt) in options.items(): |
| 22 | + result[Key(opt['loc'])] = Option(name, opt) |
| 23 | + return result |
| 24 | + |
| 25 | +# pivot back to indexed-by-full-name |
| 26 | +# like the docbook build we'll just fail if multiple options with differing locs |
| 27 | +# render to the same option name. |
| 28 | +def unpivot(options): |
| 29 | + result = dict() |
| 30 | + for (key, opt) in options.items(): |
| 31 | + if opt.name in result: |
| 32 | + raise RuntimeError( |
| 33 | + 'multiple options with colliding ids found', |
| 34 | + opt.name, |
| 35 | + result[opt.name]['loc'], |
| 36 | + opt.value['loc'], |
| 37 | + ) |
| 38 | + result[opt.name] = opt.value |
| 39 | + return result |
| 40 | + |
| 41 | +options = pivot(json.load(open(sys.argv[1], 'r'))) |
| 42 | +overrides = pivot(json.load(open(sys.argv[2], 'r'))) |
| 43 | + |
| 44 | +# fix up declaration paths in lazy options, since we don't eval them from a full nixpkgs dir |
| 45 | +for (k, v) in options.items(): |
| 46 | + v.value['declarations'] = list(map(lambda s: f'nixos/modules/{s}', v.value['declarations'])) |
| 47 | + |
| 48 | +# merge both descriptions |
| 49 | +for (k, v) in overrides.items(): |
| 50 | + cur = options.setdefault(k, v).value |
| 51 | + for (ok, ov) in v.value.items(): |
| 52 | + if ok == 'declarations': |
| 53 | + decls = cur[ok] |
| 54 | + for d in ov: |
| 55 | + if d not in decls: |
| 56 | + decls += [d] |
| 57 | + elif ok == "type": |
| 58 | + # ignore types of placeholder options |
| 59 | + if ov != "_unspecified" or cur[ok] == "_unspecified": |
| 60 | + cur[ok] = ov |
| 61 | + elif ov is not None or cur.get(ok, None) is None: |
| 62 | + cur[ok] = ov |
| 63 | + |
| 64 | +# check that every option has a description |
| 65 | +# TODO: nixos-rebuild with flakes may hide the warning, maybe turn on -L by default for those? |
| 66 | +for (k, v) in options.items(): |
| 67 | + if v.value.get('description', None) is None: |
| 68 | + print(f"\x1b[1;31mwarning: option {v.name} has no description\x1b[0m", file=sys.stderr) |
| 69 | + v.value['description'] = "This option has no description." |
| 70 | + |
| 71 | +json.dump(unpivot(options), fp=sys.stdout) |
0 commit comments