Run a command and return stdout, stderr and return code cmd: string or list of command and args stderr: STDOUT to merge stderr with stdout shell: run command using shell echo: monitor output to console
( *cmd, **kwargs )
| 131 | |
| 132 | # pylint: disable=too-many-branches,too-many-statements |
| 133 | def errRun( *cmd, **kwargs ): |
| 134 | """Run a command and return stdout, stderr and return code |
| 135 | cmd: string or list of command and args |
| 136 | stderr: STDOUT to merge stderr with stdout |
| 137 | shell: run command using shell |
| 138 | echo: monitor output to console""" |
| 139 | # By default we separate stderr, don't run in a shell, and don't echo |
| 140 | stderr = kwargs.get( 'stderr', PIPE ) |
| 141 | shell = kwargs.get( 'shell', False ) |
| 142 | echo = kwargs.get( 'echo', False ) |
| 143 | if echo: |
| 144 | # cmd goes to stderr, output goes to stdout |
| 145 | info( cmd, '\n' ) |
| 146 | if len( cmd ) == 1: |
| 147 | cmd = cmd[ 0 ] |
| 148 | # Allow passing in a list or a string |
| 149 | if isinstance( cmd, BaseString ) and not shell: |
| 150 | cmd = cmd.split( ' ' ) |
| 151 | cmd = [ str( arg ) for arg in cmd ] |
| 152 | elif isinstance( cmd, list ) and shell: |
| 153 | cmd = " ".join( arg for arg in cmd ) |
| 154 | debug( '*** errRun:', cmd, '\n' ) |
| 155 | # pylint: disable=consider-using-with |
| 156 | popen = Popen( cmd, stdout=PIPE, stderr=stderr, shell=shell ) |
| 157 | # We use poll() because select() doesn't work with large fd numbers, |
| 158 | # and thus communicate() doesn't work either |
| 159 | out, err = '', '' |
| 160 | poller = poll() |
| 161 | poller.register( popen.stdout, POLLIN ) |
| 162 | fdToFile = { popen.stdout.fileno(): popen.stdout } |
| 163 | fdToDecoder = { popen.stdout.fileno(): getincrementaldecoder() } |
| 164 | outDone, errDone = False, True |
| 165 | if popen.stderr: |
| 166 | fdToFile[ popen.stderr.fileno() ] = popen.stderr |
| 167 | fdToDecoder[ popen.stderr.fileno() ] = getincrementaldecoder() |
| 168 | poller.register( popen.stderr, POLLIN ) |
| 169 | errDone = False |
| 170 | while not outDone or not errDone: |
| 171 | readable = poller.poll() |
| 172 | for fd, event in readable: |
| 173 | f = fdToFile[ fd ] |
| 174 | decoder = fdToDecoder[ fd ] |
| 175 | if event & ( POLLIN | POLLHUP ): |
| 176 | data = decoder.decode( f.read( 1024 ) ) |
| 177 | if echo: |
| 178 | output( data ) |
| 179 | if f == popen.stdout: |
| 180 | out += data |
| 181 | if data == '': |
| 182 | outDone = True |
| 183 | elif f == popen.stderr: |
| 184 | err += data |
| 185 | if data == '': |
| 186 | errDone = True |
| 187 | else: # something unexpected |
| 188 | if f == popen.stdout: |
| 189 | outDone = True |
| 190 | elif f == popen.stderr: |
no test coverage detected