1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17  """ 
 18  Struct Member Definitions 
 19  ========================= 
 20   
 21  This module exactly describes the struct member definitions used by 
 22  the svnmailer. All those definitions are pooled in the L{typemap} dict, which 
 23  can be supplied as-is to L{typedstruct.members}. 
 24   
 25  The following types are defined by this module: 
 26      - C{unicode}: see L{UnicodeDescriptor} 
 27      - C{string}: see L{StringDescriptor} 
 28      - C{int}: see L{IntegerDescriptor} 
 29      - C{bool}: see L{BooleanDescriptor} 
 30      - C{humanbool}: see L{HumanBooleanDescriptor} 
 31      - C{regex}: see L{RegexDescriptor} 
 32      - C{token}: see L{TokenDescriptor} 
 33      - C{tokenlist}: see L{TokenlistDescriptor} 
 34      - C{filename}: see L{FilenameDescriptor} 
 35      - C{unicommand}: see L{CommandlineDescriptor} 
 36      - C{quotedstr} : see L{QuotedstringDescriptor} 
 37      - C{stdin}: see L{StdinDescriptor} 
 38      - C{mailaction}: see L{MailactionDescriptor} 
 39   
 40  @var typemap: The type mapping dict (C{{<name>: <class>}}) 
 41  @type typemap: C{svnmailer.util.ReadOnlyDict} 
 42  """ 
 43  __author__    = "André Malo" 
 44  __docformat__ = "epytext en" 
 45  __all__       = ['typemap'] 
 46   
 47   
 48  from svnmailer import typedstruct, util 
 49   
 50   
 51   
 53      """ This method is not supported """ 
 54      pass 
  55   
 56   
 58      """ Base class for svnmailer descriptors """ 
 59   
 60 -    def __init__(self, name, private, param = None): 
  61          """ Initialization """ 
 62          super(BaseDescriptor, self).__init__(name, private, param or {}) 
 63          self.MAP = bool(self.param.get('map')) 
 64          self.SUBST = bool(self.param.get('subst')) 
  65   
 66   
 73   
 74   
 76          """ Substitute the value if it's activated """ 
 77          if self.SUBST and value is not None: 
 78              value = self.doSubstitute(value, subst, arg) 
 79   
 80          return value 
  81   
 82   
 83 -    def premap(self, value, mapper, arg): 
  84          """ Premap the value if it's activated """ 
 85          if self.MAP and value is not None: 
 86              value = self.doPremap(value, mapper, arg) 
 87   
 88          return value 
  89   
 90   
 91 -    def postmap(self, value, mapper, arg): 
  92          """ Postmap the value if it's activated """ 
 93          if self.MAP and value is not None: 
 94              value = self.doPostmap(value, mapper, arg) 
 95   
 96          return value 
  97   
 98   
100          """ Returns the charset """ 
101          return (arg and arg["encoding"]) or 'us-ascii' 
 102   
103   
105          """ Returns the file system charset """ 
106          return arg and arg["path_encoding"] 
 107   
108   
109 -    def doPremap(self, value, mapper, arg): 
 110          """ abstract method 
111   
112              @param value: The value to premap 
113              @type value: any 
114   
115              @param mapper: The mapper function 
116              @type mapper: C{function} 
117   
118              @param arg: The argument used for struct initialization 
119              @type arg: any 
120          """ 
121          raise NotSupportedError() 
 122   
123   
137   
138   
140          """ abstract method 
141   
142              @param value: The value to substitute 
143              @type value: any 
144   
145              @param subst: The substitution dictionary 
146              @type subst: C{dict} 
147   
148              @param arg: The argument used for struct initialization 
149              @type arg: any 
150   
151              @return: The substituted value 
152              @rtype: any 
153          """ 
154          raise NotSupportedError() 
 155   
156   
157 -    def doPostmap(self, value, mapper, arg): 
 158          """ abstract method 
159   
160              @param value: The value to premap 
161              @type value: any 
162   
163              @param mapper: The mapper function 
164              @type mapper: C{function} 
165   
166              @param arg: The argument used for struct initialization 
167              @type arg: any 
168          """ 
169          raise NotSupportedError() 
  170   
171   
173      """ Base class for premap only descriptors """ 
174   
175 -    def doPremap(self, value, mapper, arg): 
 176          """ Maps the value """ 
177          return mapper(value) 
 178   
179   
180 -    def doPostmap(self, value, mapper, arg): 
 181          """ Passes through """ 
182          return value 
  183   
