PageRenderTime 23ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/cnucnu-0git315bba3b/cnucnu/helper.py

#
Python | 284 lines | 254 code | 4 blank | 26 comment | 0 complexity | 4b94a954b46084de71eb05a31c922582 MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0
  1. #!/usr/bin/python
  2. # vim: fileencoding=utf8 foldmethod=marker
  3. # {{{ License header: GPLv2+
  4. # This file is part of cnucnu.
  5. #
  6. # Cnucnu is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 2 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # Cnucnu is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with cnucnu. If not, see <http://www.gnu.org/licenses/>.
  18. # }}}
  19. """ :author: Till Maas
  20. :contact: opensource@till.name
  21. :license: GPLv2+
  22. """
  23. __docformat__ = "restructuredtext"
  24. #from twisted.internet import reactor
  25. import re
  26. import pprint as pprint_module
  27. pp = pprint_module.PrettyPrinter(indent=4)
  28. pprint = pp.pprint
  29. __html_regex = re.compile(r'\bhref\s*=\s*["\']([^"\'/]+)/["\']', re.I)
  30. __text_regex = re.compile(r'^d.+\s(\S+)\s*$', re.I|re.M)
  31. def expand_subdirs(url, glob_char="*"):
  32. """ Expand glob_char in the given URL with the latest dir at that level
  33. Example URL: http://www.example.com/foo/*/
  34. The globbing char needs to be enclosed by slashes like "/*/".
  35. """
  36. glob_pattern = "/%s/" % glob_char
  37. glob_pos = url.find(glob_pattern)
  38. # url until first slash before glob_char
  39. url_prefix = url[0:glob_pos+1]
  40. # everything after the slash after glob_char
  41. url_suffix = url[glob_pos+len(glob_pattern):]
  42. if url_prefix != "":
  43. dir_listing = get_html(url_prefix)
  44. if not dir_listing:
  45. return url
  46. subdirs = []
  47. regex = url.startswith("ftp://") and __text_regex or __html_regex
  48. for match in regex.finditer(dir_listing):
  49. subdir = match.group(1)
  50. if subdir not in (".", ".."):
  51. subdirs.append(subdir)
  52. if not subdirs:
  53. return url
  54. latest = upstream_max(subdirs)
  55. url = "%s%s/%s" % (url_prefix, latest, url_suffix)
  56. return expand_subdirs(url, glob_char)
  57. return url
  58. def get_html(url, callback=None, errback=None):
  59. if url.startswith("ftp://"):
  60. import urllib
  61. req = urllib.urlopen(url)
  62. data = req.read()
  63. if callback:
  64. try:
  65. for cb in callback:
  66. cb(data)
  67. except TypeError:
  68. callback(data)
  69. return data
  70. else:
  71. if callback:
  72. from twisted.web.client import getPage
  73. df = getPage(url)
  74. try:
  75. for cb in callback:
  76. df.addCallback(cb)
  77. except TypeError:
  78. df.addCallback(callback)
  79. if errback:
  80. try:
  81. for eb in errback:
  82. df.addErrback(eb)
  83. except TypeError:
  84. df.addErrback(errback)
  85. else:
  86. import StringIO
  87. import pycurl
  88. res = StringIO.StringIO()
  89. c = pycurl.Curl()
  90. c.setopt(pycurl.URL, url.encode("ascii"))
  91. c.setopt(pycurl.WRITEFUNCTION, res.write)
  92. c.setopt(pycurl.FOLLOWLOCATION, 1)
  93. c.setopt(pycurl.MAXREDIRS, 10)
  94. c.perform()
  95. c.close()
  96. # this causes a hangug if reactor.run() was already called once
  97. #df = getPage(url)
  98. #df.addCallback(res.write)
  99. #df.addCallback(lambda ignore: reactor.stop())
  100. #reactor.run()
  101. data = res.getvalue()
  102. res.close()
  103. return data
  104. def rpm_cmp(v1, v2):
  105. import rpm
  106. diff = rpm.labelCompare((None, v1, None), (None, v2, None))
  107. return diff
  108. def rpm_max(list):
  109. list.sort(cmp=rpm_cmp)
  110. return list[-1]
  111. def upstream_cmp(v1, v2):
  112. """ Compare two upstream versions
  113. :Parameters:
  114. v1 : str
  115. Upstream version string 1
  116. v2 : str
  117. Upstream version string 2
  118. :return:
  119. - -1 - second version newer
  120. - 0 - both are the same
  121. - 1 - first version newer
  122. :rtype: int
  123. """
  124. v1, rc1, rcn1 = split_rc(v1)
  125. v2, rc2, rcn2 = split_rc(v2)
  126. diff = rpm_cmp(v1, v2)
  127. if diff != 0:
  128. # base versions are different, ignore rc-status
  129. return diff
  130. if rc1 and rc2:
  131. # both are rc, higher rc is newer
  132. diff = cmp(rc1.lower(), rc2.lower())
  133. if diff != 0:
  134. # rc > pre > beta > alpha
  135. return diff
  136. if rcn1 and rcn2:
  137. # both have rc number
  138. return cmp(int(rcn1), int(rcn2))
  139. if rcn1:
  140. # only first has rc number, then it is newer
  141. return 1
  142. if rcn2:
  143. # only second has rc number, then it is newer
  144. return -1
  145. # both rc numbers are missing or same
  146. return 0
  147. if rc1:
  148. # only first is rc, then second is newer
  149. return -1
  150. if rc2:
  151. # only second is rc, then first is newer
  152. return 1
  153. # neither is a rc
  154. return 0
  155. __rc_ups_regex = re.compile("(.*?)(-?(rc|pre|beta|alpha)([0-9]*))", re.I)
  156. __rc_rel_regex = re.compile(r'0\.[0-9]+\.(rc|pre|beta|alpha)([0-9]*)', re.I)
  157. def split_rc(version):
  158. """ Split version into version and release candidate string +
  159. release candidate number if possible
  160. """
  161. match = __rc_ups_regex.match(version)
  162. if not match:
  163. return (version, "", "")
  164. rc_str = match.group(3)
  165. if rc_str:
  166. v = match.group(1)
  167. rc_num = match.group(4)
  168. return (v, rc_str, rc_num)
  169. else:
  170. # if version contains a dash, but no release candidate string is found, v != version, therefore use version here
  171. # Example version: 1.8.23-20100128-r1100
  172. # Then: v=1.8.23, but rc_str=""
  173. return (version, "", "")
  174. def get_rc(release):
  175. match = __rc_rel_regex.match(release)
  176. if match:
  177. return (match.group(1), match.group(2))
  178. else:
  179. return ("", "")
  180. def upstream_max(list):
  181. list.sort(cmp=upstream_cmp)
  182. return list[-1]
  183. def cmp_upstream_repo(upstream_v, repo_vr):
  184. repo_rc = get_rc(repo_vr[1])
  185. repo_version = "%s%s%s" % (repo_vr[0], repo_rc[0], repo_rc[1])
  186. return upstream_cmp(upstream_v, repo_version)
  187. def filter_dict(d, key_list):
  188. """ return a dict that only contains keys that are in key_list
  189. """
  190. return dict([v for v in d.items() if v[0] in key_list])
  191. def secure_download(url, cainfo=""):
  192. import pycurl
  193. import StringIO
  194. c = pycurl.Curl()
  195. c.setopt(pycurl.URL, url.encode("ascii"))
  196. # -k / --insecure
  197. # c.setopt(pycurl.SSL_VERIFYPEER, 0)
  198. # Verify certificate
  199. c.setopt(pycurl.SSL_VERIFYPEER, 1)
  200. # Verify CommonName or Subject Alternate Name
  201. c.setopt(pycurl.SSL_VERIFYHOST, 2)
  202. # --cacert
  203. if cainfo:
  204. c.setopt(pycurl.CAINFO, cainfo)
  205. res = StringIO.StringIO()
  206. c.setopt(pycurl.WRITEFUNCTION, res.write)
  207. # follow up to 10 http location: headers
  208. c.setopt(pycurl.FOLLOWLOCATION, 1)
  209. c.setopt(pycurl.MAXREDIRS, 10)
  210. c.perform()
  211. c.close()
  212. data = res.getvalue()
  213. res.close()
  214. return data
  215. def match_interval(text, regex, begin_marker, end_marker):
  216. """ returns a list of match.groups() for all lines after a line
  217. like begin_marker and before a line like end_marker
  218. """
  219. res = []
  220. inside = False
  221. for line in text.splitlines():
  222. if not inside:
  223. if line == begin_marker:
  224. inside = True
  225. else:
  226. match = regex.match(line)
  227. if match:
  228. yield match.groups()
  229. elif line == end_marker:
  230. inside = False
  231. break