home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 May / maximum-cd-2009-05.iso / DiscContents / XBMC_for_Windows-8.10.exe / system / python / spyce / spyceCmd.py < prev    next >
Encoding:
Python Source  |  2008-11-03  |  11.4 KB  |  335 lines

  1. ##################################################
  2. # SPYCE - Python-based HTML Scripting
  3. # Copyright (c) 2002 Rimon Barr.
  4. #
  5. # Refer to spyce.py
  6. # CVS: $Id: spyceCmd.py 5659 2006-04-27 16:15:15Z jwnmulder $
  7. ##################################################
  8.  
  9. import getopt, sys, traceback, os, string, glob, copy
  10. import spyce, spyceException, spyceUtil
  11.  
  12. __doc__ = '''Command-line and CGI-based Spyce entry point.'''
  13.  
  14. ##################################################
  15. # Output
  16. #
  17.  
  18. # output version
  19. def showVersion(out=sys.stdout):
  20.   "Emit version information."
  21.   out.write('spyce v'+spyce.__version__+', by Rimon Barr: ')
  22.   out.write('Python Server Pages\n')
  23.  
  24. # output syntax
  25. def showUsage(out=sys.stdout):
  26.   "Emit command-line usage information."
  27.   showVersion(out)
  28.   out.write('Command-line usage:\n')
  29.   out.write('  spyce [-c] [-o filename.html] <filename.spy>\n')
  30.   out.write('  spyce [-w] <filename.spy>              <-- CGI\n')
  31.   out.write('  spyce -O filename(s).spy               <-- batch process\n')
  32.   out.write('  spyce -l [-p port] [-d file ] [<root>] <-- proxy server\n')
  33.   out.write('  spyce -h | -v\n')
  34.   out.write('    -h, -?, --help       display this help information\n')
  35.   out.write('    -v, --version        display version\n')
  36.   out.write('    -o, --output         send output to given file\n')
  37.   out.write('    -O                   send outputs of multiple files to *.html\n')
  38.   out.write('    -c, --compile        compile only; do not execute\n')
  39.   out.write('    -w, --web            cgi mode: emit headers (or use run_spyceCGI.py)\n')
  40.   out.write('    -q, --query          set QUERY_STRING environment variable\n')
  41.   out.write('    -l, --listen         run in HTTP server mode\n')
  42.   out.write('    -d, --daemon         run as a daemon process with given pidfile\n')
  43.   out.write('    -p, --port           listen on given port, default 80\n')
  44.   out.write('    --conf [file]        Spyce configuration file\n')
  45.   out.write('To configure Apache, please refer to: spyceApache.conf\n')
  46.   out.write('For more details, refer to the documentation.\n')
  47.   out.write('  http://spyce.sourceforce.net\n')
  48.   out.write('Send comments, suggestions and bug reports to <rimon-AT-acm.org>.\n')
  49.  
  50. ##################################################
  51. # Request / Response handlers
  52. #
  53.  
  54. class spyceCmdlineRequest(spyce.spyceRequest):
  55.   'CGI/Command-line Spyce request object. (see spyce.spyceRequest)'
  56.   def __init__(self, input, env, filename):
  57.     spyce.spyceRequest.__init__(self)
  58.     self._in = input
  59.     self._env = copy.copy(env)
  60.     if not self._env.has_key('SERVER_SOFTWARE'):
  61.       self._env['SERVER_SOFTWARE'] = 'spyce %s Command-line' % spyce.__version__
  62.     if not self._env.has_key('REQUEST_URI'): 
  63.       self._env['REQUEST_URI']=filename
  64.     if not self._env.has_key('REQUEST_METHOD'): 
  65.       self._env['REQUEST_METHOD']='spyce'
  66.     if not self._env.has_key('QUERY_STRING'): 
  67.       self._env['QUERY_STRING']=''
  68.     self._headers = {
  69.       'Content-Length': self.env('CONTENT_LENGTH'),
  70.       'Content-Type': self.env('CONTENT_TYPE'),
  71.       'User-Agent': self.env('HTTP_USER_AGENT'),
  72.       'Accept': self.env('HTTP_ACCEPT'),
  73.       'Accept-Encoding': self.env('HTTP_ACCEPT_ENCODING'),
  74.       'Accept-Language': self.env('HTTP_ACCEPT_LANGUAGE'),
  75.       'Accept-Charset': self.env('HTTP_ACCEPT_CHARSET'),
  76.       'Cookie': self.env('HTTP_COOKIE'),
  77.       'Referer': self.env('HTTP_REFERER'),
  78.       'Host': self.env('HTTP_HOST'),
  79.       'Connection': self.env('HTTP_CONNECTION'),
  80.       'Keep-Alive': self.env('HTTP_KEEP_ALIVE'),
  81.     }
  82.   def env(self, name=None):
  83.     return spyceUtil.extractValue(self._env, name)
  84.   def getHeader(self, type=None):
  85.     return spyceUtil.extractValue(self._headers, type)
  86.   def getServerID(self):
  87.     return os.getpid()
  88.  
  89. class spyceCmdlineResponse(spyce.spyceResponse):
  90.   'CGI/Command-line Spyce response object. (see spyce.spyceResponse)'
  91.   def __init__(self, out, err, cgimode=0):
  92.     spyce.spyceResponse.__init__(self)
  93.     if not cgimode:
  94.       self.RETURN_OK = 0
  95.       self.RETURN_CODE[self.RETURN_OK] = 'OK'
  96.     self.origout = out
  97.     self.out = spyceUtil.BufferedOutput(out)
  98.     self.err = err
  99.     self.cgimode = cgimode
  100.     self.headers = []
  101.     self.headersSent = 0
  102.     self.CT = None
  103.     self.returncode = self.RETURN_OK
  104.     # functions (for performance)
  105.     self.write = self.out.write
  106.     self.writeErr = self.err.write
  107.     self.clear = self.out.clear
  108.   def close(self):
  109.     self.flush()
  110.     self.out.close()
  111.   def sendHeaders(self):
  112.     if self.cgimode and not self.headersSent:
  113.       resultText = spyceUtil.extractValue(self.RETURN_CODE, self.returncode)
  114.       self.origout.write('Status: %3d "%s"\n' % (self.returncode, resultText))
  115.       if not self.CT:
  116.         self.setContentType('text/html')
  117.       self.origout.write('Content-Type: %s\n' % self.CT)
  118.       for h in self.headers:
  119.         self.origout.write('%s: %s\n'%h)
  120.       self.origout.write('\n')
  121.       self.headersSent = 1
  122.   def clearHeaders(self):
  123.     if self.headersSent:
  124.       raise 'headers already sent'
  125.     self.headers = []
  126.   def setContentType(self, content_type):
  127.     if self.headersSent:
  128.       raise 'headers already sent'
  129.     self.CT = content_type
  130.   def setReturnCode(self, code):
  131.     if self.headersSent:
  132.       raise 'headers already sent'
  133.     self.returncode = code
  134.   def addHeader(self, type, data, replace=0):
  135.     if self.headersSent:
  136.       raise 'headers already sent'
  137.     if type=='Content-Type':
  138.       self.setContentType(data)
  139.     else:
  140.       if replace:
  141.         self.headers = filter(lambda (type, _), t2=type: type!=t2, self.headers)
  142.       self.headers.append((type, data))
  143.   def flush(self, stopFlag=0):
  144.     if stopFlag: return
  145.     self.sendHeaders()
  146.     self.out.flush()
  147.   def unbuffer(self):
  148.     self.sendHeaders()
  149.     self.out.unbuffer()
  150.  
  151. ##################################################
  152. # Daemonizing
  153. #
  154.  
  155. def daemonize(stdin='/dev/null', stdout='/dev/null', stderr='/dev/null', pidfile=None):
  156.   '''Forks current process into a daemon. stdin, stdout, and stderr arguments 
  157.   are file names that are opened and used in place of the standard file descriptors
  158.   in sys.stdin, sys.stdout, and sys.stderr, which default to /dev/null.
  159.   Note that stderr is unbuffered, so output may interleave with unexpected order
  160.   if shares destination with stdout.'''
  161.   def forkToChild():
  162.     try: 
  163.       if os.fork()>0: sys.exit(0) # exit parent.
  164.     except OSError, e: 
  165.       sys.stderr.write("fork failed: (%d) %s\n" % (e.errno, e.strerror))
  166.       sys.exit(1)
  167.   # First fork; decouple
  168.   forkToChild()
  169.   os.chdir("/") 
  170.   os.umask(0) 
  171.   os.setsid() 
  172.   # Second fork; create pidfile; redirect descriptors
  173.   forkToChild()
  174.   pid = str(os.getpid())
  175.   if pidfile: 
  176.     f = open(pidfile,'w+')
  177.     f.write("%s\n" % pid)
  178.     f.close()
  179.   si = open(stdin, 'r')
  180.   so = open(stdout, 'a+')
  181.   se = open(stderr, 'a+', 0)
  182.   os.dup2(si.fileno(), sys.stdin.fileno())
  183.   os.dup2(so.fileno(), sys.stdout.fileno())
  184.   os.dup2(se.fileno(), sys.stderr.fileno())
  185.   # I am a daemon!
  186.  
  187. ##################################################
  188. # Command-line entry point
  189. #
  190.  
  191. #for debugging/profiling only
  192. #sys.stdout = spyceUtil.NoCloseOut(sys.stdout)
  193.  
  194. def spyceMain(cgimode=0, cgiscript=None, 
  195.     stdout=sys.stdout, stdin=sys.stdin, stderr=sys.stderr, environ=os.environ):
  196.   "Command-line and CGI entry point."
  197.   # defaults
  198.   compileonlyMode = 0
  199.   outputFilename = None
  200.   defaultOutputFilename = 0
  201.   httpmode = 0
  202.   httpport = None
  203.   httproot = None
  204.   daemon = None
  205.   configFile = None
  206.   # parse options
  207.   if cgimode and cgiscript:
  208.     args = [cgiscript]
  209.   else:
  210.     try:
  211.       opts, args = getopt.getopt(sys.argv[1:], 'h?vco:Owq:ld:p:',
  212.         ['help', 'version', 'compile', 'output=', 'web', 
  213.          'query=', 'listen', 'daemon=', 'port=', 'conf=',])
  214.     except getopt.error: 
  215.       if cgimode:
  216.         stdout.write('Content-Type: text/plain\n\n')
  217.       stdout.write('syntax: unknown switch used\n')
  218.       stdout.write('Use -h option for help.\n')
  219.       return -1
  220.     for o, a in opts:
  221.       if o in ("-v", "--version"):
  222.         showVersion(); return
  223.       if o in ("-h", "--help", "-?"):
  224.         showUsage(); return
  225.       if o in ("-c", "--compileonly"):
  226.         compileonlyMode = 1
  227.       if o in ("-o", "--output"):
  228.         outputFilename = a
  229.       if o in ("-O", ):
  230.         defaultOutputFilename = 1
  231.       if o in ("-w", "--web"):
  232.         cgimode = 1
  233.       if o in ("-q", "--query"):
  234.         environ['QUERY_STRING'] = a
  235.       if o in ("-l", "--listen"):
  236.         httpmode = 1
  237.       if o in ("-d", "--daemon"):
  238.         daemon = a
  239.       if o in ("-p", "--port"):
  240.         try: httpport = int(a)
  241.         except:
  242.           stdout.write('syntax: port must be integer\n')
  243.           stdout.write('Use -h option for help.\n')
  244.           return -1
  245.       if o in ("--conf", ):
  246.         configFile = a
  247.  
  248.   # web server mode
  249.   if httpmode:
  250.     if len(args):
  251.       httproot = args[0]
  252.     import spyceWWW
  253.     return spyceWWW.spyceHTTPserver(httpport, httproot, config_file=configFile, daemon=daemon)
  254.   # some checks
  255.   if not cgimode and not defaultOutputFilename and len(args)>1:
  256.     stdout.write('syntax: too many files to process\n')
  257.     stdout.write('Use -h option for help.\n')
  258.     return -1
  259.   # file globbing
  260.   if defaultOutputFilename:
  261.     globbed = map(glob.glob, args)
  262.     args = []
  263.     for g in globbed:
  264.       for f in g:
  265.         args.append(f)
  266.   if not len(args):
  267.     if cgimode:
  268.       stdout.write('Content-Type: text/plain\n\n')
  269.     stdout.write('syntax: please specify a spyce file to process\n')
  270.     stdout.write('Use -h option for help.\n')
  271.     return -1
  272.   # run spyce
  273.   result=0
  274.   try:
  275.     while len(args):
  276.       result=0
  277.       script = args[0]
  278.       del args[0]
  279.       if cgimode:
  280.         dir = os.path.dirname(script)
  281.         if dir: 
  282.           script = os.path.basename(script)
  283.           os.chdir(dir)
  284.       try:
  285.         output = stdout
  286.         if defaultOutputFilename:
  287.           outputFilename = os.path.splitext(script)[0]+'.html'
  288.           stdout.write('Processing: %s\n'%script)
  289.           stdout.flush()
  290.         if outputFilename:
  291.           output = None
  292.           output = open(outputFilename, 'w')
  293.         if compileonlyMode:
  294.           s = spyce.getServer().spyce_cache['file', script]
  295.           output.write(s.getCode())
  296.           output.write('\n')
  297.         else:
  298.           request = spyceCmdlineRequest(stdin, environ, script)
  299.           response = spyceCmdlineResponse(output, stderr, cgimode)
  300.           result = spyce.spyceFileHandler(request, response, script)
  301.           response.close()
  302.       except KeyboardInterrupt: raise
  303.       except SystemExit: pass
  304.       except (spyceException.spyceForbidden, spyceException.spyceNotFound), e:
  305.         if cgimode:
  306.           stdout.write('Content-Type: text/plain\n\n')
  307.         stdout.write(str(e)+'\n')
  308.       except:
  309.         if cgimode:
  310.           stdout.write('Content-Type: text/plain\n\n')
  311.         stdout.write(spyceUtil.exceptionString()+'\n')
  312.       if output:
  313.         output.close()
  314.   except KeyboardInterrupt:
  315.     stdout.write('Break!\n')
  316.   return result
  317.  
  318. ABSPATH = 1
  319. if ABSPATH:
  320.   for i in range(len(sys.path)):
  321.     sys.path[i] = os.path.abspath(sys.path[i])
  322.   ABSPATH = 0
  323.  
  324. # Command-line entry point
  325. if __name__=='__main__': 
  326.   os.environ[spyce.SPYCE_ENTRY] = 'cmd'
  327.   try:
  328.     exitcode=0
  329.     exitcode=spyceMain(cgimode=0)
  330.   except: 
  331.     exitcode=1
  332.     traceback.print_exc()
  333.   sys.exit(exitcode)
  334.  
  335.