Runs a given command on the system within a set time period, providing an easy way to access
        command output as it happens without waiting for the command to finish running.

        :type list
        :param command: Should be a list that contains the command that should be ran on the given
                        system. The only whitespaces that can occur is for paths that use a backslash
                        to escape it appropriately

        :type int
        :param timeout: Specificed in seconds. If a command outruns the timeout then the command and
                        its child processes will be terminated. The default is to run

        :type string
        :param cwd: If cwd is set then the current directory will be changed to cwd before it is executed.
                    Note that this directory is not considered when searching the executable, so you
                    can’t specify the program’s path relative to cwd.

        :type dict
        :param env: A dict of any ENV variables that should be combined into the OS ENV that will help
                    the command to run successfully. Note that more often than not the command run
                    does not have the same ENV variables available as your shell by default and as such
                    require some assistance.

        :type function
        :param debug: A function (also a class function) can be passed in here and all output, line by line,
                      from the command being run will be passed to it as it gets outputted to stdout.
                      This allows for things such as logging (using the built in python logging lib)
                      what is happening on long running commands or redirect output of a tail -f call
                      as lines get outputted without having to wait till the command finishes.

        :return returns :class:`Command.Response` that contains the exit code and the output from the command

def run(cls, command, timeout=None, cwd=None, env=None, debug=None):
        """
        Runs a given command on the system within a set time period, providing an easy way to access
        command output as it happens without waiting for the command to finish running.

        :type list
        :param command: Should be a list that contains the command that should be ran on the given
                        system. The only whitespaces that can occur is for paths that use a backslash
                        to escape it appropriately

        :type int
        :param timeout: Specificed in seconds. If a command outruns the timeout then the command and
                        its child processes will be terminated. The default is to run

        :type string
        :param cwd: If cwd is set then the current directory will be changed to cwd before it is executed.
                    Note that this directory is not considered when searching the executable, so you
                    can’t specify the program’s path relative to cwd.

        :type dict
        :param env: A dict of any ENV variables that should be combined into the OS ENV that will help
                    the command to run successfully. Note that more often than not the command run
                    does not have the same ENV variables available as your shell by default and as such
                    require some assistance.

        :type function
        :param debug: A function (also a class function) can be passed in here and all output, line by line,
                      from the command being run will be passed to it as it gets outputted to stdout.
                      This allows for things such as logging (using the built in python logging lib)
                      what is happening on long running commands or redirect output of a tail -f call
                      as lines get outputted without having to wait till the command finishes.

        :return returns :class:`Command.Response` that contains the exit code and the output from the command
        """

        # Merge together the system ENV details and the passed in ones if any
        environ = dict(os.environ)
        environ.update(env or {})

        # If string is passed in for the command then attempt to split it up
        if isinstance(command, str):
            command = shlex.split(command)

        # Check if the executable is executable and in fact exists
        which(command[0], environ)

        # Use tempfile to get past a limitation with subprocess.PIPE and 64kb.
        # Also to have a file to plug into the track generator
        outputtmp = tempfile.NamedTemporaryFile()

        try:
            # Verify debug is in fact a function we can call
            debug_output = False
            if debug and (callable(debug) or hasattr(debug, "__call__")):
                debug_output = True

            if debug_output:
                def track(thefile, shutdown=None):
                    """Process the temp file until a valid line is found and return it"""
                    thefile.seek(0, 2)
                    while True:
                        if shutdown and shutdown.isSet():
                            break

                        line = thefile.readline()
                        if not line:
                            time.sleep(0.00001)
                            continue
                        yield line

                def track_run(output, debug, shutdown_event):
                    """Wrap track and pass information on the fly to the debug process"""
                    for line in track(output, shutdown_event):
                        debug(line.rstrip())

                # Run the track generator in a separate thread so we can run the command
                shutdown_event = threading.Event()
                thread = threading.Thread(
                    target=track_run,
                    args=(open(outputtmp.name, 'rb'), debug, shutdown_event),
                    name='Monitoring'
                )
                thread.start()

            def target():
                # Run the actual command
                cls.process = subprocess.Popen(
                    command,
                    universal_newlines=True,
                    shell=False,
                    env=environ,
                    cwd=cwd,
                    preexec_fn=os.setsid,
                    stdout=outputtmp,
                    stderr=outputtmp
                )

                cls.process.communicate()

            # Deal with timeout
            thread = threading.Thread(target=target, name='Command Runner')
            thread.start()
            thread.join(timeout)

            if thread.is_alive():
                cls.process.terminate()
                thread.join()
                if thread.is_alive():
                    cls.process.kill()

            # Prime the response
            response = Response
            response.command = command
            response.exit = cls.process.returncode

            # Fetch from the temp file
            outputtmp.seek(0, 0)
            response.output = outputtmp.read().strip()
            outputtmp.close()

            if response.exit < 0:
                raise CommandException("command ('%s') was terminated by signal: %s"
                                       % (' '.join(command), -response.exit),
                                       response.exit,
                                       response.output)
            if response.exit > 0:
                raise CommandException("command ('%s') exited with value: %s\n\n%s"
                                       % (' '.join(command), str(response.exit), response.output),
                                       response.exit,
                                       response.output)

            return response
        except OSError as error:
            # Use fake exit code since we can't get the accurate one from this
            raise CommandException("command failed: %s" % error, 1, error)
        except subprocess.CalledProcessError as error:
            raise CommandException(error.output, error.returncode, error.output)
        finally:
            if debug_output:
                shutdown_event.set()