command.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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. 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. while pipeline:
  60. cmd = pipeline.pop(0)
  61. if last_pipe is not None:
  62. kwargs['stdin'] = last_pipe.stdout
  63. elif infile:
  64. kwargs['stdin'] = open(infile, 'rb')
  65. if pipeline or capture:
  66. kwargs['stdout'] = cros_subprocess.PIPE
  67. elif outfile:
  68. kwargs['stdout'] = open(outfile, 'wb')
  69. if capture_stderr:
  70. kwargs['stderr'] = cros_subprocess.PIPE
  71. try:
  72. last_pipe = cros_subprocess.Popen(cmd, cwd=cwd, **kwargs)
  73. except Exception, err:
  74. result.exception = err
  75. print 'exception', pipe_list, err
  76. raise Exception("Error running '%s': %s" % (pipe_list, str))
  77. if capture:
  78. result.stdout, result.stderr, result.combined = (
  79. last_pipe.CommunicateFilter(None))
  80. if result.stdout and oneline:
  81. result.output = result.stdout.rstrip('\r\n')
  82. result.return_code = last_pipe.wait()
  83. else:
  84. result.return_code = os.waitpid(last_pipe.pid, 0)[1]
  85. if result.return_code:
  86. raise Exception("Error running '%s'" % pipe_list)
  87. return result
  88. def Output(*cmd):
  89. return RunPipe([cmd], capture=True).stdout
  90. def OutputOneLine(*cmd, **kwargs):
  91. return (RunPipe([cmd], capture=True, oneline=True,
  92. **kwargs).stdout.strip())
  93. def Run(*cmd, **kwargs):
  94. return RunPipe([cmd], **kwargs).stdout
  95. def RunList(cmd):
  96. return RunPipe([cmd], capture=True).stdout
  97. def StopAll():
  98. cros_subprocess.stay_alive = False