Package eggbasket :: Package controllers :: Module packages
[hide private]

Source Code for Module eggbasket.controllers.packages

  1  # -*- coding: UTF-8 -*- 
  2   
  3  # standard library imports 
  4  import logging 
  5  import os 
  6   
  7  from os.path import dirname, exists, isdir, join 
  8  from operator import attrgetter 
  9   
 10  # third-party library imports 
 11  import cherrypy as cp 
 12  import turbogears as tg 
 13   
 14  from cherrypy.lib.cptools import serve_file 
 15   
 16  # private modules 
 17  from eggbasket import model 
 18  from eggbasket.validators import ValidPackage, PackageFileSchema 
 19  from eggbasket.util import is_package_dir, munge_pkg_info, txt2html 
 20  from eggbasket.permissions import has_permission 
 21   
 22  log = logging.getLogger("eggbasket.controllers") 
23 24 -class PackageController(tg.controllers.Controller):
25 """Controller for handling package info display, download and upload.""" 26 27 @tg.expose(template="eggbasket.templates.package_list") 28 @tg.identity.require(has_permission(u'viewpkgs', 29 u'You have no permission to view the list of packages.'))
30 - def index(self, *args, **kw):
31 """Return list of packages in the repository.""" 32 33 pkg_root = tg.config.get('eggbasket.package_root', os.getcwd()) 34 log.debug("Listing package root directory: %s", pkg_root) 35 packages = [model.Package(join(pkg_root, name)) 36 for name in os.listdir(pkg_root) 37 if is_package_dir(join(pkg_root, name))] 38 packages.sort(key=attrgetter('name')) 39 #log.debug("Packages found: %r", packages) 40 41 return dict(packages=packages)
42 43 @tg.expose("eggbasket.templates.package_files") 44 @tg.validate(validators=dict(package=ValidPackage)) 45 @tg.identity.require(has_permission(u'viewfiles', 46 u'You have no permission to view package distibution file lists.'))
47 - def files(self, package, tg_errors=None):
48 """List available releases and distribution files for given package.""" 49 if tg_errors: 50 # Send 404 for unavailable packages, to not confuse easy_install 51 raise cp.NotFound() 52 # XXX: I should test if it's ok to do the following instead: 53 #tg.flash(unicode(tg_errors['package'])) 54 #tg.redirect('/') 55 56 pkg_root = tg.config.get('eggbasket.package_root', os.getcwd()) 57 pkg_dir = join(pkg_root, package) 58 log.debug("Reading package directory %s.", pkg_dir) 59 package = model.Package(pkg_dir) 60 return dict(package=package)
61 62 default = files 63 64 @tg.expose('eggbasket.templates.package_info') 65 @tg.validate(validators=PackageFileSchema) 66 @tg.identity.require(has_permission(u'viewinfo', 67 u'You have no permission to view package meta data.'))
68 - def info(self, package, filename, tg_errors=None):
69 """Show meta data from PKG-INFO for given package distribution file.""" 70 if tg_errors: 71 if tg_errors.get('package'): 72 tg.redirect('/') 73 flash(unicode(tg_errors['package'])) 74 if tg_errors.get('filename'): 75 flash(unicode(tg_errors['filename'])) 76 tg.redirect('/package/%s' % package) 77 78 pkg_root = tg.config.get('eggbasket.package_root', os.getcwd()) 79 pkg_dir = join(pkg_root, package) 80 package = model.Package(pkg_dir) 81 pkg_info = package.package_info(join(pkg_dir, filename)) 82 pkg_desc = txt2html(pkg_info.pop('description', ''), 83 tg.config.get('eggbasket.pkg_desc_format', 'plain') == 'rest') 84 pkg_info = munge_pkg_info(pkg_info) 85 return dict(package=package, description=pkg_desc, pkg_info=pkg_info, 86 filename=filename)
87 88 @tg.expose() 89 @tg.validate(validators=PackageFileSchema) 90 @tg.identity.require(has_permission(u'download', 91 u'You have no permission to download package distribution files.'))
92 - def download(self, package, filename, tg_errors=None):
93 """Serve given package distribution file as binary download.""" 94 if tg_errors: 95 if tg_errors.get('package'): 96 tg.redirect('/') 97 flash(unicode(tg_errors['package'])) 98 if tg_errors.get('filename'): 99 flash(unicode(tg_errors['filename'])) 100 tg.redirect('/package/%s' % package) 101 102 pkg_root = tg.config.get('eggbasket.package_root', os.getcwd()) 103 pkg_file = join(pkg_root, package, filename) 104 return serve_file(pkg_file, "application/octet-stream", 105 "attachment", filename)
106 107 @tg.expose()
108 - def upload(self, name, content, *args, **kw):
109 """Handle submissions from the distutils 'upload' command.""" 110 # We don't use the identity.require decorator, since we don't want to 111 # return the login form on an authentication error here. 112 if not has_permission('upload'): 113 # User does not have 'upload' permission 114 raise cp.HTTPError(401, "Unauthorized - No upload permission") 115 116 pkg_root = tg.config.get('eggbasket.package_root', os.getcwd()) 117 pkg_dir = join(pkg_root, name) 118 pkg_file = os.path.join(pkg_dir, content.filename) 119 if exists(pkg_file) and not has_permission('overwrite'): 120 # File exists: return standard HTTP status code 409 121 raise cp.HTTPError(409, "Conflict - File exists") 122 123 # create package directory, if it does not exist 124 if not isdir(pkg_dir): 125 try: 126 os.makedirs(pkg_dir) 127 except (IOError, OSError), exc: 128 # Directory cannot be created 129 log.error("Could not create package directory '%s': %s", 130 pkg_dir, exc) 131 raise cp.HTTPError(500, "Internal Server Error" 132 " - Could not create package directory") 133 134 # write uploaded package to file 135 try: 136 fo = open(pkg_file, 'wb') 137 try: 138 while True: 139 chunk = content.file.read(8192) 140 if not chunk: 141 break 142 fo.write(chunk) 143 finally: 144 fo.close() 145 except (IOError, OSError), exc: 146 # Package file not writeable 147 log.error("Could not write package file '%s': %s", 148 pkg_file, exc) 149 raise cp.HTTPError(500, "Internal Server Error" 150 " - Could not write package file") 151 log.info('Uploaded %s' % pkg_file) 152 return ""
153 154 155 @tg.expose() 156 @tg.validate(validators=PackageFileSchema) 157 @tg.identity.require(has_permission(u'delete', 158 u'You have no permission to delete package distribution files.'))
159 - def delete(self, package, filename, tg_errors=None):
160 """Delete a package file from the repository.""" 161 162 if tg_errors: 163 if tg_errors.get('package'): 164 tg.redirect('/') 165 flash(unicode(tg_errors['package'])) 166 if tg_errors.get('filename'): 167 flash(unicode(tg_errors['filename'])) 168 tg.redirect('/package/%s' % package) 169 pkg_root = tg.config.get('eggbasket.package_root', os.getcwd()) 170 pkg_file = join(pkg_root, package, filename) 171 try: 172 os.unlink(pkg_file) 173 tg.flash(u"Package file '%s' deleted." % filename) 174 except OSError, exc: 175 tg.flash(u"Could not delete package file '%s': %s" % ( 176 filename, exc)) 177 if is_package_dir(join(pkg_root, package)): 178 tg.redirect('/package/%s' % package) 179 else: 180 tg.redirect('/')
181