Ejemplo n.º 1
0
    def read(self):
        """Reads the files content.

        The file content will cached. Consecutive reads will yield the cache content so the file doesn't have to be read
        twice.

        Returns:
            str: The content of the file.

        Raises:
            FileNotFoundError: If the file could not be found under the path
            IOError: If the given path does not contain a file
        """
        if self.cache and self.cache['path'] == self.path:
            Log.debug("Return cached file '{0}'...".format(self.path))
            return self.cache['content']

        else:
            self.cache = {}

            if not self.exists():
                raise FileNotFoundError("File does not exist: '{0}'".format(
                    self.path))
            if not os.path.isfile(self.path):
                raise IOError("Is not a file: '{0}".format(self.path))

            Log.debug("Loading file '{0}'...".format(self.path))
            with io.open(self.path, 'r', encoding='utf8') as f:
                file_content = f.read()

            self.cache['path'] = self.path
            self.cache['content'] = file_content
            self.cache['hash'] = hash(file_content)
            return self.cache['content']
Ejemplo n.º 2
0
    def write(content, path, force_overwrite=False):
        """Writes the content into a file with the given path.

        Args:
            content (str): Content to write into the file
            path (str): Path where the content shall be written to
            force_overwrite (bool): If true any existing file will be overwritten

        Raises:
            IOError: If desired output file exists or is not a file
        """
        if os.path.exists(path):
            if os.path.isfile(path):
                if not force_overwrite:
                    raise IOError(
                        "Destination already exists. Use '-f' flag to overwrite the file: '{0}"
                        .format(path))
            else:
                raise IOError(
                    "Destination exists and is not a file: '{0}".format(path))
        else:
            # create dir
            if os.path.dirname(path):
                os.makedirs(os.path.dirname(path), exist_ok=True)

        # write content to file
        Log.debug("Writing file '{0}'...".format(path))
        with io.open(path, 'w', encoding='utf8') as f:
            f.write(content)
def dump_yaml(data):
    """Dumps a Python object as a YAML string.

    Args:
        data (dict): The data to be dumped as YAML

    Returns:
        str: The dumped YAML

    Raises:
        yaml.TypeError: If a YAML type error occurred
    """

    import ruamel.yaml as yaml
    from io import StringIO
    from docker_compose_templer.log import Log

    yml = yaml.YAML()
    yml.indent(mapping=2, sequence=4, offset=2)
    yml.width = 1000
    try:
        Log.debug("Dumping YAML...")
        sio = StringIO()
        yml.dump(data, sio)
        return sio.getvalue()
    except yaml.TypeError as e:
        raise yaml.TypeError("YAML dump error: {0}".format(e.problem))
    except Exception:
        raise
def load_yaml(string, safe=True):
    """Parses a YAML string and produce the corresponding Python object.

    Args:
        string (str): The input string to be parsed
        safe (bool): If True the CSafeLoader is used otherwise the RoundTripLoader

    Returns:
        dict: The parsed YAML

    Raises:
        yaml.YAMLError: If the YAML string is malformed
    """

    import ruamel.yaml as yaml
    from docker_compose_templer.log import Log

    try:
        Log.debug("Parsing YAML...")
        if safe:
            yml = yaml.YAML(typ='safe')
        else:
            yml = yaml.YAML(typ='rt')
        return yml.load(string) or {}
    except yaml.YAMLError as e:
        raise yaml.YAMLError("YAML parsing error: {0}".format(e.problem))
    except Exception:
        raise
Ejemplo n.º 5
0
 def _on_change(self, *args, **kwargs):
     """Gets executed on change event."""
     old_hash = self.cache['hash']
     self.cache = None
     self.read()
     if old_hash != self.cache['hash']:
         Log.debug("File '{0}' changed".format(self.path))
         self.on_change_event()
Ejemplo n.º 6
0
 def _on_change(self, *args, **kwargs):
     """Gets executed on a change event."""
     old_hash = self.cache_hash
     try:
         self._create_context()
     except Exception as e:
         Log.error("Faild to create context: {0}".format(str(e)))
         raise
     if self.cache_hash != old_hash:
         self.on_change_event()
Ejemplo n.º 7
0
    def process(self):
        """Process the definition.

        Parses the definition file, loads the external context from YAML files and renders the defined templates.

        Returns:
            bool: True if the processing finished without errors else False
        """
        Log.info("\nProcess Definition: '{0}'".format(self.file.path))
        try:
            self._parse()
        except Exception as e:
            Log.error(
                "Error loading options from definition file: {0}".format(
                    str(e)), 2)
            return False

        return self._render_templates()
    def start(self):
        """Starts the Auto Renderer."""
        Log.info("Auto renderer started")

        # render on start
        for d in self.definitions:
            d.process()

        Log.info("\nWaiting for changes...")

        # start file change listener
        while (True):
            try:
                for notifier in [f.notifier for _, f in CachedFile.files.items()]:
                    try:
                        if notifier.check_events():
                            notifier.read_events()
                            notifier.process_events()
                    except KeyboardInterrupt:
                        raise
                    except Exception:
                        break
                time.sleep(0.5)
            except KeyboardInterrupt:
                break

        Log.info("\nAuto renderer stopped")
    def render(self):
        """Renders the template file with Jinja and writes the output to the destination.

        Returns:
            bool: True if the processing finished without errors else false
        """
        src_rel = self.src
        dest_rel = self.dest

        try:
            try:
                src_rel = self._create_path(self.src, False)
                dest_rel = self._create_path(self.dest, False)
            finally:
                Log.info("Render template: '{0}' --> '{1}'".format(
                    src_rel, dest_rel))

            file_content = self.file.read()

            # render the template with Jinja
            rendered_file_content = JinjaRenderer.render_string(
                file_content, self.context.get_context())

            # remove values containing an omit placeholder
            processed_content = dump_yaml(
                JinjaRenderer.remove_omit_from_dict(
                    load_yaml(rendered_file_content, safe=False)))

            # write the rendered content into a file
            dest_path = self._create_path(self.dest)
            self.file.write(content=processed_content,
                            path=dest_path,
                            force_overwrite=self.force_overwrite)

            return True

        except Exception as e:
            Log.error("Error while rendering template: {0}".format(str(e)), 2)
            return False