#!/usr/bin/env python
# Copyright (c) 2008, 2009, 2011 Arastra, Inc.  All rights reserved.
# Arastra, Inc. Confidential and Proprietary.

from __future__ import absolute_import, division, print_function
import os, sys, FastServ, FastServUtil, Ark
import six

def doArgv( argv ):
   if argv:
      if argv[0] == '-c':
         six.exec_( ' '.join( argv[1:] ))
      else:
         sys.argv = argv
         six.exec_( open( argv[0] ).read(), globals() )
   else:
      import code
      code.interact()

serviceName = None
pythonMode = None
def main():
   global opts
   import optparse
   op = optparse.OptionParser( usage="%prog [OPTIONS] [<name>]" )
   op.add_option( "-c", "--command", action="store",
                  help="exec python code before serving",
                  metavar="CODE")
   op.add_option( "-d", "--daemonize", action="store_true",
                   help="daemonize and return immediately" )
   op.add_option( "-n", action="store_true", help="starts a namespace" )
   op.add_option( "-p", "--python", action="store_true", help="python mode" )
   op.add_option( "-f", action="store", help="specify namespace flags [nmshiu]: "
                  "n=NET, m=NS(mount), h=UTS, i=IPC, u=USER, p=PID "
                  "(-n is required, default=nm)",
                  metavar="FLAGS")
   op.add_option( "--logfile", action="store",
                  help="write output to LOGFILE (default=%default)" )
   op.add_option( "--pidfile", action="store",
                  help="write process ID of server to PIDFILE (default=%default)" )
   opts,args = op.parse_args()

   if opts.f and not opts.n:
      op.error( "options flags (-f) can only be used when creating a namespace "
                "(-n)" )

   if opts.logfile:
      os.close( 1 )
      os.close( 2 )
      os.open( opts.logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND )
      os.dup( 1 )

   namespaceFlags = None
   if opts.n:
      if opts.f:
         namespaceFlags = opts.f
      else:
         namespaceFlags = 'nm'

   if opts.command:
      six.exec_( opts.command )

   global pythonMode
   pythonMode = opts.python

   if opts.daemonize:
      if os.fork() != 0:
         sys.exit()
      os.setsid()
      if os.fork() != 0:
         os._exit( 0 )
      os.umask( 0 )
      os.close( 0 )
      os.open( "/dev/null", os.O_RDONLY )

   if args:
      global serviceName
      serviceName = args[0]
      server = ":/fastclient/" + args[0]
   else:
      op.error( "service name must be specified" )

   if len( args ) > 1:
      op.error( "unexpected arguments: '%s'" % ' '.join( args[1:] ) )

   # clean up environment variables that interfere
   for i in ['COLUMNS','TERM']:
      os.environ.pop( i, None )

   if opts.pidfile:
      open( opts.pidfile, "w+", 1 ).write( "%d\n" % os.getpid() )

   # This call never exits, but it is like a fork.  The child process
   # returns from it, but the parent never does.  The file descriptor
   # returned is connected to the front-end.
   fd = FastServ.serve( "fastserv", server, namespaceFlags )
   after(fd, namespaceFlags)

def after(fd, namespaceFlags):
   argv = FastServUtil.processEnvArgs( fd )
   argv = FastServUtil.popEnvFromArgv( argv )

   if namespaceFlags:
      os.environ['NSNAME'] = serviceName

   if not argv:
      argv = [ os.environ.get('SHELL','bash') ]

   if argv[0] != '-c':
      try:
         if pythonMode:
            exe = Ark.findInPath( argv[0], 'PATH', os.X_OK )
            isPython=False
            try:
               fp = open( exe )
               first128 = fp.read(128)
               fp.close()
               if 'python' in first128:
                  isPython=True
            except:
               pass
            if not isPython:
               os.execl( exe, *argv )
         else:
            os.execlp( argv[0], *argv )
      except ValueError:
         print( "fastserv: executable not found:", argv[0] )
         sys.exit(255)
      else:
         argv[0] = exe
   doArgv( argv )

if __name__ == "__main__":
   main()
