Package svnmailer :: Module settings

[hide private]

# Source Code for Module svnmailer.settings

      1  # -*- coding: utf-8 -*-
      2  #
      3  # Copyright 2004-2006 André Malo or his licensors, as applicable
      4  #
      5  # Licensed under the Apache License, Version 2.0 (the "License");
      6  # you may not use this file except in compliance with the License.
      7  # You may obtain a copy of the License at
      8  #
      9  #     http://www.apache.org/licenses/LICENSE-2.0
     10  #
     11  # Unless required by applicable law or agreed to in writing, software
     12  # distributed under the License is distributed on an "AS IS" BASIS,
     13  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  # See the License for the specific language governing permissions and
     15  # limitations under the License.
     16  """
     17  Runtime settings for the svnmailer
     18  ==================================
     19
     20  This module defines one public class, called L{Settings}. This class is the
     21  storage container for all settings used by the svnmailer. L{Settings} is an
     22  abstract class. There is just one method that must be implemented --
     23  L{Settings.init}. This method is responsible for filling the container
     24  properly. An implementor of the L{Settings} class can be found in the
     25  L{svnmailer.config} module.
     26
     27  This module further defines the Settings subcontainers
     28  L{GroupSettingsContainer}, L{GeneralSettingsContainer} and
     29  L{RuntimeSettingsContainer}, but you should not instantiate them directly --
     30  L{Settings} provides methods that return instances of these containers.
     31  """
     32  __author__    = "André Malo"
     33  __docformat__ = "epytext en"
     34  __all__       = ['Settings', 'modes']
     35
     36  # global imports
     37  from svnmailer import typedstruct, struct_accessors
     38
     39
     40 -class _Tokens(object):
     41      """ Generic token container
     42
     43          @ivar valid_tokens: The valid mode tokens (str, str, ...)
     44          @type valid_tokens: C{tuple}
     45      """
     46      valid_tokens = ()
     47
     48 -    def __init__(self, *args):
     49          """ Initialization """
     50          self.valid_tokens = args
     51          for token in self.valid_tokens:
     52              setattr(self, token.encode('us-ascii'), token)
     53
     54  modes = _Tokens('commit', 'propchange', 'lock', 'unlock')
     55  xpath = _Tokens(u'yes', u'no', u'ignore')
     56  showenc = _Tokens(u'yes', u'no', u'nondefault')
     57
     58
     59 -def groupMembers(space):
     60      """ Define the members of the group settings
     61
     62          The following members are defined:
     63              - C{_name}: Name of the group
     64              - C{_def_for_repos}: default for_repos regex
     65              - C{_def_for_paths}: default for_paths regex
     66              - C{for_repos}: Repository regex
     67              - C{for_paths}: Path regex (inside the repos)
     68              - C{exclude_paths}: Exclude path regex to prevent for_paths from
     69                  being applied
     70              - C{ignore_if_other_matches}: this group will be ignored if there
     71                  are any other groups selected for a particular path
     72              - C{show_nonmatching_paths}: How to deal with paths that are not
     73                  matched by the group
     74              - C{commit_subject_template}: Subject template for commit mail
     75              - C{propchange_subject_template}: Subject template for revpropchanges
     76              - C{lock_subject_template}: Subject template for locks
     77              - C{unlock_subject_template}: Subject template for unlocks
     78              - C{commit_subject_prefix}: Subject prefix for commit mail
     79              - C{propchange_subject_prefix}: Subject prefix for revpropchanges
     80              - C{lock_subject_prefix}: Subject prefix for locks
     81              - C{unlock_subject_prefix}: Subject prefix for unlocks
     82              - C{max_subject_length}: Maximum subject length
     83              - C{from_addr}: C{From:} address format string
     84              - C{to_addr}: C{To:} address format string
     85              - C{to_fake}: C{To:} non-address format string
     86              - C{bcc_addr}: C{Bcc:} address format string
     87              - C{reply_to_addr}: C{Reply-To:} address format string
     88              - C{diff_command}: The diff command to use
     89              - C{generate_diffs}: List of actions for which diffs are generated
     90              - C{browser_base_url}: type and format string of the repository
     91                  browser base url
     92              - C{custom_header}: custom header name and format template
     93              - C{to_newsgroup}: The newsgroup where the notification should be
     94                  posted to
     95              - C{long_news_action}: The action to take on huge commit postings
     96              - C{long_mail_action}: The action to take on huge commit mails
     97              - C{mail_transfer_encoding}: Content-Transfer-Encoding for mails
     98              - C{news_transfer_encoding}: Content-Transfer-Encoding for news
     99              - C{mail_type}: The mail construction type
    100              - C{extract_x509_author}: Treat author as x509 subject and try to
    101                  extract author's real name and email address
    102              - C{cia_project_name}: The project name used for CIA notifications
    103              - C{cia_project_module}: The project module used for CIA
    104                  notifications
    105              - C{cia_project_branch}: The project branch used for CIA
    106                  notifications
    107              - C{cia_project_submodule}: The project submodule used for CIA
    108                  notifications
    109              - C{cia_project_path}: The project path, which will be stripped from
    110                  the absolute node path
    111              - C{apply_charset_property}: Should svnmailer:content-charset
    112                  properties be recognized?
    113              - C{show_applied_charset}: Show the encoding of the files in the
    114                  diff?
    115              - C{viewcvs_base_url}: (I{deprecated}, use C{browser_base_url}
    116                  instead) format string for the viewcvs URL
    117
    118          @param space: The namespace to pollute
    119          @type space: C{dict}
    120
    121          @return: The members definition
    122          @rtype: C{dict}
    123      """
    124      args = {
    125          'space'      : space,
    126          'typemap'    : struct_accessors.typemap,
    127          'the_members': {
    128              '_name'                      : 'unicode',
    129              '_def_for_repos'             : 'regex',
    130              '_def_for_paths'             : 'regex',
    131              'for_repos'                  : ('regex',      {'map': True}),
    132              'for_paths'                  : ('regex',      {'map': True}),
    133              'exclude_paths'              : ('regex',      {'map': True}),
    134              'ignore_if_other_matches'    : 'humanbool',
    135              'show_nonmatching_paths'     : ('token',
    136                                             {'map': True,
    137                                              'allowed': xpath.valid_tokens}),
    138              'commit_subject_template'    : ('unicode',    {'map': True}),
    139              'propchange_subject_template': ('unicode',    {'map': True}),
    140              'lock_subject_template'      : ('unicode',    {'map': True}),
    141              'unlock_subject_template'    : ('unicode',    {'map': True}),
    142              'commit_subject_prefix'      : ('unicode',
    143                                             {'subst': True, 'map': True}),
    144              'propchange_subject_prefix'  : ('unicode',
    145                                             {'subst': True, 'map': True}),
    146              'lock_subject_prefix'        : ('unicode',
    147                                             {'subst': True, 'map': True}),
    148              'unlock_subject_prefix'      : ('unicode',
    149                                             {'subst': True, 'map': True}),
    150              'max_subject_length'         : 'int',
    151              'from_addr'                  : ('tokenlist',
    152                                             {'subst': True, 'map': True}),
    153              'to_addr'                    : ('tokenlist',
    154                                             {'subst': True, 'map': True}),
    155              'to_fake'                    : ('unicode',
    156                                             {'subst': True, 'map': True}),
    157              'bcc_addr'                   : ('tokenlist',
    158                                             {'subst': True, 'map': True}),
    159              'reply_to_addr'              : ('unicode',
    160                                             {'subst': True, 'map': True}),
    161              'to_newsgroup'               : ('tokenlist',
    162                                             {'subst': True, 'map': True}),
    163              'diff_command'               : ('unicommand', {'map': True}),
    164              'generate_diffs'             : 'tokenlist',
    165              'browser_base_url'           : ('unicode',
    166                                             {'subst': True, 'map': True}),
    167              'long_mail_action'           : ('mailaction', {'map': True}),
    168              'long_news_action'           : ('mailaction', {'map': True}),
    169              'mail_type'                  : ('unicode',    {'map': True}),
    170              'mail_transfer_encoding'     : 'unicode',
    171              'news_transfer_encoding'     : 'unicode',
    172              'custom_header'              : ('unicode',
    173                                             {'subst': True, 'map': True}),
    174              'extract_x509_author'        : 'humanbool',
    175              'cia_rpc_server'             : ('unicode',    {'map': True}),
    176              'cia_project_name'           : ('unicode',
    177                                             {'subst': True, 'map': True}),
    178              'cia_project_module'         : ('unicode',
    179                                             {'subst': True, 'map': True}),
    180              'cia_project_branch'         : ('unicode',
    181                                             {'subst': True, 'map': True}),
    182              'cia_project_submodule'      : ('unicode',
    183                                             {'subst': True, 'map': True}),
    184              'cia_project_path'           : ('unicode',
    185                                             {'subst': True, 'map': True}),
    186              'apply_charset_property'     : 'humanbool',
    187              'show_applied_charset'       : ('token',
    188                                             {'allowed': showenc.valid_tokens}),
    189
    190              # deprecated
    191              'viewcvs_base_url'           : ('unicode',
    192                                             {'subst': True, 'map': True}),
    193          },
    194          'aliases': {
    195              'suppress_if_match'  : 'ignore_if_other_matches',
    196              'fallback'           : 'ignore_if_other_matches',
    197              'reply_to'           : 'reply_to_addr',
    198              'x509_author'        : 'extract_x509_author',
    199              'charset_property'   : 'apply_charset_property',
    200              'truncate_subject'   : 'max_subject_length',
    201              'subject_length'     : 'max_subject_length',
    202              'diff'               : 'diff_command',
    203              'nonmatching_paths'  : 'show_nonmatching_paths',
    204              'nongroup_paths'     : 'show_nonmatching_paths',
    205              'show_nongroup_paths': 'show_nonmatching_paths',
    206          },
    207      }
    208
    209      return typedstruct.members(**args)
    210
    211
    212 -def generalMembers(space):
    213      """ Define the members of the general settings
    214
    215          The following members are defined:
    216              - C{diff_command}: The diff command
    217              - C{sendmail_command}: The sendmail compatible command
    218              - C{smtp_host}: The smtp host (C{host[:port]})
    219              - C{smtp_user}: The smtp auth. user
    220              - C{smtp_pass}: The smtp auth. password
    221              - C{debug_all_mails_to}: All mails are sent to these addresses
    222                  (for debugging purposes)
    223              - C{cia_rpc_server}: The XML-RPC server running the CIA tracker
    224              - C{tempdir}: The directory to use for temporary files
    225
    226          @param space: The namespace to pollute
    227          @type space: C{dict}
    228
    229          @return: The members definition
    230          @rtype: C{dict}
    231      """
    232      args = {
    233          'space'      : space,
    234          'typemap'    : struct_accessors.typemap,
    235          'the_members': {
    236              'sendmail_command'  : ('unicommand', {'map': True}),
    237              'smtp_host'         : ('unicode',    {'map': True}),
    238              'smtp_user'         : ('quotedstr',  {'map': True}),
    239              'smtp_pass'         : ('quotedstr',  {'map': True}),
    240              'nntp_host'         : ('unicode',    {'map': True}),
    241              'nntp_user'         : ('quotedstr',  {'map': True}),
    242              'nntp_pass'         : ('quotedstr',  {'map': True}),
    243              'debug_all_mails_to': ('tokenlist',  {'map': True}),
    244              'tempdir'           : ('filename',   {'map': True}),
    245
    246              # deprecated
    247              'cia_rpc_server'    : ('unicode',    {'map': True}),
    248              'diff_command'      : ('unicommand', {'map': True}),
    249          },
    250          'aliases'    : {
    251              'mail_command' : 'sendmail_command',
    252              'smtp_hostname': 'smtp_host',
    253              'diff'         : 'diff_command',
    254          },
    255      }
    256
    257      return typedstruct.members(**args)
    258
    259
    260 -def runtimeMembers(space):
    261      """ Define the members of the runtime settings
    262
    263          The following members are defined:
    264              - C{_repos}: The repository object
    265              - C{stdin}: The stdin, read once
    266              - C{path_encoding}: The path-encoding parameter
    267              - C{debug}: debug mode (True/False)
    268              - C{revision}: committed revision number
    269              - C{repository}: path to the repository
    270              - C{config}: supplied config file name
    271              - C{mode}: running mode (see L{modes})
    272              - C{author}: Author of the commit or revpropchange
    273              - C{propname}: Property changed (in revpropchange)
    274              - C{action}: The revprop action (M, A, D)
    275
    276          @param space: The namespace to pollute
    277          @type space: C{dict}
    278
    279          @return: The members definition
    280          @rtype: C{dict}
    281      """
    282      args = {
    283          'space'      : space,
    284          'typemap'    : struct_accessors.typemap,
    285          'the_members': {
    286              '_repos'       : None,       # internal usage (Repository object)
    287              'stdin'        : 'stdin',
    288              'path_encoding': 'string',
    289              'debug'        : 'bool',
    290              'revision'     : 'int',
    291              'repository'   : 'filename',
    292              'config'       : 'filename',
    293              'mode'         : 'string',
    294              'author'       : 'unicode',
    295              'propname'     : 'unicode',
    296              'action'       : 'unicode',  # >= svn 1.2
    297          },
    298          'aliases'    : None,
    299      }
    300
    301      return typedstruct.members(**args)
    302
    303
    304 -class GroupSettingsContainer(typedstruct.Struct):
    305      """ Container for group settings
    306
    307          @see: L{groupMembers} for the actual member list
    308      """
    309      __slots__ = groupMembers(locals())
    310
    311 -    def _compare(self, other):
    312          """ compare some of the attributes
    313
    314              @note: It uses a list of attributes that are compared if two
    315                  of these types are tested for equality. Keep in mind that
    316                  this comparision takes place, when the decision is made
    317                  whether a mail for more than one group should be sent more
    318                  than once (if the groups are not equal). All attributes, but
    319                  the ones returned by L{_getIgnorableMembers} are compared.
    320
    321              @see: L{_getIgnorableMembers}
    322
    323              @param other: The object compared to
    324              @type other: C{GroupSettingsContainer}
    325
    326              @return: Are the objects equal?
    327              @rtype: C{bool}
    328          """
    329          if type(self) != type(other):
    330              return False
    331
    332          attrs = [name for name in self._members_
    333              if name not in self._getIgnorableMembers()
    334          ]
    335
    336          for name in attrs:
    337              if getattr(self, name) != getattr(other, name):
    338                  return False
    339
    340          return True
    341
    342
    343 -    def _getIgnorableMembers(self):
    344          """ Returns the list of member names that be ignored in comparisons
    345
    346              This method called by L{_compare}. Override this method to modify
    347              the list.
    348
    349              @return: The list
    350              @rtype: C{list}
    351          """
    352          return [
    353              '_name', '_def_for_repos', '_def_for_paths',
    354              'for_repos', 'for_paths', 'exclude_paths',
    355              'ignore_if_other_matches', 'to_addr', 'from_addr',
    356              'to_newsgroup', 'custom_header', 'cia_rpc_server',
    357              'cia_project_name', 'cia_project_module', 'cia_project_branch',
    358              'cia_project_submodule', 'cia_project_path',
    359          ]
    360
    361
    362 -class GeneralSettingsContainer(typedstruct.Struct):
    363      """ Container for general settings
    364
    365          @see: L{generalMembers} for the actual member list
    366      """
    367      __slots__ = generalMembers(locals())
    368
    369
    370 -class RuntimeSettingsContainer(typedstruct.Struct):
    371      """ Container for runtime settings
    372
    373          @see: L{runtimeMembers} for the actual member list
    374      """
    375      __slots__ = runtimeMembers(locals())
    376
    377
    378 -class Settings(object):
    379      """ Settings management
    380
    381          @note: The C{init} method must be overridden to do the actual
    382          initialization.
    383
    384          @ivar groups: group settings list
    385          @type groups: C{list} of C{GroupSettingsContainer}
    386
    387          @ivar general: General settings
    388          @type general: C{GeneralSettingsContainer}
    389
    390          @ivar runtime: Runtime settigs
    391          @type runtime: C{RuntimeSettingsContainer}
    392
    393          @ivar debug: Debug state
    394          @type debug: C{bool}
    395
    396          @ivar _charset_: The charset used for settings recoding
    397          @type _charset_: C{str}
    398
    399          @ivar _maps_: The value mappers to use or C{None}
    400          @type _maps_: C{dict}
    401      """
    402
    403 -    def __init__(self, *args, **kwargs):
    404          """ Constructor
    405
    406              Don't override this one. Override C{init()} instead.
    407          """
    408          # supply default values
    409          self._charset_  = 'us-ascii'
    410          self._fcharset_ = None
    411          self._maps_     = None
    412
    413          self.groups = []
    414          self.general  = None
    415          self.runtime  = None
    416
    417          # parameter initialization
    418          self.init(*args, **kwargs)
    419
    420          # sanity check
    421          self._checkInitialization()
    422
    423
    424 -    def _checkInitialization(self):
    425          """ Checks if all containers are filled """
    426          if not(self.general and self.runtime and self.groups):
    427              raise RuntimeError("Settings are not completely initialized")
    428
    429
    430 -    def init(self, *args, **kwargs):
    431          """ Abstract initialization method """
    432          raise NotImplementedError()
    433
    434
    435 -    def _getArgs(self):
    436          """ Returns the basic arguments for container initialization
    437
    438              @return: The args
    439              @rtype: C{list}
    440          """
    441          return [
    442              self._maps_,
    443              {'encoding': self._charset_, 'path_encoding': self._fcharset_}
    444          ]
    445
    446
    447 -    def getGroupContainer(self, **kwargs):
    448          """ Returns an initialized group settings container
    449
    450              @return: The container object
    451              @rtype: C{GroupSettingsContainer}
    452          """
    453          return GroupSettingsContainer(*self._getArgs(), **kwargs)
    454
    455
    456 -    def getDefaultGroupContainer(self, **kwargs):
    457          """ Returns an initialized default group settings container
    458
    459              @return: The container object
    460              @rtype: C{GroupSettingsContainer}
    461          """
    462          args = self._getArgs()
    463          args[0] = None # no maps
    464          return GroupSettingsContainer(*args, **kwargs)
    465
    466
    467 -    def getGeneralContainer(self, **kwargs):
    468          """ Returns an initialized general settings container
    469
    470              @return: The container object
    471              @rtype: C{GeneralSettingsContainer}
    472          """
    473          return GeneralSettingsContainer(*self._getArgs(), **kwargs)
    474
    475
    476 -    def getRuntimeContainer(self, **kwargs):
    477          """ Returns an initialized runtime settings container
    478
    479              Note that the runtime settings (from commandline)
    480              are always assumed to be utf-8 encoded.
    481
    482              @return: The container object
    483              @rtype: C{RuntimeSettingsContainer}
    484          """
    485          args = self._getArgs()
    486          args[0] = None
    487          args[1]["encoding"] = "utf-8"
    488          return RuntimeSettingsContainer(*args, **kwargs)
    489