
import os
import sys
import signal

class OsUtilsException(Exception):
    pass

class ExecutableDoesNotExist(OsUtilsException):
    def __init__(self, cmd):
        OsUtilsException.__init__(self,
          _("The executable '%s' does not exist.") % cmd)

class ExecutableFormatStringException(OsUtilsException):
    def __init__(self):
        OsUtilsException.__init__(self,
          _("The executable string should contain zero or one '%s'."))


__all__ = ['run_external_program',
    'OsUtilsException',
    'ExecutableDoesNotExist',
    'ExecutableFormatStringException'
]
__child_pid = None

def kill_external_program():
    """
    Kill the previous ran program if it is still running.
    Do nothing if there is nothing to kill.
    """
    global __child_pid
    if sys.platform != 'win32':
        if __child_pid:
            try:
                os.kill(__child_pid, signal.SIGKILL)
            except OSError:
                pass
            os.wait()
            __child_pid = None

def run_external_program(cmdstring, wdir, argument):
    global __child_pid
    if not cmdstring:
        raise ExecutableDoesNotExist(cmdstring)
    if "%s" not in cmdstring:
        cmdline = "%s %s" % (cmdstring, argument)
    else:
        try:
            cmdline = cmdstring % argument
        except TypeError:
            raise ExecutableFormatStringException()
    wdir = os.path.normpath(wdir)
    cur_dir = os.getcwdu()
    v = cmdline.split()
    v = v[:1] + v
    if not os.path.exists(os.path.join(wdir, v[0])):
        raise ExecutableDoesNotExist(v[0])
        return
    if sys.platform == 'win32':
        os.system(cmdline)
        return
    kill_external_program()
    pid = os.fork()
    if pid == 0:
        os.chdir(wdir)
        try:
            os.execlp(*v)
        except OSError, x:
            print >> sys.stderr, "OS Error:", x
            os._exit(-1)
            os.chdir(cur_dir)
        os.chdir(cur_dir)
    else:
        __child_pid = pid


