Execute a program and logs standard output into a file.

        :param return_output:      returns the STDOUT value if True or returns the return code
        :param logfile:            path where log file should be written ( displayed on STDOUT if not set)
        :param error_logfile:      path where error log file should be written ( displayed on STDERR if not set)
        :param timeout:            if set, it will kill the subprocess created when "timeout" seconds is reached. It will then raise an Exception.
        :param line_function:      set it to a "function pointer" for the function to be called each time a new line is written (line passed as a parameter).
        :param poll_timing:        wait time between timeout checks and std output check.

        :returns:   Standard output of the command or if return_output=False, it will give the "return code" of the command

def execute(command, return_output=True, log_file=None, log_settings=None, error_logfile=None, timeout=None, line_function=None, poll_timing = 0.01, logger=None, working_folder=None, env=None):
    """
        Execute a program and logs standard output into a file.

        :param return_output:      returns the STDOUT value if True or returns the return code
        :param logfile:            path where log file should be written ( displayed on STDOUT if not set)
        :param error_logfile:      path where error log file should be written ( displayed on STDERR if not set)
        :param timeout:            if set, it will kill the subprocess created when "timeout" seconds is reached. It will then raise an Exception.
        :param line_function:      set it to a "function pointer" for the function to be called each time a new line is written (line passed as a parameter).
        :param poll_timing:        wait time between timeout checks and std output check.

        :returns:   Standard output of the command or if return_output=False, it will give the "return code" of the command
    """

    tmp_log = False
    if log_settings:
        log_folder = log_settings.get('LOG_FOLDER')
    else:
        tmp_log = True
        log_folder = tempfile.mkdtemp()

    if not log_file:
        log_file = os.path.join(log_folder, "commands", "execute-command-logfile-%s.log" % UUID.uuid4())
        try:
            if not os.path.isdir(os.path.join(log_folder, "commands")):
                os.makedirs(os.path.join(log_folder, "commands"))
        except:
            pass
    if not logger:
        logger = logging.getLogger('command_execute')

    logfile_writer = open(log_file, 'a')
    header = "%s - Executing command (timeout=%s) :\n\t%s\n\n\n" % (datetime.now().isoformat(), timeout, command)
    logfile_writer.write(header)
    logfile_writer.flush()

    logfile_reader = open(log_file, 'rb')
    logfile_reader.seek(0, os.SEEK_END)
    logfile_start_position = logfile_reader.tell()

    if error_logfile:
        err_logfile_writer = open(error_logfile, 'a')
    else:
        err_logfile_writer = logfile_writer

    start = datetime.now()
    timeout_string = ""
    if timeout:
        timeout_string = "(timeout=%s)" % timeout
    logger.info(u"Executing command %s :\n\t\t%s" % (timeout_string, command) )

    # We use "exec <command>" as Popen launches a shell, that runs the command.
    # It will transform the child process "sh" into the "command exectable" because of the "exec".
    # Said more accuratly, it won't fork to create launch the command in a sub sub process.
    # Therefore, when you kill the child process, you kill the "command" process and not the unecessary "sh" parent process.
    if sys.platform != 'win32':
        command = u"exec %s" % text_utils.uni(command)
    process = subprocess.Popen(command, stdout=logfile_writer, stderr=err_logfile_writer, bufsize=1, shell=True, cwd=working_folder, env=env)

    while process.poll() == None:
        # In order to avoid unecessary cpu usage, we wait for "poll_timing" seconds ( default: 0.1 sec )
        time.sleep(poll_timing)

        # Timeout check
        if timeout != None:
            now = datetime.now()
            if (now - start).seconds> timeout:
                #process.terminate() ??
                os.kill(process.pid, signal.SIGKILL)
                os.waitpid(-1, os.WNOHANG)
                raise Exception("Command execution timed out (took more than %s seconds...)" % timeout)

        # Line function call:
        #   => if line_function is defined, we call it on each new line of the file.
        if line_function:
            o = text_utils.uni(logfile_reader.readline()).rstrip()
            while o != '':
                line_function(o)
                o = text_utils.uni(logfile_reader.readline()).rstrip()

    if not return_output:
        # Return result code and ensure we have waited for the end of sub process
        return process.wait()

    logfile_reader.seek(logfile_start_position, os.SEEK_SET) #back to the beginning of the file

    res = text_utils.uni(logfile_reader.read())

    try:
        logfile_reader.close()
        logfile_writer.close()
        err_logfile_writer.close()

        if tmp_log:
            shutil.rmtree(log_folder, ignore_errors=True)
    except:
        logger.exception("Error while cleaning after tbx.execute() call.")

    return res