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