%PDF- %PDF-
Direktori : /usr/lib/python3/dist-packages/aptdaemon/ |
Current File : //usr/lib/python3/dist-packages/aptdaemon/config.py |
"""Handling configuration files.""" # Copyright (C) 2010 Sebastian Heinlein <sevel@glatzor.de> # # Licensed under the GNU General Public License Version 2 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # 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, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. __author__ = "Sebastian Heinlein <devel@glatzor.de>" __all__ = ("ConfigWriter",) import logging import os import apt_pkg log = logging.getLogger("AptDaemon.ConfigWriter") class Value(object): """Represents a value with position information. .. attribute:: string The value string. .. attribute:: line The line number of the configuration file in which the value is set. .. attribute:: start The position in the line at which the value starts. .. attribute:: end The position in the line at which the value ends. .. attribute:: quotes The outer qoutes of the value: ' or " """ def __init__(self, line, start, quotes): self.string = "" self.start = start self.end = None self.line = line self.quotes = quotes def __cmp__(self, other): return self.string == other def __repr__(self): return "Value: '%s' (line %s: %s to %s)" % (self.string, self.line, self.start, self.end) class ConfigWriter(object): """Modifies apt configuration files.""" def parse(self, lines): """Parse an ISC based apt configuration. :param lines: The list of lines of a configuration file. :returns: Dictionary of key, values found in the parsed configuration. """ options = {} in_comment = False in_value = False prev_char = None option = [] value = None option_name = "" value_list = [] in_brackets = True level = 0 for line_no, line in enumerate(lines): for char_no, char in enumerate(line): if not in_comment and char == "*" and prev_char == "/": in_comment = True prev_char = "" continue elif in_comment and char == "/" and prev_char == "*": # A multiline comment was closed in_comment = False prev_char = "" option_name = option_name[:-1] continue elif in_comment: # We ignore the content of multiline comments pass elif not in_value and ((char == "/" and prev_char == "/") or char == "#"): # In the case of a line comment continue processing # the next line prev_char = "" option_name = option_name[:-1] break elif char in "'\"": if in_value and value.quotes == char: value.end = char_no in_value = not in_value elif not value: value = Value(line_no, char_no, char) in_value = not in_value else: value.string += char elif in_value: value.string += char elif option_name and char == ":" and prev_char == ":": option.append(option_name[:-1]) option_name = "" elif char.isalpha() or char in "/-:._+": option_name += char.lower() elif char == ";": if in_brackets: value_list.append(value) value = None continue if value_list: log.debug("Found %s \"%s\"", "::".join(option), value_list) options["::".join(option)] = value_list value_list = [] elif value: log.debug("Found %s \"%s\"", "::".join(option), value) options["::".join(option)] = value else: log.debug("Skipping empty key %s", "::".join(option)) value = None if level > 0: option.pop() else: option = [] elif char == "}": level -= 1 in_brackets = False elif char == "{": level += 1 if option_name: option.append(option_name) option_name = "" in_brackets = True elif char in "\t\n ": if option_name: option.append(option_name) option_name = "" in_brackets = False else: raise ValueError("Unknown char '%s' in line: '%s'" % (char, line)) prev_char = char return options def set_value(self, option, value, defaultfile): """Change the value of an option in the configuration. :param option: The name of the option, e.g. 'apt::periodic::AutoCleanInterval'. :param value: The value of the option. Will be converted to string. :param defaultfile: The filename of the ``/etc/apt/apt.conf.d`` configuration snippet in which the option should be set. If the value is overriden by a later configuration file snippet it will be disabled in the corresponding configuration file. """ # FIXME: Support value lists # Convert the value to string if value is True: value = "true" elif value is False: value = "false" else: value = str(value) # Check all configuration file snippets etc_parts = os.path.join(apt_pkg.config.find_dir("Dir::Etc"), apt_pkg.config.find_dir("Dir::Etc::Parts")) for filename in os.listdir(etc_parts): if filename < defaultfile: continue with open(os.path.join(etc_parts, filename)) as fd: lines = fd.readlines() config = self.parse(lines) try: val = config[option.lower()] except KeyError: if filename == defaultfile: lines.append("%s '%s';\n" % (option, value)) else: continue else: # Check if the value needs to be changed at all if ((value == "true" and val.string.lower() in ["yes", "with", "on", "enable"]) or (value == "false" and val.string.lower() in ["no", "without", "off", "disable"]) or (str(value) == val.string)): continue if filename == defaultfile: line = lines[val.line] new_line = line[:val.start + 1] new_line += value new_line += line[val.end:] lines[val.line] = new_line else: # Comment out existing values instead in non default # configuration files # FIXME Quite dangerous for brackets lines[val.line] = "// %s" % lines[val.line] with open(os.path.join(etc_parts, filename), "w") as fd: log.debug("Writting %s", filename) fd.writelines(lines) if not os.path.exists(os.path.join(etc_parts, defaultfile)): with open(os.path.join(etc_parts, defaultfile), "w") as fd: log.debug("Writting %s", filename) line = "%s '%s';\n" % (option, value) fd.write(line) def main(): apt_pkg.init_config() cw = ConfigWriter() for filename in sorted(os.listdir("/etc/apt/apt.conf.d/")): lines = open("/etc/apt/apt.conf.d/%s" % filename).readlines() cw.parse(lines) print((cw.set_value("huhu::abc", "lumpi", "10glatzor"))) if __name__ == "__main__": main() # vim:ts=4:sw=4:et