]>
git.ipfire.org Git - people/shoehn/ipfire.org.git/blob - webapp/backend/releases.py
9e68e5905d11de02102672f96af496d788cae318
12 from misc
import Object
15 def __init__(self
, backend
, release
, id, data
=None):
16 Object
.__init
__(self
, backend
)
19 self
._release
= release
21 # get all data from database
24 def __cmp__(self
, other
):
25 return cmp(self
.prio
, other
.prio
)
29 if self
.__data
is None:
30 self
.__data
= self
.db
.get("SELECT * FROM files WHERE id = %s", self
.id)
38 release_id
= self
.data
.get("releases")
39 self
._release
= Release(release_id
)
45 filename
= self
.filename
47 if filename
.endswith(".iso"):
50 elif filename
.endswith(".torrent"):
53 elif "xen" in filename
:
54 if "downloader" in filename
:
55 return "xen-downloader"
59 elif "sources" in filename
:
62 elif "usb-fdd" in filename
:
65 elif "usb-hdd" in filename
:
68 elif "armv5tel" in filename
and "scon" in filename
:
69 return "armv5tel-scon"
71 elif "armv5tel" in filename
:
74 elif "scon" in filename
:
77 elif filename
.endswith(".img.gz"):
85 baseurl
= self
.settings
.get("download_url", "http://downloads.ipfire.org")
87 return urlparse
.urljoin(baseurl
, self
.filename
)
94 "armv5tel" : _("Image for the armv5tel architecture"),
95 "armv5tel-scon" : _("armv5tel image for boards with serial console"),
96 "iso" : _("Installable CD image"),
97 "torrent" : _("Torrent file"),
98 "flash" : _("Flash image"),
99 "alix" : _("Flash image for devices with serial console"),
100 "usbfdd" : _("USB FDD Image"),
101 "usbhdd" : _("USB HDD Image"),
102 "xen" : _("Pregenerated Xen image"),
103 "xen-downloader": _("Xen-Image Generator"),
107 return descriptions
[self
.type]
109 return _("Unknown image type")
121 "armv5tel-scon" : 41,
123 "xen-downloader": 51,
127 return priorities
[self
.type]
136 "armv5tel" : _("This image runs on many ARM-based boards"),
137 "armv5tel-scon" : _("This image runs on ARM boards with a serial console"),
138 "iso" : _("Use this image to burn a CD and install IPFire from it."),
139 "torrent" : _("Download the CD image from the torrent network."),
140 "flash" : _("An image that is meant to run on embedded devices."),
141 "alix" : _("Flash image where a serial console is enabled by default."),
142 "usbfdd" : _("Install IPFire from a floppy-formated USB key."),
143 "usbhdd" : _("If the floppy image doesn't work, use this image instead."),
144 "xen" : _("A ready-to-run image for Xen."),
145 "xen-downloader": _("Generator for creating a Xen image."),
149 return remarks
[self
.type]
151 return _("Unknown image type")
155 return self
.data
.get("sha1")
159 return self
.data
.get("filename")
163 return os
.path
.basename(self
.filename
)
167 return self
.data
.get("filesize")
171 known_arches
= ("x86_64", "i586", "arm")
173 for arch
in known_arches
:
174 if arch
in self
.basename
:
180 def torrent_hash(self
):
181 return self
.data
.get("torrent_hash", None)
184 def magnet_link(self
):
185 # Don't return anything if we have no torrent hash.
186 if self
.torrent_hash
is None:
189 s
= "magnet:?xt=urn:btih:%s" % self
.torrent_hash
191 #s += "&xl=%d" % self.size
192 s
+= "&dn=%s" % urllib
.quote(self
.basename
)
195 s
+= "&tr=http://tracker.ipfire.org:6969/announce"
201 if not self
.torrent_hash
:
204 return self
.backend
.tracker
.complete(self
.torrent_hash
)
208 if not self
.torrent_hash
:
211 return self
.backend
.tracker
.incomplete(self
.torrent_hash
)
214 class Release(Object
):
215 def __init__(self
, backend
, id, data
=None):
216 Object
.__init
__(self
, backend
)
219 # get all data from database
220 self
.__data
= data
or self
.db
.get("SELECT * FROM releases WHERE id = %s", self
.id)
226 return "<%s %s>" % (self
.__class
__.__name
__, self
.name
)
228 def __cmp__(self
, other
):
229 return cmp(self
.id, other
.id)
234 files
= self
.db
.query("SELECT * FROM files WHERE releases = %s \
235 AND NOT filename LIKE '%%.torrent'", self
.id)
237 self
.__files
= [File(self
.backend
, self
, f
.id, f
) for f
in files
]
246 for file in self
.files
:
247 if not file.torrent_hash
:
250 torrents
.append(file)
256 return self
.__data
.name
260 return self
.__data
.sname
263 def fireinfo_id(self
):
264 name
= self
.sname
.replace("ipfire-", "IPFire ").replace("-", " - ")
266 res
= self
.db
.get("SELECT id FROM fireinfo_releases \
267 WHERE name = %s", name
)
274 return self
.__data
.stable
278 return self
.__data
.published
284 return self
.__data
.path
286 def get_file(self
, type):
287 for file in self
.files
:
288 if file.type == type:
291 def __file_hash(self
, filename
):
292 sha1
= hashlib
.sha1()
294 with
open(filename
) as f
:
296 buf
= f
.read(buf_size
)
299 buf
= f
.read(buf_size
)
301 return sha1
.hexdigest()
303 def scan_files(self
, basepath
="/srv/mirror0"):
307 path
= os
.path
.join(basepath
, self
.path
)
308 if not os
.path
.exists(path
):
311 files
= self
.db
.query("SELECT filename FROM files WHERE releases = %s", self
.id)
312 files
= [f
.filename
for f
in files
]
314 # Make files that do not exists not loadable.
315 for filename
in files
:
316 _filename
= os
.path
.join(basepath
, filename
)
317 if not os
.path
.exists(_filename
):
318 self
.db
.execute("UPDATE files SET loadable='N' WHERE filename = %s", filename
)
320 for filename
in os
.listdir(path
):
321 filename
= os
.path
.join(path
, filename
)
323 if os
.path
.isdir(filename
):
326 _filename
= re
.match(".*(releases/.*)", filename
).group(1)
327 if _filename
in files
:
330 if filename
.endswith(".md5"):
333 logging
.info("Hashing %s..." % filename
)
334 filehash
= self
.__file
_hash
(filename
)
335 filesize
= os
.path
.getsize(filename
)
337 # Check if there is a torrent download available for this file:
339 torrent_file
= "%s.torrent" % filename
340 if os
.path
.exists(torrent_file
):
341 torrent_hash
= self
.torrent_read_hash(torrent_file
)
343 self
.db
.execute("INSERT INTO files(releases, filename, filesize, \
344 sha1, torrent_hash) VALUES(%s, %s, %s, %s, %s)",
345 self
.id, _filename
, filesize
, filehash
, torrent_hash
)
347 # Search for all files that miss a torrent hash.
348 files
= self
.db
.query("SELECT id, filename FROM files \
349 WHERE releases = %s AND torrent_hash IS NULL", self
.id)
352 path
= os
.path
.join(basepath
, file.filename
)
354 torrent_file
= "%s.torrent" % path
355 if os
.path
.exists(torrent_file
):
356 torrent_hash
= self
.torrent_read_hash(torrent_file
)
358 self
.db
.execute("UPDATE files SET torrent_hash = %s WHERE id = %s",
359 torrent_hash
, file.id)
361 def torrent_read_hash(self
, filename
):
364 f
= open(filename
, "rb")
366 metainfo
= tracker
.bdecode(f
.read())
367 metainfo
= tracker
.bencode(metainfo
["info"])
369 hash = hashlib
.sha1()
370 hash.update(metainfo
)
372 return hash.hexdigest()
378 def supports_arch(self
, arch
):
379 return arch
in ("x86_64", "i586")
381 def supports_platform(self
, platform
):
382 # Currently there is nothing else than pcbios supported
383 if platform
== "pcbios":
388 def is_netboot_capable(self
):
389 return self
.path
and "ipfire-2.x" in self
.path
391 def netboot_kernel_url(self
, arch
, platform
):
392 assert self
.supports_arch(arch
)
393 assert self
.supports_platform(platform
)
395 if self
.sname
>= "ipfire-2.19-core100":
396 return "http://downloads.ipfire.org/%s/images/%s/vmlinuz" % (self
.path
, arch
)
398 return "http://downloads.ipfire.org/%s/images/vmlinuz" % self
.path
400 def netboot_initrd_url(self
, arch
, platform
):
401 assert self
.supports_arch(arch
)
402 assert self
.supports_platform(platform
)
404 if self
.sname
>= "ipfire-2.19-core100":
405 return "http://downloads.ipfire.org/%s/images/%s/instroot" % (self
.path
, arch
)
407 return "http://downloads.ipfire.org/%s/images/instroot" % self
.path
409 def netboot_args(self
, arch
, platform
):
414 return self
.__data
.news_id
418 if not hasattr(self
, "_news"):
419 self
._news
= self
.backend
.news
.get(self
.news_id
)
426 def penetration(self
):
427 penetration
= self
.memcache
.get("%s-penetration" % self
.sname
)
433 # Get penetration from fireinfo
434 penetration
= self
.backend
.fireinfo
.get_release_penetration(self
)
437 self
.memcache
.set("%s-penetration" % self
.sname
, penetration
, 3600)
442 class Releases(Object
):
443 def get_by_id(self
, id):
444 ret
= self
.db
.get("SELECT * FROM releases WHERE id = %s", id)
447 return Release(self
.backend
, ret
.id, data
=ret
)
449 def get_by_sname(self
, sname
):
450 ret
= self
.db
.get("SELECT * FROM releases WHERE sname = %s", sname
)
453 return Release(self
.backend
, ret
.id, data
=ret
)
455 def get_by_news_id(self
, news_id
):
456 ret
= self
.db
.get("SELECT * FROM releases WHERE news_id = %s", news_id
)
459 return Release(self
.backend
, ret
.id, data
=ret
)
461 def get_latest(self
, stable
=True):
462 ret
= self
.db
.get("SELECT * FROM releases WHERE published IS NOT NULL AND published <= NOW() \
463 AND stable = %s ORDER BY published DESC LIMIT 1", stable
)
466 return Release(self
.backend
, ret
.id, data
=ret
)
468 def get_latest_unstable(self
):
469 ret
= self
.db
.get("SELECT * FROM releases r1 \
470 WHERE r1.published IS NOT NULL AND r1.published <= NOW() \
471 AND stable = %s AND NOT EXISTS ( \
472 SELECT * FROM releases r2 WHERE r2.stable = %s AND \
473 r2.published IS NOT NULL AND r2.published >= r1.published \
474 ) ORDER BY r1.published DESC LIMIT 1", False, True)
477 return Release(self
.backend
, ret
.id, data
=ret
)
479 def get_stable(self
):
480 query
= self
.db
.query("SELECT * FROM releases \
481 WHERE published IS NOT NULL AND published <= NOW() AND stable = TRUE \
482 ORDER BY published DESC")
486 release
= Release(self
.backend
, row
.id, data
=row
)
487 releases
.append(release
)
491 def get_unstable(self
):
492 query
= self
.db
.query("SELECT * FROM releases \
493 WHERE published IS NOT NULL AND published <= NOW() AND stable = FALSE \
494 ORDER BY published DESC")
498 release
= Release(self
.backend
, row
.id, data
=row
)
499 releases
.append(release
)
504 query
= self
.db
.query("SELECT * FROM releases \
505 WHERE published IS NOT NULL AND published <= NOW() \
506 ORDER BY published DESC")
510 release
= Release(self
.backend
, row
.id, data
=row
)
511 releases
.append(release
)
516 query
= self
.db
.query("SELECT * FROM releases ORDER BY published DESC")
520 release
= Release(self
.backend
, row
.id, data
=row
)
521 releases
.append(release
)
525 def get_file_for_torrent_hash(self
, torrent_hash
):
526 file = self
.db
.get("SELECT id, releases FROM files WHERE torrent_hash = %s LIMIT 1",
532 release
= Release(self
.backend
, file.releases
)
533 file = File(self
.backend
, release
, file.id)