7b3f42b0fa6a57bd9b9ac2a01a3d1142a9599ea2
[vuplus_bitbake] / bin / oe / fetch.py
1 #!/usr/bin/env python
2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4 """
5 OpenEmbedded 'Fetch' implementations
6
7 Classes for obtaining upstream sources for the
8 OpenEmbedded (http://openembedded.org) build infrastructure.
9
10 NOTE that it requires Python 2.x due to its use of static methods.
11
12 Copyright: (c) 2003 Chris Larson
13
14 Based on functions from the base oe module, Copyright 2003 Holger Schurig
15 """
16
17 import os, re
18 import oe
19 import oe.data
20
21 class FetchError(Exception):
22     """Exception raised when a download fails"""
23
24 class NoMethodError(Exception):
25     """Exception raised when there is no method to obtain a supplied url or set of urls"""
26
27 class MissingParameterError(Exception):
28     """Exception raised when a fetch method is missing a critical parameter in the url"""
29
30 #decodeurl("cvs://anoncvs:anonymous@cvs.handhelds.org/cvs;module=familiar/dist/ipkg;tag=V0-99-81")
31 #('cvs', 'cvs.handhelds.org', '/cvs', 'anoncvs', 'anonymous', {'tag': 'V0-99-81', 'module': 'familiar/dist/ipkg'})
32
33 def uri_replace(uri, uri_find, uri_replace, d = oe.data.init()):
34 #   oe.note("uri_replace: operating on %s" % uri)
35     if not uri or not uri_find or not uri_replace:
36         oe.debug(1, "uri_replace: passed an undefined value, not replacing")
37     uri_decoded = list(oe.decodeurl(uri))
38     uri_find_decoded = list(oe.decodeurl(uri_find))
39     uri_replace_decoded = list(oe.decodeurl(uri_replace))
40     result_decoded = ['','','','','',{}]
41     for i in uri_find_decoded:
42         loc = uri_find_decoded.index(i)
43         result_decoded[loc] = uri_decoded[loc]
44         import types
45         if type(i) == types.StringType:
46             import re
47             if (re.match(i, uri_decoded[loc])):
48                 result_decoded[loc] = re.sub(i, uri_replace_decoded[loc], uri_decoded[loc])
49                 if uri_find_decoded.index(i) == 2:
50                     if d:
51                         localfn = oe.fetch.localpath(uri, d)
52                         if localfn:
53                             result_decoded[loc] = os.path.dirname(result_decoded[loc]) + "/" + os.path.basename(oe.fetch.localpath(uri, d))
54 #                       oe.note("uri_replace: matching %s against %s and replacing with %s" % (i, uri_decoded[loc], uri_replace_decoded[loc]))
55             else:
56 #               oe.note("uri_replace: no match")
57                 return uri
58 #           else:
59 #               for j in i.keys():
60 #                   FIXME: apply replacements against options
61     return oe.encodeurl(result_decoded)
62
63 methods = []
64
65 def init(urls = [], d = oe.data.init()):
66     for m in methods:
67         m.urls = []
68
69     for u in urls:
70         for m in methods:
71             m.data = d
72             if m.supports(u, d):
73                 m.urls.append(u)
74
75 def go(d = oe.data.init()):
76     """Fetch all urls"""
77     for m in methods:
78         if m.urls:
79             m.go(d)
80
81 def localpaths(d):
82     """Return a list of the local filenames, assuming successful fetch"""
83     local = []
84     for m in methods:
85         for u in m.urls:
86             local.append(m.localpath(u, d))
87     return local
88
89 def localpath(url, d = oe.data.init()):
90     for m in methods:
91         if m.supports(url, d):
92             return m.localpath(url, d)
93     return url
94
95 class Fetch(object):
96     """Base class for 'fetch'ing data"""
97
98     def __init__(self, urls = []):
99         self.urls = []
100         for url in urls:
101             if self.supports(oe.decodeurl(url), d) is 1:
102                 self.urls.append(url)
103
104     def supports(url, d):
105         """Check to see if this fetch class supports a given url.
106            Expects supplied url in list form, as outputted by oe.decodeurl().
107         """
108         return 0
109     supports = staticmethod(supports)
110
111     def localpath(url, d = oe.data.init()):
112         """Return the local filename of a given url assuming a successful fetch.
113         """
114         return url
115     localpath = staticmethod(localpath)
116
117     def setUrls(self, urls):
118         self.__urls = urls
119
120     def getUrls(self):
121         return self.__urls
122
123     urls = property(getUrls, setUrls, None, "Urls property")
124
125     def setData(self, data):
126         self.__data = data
127
128     def getData(self):
129         return self.__data
130
131     data = property(getData, setData, None, "Data property")
132
133     def go(self, urls = []):
134         """Fetch urls"""
135         raise NoMethodError("Missing implementation for url")
136
137 class Wget(Fetch):
138     """Class to fetch urls via 'wget'"""
139     def supports(url, d):
140         """Check to see if a given url can be fetched using wget.
141            Expects supplied url in list form, as outputted by oe.decodeurl().
142         """
143         (type, host, path, user, pswd, parm) = oe.decodeurl(oe.data.expand(url, d))
144         return type in ['http','https','ftp']
145     supports = staticmethod(supports)
146
147     def localpath(url, d):
148 #       strip off parameters
149         (type, host, path, user, pswd, parm) = oe.decodeurl(oe.data.expand(url, d))
150         if "localpath" in parm:
151 #           if user overrides local path, use it.
152             return parm["localpath"]
153         url = oe.encodeurl([type, host, path, user, pswd, {}])
154         return os.path.join(oe.data.getVar("DL_DIR", d), os.path.basename(url))
155     localpath = staticmethod(localpath)
156
157     def go(self, d = oe.data.init(), urls = []):
158         """Fetch urls"""
159         def fetch_uri(uri, basename, dl, md5, d):
160             if os.path.exists(dl):
161 #               file exists, but we didnt complete it.. trying again..
162                 fetchcmd = oe.data.getVar("RESUMECOMMAND", d, 1)
163             else:
164                 fetchcmd = oe.data.getVar("FETCHCOMMAND", d, 1)
165
166             oe.note("fetch " + uri)
167             fetchcmd = fetchcmd.replace("${URI}", uri)
168             fetchcmd = fetchcmd.replace("${FILE}", basename)
169             oe.debug(2, "executing " + fetchcmd)
170             ret = os.system(fetchcmd)
171             if ret != 0:
172                 return False
173
174 #           supposedly complete.. write out md5sum
175             if oe.which(oe.data.getVar('PATH', d), 'md5sum'):
176                 try:
177                     md5pipe = os.popen('md5sum ' + dl)
178                     md5data = (md5pipe.readline().split() or [ "" ])[0]
179                     md5pipe.close()
180                 except OSError:
181                     md5data = ""
182                 md5out = file(md5, 'w')
183                 md5out.write(md5data)
184                 md5out.close()
185             else:
186                 md5out = file(md5, 'w')
187                 md5out.write("")
188                 md5out.close()
189             return True
190
191         if not urls:
192             urls = self.urls
193
194         from copy import deepcopy
195         localdata = deepcopy(d)
196         oe.data.setVar('OVERRIDES', "wget:" + oe.data.getVar('OVERRIDES', localdata), localdata)
197         oe.data.update_data(localdata)
198
199         for uri in urls:
200             completed = 0
201             (type, host, path, user, pswd, parm) = oe.decodeurl(oe.data.expand(uri, localdata))
202             basename = os.path.basename(path)
203             dl = self.localpath(uri, d)
204             dl = oe.data.expand(dl, localdata)
205             md5 = dl + '.md5'
206
207             if os.path.exists(md5):
208 #               complete, nothing to see here..
209                 continue
210
211             premirrors = [ i.split() for i in (oe.data.getVar('PREMIRRORS', localdata, 1) or "").split('\n') if i ]
212             for (find, replace) in premirrors:
213                 newuri = uri_replace(uri, find, replace)
214                 if newuri != uri:
215                     if fetch_uri(newuri, basename, dl, md5, localdata):
216                         completed = 1
217                         break
218
219             if completed:
220                 continue
221
222             if fetch_uri(uri, basename, dl, md5, localdata):
223                 continue
224
225 #           try mirrors
226             mirrors = [ i.split() for i in (oe.data.getVar('MIRRORS', localdata, 1) or "").split('\n') if i ]
227             for (find, replace) in mirrors:
228                 newuri = uri_replace(uri, find, replace)
229                 if newuri != uri:
230                     if fetch_uri(newuri, basename, dl, md5, localdata):
231                         completed = 1
232                         break
233
234             if not completed:
235                 raise FetchError(uri)
236
237         del localdata
238
239
240 methods.append(Wget())
241
242 class Cvs(Fetch):
243     """Class to fetch a module or modules from cvs repositories"""
244     def supports(url, d):
245         """Check to see if a given url can be fetched with cvs.
246            Expects supplied url in list form, as outputted by oe.decodeurl().
247         """
248         (type, host, path, user, pswd, parm) = oe.decodeurl(oe.data.expand(url, d))
249         return type in ['cvs', 'pserver']
250     supports = staticmethod(supports)
251
252     def localpath(url, d):
253         (type, host, path, user, pswd, parm) = oe.decodeurl(oe.data.expand(url, d))
254         if "localpath" in parm:
255 #           if user overrides local path, use it.
256             return parm["localpath"]
257
258         if not "module" in parm:
259             raise MissingParameterError("cvs method needs a 'module' parameter")
260         else:
261             module = parm["module"]
262         if 'tag' in parm:
263             tag = parm['tag']
264         else:
265             tag = ""
266         if 'date' in parm:
267             date = parm['date']
268         else:
269             if not tag:
270                 date = oe.data.getVar("CVSDATE", d, 1) or oe.data.getVar("DATE", d, 1)
271             else:
272                 date = ""
273
274         return os.path.join(oe.data.getVar("DL_DIR", d, 1),oe.data.expand('%s_%s_%s_%s.tar.gz' % ( module.replace('/', '.'), host, tag, date), d))
275     localpath = staticmethod(localpath)
276
277     def go(self, d = oe.data.init(), urls = []):
278         """Fetch urls"""
279         if not urls:
280             urls = self.urls
281
282         from copy import deepcopy
283         localdata = deepcopy(d)
284         oe.data.setVar('OVERRIDES', "cvs:%s" % oe.data.getVar('OVERRIDES', localdata), localdata)
285         oe.data.update_data(localdata)
286
287         for loc in urls:
288             (type, host, path, user, pswd, parm) = oe.decodeurl(oe.data.expand(loc, localdata))
289             if not "module" in parm:
290                 raise MissingParameterError("cvs method needs a 'module' parameter")
291             else:
292                 module = parm["module"]
293
294             dlfile = self.localpath(loc, localdata)
295             dldir = oe.data.getVar('DL_DIR', localdata, 1)
296 #           if local path contains the cvs
297 #           module, consider the dir above it to be the
298 #           download directory
299 #           pos = dlfile.find(module)
300 #           if pos:
301 #               dldir = dlfile[:pos]
302 #           else:
303 #               dldir = os.path.dirname(dlfile)
304
305 #           setup cvs options
306             options = []
307             if 'tag' in parm:
308                 tag = parm['tag']
309             else:
310                 tag = ""
311
312             if 'date' in parm:
313                 date = parm['date']
314             else:
315                 if not tag:
316                     date = oe.data.getVar("CVSDATE", d, 1) or oe.data.getVar("DATE", d, 1)
317                 else:
318                     date = ""
319
320             if "method" in parm:
321                 method = parm["method"]
322             else:
323                 method = "pserver"
324
325             if "localdir" in parm:
326                 localdir = parm["localdir"]
327             else:
328                 localdir = os.path.basename(module)
329
330             cvs_rsh = None
331             if method == "ext":
332                 if "rsh" in parm:
333                     cvs_rsh = parm["rsh"]
334
335             tarfn = oe.data.expand('%s_%s_%s_%s.tar.gz' % (module.replace('/', '.'), host, tag, date), localdata)
336             oe.data.setVar('TARFILES', dlfile, localdata)
337             oe.data.setVar('TARFN', tarfn, localdata)
338
339             dl = os.path.join(dldir, tarfn)
340             if os.access(dl, os.R_OK):
341                 oe.debug(1, "%s already exists, skipping cvs checkout." % tarfn)
342                 continue
343
344             pn = oe.data.getVar('PN', d, 1)
345             cvs_tarball_stash = None
346             if pn:
347                 cvs_tarball_stash = oe.data.getVar('CVS_TARBALL_STASH_%s' % pn, d, 1)
348             if cvs_tarball_stash == None:
349                 cvs_tarball_stash = oe.data.getVar('CVS_TARBALL_STASH', d, 1)
350             if cvs_tarball_stash:
351                 fetchcmd = oe.data.getVar("FETCHCOMMAND_wget", d, 1)
352                 uri = cvs_tarball_stash + tarfn
353                 oe.note("fetch " + uri)
354                 fetchcmd = fetchcmd.replace("${URI}", uri)
355                 ret = os.system(fetchcmd)
356                 if ret == 0:
357                     oe.note("Fetched %s from tarball stash, skipping checkout" % tarfn)
358                     continue
359
360             if date:
361                 options.append("-D %s" % date)
362             if tag:
363                 options.append("-r %s" % tag)
364
365             olddir = os.path.abspath(os.getcwd())
366             os.chdir(oe.data.expand(dldir, localdata))
367
368 #           setup cvsroot
369             if method == "dir":
370                 cvsroot = path
371             else:
372                 cvsroot = ":" + method + ":" + user
373                 if pswd:
374                     cvsroot += ":" + pswd
375                 cvsroot += "@" + host + ":" + path
376
377             oe.data.setVar('CVSROOT', cvsroot, localdata)
378             oe.data.setVar('CVSCOOPTS', " ".join(options), localdata)
379             oe.data.setVar('CVSMODULE', module, localdata)
380             cvscmd = oe.data.getVar('FETCHCOMMAND', localdata, 1)
381             cvsupdatecmd = oe.data.getVar('UPDATECOMMAND', localdata, 1)
382
383             if cvs_rsh:
384                 cvscmd = "CVS_RSH=\"%s\" %s" % (cvs_rsh, cvscmd)
385
386 #           create module directory
387             oe.debug(2, "Fetch: checking for module directory")
388             pkg=oe.data.expand('${PN}', d)
389             pkgdir=os.path.join(oe.data.expand('${CVSDIR}', localdata), pkg)
390             moddir=os.path.join(pkgdir,module)
391             if os.access(os.path.join(moddir,'CVS'), os.R_OK):
392                 oe.note("Update " + loc)
393 #               update sources there
394                 os.chdir(moddir)
395                 myret = os.system(cvsupdatecmd)
396             else:
397                 oe.note("Fetch " + loc)
398 #               check out sources there
399                 oe.mkdirhier(pkgdir)
400                 os.chdir(pkgdir)
401                 oe.debug(1, "Running %s" % cvscmd)
402                 myret = os.system(cvscmd)
403
404             if myret != 0:
405                 try:
406                     os.rmdir(moddir)
407                 except OSError:
408                     pass
409                 raise FetchError(module)
410
411             os.chdir(moddir)
412             os.chdir('..')
413 #           tar them up to a defined filename
414             myret = os.system("tar -czf %s %s" % (os.path.join(dldir,tarfn), localdir))
415             if myret != 0:
416                 try:
417                     os.unlink(tarfn)
418                 except OSError:
419                     pass
420             os.chdir(olddir)
421         del localdata
422
423 methods.append(Cvs())
424
425 class Bk(Fetch):
426     def supports(url, d):
427         """Check to see if a given url can be fetched via bitkeeper.
428            Expects supplied url in list form, as outputted by oe.decodeurl().
429         """
430         (type, host, path, user, pswd, parm) = oe.decodeurl(oe.data.expand(url, d))
431         return type in ['bk']
432     supports = staticmethod(supports)
433
434 methods.append(Bk())
435
436 class Local(Fetch):
437     def supports(url, d):
438         """Check to see if a given url can be fetched in the local filesystem.
439            Expects supplied url in list form, as outputted by oe.decodeurl().
440         """
441         (type, host, path, user, pswd, parm) = oe.decodeurl(oe.data.expand(url, d))
442         return type in ['file','patch']
443     supports = staticmethod(supports)
444
445     def localpath(url, d):
446         """Return the local filename of a given url assuming a successful fetch.
447         """
448         path = url.split("://")[1]
449         newpath = path
450         if path[0] != "/":
451             filespath = oe.data.getVar('FILESPATH', d, 1)
452             if filespath:
453                 newpath = oe.which(filespath, path)
454             if not newpath:
455                 filesdir = oe.data.getVar('FILESDIR', d, 1)
456                 if filesdir:
457                     newpath = os.path.join(filesdir, path)
458         return newpath
459     localpath = staticmethod(localpath)
460
461     def go(self, urls = []):
462         """Fetch urls (no-op for Local method)"""
463 #       no need to fetch local files, we'll deal with them in place.
464         return 1
465
466 methods.append(Local())
467
468 class Svn(Fetch):
469     """Class to fetch a module or modules from svn repositories"""
470     def supports(url, d):
471         """Check to see if a given url can be fetched with svn.
472            Expects supplied url in list form, as outputted by oe.decodeurl().
473         """
474         (type, host, path, user, pswd, parm) = oe.decodeurl(oe.data.expand(url, d))
475         return type in ['svn']
476     supports = staticmethod(supports)
477
478     def localpath(url, d):
479         (type, host, path, user, pswd, parm) = oe.decodeurl(oe.data.expand(url, d))
480         if "localpath" in parm:
481 #           if user overrides local path, use it.
482             return parm["localpath"]
483
484         if not "module" in parm:
485             raise MissingParameterError("svn method needs a 'module' parameter")
486         else:
487             module = parm["module"]
488         if 'tag' in parm:
489             tag = parm['tag']
490         else:
491             tag = ""
492         if 'date' in parm:
493             date = parm['date']
494         else:
495             if not tag or tag == "HEAD":
496                 date = oe.data.getVar("CVSDATE", d, 1) or oe.data.getVar("DATE", d, 1)
497             else:
498                 date = ""
499
500         return os.path.join(oe.data.getVar("DL_DIR", d, 1),oe.data.expand('%s_%s_%s_%s.tar.gz' % ( module.replace('/', '.'), host, tag, date), d))
501     localpath = staticmethod(localpath)
502
503     def go(self, d = oe.data.init(), urls = []):
504         """Fetch urls"""
505         if not urls:
506             urls = self.urls
507
508         from copy import deepcopy
509         localdata = deepcopy(d)
510         oe.data.setVar('OVERRIDES', "svn:%s" % oe.data.getVar('OVERRIDES', localdata), localdata)
511         oe.data.update_data(localdata)
512
513         for loc in urls:
514             (type, host, path, user, pswd, parm) = oe.decodeurl(oe.data.expand(loc, localdata))
515             if not "module" in parm:
516                 raise MissingParameterError("svn method needs a 'module' parameter")
517             else:
518                 module = parm["module"]
519
520             dlfile = self.localpath(loc, localdata)
521             dldir = oe.data.getVar('DL_DIR', localdata, 1)
522 #           if local path contains the svn
523 #           module, consider the dir above it to be the
524 #           download directory
525 #           pos = dlfile.find(module)
526 #           if pos:
527 #               dldir = dlfile[:pos]
528 #           else:
529 #               dldir = os.path.dirname(dlfile)
530
531 #           setup svn options
532             options = []
533             if 'tag' in parm:
534                 tag = parm['tag']
535             else:
536                 tag = ""
537
538             if 'date' in parm:
539                 date = parm['date']
540             else:
541                 if not tag or tag == "HEAD":
542                     date = oe.data.getVar("CVSDATE", d, 1) or oe.data.getVar("DATE", d, 1)
543                 else:
544                     date = ""
545
546             if "method" in parm:
547                 method = parm["method"]
548             else:
549                 method = "pserver"
550
551             svn_rsh = None
552             if method == "ext":
553                 if "rsh" in parm:
554                     svn_rsh = parm["rsh"]
555
556             tarfn = oe.data.expand('%s_%s_%s_%s.tar.gz' % (module.replace('/', '.'), host, tag, date), localdata)
557             oe.data.setVar('TARFILES', dlfile, localdata)
558             oe.data.setVar('TARFN', tarfn, localdata)
559
560             dl = os.path.join(dldir, tarfn)
561             if os.access(dl, os.R_OK):
562                 oe.debug(1, "%s already exists, skipping svn checkout." % tarfn)
563                 continue
564
565             svn_tarball_stash = oe.data.getVar('CVS_TARBALL_STASH', d, 1)
566             if svn_tarball_stash:
567                 fetchcmd = oe.data.getVar("FETCHCOMMAND_wget", d, 1)
568                 uri = svn_tarball_stash + tarfn
569                 oe.note("fetch " + uri)
570                 fetchcmd = fetchcmd.replace("${URI}", uri)
571                 ret = os.system(fetchcmd)
572                 if ret == 0:
573                     oe.note("Fetched %s from tarball stash, skipping checkout" % tarfn)
574                     continue
575
576             if date:
577                 options.append("-D %s" % date)
578             if tag:
579                 options.append("-r %s" % tag)
580
581             olddir = os.path.abspath(os.getcwd())
582             os.chdir(oe.data.expand(dldir, localdata))
583
584 #           setup svnroot
585 #            svnroot = ":" + method + ":" + user
586 #            if pswd:
587 #                svnroot += ":" + pswd
588             svnroot = host + path
589
590             oe.data.setVar('SVNROOT', svnroot, localdata)
591             oe.data.setVar('SVNCOOPTS', " ".join(options), localdata)
592             oe.data.setVar('SVNMODULE', module, localdata)
593             svncmd = oe.data.getVar('FETCHCOMMAND', localdata, 1)
594             svncmd = "svn co http://%s/%s" % (svnroot, module)
595
596             if svn_rsh:
597                 svncmd = "svn_RSH=\"%s\" %s" % (svn_rsh, svncmd)
598
599 #           create temp directory
600             oe.debug(2, "Fetch: creating temporary directory")
601             oe.mkdirhier(oe.data.expand('${WORKDIR}', localdata))
602             oe.data.setVar('TMPBASE', oe.data.expand('${WORKDIR}/oesvn.XXXXXX', localdata), localdata)
603             tmppipe = os.popen(oe.data.getVar('MKTEMPDIRCMD', localdata, 1) or "false")
604             tmpfile = tmppipe.readline().strip()
605             if not tmpfile:
606                 oe.error("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.")
607                 raise FetchError(module)
608
609 #           check out sources there
610             os.chdir(tmpfile)
611             oe.note("Fetch " + loc)
612             oe.note(svncmd)
613             oe.debug(1, "Running %s" % svncmd)
614             myret = os.system(svncmd)
615             if myret != 0:
616                 try:
617                     os.rmdir(tmpfile)
618                 except OSError:
619                     pass
620                 raise FetchError(module)
621
622             os.chdir(os.path.join(tmpfile, os.path.dirname(module)))
623 #           tar them up to a defined filename
624             myret = os.system("tar -czf %s %s" % (os.path.join(dldir,tarfn), os.path.basename(module)))
625             if myret != 0:
626                 try:
627                     os.unlink(tarfn)
628                 except OSError:
629                     pass
630 #           cleanup
631             os.system('rm -rf %s' % tmpfile)
632             os.chdir(olddir)
633         del localdata
634
635 methods.append(Svn())