]>
git.ipfire.org Git - people/stevee/pakfire.git/blob - python/pakfire/downloader.py
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 ###############################################################################
27 log
= logging
.getLogger("pakfire")
29 from config
import Config
31 from urlgrabber
.grabber
import URLGrabber
, URLGrabError
32 from urlgrabber
.mirror
import MirrorGroup
33 from urlgrabber
.progress
import TextMeter
35 from pakfire
.constants
import *
36 from pakfire
.i18n
import _
38 class PakfireGrabber(URLGrabber
):
40 Class to make some modifications on the urlgrabber configuration.
42 def __init__(self
, pakfire
, *args
, **kwargs
):
45 "user_agent" : "pakfire/%s" % PAKFIRE_VERSION
,
48 if isinstance(pakfire
, Config
):
51 config
= pakfire
.config
53 if config
.get("offline"):
54 raise OfflineModeError
, "Cannot use %s in offline mode." % self
.__class
__.__name
__
56 # Set throttle setting.
57 bandwidth_throttle
= config
.get("bandwidth_throttle")
58 if bandwidth_throttle
:
60 bandwidth_throttle
= int(bandwidth_throttle
)
62 log
.error("Configuration value for bandwidth_throttle is invalid.")
63 bandwidth_throttle
= 0
65 kwargs
.update({ "throttle" : bandwidth_throttle
})
67 # Configure HTTP proxy.
68 http_proxy
= config
.get("http_proxy")
70 kwargs
.update({ "proxies" : { "http" : http_proxy
}})
72 URLGrabber
.__init
__(self
, *args
, **kwargs
)
74 def urlread(self
, filename
, *args
, **kwargs
):
75 # This is for older versions of urlgrabber which are packaged in Debian
76 # and Ubuntu and cannot handle filenames as a normal Python string but need
78 return URLGrabber
.urlread(self
, filename
.encode("utf-8"), *args
, **kwargs
)
81 class PackageDownloader(PakfireGrabber
):
82 def __init__(self
, pakfire
, *args
, **kwargs
):
84 "progress_obj" : TextMeter(),
87 PakfireGrabber
.__init
__(self
, pakfire
, *args
, **kwargs
)
90 class MetadataDownloader(PakfireGrabber
):
91 def __init__(self
, pakfire
, *args
, **kwargs
):
93 "http_headers" : (('Pragma', 'no-cache'),),
96 PakfireGrabber
.__init
__(self
, pakfire
, *args
, **kwargs
)
99 class DatabaseDownloader(PackageDownloader
):
100 def __init__(self
, pakfire
, *args
, **kwargs
):
102 "http_headers" : (('Pragma', 'no-cache'),),
105 PackageDownloader
.__init
__(self
, pakfire
, *args
, **kwargs
)
108 class SourceDownloader(object):
109 def __init__(self
, pakfire
, mirrors
=None):
110 self
.pakfire
= pakfire
112 self
.grabber
= PakfireGrabber(
114 progress_obj
= TextMeter(),
118 self
.grabber
= MirrorGroup(self
.grabber
,
119 [{ "mirror" : m
.encode("utf-8") } for m
in mirrors
])
121 def download(self
, files
):
126 filename
= os
.path
.join(SOURCE_CACHE_DIR
, file)
128 if os
.path
.exists(filename
):
129 existant_files
.append(filename
)
131 download_files
.append(filename
)
134 log
.info(_("Downloading source files:"))
136 # Create source download directory.
137 if not os
.path
.exists(SOURCE_CACHE_DIR
):
138 os
.makedirs(SOURCE_CACHE_DIR
)
140 for filename
in download_files
:
142 self
.grabber
.urlgrab(os
.path
.basename(filename
), filename
=filename
)
143 except URLGrabError
, e
:
144 raise DownloadError
, "%s %s" % (os
.path
.basename(filename
), e
)
148 return existant_files
+ download_files
151 class Mirror(object):
152 def __init__(self
, url
, location
=None, preferred
=False):
153 # Save URL of the mirror in full format
156 # Save the location (if given)
157 self
.location
= location
160 self
.preferred
= False
163 class MirrorList(object):
164 def __init__(self
, pakfire
, repo
):
165 self
.pakfire
= pakfire
170 # Save URL to more mirrors.
171 self
.mirrorlist
= repo
.mirrorlist
173 self
.update(force
=False)
178 Shortcut to cache from repository.
180 return self
.repo
.cache
182 def update(self
, force
=False):
183 # XXX should this be allowed?
184 if not self
.mirrorlist
:
187 # If the system is not online, we cannot download anything.
188 if self
.pakfire
.offline
:
191 log
.debug("Updating mirrorlist for repository '%s' (force=%s)" % (self
.repo
.name
, force
))
193 cache_filename
= "mirrors/mirrorlist"
195 # Force the update if no mirrorlist is available.
196 if not self
.cache
.exists(cache_filename
):
199 if not force
and self
.cache
.exists(cache_filename
):
200 age
= self
.cache
.age(cache_filename
)
202 # If the age could be determined and is higher than 24h,
203 # we force an update.
204 if age
and age
> TIME_24H
:
208 g
= MetadataDownloader(self
.pakfire
)
211 mirrordata
= g
.urlread(self
.mirrorlist
, limit
=MIRRORLIST_MAXSIZE
)
212 except URLGrabError
, e
:
213 log
.warning("Could not update the mirrorlist for repo '%s': %s" % (self
.repo
.name
, e
))
216 # XXX check for empty files or damaged output
218 # Save new mirror data to cache.
219 f
= self
.cache
.open(cache_filename
, "w")
223 # Read mirrorlist from cache and parse it.
224 with self
.cache
.open(cache_filename
) as f
:
225 self
.parse_mirrordata(f
.read())
227 def parse_mirrordata(self
, data
):
228 data
= json
.loads(data
)
230 for mirror
in data
["mirrors"]:
231 self
.add_mirror(**mirror
)
233 def add_mirror(self
, *args
, **kwargs
):
234 mirror
= Mirror(*args
, **kwargs
)
236 self
.__mirrors
.append(mirror
)
241 Return a generator for all mirrors that are preferred.
243 for mirror
in self
.__mirrors
:
248 def non_preferred(self
):
250 Return a generator for all mirrors that are not preferred.
252 for mirror
in self
.__mirrors
:
253 if not mirror
.preferred
:
259 Return a generator for all mirrors.
261 for mirror
in self
.__mirrors
:
264 def group(self
, grabber
):
266 Return a MirrorGroup object for the given grabber.
268 # A list of mirrors that is passed to MirrorGroup.
271 # Add all preferred mirrors at the first place and shuffle them
272 # that we will start at a random place.
273 for mirror
in self
.preferred
:
274 mirrors
.append(mirror
.url
.encode("utf-8"))
275 random
.shuffle(mirrors
)
277 # All other mirrors are added as well and will only be used if all
278 # preferred mirrors did not work.
279 for mirror
in self
.all
:
280 if mirror
.url
in mirrors
:
283 mirrors
.append({ "mirror" : mirror
.url
.encode("utf-8") })
285 return MirrorGroup(grabber
, mirrors
)
289 class Downloader(object):
290 def __init__(self
, mirrors
, files
):
291 self
.grabber
= PakfireGrabber()
293 self
.mirrorgroup
= mirrors
.group(self
.grabber
)