184   
185 -class BasePostmapDescriptor(BaseDescriptor): 
 186      """ Base class for postmap only descriptors """ 
187   
188 -    def doPremap(self, value, mapper, arg): 
 189          """ Passes through """ 
190          return value 
  191   
192   
194      """ Unicode object storage """ 
195   
213   
214   
216          """ Substitutes the value """ 
217          return util.substitute(value, subst) 
 218   
219   
220 -    def doPostmap(self, value, mapper, arg): 
 221          """ Maps the value 
222   
223              @exception TypeError: The mapped value is neither C{str} nor 
224                 C{unicode} 
225              @exception UnicodeError: The mapped value is a string and cannot 
226                  be interpreted as the specified charset 
227          """ 
228          return self.transform(mapper(value), arg) 
  229   
230   
232      """ String storage """ 
233   
 241   
242   
244      """ Integer storage """ 
245   
 253   
254   
256      """ Boolean storage """ 
257   
 261   
262   
264      """ Boolean storage with translater from human readable booleans 
265   
266          @cvar TRUE: The true words (C{tuple} of C{str}) 
267          @type TRUE: C{tuple} 
268   
269          @cvar FALSE: The false words (C{tuple} of C{str}) 
270          @type FALSE: C{tuple} 
271   
272          @ivar HUMAN: The dictionary containing true and false keys 
273          @type HUMAN: C{dict} 
274      """ 
275      TRUE = ('1', 'yes', 'on', 'true') 
276      FALSE = ('', '0', 'no', 'off', 'false', 'none') 
277   
278 -    def __init__(self, name, private, param = None): 
 284   
285   
 298   
299   
301      """ Regex storage 
302   
303          @ivar FLAGS: The flags for the regex compiler 
304          @type FLAGS: C{int} 
305      """ 
306   
307 -    def __init__(self, name, private, param = None): 
 311   
312   
 333   
334   
336      """ Unicode token storage """ 
337   
338 -    def __init__(self, name, private, param = None): 
 339          """ Initialization """ 
340          super(TokenDescriptor, self).__init__(name, private, param) 
341   
342          allowed = self.param.get('allowed') 
343          if allowed: 
344              self.ALLOWED = dict.fromkeys([token.lower() for token in allowed]) 
345          else: 
346              self.ALLOWED = None 
 347   
348   
 374   
375   
377      """ (Unicode) Tokenlist storage """ 
378   
379 -    def __init__(self, name, private, param = None): 
 380          """ Initialization """ 
381          super(TokenlistDescriptor, self).__init__(name, private, param) 
382   
383          allowed = self.param.get('allowed') 
384          if allowed: 
385              self.ALLOWED = dict.fromkeys([token.lower() for token in allowed]) 
386          else: 
387              self.ALLOWED = None 
 388   
389   
420   
421   
423          """ Substitutes the items """ 
424          return tuple([util.substitute(token, subst) for token in value]) 
 425   
426   
427 -    def doPostmap(self, value, mapper, arg): 
 428          """ Maps the items """ 
429          value = tuple([mapper(token) for token in value]) 
430   
431          if self.ALLOWED: 
432              for token in value: 
433                  if not self.ALLOWED.has_key(token.lower()): 
434                      raise ValueError( 
435                          "Supplied token %r is not allowed" % token 
436                      ) 
437   
438          return value 
  439   
440   
442      """ Filename storage """ 
443   
460              value = RecodedFilename(value) 
461          else: 
462              raise TypeError( 
463                  "Supplied value must be string or unicode, not %r" % 
464                  type(value).__name__ 
465              ) 
466   
467          return value 
 468   
469   
471      """ Commandline storage """ 
472   
 502   
503   
505      """ Holds a quoted string """ 
506      import re 
507      _parsed_quoted_string = ( 
508          re.compile(r'(?:[^"\s]\S*|"[^\\"]*(?:\\[\\"][^\\"]*)*")$'), 
509          re.compile(r'\\([\\"])') 
510      ) 
511      del re 
512   
514          """ Initialization and check 
515   
516              @param value: The value to initialize the string 
517              @type value: C{str} 
518   
519              @exception ValueError: The string did not pass the test 
520          """ 
521          checkre, subre = cls._parsed_quoted_string 
522          if value and not checkre.match(value): 
523              raise ValueError("Could not parse quoted string %r" % value) 
524   
525          if value.startswith('"'): 
526              value = subre.sub(r'\1', value[1:-1]) 
527   
528          return str.__new__(cls, value) 
 529   
