NixOS/nixops — pull request #131 by aszlig (2013-08-22 00:25:26+00:00)
Title: Use a pretty-printer for generating the physical specification.

This implements a pretty printer for Nix expressions, which converts native Python datatypes to Nix expressions. Although we get consistency and "pretty output", the main reasons for doing this are:

- Avoid clashes in attribute sets and lists.
- Correctly escape strings and other values (for example attribute keys).
- Fix wrong machine spec merging due to 74e37832683abafd2ad680c8636d17b81c994cbf (the revert was because of security implications, due to private keys ending up in the Nix store).

Fortunately, in case of NixOps, we don't need a full pretty printer and only handle scalar types, attributes, lists and a lightweight form of function declarations. Everything else can be given using `RawValue`s, which allow to inject an arbitrary expression, but as the name implies, no form of processing or escaping will be done on these values.

So far, this is what the function `py2nix()` does, but we also need the counterpart (`nix2py()`) in order to merge existing raw Nix expressions. As with `py2nix()`, this parser doesn't parse the full Nix language, but a subset, which is everything that we need in order to correctly merge attribute sets and lists.

Currently, the parser is only used for the Hetzner backend, as we use `nixos-hardware-scan` and `nixpart` there, which to my knowledge is the only place in NixOps where you get back raw Nix expressions.

Both the parser and the pretty printer are pure functions (although not internally), so they shouldn't introduce any more side-effects.

Tested against: unit tests, none backend, hetzner backend
CC for review: @edolstra, @rbvermaa