PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/svnmailer-1.0.8/src/lib/svnmailer/browser.py

#
Python | 338 lines | 172 code | 54 blank | 112 comment | 25 complexity | a8f995bd0517465bc776c5c8723f8aa8 MD5 | raw file
Possible License(s): Apache-2.0
  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. # Exceptions
  23. class Error(Exception):
  24. """ Base exception for this module """
  25. pass
  26. class InvalidBaseUrlError(Error):
  27. """ Invalid URL was configured """
  28. pass
  29. def getBrowserUrlGenerator(config):
  30. """ Returns an initialized repos browser generator
  31. @param config: The group configuration
  32. @type config: C{svnmailer.settings.GroupSettingsContainer}
  33. @return: The generator object or C{None}
  34. @rtype: C{object}
  35. """
  36. if config.browser_base_url:
  37. b_type, base_url = parseBrowserBase(config.browser_base_url)
  38. if b_type == "viewcvs":
  39. return ViewcvsGenerator(base_url)
  40. elif b_type == "websvn":
  41. return WebsvnGenerator(base_url)
  42. elif config.viewcvs_base_url:
  43. return ViewcvsGenerator(config.viewcvs_base_url)
  44. return None
  45. def parseBrowserBase(base_config):
  46. """ Parses the given option value into type and base url
  47. @param base_config: The option value
  48. @type base_config: C{str}
  49. @return: The type and the base url
  50. @rtype: C{tuple}
  51. """
  52. if base_config:
  53. tokens = base_config.split(None, 1)
  54. if len(tokens) == 2:
  55. return (tokens[0].lower(), tokens[1])
  56. return (None, None)
  57. class ParsedUrl(object):
  58. """ Container for URL parsing and modification
  59. @ivar scheme: The scheme
  60. @type scheme: C{str}
  61. @ivar netloc: The netloc
  62. @type netloc: C{str}
  63. @ivar path: The path
  64. @type path: C{str}
  65. @ivar param: The path param
  66. @type param:C{str}
  67. @ivar query: The query string
  68. @type query: C{str}
  69. @ivar fragment: The fragment
  70. @type fragment: C{str}
  71. """
  72. def __init__(self, url):
  73. """ Initialization """
  74. import urlparse
  75. (self.scheme, self.netloc, self.path, self.param, self.query,
  76. self.fragment) = urlparse.urlparse(url)
  77. def __str__(self):
  78. """ Returns the URL as string
  79. @return: The URL as string
  80. @rtype: C{str}
  81. """
  82. import urlparse
  83. return urlparse.urlunparse((
  84. self.scheme, self.netloc, self.path, self.param, self.query,
  85. self.fragment
  86. ))
  87. class ViewcvsGenerator(object):
  88. """ viewcvs generator
  89. @ivar base: The base url
  90. @type base: C{str}
  91. """
  92. def __init__(self, base):
  93. """ Initialization
  94. @param base: The base url
  95. @type base: C{str}
  96. """
  97. self.base = base
  98. def getRevisionUrl(self, revision):
  99. """ Returns the revision summary URL
  100. @param revision: The revision number
  101. @type revision: C{int}
  102. @return: The url
  103. @rtype: C{str}
  104. """
  105. import urllib
  106. from svnmailer import util
  107. url = ParsedUrl(self.base)
  108. while url.path[-1:] == '/':
  109. url.path = url.path[:-1]
  110. url.query = util.modifyQuery(url.query,
  111. rem = ['p1', 'p2', 'r1', 'r2'],
  112. set = [
  113. ('view', 'rev'),
  114. ('rev', urllib.quote(str(revision))),
  115. ]
  116. )
  117. return str(url)
  118. def getContentDiffUrl(self, change):
  119. """ Returns the content diff url for a particular change
  120. @param change: The change to process
  121. @type change: C{svnmailer.subversion.VersionedPathDescriptor}
  122. """
  123. import urllib, posixpath
  124. from svnmailer import util
  125. url = ParsedUrl(self.base)
  126. url.path = posixpath.join(url.path, urllib.quote((
  127. change.wasDeleted() and [change.getBasePath()] or [change.path]
  128. )[0]))
  129. if change.isDirectory():
  130. url.path = "%s/" % url.path
  131. if change.wasDeleted():
  132. url.query = util.modifyQuery(url.query,
  133. rem = ['p1', 'p2', 'r1', 'r2'],
  134. set = [
  135. ('view', 'auto'),
  136. ('rev', urllib.quote(str(change.getBaseRevision()))),
  137. ]
  138. )
  139. elif change.wasCopied():
  140. if change.isDirectory():
  141. return None # no text changes
  142. url.query = util.modifyQuery(url.query, set = [
  143. ('view', 'diff'),
  144. ('rev', urllib.quote(str(change.revision))),
  145. ('p1', urllib.quote(change.getBasePath())),
  146. ('r1', urllib.quote(str(change.getBaseRevision()))),
  147. ('p2', urllib.quote(change.path)),
  148. ('r2', urllib.quote(str(change.revision))),
  149. ])
  150. elif change.wasAdded():
  151. url.query = util.modifyQuery(url.query,
  152. rem = ['p1', 'p2', 'r1', 'r2'],
  153. set = [
  154. ('view', 'auto'),
  155. ('rev', urllib.quote(str(change.revision))),
  156. ]
  157. )
  158. else: # modified
  159. if change.isDirectory():
  160. return None # no text changes
  161. url.query = util.modifyQuery(url.query,
  162. rem = ['p1', 'p2'],
  163. set = [
  164. ('view', 'diff'),
  165. ('rev', urllib.quote(str(change.revision))),
  166. ('r1', urllib.quote(str(change.getBaseRevision()))),
  167. ('r2', urllib.quote(str(change.revision))),
  168. ]
  169. )
  170. return str(url)
  171. class WebsvnGenerator(object):
  172. """ websvn generator
  173. @ivar base: The base url
  174. @type base: C{str}
  175. """
  176. def __init__(self, base):
  177. """ Initialization
  178. @param base: The base url
  179. @type base: C{str}
  180. """
  181. self.base = base
  182. def getRevisionUrl(self, revision):
  183. """ Returns the revision summary URL
  184. @param revision: The revision number
  185. @type revision: C{int}
  186. @return: The url
  187. @rtype: C{str}
  188. """
  189. import urllib, posixpath
  190. from svnmailer import util
  191. url = ParsedUrl(self.base)
  192. parsed_query = util.parseQuery(url.query)
  193. # no path info...
  194. if parsed_query.has_key("repname"):
  195. dirname, basename = posixpath.split(url.path)
  196. if not basename:
  197. raise InvalidBaseUrlError("Missing PHP file...?")
  198. url.path = posixpath.join(dirname, 'listing.php')
  199. # path info configured
  200. else:
  201. while url.path[-1:] == '/':
  202. url.path = url.path[:-1]
  203. url.path = "%s/" % url.path
  204. url.query = util.modifyQuery(parsed_query,
  205. rem = ['path'],
  206. set = [
  207. ('sc', '1'),
  208. ('rev', urllib.quote(str(revision))),
  209. ]
  210. )
  211. return str(url)
  212. def getContentDiffUrl(self, change):
  213. """ Returns the content diff url for a particular change
  214. @param change: The change to process
  215. @type change: C{svnmailer.subversion.VersionedPathDescriptor}
  216. """
  217. import urllib, posixpath
  218. from svnmailer import util
  219. if change.isDirectory() and not change.wasDeleted() and (
  220. not change.wasAdded() or change.wasCopied()):
  221. # show only a directory URL on adding and deleting
  222. return
  223. url = ParsedUrl(self.base)
  224. parsed_query = util.parseQuery(url.query)
  225. cpath = urllib.quote("%s%s" % (
  226. (change.wasDeleted() and
  227. [change.getBasePath()] or [change.path])[0],
  228. ["", "/"][change.isDirectory()]
  229. ))
  230. toset = [("rev", urllib.quote(str((change.wasDeleted() and
  231. [change.getBaseRevision()] or [change.revision]
  232. )[0])))]
  233. if parsed_query.has_key("repname"):
  234. dirname, basename = posixpath.split(url.path)
  235. if not basename:
  236. raise InvalidBaseUrlError(
  237. "Missing PHP file in '%s'?" % self.base
  238. )
  239. url.query = util.modifyQuery(parsed_query,
  240. set = [('path', "/%s" % cpath)]
  241. )
  242. url.path = dirname
  243. cpath = ["diff.php", ["filedetails.php", "listing.php"]
  244. [change.isDirectory()]][
  245. change.wasDeleted() or (
  246. change.wasAdded() and not change.wasCopied())
  247. ]
  248. else:
  249. toset.append(("op",
  250. ["diff", ["file", "dir"][change.isDirectory()]][
  251. change.wasDeleted() or (
  252. change.wasAdded() and not change.wasCopied())
  253. ]
  254. ))
  255. url.path = posixpath.join(url.path, cpath)
  256. url.query = util.modifyQuery(url.query, rem = ["sc"], set = toset)
  257. return str(url)