def run_command(self, **args):
        # Initialize a settings wrapper (because we have so many!)
        self._settings = AdvancedBuilderSettings(self.window, args)
        self._exec = OutputWindowController()
        self._exec.init(self, self._settings.active_task(), jump_to_error = self._settings.jump_to_error())
        self._current_phase = None
        self._quiet = self._settings.quiet()
        self._exec.quiet = self._quiet
        self._stop = False

        # Get the phases
        self._phases = []
        for phase_config in self._settings.build_phases():
            phase = self._get_phase_object(phase_config)
            printcons("Evaluating phase ", phase)
            if(phase is None) or (not phase.is_valid()):
                self._exec.write("Invalid config for phase: %s ([%s]), aborting" % (phase_config.get("name"), str(phase)))
                return

            self._phases.append(phase)

        # Run it this way, to not run into concurrency issues.
        sublime.set_timeout(self._run_tasks, 200)
class AdvancedBuilderCommand(sublime_plugin.WindowCommand):
    """
    The sublime plugin command class.
    """

    PHASE_SOLUTION = "solution"
    PHASE_SOLUTION = "unity_project"
    PHASE_COPY = "copy"
    PHASE_STYLECOP = "stylecop"
    PHASE_COMMAND = "command"
    RUN_ASYNC = True

    def run(self, **args):
        """
        Run the command. This is called by sublime, when a build is executed.
        """
        kill = args.get("kill")
        if(kill is not None) and (kill):
            # Kill the currently running process and get out
            if(hasattr(self, "_exec")) and (self._exec is not None):
                printcons("Killing current task")
                self.cancel_command()
            else:
                printcons("No task to kill")

            return

        if(hasattr(self, "_exec")) and (self._exec is not None):
            # There is a command already running, ask if it should be stopped
            stop = sublime.ok_cancel_dialog("There is already a command being processed, do you want to cancel it?", "Stop")
            if(stop):
                # Stop the old process and continue to use the new one
                self.cancel_command()
            else:
                # Get out, there should only be one build running
                return

        self.run_command(**args)

    def cancel_command(self):
        self._exec.kill()
        self._stop = True
        if(not self._quiet):
            self._exec.write("Killed: %s [%s]" % (self._current_phase, self._settings.active_configuration()))
        self._cleanup_command()

    def run_command(self, **args):
        # Initialize a settings wrapper (because we have so many!)
        self._settings = AdvancedBuilderSettings(self.window, args)
        self._exec = OutputWindowController()
        self._exec.init(self, self._settings.active_task(), jump_to_error = self._settings.jump_to_error())
        self._current_phase = None
        self._quiet = self._settings.quiet()
        self._exec.quiet = self._quiet
        self._stop = False

        # Get the phases
        self._phases = []
        for phase_config in self._settings.build_phases():
            phase = self._get_phase_object(phase_config)
            printcons("Evaluating phase ", phase)
            if(phase is None) or (not phase.is_valid()):
                self._exec.write("Invalid config for phase: %s ([%s]), aborting" % (phase_config.get("name"), str(phase)))
                return

            self._phases.append(phase)

        # Run it this way, to not run into concurrency issues.
        sublime.set_timeout(self._run_tasks, 200)

    def _cleanup_command(self):
        self._exec = None
        self._settings = None
        self._phases = None
        self._current_phase = None

    def _run_tasks(self):
        """
        Run all tasks sequentially.
        """
        if(self._stop):
            # Now it gets funky: If a process was killed, the new one
            # will spawn a new _run_tasks method. That would mean we
            # have two. But because this method does not hold a context
            # by itself, we don't care, which of the two is stopped, it
            # will be the first one to come in here. Care must be taken
            # however on when to clean up the _exec context, which needs
            # to happen when _stop is set to True, so as to not screw up
            # the context of the new process.
            self._stop = False
            return

        if(self._exec.is_running()):
            # Still waiting for the process to finish, wait another 0.1s
            sublime.set_timeout(self._run_tasks, 100)
            return

        if(len(self._phases) < 1):
            # We are done
            self._exec.done()
            self._cleanup_command()
            return;

        if(self._exec.has_errors) and (self._current_phase is not None) and (self._current_phase.stop_on_error):
            # Don't start the next one, this one broke.
            if(not self._quiet):
                self._exec.write("%s [%s] has errors, stopping" % (self._current_phase, self._settings.active_configuration()))
            self._exec.done()
            self._cleanup_command()
            return

        # The last phase finished successfully, start a new one.
        started = False
        while(not started):
            if(len(self._phases) < 1):
                self._exec.done()
                self._cleanup_command()
                return;

            self._current_phase = self._phases[0]
            self._phases = self._phases[1:]

            # Start the next phase and poll for its completion
            started = self._run_new_phase(self._current_phase)

        # Wait for 0.2s before checking again
        sublime.set_timeout(self._run_tasks, 200)

    def _run_new_phase(self, phase):
        if(not (self._settings.build_all() or phase.should_run())):
            # A task, that doesn't apply to the configuration.
            if(not self._quiet):
                self._exec.write("Skipped: %s [%s]" % (phase, self._settings.active_configuration()))
            return False

        task = phase.get_task()
        if(task is None):
            # The task had errors on building its run configuration, get out!
            return False;

        self._exec.write("%s [%s]" % (phase, self._settings.active_configuration()))
        self._exec.run(**task)
        return self._exec.is_running()

    def _get_phase_object(self, phase_config):
        """
        Get a BuildPhase object for the type of the build phase.

        @returns The appropriet, initialized phase for the configured type or None, if none exists.
        """
        # Resolve the type of the phase
        phase_type = phase_config.get("type")
        if(phase_type is None):
            return None

        # Resolve the class of the type
        phase_class = supported_build_phases.get(phase_type)
        if(phase_class is None):
            return None

        phase = phase_class()
        phase.init(self._settings, **phase_config)
        return phase