]>
git.ipfire.org Git - ipfire.org.git/blob - src/backend/releases.py
8aaf599d112eda88e0beb4857767acc69ef5df8c
11 from . import database
12 from .misc
import Object
13 from .decorators
import *
16 "http://ipv4.tracker.ipfire.org:6969/announce",
17 "udp://ipv4.tracker.ipfire.org:6969",
18 "http://ipv6.tracker.ipfire.org:6969/announce",
19 "udp://ipv6.tracker.ipfire.org:6969",
23 def __init__(self
, backend
, release
, id, data
=None):
24 Object
.__init
__(self
, backend
)
27 self
._release
= release
29 # get all data from database
32 def __eq__(self
, other
):
33 if isinstance(other
, self
.__class
__):
34 return self
.id == otherid
36 def __lt__(self
, other
):
37 if isinstance(other
, self
.__class
__):
38 return self
.prio
< other
.prio
42 if self
.__data
is None:
43 self
.__data
= self
.db
.get("SELECT * FROM files WHERE id = %s", self
.id)
51 release_id
= self
.data
.get("releases")
52 self
._release
= Release(release_id
)
58 filename
= self
.filename
60 if filename
.endswith(".iso"):
63 elif filename
.endswith(".torrent"):
66 elif "xen" in filename
:
67 if "downloader" in filename
:
68 return "xen-downloader"
72 elif "sources" in filename
:
75 elif "usb-fdd" in filename
:
78 elif "usb-hdd" in filename
:
81 elif "armv5tel" in filename
and "scon" in filename
:
82 return "armv5tel-scon"
84 elif "armv5tel" in filename
:
87 elif "scon" in filename
:
90 elif filename
.endswith(".img.gz") or filename
.endswith(".img.xz"):
98 return urllib
.parse
.urljoin("https://downloads.ipfire.org", self
.filename
)
105 "armv5tel" : _("Flash Image"),
106 "armv5tel-scon" : _("Flash Image with serial console"),
107 "iso" : _("ISO Image"),
108 "torrent" : _("Torrent File"),
109 "flash" : _("Flash Image"),
110 "alix" : _("Flash Image with serial console"),
111 "usbfdd" : _("USB FDD Image"),
112 "usbhdd" : _("USB HDD Image"),
113 "xen" : _("Pre-generated Xen Image"),
114 "xen-downloader": _("Xen-Image Generator"),
118 return descriptions
[self
.type]
120 return _("Unknown image type")
132 "armv5tel-scon" : 41,
134 "xen-downloader": 51,
138 return priorities
[self
.type]
144 return self
.data
.get("sha256")
148 return self
.data
.get("sha1")
152 return self
.data
.get("filename")
156 return os
.path
.basename(self
.filename
)
160 return self
.data
.get("filesize")
164 known_arches
= ("x86_64", "i586", "arm")
166 for arch
in known_arches
:
167 if arch
in self
.basename
:
173 def torrent_hash(self
):
174 return self
.data
.get("torrent_hash", None)
177 def torrent_url(self
):
178 if self
.torrent_hash
:
179 return "%s.torrent" % self
.url
182 def magnet_link(self
):
183 # Don't return anything if we have no torrent hash.
184 if self
.torrent_hash
is None:
187 s
= "magnet:?xt=urn:btih:%s" % self
.torrent_hash
189 #s += "&xl=%d" % self.size
190 s
+= "&dn=%s" % urllib
.parse
.quote(self
.basename
)
193 for tracker
in TRACKERS
:
194 s
+= "&tr=%s" % tracker
196 # Add web download URL
197 s
+= "&as=%s" % urllib
.parse
.quote(self
.url
)
202 class Release(Object
):
203 def __init__(self
, backend
, id, data
=None):
204 Object
.__init
__(self
, backend
)
207 # get all data from database
208 self
.__data
= data
or self
.db
.get("SELECT * FROM releases WHERE id = %s", self
.id)
217 return "<%s %s>" % (self
.__class
__.__name
__, self
.name
)
219 def __cmp__(self
, other
):
220 return cmp(self
.id, other
.id)
224 for arch
in ("x86_64", "aarch64", "i586", "arm"):
225 if arch
in (f
.arch
for f
in self
.files
):
231 files
= self
.db
.query("SELECT * FROM files WHERE releases = %s \
232 AND NOT filename LIKE '%%.torrent'", self
.id)
234 self
.__files
= [File(self
.backend
, self
, f
.id, f
) for f
in files
]
239 def get_files_by_arch(self
, arch
):
248 for file in self
.files
:
249 if not file.torrent_hash
:
252 torrents
.append(file)
258 return self
.__data
.name
262 return self
.__data
.sname
269 if self
.__data
.blog_id
:
270 return self
.backend
.blog
.get_by_id(self
.__data
.blog_id
)
273 def fireinfo_id(self
):
274 name
= self
.sname
.replace("ipfire-", "IPFire ").replace("-", " - ")
276 res
= self
.db
.get("SELECT id FROM fireinfo_releases \
277 WHERE name = %s", name
)
284 return self
.__data
.stable
288 return self
.__data
.published
294 return self
.__data
.path
296 def get_file(self
, type):
297 for file in self
.files
:
298 if file.type == type:
301 def __file_hash(self
, filename
, algo
="sha256"):
302 h
= hashlib
.new(algo
)
304 with
open(filename
, "rb") as f
:
306 buf
= f
.read(buf_size
)
309 buf
= f
.read(buf_size
)
313 def scan_files(self
, basepath
="/pub/mirror"):
317 path
= os
.path
.join(basepath
, self
.path
)
318 if not os
.path
.exists(path
):
321 files
= self
.db
.query("SELECT filename FROM files WHERE releases = %s", self
.id)
322 files
= [f
.filename
for f
in files
]
324 # Make files that do not exists not loadable.
325 for filename
in files
:
326 _filename
= os
.path
.join(basepath
, filename
)
327 if not os
.path
.exists(_filename
):
328 self
.db
.execute("UPDATE files SET loadable='N' WHERE filename = %s", filename
)
330 for filename
in os
.listdir(path
):
331 filename
= os
.path
.join(path
, filename
)
333 if os
.path
.isdir(filename
):
336 _filename
= re
.match(".*(releases/.*)", filename
).group(1)
337 if _filename
in files
:
340 if filename
.endswith(".md5"):
343 logging
.info("Hashing %s..." % filename
)
344 hash_sha256
= self
.__file
_hash
(filename
, "sha256")
345 hash_sha1
= self
.__file
_hash
(filename
, "sha1")
346 filesize
= os
.path
.getsize(filename
)
348 # Check if there is a torrent download available for this file:
350 torrent_file
= "%s.torrent" % filename
351 if os
.path
.exists(torrent_file
):
352 torrent_hash
= self
.torrent_read_hash(torrent_file
)
354 self
.db
.execute("INSERT INTO files(releases, filename, filesize, \
355 sha256, sha1, torrent_hash) VALUES(%s, %s, %s, %s, %s, %s)",
356 self
.id, _filename
, filesize
, hash_sha256
, hash_sha1
, torrent_hash
)
358 # Search for all files that miss a torrent hash.
359 files
= self
.db
.query("SELECT id, filename FROM files \
360 WHERE releases = %s AND torrent_hash IS NULL", self
.id)
363 path
= os
.path
.join(basepath
, file.filename
)
365 torrent_file
= "%s.torrent" % path
366 if os
.path
.exists(torrent_file
):
367 torrent_hash
= self
.torrent_read_hash(torrent_file
)
369 self
.db
.execute("UPDATE files SET torrent_hash = %s WHERE id = %s",
370 torrent_hash
, file.id)
372 def torrent_read_hash(self
, filename
):
373 with
open(filename
, "rb") as f
:
374 metainfo
= yabencode
.decode(f
)
375 metainfo
= yabencode
.encode(metainfo
["info"])
377 h
= hashlib
.new("sha1")
382 def supports_arch(self
, arch
):
383 return arch
in ("x86_64", "i586")
385 def supports_platform(self
, platform
):
386 # Currently there is nothing else than pcbios supported
387 if platform
== "pcbios":
392 def is_netboot_capable(self
):
393 return self
.path
and "ipfire-2.x" in self
.path
395 def netboot_kernel_url(self
, arch
, platform
):
396 assert self
.supports_arch(arch
)
397 assert self
.supports_platform(platform
)
399 if self
.sname
>= "ipfire-2.19-core100":
400 return "https://boot.ipfire.org/%s/images/%s/vmlinuz" % (self
.path
, arch
)
402 return "https://boot.ipfire.org/%s/images/vmlinuz" % self
.path
404 def netboot_initrd_url(self
, arch
, platform
):
405 assert self
.supports_arch(arch
)
406 assert self
.supports_platform(platform
)
408 if self
.sname
>= "ipfire-2.19-core100":
409 return "https://boot.ipfire.org/%s/images/%s/instroot" % (self
.path
, arch
)
411 return "https://boot.ipfire.org/%s/images/instroot" % self
.path
413 def netboot_args(self
, arch
, platform
):
418 if self
.__data
.blog_id
:
419 return self
.backend
.blog
.get_by_id(self
.__data
.blog_id
)
424 def penetration(self
):
425 # Get penetration from fireinfo
426 return self
.backend
.fireinfo
.get_release_penetration(self
)
429 class Releases(Object
):
430 def _get_release(self
, query
, *args
):
431 res
= self
.db
.get(query
, *args
)
434 return Release(self
.backend
, res
.id, data
=res
)
436 def _get_releases(self
, query
, *args
):
437 res
= self
.db
.query(query
, *args
)
440 yield Release(self
.backend
, row
.id, data
=row
)
443 releases
= self
._get
_releases
("SELECT * FROM releases \
444 ORDER BY published DESC NULLS FIRST")
446 return iter(releases
)
448 def get_by_id(self
, id):
449 ret
= self
.db
.get("SELECT * FROM releases WHERE id = %s", id)
452 return Release(self
.backend
, ret
.id, data
=ret
)
454 def get_by_sname(self
, sname
):
455 ret
= self
.db
.get("SELECT * FROM releases WHERE sname = %s", sname
)
458 return Release(self
.backend
, ret
.id, data
=ret
)
460 def get_by_news_id(self
, news_id
):
461 ret
= self
.db
.get("SELECT * FROM releases WHERE news_id = %s", news_id
)
464 return Release(self
.backend
, ret
.id, data
=ret
)
466 def get_latest(self
, stable
=True):
467 ret
= self
.db
.get("SELECT * FROM releases WHERE published IS NOT NULL AND published <= NOW() \
468 AND stable = %s ORDER BY published DESC LIMIT 1", stable
)
471 return Release(self
.backend
, ret
.id, data
=ret
)
473 def get_releases_older_than(self
, release
, limit
=None):
474 return self
._get
_releases
("SELECT * FROM releases \
475 WHERE published IS NOT NULL AND published < %s \
476 ORDER BY published DESC LIMIT %s", release
.published
, limit
)
478 def get_latest_unstable(self
):
479 ret
= self
.db
.get("SELECT * FROM releases r1 \
480 WHERE r1.published IS NOT NULL AND r1.published <= NOW() \
481 AND stable = %s AND NOT EXISTS ( \
482 SELECT * FROM releases r2 WHERE r2.stable = %s AND \
483 r2.published IS NOT NULL AND r2.published >= r1.published \
484 ) ORDER BY r1.published DESC LIMIT 1", False, True)
487 return Release(self
.backend
, ret
.id, data
=ret
)
489 def get_stable(self
):
490 query
= self
.db
.query("SELECT * FROM releases \
491 WHERE published IS NOT NULL AND published <= NOW() AND stable = TRUE \
492 ORDER BY published DESC")
496 release
= Release(self
.backend
, row
.id, data
=row
)
497 releases
.append(release
)
501 def get_unstable(self
):
502 query
= self
.db
.query("SELECT * FROM releases \
503 WHERE published IS NOT NULL AND published <= NOW() AND stable = FALSE \
504 ORDER BY published DESC")
508 release
= Release(self
.backend
, row
.id, data
=row
)
509 releases
.append(release
)
514 query
= self
.db
.query("SELECT * FROM releases \
515 WHERE published IS NOT NULL AND published <= NOW() \
516 ORDER BY published DESC")
520 release
= Release(self
.backend
, row
.id, data
=row
)
521 releases
.append(release
)
526 query
= self
.db
.query("SELECT * FROM releases ORDER BY published DESC")
530 release
= Release(self
.backend
, row
.id, data
=row
)
531 releases
.append(release
)
535 def get_file_for_torrent_hash(self
, torrent_hash
):
536 file = self
.db
.get("SELECT id, releases FROM files WHERE torrent_hash = %s LIMIT 1",
542 release
= Release(self
.backend
, file.releases
)
543 file = File(self
.backend
, release
, file.id)
547 @tornado.gen
.coroutine
548 def scan_files(self
, basepath
="/pub/mirror"):
550 logging
.info("Scanning %s..." % release
)
552 with self
.db
.transaction():
553 release
.scan_files(basepath
=basepath
)