1
2
3
4 import logging
5 import os
6
7 from os.path import dirname, exists, isdir, join
8 from operator import attrgetter
9
10
11 import cherrypy as cp
12 import turbogears as tg
13
14 from cherrypy.lib.cptools import serve_file
15
16
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")
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):
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
51 raise cp.NotFound()
52
53
54
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
111
112 if not has_permission('upload'):
113
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
121 raise cp.HTTPError(409, "Conflict - File exists")
122
123
124 if not isdir(pkg_dir):
125 try:
126 os.makedirs(pkg_dir)
127 except (IOError, OSError), exc:
128
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
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
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