#!/usr/bin/python

#if 0 /*
# -----------------------------------------------------------------------
# freevo - the main entry point to the whole suite of applications
# -----------------------------------------------------------------------
# $Id: freevo 8261 2006-09-29 12:20:17Z duncan $
#
# Notes: This is a rewrite of the old shell script in Python
# Todo:
#
# -----------------------------------------------------------------------
# $Log$
# Revision 1.113  2004/06/08 19:34:12  dischi
# fix bad freevo_script for installed version
#
# Revision 1.112  2004/06/08 19:11:56  dischi
# support direct start without execute
#
# Revision 1.111  2004/04/12 05:34:14  dischi
# extend PATH and set HOME and USER
#
# Revision 1.110  2004/02/10 00:17:52  rshortt
# Use env from /usr/bin rather than /bin.  I beleive it is standard in /usr/bin,
# looking in /bin breaks Debian and others while it is available in both places
# (so I have been told) in RedHat and Gentoo.
#
# Also standardize the naming of pid files.
#
# Revision 1.109  2004/02/06 18:01:21  dischi
# fix bug with helper softlinks
#
# Revision 1.108  2004/01/26 19:33:17  dischi
# python 2.2 has no True/False
#
# Revision 1.107  2004/01/10 20:45:50  mikeruelle
# can not start freevo -fs without this change
#
# Revision 1.106  2004/01/10 18:24:17  dischi
# fix uid storage for execute and runapp calls
#
# Revision 1.105  2004/01/10 16:53:48  dischi
# better shutdown
#
# Revision 1.104  2004/01/10 14:56:19  dischi
# better KeyboardInterrupt handling
#
# Revision 1.103  2004/01/09 20:18:31  dischi
# check if programm is still running
#
# Revision 1.102  2004/01/09 18:55:53  dischi
# helper stop fixes
#
# Revision 1.101  2004/01/07 21:59:10  dischi
# replace the shell script with a nice python version
#
#
# -----------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2003 Krister Lagerstrom, et al.
# Please see the file freevo/Docs/CREDITS for a complete list of authors.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# ----------------------------------------------------------------------- */
#endif


import os
import sys
import popen2

from signal import *


def show_help():
    """
    show how to use this script
    """
    helper_list = ''
    for helper in os.listdir(os.environ['FREEVO_HELPERS']):
        if helper.endswith('.py') and not helper == '__init__.py':
            helper_list += '  ' + helper[:-3] + '\n'

    print '''\
freevo [ script | options]
options:
  -fs            start freevo in a new x session in fullscreen
  -doc           create api documentation (for developers)
  -trace         activate full trace (usefull for debugging)
  setup          run freevo setup to scan your environment
  start          start freevo as daemon in background
  stop           stop the current freevo process

freevo can start the following scripts, use --help on these
scripts to get more informations about options.

%s

Example: freevo imdb --help"
         freevo webserver start"

You can also create a symbolic link to freevo with the name of the
script you want to execute. E.g. put a link imdb pointing to freevo
in your path to access the imdb helper script

Example: ln -s path-to-freevo imdb
         imdb --help

Before running freevo the first time, you need to run \'freevo setup\'
After that, you can run freevo without parameter.
    ''' % helper_list
    sys.exit(0)



def get_python(check_freevo):
    """
    get the newest version of python [ with freevo installed ]
    """
    if float(sys.version[0:3]) >= 2.3:
        # python seems to be ok
        search = ('python', 'python2')
    elif float(sys.version[0:3]) >= 2.2:
        # try python2.3, else take python
        search = ('python2.3', 'python')
    else:
        # python is too old, try to find python2.3 or python2
        search = ('python2.3', 'python2')

    for python in search:
        for path in os.environ['PATH'].split(':'):
            if os.path.isfile(os.path.join(path, python)):
                # we found the binary for python
                if not check_freevo:
                    # return if we don't check for an installed version
                    # of freevo
                    return python

                # try to import freevo with this python and get
                # the path
                cmd = '%s -c "import freevo; print freevo.__path__[0]"' % python
                child = popen2.Popen4(cmd)
                while 1:
                    data = child.fromchild.readline()
                    if not data:
                        break
                    if os.path.isdir(data[:-1]):
                        # ok, found it, close child and return
                        child.wait()
                        child.fromchild.close()
                        if child.childerr:
                            child.childerr.close()
                        child.tochild.close()
                        return python, data[:-1]

                child.wait()
                child.fromchild.close()
                if child.childerr:
                    child.childerr.close()
                child.tochild.close()

    # nothing found? That's bad!
    if check_freevo:
        return None, None
    return None


                
