Skip to content

Commit

Permalink
Alter System() class to internally buffer stdout and stderr, rather than
Browse files Browse the repository at this point in the history
relying on limited 64K buffer of UNIX pipes.  Add option to run calls
natively, rather than through Bourne shell.
  • Loading branch information
wagnerrp committed Jan 9, 2011
1 parent 3b10231 commit b35ddbf
Showing 1 changed file with 43 additions and 7 deletions.
50 changes: 43 additions & 7 deletions mythtv/bindings/python/MythTV/system.py
Expand Up @@ -11,7 +11,9 @@
from database import DBCache

from subprocess import Popen
from select import select
from lxml import etree
import shlex
import os

class System( DBCache ):
Expand Down Expand Up @@ -40,24 +42,41 @@ def system(cls, command, db=None):
except MythError:
return s.returncode

def __init__(self, path=None, setting=None, db=None):
def __init__(self, path=None, setting=None, db=None, useshell=True):
DBCache.__init__(self, db=db)
self.log = MythLog(self.logmodule, db=self)
self.path = None

if setting is not None:
# pull setting from database, substitute from argument if needed
host = self.gethostname()
self.path = self.settings[host][setting]
if (self.path is None) and (path is None):
raise MythDBError(MythError.DB_SETTING, setting, host)

if self.path is None:
# setting not given, use path from argument
if path is None:
raise MythError('Invalid input to System()')
self.path = path

cmd = self.path.split()[0]
if self.path.startswith('/'):
if not os.access(self.path.split()[0], os.F_OK):
raise MythFileError('Defined grabber path does not exist.')
# test full given path
if not os.access(cmd, os.F_OK):
raise MythFileError('Defined executable path does not exist.')
else:
# search command from PATH
for folder in os.environ['PATH'].split(':'):
if os.access(os.path.join(folder,cmd), os.F_OK):
self.path = os.path.join(folder,self.path)
break
else:
raise MythFileError('Defined executable path does not exist.')

self.returncode = 0
self.stderr = ''
self.useshell = useshell

def __call__(self, *args): return self.command(*args)

Expand Down Expand Up @@ -93,15 +112,32 @@ def command(self, *args):
arg = ' '+' '.join(['%s' % a for a in args])
return self._runcmd('%s %s' % (self.path, arg))

def _runcmd(self, cmd):
def _runshell(self, cmd):
self.log(MythLog.SYSTEM, 'Running external command', cmd)
fd = Popen(cmd, stdout=-1, stderr=-1, shell=True)
self.returncode = fd.wait()
stdout,self.stderr = fd.communicate()
return self._runshared(fd)

def _runnative(self, cmd):
self.log(MythLog.SYSTEM, 'Running external command', cmd)
args = shlex.split(cmd)
fd = Popen(args, stdout=-1, stderr=-1)
return self._runshared(fd)

def _runshared(self, fd):
pmap = {fd.stdout:'', fd.stderr:''}
while fd.poll() is None:
socks = select([fd.stdout, fd.stderr],[],[])
for sock in socks[0]:
pmap[sock] += sock.read()
self.stderr = pmap[fd.stderr]

self.returncode = fd.poll()
if self.returncode:
raise MythError(MythError.SYSTEM,self.returncode,cmd,self.stderr)
return stdout
return pmap[fd.stdout]

def _runcmd(self, cmd):
return self._runshell(cmd) if self.useshell else self._runnative(cmd)

class Metadata( DictData ):
_global_type = {'title':3, 'subtitle':3, 'tagline':3,
Expand Down

0 comments on commit b35ddbf

Please sign in to comment.