Ejemplo n.º 1
0
def main():
    global jinja, yaml, inp
    parser = argparse.ArgumentParser()
    parser.add_argument("input", help="Input directory", nargs='?')
    parser.add_argument("-o", "--output", help="Output file")

    args = parser.parse_args()

    inp = get_input_dir(args.input)
    outp = args.output or os.path.join(inp, '..', 'ui-lovelace.yaml')

    jinja = jinja2.Environment(loader=jinja2.FileSystemLoader(inp))
    yaml = YAML(typ='safe')
    yaml.Constructor = SafeConstructor

    SafeConstructor.add_constructor("!include", include_statement)
    SafeConstructor.add_constructor("!file", file_statement)

    try:
        data = process_file(jinja, yaml, MAIN_FILE)
    except Exception as e:
        print("Processing of yaml failed.", file=sys.stderr)
        print(e)
        sys.exit(3)

    try:
        with open(outp, 'w') as fp:
            fp.write(GENERATOR_MESSAGE)
            yaml.dump(data, fp)
    except Exception as e:
        print("Writing ui-lovelace.yaml failed.", file=sys.stderr)
        print(e)
        sys.exit(4)
def process_file(path, args={}):
    global jinja
    template = jinja.get_template(path)
    yaml = YAML(typ='rt')
    yaml.preserve_quotes = True
    yaml.Constructor = RoundTripConstructor
    return yaml.load(template.render(args) + '\n')
Ejemplo n.º 3
0
def parse_yaml_preserve_spans(contents: str,
                              filename: Optional[str]) -> YamlTree:
    """
    parse yaml into a YamlTree object. The resulting spans are tracked in SourceTracker
    so they can be used later when constructing error messages or displaying context.

    :raise jsonschema.exceptions.SchemaError: if config is invalid
    """

    source_hash = SourceTracker.add_source(contents)

    # this uses the `RoundTripConstructor` which inherits from `SafeConstructor`
    class SpanPreservingRuamelConstructor(RoundTripConstructor):
        def construct_object(self, node: Node, deep: bool = False) -> YamlTree:
            r = super().construct_object(node, deep)
            if r is None:
                from semgrep.error import InvalidRuleSchemaError

                Span.from_node(node,
                               source_hash=source_hash,
                               filename=filename)
                raise InvalidRuleSchemaError(
                    short_msg="null values prohibited",
                    long_msg=
                    "In semgrep YAML configuration, null values are prohibited",
                    spans=[
                        Span.from_node(node,
                                       source_hash=source_hash,
                                       filename=filename).with_context(
                                           before=1, after=1)
                    ],
                )

            if isinstance(r, dict):
                r = YamlMap(r)
            return YamlTree(
                r,
                Span.from_node(node,
                               source_hash=source_hash,
                               filename=filename))

    yaml = YAML()
    yaml.Constructor = SpanPreservingRuamelConstructor
    data = yaml.load(StringIO(contents))

    validate_yaml(data)

    if not isinstance(data, YamlTree):
        raise Exception(
            f"Something went wrong parsing Yaml (expected a YamlTree as output, but got {type(data).__name__}): {PLEASE_FILE_ISSUE_TEXT}"
        )
    return data
Ejemplo n.º 4
0
def load_yaml(fname):
    """Load a YAML file."""
    yaml = YAML(typ="safe")
    # Compat with HASS
    yaml.allow_duplicate_keys = True
    # Stub HASS constructors
    HassSafeConstructor.name = fname
    yaml.Constructor = HassSafeConstructor

    with open(fname, encoding="utf-8") as conf_file:
        # If configuration file is empty YAML returns None
        # We convert that to an empty dict
        return yaml.load(conf_file) or {}
Ejemplo n.º 5
0
def load_hass_config(path):
    """Load the HASS config."""
    fname = os.path.join(path, 'configuration.yaml')

    yaml = YAML(typ='safe')
    # Compat with HASS
    yaml.allow_duplicate_keys = True
    # Stub HASS constructors
    HassSafeConstructor.name = fname
    yaml.Constructor = HassSafeConstructor

    with open(fname, encoding='utf-8') as conf_file:
        # If configuration file is empty YAML returns None
        # We convert that to an empty dict
        return yaml.load(conf_file) or {}
Ejemplo n.º 6
0
def load_yaml(fname: str, round_trip: bool = False) -> JSON_TYPE:
    """Load a YAML file."""
    if round_trip:
        yaml = YAML(typ='rt')
        yaml.preserve_quotes = True
    else:
        if not hasattr(ExtSafeConstructor, 'name'):
            ExtSafeConstructor.name = fname
        yaml = YAML(typ='safe')
        yaml.Constructor = ExtSafeConstructor

    try:
        with open(fname, encoding='utf-8') as conf_file:
            # If configuration file is empty YAML returns None
            # We convert that to an empty dict
            return yaml.load(conf_file) or OrderedDict()
    except YAMLError as exc:
        _LOGGER.error("YAML error in %s: %s", fname, exc)
        raise HomeAssistantError(exc)
    except UnicodeDecodeError as exc:
        _LOGGER.error("Unable to read file %s: %s", fname, exc)
        raise HomeAssistantError(exc)
