Convert fetchers to use bb.msg
[bitbake.git] / lib / bb / fetch / __init__.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 BitBake 'Fetch' implementations
6
7 Classes for obtaining upstream sources for the
8 BitBake build tools.
9
10 Copyright (C) 2003, 2004  Chris Larson
11
12 This program is free software; you can redistribute it and/or modify it under
13 the terms of the GNU General Public License as published by the Free Software
14 Foundation; either version 2 of the License, or (at your option) any later
15 version.
16
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23 Place, Suite 330, Boston, MA 02111-1307 USA. 
24
25 Based on functions from the base bb module, Copyright 2003 Holger Schurig
26 """
27
28 import os, re
29 import bb
30 from   bb import data
31
32 class FetchError(Exception):
33     """Exception raised when a download fails"""
34
35 class NoMethodError(Exception):
36     """Exception raised when there is no method to obtain a supplied url or set of urls"""
37
38 class MissingParameterError(Exception):
39     """Exception raised when a fetch method is missing a critical parameter in the url"""
40
41 class ParameterError(Exception):
42     """Exception raised when a url cannot be proccessed due to invalid parameters."""
43
44 class MD5SumError(Exception):
45     """Exception raised when a MD5SUM of a file does not match the expected one"""
46
47 def uri_replace(uri, uri_find, uri_replace, d):
48 #   bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: operating on %s" % uri)
49     if not uri or not uri_find or not uri_replace:
50         bb.msg.debug(1, bb.msg.domain.Fetcher, "uri_replace: passed an undefined value, not replacing")
51     uri_decoded = list(bb.decodeurl(uri))
52     uri_find_decoded = list(bb.decodeurl(uri_find))
53     uri_replace_decoded = list(bb.decodeurl(uri_replace))
54     result_decoded = ['','','','','',{}]
55     for i in uri_find_decoded:
56         loc = uri_find_decoded.index(i)
57         result_decoded[loc] = uri_decoded[loc]
58         import types
59         if type(i) == types.StringType:
60             import re
61             if (re.match(i, uri_decoded[loc])):
62                 result_decoded[loc] = re.sub(i, uri_replace_decoded[loc], uri_decoded[loc])
63                 if uri_find_decoded.index(i) == 2:
64                     if d:
65                         localfn = bb.fetch.localpath(uri, d)
66                         if localfn:
67                             result_decoded[loc] = os.path.dirname(result_decoded[loc]) + "/" + os.path.basename(bb.fetch.localpath(uri, d))
68 #                       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]))
69             else:
70 #               bb.msg.note(1, bb.msg.domain.Fetcher, "uri_replace: no match")
71                 return uri
72 #           else:
73 #               for j in i.keys():
74 #                   FIXME: apply replacements against options
75     return bb.encodeurl(result_decoded)
76
77 methods = []
78
79 def init(urls = [], d = None):
80     if d == None:
81         bb.msg.debug(2, bb.msg.domain.Fetcher, "BUG init called with None as data object!!!")
82         return
83
84     for m in methods:
85         m.urls = []
86
87     for u in urls:
88         for m in methods:
89             m.data = d
90             if m.supports(u, d):
91                 m.urls.append(u)
92
93 def go(d):
94     """Fetch all urls"""
95     for m in methods:
96         if m.urls:
97             m.go(d)
98
99 def localpaths(d):
100     """Return a list of the local filenames, assuming successful fetch"""
101     local = []
102     for m in methods:
103         for u in m.urls:
104             local.append(m.localpath(u, d))
105     return local
106
107 def localpath(url, d):
108     for m in methods:
109         if m.supports(url, d):
110             return m.localpath(url, d)
111     return url
112
113 class Fetch(object):
114     """Base class for 'fetch'ing data"""
115
116     def __init__(self, urls = []):
117         self.urls = []
118         for url in urls:
119             if self.supports(bb.decodeurl(url), d) is 1:
120                 self.urls.append(url)
121
122     def supports(url, d):
123         """Check to see if this fetch class supports a given url.
124            Expects supplied url in list form, as outputted by bb.decodeurl().
125         """
126         return 0
127     supports = staticmethod(supports)
128
129     def localpath(url, d):
130         """Return the local filename of a given url assuming a successful fetch.
131         """
132         return url
133     localpath = staticmethod(localpath)
134
135     def setUrls(self, urls):
136         self.__urls = urls
137
138     def getUrls(self):
139         return self.__urls
140
141     urls = property(getUrls, setUrls, None, "Urls property")
142
143     def setData(self, data):
144         self.__data = data
145
146     def getData(self):
147         return self.__data
148
149     data = property(getData, setData, None, "Data property")
150
151     def go(self, urls = []):
152         """Fetch urls"""
153         raise NoMethodError("Missing implementation for url")
154
155     def getSRCDate(d):
156         """
157         Return the SRC Date for the component
158
159         d the bb.data module
160         """
161         return data.getVar("SRCDATE", d, 1) or data.getVar("CVSDATE", d, 1) or data.getVar("DATE", d, 1 )
162     getSRCDate = staticmethod(getSRCDate)
163
164     def try_mirror(d, tarfn):
165         """
166         Try to use a mirrored version of the sources. We do this
167         to avoid massive loads on foreign cvs and svn servers.
168         This method will be used by the different fetcher
169         implementations.
170
171         d Is a bb.data instance
172         tarfn is the name of the tarball
173         """
174         tarpath = os.path.join(data.getVar("DL_DIR", d, 1), tarfn)
175         if os.access(tarpath, os.R_OK):
176             bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists, skipping checkout." % tarfn)
177             return True
178
179         pn = data.getVar('PN', d, True)
180         src_tarball_stash = None
181         if pn:
182             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()
183
184         for stash in src_tarball_stash:
185             fetchcmd = data.getVar("FETCHCOMMAND_mirror", d, True) or data.getVar("FETCHCOMMAND_wget", d, True)
186             uri = stash + tarfn
187             bb.msg.note(1, bb.msg.domain.Fetcher, "fetch " + uri)
188             fetchcmd = fetchcmd.replace("${URI}", uri)
189             ret = os.system(fetchcmd)
190             if ret == 0:
191                 bb.msg.note(1, bb.msg.domain.Fetcher, "Fetched %s from tarball stash, skipping checkout" % tarfn)
192                 return True
193         return False
194     try_mirror = staticmethod(try_mirror)
195
196     def check_for_tarball(d, tarfn, dldir, date):
197         """
198         Check for a local copy then check the tarball stash.
199         Both checks are skipped if date == 'now'.
200
201         d Is a bb.data instance
202         tarfn is the name of the tarball
203         date is the SRCDATE
204         """
205         if "now" != date:
206             dl = os.path.join(dldir, tarfn)
207             if os.access(dl, os.R_OK):
208                 bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists, skipping checkout." % tarfn)
209                 return True
210
211             # try to use the tarball stash
212             if Fetch.try_mirror(d, tarfn):
213                 return True
214         return False
215     check_for_tarball = staticmethod(check_for_tarball)
216
217
218 import cvs
219 import git
220 import local
221 import svn
222 import wget
223 import svk
224
225 methods.append(cvs.Cvs())
226 methods.append(git.Git())
227 methods.append(local.Local())
228 methods.append(svn.Svn())
229 methods.append(wget.Wget())
230 methods.append(svk.Svk())