# HG changeset patch # User Pascal Volk # Date 1280028692 0 # Node ID a0a10100aee5ccd0050d50d747ceb33471c137f5 # Parent 644e2cc4a44189f4b5d6f72e6619cd9337981e80 VMM/ext/Postconf: Reworked class Postconf. Added method edit(). diff -r 644e2cc4a441 -r a0a10100aee5 VirtualMailManager/ext/Postconf.py --- a/VirtualMailManager/ext/Postconf.py Fri Jul 23 19:07:30 2010 +0000 +++ b/VirtualMailManager/ext/Postconf.py Sun Jul 25 03:31:32 2010 +0000 @@ -1,84 +1,127 @@ # -*- coding: UTF-8 -*- # Copyright (c) 2008 - 2010, Pascal Volk # See COPYING for distribution information. +""" + VirtualMailManager.ext.Postconf + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -"""A small - r/o - wrapper class for Postfix' postconf.""" + Wrapper class for Postfix's postconf. + Postconf instances can be used to read actual values of configuration + parameters or edit the value of a configuration parameter. + + postconf.read(parameter) -> value + postconf.edit(parameter, value) +""" import re from subprocess import Popen, PIPE -import VirtualMailManager.constants.ERROR as ERR from VirtualMailManager.errors import VMMError +from VirtualMailManager.constants.ERROR import VMM_ERROR -RE_PC_PARAMS = """^\w+$""" -RE_PC_VARIABLES = r"""\$\b\w+\b""" +_ = lambda msg: msg + class Postconf(object): - __slots__ = ('__bin', '__val', '__varFinder') + """Wrapper class for Postfix's postconf.""" + __slots__ = ('_bin', '_val') + _parameter_re = re.compile(r'^\w+$') + _variables_re = re.compile(r'\$\b\w+\b') + def __init__(self, postconf_bin): """Creates a new Postconf instance. - Keyword arguments: - postconf_bin -- absolute path to the Postfix postconf binary (str) + Argument: + + `postconf_bin` : str + absolute path to the Postfix postconf binary. """ - self.__bin = postconf_bin - self.__val = '' - self.__varFinder = re.compile(RE_PC_VARIABLES) + self._bin = postconf_bin + self._val = '' + + def edit(self, parameter, value): + """Set the `parameter`'s value to `value`. + + Arguments: + + `parameter` : str + the name of a Postfix configuration parameter + `value` : str + the parameter's new value. + """ + self._check_parameter(parameter) + stdout, stderr = Popen((self._bin, '-e', parameter + '=' + str(value)), + stderr=PIPE).communicate() + if stderr: + raise VMMError(stderr.strip(), VMM_ERROR) def read(self, parameter, expand_vars=True): """Returns the parameters value. If expand_vars is True (default), all variables in the value will be expanded: - e.g. mydestination -> mail.example.com, localhost.example.com, localhost + e.g. mydestination: mail.example.com, localhost.example.com, localhost Otherwise the value may contain one or more variables. - e.g. mydestination -> $myhostname, localhost.$mydomain, localhost + e.g. mydestination: $myhostname, localhost.$mydomain, localhost + + Arguments: - Keyword arguments: - parameter -- the name of a Postfix configuration parameter (str) - expand_vars -- default True (bool) + `parameter` : str + the name of a Postfix configuration parameter. + `expand_vars` : bool + indicates if variables should be expanded or not, default True """ - if not re.match(RE_PC_PARAMS, parameter): + self._check_parameter(parameter) + self._val = self._read(parameter) + if expand_vars: + self._expand_vars() + return self._val + + def _check_parameter(self, parameter): + """Check that the `parameter` looks like a configuration parameter. + If not, a VMMError will be raised.""" + if not self.__class__._parameter_re.match(parameter): raise VMMError(_(u"The value '%s' doesn't look like a valid " u"postfix configuration parameter name.") % - parameter, ERR.VMM_ERROR) - self.__val = self.__read(parameter) - if expand_vars: - self.__expandVars() - return self.__val + parameter, VMM_ERROR) - def __expandVars(self): + def _expand_vars(self): + """Expand the $variables in self._val to their values.""" while True: - pvars = set(self.__varFinder.findall(self.__val)) - pvars_len = len(pvars) - if pvars_len < 1: + pvars = set(self.__class__._variables_re.findall(self._val)) + if not pvars: break - if pvars_len > 1: - self.__expandMultiVars(self.__readMulti(pvars)) + if len(pvars) > 1: + self._expand_multi_vars(self._read_multi(pvars)) continue pvars = pvars.pop() - self.__val = self.__val.replace(pvars, self.__read(pvars[1:])) + self._val = self._val.replace(pvars, self._read(pvars[1:])) - def __expandMultiVars(self, old_new): - for old, new in old_new.items(): - self.__val = self.__val.replace('$'+old, new) + def _expand_multi_vars(self, old_new): + """Replace all $vars in self._val with their values.""" + for old, new in old_new.iteritems(): + self._val = self._val.replace('$' + old, new) - def __read(self, parameter): - out, err = Popen([self.__bin, '-h', parameter], stdout=PIPE, - stderr=PIPE).communicate() - if len(err): - raise VMMError(err.strip(), ERR.VMM_ERROR) - return out.strip() + def _read(self, parameter): + """Ask postconf for the value of a single configuration parameter.""" + stdout, stderr = Popen([self._bin, '-h', parameter], stdout=PIPE, + stderr=PIPE).communicate() + if stderr: + raise VMMError(stderr.strip(), VMM_ERROR) + return stdout.strip() - def __readMulti(self, parameters): - cmd = [self.__bin] + def _read_multi(self, parameters): + """Ask postconf for multiple configuration parameters. Returns a dict + parameter: value items.""" + cmd = [self._bin] cmd.extend(parameter[1:] for parameter in parameters) - out, err = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() - if len(err): - raise VMMError(err.strip(), ERR.VMM_ERROR) + stdout, stderr = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() + if stderr: + raise VMMError(stderr.strip(), VMM_ERROR) par_val = {} - for line in out.splitlines(): + for line in stdout.splitlines(): par, val = line.split(' = ') par_val[par] = val return par_val +del _