def getpid(name, arg):
    """
    get pid of running 'name'
    """
    for fname in ('/var/run/' + name  + '-%s.pid' % os.getuid(), 
                  '/tmp/' + name + '-%s.pid' % os.getuid()):
        if os.path.isfile(fname):
            f = open(fname)
            try:
                pid = int(f.readline()[:-1])
            except ValueError:
                # file does not contain a number
                return fname, 0
            f.close()

            proc = '/proc/' + str(pid) + '/cmdline'
            # FIXME: BSD support missing here
            try:
                if os.path.isfile(proc):
                    f = open(proc)
                    proc_arg = f.readline().split('\0')[:-1]
                    f.close()
                else:
                    # process not running
                    return fname, 0

            except (OSError, IOError):
                # running, but not freevo (because not mine)
                return fname, 0

            if '-OO' in proc_arg:
                proc_arg.remove('-OO')
                
            if proc_arg and ((arg[0].find('runapp') == -1 and \
                              len(proc_arg)>2 and arg[1] != proc_arg[1]) or \
                             len(proc_arg)>3 and arg[2] != proc_arg[2]):
                # different proc I guess
                try:
                    os.unlink(fname)
                except OSError:
                    pass
                return fname, 0
            return fname, pid
    return fname, 0


def stop(name, arg):
    """
    stop running process 'name'
    """
    fname, pid = getpid(name, arg)
    if not pid:
        return 0
    try:
        try:
            os.unlink(fname)
        except OSError:
            pass
        os.kill(pid, SIGTERM)
        return 1
    except OSError:
        return 0



def start(name, arg, bg, store=1):
    """
    start a process
    """
    pid = os.fork()
    if pid:
        if store:
            try:
                f = open('/var/run/' + name + '-%s.pid' % os.getuid(), 'w')
            except (OSError, IOError):
                f = open('/tmp/' + name + '-%s.pid' % os.getuid(), 'w')

            f.write(str(pid)+'\n')
            f.close()

        if not bg:
            try:
                os.waitpid(pid, 0)
            except KeyboardInterrupt:
                os.kill(pid, SIGTERM)
                try:
                    os.waitpid(pid, 0)
                except KeyboardInterrupt:
                    pass
                if store and os.path.isfile(f.name):
                    os.unlink(f.name)
    else:
        os.execvp(arg[0], arg)


freevo_script = os.path.abspath(sys.argv[0])
if os.path.islink(freevo_script):
    freevo_script = os.readlink(freevo_script)

if os.path.isdir(os.path.join(os.path.dirname(freevo_script), 'src/plugins')):
    #
    # we start freevo from a directory
    #
    dname = os.path.dirname(freevo_script)
    freevo_python  = os.path.join(dname, 'src')
    freevo_helpers = os.path.join(dname, 'src/helpers')
    freevo_locale  = os.path.join(dname, 'i18n')
    freevo_share   = os.path.join(dname, 'share')
    freevo_contrib = os.path.join(dname, 'contrib')
    freevo_config  = os.path.join(dname, 'freevo_config.py')

    if os.path.isfile(os.path.join(dname, 'runtime/runapp')):
        #
        # there is a runtime, use it
        #
        runapp = os.path.join(dname, './runtime/runapp')
        python = [ runapp, os.path.join(dname, './runtime/apps/freevo_python') ]
        preload = ''
        f = open(os.path.join(dname, './runtime/preloads'))
        for lib in f.readline()[:-1].split(' '):
            preload += os.path.join(dname, lib) + ':'
        if preload:
            preload = preload[:-1]
        os.environ['FREEVO_PRELOADS'] = preload
        # FIXME: use FREEVO_PRELOADS in runapp to avoid chdirs

    else:
        #
        # no runtime, get best python version
        #
        python = get_python(0)
        if not python:
            print 'can\'t find python >= 2.2'
            sys.exit(0)
        python = [ python ]
        runapp = ''
else:
    #
    # installed version of freevo, get best python + freevo path
    #
    if not os.path.isfile(freevo_script):
        for path in os.environ['PATH'].split(':'):
            if os.path.isfile(os.path.join(path, freevo_script)):
                freevo_script = os.path.join(path, freevo_script)
    python, freevo_python = get_python(1)
    if not python:
        print 'can\'t find python version with installed freevo'
        sys.exit(0)
    freevo_helpers = os.path.join(freevo_python, 'helpers')
    dname = os.path.abspath(os.path.join(os.path.dirname(freevo_script), '../'))
    freevo_locale  = os.path.join(dname, 'share/locale')
    freevo_share   = os.path.join(dname, 'share/freevo')
    freevo_contrib = os.path.join(freevo_share, 'contrib')
    freevo_config  = os.path.join(freevo_share, 'freevo_config.py')
    runapp         = ''
    python = [ python ]



