]> git.ipfire.org Git - people/jschlag/pbs.git/blame - src/web/__init__.py
Rename main object from Pakfire to Backend
[people/jschlag/pbs.git] / src / web / __init__.py
CommitLineData
9137135a 1#!/usr/bin/python
a90bd9b0 2# encoding: utf-8
9137135a
MT
3
4import logging
51db04b0 5import multiprocessing
9137135a
MT
6import os.path
7import tornado.httpserver
8import tornado.locale
9import tornado.options
10import tornado.web
11
57859ebc
MT
12from .. import Backend
13
2c909128 14from . import handlers_api
9137135a 15
2c909128
MT
16from .handlers import *
17from .ui_modules import *
35c46db4 18
9137135a
MT
19BASEDIR = os.path.join(os.path.dirname(__file__), "..", "data")
20
21# Enable logging
97144eb5 22tornado.options.define("debug", default=False, help="Run in debug mode", type=bool)
9137135a
MT
23tornado.options.parse_command_line()
24
25class Application(tornado.web.Application):
26 def __init__(self):
f6e6ff79
MT
27 self.__pakfire = None
28
9137135a 29 settings = dict(
97144eb5 30 debug = tornado.options.options.debug,
2b229cb1 31 gzip = True,
9137135a
MT
32 login_url = "/login",
33 template_path = os.path.join(BASEDIR, "templates"),
34 ui_modules = {
f6e6ff79
MT
35 "Text" : TextModule,
36 "Modal" : ModalModule,
37
38 "Footer" : FooterModule,
39
40 # Logging
41 "Log" : LogModule,
42 "LogEntry" : LogEntryModule,
43 "LogEntryComment" : LogEntryCommentModule,
44
f96eb5ed
MT
45 # Builders
46 "BuildersLoad" : BuildersLoadModule,
47
f6e6ff79
MT
48 "BuildHeadline" : BuildHeadlineModule,
49 "BuildStateWarnings" : BuildStateWarningsModule,
50
51 "BugsTable" : BugsTableModule,
52 "BuildLog" : BuildLogModule,
53 "BuildOffset" : BuildOffsetModule,
54 "BuildTable" : BuildTableModule,
4b1e87c4
MT
55
56 # Changelog
57 "Changelog" : ChangelogModule,
58 "ChangelogEntry" : ChangelogEntryModule,
59
6e63ed49
MT
60 # Jobs
61 "JobsList" : JobsListModule,
eedc6432 62 "JobsStatus" : JobsStatusModule,
6e63ed49 63
5669a87f
MT
64 # Packages
65 "PackagesDependencyTable" : PackagesDependencyTableModule,
66
b9d096e0 67 "CommitMessage" : CommitMessageModule,
f6e6ff79 68 "CommitsTable" : CommitsTableModule,
3c7e0537
MT
69 "JobsBoxes" : JobsBoxesModule,
70 "JobState" : JobStateModule,
f6e6ff79 71 "JobsTable" : JobsTableModule,
f6e6ff79
MT
72 "CommentsTable" : CommentsTableModule,
73 "FilesTable" : FilesTableModule,
74 "LogTable" : LogTableModule,
75 "LogFilesTable" : LogFilesTableModule,
76 "Maintainer" : MaintainerModule,
77 "PackagesTable" : PackagesTableModule,
78 "PackageTable2" : PackageTable2Module,
79 "PackageHeader" : PackageHeaderModule,
80 "PackageFilesTable" : PackageFilesTableModule,
81 "RepositoryTable" : RepositoryTableModule,
82 "RepoActionsTable" : RepoActionsTableModule,
83 "SourceTable" : SourceTableModule,
84 "UpdatesTable" : UpdatesTableModule,
85 "UsersTable" : UsersTableModule,
86 "WatchersSidebarTable" : WatchersSidebarTableModule,
cd870d0a 87
eedc6432
MT
88 "HeadingDate" : HeadingDateModule,
89
cd870d0a
MT
90 "SelectLocale" : SelectLocaleModule,
91 "SelectTimezone" : SelectTimezoneModule,
9137135a 92 },
bc293d03 93 ui_methods = {
a90bd9b0 94 "format_eta" : self.format_eta,
bc293d03
MT
95 "format_time" : self.format_time,
96 },
9137135a
MT
97 xsrf_cookies = True,
98 )
99
100 # Load translations.
101 tornado.locale.load_gettext_translations(
102 os.path.join(BASEDIR, "translations"), "pakfire")
103
104 tornado.web.Application.__init__(self, **settings)
105
106 self.settings["static_path"] = static_path = os.path.join(BASEDIR, "static")
107 static_handlers = [
108 (r"/static/(.*)", tornado.web.StaticFileHandler, dict(path = static_path)),
109 (r"/(favicon\.ico)", tornado.web.StaticFileHandler, dict(path = static_path)),
110 (r"/(robots\.txt)", tornado.web.StaticFileHandler, dict(path = static_path)),
111 ]
112
113 self.add_handlers(r".*", [
114 # Entry site that lead the user to index
115 (r"/", IndexHandler),
116
117 # Handle all the users logins/logouts/registers and stuff.
118 (r"/login", LoginHandler),
119 (r"/logout", LogoutHandler),
120 (r"/register", RegisterHandler),
f6e6ff79
MT
121 (r"/password-recovery", PasswordRecoveryHandler),
122
123 # User profiles
9137135a 124 (r"/users", UsersHandler),
f6e6ff79
MT
125 (r"/user/impersonate", UserImpersonateHandler),
126 (r"/user/(\w+)/passwd", UserPasswdHandler),
127 (r"/user/(\w+)/delete", UserDeleteHandler),
128 (r"/user/(\w+)/edit", UserEditHandler),
129 (r"/user/(\w+)/activate", ActivationHandler),
9137135a 130 (r"/user/(\w+)", UserHandler),
9137135a 131 (r"/profile", UserHandler),
f6e6ff79 132 (r"/profile/builds", UsersBuildsHandler),
9137135a
MT
133
134 # Packages
135 (r"/packages", PackageListHandler),
f6e6ff79 136 (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", PackageDetailHandler),
01197c1d 137 (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/download(.*)", PackageFileDownloadHandler),
de4e09a5 138 (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/view(.*)", PackageFileViewHandler),
d22eae24 139 (r"/package/([\w\-\+]+)", PackageNameHandler),
a15d6139 140 (r"/package/([\w\-\+]+)/builds/scratch", PackageScratchBuildsHandler),
bc293d03 141 (r"/package/([\w\-\+]+)/builds/times", PackageBuildsTimesHandler),
d22eae24
MT
142 (r"/package/([\w\-\+]+)/changelog", PackageChangelogHandler),
143 (r"/package/([\w\-\+]+)/properties", PackagePropertiesHandler),
9137135a
MT
144
145 # Files
146 (r"/file/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", FileDetailHandler),
147
148 # Builds
f6e6ff79 149 (r"/builds", BuildsHandler),
9137135a 150 (r"/builds/filter", BuildFilterHandler),
f6e6ff79 151 (r"/builds/queue", BuildQueueHandler),
62c7e7cd
MT
152 (r"/builds/comments", BuildsCommentsHandler),
153 (r"/builds/comments/(\w+)", BuildsCommentsHandler),
9137135a 154 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", BuildDetailHandler),
f6e6ff79
MT
155 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/bugs", BuildBugsHandler),
156 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/manage", BuildManageHandler),
157 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/comment", BuildDetailCommentHandler),
158 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/priority", BuildPriorityHandler),
159 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/state", BuildStateHandler),
160 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/watch", BuildWatchersAddHandler),
161 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/watchers", BuildWatchersHandler),
162 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/delete", BuildDeleteHandler),
163
164 # Jobs
9177f86a
MT
165 (r"/jobs", JobsIndexHandler),
166 (r"/jobs/filter", JobsFilterHandler),
f6e6ff79
MT
167 (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", JobDetailHandler),
168 (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/abort", JobAbortHandler),
169 (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/buildroot", JobBuildrootHandler),
170 (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/schedule", JobScheduleHandler),
9137135a
MT
171
172 # Builders
173 (r"/builders", BuilderListHandler),
174 (r"/builder/new", BuilderNewHandler),
f6e6ff79
MT
175 (r"/builder/([A-Za-z0-9\-\.]+)/enable", BuilderEnableHander),
176 (r"/builder/([A-Za-z0-9\-\.]+)/disable", BuilderDisableHander),
177 (r"/builder/([A-Za-z0-9\-\.]+)/delete", BuilderDeleteHandler),
178 (r"/builder/([A-Za-z0-9\-\.]+)/edit", BuilderEditHandler),
179 (r"/builder/([A-Za-z0-9\-\.]+)/renew", BuilderRenewPassphraseHandler),
9137135a
MT
180 (r"/builder/([A-Za-z0-9\-\.]+)", BuilderDetailHandler),
181
9137135a 182 # Distributions
f6e6ff79
MT
183 (r"/distros", DistributionListHandler),
184 (r"/distro/([A-Za-z0-9\-\.]+)", DistributionDetailHandler),
185
186 # XXX THOSE URLS ARE DEPRECATED
9137135a
MT
187 (r"/distribution/delete/([A-Za-z0-9\-\.]+)", DistributionDetailHandler),
188 (r"/distribution/edit/([A-Za-z0-9\-\.]+)", DistributionEditHandler),
f6e6ff79
MT
189
190 (r"/distro/([A-Za-z0-9\-\.]+)/repo/([A-Za-z0-9\-]+)",
191 RepositoryDetailHandler),
192 (r"/distro/([A-Za-z0-9\-\.]+)/repo/([A-Za-z0-9\-]+)\.repo",
193 RepositoryConfHandler),
194 (r"/distro/([A-Za-z0-9\-\.]+)/repo/([A-Za-z0-9\-]+)/mirrorlist",
195 RepositoryMirrorlistHandler),
196 (r"/distro/([A-Za-z0-9\-\.]+)/repo/([A-Za-z0-9\-]+)/edit",
197 RepositoryEditHandler),
198
199 (r"/distro/([A-Za-z0-9\-\.]+)/source/([A-Za-z0-9\-\.]+)",
200 DistroSourceDetailHandler),
201 (r"/distro/([A-Za-z0-9\-\.]+)/source/([A-Za-z0-9\-\.]+)/commits",
202 DistroSourceCommitsHandler),
203 (r"/distro/([A-Za-z0-9\-\.]+)/source/([A-Za-z0-9\-\.]+)/([\w]{40})",
204 DistroSourceCommitDetailHandler),
205 (r"/distro/([A-Za-z0-9\-\.]+)/source/([A-Za-z0-9\-\.]+)/([\w]{40})/reset",
206 DistroSourceCommitResetHandler),
207
208 (r"/distro/([A-Za-z0-9\-\.]+)/update/create",
209 DistroUpdateCreateHandler),
210 (r"/distro/([A-Za-z0-9\-\.]+)/update/(\d+)/(\d+)",
211 DistroUpdateDetailHandler),
212
213 # Updates
214 (r"/updates", UpdatesHandler),
215
216 # Mirrors
217 (r"/mirrors", MirrorListHandler),
218 (r"/mirror/new", MirrorNewHandler),
219 (r"/mirror/([A-Za-z0-9\-\.]+)/delete", MirrorDeleteHandler),
220 (r"/mirror/([A-Za-z0-9\-\.]+)/edit", MirrorEditHandler),
221 (r"/mirror/([A-Za-z0-9\-\.]+)", MirrorDetailHandler),
222
223 # Key management
224 (r"/keys", KeysListHandler),
225 (r"/key/import", KeysImportHandler),
226 (r"/key/([A-Z0-9]+)", KeysDownloadHandler),
227 (r"/key/([A-Z0-9]+)/delete", KeysDeleteHandler),
228
229 # Statistics
230 (r"/statistics", StatisticsMainHandler),
9137135a
MT
231
232 # Documents
233 (r"/documents", DocsIndexHandler),
234 (r"/documents/builds", DocsBuildsHandler),
235 (r"/documents/users", DocsUsersHandler),
f6e6ff79 236 (r"/documents/what-is-the-pakfire-build-service", DocsWhatsthisHandler),
9137135a
MT
237
238 # Search
239 (r"/search", SearchHandler),
240
f6e6ff79
MT
241 # Uploads
242 (r"/uploads", UploadsHandler),
9137135a
MT
243
244 # Log
245 (r"/log", LogHandler),
9137135a 246
20d7f5eb
MT
247 # Sessions
248 (r"/sessions", SessionsHandler),
249
35c46db4
MT
250 # API handlers
251 (r"/api/packages/autocomplete", handlers_api.ApiPackagesAutocomplete),
252
f6e6ff79
MT
253 ] + static_handlers + [
254
255 # Everything else is catched by the 404 handler.
256 (r"/.*", Error404Handler),
257 ])
9137135a
MT
258
259 logging.info("Successfully initialied application")
260
f6e6ff79
MT
261 @property
262 def pakfire(self):
263 if self.__pakfire is None:
4585a44d
MT
264 config_file = os.path.join(BASEDIR, "..", "pbs.conf")
265
57859ebc 266 self.__pakfire = Backend(config_file=config_file)
f6e6ff79
MT
267
268 return self.__pakfire
269
9137135a
MT
270 def __del__(self):
271 logging.info("Shutting down application")
272
273 @property
274 def ioloop(self):
275 return tornado.ioloop.IOLoop.instance()
276
277 def shutdown(self, *args):
278 logging.debug("Caught shutdown signal")
279 self.ioloop.stop()
280
51db04b0 281 def run(self, port=7001):
9137135a
MT
282 logging.debug("Going to background")
283
9137135a
MT
284 http_server = tornado.httpserver.HTTPServer(self, xheaders=True)
285
286 # If we are not running in debug mode, we can actually run multiple
287 # frontends to get best performance out of our service.
51db04b0 288 if self.settings.get("debug", False):
9137135a 289 http_server.listen(port)
51db04b0
MT
290 else:
291 cpu_count = multiprocessing.cpu_count()
292
293 http_server.bind(port)
294 http_server.start(num_processes=cpu_count)
9137135a 295
f6e6ff79
MT
296 # All requests should be done after 60 seconds or they will be killed.
297 self.ioloop.set_blocking_log_threshold(60)
298
9137135a
MT
299 self.ioloop.start()
300
301 def reload(self):
302 logging.debug("Caught reload signal")
bc293d03
MT
303
304 ## UI methods
305
a90bd9b0
MT
306 def format_eta(self, handler, (s, stddev)):
307 if s is None:
308 _ = handler.locale.translate
309 return _("Unknown")
310
311 if s < 0:
312 s = 0
313
747786f1 314 return u"%s ± %s" % (
a90bd9b0 315 self.format_time(handler, s),
96a1c465 316 self.format_time_short(handler, stddev / 2),
a90bd9b0
MT
317 )
318
7514d7dc 319 def format_time(self, handler, s, shorter=False):
bc293d03
MT
320 _ = handler.locale.translate
321
322 hrs, s = divmod(s, 3600)
323 min, s = divmod(s, 60)
324
325 if s >= 30:
326 min += 1
327
7514d7dc
MT
328 if shorter and not hrs:
329 return _("%(min)d min") % { "min" : min }
330
bc293d03 331 return _("%(hrs)d:%(min)02d hrs") % {"hrs" : hrs, "min" : min}
a90bd9b0
MT
332
333 def format_time_short(self, handler, s):
334 _ = handler.locale.translate
335
336 hrs = s / 3600
337 if hrs >= 1:
338 return _("%dh") % hrs
339
340 min = s / 60
341 if min >= 1:
342 return _("%dm") % min
343
344 return _("%ds") % s