1 # Copyright (C) 2009-2012 Chris Ball <cjb@laptop.org>
2 # W. Trevor King <wking@tremily.us>
4 # This file is part of Bugs Everywhere.
6 # Bugs Everywhere is free software: you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the Free
8 # Software Foundation, either version 2 of the License, or (at your option) any
11 # Bugs Everywhere is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 # You should have received a copy of the GNU General Public License along with
17 # Bugs Everywhere. If not, see <http://www.gnu.org/licenses/>.
20 Functions for running external commands in subprocesses.
23 from subprocess import Popen, PIPE
28 from encoding import get_encoding
29 if libbe.TESTING == True:
32 _MSWINDOWS = sys.platform == 'win32'
33 _POSIX = not _MSWINDOWS
39 class CommandError(Exception):
40 def __init__(self, command, status, stdout=None, stderr=None):
41 strerror = ['Command failed (%d):\n %s\n' % (status, stderr),
42 'while executing\n %s' % str(command)]
43 Exception.__init__(self, '\n'.join(strerror))
44 self.command = command
49 def invoke(args, stdin=None, stdout=PIPE, stderr=PIPE, expect=(0,),
50 cwd=None, shell=None, unicode_output=True, verbose=False,
51 encoding=None, **kwargs):
53 expect should be a tuple of allowed exit codes. cwd should be
54 the directory from which the command will be executed. When
55 unicode_output == True, convert stdout and stdin strings to
56 unicode before returing them.
60 if isinstance(shell, types.StringTypes):
61 list_args = ' '.split(args) # sloppy, but just for logging
65 str_args = ' '.join(args) # sloppy, but just for logging
67 print >> sys.stderr, '%s$ %s' % (cwd, str_args)
72 q = Popen(args, stdin=PIPE, stdout=stdout, stderr=stderr,
73 shell=shell, cwd=cwd, **kwargs)
75 assert _MSWINDOWS==True, 'invalid platform'
78 # win32 don't have os.execvp() so have to run command in a shell
79 q = Popen(args, stdin=PIPE, stdout=stdout, stderr=stderr,
80 shell=shell, cwd=cwd, **kwargs)
82 raise CommandError(list_args, status=e.args[0], stderr=e)
83 stdout,stderr = q.communicate(input=stdin)
85 if unicode_output == True:
87 encoding = get_encoding()
89 stdout = unicode(stdout, encoding)
91 stderr = unicode(stderr, encoding)
93 print >> sys.stderr, '%d\n%s%s' % (status, stdout, stderr)
94 if status not in expect:
95 raise CommandError(list_args, status, stdout, stderr)
96 return status, stdout, stderr
98 if libbe.TESTING == True:
99 suite = doctest.DocTestSuite()