# add the variables from above into environ so Freevo can use them, too
for var in ('freevo_script', 'runapp', 'freevo_python', 'freevo_locale',
            'freevo_share', 'freevo_contrib', 'freevo_config', 'freevo_helpers'):
    os.environ[var.upper()] = eval(var)

# extend PYTHONPATH to freevo
if os.environ.has_key('PYTHONPATH'):
    os.environ['PYTHONPATH'] = '%s:%s' % (freevo_python, os.environ['PYTHONPATH'])
else:
    os.environ['PYTHONPATH'] = freevo_python

# extend PATH to make sure the basics are there
os.environ['PATH'] = '%s:/usr/bin:/bin:/usr/local/bin:' % os.environ['PATH'] + \
                     '/usr/X11R6/bin/:/sbin:/usr/sbin'

# set basic env variables
if not os.environ.has_key('HOME') or not os.environ['HOME']:
    os.environ['HOME'] = '/root'
if not os.environ.has_key('USER') or not os.environ['USER']:
    os.environ['USER'] = 'root'

# now check what and how we should start freevo
bg    = 0 # start in background
proc  = [ os.path.abspath(os.path.join(freevo_python, 'main.py')) ]
name  = os.path.splitext(os.path.basename(os.path.abspath(sys.argv[0])))[0]
check = 1 # check running instance

if len(sys.argv) > 1:
    arg = sys.argv[1]
else:
    arg = ''


# check the arg

if arg in ('--help', '-h'):
    # show help
    show_help()

    
if arg == 'stop':
    # stop running freevo
    if not stop(name, python + proc):
        print 'freevo not running'
    sys.exit(0)
    
elif arg == 'start':
    # start freevo in background
    sys.argv = [ sys.argv[0] ]
    bg = 1


elif arg == '-fs':
    # start X server and run freevo, ignore everything else for now
    server_num = 0
    while 1:
        if not os.path.exists('/tmp/.X11-unix/X' + str(server_num)):
            break
        server_num += 1
    sys.stdin.close()
    os.execvp('xinit', [ 'xinit', freevo_script, '-force-fs',  '--', ':'+str(server_num) ])

    
elif arg == 'execute':
    # execute a python script
    proc  = sys.argv[2:]
    check = 0

elif arg == 'setup':
    # run setup
    proc = [ os.path.join(freevo_python, 'setup_freevo.py') ] + sys.argv[2:]


elif arg == 'prompt':
    # only run python inside the freevo env
    proc = []


elif arg == 'runapp':
    # Oops, runapp. We don't start python, we start sys.argv[1]
    # with the rest as args
    python[-1] = sys.argv[2]
    proc       = sys.argv[3:]
    check      = 0

elif arg and name == 'freevo' and not arg.startswith('-'):
    # start a helper. arg is the name of the script in
    # the helpers directory
    name     = arg
    proc     = [ os.path.join(freevo_python, 'helpers', name + '.py') ]
    if len(sys.argv) > 2:
        if sys.argv[2] == 'stop':
            if not stop(name, python + proc):
                print '%s not running' % name
            sys.exit(0)
        if sys.argv[2] == 'start':
            bg = 1
            sys.argv = [ sys.argv[0] ]
        else:
            sys.argv = [ sys.argv[0] ] + sys.argv[2:]


elif arg and name == 'freevo' and not (arg in ['-force-fs', '-trace', '-doc']):
    # ok, don't know about that arg, freevo should be started, but
    # it's also no freevo arg
    print 'unknown command line option: %s' % sys.argv[1:]
    print
    show_help()


else:
    # arg for freevo
    proc += sys.argv[1:]
    

if name != 'freevo':
    proc = [ os.path.join(freevo_python, 'helpers', name + '.py') ] +  sys.argv[1:]
    if not os.path.isfile(proc[0]):
        if os.path.isfile(name):
            name = os.path.splitext(os.path.basename(name))[0]
            proc = proc[1:]
        else:
            proc = [ os.path.join(freevo_python, 'helpers', name + '.py') ] +  sys.argv[1:]
            print 'can\'t find helper %s' % name
            sys.exit(1)

if getpid(name, python + proc)[1] and check:
    if name != 'freevo':
        print '%s still running, run \'freevo %s stop\' to stop' % (name, name)
    else:
        print 'freevo still running, run \'freevo stop\' to stop'
    sys.exit(0)

start(name, python + proc , bg, check)
