import os
import json
import threading
import subprocess

import sublime


class ExecFlowCommand(threading.Thread):
    """Threaded class used for running flow commands in a different thread.

    The subprocess must be threaded so we don't lockup the UI.
    """

    def __init__(self, cmd, content):
        """Initialize with the command and the file content to send."""
        self.cmd = cmd
        self.content = content
        self.stdout = None
        self.returncode = 0
        self.stderr = None

        threading.Thread.__init__(self)

    def run(self):
        """Execute the command in a subprocess."""
        read, write = os.pipe()
        os.write(write, str.encode(self.content))
        os.close(write)

        try:
            output = subprocess.check_output(
                self.cmd,
                shell=sublime.platform() == 'windows',
                stdin=read,
                stderr=subprocess.STDOUT
            )

            if type(output) is bytes:
                output = output.decode('utf-8')

            try:
                self.stdout = json.loads(output)
            except ValueError:
                self.stdout = output

            os.close(read)
        except subprocess.CalledProcessError as err:
            self.stderr = str(err)
            self.returncode = 1

import os
import json
import threading
import subprocess

import sublime


class ExecFlowCommand(threading.Thread):
    """Threaded class used for running flow commands in a different thread.

    The subprocess must be threaded so we don't lockup the UI.
    """

    def __init__(self, cmd, content):
        """Initialize with the command and the file content to send."""
        self.cmd = cmd
        self.content = content
        self.stdout = None
        self.returncode = 0
        self.stderr = None

        threading.Thread.__init__(self)

    def run(self):
        """Execute the command in a subprocess."""
        read, write = os.pipe()
        os.write(write, str.encode(self.content))
        os.close(write)

        try:
            output = subprocess.check_output(
                self.cmd,
                shell=sublime.platform() == 'windows',
                stdin=read,
                stderr=subprocess.STDOUT
            )

            if type(output) is bytes:
                output = output.decode('utf-8')

            try:
                self.stdout = json.loads(output)
            except ValueError:
                self.stdout = output

            os.close(read)
        except subprocess.CalledProcessError as err:
            if type(err.output) is bytes:
                output = err.output.decode('utf-8')
            else:
                output = err.output
            self.stderr = str(err) + ': ' + str(output)
            self.returncode = 1

Add error output to exec error messages
Add error output to exec error messages

e.g. for an error like "env: ‘node’: No such file or directory"
the sublime console was only reporting "exited with code 127"
which wasn't very helpful in determining the cause.

  import os
  import json
  import threading
  import subprocess
  
  import sublime
  
  
  class ExecFlowCommand(threading.Thread):
      """Threaded class used for running flow commands in a different thread.
  
      The subprocess must be threaded so we don't lockup the UI.
      """
  
      def __init__(self, cmd, content):
          """Initialize with the command and the file content to send."""
          self.cmd = cmd
          self.content = content
          self.stdout = None
          self.returncode = 0
          self.stderr = None
  
          threading.Thread.__init__(self)
  
      def run(self):
          """Execute the command in a subprocess."""
          read, write = os.pipe()
          os.write(write, str.encode(self.content))
          os.close(write)
  
          try:
              output = subprocess.check_output(
                  self.cmd,
                  shell=sublime.platform() == 'windows',
                  stdin=read,
                  stderr=subprocess.STDOUT
              )
  
              if type(output) is bytes:
                  output = output.decode('utf-8')
  
              try:
                  self.stdout = json.loads(output)
              except ValueError:
                  self.stdout = output
  
              os.close(read)
          except subprocess.CalledProcessError as err:
+             if type(err.output) is bytes:
+                 output = err.output.decode('utf-8')
+             else:
+                 output = err.output
-             self.stderr = str(err)
+             self.stderr = str(err) + ': ' + str(output)
              self.returncode = 1
  
Add error output to exec error messages
## Code Before:
import os
import json
import threading
import subprocess

import sublime


class ExecFlowCommand(threading.Thread):
    """Threaded class used for running flow commands in a different thread.

    The subprocess must be threaded so we don't lockup the UI.
    """

    def __init__(self, cmd, content):
        """Initialize with the command and the file content to send."""
        self.cmd = cmd
        self.content = content
        self.stdout = None
        self.returncode = 0
        self.stderr = None

        threading.Thread.__init__(self)

    def run(self):
        """Execute the command in a subprocess."""
        read, write = os.pipe()
        os.write(write, str.encode(self.content))
        os.close(write)

        try:
            output = subprocess.check_output(
                self.cmd,
                shell=sublime.platform() == 'windows',
                stdin=read,
                stderr=subprocess.STDOUT
            )

            if type(output) is bytes:
                output = output.decode('utf-8')

            try:
                self.stdout = json.loads(output)
            except ValueError:
                self.stdout = output

            os.close(read)
        except subprocess.CalledProcessError as err:
            self.stderr = str(err)
            self.returncode = 1

## Instruction:
Add error output to exec error messages
## Code After:
import os
import json
import threading
import subprocess

import sublime


class ExecFlowCommand(threading.Thread):
    """Threaded class used for running flow commands in a different thread.

    The subprocess must be threaded so we don't lockup the UI.
    """

    def __init__(self, cmd, content):
        """Initialize with the command and the file content to send."""
        self.cmd = cmd
        self.content = content
        self.stdout = None
        self.returncode = 0
        self.stderr = None

        threading.Thread.__init__(self)

    def run(self):
        """Execute the command in a subprocess."""
        read, write = os.pipe()
        os.write(write, str.encode(self.content))
        os.close(write)

        try:
            output = subprocess.check_output(
                self.cmd,
                shell=sublime.platform() == 'windows',
                stdin=read,
                stderr=subprocess.STDOUT
            )

            if type(output) is bytes:
                output = output.decode('utf-8')

            try:
                self.stdout = json.loads(output)
            except ValueError:
                self.stdout = output

            os.close(read)
        except subprocess.CalledProcessError as err:
            if type(err.output) is bytes:
                output = err.output.decode('utf-8')
            else:
                output = err.output
            self.stderr = str(err) + ': ' + str(output)
            self.returncode = 1
