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  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   
57 -class IO(object):
58 """ """ 59
60 - def __init__(self):
61 """ """ 62 63 self.buffer = cStringIO.StringIO()
64
65 - def write(self, data):
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
75 -def try_start_browser(url):
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
85 -def start_browser(ip, port):
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
93 -def presentation(root):
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 # Prevent garbage collection of img 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
145 -class web2pyDialog(object):
146 """ Main window dialog """ 147
148 - def __init__(self, root, options):
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 # Building the Menu 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 # Home Page 174 item = lambda: try_start_browser('http://www.web2py.com') 175 helpmenu.add_command(label='Home Page', 176 command=item) 177 178 # About 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 # IP 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 # Port 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 # Password 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 # Prepare the canvas 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 # Prepare the frame 237 frame = Tkinter.Frame(self.root) 238 frame.grid(row=4, column=0, columnspan=2) 239 240 # Start button 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 # Stop button 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
266 - def checkTaskBar(self):
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
288 - def update(self, text):
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 # ## this should only happen in case app is destroyed
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
332 - def start(self):
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
393 - def stop(self):
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
406 - def update_canvas(self):
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
441 -def console():
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=5, 559 type='int', 560 dest='socket_timeout', 561 help='timeout for socket (5 second)') 562 563 parser.add_option('-f', 564 '--folder', 565 default=os.getcwd(), 566 dest='folder', 567 help='folder from which to run web2py') 568 569 parser.add_option('-v', 570 '--verbose', 571 action='store_true', 572 dest='verbose', 573 default=False, 574 help='increase --test verbosity') 575 576 parser.add_option('-Q', 577 '--quiet', 578 action='store_true', 579 dest='quiet', 580 default=False, 581 help='disable all output') 582 583 msg = 'set debug output level (0-100, 0 means all, 100 means none;' 584 msg += ' default is 30)' 585 parser.add_option('-D', 586 '--debug', 587 dest='debuglevel', 588 default=30, 589 type='int', 590 help=msg) 591 592 msg = 'run web2py in interactive shell or IPython (if installed) with' 593 msg += ' specified appname (if app does not exist it will be created).' 594 msg += ' APPNAME like a/c/f (c,f optional)' 595 parser.add_option('-S', 596 '--shell', 597 dest='shell', 598 metavar='APPNAME', 599 help=msg) 600 601 msg = 'run web2py in interactive shell or bpython (if installed) with' 602 msg += ' specified appname (if app does not exist it will be created).' 603 msg += '\n Use combined with --shell' 604 parser.add_option('-B', 605 '--bpython', 606 action='store_true', 607 default=False, 608 dest='bpython', 609 help=msg) 610 611 msg = 'only use plain python shell; should be used with --shell option' 612 parser.add_option('-P', 613 '--plain', 614 action='store_true', 615 default=False, 616 dest='plain', 617 help=msg) 618 619 msg = 'auto import model files; default is False; should be used' 620 msg += ' with --shell option' 621 parser.add_option('-M', 622 '--import_models', 623 action='store_true', 624 default=False, 625 dest='import_models', 626 help=msg) 627 628 msg = 'run PYTHON_FILE in web2py environment;' 629 msg += ' should be used with --shell option' 630 parser.add_option('-R', 631 '--run', 632 dest='run', 633 metavar='PYTHON_FILE', 634 default='', 635 help=msg) 636 637 msg = 'run scheduled tasks for the specified apps' 638 msg += '-K app1,app2,app3' 639 msg += 'requires a scheduler defined in the models' 640 parser.add_option('-K', 641 '--scheduler', 642 dest='scheduler', 643 default=None, 644 help=msg) 645 646 msg = 'run doctests in web2py environment; ' +\ 647 'TEST_PATH like a/c/f (c,f optional)' 648 parser.add_option('-T', 649 '--test', 650 dest='test', 651 metavar='TEST_PATH', 652 default=None, 653 help=msg) 654 655 parser.add_option('-W', 656 '--winservice', 657 dest='winservice', 658 default='', 659 help='-W install|start|stop as Windows service') 660 661 msg = 'trigger a cron run manually; usually invoked from a system crontab' 662 parser.add_option('-C', 663 '--cron', 664 action='store_true', 665 dest='extcron', 666 default=False, 667 help=msg) 668 669 msg = 'triggers the use of softcron' 670 parser.add_option('--softcron', 671 action='store_true', 672 dest='softcron', 673 default=False, 674 help=msg) 675 676 parser.add_option('-N', 677 '--no-cron', 678 action='store_true', 679 dest='nocron', 680 default=False, 681 help='do not start cron automatically') 682 683 parser.add_option('-J', 684 '--cronjob', 685 action='store_true', 686 dest='cronjob', 687 default=False, 688 help='identify cron-initiated command') 689 690 parser.add_option('-L', 691 '--config', 692 dest='config', 693 default='', 694 help='config file') 695 696 parser.add_option('-F', 697 '--profiler', 698 dest='profiler_filename', 699 default=None, 700 help='profiler filename') 701 702 parser.add_option('-t', 703 '--taskbar', 704 action='store_true', 705 dest='taskbar', 706 default=False, 707 help='use web2py gui and run in taskbar (system tray)') 708 709 parser.add_option('', 710 '--nogui', 711 action='store_true', 712 default=False, 713 dest='nogui', 714 help='text-only, no GUI') 715 716 parser.add_option('-A', 717 '--args', 718 action='store', 719 dest='args', 720 default=None, 721 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') 722 723 parser.add_option('--no-banner', 724 action='store_true', 725 default=False, 726 dest='nobanner', 727 help='Do not print header banner') 728 729 730 msg = 'listen on multiple addresses: "ip:port:cert:key:ca_cert;ip2:port2:cert2:key2:ca_cert2;..." (:cert:key optional; no spaces)' 731 parser.add_option('--interfaces', 732 action='store', 733 dest='interfaces', 734 default=None, 735 help=msg) 736 737 if '-A' in sys.argv: k = sys.argv.index('-A') 738 elif '--args' in sys.argv: k = sys.argv.index('--args') 739 else: k=len(sys.argv) 740 sys.argv, other_args = sys.argv[:k], sys.argv[k+1:] 741 (options, args) = parser.parse_args() 742 options.args = [options.run] + other_args 743 global_settings.cmd_options = options 744 global_settings.cmd_args = args 745 746 if options.quiet: 747 capture = cStringIO.StringIO() 748 sys.stdout = capture 749 logger.setLevel(logging.CRITICAL + 1) 750 else: 751 logger.setLevel(options.debuglevel) 752 753 if options.config[-3:] == '.py': 754 options.config = options.config[:-3] 755 756 if options.cronjob: 757 global_settings.cronjob = True # tell the world 758 options.nocron = True # don't start cron jobs 759 options.plain = True # cronjobs use a plain shell 760 761 options.folder = os.path.abspath(options.folder) 762 763 # accept --interfaces in the form 764 # "ip:port:cert:key;ip2:port2;ip3:port3:cert3:key3" 765 # (no spaces; optional cert:key indicate SSL) 766 if isinstance(options.interfaces, str): 767 options.interfaces = [ 768 interface.split(':') for interface in options.interfaces.split(';')] 769 for interface in options.interfaces: 770 interface[1] = int(interface[1]) # numeric port 771 options.interfaces = [ 772 tuple(interface) for interface in options.interfaces] 773 774 if options.numthreads is not None and options.minthreads is None: 775 options.minthreads = options.numthreads # legacy 776 777 if not options.cronjob: 778 # If we have the applications package or if we should upgrade 779 if not os.path.exists('applications/__init__.py'): 780 write_file('applications/__init__.py', '') 781 782 if not os.path.exists('welcome.w2p') or os.path.exists('NEWINSTALL'): 783 try: 784 w2p_pack('welcome.w2p','applications/welcome') 785 os.unlink('NEWINSTALL') 786 except: 787 msg = "New installation: unable to create welcome.w2p file" 788 sys.stderr.write(msg) 789 790 return (options, args)
791
792 -def start_schedulers(options):
793 apps = [app.strip() for app in options.scheduler.split(',')] 794 try: 795 from multiprocessing import Process 796 except: 797 sys.stderr.write('Sorry, -K only supported for python 2.6-2.7\n') 798 return 799 processes = [] 800 code = "from gluon import current; current._scheduler.loop()" 801 for app in apps: 802 print 'starting scheduler for "%s"...' % app 803 args = (app,True,True,None,False,code) 804 logging.getLogger().setLevel(logging.DEBUG) 805 p = Process(target=run, args=args) 806 processes.append(p) 807 print "Currently running %s scheduler processes" % (len(processes)) 808 p.start() 809 print "Processes started" 810 for p in processes: 811 try: 812 p.join() 813 except KeyboardInterrupt: 814 p.terminate() 815 p.join()
816 817
818 -def start(cron=True):
819 """ Start server """ 820 821 # ## get command line arguments 822 823 (options, args) = console() 824 825 if not options.nobanner: 826 print ProgramName 827 print ProgramAuthor 828 print ProgramVersion 829 830 from dal import drivers 831 if not options.nobanner: 832 print 'Database drivers available: %s' % ', '.join(drivers) 833 834 835 # ## if -L load options from options.config file 836 if options.config: 837 try: 838 options2 = __import__(options.config, {}, {}, '') 839 except Exception: 840 try: 841 # Jython doesn't like the extra stuff 842 options2 = __import__(options.config) 843 except Exception: 844 print 'Cannot import config file [%s]' % options.config 845 sys.exit(1) 846 for key in dir(options2): 847 if hasattr(options,key): 848 setattr(options,key,getattr(options2,key)) 849 850 # ## if -T run doctests (no cron) 851 if hasattr(options,'test') and options.test: 852 test(options.test, verbose=options.verbose) 853 return 854 855 # ## if -K 856 if options.scheduler: 857 try: 858 start_schedulers(options) 859 except KeyboardInterrupt: 860 pass 861 return 862 863 # ## if -S start interactive shell (also no cron) 864 if options.shell: 865 if not options.args is None: 866 sys.argv[:] = options.args 867 run(options.shell, plain=options.plain, bpython=options.bpython, 868 import_models=options.import_models, startfile=options.run) 869 return 870 871 # ## if -C start cron run (extcron) and exit 872 # ## if -N or not cron disable cron in this *process* 873 # ## if --softcron use softcron 874 # ## use hardcron in all other cases 875 if options.extcron: 876 print 'Starting extcron...' 877 global_settings.web2py_crontype = 'external' 878 extcron = newcron.extcron(options.folder) 879 extcron.start() 880 extcron.join() 881 return 882 elif cron and not options.nocron and options.softcron: 883 print 'Using softcron (but this is not very efficient)' 884 global_settings.web2py_crontype = 'soft' 885 elif cron and not options.nocron: 886 print 'Starting hardcron...' 887 global_settings.web2py_crontype = 'hard' 888 newcron.hardcron(options.folder).start() 889 890 # ## if -W install/start/stop web2py as service 891 if options.winservice: 892 if os.name == 'nt': 893 web2py_windows_service_handler(['', options.winservice], 894 options.config) 895 else: 896 print 'Error: Windows services not supported on this platform' 897 sys.exit(1) 898 return 899 900 # ## if no password provided and havetk start Tk interface 901 # ## or start interface if we want to put in taskbar (system tray) 902 903 try: 904 options.taskbar 905 except: 906 options.taskbar = False 907 908 if options.taskbar and os.name != 'nt': 909 print 'Error: taskbar not supported on this platform' 910 sys.exit(1) 911 912 root = None 913 914 if not options.nogui: 915 try: 916 import Tkinter 917 havetk = True 918 except ImportError: 919 logger.warn('GUI not available because Tk library is not installed') 920 havetk = False 921 922 if options.password == '<ask>' and havetk or options.taskbar and havetk: 923 try: 924 root = Tkinter.Tk() 925 except: 926 pass 927 928 if root: 929 root.focus_force() 930 if not options.quiet: 931 presentation(root) 932 master = web2pyDialog(root, options) 933 signal.signal(signal.SIGTERM, lambda a, b: master.quit()) 934 935 try: 936 root.mainloop() 937 except: 938 master.quit() 939 940 sys.exit() 941 942 # ## if no tk and no password, ask for a password 943 944 if not root and options.password == '<ask>': 945 options.password = raw_input('choose a password:') 946 947 if not options.password and not options.nobanner: 948 print 'no password, no admin interface' 949 950 # ## start server 951 952 (ip, port) = (options.ip, int(options.port)) 953 954 if not options.nobanner: 955 print 'please visit:' 956 print '\thttp://%s:%s' % (ip, port) 957 print 'use "kill -SIGTERM %i" to shutdown the web2py server' % os.getpid() 958 959 server = main.HttpServer(ip=ip, 960 port=port, 961 password=options.password, 962 pid_filename=options.pid_filename, 963 log_filename=options.log_filename, 964 profiler_filename=options.profiler_filename, 965 ssl_certificate=options.ssl_certificate, 966 ssl_private_key=options.ssl_private_key, 967 ssl_ca_certificate=options.ssl_ca_certificate, 968 min_threads=options.minthreads, 969 max_threads=options.maxthreads, 970 server_name=options.server_name, 971 request_queue_size=options.request_queue_size, 972 timeout=options.timeout, 973 socket_timeout=options.socket_timeout, 974 shutdown_timeout=options.shutdown_timeout, 975 path=options.folder, 976 interfaces=options.interfaces) 977 978 try: 979 server.start() 980 except KeyboardInterrupt: 981 server.stop() 982 logging.shutdown()
983