Blame cloudinit/distros/parsers/sys_conf.py

Packit Service a04d08
# Copyright (C) 2012 Yahoo! Inc.
Packit Service a04d08
#
Packit Service a04d08
# Author: Joshua Harlow <harlowja@yahoo-inc.com>
Packit Service a04d08
#
Packit Service a04d08
# This file is part of cloud-init. See LICENSE file for license information.
Packit Service a04d08
Packit Service a04d08
import pipes
Packit Service a04d08
import re
Packit Service 9bfd13
from io import StringIO
Packit Service a04d08
Packit Service a04d08
# This library is used to parse/write
Packit Service a04d08
# out the various sysconfig files edited (best attempt effort)
Packit Service a04d08
#
Packit Service a04d08
# It has to be slightly modified though
Packit Service a04d08
# to ensure that all values are quoted/unquoted correctly
Packit Service a04d08
# since these configs are usually sourced into
Packit Service a04d08
# bash scripts...
Packit Service a04d08
import configobj
Packit Service a04d08
Packit Service a04d08
# See: http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html
Packit Service a04d08
# or look at the 'param_expand()' function in the subst.c file in the bash
Packit Service a04d08
# source tarball...
Packit Service a04d08
SHELL_VAR_RULE = r'[a-zA-Z_]+[a-zA-Z0-9_]*'
Packit Service a04d08
SHELL_VAR_REGEXES = [
Packit Service a04d08
    # Basic variables
Packit Service a04d08
    re.compile(r"\$" + SHELL_VAR_RULE),
Packit Service a04d08
    # Things like $?, $0, $-, $@
Packit Service a04d08
    re.compile(r"\$[0-9#\?\-@\*]"),
Packit Service a04d08
    # Things like ${blah:1} - but this one
Packit Service a04d08
    # gets very complex so just try the
Packit Service a04d08
    # simple path
Packit Service a04d08
    re.compile(r"\$\{.+\}"),
Packit Service a04d08
]
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def _contains_shell_variable(text):
Packit Service a04d08
    for r in SHELL_VAR_REGEXES:
Packit Service a04d08
        if r.search(text):
Packit Service a04d08
            return True
Packit Service a04d08
    return False
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class SysConf(configobj.ConfigObj):
Packit Service a04d08
    """A configobj.ConfigObj subclass specialised for sysconfig files.
Packit Service a04d08
Packit Service a04d08
    :param contents:
Packit Service a04d08
        The sysconfig file to parse, in a format accepted by
Packit Service a04d08
        ``configobj.ConfigObj.__init__`` (i.e. "a filename, file like object,
Packit Service a04d08
        or list of lines").
Packit Service a04d08
    """
Packit Service a04d08
    def __init__(self, contents):
Packit Service a04d08
        configobj.ConfigObj.__init__(self, contents,
Packit Service a04d08
                                     interpolation=False,
Packit Service a04d08
                                     write_empty_values=True)
Packit Service a04d08
Packit Service a04d08
    def __str__(self):
Packit Service a04d08
        contents = self.write()
Packit Service a04d08
        out_contents = StringIO()
Packit Service a04d08
        if isinstance(contents, (list, tuple)):
Packit Service a04d08
            out_contents.write("\n".join(contents))
Packit Service a04d08
        else:
Packit Service a04d08
            out_contents.write(str(contents))
Packit Service a04d08
        return out_contents.getvalue()
Packit Service a04d08
Packit Service a04d08
    def _quote(self, value, multiline=False):
Packit Service 9bfd13
        if not isinstance(value, str):
Packit Service a04d08
            raise ValueError('Value "%s" is not a string' % (value))
Packit Service a04d08
        if len(value) == 0:
Packit Service a04d08
            return ''
Packit Service a04d08
        quot_func = None
Packit Service a04d08
        if value[0] in ['"', "'"] and value[-1] in ['"', "'"]:
Packit Service a04d08
            if len(value) == 1:
Packit Service a04d08
                quot_func = (lambda x: self._get_single_quote(x) % x)
Packit Service a04d08
        else:
Packit Service a04d08
            # Quote whitespace if it isn't the start + end of a shell command
Packit Service a04d08
            if value.strip().startswith("$(") and value.strip().endswith(")"):
Packit Service a04d08
                pass
Packit Service a04d08
            else:
Packit Service a04d08
                if re.search(r"[\t\r\n ]", value):
Packit Service a04d08
                    if _contains_shell_variable(value):
Packit Service a04d08
                        # If it contains shell variables then we likely want to
Packit Service a04d08
                        # leave it alone since the pipes.quote function likes
Packit Service a04d08
                        # to use single quotes which won't get expanded...
Packit Service a04d08
                        if re.search(r"[\n\"']", value):
Packit Service a04d08
                            quot_func = (lambda x:
Packit Service a04d08
                                         self._get_triple_quote(x) % x)
Packit Service a04d08
                        else:
Packit Service a04d08
                            quot_func = (lambda x:
Packit Service a04d08
                                         self._get_single_quote(x) % x)
Packit Service a04d08
                    else:
Packit Service a04d08
                        quot_func = pipes.quote
Packit Service a04d08
        if not quot_func:
Packit Service a04d08
            return value
Packit Service a04d08
        return quot_func(value)
Packit Service a04d08
Packit Service a04d08
    def _write_line(self, indent_string, entry, this_entry, comment):
Packit Service a04d08
        # Ensure it is formatted fine for
Packit Service a04d08
        # how these sysconfig scripts are used
Packit Service a04d08
        val = self._decode_element(self._quote(this_entry))
Packit Service a04d08
        key = self._decode_element(self._quote(entry))
Packit Service a04d08
        cmnt = self._decode_element(comment)
Packit Service a04d08
        return '%s%s%s%s%s' % (indent_string,
Packit Service a04d08
                               key,
Packit Service a04d08
                               self._a_to_u('='),
Packit Service a04d08
                               val,
Packit Service a04d08
                               cmnt)
Packit Service a04d08
Packit Service a04d08
# vi: ts=4 expandtab