From: Michael Tremer Date: Mon, 3 Dec 2012 21:45:28 +0000 (+0100) Subject: Make it possible to download files from the packages. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=01197c1d0adc0523935293d1ab45a5d244169ebe;p=pbs.git Make it possible to download files from the packages. --- diff --git a/backend/constants.py b/backend/constants.py index 54b549ab..88ff0bd6 100644 --- a/backend/constants.py +++ b/backend/constants.py @@ -19,6 +19,25 @@ BUFFER_SIZE = 1024 * 100 # 100kb BUGZILLA_PATTERN = r"(bug\s?|#)(\d+)" CVE_PATTERN = r"(CVE)(\s|\-)(\d{4}\-\d{4})" +FILE_EXTENSIONS_VIEWABLE = ( + ".c", + ".cfg", + ".conf", + ".config", + ".h", + ".nm", + ".patch", + ".pl", + ".pm", + ".py", + ".S", + ".s", + ".sh", + ".txt", + "Kconfig", + "Makefile", +) + N_ = lambda x: x MSG_BUILD_FAILED_SUBJECT = N_("[%(build_name)s] Build job failed.") diff --git a/backend/packages.py b/backend/packages.py index 68058ebb..d2f9ca19 100644 --- a/backend/packages.py +++ b/backend/packages.py @@ -477,15 +477,19 @@ class Package(base.Object): @property def filelist(self): if self._filelist is None: - self._filelist = \ - self.db.query("SELECT * FROM filelists WHERE pkg_id = %s ORDER BY name", - self.id) + self._filelist = [] + + for f in self.db.query("SELECT * FROM filelists WHERE pkg_id = %s ORDER BY name", self.id): + f = File(self.pakfire, f) + self._filelist.append(f) return self._filelist def get_file(self): - if os.path.exists(self.path): - return pakfire.packages.open(self.path) + path = os.path.join(PACKAGES_DIR, self.path) + + if os.path.exists(path): + return pakfire.packages.open(None, None, path) ## properties @@ -515,9 +519,35 @@ class Package(base.Object): return self.properties.get("critical_path", "N") == "Y" +class File(base.Object): + def __init__(self, pakfire, data): + base.Object.__init__(self, pakfire) + + self.data = data + + def __getattr__(self, attr): + try: + return self.data[attr] + except KeyError: + raise AttributeError, attr + + @property + def downloadable(self): + # All regular files are downloadable. + return self.type == 0 + + @property + def viewable(self): + for ext in FILE_EXTENSIONS_VIEWABLE: + if self.name.endswith(ext): + return True + + return False + + # XXX DEAD CODE -class File(base.Object): +class __File(base.Object): def __init__(self, pakfire, path): base.Object.__init__(self, pakfire) diff --git a/data/templates/modules/packages-files-table.html b/data/templates/modules/packages-files-table.html index 3b9cfb0e..58de689d 100644 --- a/data/templates/modules/packages-files-table.html +++ b/data/templates/modules/packages-files-table.html @@ -19,11 +19,17 @@ {{ file.name }} -
-
- V - D -
+
+ {% if file.viewable %} + + + + {% end %} + {% if file.downloadable %} + + + + {% end %}
diff --git a/web/__init__.py b/web/__init__.py index 71a68753..83f4e3c5 100644 --- a/web/__init__.py +++ b/web/__init__.py @@ -121,6 +121,7 @@ class Application(tornado.web.Application): (r"/package/([\w\-\+]+)/properties", PackagePropertiesHandler), (r"/package/([\w\-\+]+)", PackageNameHandler), (r"/package/([\w\-\+]+)/changelog", PackageChangelogHandler), + (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/download(.*)", PackageFileDownloadHandler), # Files (r"/file/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", FileDetailHandler), diff --git a/web/handlers_packages.py b/web/handlers_packages.py index a9321b0c..9883088d 100644 --- a/web/handlers_packages.py +++ b/web/handlers_packages.py @@ -1,9 +1,13 @@ #!/usr/bin/python +import mimetypes +import os.path import tornado.web from handlers_base import BaseHandler +from backend.constants import BUFFER_SIZE + class PackageIDDetailHandler(BaseHandler): def get(self, id): package = self.packages.get_by_id(id) @@ -162,3 +166,47 @@ class PackagePropertiesHandler(BaseHandler): else: critical_path = False build.pkg.update_property("critical_path", critical_path) + + +class PackageFileDownloadHandler(BaseHandler): + def get(self, pkg_uuid, filename): + # Fetch package. + pkg = self.pakfire.packages.get_by_uuid(pkg_uuid) + if not pkg: + raise tornado.web.HTTPError(404, "Package not found: %s" % pkg_uuid) + + # Check if the package has got a file with the given name. + if not filename in [f.name for f in pkg.filelist]: + raise tornado.web.HTTPError(404, "Package %s does not contain file %s" % (pkg, filename)) + + # Open the package in the filesystem. + pkg_file = pkg.get_file() + if not pkg_file: + raise torando.web.HTTPError(404, "Could not open package %s" % pkg.path) + + # Open the file to transfer it to the client. + f = pkg_file.open_file(filename) + if not f: + raise tornado.web.HTTPError(404, "Package %s does not contain file %s" % (pkg_file, filename)) + + # Send the filename in header. + self.set_header("Content-Disposition", "attachment; filename=%s" % os.path.basename(filename)) + + # Guess the MIME type of the file. + (type, encoding) = mimetypes.guess_type(filename) + if not type: + type = "text/plain" + self.set_header("Content-Type", type) + + # Transfer the content chunk by chunk. + while True: + buf = f.read(BUFFER_SIZE) + if not buf: + break + + self.write(buf) + + f.close() + + # Done. + self.finish()