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