terom@5: """ terom@5: Invoke external commands. terom@72: terom@72: XXX: replace with pvl.invoke terom@5: """ terom@5: terom@5: import subprocess terom@5: import logging terom@5: terom@5: log = logging.getLogger('pvl.backup.invoke') terom@5: terom@68: SUDO = '/usr/bin/sudo' terom@68: terom@5: class InvokeError (Exception) : terom@5: def __init__ (self, cmd, exit) : terom@5: self.cmd = cmd terom@5: self.exit = exit terom@5: terom@5: def __str__ (self) : terom@5: return "{cmd} failed: {exit}".format(cmd=self.cmd, exit=self.exit) terom@5: terom@68: def invoke (cmd, args, data=None, sudo=False) : terom@5: """ terom@5: Invoke a command directly. terom@5: terom@5: data: data to pass in on stdin, returning stdout. terom@5: if given as False, passes through our process stdin/out terom@68: sudo: exec using sudo terom@5: terom@5: Doesn't give any data on stdin, and keeps process stderr. terom@5: Returns stdout. terom@5: """ terom@5: terom@68: log.debug("{sudo}{cmd} {args}".format(sudo=('sudo ' if sudo else ''), cmd=cmd, args=' '.join(args))) terom@5: terom@5: if data is False : terom@5: # keep process stdin/out terom@5: io = None terom@5: else : terom@5: io = subprocess.PIPE terom@5: terom@68: args = [cmd] + args terom@68: terom@68: if sudo : terom@68: args = [SUDO] + args terom@68: terom@68: p = subprocess.Popen(args, stdin=io, stdout=io) terom@5: terom@5: # get output terom@5: stdout, stderr = p.communicate(input=data) terom@5: terom@5: if p.returncode : terom@5: # failed terom@5: raise InvokeError(cmd, p.returncode) terom@5: terom@5: return stdout terom@5: terom@12: def process_opt (opt, value) : terom@12: """ terom@12: Mangle from python keyword-argument dict format to command-line option tuple format. terom@12: terom@12: >>> process_opt('foo', True) terom@12: ('--foo',) terom@12: >>> process_opt('foo', 2) terom@12: ('--foo', '2') terom@12: >>> process_opt('foo', 'bar') terom@12: ('--foo', 'bar') terom@12: >>> process_opt('foo_bar', 'asdf') terom@12: ('--foo-bar', 'asdf') terom@12: terom@27: # empty terom@27: >>> process_opt('foo', False) terom@27: () terom@27: >>> process_opt('foo', None) terom@27: () terom@12: >>> process_opt('bar', '') terom@27: () terom@12: terom@12: Returns a tuple of argv items. terom@12: """ terom@12: terom@12: # mangle opt terom@12: opt = '--' + opt.replace('_', '-') terom@12: terom@12: if value is True : terom@12: # flag opt terom@12: return (opt, ) terom@12: terom@27: elif not value : terom@12: # flag opt / omit terom@12: return ( ) terom@12: terom@12: else : terom@12: # as-is terom@12: return (opt, str(value)) terom@12: terom@5: def optargs (*args, **kwargs) : terom@5: """ terom@5: Convert args/options into command-line format terom@5: """ terom@5: terom@12: ## opts terom@5: # process terom@12: opts = [process_opt(opt, value) for opt, value in kwargs.iteritems()] terom@5: terom@5: # flatten terom@5: opts = [str(opt_part) for opt_parts in opts for opt_part in opt_parts if opt_part] terom@5: terom@12: ## args terom@5: args = [str(arg) for arg in args if arg] terom@5: terom@5: return opts + args terom@5: terom@5: def command (cmd, *args, **opts) : terom@5: """ terom@5: Invoke a command with options/arguments, given via Python arguments/keyword arguments. terom@5: terom@5: Return stdout. terom@5: """ terom@5: terom@5: log.debug("{cmd} {opts} {args}".format(cmd=cmd, args=args, opts=opts)) terom@5: terom@5: # invoke terom@5: return invoke(cmd, optargs(*args, **opts)) terom@12: terom@12: if __name__ == '__main__': terom@12: import doctest terom@12: doctest.testmod() terom@12: