| class Command: |
| def __init__(self, args, redirects): |
| self.args = list(args) |
| self.redirects = list(redirects) |
| |
| def __repr__(self): |
| return 'Command(%r, %r)' % (self.args, self.redirects) |
| |
| def __eq__(self, other): |
| if not isinstance(other, Command): |
| return False |
| |
| return ((self.args, self.redirects) == |
| (other.args, other.redirects)) |
| |
| def toShell(self, file): |
| for arg in self.args: |
| if "'" not in arg: |
| quoted = "'%s'" % arg |
| elif '"' not in arg and '$' not in arg: |
| quoted = '"%s"' % arg |
| else: |
| raise NotImplementedError('Unable to quote %r' % arg) |
| file.write(quoted) |
| |
| # For debugging / validation. |
| import ShUtil |
| dequoted = list(ShUtil.ShLexer(quoted).lex()) |
| if dequoted != [arg]: |
| raise NotImplementedError('Unable to quote %r' % arg) |
| |
| for r in self.redirects: |
| if len(r[0]) == 1: |
| file.write("%s '%s'" % (r[0][0], r[1])) |
| else: |
| file.write("%s%s '%s'" % (r[0][1], r[0][0], r[1])) |
| |
| class GlobItem: |
| def __init__(self, pattern): |
| self.pattern = pattern |
| |
| def __repr__(self): |
| return self.pattern |
| |
| def __eq__(self, other): |
| if not isinstance(other, Command): |
| return False |
| |
| return (self.pattern == other.pattern) |
| |
| def resolve(self, cwd): |
| import glob |
| import os |
| if os.path.isabs(self.pattern): |
| abspath = self.pattern |
| else: |
| abspath = os.path.join(cwd, self.pattern) |
| results = glob.glob(abspath) |
| return [self.pattern] if len(results) == 0 else results |
| |
| class Pipeline: |
| def __init__(self, commands, negate=False, pipe_err=False): |
| self.commands = commands |
| self.negate = negate |
| self.pipe_err = pipe_err |
| |
| def __repr__(self): |
| return 'Pipeline(%r, %r, %r)' % (self.commands, self.negate, |
| self.pipe_err) |
| |
| def __eq__(self, other): |
| if not isinstance(other, Pipeline): |
| return False |
| |
| return ((self.commands, self.negate, self.pipe_err) == |
| (other.commands, other.negate, self.pipe_err)) |
| |
| def toShell(self, file, pipefail=False): |
| if pipefail != self.pipe_err: |
| raise ValueError('Inconsistent "pipefail" attribute!') |
| if self.negate: |
| file.write('! ') |
| for cmd in self.commands: |
| cmd.toShell(file) |
| if cmd is not self.commands[-1]: |
| file.write('|\n ') |
| |
| class Seq: |
| def __init__(self, lhs, op, rhs): |
| assert op in (';', '&', '||', '&&') |
| self.op = op |
| self.lhs = lhs |
| self.rhs = rhs |
| |
| def __repr__(self): |
| return 'Seq(%r, %r, %r)' % (self.lhs, self.op, self.rhs) |
| |
| def __eq__(self, other): |
| if not isinstance(other, Seq): |
| return False |
| |
| return ((self.lhs, self.op, self.rhs) == |
| (other.lhs, other.op, other.rhs)) |
| |
| def toShell(self, file, pipefail=False): |
| self.lhs.toShell(file, pipefail) |
| file.write(' %s\n' % self.op) |
| self.rhs.toShell(file, pipefail) |