#!/usr/bin/python
+import hashlib
import logging
+import os
+import re
+import urllib
import urlparse
+import tracker
+
from databases import Databases
from misc import Singleton
from settings import Settings
@property
def type(self):
- return self.__data.get("filetype")
+ filename = self.filename
+
+ if filename.endswith(".iso"):
+ return "iso"
+
+ elif filename.endswith(".torrent"):
+ return "torrent"
+
+ elif "xen" in filename:
+ return "xen"
+
+ elif "sources" in filename:
+ return "source"
+
+ elif "usb-fdd" in filename:
+ return "usbfdd"
+
+ elif "usb-hdd" in filename:
+ return "usbhdd"
+
+ elif "armv5tel" in filename:
+ return "armv5tel"
+
+ elif "scon" in filename:
+ return "alix"
+
+ elif filename.endswith(".img.gz"):
+ return "flash"
+
+ else:
+ return "unknown"
@property
def url(self):
_ = lambda x: x
descriptions = {
+ "armv5tel" : _("Image for the armv5tel architecture"),
"iso" : _("Installable CD image"),
"torrent" : _("Torrent file"),
"flash" : _("Flash image"),
"alix" : 41,
"usbfdd" : 31,
"usbhdd" : 30,
+ "armv5tel" : 40,
"xen" : 50,
}
_ = lambda x: x
remarks = {
+ "armv5tel" : _("This image runs on many ARM-based boards"),
"iso" : _("Use this image to burn a CD and install IPFire from it."),
"torrent" : _("Download the CD image from the torrent network."),
"flash" : _("An image that is meant to run on embedded devices."),
def filename(self):
return self.__data.get("filename")
+ @property
+ def basename(self):
+ return os.path.basename(self.filename)
+
+ @property
+ def size(self):
+ return self.__data.get("filesize")
+
+ @property
+ def arch(self):
+ known_arches = ("i586", "arm")
+
+ for arch in known_arches:
+ if arch in self.basename:
+ return arch
+
+ return "N/A"
+
+ @property
+ def torrent_hash(self):
+ return self.__data.get("torrent_hash", None)
+
+ @property
+ def magnet_link(self):
+ # Don't return anything if we have no torrent hash.
+ if self.torrent_hash is None:
+ return
+
+ s = "magnet:?xt=urn:btih:%s" % self.torrent_hash
+
+ #s += "&xl=%d" % self.size
+ s += "&dn=%s" % urllib.quote(self.basename)
+
+ # Add our tracker.
+ s += "&tr=http://tracker.ipfire.org:6969/announce"
+
+ return s
+
class Release(object):
@property
@property
def files(self):
if not self.__files:
- files = self.db.query("SELECT id FROM files WHERE releases = %s \
+ files = self.db.query("SELECT id, filename FROM files WHERE releases = %s \
AND loadable = 'Y'", self.id)
- self.__files = [File(self, f.id) for f in files]
+ self.__files = [File(self, f.id) for f in files if not f.filename.endswith(".torrent")]
self.__files.sort(lambda a, b: cmp(a.prio, b.prio))
return self.__files
return self.__data.get("date")
@property
- def torrent_hash(self):
- h = self.__data.get("torrent_hash")
- if h:
- return h.lower()
+ def path(self):
+ return self.__data.get("path")
def get_file(self, type):
for file in self.files:
if file.type == type:
return file
+ def __file_hash(self, filename):
+ sha1 = hashlib.sha1()
+
+ with open(filename) as f:
+ buf_size = 1024
+ buf = f.read(buf_size)
+ while buf:
+ sha1.update(buf)
+ buf = f.read(buf_size)
+
+ return sha1.hexdigest()
+
+ def scan_files(self, basepath="/srv/mirror0"):
+ if not self.path:
+ return
+
+ path = os.path.join(basepath, self.path)
+ if not os.path.exists(path):
+ return
+
+ files = self.db.query("SELECT filename FROM files WHERE releases = %s", self.id)
+ files = [f.filename for f in files]
+
+ # Make files that do not exists not loadable.
+ for filename in files:
+ _filename = os.path.join(basepath, filename)
+ if not os.path.exists(_filename):
+ self.db.execute("UPDATE files SET loadable='N' WHERE filename = %s", filename)
+
+ for filename in os.listdir(path):
+ filename = os.path.join(path, filename)
+
+ if os.path.isdir(filename):
+ continue
+
+ _filename = re.match(".*(releases/.*)", filename).group(1)
+ if _filename in files:
+ continue
+
+ if filename.endswith(".md5"):
+ continue
+
+ filehash = self.__file_hash(filename)
+ filesize = os.path.getsize(filename)
+
+ # Check if there is a torrent download available for this file:
+ torrent_hash = ""
+ torrent_file = "%s.torrent" % filename
+ if os.path.exists(torrent_file):
+ torrent_hash = self.torrent_read_hash(torrent_file)
+
+ self.db.execute("INSERT INTO files(releases, filename, filesize, \
+ sha1, torrent_hash) VALUES(%s, %s, %s, %s, %s)",
+ self.id, _filename, filesize, filehash, torrent_hash)
+
+ # Search for all files that miss a torrent hash.
+ files = self.db.query("SELECT id, filename FROM files \
+ WHERE releases = %s AND torrent_hash IS NULL", self.id)
+
+ for file in files:
+ path = os.path.join(basepath, file.filename)
+
+ torrent_file = "%s.torrent" % path
+ if os.path.exists(torrent_file):
+ torrent_hash = self.torrent_read_hash(torrent_file)
+
+ self.db.execute("UPDATE files SET torrent_hash = %s WHERE id = %s",
+ torrent_hash, file.id)
+
+ def torrent_read_hash(self, filename):
+ f = None
+ try:
+ f = open(filename, "rb")
+
+ metainfo = tracker.bdecode(f.read())
+ metainfo = tracker.bencode(metainfo["info"])
+
+ hash = hashlib.sha1()
+ hash.update(metainfo)
+
+ return hash.hexdigest()
+
+ finally:
+ if f:
+ f.close()
+
class Releases(object):
__metaclass__ = Singleton
return [Release(r.id) for r in releases]
+ def get_filename_for_torrent_hash(self, torrent_hash):
+ file = self.db.get("SELECT filename FROM files WHERE torrent_hash = %s LIMIT 1",
+ torrent_hash)
+
+ if not file:
+ return
+
+ return file.filename
+
if __name__ == "__main__":
r = Releases()