1
2
3
4 """
5 This file is part of the web2py Web Framework
6 Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
7 License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
8
9 The widget is called from web2py.
10 """
11
12 import sys
13 import cStringIO
14 import time
15 import thread
16 import re
17 import os
18 import socket
19 import signal
20 import math
21 import logging
22 import newcron
23 import main
24
25 from fileutils import w2p_pack, read_file, write_file
26 from shell import run, test
27 from settings import global_settings
28
29 try:
30 import Tkinter, tkMessageBox
31 import contrib.taskbar_widget
32 from winservice import web2py_windows_service_handler
33 except:
34 pass
35
36
37 try:
38 BaseException
39 except NameError:
40 BaseException = Exception
41
42 ProgramName = 'web2py Web Framework'
43 ProgramAuthor = 'Created by Massimo Di Pierro, Copyright 2007-2011'
44 ProgramVersion = read_file('VERSION').strip()
45
46 ProgramInfo = '''%s
47 %s
48 %s''' % (ProgramName, ProgramAuthor, ProgramVersion)
49
50 if not sys.version[:3] in ['2.4', '2.5', '2.6', '2.7']:
51 msg = 'Warning: web2py requires Python 2.4, 2.5 (recommended), 2.6 or 2.7 but you are running:\n%s'
52 msg = msg % sys.version
53 sys.stderr.write(msg)
54
55 logger = logging.getLogger("web2py")
56
58 """ """
59
61 """ """
62
63 self.buffer = cStringIO.StringIO()
64
66 """ """
67
68 sys.__stdout__.write(data)
69 if hasattr(self, 'callback'):
70 self.callback(data)
71 else:
72 self.buffer.write(data)
73
74
76 """ Try to start the default browser """
77
78 try:
79 import webbrowser
80 webbrowser.open(url)
81 except:
82 print 'warning: unable to detect your browser'
83
84
86 """ Starts the default browser """
87 print 'please visit:'
88 print '\thttp://%s:%s' % (ip, port)
89 print 'starting browser...'
90 try_start_browser('http://%s:%s' % (ip, port))
91
92
94 """ Draw the splash screen """
95
96 root.withdraw()
97
98 dx = root.winfo_screenwidth()
99 dy = root.winfo_screenheight()
100
101 dialog = Tkinter.Toplevel(root, bg='white')
102 dialog.geometry('%ix%i+%i+%i' % (500, 300, dx / 2 - 200, dy / 2 - 150))
103
104 dialog.overrideredirect(1)
105 dialog.focus_force()
106
107 canvas = Tkinter.Canvas(dialog,
108 background='white',
109 width=500,
110 height=300)
111 canvas.pack()
112 root.update()
113
114 logo = 'splashlogo.gif'
115 if os.path.exists(logo):
116 img = Tkinter.PhotoImage(file=logo)
117 pnl = Tkinter.Label(canvas, image=img, background='white', bd=0)
118 pnl.pack(side='top', fill='both', expand='yes')
119
120 pnl.image=img
121
122 def add_label(text='Change Me', font_size=12, foreground='#195866', height=1):
123 return Tkinter.Label(
124 master=canvas,
125 width=250,
126 height=height,
127 text=text,
128 font=('Helvetica', font_size),
129 anchor=Tkinter.CENTER,
130 foreground=foreground,
131 background='white'
132 )
133
134 add_label('Welcome to...').pack(side='top')
135 add_label(ProgramName, 18, '#FF5C1F', 2).pack()
136 add_label(ProgramAuthor).pack()
137 add_label(ProgramVersion).pack()
138
139 root.update()
140 time.sleep(5)
141 dialog.destroy()
142 return
143
144
146 """ Main window dialog """
147
149 """ web2pyDialog constructor """
150
151 root.title('web2py server')
152 self.root = Tkinter.Toplevel(root)
153 self.options = options
154 self.menu = Tkinter.Menu(self.root)
155 servermenu = Tkinter.Menu(self.menu, tearoff=0)
156 httplog = os.path.join(self.options.folder, 'httpserver.log')
157
158
159 item = lambda: try_start_browser(httplog)
160 servermenu.add_command(label='View httpserver.log',
161 command=item)
162
163 servermenu.add_command(label='Quit (pid:%i)' % os.getpid(),
164 command=self.quit)
165
166 self.menu.add_cascade(label='Server', menu=servermenu)
167
168 self.pagesmenu = Tkinter.Menu(self.menu, tearoff=0)
169 self.menu.add_cascade(label='Pages', menu=self.pagesmenu)
170
171 helpmenu = Tkinter.Menu(self.menu, tearoff=0)
172
173
174 item = lambda: try_start_browser('http://www.web2py.com')
175 helpmenu.add_command(label='Home Page',
176 command=item)
177
178
179 item = lambda: tkMessageBox.showinfo('About web2py', ProgramInfo)
180 helpmenu.add_command(label='About',
181 command=item)
182
183 self.menu.add_cascade(label='Info', menu=helpmenu)
184
185 self.root.config(menu=self.menu)
186
187 if options.taskbar:
188 self.root.protocol('WM_DELETE_WINDOW',
189 lambda: self.quit(True))
190 else:
191 self.root.protocol('WM_DELETE_WINDOW', self.quit)
192
193 sticky = Tkinter.NW
194
195
196 Tkinter.Label(self.root,
197 text='Server IP:',
198 justify=Tkinter.LEFT).grid(row=0,
199 column=0,
200 sticky=sticky)
201 self.ip = Tkinter.Entry(self.root)
202 self.ip.insert(Tkinter.END, self.options.ip)
203 self.ip.grid(row=0, column=1, sticky=sticky)
204
205
206 Tkinter.Label(self.root,
207 text='Server Port:',
208 justify=Tkinter.LEFT).grid(row=1,
209 column=0,
210 sticky=sticky)
211
212 self.port_number = Tkinter.Entry(self.root)
213 self.port_number.insert(Tkinter.END, self.options.port)
214 self.port_number.grid(row=1, column=1, sticky=sticky)
215
216
217 Tkinter.Label(self.root,
218 text='Choose Password:',
219 justify=Tkinter.LEFT).grid(row=2,
220 column=0,
221 sticky=sticky)
222
223 self.password = Tkinter.Entry(self.root, show='*')
224 self.password.bind('<Return>', lambda e: self.start())
225 self.password.focus_force()
226 self.password.grid(row=2, column=1, sticky=sticky)
227
228
229 self.canvas = Tkinter.Canvas(self.root,
230 width=300,
231 height=100,
232 bg='black')
233 self.canvas.grid(row=3, column=0, columnspan=2)
234 self.canvas.after(1000, self.update_canvas)
235
236
237 frame = Tkinter.Frame(self.root)
238 frame.grid(row=4, column=0, columnspan=2)
239
240
241 self.button_start = Tkinter.Button(frame,
242 text='start server',
243 command=self.start)
244
245 self.button_start.grid(row=0, column=0)
246
247
248 self.button_stop = Tkinter.Button(frame,
249 text='stop server',
250 command=self.stop)
251
252 self.button_stop.grid(row=0, column=1)
253 self.button_stop.configure(state='disabled')
254
255 if options.taskbar:
256 self.tb = contrib.taskbar_widget.TaskBarIcon()
257 self.checkTaskBar()
258
259 if options.password != '<ask>':
260 self.password.insert(0, options.password)
261 self.start()
262 self.root.withdraw()
263 else:
264 self.tb = None
265
267 """ Check taskbar status """
268
269 if self.tb.status:
270 if self.tb.status[0] == self.tb.EnumStatus.QUIT:
271 self.quit()
272 elif self.tb.status[0] == self.tb.EnumStatus.TOGGLE:
273 if self.root.state() == 'withdrawn':
274 self.root.deiconify()
275 else:
276 self.root.withdraw()
277 elif self.tb.status[0] == self.tb.EnumStatus.STOP:
278 self.stop()
279 elif self.tb.status[0] == self.tb.EnumStatus.START:
280 self.start()
281 elif self.tb.status[0] == self.tb.EnumStatus.RESTART:
282 self.stop()
283 self.start()
284 del self.tb.status[0]
285
286 self.root.after(1000, self.checkTaskBar)
287
289 """ Update app text """
290
291 try:
292 self.text.configure(state='normal')
293 self.text.insert('end', text)
294 self.text.configure(state='disabled')
295 except:
296 pass
297
298 - def connect_pages(self):
299 """ Connect pages """
300
301 for arq in os.listdir('applications/'):
302 if os.path.exists('applications/%s/__init__.py' % arq):
303 url = self.url + '/' + arq
304 start_browser = lambda u = url: try_start_browser(u)
305 self.pagesmenu.add_command(label=url,
306 command=start_browser)
307
308 - def quit(self, justHide=False):
309 """ Finish the program execution """
310
311 if justHide:
312 self.root.withdraw()
313 else:
314 try:
315 self.server.stop()
316 except:
317 pass
318
319 try:
320 self.tb.Destroy()
321 except:
322 pass
323
324 self.root.destroy()
325 sys.exit(0)
326
327 - def error(self, message):
328 """ Show error message """
329
330 tkMessageBox.showerror('web2py start server', message)
331
333 """ Start web2py server """
334
335 password = self.password.get()
336
337 if not password:
338 self.error('no password, no web admin interface')
339
340 ip = self.ip.get()
341
342 regexp = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
343 if ip and not re.compile(regexp).match(ip):
344 return self.error('invalid host ip address')
345
346 try:
347 port = int(self.port_number.get())
348 except:
349 return self.error('invalid port number')
350
351 self.url = 'http://%s:%s' % (ip, port)
352 self.connect_pages()
353 self.button_start.configure(state='disabled')
354
355 try:
356 options = self.options
357 req_queue_size = options.request_queue_size
358 self.server = main.HttpServer(
359 ip,
360 port,
361 password,
362 pid_filename=options.pid_filename,
363 log_filename=options.log_filename,
364 profiler_filename=options.profiler_filename,
365 ssl_certificate=options.ssl_certificate,
366 ssl_private_key=options.ssl_private_key,
367 min_threads=options.minthreads,
368 max_threads=options.maxthreads,
369 server_name=options.server_name,
370 request_queue_size=req_queue_size,
371 timeout=options.timeout,
372 shutdown_timeout=options.shutdown_timeout,
373 path=options.folder,
374 interfaces=options.interfaces)
375
376 thread.start_new_thread(self.server.start, ())
377 except Exception, e:
378 self.button_start.configure(state='normal')
379 return self.error(str(e))
380
381 self.button_stop.configure(state='normal')
382
383 if not options.taskbar:
384 thread.start_new_thread(start_browser, (ip, port))
385
386 self.password.configure(state='readonly')
387 self.ip.configure(state='readonly')
388 self.port_number.configure(state='readonly')
389
390 if self.tb:
391 self.tb.SetServerRunning()
392
394 """ Stop web2py server """
395
396 self.button_start.configure(state='normal')
397 self.button_stop.configure(state='disabled')
398 self.password.configure(state='normal')
399 self.ip.configure(state='normal')
400 self.port_number.configure(state='normal')
401 self.server.stop()
402
403 if self.tb:
404 self.tb.SetServerStopped()
405
407 """ Update canvas """
408
409 try:
410 t1 = os.path.getsize('httpserver.log')
411 except:
412 self.canvas.after(1000, self.update_canvas)
413 return
414
415 try:
416 fp = open('httpserver.log', 'r')
417 fp.seek(self.t0)
418 data = fp.read(t1 - self.t0)
419 fp.close()
420 value = self.p0[1:] + [10 + 90.0 / math.sqrt(1 + data.count('\n'))]
421 self.p0 = value
422
423 for i in xrange(len(self.p0) - 1):
424 c = self.canvas.coords(self.q0[i])
425 self.canvas.coords(self.q0[i],
426 (c[0],
427 self.p0[i],
428 c[2],
429 self.p0[i + 1]))
430 self.t0 = t1
431 except BaseException:
432 self.t0 = time.time()
433 self.t0 = t1
434 self.p0 = [100] * 300
435 self.q0 = [self.canvas.create_line(i, 100, i + 1, 100,
436 fill='green') for i in xrange(len(self.p0) - 1)]
437
438 self.canvas.after(1000, self.update_canvas)
439
440
442 """ Defines the behavior of the console web2py execution """
443 import optparse
444 import textwrap
445
446 usage = "python web2py.py"
447
448 description = """\
449 web2py Web Framework startup script.
450 ATTENTION: unless a password is specified (-a 'passwd') web2py will
451 attempt to run a GUI. In this case command line options are ignored."""
452
453 description = textwrap.dedent(description)
454
455 parser = optparse.OptionParser(usage, None, optparse.Option, ProgramVersion)
456
457 parser.description = description
458
459 parser.add_option('-i',
460 '--ip',
461 default='127.0.0.1',
462 dest='ip',
463 help='ip address of the server (127.0.0.1)')
464
465 parser.add_option('-p',
466 '--port',
467 default='8000',
468 dest='port',
469 type='int',
470 help='port of server (8000)')
471
472 msg = 'password to be used for administration'
473 msg += ' (use -a "<recycle>" to reuse the last password))'
474 parser.add_option('-a',
475 '--password',
476 default='<ask>',
477 dest='password',
478 help=msg)
479
480 parser.add_option('-c',
481 '--ssl_certificate',
482 default='',
483 dest='ssl_certificate',
484 help='file that contains ssl certificate')
485
486 parser.add_option('-k',
487 '--ssl_private_key',
488 default='',
489 dest='ssl_private_key',
490 help='file that contains ssl private key')
491
492 parser.add_option('--ca-cert',
493 action='store',
494 dest='ssl_ca_certificate',
495 default=None,
496 help='Use this file containing the CA certificate to validate X509 certificates from clients')
497
498 parser.add_option('-d',
499 '--pid_filename',
500 default='httpserver.pid',
501 dest='pid_filename',
502 help='file to store the pid of the server')
503
504 parser.add_option('-l',
505 '--log_filename',
506 default='httpserver.log',
507 dest='log_filename',
508 help='file to log connections')
509
510 parser.add_option('-n',
511 '--numthreads',
512 default=None,
513 type='int',
514 dest='numthreads',
515 help='number of threads (deprecated)')
516
517 parser.add_option('--minthreads',
518 default=None,
519 type='int',
520 dest='minthreads',
521 help='minimum number of server threads')
522
523 parser.add_option('--maxthreads',
524 default=None,
525 type='int',
526 dest='maxthreads',
527 help='maximum number of server threads')
528
529 parser.add_option('-s',
530 '--server_name',
531 default=socket.gethostname(),
532 dest='server_name',
533 help='server name for the web server')
534
535 msg = 'max number of queued requests when server unavailable'
536 parser.add_option('-q',
537 '--request_queue_size',
538 default='5',
539 type='int',
540 dest='request_queue_size',
541 help=msg)
542
543 parser.add_option('-o',
544 '--timeout',
545 default='10',
546 type='int',
547 dest='timeout',
548 help='timeout for individual request (10 seconds)')
549
550 parser.add_option('-z',
551 '--shutdown_timeout',
552 default='5',
553 type='int',
554 dest='shutdown_timeout',
555 help='timeout on shutdown of server (5 seconds)')
556
557 parser.add_option('--socket-timeout',
558 default=1,
559 dest='socket_timeout',
560 help='timeout for socket (1 second)')
561
562 parser.add_option('-f',
563 '--folder',
564 default=os.getcwd(),
565 dest='folder',
566 help='folder from which to run web2py')
567
568 parser.add_option('-v',
569 '--verbose',
570 action='store_true',
571 dest='verbose',
572 default=False,
573 help='increase --test verbosity')
574
575 parser.add_option('-Q',
576 '--quiet',
577 action='store_true',
578 dest='quiet',
579 default=False,
580 help='disable all output')
581
582 msg = 'set debug output level (0-100, 0 means all, 100 means none;'
583 msg += ' default is 30)'
584 parser.add_option('-D',
585 '--debug',
586 dest='debuglevel',
587 default=30,
588 type='int',
589 help=msg)
590
591 msg = 'run web2py in interactive shell or IPython (if installed) with'
592 msg += ' specified appname (if app does not exist it will be created).'
593 msg += ' APPNAME like a/c/f (c,f optional)'
594 parser.add_option('-S',
595 '--shell',
596 dest='shell',
597 metavar='APPNAME',
598 help=msg)
599
600 msg = 'run web2py in interactive shell or bpython (if installed) with'
601 msg += ' specified appname (if app does not exist it will be created).'
602 msg += '\n Use combined with --shell'
603 parser.add_option('-B',
604 '--bpython',
605 action='store_true',
606 default=False,
607 dest='bpython',
608 help=msg)
609
610 msg = 'only use plain python shell; should be used with --shell option'
611 parser.add_option('-P',
612 '--plain',
613 action='store_true',
614 default=False,
615 dest='plain',
616 help=msg)
617
618 msg = 'auto import model files; default is False; should be used'
619 msg += ' with --shell option'
620 parser.add_option('-M',
621 '--import_models',
622 action='store_true',
623 default=False,
624 dest='import_models',
625 help=msg)
626
627 msg = 'run PYTHON_FILE in web2py environment;'
628 msg += ' should be used with --shell option'
629 parser.add_option('-R',
630 '--run',
631 dest='run',
632 metavar='PYTHON_FILE',
633 default='',
634 help=msg)
635
636 msg = 'run scheduled tasks for the specified apps'
637 msg += '-K app1,app2,app3'
638 msg += 'requires a scheduler defined in the models'
639 parser.add_option('-K',
640 '--scheduler',
641 dest='scheduler',
642 default=None,
643 help=msg)
644
645 msg = 'run doctests in web2py environment; ' +\
646 'TEST_PATH like a/c/f (c,f optional)'
647 parser.add_option('-T',
648 '--test',
649 dest='test',
650 metavar='TEST_PATH',
651 default=None,
652 help=msg)
653
654 parser.add_option('-W',
655 '--winservice',
656 dest='winservice',
657 default='',
658 help='-W install|start|stop as Windows service')
659
660 msg = 'trigger a cron run manually; usually invoked from a system crontab'
661 parser.add_option('-C',
662 '--cron',
663 action='store_true',
664 dest='extcron',
665 default=False,
666 help=msg)
667
668 msg = 'triggers the use of softcron'
669 parser.add_option('--softcron',
670 action='store_true',
671 dest='softcron',
672 default=False,
673 help=msg)
674
675 parser.add_option('-N',
676 '--no-cron',
677 action='store_true',
678 dest='nocron',
679 default=False,
680 help='do not start cron automatically')
681
682 parser.add_option('-J',
683 '--cronjob',
684 action='store_true',
685 dest='cronjob',
686 default=False,
687 help='identify cron-initiated command')
688
689 parser.add_option('-L',
690 '--config',
691 dest='config',
692 default='',
693 help='config file')
694
695 parser.add_option('-F',
696 '--profiler',
697 dest='profiler_filename',
698 default=None,
699 help='profiler filename')
700
701 parser.add_option('-t',
702 '--taskbar',
703 action='store_true',
704 dest='taskbar',
705 default=False,
706 help='use web2py gui and run in taskbar (system tray)')
707
708 parser.add_option('',
709 '--nogui',
710 action='store_true',
711 default=False,
712 dest='nogui',
713 help='text-only, no GUI')
714
715 parser.add_option('-A',
716 '--args',
717 action='store',
718 dest='args',
719 default=None,
720 help='should be followed by a list of arguments to be passed to script, to be used with -S, -A must be the last option')
721
722 parser.add_option('--no-banner',
723 action='store_true',
724 default=False,
725 dest='nobanner',
726 help='Do not print header banner')
727
728
729 msg = 'listen on multiple addresses: "ip:port:cert:key:ca_cert;ip2:port2:cert2:key2:ca_cert2;..." (:cert:key optional; no spaces)'
730 parser.add_option('--interfaces',
731 action='store',
732 dest='interfaces',
733 default=None,
734 help=msg)
735
736 if '-A' in sys.argv: k = sys.argv.index('-A')
737 elif '--args' in sys.argv: k = sys.argv.index('--args')
738 else: k=len(sys.argv)
739 sys.argv, other_args = sys.argv[:k], sys.argv[k+1:]
740 (options, args) = parser.parse_args()
741 options.args = [options.run] + other_args
742 global_settings.cmd_options = options
743 global_settings.cmd_args = args
744
745 if options.quiet:
746 capture = cStringIO.StringIO()
747 sys.stdout = capture
748 logger.setLevel(logging.CRITICAL + 1)
749 else:
750 logger.setLevel(options.debuglevel)
751
752 if options.config[-3:] == '.py':
753 options.config = options.config[:-3]
754
755 if options.cronjob:
756 global_settings.cronjob = True
757 options.nocron = True
758 options.plain = True
759
760 options.folder = os.path.abspath(options.folder)
761
762
763
764
765 if isinstance(options.interfaces, str):
766 options.interfaces = [
767 interface.split(':') for interface in options.interfaces.split(';')]
768 for interface in options.interfaces:
769 interface[1] = int(interface[1])
770 options.interfaces = [
771 tuple(interface) for interface in options.interfaces]
772
773 if options.numthreads is not None and options.minthreads is None:
774 options.minthreads = options.numthreads
775
776 if not options.cronjob:
777
778 if not os.path.exists('applications/__init__.py'):
779 write_file('applications/__init__.py', '')
780
781 if not os.path.exists('welcome.w2p') or os.path.exists('NEWINSTALL'):
782 try:
783 w2p_pack('welcome.w2p','applications/welcome')
784 os.unlink('NEWINSTALL')
785 except:
786 msg = "New installation: unable to create welcome.w2p file"
787 sys.stderr.write(msg)
788
789 return (options, args)
790
792 apps = [app.strip() for app in options.scheduler.split(',')]
793 try:
794 from multiprocessing import Process
795 except:
796 sys.stderr.write('Sorry, -K only supported for python 2.6-2.7\n')
797 return
798 processes = []
799 code = "from gluon import current; current._scheduler.loop()"
800 for app in apps:
801 print 'starting scheduler for "%s"...' % app
802 args = (app,True,True,None,False,code)
803 logging.getLogger().setLevel(logging.DEBUG)
804 p = Process(target=run, args=args)
805 processes.append(p)
806 print "Currently running %s scheduler processes" % (len(processes))
807 p.start()
808 print "Processes started"
809 for p in processes:
810 try:
811 p.join()
812 except KeyboardInterrupt:
813 p.terminate()
814 p.join()
815
816
818 """ Start server """
819
820
821
822 (options, args) = console()
823
824 if not options.nobanner:
825 print ProgramName
826 print ProgramAuthor
827 print ProgramVersion
828
829 from dal import drivers
830 if not options.nobanner:
831 print 'Database drivers available: %s' % ', '.join(drivers)
832
833
834
835 if options.config:
836 try:
837 options2 = __import__(options.config, {}, {}, '')
838 except Exception:
839 try:
840
841 options2 = __import__(options.config)
842 except Exception:
843 print 'Cannot import config file [%s]' % options.config
844 sys.exit(1)
845 for key in dir(options2):
846 if hasattr(options,key):
847 setattr(options,key,getattr(options2,key))
848
849
850 if hasattr(options,'test') and options.test:
851 test(options.test, verbose=options.verbose)
852 return
853
854
855 if options.scheduler:
856 try:
857 start_schedulers(options)
858 except KeyboardInterrupt:
859 pass
860 return
861
862
863 if options.shell:
864 if not options.args is None:
865 sys.argv[:] = options.args
866 run(options.shell, plain=options.plain, bpython=options.bpython,
867 import_models=options.import_models, startfile=options.run)
868 return
869
870
871
872
873
874 if options.extcron:
875 print 'Starting extcron...'
876 global_settings.web2py_crontype = 'external'
877 extcron = newcron.extcron(options.folder)
878 extcron.start()
879 extcron.join()
880 return
881 elif cron and not options.nocron and options.softcron:
882 print 'Using softcron (but this is not very efficient)'
883 global_settings.web2py_crontype = 'soft'
884 elif cron and not options.nocron:
885 print 'Starting hardcron...'
886 global_settings.web2py_crontype = 'hard'
887 newcron.hardcron(options.folder).start()
888
889
890 if options.winservice:
891 if os.name == 'nt':
892 web2py_windows_service_handler(['', options.winservice],
893 options.config)
894 else:
895 print 'Error: Windows services not supported on this platform'
896 sys.exit(1)
897 return
898
899
900
901
902 try:
903 options.taskbar
904 except:
905 options.taskbar = False
906
907 if options.taskbar and os.name != 'nt':
908 print 'Error: taskbar not supported on this platform'
909 sys.exit(1)
910
911 root = None
912
913 if not options.nogui:
914 try:
915 import Tkinter
916 havetk = True
917 except ImportError:
918 logger.warn('GUI not available because Tk library is not installed')
919 havetk = False
920
921 if options.password == '<ask>' and havetk or options.taskbar and havetk:
922 try:
923 root = Tkinter.Tk()
924 except:
925 pass
926
927 if root:
928 root.focus_force()
929 if not options.quiet:
930 presentation(root)
931 master = web2pyDialog(root, options)
932 signal.signal(signal.SIGTERM, lambda a, b: master.quit())
933
934 try:
935 root.mainloop()
936 except:
937 master.quit()
938
939 sys.exit()
940
941
942
943 if not root and options.password == '<ask>':
944 options.password = raw_input('choose a password:')
945
946 if not options.password and not options.nobanner:
947 print 'no password, no admin interface'
948
949
950
951 (ip, port) = (options.ip, int(options.port))
952
953 if not options.nobanner:
954 print 'please visit:'
955 print '\thttp://%s:%s' % (ip, port)
956 print 'use "kill -SIGTERM %i" to shutdown the web2py server' % os.getpid()
957
958 server = main.HttpServer(ip=ip,
959 port=port,
960 password=options.password,
961 pid_filename=options.pid_filename,
962 log_filename=options.log_filename,
963 profiler_filename=options.profiler_filename,
964 ssl_certificate=options.ssl_certificate,
965 ssl_private_key=options.ssl_private_key,
966 ssl_ca_certificate=options.ssl_ca_certificate,
967 min_threads=options.minthreads,
968 max_threads=options.maxthreads,
969 server_name=options.server_name,
970 request_queue_size=options.request_queue_size,
971 timeout=options.timeout,
972 socket_timeout=options.socket_timeout,
973 shutdown_timeout=options.shutdown_timeout,
974 path=options.folder,
975 interfaces=options.interfaces)
976
977 try:
978 server.start()
979 except KeyboardInterrupt:
980 server.stop()
981 logging.shutdown()
982