command.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # Copyright (c) 2011 The Chromium OS Authors.
  2. #
  3. # See file CREDITS for list of people who contributed to this
  4. # project.
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License as
  8. # published by the Free Software Foundation; either version 2 of
  9. # the License, or (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program; if not, write to the Free Software
  18. # Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  19. # MA 02111-1307 USA
  20. #
  21. import os
  22. import cros_subprocess
  23. """Shell command ease-ups for Python."""
  24. class CommandResult:
  25. """A class which captures the result of executing a command.
  26. Members:
  27. stdout: stdout obtained from command, as a string
  28. stderr: stderr obtained from command, as a string
  29. return_code: Return code from command
  30. exception: Exception received, or None if all ok
  31. """
  32. def __init__(self):
  33. self.stdout = None
  34. self.stderr = None
  35. self.return_code = None
  36. self.exception = None
  37. def RunPipe(pipe_list, infile=None, outfile=None,
  38. capture=False, capture_stderr=False, oneline=False,
  39. raise_on_error=True, cwd=None, **kwargs):
  40. """
  41. Perform a command pipeline, with optional input/output filenames.
  42. Args:
  43. pipe_list: List of command lines to execute. Each command line is
  44. piped into the next, and is itself a list of strings. For
  45. example [ ['ls', '.git'] ['wc'] ] will pipe the output of
  46. 'ls .git' into 'wc'.
  47. infile: File to provide stdin to the pipeline
  48. outfile: File to store stdout
  49. capture: True to capture output
  50. capture_stderr: True to capture stderr
  51. oneline: True to strip newline chars from output
  52. kwargs: Additional keyword arguments to cros_subprocess.Popen()
  53. Returns:
  54. CommandResult object
  55. """
  56. result = CommandResult()
  57. last_pipe = None
  58. pipeline = list(pipe_list)
  59. user_pipestr = '|'.join([' '.join(pipe) for pipe in pipe_list])
  60. while pipeline:
  61. cmd = pipeline.pop(0)
  62. if last_pipe is not None:
  63. kwargs['stdin'] = last_pipe.stdout
  64. elif infile:
  65. kwargs['stdin'] = open(infile, 'rb')
  66. if pipeline or capture:
  67. kwargs['stdout'] = cros_subprocess.PIPE
  68. elif outfile:
  69. kwargs['stdout'] = open(outfile, 'wb')
  70. if capture_stderr:
  71. kwargs['stderr'] = cros_subprocess.PIPE
  72. try:
  73. last_pipe = cros_subprocess.Popen(cmd, cwd=cwd, **kwargs)
  74. except Exception, err:
  75. result.exception = err
  76. if raise_on_error:
  77. raise Exception("Error running '%s': %s" % (user_pipestr, str))
  78. result.return_code = 255
  79. return result
  80. if capture:
  81. result.stdout, result.stderr, result.combined = (
  82. last_pipe.CommunicateFilter(None))
  83. if result.stdout and oneline:
  84. result.output = result.stdout.rstrip('\r\n')
  85. result.return_code = last_pipe.wait()
  86. else:
  87. result.return_code = os.waitpid(last_pipe.pid, 0)[1]
  88. if raise_on_error and result.return_code:
  89. raise Exception("Error running '%s'" % user_pipestr)
  90. return result
  91. def Output(*cmd):
  92. return RunPipe([cmd], capture=True, raise_on_error=False).stdout
  93. def OutputOneLine(*cmd, **kwargs):
  94. raise_on_error = kwargs.pop('raise_on_error', True)
  95. return (RunPipe([cmd], capture=True, oneline=True,
  96. raise_on_error=raise_on_error,
  97. **kwargs).stdout.strip())
  98. def Run(*cmd, **kwargs):
  99. return RunPipe([cmd], **kwargs).stdout
  100. def RunList(cmd):
  101. return RunPipe([cmd], capture=True).stdout
  102. def StopAll():
  103. cros_subprocess.stay_alive = False