Package web2py :: Package gluon :: Module widget
[hide private]
[frames] | no frames]

Source Code for Module web2py.gluon.widget

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