__init__.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. # ex:ts=4:sw=4:sts=4:et
  2. # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
  3. """
  4. BitBake 'Fetch' implementations
  5. Classes for obtaining upstream sources for the
  6. BitBake build tools.
  7. """
  8. # Copyright (C) 2003, 2004 Chris Larson
  9. #
  10. # This program is free software; you can redistribute it and/or modify
  11. # it under the terms of the GNU General Public License version 2 as
  12. # published by the Free Software Foundation.
  13. #
  14. # This program is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public License along
  20. # with this program; if not, write to the Free Software Foundation, Inc.,
  21. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  22. #
  23. # Based on functions from the base bb module, Copyright 2003 Holger Schurig
  24. import os, re
  25. import bb
  26. from bb import data
  27. class FetchError(Exception):
  28. """Exception raised when a download fails"""
  29. class NoMethodError(Exception):
  30. """Exception raised when there is no method to obtain a supplied url or set of urls"""
  31. class MissingParameterError(Exception):
  32. """Exception raised when a fetch method is missing a critical parameter in the url"""
  33. class ParameterError(Exception):
  34. """Exception raised when a url cannot be proccessed due to invalid parameters."""
  35. class MD5SumError(Exception):
  36. """Exception raised when a MD5SUM of a file does not match the expected one"""
  37. def uri_replace(uri, uri_find, uri_replace, d):
  38. # bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: operating on %s" % uri)
  39. if not uri or not uri_find or not uri_replace:
  40. bb.msg.debug(1, bb.msg.domain.Fetcher, "uri_replace: passed an undefined value, not replacing")
  41. uri_decoded = list(bb.decodeurl(uri))
  42. uri_find_decoded = list(bb.decodeurl(uri_find))
  43. uri_replace_decoded = list(bb.decodeurl(uri_replace))
  44. result_decoded = ['','','','','',{}]
  45. for i in uri_find_decoded:
  46. loc = uri_find_decoded.index(i)
  47. result_decoded[loc] = uri_decoded[loc]
  48. import types
  49. if type(i) == types.StringType:
  50. import re
  51. if (re.match(i, uri_decoded[loc])):
  52. result_decoded[loc] = re.sub(i, uri_replace_decoded[loc], uri_decoded[loc])
  53. if uri_find_decoded.index(i) == 2:
  54. if d:
  55. localfn = bb.fetch.localpath(uri, d)
  56. if localfn:
  57. result_decoded[loc] = os.path.dirname(result_decoded[loc]) + "/" + os.path.basename(bb.fetch.localpath(uri, d))
  58. # bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: matching %s against %s and replacing with %s" % (i, uri_decoded[loc], uri_replace_decoded[loc]))
  59. else:
  60. # bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: no match")
  61. return uri
  62. # else:
  63. # for j in i.keys():
  64. # FIXME: apply replacements against options
  65. return bb.encodeurl(result_decoded)
  66. methods = []
  67. urldata = {}
  68. def init(urls = [], d = None):
  69. if d == None:
  70. bb.msg.debug(2, bb.msg.domain.Fetcher, "BUG init called with None as data object!!!")
  71. return
  72. for m in methods:
  73. m.urls = []
  74. for u in urls:
  75. ud = initdata(u, d)
  76. if ud.method:
  77. ud.method.urls.append(u)
  78. def initdata(url, d):
  79. fn = bb.data.getVar('FILE', d, 1)
  80. if fn not in urldata:
  81. urldata[fn] = {}
  82. if url not in urldata[fn]:
  83. ud = FetchData()
  84. (ud.type, ud.host, ud.path, ud.user, ud.pswd, ud.parm) = bb.decodeurl(data.expand(url, d))
  85. ud.date = Fetch.getSRCDate(ud, d)
  86. for m in methods:
  87. if m.supports(url, ud, d):
  88. ud.localpath = m.localpath(url, ud, d)
  89. ud.md5 = ud.localpath + '.md5'
  90. # if user sets localpath for file, use it instead.
  91. if "localpath" in ud.parm:
  92. ud.localpath = ud.parm["localpath"]
  93. ud.method = m
  94. break
  95. urldata[fn][url] = ud
  96. return urldata[fn][url]
  97. def go(d):
  98. """Fetch all urls"""
  99. fn = bb.data.getVar('FILE', d, 1)
  100. for m in methods:
  101. for u in m.urls:
  102. ud = urldata[fn][u]
  103. if ud.localfile and not m.forcefetch(u, ud, d) and os.path.exists(urldata[fn][u].md5):
  104. # File already present along with md5 stamp file
  105. # Touch md5 file to show activity
  106. os.utime(ud.md5, None)
  107. continue
  108. # RP - is olddir needed?
  109. # olddir = os.path.abspath(os.getcwd())
  110. m.go(u, ud , d)
  111. # os.chdir(olddir)
  112. if ud.localfile and not m.forcefetch(u, ud, d):
  113. Fetch.write_md5sum(u, ud, d)
  114. def localpaths(d):
  115. """Return a list of the local filenames, assuming successful fetch"""
  116. local = []
  117. fn = bb.data.getVar('FILE', d, 1)
  118. for m in methods:
  119. for u in m.urls:
  120. local.append(urldata[fn][u].localpath)
  121. return local
  122. def localpath(url, d):
  123. ud = initdata(url, d)
  124. if ud.method:
  125. return ud.localpath
  126. return url
  127. class FetchData(object):
  128. """Class for fetcher variable store"""
  129. def __init__(self):
  130. self.localfile = ""
  131. class Fetch(object):
  132. """Base class for 'fetch'ing data"""
  133. def __init__(self, urls = []):
  134. self.urls = []
  135. def supports(self, url, urldata, d):
  136. """
  137. Check to see if this fetch class supports a given url.
  138. """
  139. return 0
  140. def localpath(self, url, urldata, d):
  141. """
  142. Return the local filename of a given url assuming a successful fetch.
  143. Can also setup variables in urldata for use in go (saving code duplication
  144. and duplicate code execution)
  145. """
  146. return url
  147. def setUrls(self, urls):
  148. self.__urls = urls
  149. def getUrls(self):
  150. return self.__urls
  151. urls = property(getUrls, setUrls, None, "Urls property")
  152. def forcefetch(self, url, urldata, d):
  153. """
  154. Force a fetch, even if localpath exists?
  155. """
  156. return False
  157. def go(self, url, urldata, d):
  158. """
  159. Fetch urls
  160. Assumes localpath was called first
  161. """
  162. raise NoMethodError("Missing implementation for url")
  163. def getSRCDate(urldata, d):
  164. """
  165. Return the SRC Date for the component
  166. d the bb.data module
  167. """
  168. if "srcdate" in urldata.parm:
  169. return urldata.parm['srcdate']
  170. pn = data.getVar("PN", d, 1)
  171. if pn:
  172. return data.getVar("SRCDATE_%s" % pn, d, 1) or data.getVar("CVSDATE_%s" % pn, d, 1) or data.getVar("DATE", d, 1)
  173. return data.getVar("SRCDATE", d, 1) or data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1)
  174. getSRCDate = staticmethod(getSRCDate)
  175. def try_mirror(d, tarfn):
  176. """
  177. Try to use a mirrored version of the sources. We do this
  178. to avoid massive loads on foreign cvs and svn servers.
  179. This method will be used by the different fetcher
  180. implementations.
  181. d Is a bb.data instance
  182. tarfn is the name of the tarball
  183. """
  184. tarpath = os.path.join(data.getVar("DL_DIR", d, 1), tarfn)
  185. if os.access(tarpath, os.R_OK):
  186. bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists, skipping checkout." % tarfn)
  187. return True
  188. pn = data.getVar('PN', d, True)
  189. src_tarball_stash = None
  190. if pn:
  191. src_tarball_stash = (data.getVar('SRC_TARBALL_STASH_%s' % pn, d, True) or data.getVar('CVS_TARBALL_STASH_%s' % pn, d, True) or data.getVar('SRC_TARBALL_STASH', d, True) or data.getVar('CVS_TARBALL_STASH', d, True) or "").split()
  192. for stash in src_tarball_stash:
  193. fetchcmd = data.getVar("FETCHCOMMAND_mirror", d, True) or data.getVar("FETCHCOMMAND_wget", d, True)
  194. uri = stash + tarfn
  195. bb.msg.note(1, bb.msg.domain.Fetcher, "fetch " + uri)
  196. fetchcmd = fetchcmd.replace("${URI}", uri)
  197. ret = os.system(fetchcmd)
  198. if ret == 0:
  199. bb.msg.note(1, bb.msg.domain.Fetcher, "Fetched %s from tarball stash, skipping checkout" % tarfn)
  200. return True
  201. return False
  202. try_mirror = staticmethod(try_mirror)
  203. def verify_md5sum(ud, got_sum):
  204. """
  205. Verify the md5sum we wanted with the one we got
  206. """
  207. wanted_sum = None
  208. if 'md5sum' in ud.parm:
  209. wanted_sum = ud.parm['md5sum']
  210. if not wanted_sum:
  211. return True
  212. return wanted_sum == got_sum
  213. verify_md5sum = staticmethod(verify_md5sum)
  214. def write_md5sum(url, ud, d):
  215. if bb.which(data.getVar('PATH', d), 'md5sum'):
  216. try:
  217. md5pipe = os.popen('md5sum ' + ud.localpath)
  218. md5data = (md5pipe.readline().split() or [ "" ])[0]
  219. md5pipe.close()
  220. except OSError:
  221. md5data = ""
  222. # verify the md5sum
  223. if not Fetch.verify_md5sum(ud, md5data):
  224. raise MD5SumError(url)
  225. md5out = file(ud.md5, 'w')
  226. md5out.write(md5data)
  227. md5out.close()
  228. write_md5sum = staticmethod(write_md5sum)
  229. import cvs
  230. import git
  231. import local
  232. import svn
  233. import wget
  234. import svk
  235. import ssh
  236. import perforce
  237. methods.append(cvs.Cvs())
  238. methods.append(git.Git())
  239. methods.append(local.Local())
  240. methods.append(svn.Svn())
  241. methods.append(wget.Wget())
  242. methods.append(svk.Svk())
  243. methods.append(ssh.SSH())
  244. methods.append(perforce.Perforce())