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