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, encoding=None, **kwargs):
52 expect should be a tuple of allowed exit codes. cwd should be
53 the directory from which the command will be executed. When
54 unicode_output == True, convert stdout and stdin strings to
55 unicode before returing them.
59 if isinstance(shell, types.StringTypes):
60 list_args = ' '.split(args) # sloppy, but just for logging
64 str_args = ' '.join(args) # sloppy, but just for logging
65 libbe.LOG.debug('{0}$ {1}'.format(cwd, str_args))
70 q = Popen(args, stdin=PIPE, stdout=stdout, stderr=stderr,
71 shell=shell, cwd=cwd, **kwargs)
73 assert _MSWINDOWS==True, 'invalid platform'
76 # win32 don't have os.execvp() so have to run command in a shell
77 q = Popen(args, stdin=PIPE, stdout=stdout, stderr=stderr,
78 shell=shell, cwd=cwd, **kwargs)
80 raise CommandError(list_args, status=e.args[0], stderr=e)
81 stdout,stderr = q.communicate(input=stdin)
83 if unicode_output == True:
85 encoding = get_encoding()
87 stdout = unicode(stdout, encoding)
89 stderr = unicode(stderr, encoding)
90 libbe.LOG.debug('{0}\n{1}{2}'.format(status, stdout, stderr))
91 if status not in expect:
92 raise CommandError(list_args, status, stdout, stderr)
93 return status, stdout, stderr
95 if libbe.TESTING == True:
96 suite = doctest.DocTestSuite()