530   
532          """ Returns the representation of the quoted string """ 
533          return repr( 
534              '"%s"' % str(self).replace('\\', r'\\').replace('"', r'\"') 
535          ) 
  536   
537   
539      """ Quoted string storage """ 
540   
 557   
558   
560      """ Stdin storage """ 
561      _stdin = None 
562   
 570   
571   
573      """ Mailaction container 
574   
575          @cvar TRUNCATE: C{truncate} token 
576          @type TRUNCATE: C{str} 
577   
578          @cvar URLS: C{showurls} token 
579          @type URLS: C{str} 
580   
581          @cvar SPLIT: C{split} token 
582          @type SPLIT: C{str} 
583   
584          @cvar REVPROP: C{revprop-changes} token 
585          @type REVPROP: C{str} 
586   
587          @cvar LOCKS: C{locks} token 
588          @type LOCKS: C{str} 
589   
590          @ivar maxbytes: maximum number of bytes 
591          @type maxbytes: C{int} 
592   
593          @ivar mode: basic mode (C{truncate}, C{showurls}, C{split}) 
594          @type mode: C{str} 
595   
596          @ivar truncate: truncate submode 
597          @type truncate: C{bool} 
598   
599          @ivar drop: drop submode or C{None} 
600          @type drop: C{int} 
601   
602          @ivar scope: additional scopes (C{revprop-changes}, C{locks}) 
603          @type scope: C{tuple} 
604      """ 
605      maxbytes = 0 
606      mode     = None 
607      truncate = False 
608      drop     = None 
609      scope    = () 
610   
611      TRUNCATE = "truncate" 
612      URLS     = "showurls" 
613      SPLIT    = "split" 
614   
615      REVPROP  = "revprop-changes" 
616      LOCKS    = "locks" 
617   
619          """ Initialization 
620   
621              @param action: The action as string 
622              @type action: C{str} 
623          """ 
624          _msg = "Can't parse action string %r" % (action,) 
625   
626          action = action.split() 
627          if len(action) < 2: 
628              raise ValueError(_msg) 
629   
630          self.maxbytes = int(action[0]) 
631          tokens = action[1].lower().split('/') 
632   
633          self.mode = tokens.pop(0).lower() 
634          if self.mode not in (self.TRUNCATE, self.URLS, self.SPLIT): 
635              raise ValueError(_msg) 
636   
637          if tokens and tokens[0].lower() == self.TRUNCATE: 
638              if self.mode not in (self.URLS, self.SPLIT): 
639                  raise ValueError(_msg) 
640              self.truncate = True 
641              tokens.pop(0) 
642   
643          if tokens: 
644              if self.mode != self.SPLIT: 
645                  raise ValueError(_msg) 
646              self.drop = int(tokens.pop(0)) 
647   
648          if tokens: 
649              raise ValueError(_msg) 
650   
651          sdict = {} 
652          for token in action[2:]: 
653              if token.lower() not in (self.REVPROP, self.LOCKS): 
654                  raise ValueError(_msg) 
655              sdict[token.lower()] = None 
656          self.scope = tuple(sdict.keys()) 
 657   
658   
660          """ String representation of the object 
661   
662              @return: The representation 
663              @rtype: C{str} 
664          """ 
665          result = "%d %s" % (self.maxbytes, self.mode) 
666          if self.truncate: 
667              result = "%s/truncate" % result 
668          if self.drop: 
669              result = "%s/%d" % (result, self.drop) 
670          if self.scope: 
671              scopes = list(self.scope) 
672              scopes.sort() 
673              result = " ".join([result] + scopes) 
674   
675          return result 
  676   
677   
679      """ Mail action parsing and storage """ 
680   
 696   
697   
698   
699  typemap = util.ReadOnlyDict({ 
700      'unicode'   : UnicodeDescriptor, 
701      'string'    : StringDescriptor, 
702      'int'       : IntegerDescriptor, 
703      'bool'      : BooleanDescriptor, 
704      'humanbool' : HumanBooleanDescriptor, 
705      'regex'     : RegexDescriptor, 
706      'token'     : TokenDescriptor, 
707      'tokenlist' : TokenlistDescriptor, 
708      'filename'  : FilenameDescriptor, 
709      'unicommand': CommandlineDescriptor, 
710      'quotedstr' : QuotedstringDescriptor, 
711      'stdin'     : StdinDescriptor, 
712      'mailaction': MailactionDescriptor, 
713  }) 
714