Package svnmailer :: Module browser

[hide private]

# Source Code for Module svnmailer.browser

      1  # -*- coding: utf-8 -*-
      2  #
      3  # Copyright 2005-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  Respository Browser URL construction
     18  """
     19  __author__    = "André Malo"
     20  __docformat__ = "epytext en"
     21  __all__       = ['getBrowserUrlGenerator']
     22
     23
     24  # Exceptions
     25 -class Error(Exception):
     26      """ Base exception for this module """
     27      pass
     28
     29 -class InvalidBaseUrlError(Error):
     30      """ Invalid URL was configured """
     31      pass
     32
     33
     34 -def getBrowserUrlGenerator(config):
     35      """ Returns an initialized repos browser generator
     36
     37          @param config: The group configuration
     38          @type config: C{svnmailer.settings.GroupSettingsContainer}
     39
     40          @return: The generator object or C{None}
     41          @rtype: C{object}
     42      """
     43      if config.browser_base_url:
     44          b_type, base_url = parseBrowserBase(config.browser_base_url)
     45
     46          if b_type == "viewcvs":
     47              return ViewcvsGenerator(base_url)
     48          elif b_type == "websvn":
     49              return WebsvnGenerator(base_url)
     50
     51      elif config.viewcvs_base_url:
     52          return ViewcvsGenerator(config.viewcvs_base_url)
     53
     54      return None
     55
     56
     57 -def parseBrowserBase(base_config):
     58      """ Parses the given option value into type and base url
     59
     60          @param base_config: The option value
     61          @type base_config: C{str}
     62
     63          @return: The type and the base url
     64          @rtype: C{tuple}
     65      """
     66      if base_config:
     67          tokens = base_config.split(None, 1)
     68          if len(tokens) == 2:
     69              return (tokens[0].lower(), tokens[1])
     70
     71      return (None, None)
     72
     73
     74 -class ParsedUrl(object):
     75      """ Container for URL parsing and modification
     76
     77          @ivar scheme: The scheme
     78          @type scheme: C{str}
     79
     80          @ivar netloc: The netloc
     81          @type netloc: C{str}
     82
     83          @ivar path: The path
     84          @type path: C{str}
     85
     86          @ivar param: The path param
     87          @type param:C{str}
     88
     89          @ivar query: The query string
     90          @type query: C{str}
     91
     92          @ivar fragment: The fragment
     93          @type fragment: C{str}
     94      """
     95
     96 -    def __init__(self, url):
     97          """ Initialization """
     98          import urlparse
     99
    100          (self.scheme, self.netloc, self.path, self.param, self.query,
    101           self.fragment) = urlparse.urlparse(url)
    102
    103
    104 -    def __str__(self):
    105          """ Returns the URL as string
    106
    107              @return: The URL as string
    108              @rtype: C{str}
    109          """
    110          import urlparse
    111
    112          return urlparse.urlunparse((
    113              self.scheme, self.netloc, self.path, self.param, self.query,
    114              self.fragment
    115          ))
    116
    117
    118 -class ViewcvsGenerator(object):
    119      """ viewcvs generator
    120
    121          @ivar base: The base url
    122          @type base: C{str}
    123      """
    124
    125 -    def __init__(self, base):
    126          """ Initialization
    127
    128              @param base: The base url
    129              @type base: C{str}
    130          """
    131          self.base = base
    132
    133
    134 -    def getRevisionUrl(self, revision):
    135          """ Returns the revision summary URL
    136
    137              @param revision: The revision number
    138              @type revision: C{int}
    139
    140              @return: The url
    141              @rtype: C{str}
    142          """
    143          import urllib
    144          from svnmailer import util
    145
    146          url = ParsedUrl(self.base)
    147
    148          while url.path[-1:] == '/':
    149              url.path = url.path[:-1]
    150
    151          url.query = util.modifyQuery(url.query,
    152              rem = ['p1', 'p2', 'r1', 'r2'],
    153              set = [
    154                  ('view', 'rev'),
    155                  ('rev', urllib.quote(str(revision))),
    156              ]
    157          )
    158
    159          return str(url)
    160
    161
    162 -    def getContentDiffUrl(self, change):
    163          """ Returns the content diff url for a particular change
    164
    165              @param change: The change to process
    166              @type change: C{svnmailer.subversion.VersionedPathDescriptor}
    167          """
    168          import urllib, posixpath
    169          from svnmailer import util
    170
    171          url = ParsedUrl(self.base)
    172
    173          url.path = posixpath.join(url.path, urllib.quote((
    174              change.wasDeleted() and [change.getBasePath()] or [change.path]
    175          )[0]))
    176
    177          if change.isDirectory():
    178              url.path = "%s/" % url.path
    179
    180          if change.wasDeleted():
    181              url.query = util.modifyQuery(url.query,
    182                  rem = ['p1', 'p2', 'r1', 'r2'],
    183                  set = [
    184                      ('view', 'auto'),
    185                      ('rev',  urllib.quote(str(change.getBaseRevision()))),
    186                  ]
    187              )
    188
    189          elif change.wasCopied():
    190              if change.isDirectory():
    191                  return None # no text changes
    192
    193              url.query = util.modifyQuery(url.query, set = [
    194                  ('view', 'diff'),
    195                  ('rev',  urllib.quote(str(change.revision))),
    196                  ('p1',   urllib.quote(change.getBasePath())),
    197                  ('r1',   urllib.quote(str(change.getBaseRevision()))),
    198                  ('p2',   urllib.quote(change.path)),
    199                  ('r2',   urllib.quote(str(change.revision))),
    200              ])
    201
    202          elif change.wasAdded():
    203              url.query = util.modifyQuery(url.query,
    204                  rem = ['p1', 'p2', 'r1', 'r2'],
    205                  set = [
    206                      ('view', 'auto'),
    207                      ('rev',  urllib.quote(str(change.revision))),
    208                  ]
    209              )
    210
    211          else: # modified
    212              if change.isDirectory():
    213                  return None # no text changes
    214
    215              url.query = util.modifyQuery(url.query,
    216                  rem = ['p1', 'p2'],
    217                  set = [
    218                      ('view', 'diff'),
    219                      ('rev',  urllib.quote(str(change.revision))),
    220                      ('r1',   urllib.quote(str(change.getBaseRevision()))),
    221                      ('r2',   urllib.quote(str(change.revision))),
    222                  ]
    223              )
    224
    225          return str(url)
    226
    227
    228 -class WebsvnGenerator(object):
    229      """ websvn generator
    230
    231          @ivar base: The base url
    232          @type base: C{str}
    233      """
    234
    235 -    def __init__(self, base):
    236          """ Initialization
    237
    238              @param base: The base url
    239              @type base: C{str}
    240          """
    241          self.base = base
    242
    243
    244 -    def getRevisionUrl(self, revision):
    245          """ Returns the revision summary URL
    246
    247              @param revision: The revision number
    248              @type revision: C{int}
    249
    250              @return: The url
    251              @rtype: C{str}
    252          """
    253          import urllib, posixpath
    254          from svnmailer import util
    255
    256          url = ParsedUrl(self.base)
    257          parsed_query = util.parseQuery(url.query)
    258
    259          # no path info...
    260          if parsed_query.has_key("repname"):
    261              dirname, basename = posixpath.split(url.path)
    262              if not basename:
    263                  raise InvalidBaseUrlError("Missing PHP file...?")
    264
    265              url.path = posixpath.join(dirname, 'listing.php')
    266
    267          # path info configured
    268          else:
    269              while url.path[-1:] == '/':
    270                  url.path = url.path[:-1]
    271              url.path = "%s/" % url.path
    272
    273          url.query = util.modifyQuery(parsed_query,
    274              rem = ['path'],
    275              set = [
    276                  ('sc', '1'),
    277                  ('rev', urllib.quote(str(revision))),
    278              ]
    279          )
    280
    281          return str(url)
    282
    283
    284 -    def getContentDiffUrl(self, change):
    285          """ Returns the content diff url for a particular change
    286
    287              @param change: The change to process
    288              @type change: C{svnmailer.subversion.VersionedPathDescriptor}
    289          """
    290          import urllib, posixpath
    291          from svnmailer import util
    292
    293          if change.isDirectory() and not change.wasDeleted() and (
    294                  not change.wasAdded() or change.wasCopied()):
    295              # show only a directory URL on adding and deleting
    296              return
    297
    298          url = ParsedUrl(self.base)
    299          parsed_query = util.parseQuery(url.query)
    300          cpath = urllib.quote("%s%s" % (
    301              (change.wasDeleted() and
    302                  [change.getBasePath()] or [change.path])[0],
    303              ["", "/"][change.isDirectory()]
    304          ))
    305
    306          toset = [("rev", urllib.quote(str((change.wasDeleted() and
    307              [change.getBaseRevision()] or [change.revision]
    308          )[0])))]
    309
    310          if parsed_query.has_key("repname"):
    311              dirname, basename = posixpath.split(url.path)
    312              if not basename:
    313                  raise InvalidBaseUrlError(
    314                      "Missing PHP file in '%s'?" % self.base
    315                  )
    316
    317              url.query = util.modifyQuery(parsed_query,
    318                  set = [('path', "/%s" % cpath)]
    319              )
    320              url.path = dirname
    321              cpath = ["diff.php", ["filedetails.php", "listing.php"]
    322                      [change.isDirectory()]][
    323                          change.wasDeleted() or (
    324                          change.wasAdded() and not change.wasCopied())
    325                      ]
    326
    327          else:
    328              toset.append(("op",
    329                  ["diff", ["file", "dir"][change.isDirectory()]][
    330                      change.wasDeleted() or (
    331                      change.wasAdded() and not change.wasCopied())
    332                  ]
    333              ))
    334
    335          url.path = posixpath.join(url.path, cpath)
    336          url.query = util.modifyQuery(url.query, rem = ["sc"], set = toset)
    337
    338          return str(url)
    339