]>
git.ipfire.org Git - pakfire.git/blob - python/pakfire/downloader.py
0b5b5b6a47f59cd8c87301c37d01a3a71330b8cc
2 ###############################################################################
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
28 log
= logging
.getLogger("pakfire")
30 from config
import _Config
32 import urlgrabber
.grabber
33 from urlgrabber
.grabber
import URLGrabber
, URLGrabError
34 from urlgrabber
.mirror
import MirrorGroup
35 from urlgrabber
.progress
import TextMeter
37 from pakfire
.constants
import *
38 from pakfire
.i18n
import _
40 class PakfireGrabber(URLGrabber
):
42 Class to make some modifications on the urlgrabber configuration.
44 def __init__(self
, pakfire
, *args
, **kwargs
):
47 "user_agent" : "pakfire/%s" % PAKFIRE_VERSION
,
49 "ssl_verify_host" : False,
50 "ssl_verify_peer" : False,
53 if isinstance(pakfire
, _Config
):
56 config
= pakfire
.config
59 # Set throttle setting.
60 bandwidth_throttle
= config
.get("downloader", "bandwidth_throttle")
61 if bandwidth_throttle
:
63 bandwidth_throttle
= int(bandwidth_throttle
)
65 log
.error("Configuration value for bandwidth_throttle is invalid.")
66 bandwidth_throttle
= 0
68 kwargs
.update({ "throttle" : bandwidth_throttle
})
70 # Configure HTTP proxy.
71 http_proxy
= config
.get("downloader", "http_proxy")
73 kwargs
.update({ "proxies" : { "http" : http_proxy
, "https" : http_proxy
}})
75 URLGrabber
.__init
__(self
, *args
, **kwargs
)
77 def check_offline_mode(self
):
78 offline
= self
.config
.get("downloader", "offline")
82 raise OfflineModeError
84 def urlread(self
, filename
, *args
, **kwargs
):
85 self
.check_offline_mode()
87 # This is for older versions of urlgrabber which are packaged in Debian
88 # and Ubuntu and cannot handle filenames as a normal Python string but need
90 return URLGrabber
.urlread(self
, filename
.encode("utf-8"), *args
, **kwargs
)
92 def urlopen(self
, filename
, *args
, **kwargs
):
93 self
.check_offline_mode()
95 # This is for older versions of urlgrabber which are packaged in Debian
96 # and Ubuntu and cannot handle filenames as a normal Python string but need
98 return URLGrabber
.urlopen(self
, filename
.encode("utf-8"), *args
, **kwargs
)
100 def urlgrab(self
, url
, *args
, **kwargs
):
101 self
.check_offline_mode()
103 # This is for older versions of urlgrabber which are packaged in Debian
104 # and Ubuntu and cannot handle filenames as a normal Python string but need
106 return URLGrabber
.urlgrab(self
, url
.encode("utf-8"), *args
, **kwargs
)
109 class PackageDownloader(PakfireGrabber
):
110 def __init__(self
, pakfire
, *args
, **kwargs
):
112 "progress_obj" : TextMeter(),
115 PakfireGrabber
.__init
__(self
, pakfire
, *args
, **kwargs
)
118 class MetadataDownloader(PakfireGrabber
):
119 def __init__(self
, pakfire
, *args
, **kwargs
):
121 "http_headers" : (('Pragma', 'no-cache'),),
124 PakfireGrabber
.__init
__(self
, pakfire
, *args
, **kwargs
)
127 class DatabaseDownloader(PackageDownloader
):
128 def __init__(self
, pakfire
, *args
, **kwargs
):
130 "http_headers" : (('Pragma', 'no-cache'),),
133 PackageDownloader
.__init
__(self
, pakfire
, *args
, **kwargs
)
136 class SourceDownloader(object):
137 def __init__(self
, pakfire
, mirrors
=None):
138 self
.pakfire
= pakfire
140 self
.grabber
= PakfireGrabber(
142 progress_obj
= TextMeter(),
146 self
.grabber
= MirrorGroup(self
.grabber
,
147 [{ "mirror" : m
.encode("utf-8") } for m
in mirrors
])
149 def download(self
, files
):
154 filename
= os
.path
.join(SOURCE_CACHE_DIR
, file)
155 log
.debug("Checking existance of %s..." % filename
)
157 if os
.path
.exists(filename
) and os
.path
.getsize(filename
):
158 log
.debug("...exists!")
159 existant_files
.append(filename
)
161 log
.debug("...does not exist!")
162 download_files
.append(filename
)
165 log
.info(_("Downloading source files:"))
167 if self
.pakfire
.offline
:
168 raise OfflineModeError
, _("Cannot download source code in offline mode.")
170 # Create source download directory.
171 if not os
.path
.exists(SOURCE_CACHE_DIR
):
172 os
.makedirs(SOURCE_CACHE_DIR
)
174 for filename
in download_files
:
176 self
.grabber
.urlgrab(os
.path
.basename(filename
), filename
=filename
)
177 except URLGrabError
, e
:
178 # Remove partly downloaded file.
184 raise DownloadError
, "%s %s" % (os
.path
.basename(filename
), e
)
186 # Check if the downloaded file was empty.
187 if os
.path
.getsize(filename
) == 0:
188 # Remove the file and raise an error.
191 raise DownloadError
, _("Downloaded empty file: %s") \
192 % os
.path
.basename(filename
)
196 return existant_files
+ download_files
199 class Mirror(object):
200 def __init__(self
, url
, location
=None, preferred
=False):
201 # Save URL of the mirror in full format
204 # Save the location (if given)
205 self
.location
= location
208 self
.preferred
= False
211 class MirrorList(object):
212 def __init__(self
, pakfire
, repo
, mirrorlist
):
213 self
.pakfire
= pakfire
218 # Save URL to more mirrors.
219 self
.mirrorlist
= mirrorlist
222 def base_mirror(self
):
223 if not self
.repo
.baseurl
:
226 return Mirror(self
.repo
.baseurl
, preferred
=False)
230 return self
.repo
.distro
235 Shortcut to cache from repository.
237 return self
.repo
.cache
239 def update(self
, force
=False):
240 # XXX should this be allowed?
241 if not self
.mirrorlist
:
244 # If the system is not online, we cannot download anything.
245 if self
.pakfire
.offline
:
248 log
.debug("Updating mirrorlist for repository '%s' (force=%s)" % (self
.repo
.name
, force
))
249 cache_filename
= os
.path
.join("repodata", self
.distro
.sname
, self
.distro
.release
,
250 self
.repo
.name
, self
.distro
.arch
, "mirrors")
252 # Force the update if no mirrorlist is available.
253 if not self
.cache
.exists(cache_filename
):
256 if not force
and self
.cache
.exists(cache_filename
):
257 age
= self
.cache
.age(cache_filename
)
259 # If the age could be determined and is higher than 24h,
260 # we force an update.
261 if age
and age
> TIME_24H
:
265 g
= MetadataDownloader(self
.pakfire
)
268 mirrordata
= g
.urlread(self
.mirrorlist
, limit
=MIRRORLIST_MAXSIZE
)
269 except URLGrabError
, e
:
270 log
.warning("Could not update the mirrorlist for repo '%s': %s" % (self
.repo
.name
, e
))
273 # XXX check for empty files or damaged output
275 # Save new mirror data to cache.
276 f
= self
.cache
.open(cache_filename
, "w")
280 # Read mirrorlist from cache and parse it.
281 self
.forget_mirrors()
282 with self
.cache
.open(cache_filename
) as f
:
283 self
.parse_mirrordata(f
.read())
285 def parse_mirrordata(self
, data
):
286 data
= json
.loads(data
)
288 for mirror
in data
["mirrors"]:
289 self
.add_mirror(**mirror
)
291 def add_mirror(self
, *args
, **kwargs
):
292 mirror
= Mirror(*args
, **kwargs
)
294 self
.__mirrors
.append(mirror
)
296 def forget_mirrors(self
):
302 Return a generator for all mirrors that are preferred.
304 for mirror
in self
.__mirrors
:
309 def non_preferred(self
):
311 Return a generator for all mirrors that are not preferred.
313 for mirror
in self
.__mirrors
:
314 if not mirror
.preferred
:
320 Return a generator for all mirrors.
322 for mirror
in self
.__mirrors
:
325 def group(self
, grabber
):
327 Return a MirrorGroup object for the given grabber.
329 # Make sure the mirrorlist is up to date.
332 # A list of mirrors that is passed to MirrorGroup.
335 # Add all preferred mirrors at the first place and shuffle them
336 # that we will start at a random place.
337 for mirror
in self
.preferred
:
338 mirrors
.append({ "mirror" : mirror
.url
.encode("utf-8") })
339 random
.shuffle(mirrors
)
341 # All other mirrors are added as well and will only be used if all
342 # preferred mirrors did not work.
343 for mirror
in self
.all
:
344 mirror
= { "mirror" : mirror
.url
.encode("utf-8") }
345 if mirror
in mirrors
:
348 mirrors
.append(mirror
)
350 # Always add the base mirror if any.
351 base_mirror
= self
.base_mirror
353 mirror
= { "mirror" : base_mirror
.url
.encode("utf-8") }
354 if not mirror
in mirrors
:
355 mirrors
.append(mirror
)
357 return MirrorGroup(grabber
, mirrors
)
361 class Downloader(object):
362 def __init__(self
, mirrors
, files
):
363 self
.grabber
= PakfireGrabber()
365 self
.mirrorgroup
= mirrors
.group(self
.grabber
)