Ejemplo n.º 7
0
def load_yaml(fname: str, round_trip: bool = False) -> JSON_TYPE:
    """Load a YAML file."""
    if round_trip:
        yaml = YAML(typ="rt")
        yaml.preserve_quotes = True  # type: ignore[assignment]
    else:
        if ExtSafeConstructor.name is None:
            ExtSafeConstructor.name = fname
        yaml = YAML(typ="safe")
        yaml.Constructor = ExtSafeConstructor

    try:
        with open(fname, encoding="utf-8") as conf_file:
            # If configuration file is empty YAML returns None
            # We convert that to an empty dict
            return yaml.load(conf_file) or OrderedDict()
    except YAMLError as exc:
        _LOGGER.error("YAML error in %s: %s", fname, exc)
        raise OpenPeerPowerError(exc) from exc
    except UnicodeDecodeError as exc:
        _LOGGER.error("Unable to read file %s: %s", fname, exc)
        raise OpenPeerPowerError(exc) from exc
Ejemplo n.º 8
0
def load_yaml(fname: str, round_trip: bool = False) -> JSON_TYPE:
    """Load a YAML file."""
    if round_trip:
        yaml = YAML(typ='rt')
        yaml.preserve_quotes = True
    else:
        if not hasattr(ExtSafeConstructor, 'name'):
            ExtSafeConstructor.name = fname
        yaml = YAML(typ='safe')
        yaml.Constructor = ExtSafeConstructor

    try:
        with open(fname, encoding='utf-8') as conf_file:
            # If configuration file is empty YAML returns None
            # We convert that to an empty dict
            return yaml.load(conf_file) or OrderedDict()
    except YAMLError as exc:
        _LOGGER.error("YAML error in %s: %s", fname, exc)
        raise HomeAssistantError(exc)
    except UnicodeDecodeError as exc:
        _LOGGER.error("Unable to read file %s: %s", fname, exc)
        raise HomeAssistantError(exc)
Ejemplo n.º 9
0
def load_yaml(fname: str, round_trip: bool = False) -> JSON_TYPE:
    """Load a YAML file."""
    if round_trip:
        yaml = YAML(typ="rt")
        # type ignore: https://bitbucket.org/ruamel/yaml/pull-requests/42
        yaml.preserve_quotes = True  # type: ignore
    else:
        if ExtSafeConstructor.name is None:
            ExtSafeConstructor.name = fname
        yaml = YAML(typ="safe")
        yaml.Constructor = ExtSafeConstructor

    try:
        with open(fname, encoding="utf-8") as conf_file:
            # If configuration file is empty YAML returns None
            # We convert that to an empty dict
            return yaml.load(conf_file) or OrderedDict()
    except YAMLError as exc:
        _LOGGER.error("YAML error in %s: %s", fname, exc)
        raise HomeAssistantError(exc)
    except UnicodeDecodeError as exc:
        _LOGGER.error("Unable to read file %s: %s", fname, exc)
        raise HomeAssistantError(exc)
Ejemplo n.º 10
0
def parse_yaml_preserve_spans(contents: str,
                              filename: Optional[str]) -> YamlTree:
    """
    parse yaml into a YamlTree object. The resulting spans are tracked in SourceTracker
    so they can be used later when constructing error messages or displaying context.

    :raise jsonschema.exceptions.SchemaError: if config is invalid
    """

    source_hash = SourceTracker.add_source(contents)

    # this uses the `RoundTripConstructor` which inherits from `SafeConstructor`
    class SpanPreservingRuamelConstructor(RoundTripConstructor):
        def construct_object(self, node: Node, deep: bool = False) -> YamlTree:
            r = super().construct_object(node, deep)

            # Check for duplicate mapping keys.
            # This -should- be caught and raised by ruamel.yaml.
            # However, resetting the constructor below, where the line
            # reads yaml.Constructor = SpanPreservingRuamelConstructor,
            # causes ruamel's DuplicateKeyError not to be raised.
            # This is a quick implementation that will check MappingNodes
            #
            if isinstance(node, MappingNode):
                from semgrep.error import InvalidRuleSchemaError

                kv_pairs: List[Tuple[Node, Node]] = [t for t in node.value]
                uniq_key_names: Set[str] = set(t[0].value for t in kv_pairs)
                # If the number of unique key names is less than the number
                # of key-value nodes, then there's a duplicate key
                if len(uniq_key_names) < len(kv_pairs):
                    raise InvalidRuleSchemaError(
                        short_msg="Detected duplicate key",
                        long_msg=
                        f"Detected duplicate key name, one of {list(sorted(uniq_key_names))}.",
                        spans=[
                            Span.from_node(node,
                                           source_hash=source_hash,
                                           filename=filename).with_context(
                                               before=1, after=1)
                        ],
                    )

            if r is None:
                from semgrep.error import InvalidRuleSchemaError

                Span.from_node(node,
                               source_hash=source_hash,
                               filename=filename)
                raise InvalidRuleSchemaError(
                    short_msg="null values prohibited",
                    long_msg=
                    "In semgrep YAML configuration, null values are prohibited",
                    spans=[
                        Span.from_node(node,
                                       source_hash=source_hash,
                                       filename=filename).with_context(
                                           before=1, after=1)
                    ],
                )

            if isinstance(r, dict):
                r = YamlMap(r)
            return YamlTree(
                r,
                Span.from_node(node,
                               source_hash=source_hash,
                               filename=filename))

    yaml = YAML()
    yaml.Constructor = SpanPreservingRuamelConstructor
    data = yaml.load(StringIO(contents))

    validate_yaml(data)

    if not isinstance(data, YamlTree):
        raise Exception(
            f"Something went wrong parsing Yaml (expected a YamlTree as output, but got {type(data).__name__}): {PLEASE_FILE_ISSUE_TEXT}"
        )
    return data