python (3.11.7)
       1  """distutils.spawn
       2  
       3  Provides the 'spawn()' function, a front-end to various platform-
       4  specific functions for launching another program in a sub-process.
       5  Also provides the 'find_executable()' to search the path for a given
       6  executable name.
       7  """
       8  
       9  import sys
      10  import os
      11  import subprocess
      12  
      13  from distutils.errors import DistutilsExecError
      14  from distutils.debug import DEBUG
      15  from distutils import log
      16  
      17  
      18  def spawn(cmd, search_path=1, verbose=0, dry_run=0, env=None):  # noqa: C901
      19      """Run another program, specified as a command list 'cmd', in a new process.
      20  
      21      'cmd' is just the argument list for the new process, ie.
      22      cmd[0] is the program to run and cmd[1:] are the rest of its arguments.
      23      There is no way to run a program with a name different from that of its
      24      executable.
      25  
      26      If 'search_path' is true (the default), the system's executable
      27      search path will be used to find the program; otherwise, cmd[0]
      28      must be the exact path to the executable.  If 'dry_run' is true,
      29      the command will not actually be run.
      30  
      31      Raise DistutilsExecError if running the program fails in any way; just
      32      return on success.
      33      """
      34      # cmd is documented as a list, but just in case some code passes a tuple
      35      # in, protect our %-formatting code against horrible death
      36      cmd = list(cmd)
      37  
      38      log.info(subprocess.list2cmdline(cmd))
      39      if dry_run:
      40          return
      41  
      42      if search_path:
      43          executable = find_executable(cmd[0])
      44          if executable is not None:
      45              cmd[0] = executable
      46  
      47      env = env if env is not None else dict(os.environ)
      48  
      49      if sys.platform == 'darwin':
      50          from distutils.util import MACOSX_VERSION_VAR, get_macosx_target_ver
      51  
      52          macosx_target_ver = get_macosx_target_ver()
      53          if macosx_target_ver:
      54              env[MACOSX_VERSION_VAR] = macosx_target_ver
      55  
      56      try:
      57          proc = subprocess.Popen(cmd, env=env)
      58          proc.wait()
      59          exitcode = proc.returncode
      60      except OSError as exc:
      61          if not DEBUG:
      62              cmd = cmd[0]
      63          raise DistutilsExecError(
      64              "command {!r} failed: {}".format(cmd, exc.args[-1])
      65          ) from exc
      66  
      67      if exitcode:
      68          if not DEBUG:
      69              cmd = cmd[0]
      70          raise DistutilsExecError(
      71              "command {!r} failed with exit code {}".format(cmd, exitcode)
      72          )
      73  
      74  
      75  def find_executable(executable, path=None):
      76      """Tries to find 'executable' in the directories listed in 'path'.
      77  
      78      A string listing directories separated by 'os.pathsep'; defaults to
      79      os.environ['PATH'].  Returns the complete filename or None if not found.
      80      """
      81      _, ext = os.path.splitext(executable)
      82      if (sys.platform == 'win32') and (ext != '.exe'):
      83          executable = executable + '.exe'
      84  
      85      if os.path.isfile(executable):
      86          return executable
      87  
      88      if path is None:
      89          path = os.environ.get('PATH', None)
      90          if path is None:
      91              try:
      92                  path = os.confstr("CS_PATH")
      93              except (AttributeError, ValueError):
      94                  # os.confstr() or CS_PATH is not available
      95                  path = os.defpath
      96          # bpo-35755: Don't use os.defpath if the PATH environment variable is
      97          # set to an empty string
      98  
      99      # PATH='' doesn't match, whereas PATH=':' looks in the current directory
     100      if not path:
     101          return None
     102  
     103      paths = path.split(os.pathsep)
     104      for p in paths:
     105          f = os.path.join(p, executable)
     106          if os.path.isfile(f):
     107              # the file exists, we have a shot at spawn working
     108              return f
     109      return None