test_nix_expr: Reorganize to use a base class.

This is to allow for different test cases for Py2NixTest and Nix2PyTest,
while avoiding to duplicate common tests.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
nix_expr: Allow to use Function for calls as well.

There is only a subtle difference between Function as a definition and
as a call, as the function head is a raw value. So, if you want to
create a function call, you could use something like:

Function("function_to_call arg1 arg2", arg3)

To produce something like this:

function_to_call arg1 arg2 [ "whatever" "expr" "is" "in" "arg3" ]

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
nix_expr: Improve and rename merge_dicts().

The function is now called nixmerge() and is able to merge not only
dicts but also lists and maybe more someday.

One limitation is that it cannot merge nested lists and or lists
containing dicts, because the merge is done with a union of two sets and
all items within a set need to be hashable.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
nix_expr: Ignore case when matching identifiers.

This actually HURTS a LOT. Especially because all identifiers in the
test cases are lower case. The tests now have a lot more variation if it
comes to the use of lower and upper case letters in identifiers.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
nix_expr: Correctly parse and encode empty exprs.

Outputs like "foo = [  ];" really look ugly, so let's make those empty
values RawValues() when pretty-printing. Also, when parsing, in case of
strings, we need to make sure we catch empty values with the RE_STRING
regular expression.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
nix_expr: Fix off-by-one error in _parse_keyval().

Tho position is already passed by the outor function incremented by one.
So if we have a quite dense input, we might end up skipping characters
and thus get to the end of the input.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
nix_expr: Fix encoding nested attribute keys.

If we have something like { "/" = b; } everything is fine, but I
actually forget to correctly encode all subnodes, so { a."/" = b; } was
encoded as { a./ = b; }, which quite obviously will cause the evaluation
to fail.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
deployment: Integrate pretty printer.

Now, this should switch almost everything from accumulating lines to
using our new pretty-printer. Within the Hetzner backend we also had to
use the parser, because the outputs of nixos-hardware-scan and nixpart
are Nix expressions. So using a simple regex won't help us there,
because the output of these programs might change.

The structure of the get_physical_spec() method of Deployment still is
inherently impure, even though we now have a way more elegant solution
using the pretty printer.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
deployment: Wrap physical spec in a function.

Before introducing the pretty-printer, the physical spec had
{ config, pkgs, ... } as the function head. So to avoid unnecessarily
breaking stuff that might rely on it, let's re-add it now.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
nix_expr: Fix docstring for py2nix().

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
nix_expr: Add docstring to nix2py().

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
nix_expr: Provide error msgs for ParseFailure's.

"Parse error at position X" could be a bit misleading sometimes, so
adding descriptive error messages should give more insight on why
parsing didn't succeed.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>