executils.py 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. from msysutils import msysActive, msysShell
  2. from os import environ
  3. from shlex import split as shsplit
  4. from subprocess import PIPE, Popen
  5. def captureStdout(log, commandLine):
  6. '''Run a command and capture what it writes to stdout.
  7. If the command fails or writes something to stderr, that is logged.
  8. Returns the captured string, or None if the command failed.
  9. '''
  10. # TODO: This is a modified copy-paste from compilers._Command.
  11. commandParts = shsplit(commandLine)
  12. env = dict(environ)
  13. while commandParts:
  14. if '=' in commandParts[0]:
  15. name, value = commandParts[0].split('=', 1)
  16. del commandParts[0]
  17. env[name] = value
  18. else:
  19. break
  20. else:
  21. raise ValueError(
  22. 'No command specified in "%s"' % commandLine
  23. )
  24. if msysActive() and commandParts[0] != 'sh':
  25. commandParts = [
  26. environ.get('MSYSCON') or environ.get('SHELL') or 'sh.exe',
  27. '-c', shjoin(commandParts)
  28. ]
  29. try:
  30. proc = Popen(
  31. commandParts, bufsize = -1, env = env,
  32. stdin = None, stdout = PIPE, stderr = PIPE,
  33. )
  34. except OSError, ex:
  35. print >> log, 'Failed to execute "%s": %s' % (commandLine, ex)
  36. return None
  37. stdoutdata, stderrdata = proc.communicate()
  38. if stderrdata:
  39. severity = 'warning' if proc.returncode == 0 else 'error'
  40. log.write('%s executing "%s"\n' % (severity.capitalize(), commandLine))
  41. # pylint 0.18.0 somehow thinks stderrdata is a list, not a string.
  42. # pylint: disable-msg=E1103
  43. stderrdata = stderrdata.replace('\r', '')
  44. log.write(stderrdata)
  45. if not stderrdata.endswith('\n'):
  46. log.write('\n')
  47. if proc.returncode == 0:
  48. return stdoutdata
  49. else:
  50. print >> log, 'Execution failed with exit code %d' % proc.returncode
  51. return None
  52. def shjoin(parts):
  53. '''Joins the given sequence into a single string with space as a separator.
  54. Characters that have a special meaning for the shell are escaped.
  55. This is the counterpart of shlex.split().
  56. '''
  57. def escape(part):
  58. return ''.join(
  59. '\\' + ch if ch in '\\ \'"$()[]' else ch
  60. for ch in part
  61. )
  62. return ' '.join(escape(part) for part in parts)