]>
git.ipfire.org Git - ipfire.org.git/blob - src/backend/releases.py
10 from .misc
import Object
11 from .decorators
import *
14 def __init__(self
, backend
, release
, id, data
=None):
15 Object
.__init
__(self
, backend
)
18 self
._release
= release
20 # get all data from database
23 def __eq__(self
, other
):
24 if isinstance(other
, self
.__class
__):
25 return self
.id == otherid
27 def __lt__(self
, other
):
28 if isinstance(other
, self
.__class
__):
29 return self
.prio
< other
.prio
33 if self
.__data
is None:
34 self
.__data
= self
.db
.get("SELECT * FROM files WHERE id = %s", self
.id)
42 release_id
= self
.data
.get("releases")
43 self
._release
= Release(release_id
)
49 filename
= self
.filename
51 if filename
.endswith(".iso"):
54 elif "xen" in filename
:
55 if "downloader" in filename
:
56 return "xen-downloader"
60 elif "sources" in filename
:
63 elif "usb-fdd" in filename
:
66 elif "usb-hdd" in filename
:
69 elif "armv5tel" in filename
and "scon" in filename
:
70 return "armv5tel-scon"
72 elif "armv5tel" in filename
:
75 elif "scon" in filename
:
78 elif filename
.endswith(".img.gz") or filename
.endswith(".img.xz"):
86 return urllib
.parse
.urljoin("https://downloads.ipfire.org", self
.filename
)
93 "armv5tel" : _("Flash Image"),
94 "armv5tel-scon" : _("Flash Image with serial console"),
95 "iso" : _("ISO Image"),
96 "flash" : _("Flash Image"),
97 "alix" : _("Flash Image with serial console"),
98 "usbfdd" : _("USB FDD Image"),
99 "usbhdd" : _("USB HDD Image"),
100 "xen" : _("Pre-generated Xen Image"),
101 "xen-downloader": _("Xen-Image Generator"),
105 return descriptions
[self
.type]
107 return _("Unknown image type")
118 "armv5tel-scon" : 41,
120 "xen-downloader": 51,
124 return priorities
[self
.type]
130 return self
.data
.get("sha256")
134 return self
.data
.get("sha1")
138 return self
.data
.get("filename")
142 return os
.path
.basename(self
.filename
)
146 return self
.data
.get("filesize")
150 known_arches
= ("x86_64", "aarch64", "arm", "i586")
152 for arch
in known_arches
:
153 if arch
in self
.basename
:
159 class Release(Object
):
160 def __init__(self
, backend
, id, data
=None):
161 Object
.__init
__(self
, backend
)
164 # get all data from database
165 self
.__data
= data
or self
.db
.get("SELECT * FROM releases WHERE id = %s", self
.id)
174 return "<%s %s>" % (self
.__class
__.__name
__, self
.name
)
176 def __cmp__(self
, other
):
177 return cmp(self
.id, other
.id)
181 for arch
in ("x86_64", "aarch64", "i586", "arm"):
182 if arch
in (f
.arch
for f
in self
.files
):
186 def primary_arches(self
):
189 # Add x86_64 when available, otherwise add i586
190 for arch
in ("x86_64", "i586"):
191 if arch
in self
.arches
:
195 # Add aarch64 if available
196 if "aarch64" in self
.arches
:
197 arches
.append("aarch64")
199 # Add ARM before 2.27 if available
200 if "arm" in self
.arches
and self
.sname
< "ipfire-2.27-core159":
206 def secondary_arches(self
):
209 for arch
in self
.arches
:
210 if arch
in self
.primary_arches
:
218 def experimental_arches(self
):
224 files
= self
.db
.query("SELECT * FROM files WHERE releases = %s \
225 AND NOT filename LIKE '%%.torrent'", self
.id)
227 self
.__files
= [File(self
.backend
, self
, f
.id, f
) for f
in files
]
232 def get_files_by_arch(self
, arch
):
239 return self
.__data
.name
243 return self
.__data
.sname
250 if self
.__data
.blog_id
:
251 return self
.backend
.blog
.get_by_id(self
.__data
.blog_id
)
255 return self
.__data
.stable
259 return self
.__data
.published
265 return self
.__data
.path
267 def get_file(self
, type):
268 for file in self
.files
:
269 if file.type == type:
272 def __file_hash(self
, filename
, algo
="sha256"):
273 h
= hashlib
.new(algo
)
275 with
open(filename
, "rb") as f
:
277 buf
= f
.read(buf_size
)
280 buf
= f
.read(buf_size
)
284 def scan_files(self
, basepath
="/pub/mirror"):
288 path
= os
.path
.join(basepath
, self
.path
)
289 if not os
.path
.exists(path
):
292 files
= self
.db
.query("SELECT filename FROM files WHERE releases = %s", self
.id)
293 files
= [f
.filename
for f
in files
]
295 # Make files that do not exists not loadable.
296 for filename
in files
:
297 _filename
= os
.path
.join(basepath
, filename
)
298 if not os
.path
.exists(_filename
):
299 self
.db
.execute("UPDATE files SET loadable='N' WHERE filename = %s", filename
)
301 for filename
in os
.listdir(path
):
302 filename
= os
.path
.join(path
, filename
)
304 if os
.path
.isdir(filename
):
307 _filename
= re
.match(".*(releases/.*)", filename
).group(1)
308 if _filename
in files
:
311 if filename
.endswith(".b2") or filename
.endswith(".md5"):
314 logging
.info("Hashing %s..." % filename
)
315 hash_sha256
= self
.__file
_hash
(filename
, "sha256")
316 hash_sha1
= self
.__file
_hash
(filename
, "sha1")
317 filesize
= os
.path
.getsize(filename
)
319 self
.db
.execute("INSERT INTO files(releases, filename, filesize, \
320 sha256, sha1) VALUES(%s, %s, %s, %s, %s)",
321 self
.id, _filename
, filesize
, hash_sha256
, hash_sha1
)
323 def supports_arch(self
, arch
):
324 return arch
in ("x86_64", "i586")
326 def supports_platform(self
, platform
):
327 # Currently there is nothing else than pcbios supported
328 if platform
== "pcbios":
333 def is_netboot_capable(self
):
334 return self
.path
and "ipfire-2.x" in self
.path
336 def netboot_kernel_url(self
, arch
, platform
):
337 assert self
.supports_arch(arch
)
338 assert self
.supports_platform(platform
)
340 if self
.sname
>= "ipfire-2.19-core100":
341 return "http://boot.ipfire.org/%s/images/%s/vmlinuz" % (self
.path
, arch
)
343 return "http://boot.ipfire.org/%s/images/vmlinuz" % self
.path
345 def netboot_initrd_url(self
, arch
, platform
):
346 assert self
.supports_arch(arch
)
347 assert self
.supports_platform(platform
)
349 if self
.sname
>= "ipfire-2.19-core100":
350 return "http://boot.ipfire.org/%s/images/%s/instroot" % (self
.path
, arch
)
352 return "http://boot.ipfire.org/%s/images/instroot" % self
.path
354 def netboot_args(self
, arch
, platform
):
359 if self
.__data
.blog_id
:
360 return self
.backend
.blog
.get_by_id(self
.__data
.blog_id
)
364 def get_usage(self
, when
=None):
365 name
= self
.sname
.replace("ipfire-", "IPFire ").replace("-", " - ")
367 # Get penetration from fireinfo
368 releases
= self
.backend
.fireinfo
.get_releases_map(when
=when
)
370 return releases
.get(name
, 0)
373 class Releases(Object
):
374 def _get_release(self
, query
, *args
):
375 res
= self
.db
.get(query
, *args
)
378 return Release(self
.backend
, res
.id, data
=res
)
380 def _get_releases(self
, query
, *args
):
381 res
= self
.db
.query(query
, *args
)
384 yield Release(self
.backend
, row
.id, data
=row
)
387 releases
= self
._get
_releases
("SELECT * FROM releases \
388 ORDER BY published DESC NULLS FIRST")
390 return iter(releases
)
392 def get_by_id(self
, id):
393 ret
= self
.db
.get("SELECT * FROM releases WHERE id = %s", id)
396 return Release(self
.backend
, ret
.id, data
=ret
)
398 def get_by_sname(self
, sname
):
399 ret
= self
.db
.get("SELECT * FROM releases WHERE sname = %s", sname
)
402 return Release(self
.backend
, ret
.id, data
=ret
)
404 def get_by_news_id(self
, news_id
):
405 ret
= self
.db
.get("SELECT * FROM releases WHERE news_id = %s", news_id
)
408 return Release(self
.backend
, ret
.id, data
=ret
)
410 def get_latest(self
, stable
=True):
411 ret
= self
.db
.get("SELECT * FROM releases WHERE published IS NOT NULL AND published <= NOW() \
412 AND stable = %s ORDER BY published DESC LIMIT 1", stable
)
415 return Release(self
.backend
, ret
.id, data
=ret
)
417 def get_releases_older_than(self
, release
, limit
=None):
418 return self
._get
_releases
("SELECT * FROM releases \
419 WHERE published IS NOT NULL AND published < %s \
420 ORDER BY published DESC LIMIT %s", release
.published
, limit
)
422 def get_latest_unstable(self
):
423 ret
= self
.db
.get("SELECT * FROM releases r1 \
424 WHERE r1.published IS NOT NULL AND r1.published <= NOW() \
425 AND stable = %s AND NOT EXISTS ( \
426 SELECT * FROM releases r2 WHERE r2.stable = %s AND \
427 r2.published IS NOT NULL AND r2.published >= r1.published \
428 ) ORDER BY r1.published DESC LIMIT 1", False, True)
431 return Release(self
.backend
, ret
.id, data
=ret
)
433 def get_stable(self
):
434 query
= self
.db
.query("SELECT * FROM releases \
435 WHERE published IS NOT NULL AND published <= NOW() AND stable = TRUE \
436 ORDER BY published DESC")
440 release
= Release(self
.backend
, row
.id, data
=row
)
441 releases
.append(release
)
445 def get_unstable(self
):
446 query
= self
.db
.query("SELECT * FROM releases \
447 WHERE published IS NOT NULL AND published <= NOW() AND stable = FALSE \
448 ORDER BY published DESC")
452 release
= Release(self
.backend
, row
.id, data
=row
)
453 releases
.append(release
)
458 query
= self
.db
.query("SELECT * FROM releases \
459 WHERE published IS NOT NULL AND published <= NOW() \
460 ORDER BY published DESC")
464 release
= Release(self
.backend
, row
.id, data
=row
)
465 releases
.append(release
)
470 query
= self
.db
.query("SELECT * FROM releases ORDER BY published DESC")
474 release
= Release(self
.backend
, row
.id, data
=row
)
475 releases
.append(release
)
479 async def scan_files(self
, basepath
="/pub/mirror"):
481 logging
.debug("Scanning %s..." % release
)
483 with self
.db
.transaction():
484 release
.scan_files(basepath
=basepath
)