Skip to content

Commit

Permalink
buildchain/targets: add a SLS Renderer
Browse files Browse the repository at this point in the history
For now we define a SLS as a YAML file with optional shebang and list of
imports.

Since both YAML and SLS renderer uses YAML dump, we extract it into an
helper.

Refs: #2070
Signed-off-by: Sylvain Laperche <[email protected]>
  • Loading branch information
slaperche-scality committed Dec 9, 2019
1 parent 2635f0f commit 12e8a0a
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 16 deletions.
6 changes: 4 additions & 2 deletions buildchain/buildchain/targets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
from buildchain.targets.repository import (
Repository, RPMRepository, DEBRepository
)
from buildchain.targets.serialize import Renderer, SerializedData, YAMLDocument
from buildchain.targets.serialize import (
Renderer, SerializedData, SaltState, YAMLDocument
)
from buildchain.targets.template import TemplateFile

# For mypy, see `--no-implicit-reexport` documentation.
Expand All @@ -29,6 +31,6 @@
'Package', 'RPMPackage', 'DEBPackage',
'RemoteImage',
'Repository', 'RPMRepository', 'DEBRepository',
'Renderer', 'SerializedData', 'YAMLDocument',
'Renderer', 'SerializedData', 'SaltState', 'YAMLDocument',
'TemplateFile',
]
52 changes: 38 additions & 14 deletions buildchain/buildchain/targets/serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
"""Targets to write files from Python objects."""

import base64
import collections
import enum
import json
from pathlib import Path
from typing import Any, Callable, Dict, Mapping
from typing import Any, Callable, Dict, IO, Mapping

import yaml

Expand Down Expand Up @@ -35,25 +36,26 @@ def render_envfile(variables: Mapping[str, str], filepath: Path) -> None:
def render_yaml(data: Any, filepath: Path) -> None:
"""Serialize an object as YAML to a given file path."""
with filepath.open('w', encoding='utf-8') as fp:
dumper = yaml.SafeDumper(fp, sort_keys=False) # type: ignore
dumper.add_representer( # type: ignore
YAMLDocument.Literal, _literal_representer
)
dumper.add_representer( # type: ignore
YAMLDocument.ByteString, _bytestring_representer
)
try:
dumper.open() # type: ignore
dumper.represent(data) # type: ignore
dumper.close() # type: ignore
finally:
dumper.dispose() # type: ignore
_yaml_dump(data, fp)


def render_sls(sls: 'SaltState', filepath: Path) -> None:
"""Serialize a Salt state to a given file path."""
with filepath.open('w', encoding='utf-8') as fp:
if sls.shebang:
fp.write(sls.shebang)
fp.write('\n'*2)
if sls.imports:
fp.write('\n'.join(sls.imports))
fp.write('\n'*2)
_yaml_dump(sls.content, fp)


class Renderer(enum.Enum):
"""Supported rendering methods for `SerializedData` targets."""
JSON = 'JSON'
ENV = 'ENV'
SLS = 'SLS'
YAML = 'YAML'


Expand All @@ -64,6 +66,7 @@ class SerializedData(base.AtomicTarget):
Renderer.JSON: render_json,
Renderer.ENV: render_envfile,
Renderer.YAML: render_yaml,
Renderer.SLS: render_sls,
}

def __init__(
Expand Down Expand Up @@ -142,6 +145,11 @@ def bytestring(cls, value: bytes) -> 'YAMLDocument.ByteString':
return cls.ByteString(value)


SaltState = collections.namedtuple(
'SaltState', ['content', 'shebang', 'imports']
)


def _literal_representer(dumper: yaml.BaseDumper, data: Any) -> Any:
scalar = yaml.representer.SafeRepresenter.represent_str( # type: ignore
dumper, data
Expand All @@ -156,4 +164,20 @@ def _bytestring_representer(dumper: yaml.BaseDumper, data: Any) -> Any:
)


def _yaml_dump(data: Any, fp: IO[Any]) -> None:
dumper = yaml.SafeDumper(fp, sort_keys=False) # type: ignore
dumper.add_representer( # type: ignore
YAMLDocument.Literal, _literal_representer
)
dumper.add_representer( # type: ignore
YAMLDocument.ByteString, _bytestring_representer
)
try:
dumper.open() # type: ignore
dumper.represent(data) # type: ignore
dumper.close() # type: ignore
finally:
dumper.dispose() # type: ignore


# }}}

0 comments on commit 12e8a0a

Please sign in to comment.