Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Apr 29th, 2012  |  syntax: None  |  size: 2.96 KB  |  hits: 15  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. from collections import namedtuple
  2. from os import unlink
  3. from os.path import join as pjoin
  4. from subprocess import PIPE, Popen
  5.  
  6.  
  7. class Path(object):
  8.  
  9.     def __init__(self, pathname):
  10.         self.pathname = pathname
  11.  
  12.     def __repr__(self):
  13.         return self.pathname
  14.  
  15.     def __div__(self, b):
  16.         if isinstance(b, Path):
  17.             self.pathname = pjoin(self.pathname, b.pathname)
  18.             return self
  19.         elif isinstance(b, str):
  20.             self.pathname = pjoin(self.pathname, b)
  21.         else:
  22.             raise ValueError("Cannot join object into path")
  23.         return self
  24.  
  25.     def unlink(self):
  26.         unlink(self.pathname)
  27.  
  28.  
  29. class ShellOutput(namedtuple("ShellOutput", "retcode stdout stderr")):
  30.  
  31.     def __gt__(self, b):
  32.         """
  33.         :param b: will object to redirect the stdout into
  34.         """
  35.         self.redirect(b, 'stdout')
  36.  
  37.     def redirect(self, path_out, fd):
  38.         if isinstance(path_out, Path):
  39.             path = path_out.pathname
  40.         elif isinstance(path_out, str):
  41.             path = path_out
  42.         else:
  43.             raise ValueError("Cannot redirect to this object")
  44.  
  45.         with open(path, 'w') as out:
  46.             print >> out, getattr(self, fd)
  47.  
  48.  
  49. class ShellCmd(object):
  50.     """
  51.     This is a wrapper on Popen to help make building pipelines of commands
  52.     easier. The convenience syntax of '|' is reminiscent of regular shell
  53.     semantics but it is a bit different. In this case you must explicitly call
  54.     the resulting object
  55.     """
  56.  
  57.     def __init__(self, *cmd):
  58.         self.cmds = [cmd]
  59.         self.result = None
  60.  
  61.     def __call__(self, stdin=''):
  62.         return self.run(stdin)
  63.  
  64.     def __gt__(self, b):
  65.         if isinstance(b, str) or isinstance(b, Path):
  66.             self() > b
  67.  
  68.     def __or__(self, b):
  69.         return self.pipe(b)
  70.  
  71.     def __repr__(self):
  72.         return self().stdout
  73.  
  74.     def pipe(self, b):
  75.         if isinstance(b, ShellCmd):
  76.             b.cmds = self.cmds + b.cmds
  77.             return b
  78.  
  79.     def run(self, stdin=()):
  80.         first = True
  81.         procs = []
  82.         if isinstance(stdin, ShellCmd):
  83.             self.cmds = stdin.cmds + self.cmds
  84.             stdin = ''
  85.         for cmd in self.cmds:
  86.             if first:
  87.                 if stdin != '':
  88.                     proc = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
  89.                 else:
  90.                     proc = Popen(cmd, stdout=PIPE, stderr=PIPE)
  91.                 first = False
  92.             else:
  93.                 proc = Popen(cmd, stdin=procs[-1].stdout,
  94.                              stdout=PIPE, stderr=PIPE)
  95.             procs.append(proc)
  96.  
  97.         if len(procs) > 1:
  98.             if stdin != '':
  99.                 procs[0].communicate(stdin)
  100.             for proc in procs[:-1]:
  101.                 proc.stdout.close()
  102.             stdout, stderr = procs[-1].communicate()
  103.             retcode = procs[-1].returncode
  104.         else:
  105.             stdout, stderr = procs[0].communicate()
  106.             retcode = procs[0].returncode
  107.  
  108.         return ShellOutput(retcode, stdout, stderr)