f2/nix: provide a function to serialise python objects to nix code
Change-Id: I863029263edbc701a18b18da4b58fcb35f575614
This commit is contained in:
@@ -16,8 +16,11 @@ from testlib.fixtures.command import CommandResult, Command
|
||||
from testlib.fixtures.env import ManagedEnv
|
||||
from testlib.utils import is_value_of_type
|
||||
|
||||
from textwrap import dedent
|
||||
|
||||
|
||||
type _NixSettingValue = str | int | list[str] | bool | None
|
||||
type _NixValue = str | int | float | list[_NixValue] | dict[str, _NixValue] | bool | None
|
||||
|
||||
|
||||
def _serialise_config(value: _NixSettingValue) -> str:
|
||||
@@ -32,6 +35,39 @@ def _serialise_config(value: _NixSettingValue) -> str:
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
def serialise_nix(value: _NixValue) -> str:
|
||||
"""
|
||||
Serialises the given python object into a nix represenatation.
|
||||
NOTE: this interface does not allow accessing variables unless using interpolation, as all strings will be surrounded by quotes.
|
||||
"""
|
||||
|
||||
def escape(v: str) -> str:
|
||||
if "\\r" in v:
|
||||
raise ValueError("\\r is not supported for conversion")
|
||||
escaped = v.replace("\\", "\\\\").replace("$", "\\$").replace('"', '\\"')
|
||||
return f'"{escaped}"'
|
||||
|
||||
if is_value_of_type(value, list[_NixValue.__value__]):
|
||||
return f"[{' '.join([serialise_nix(v) for v in value])}]"
|
||||
if is_value_of_type(value, dict[str, _NixValue.__value__]):
|
||||
return dedent(f"""
|
||||
{{
|
||||
{"\n ".join([f"{escape(k)} = {serialise_nix(v)};" for k, v in value.items()])}
|
||||
}}
|
||||
""")
|
||||
if is_value_of_type(value, bool):
|
||||
return "true" if value else "false"
|
||||
if is_value_of_type(value, int | float):
|
||||
return str(value)
|
||||
if is_value_of_type(value, str):
|
||||
return escape(value)
|
||||
if is_value_of_type(value, None):
|
||||
return "null"
|
||||
|
||||
msg = f"Value is unsupported in nix code: {value!r}"
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
class NixSettings:
|
||||
"""Settings for invoking Nix"""
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@ from pathlib import Path
|
||||
import pytest
|
||||
|
||||
from testlib.fixtures.env import ManagedEnv
|
||||
from testlib.fixtures.nix import NixSettings
|
||||
from testlib.fixtures.nix import NixSettings, serialise_nix
|
||||
|
||||
from textwrap import dedent
|
||||
|
||||
|
||||
def test_nix_settings_set_item():
|
||||
@@ -115,3 +117,38 @@ def test_nix_settings_to_env_overlay_no_store_dir(tmp_path: Path):
|
||||
|
||||
settings.to_env_overlay(env)
|
||||
assert "store = local?root=/some/path\n" in env._env["NIX_CONFIG"]
|
||||
|
||||
|
||||
class TestSerialiseNix:
|
||||
def test_list(self):
|
||||
assert serialise_nix(["a", 1, None]) == '["a" 1 null]'
|
||||
|
||||
def test_dict(self):
|
||||
assert serialise_nix(
|
||||
{"a": 1, "b": None, "c": "hello world", "d": 3.14159265, "e": True}
|
||||
) == dedent("""
|
||||
{
|
||||
"a" = 1;
|
||||
"b" = null;
|
||||
"c" = "hello world";
|
||||
"d" = 3.14159265;
|
||||
"e" = true;
|
||||
}
|
||||
""")
|
||||
|
||||
def test_escaping(self):
|
||||
assert serialise_nix({'"a': 'Hello ""', "1": "${foo}", "${foo}": None}) == dedent("""
|
||||
{
|
||||
"\\"a" = "Hello \\"\\"";
|
||||
"1" = "\\${foo}";
|
||||
"\\${foo}" = null;
|
||||
}
|
||||
""")
|
||||
|
||||
def test_quotes(self):
|
||||
assert serialise_nix({"a b": None, "\\n": '${awa}"'}) == dedent("""
|
||||
{
|
||||
"a b" = null;
|
||||
"\\\\n" = "\\${awa}\\"";
|
||||
}
|
||||
""")
|
||||
|
||||
Reference in New Issue
Block a user