Python Subprocess:用subprocess.Popen复制Tee并执行并行执行?

时间:2014-10-29 01:57:27

标签: python arduino pipe subprocess

我正在尝试编写一个python脚本,通过Arduino的命令行界面将相同的hex文件并行编译并上传到多个微控制器。

我的脚本执行以下操作:

  1. 将ino文件编译为特定目录中的hex文件。例如,
  2. 将十六进制上传到所有/dev/tty.usbXXXXXX。
  3. 这些是要求:

    • 我必须能够并行上传到多个/dev/tty.usb*。
    • 我想从我的所有subprocess.Popen打印所有stdout和stderr到DEVICE - STDOUT / STDERR - MSG作为格式的主屏幕
    • 我想将每个Popen中的stdout和stderr保存到自己的tty.usb *日志文件中。

    现在我有:

    import errno
    import os
    import re
    import subprocess
    
    ARDUINO_EXECUTABLE = '/Applications/Arduino.app/Contents/MacOS/JavaApplicationStub'
    HEX_FOLDER_DIR = '/tmp/oyoroi'
    LOG_FOLDER_DIR = './logs'
    
    
    def get_devices():
      """Returns a list of tty.usbXXXXXX
      Make sure you use the USB hub. This will force an extra character in the /dev/tty.usbXXXXXX
      """
      ret = []
      for device in os.listdir('/dev'):
        if re.match('tty.usbmodem[0-9]{6}', device):
          ret.append(device)
      return ret
    
    
    class Wrapper(object):
      """Wrapper for file objects
      """
      def __init__(self, name, fobject):
        self.name = name
        self.fobject = fobject
    
      def fileno(self):
        return self.fobject.fileno()
    
      def flush(self):
        self.fobject.flush()
    
      def write(self, a_str):
        print self.name, a_str
        self.fobject.write(a_str)
    
    
    def main(fname):
      """Build once, but upload in parallel
      """
      try:
        os.makedirs(HEX_FOLDER_DIR)
      except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(HEX_FOLDER_DIR):
          pass
    
      fname = os.path.abspath(fname)
    
      # Builds the hex
      command = "%s --verify --pref build.path=%s %s" % (ARDUINO_EXECUTABLE, HEX_FOLDER_DIR, fname)
      print "(Build Command)", command
      proc = subprocess.call(command, shell=True)
    
      # Make the log directory
      try:
        os.makedirs(LOG_FOLDER_DIR)
      except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(LOG_FOLDER_DIR):
          # delete folder
          import shutil
          shutil.rmtree(LOG_FOLDER_DIR)
          # and recreate again
          os.makedirs(LOG_FOLDER_DIR)
    
      # Upload in parallel
      devices = get_devices()
      processes = []
    
      for device in devices:
        device_path = '/dev/' + device
        log_file_path = os.path.join(LOG_FOLDER_DIR, device + '.log')
        with open(log_file_path, 'a') as logfile:
          command = "%s --upload --pref build.path=%s --port %s %s" % \
                    (ARDUINO_EXECUTABLE, HEX_FOLDER_DIR, device_path, fname)
          print "(Upload Command)", command
    
          wstdout = Wrapper('%_STDOUT', logfile)
          wstderr = Wrapper('%_STDERR', logfile)
          proc = subprocess.Popen(command, shell=True, stdout=wstdout, stderr=wstderr)
          processes.append(proc)
    
    
    if __name__ == "__main__":
      import sys
      if len(sys.argv) != 2:
        print "python upload.py <.ino>"
        exit(1)
      main(sys.argv[1])
    

    我能够在每个日志文件中得到我想要的内容,但我的终端没有在屏幕上打印任何内容。它也在其他过程完成之前结束。

    我错过了什么?

1 个答案:

答案 0 :(得分:0)

main()的末尾添加如下代码:

for proc in processes:
    proc.wait()

现在,您还没有等待,所以Python会在所有进程启动后立即退出。

对于记录,我不完全确定传递Wrapper个对象而不是真正的文件对象是多么有用。 Python很可能只是调用.fileno()然后直接将子进程附加到该文件描述符。你的.write()方法可能没有被调用。如果您需要调用它,则应使用subprocess.PIPEPopen.communicate()代替Wrapper个对象和Popen.wait()。然后,您可以以任何您认为合适的方式使用communicate()的返回值(即打印它)。