diff options
| author | Vlastimil Holer <vlastimil.holer@gmail.com> | 2012-12-19 18:03:03 +0100 | 
|---|---|---|
| committer | Vlastimil Holer <vlastimil.holer@gmail.com> | 2012-12-19 18:03:03 +0100 | 
| commit | 8dd9678d97a822e477915c150d528096a83c9777 (patch) | |
| tree | a9b5708edd9d448508abf00abdd9b7bdeba16541 /cloudinit/distros/parsers/sys_conf.py | |
| parent | a9939fe768e04d52fe530c7467357d79b78a21f4 (diff) | |
| parent | 3569e71a1579b97f4e33fb46ab3fcef08a4ddad4 (diff) | |
| download | vyos-cloud-init-8dd9678d97a822e477915c150d528096a83c9777.tar.gz vyos-cloud-init-8dd9678d97a822e477915c150d528096a83c9777.zip  | |
Merged trunk lp:cloud-init
Diffstat (limited to 'cloudinit/distros/parsers/sys_conf.py')
| -rw-r--r-- | cloudinit/distros/parsers/sys_conf.py | 113 | 
1 files changed, 113 insertions, 0 deletions
diff --git a/cloudinit/distros/parsers/sys_conf.py b/cloudinit/distros/parsers/sys_conf.py new file mode 100644 index 00000000..20ca1871 --- /dev/null +++ b/cloudinit/distros/parsers/sys_conf.py @@ -0,0 +1,113 @@ +# vi: ts=4 expandtab +# +#    Copyright (C) 2012 Yahoo! Inc. +# +#    Author: Joshua Harlow <harlowja@yahoo-inc.com> +# +#    This program is free software: you can redistribute it and/or modify +#    it under the terms of the GNU General Public License version 3, as +#    published by the Free Software Foundation. +# +#    This program is distributed in the hope that it will be useful, +#    but WITHOUT ANY WARRANTY; without even the implied warranty of +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +#    GNU General Public License for more details. +# +#    You should have received a copy of the GNU General Public License +#    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +from StringIO import StringIO + +import pipes +import re + +# This library is used to parse/write +# out the various sysconfig files edited (best attempt effort) +# +# It has to be slightly modified though +# to ensure that all values are quoted/unquoted correctly +# since these configs are usually sourced into +# bash scripts... +import configobj + +# See: http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html +# or look at the 'param_expand()' function in the subst.c file in the bash +# source tarball... +SHELL_VAR_RULE = r'[a-zA-Z_]+[a-zA-Z0-9_]*' +SHELL_VAR_REGEXES = [ +    # Basic variables +    re.compile(r"\$" + SHELL_VAR_RULE), +    # Things like $?, $0, $-, $@ +    re.compile(r"\$[0-9#\?\-@\*]"), +    # Things like ${blah:1} - but this one +    # gets very complex so just try the +    # simple path +    re.compile(r"\$\{.+\}"), +] + + +def _contains_shell_variable(text): +    for r in SHELL_VAR_REGEXES: +        if r.search(text): +            return True +    return False + + +class SysConf(configobj.ConfigObj): +    def __init__(self, contents): +        configobj.ConfigObj.__init__(self, contents, +                                     interpolation=False, +                                     write_empty_values=True) + +    def __str__(self): +        contents = self.write() +        out_contents = StringIO() +        if isinstance(contents, (list, tuple)): +            out_contents.write("\n".join(contents)) +        else: +            out_contents.write(str(contents)) +        return out_contents.getvalue() + +    def _quote(self, value, multiline=False): +        if not isinstance(value, (str, basestring)): +            raise ValueError('Value "%s" is not a string' % (value)) +        if len(value) == 0: +            return '' +        quot_func = None +        if value[0] in ['"', "'"] and value[-1] in ['"', "'"]: +            if len(value) == 1: +                quot_func = (lambda x: +                                self._get_single_quote(x) % x) +        else: +            # Quote whitespace if it isn't the start + end of a shell command +            if value.strip().startswith("$(") and value.strip().endswith(")"): +                pass +            else: +                if re.search(r"[\t\r\n ]", value): +                    if _contains_shell_variable(value): +                        # If it contains shell variables then we likely want to +                        # leave it alone since the pipes.quote function likes +                        # to use single quotes which won't get expanded... +                        if re.search(r"[\n\"']", value): +                            quot_func = (lambda x: +                                            self._get_triple_quote(x) % x) +                        else: +                            quot_func = (lambda x: +                                            self._get_single_quote(x) % x) +                    else: +                        quot_func = pipes.quote +        if not quot_func: +            return value +        return quot_func(value) + +    def _write_line(self, indent_string, entry, this_entry, comment): +        # Ensure it is formatted fine for +        # how these sysconfig scripts are used +        val = self._decode_element(self._quote(this_entry)) +        key = self._decode_element(self._quote(entry)) +        cmnt = self._decode_element(comment) +        return '%s%s%s%s%s' % (indent_string, +                               key, +                               self._a_to_u('='), +                               val, +                               cmnt)  | 
