1class Command: 2 def __init__(self, args, redirects): 3 self.args = list(args) 4 self.redirects = list(redirects) 5 6 def __repr__(self): 7 return "Command(%r, %r)" % (self.args, self.redirects) 8 9 def __eq__(self, other): 10 if not isinstance(other, Command): 11 return False 12 13 return (self.args, self.redirects) == (other.args, other.redirects) 14 15 def toShell(self, file): 16 for arg in self.args: 17 if "'" not in arg: 18 quoted = "'%s'" % arg 19 elif '"' not in arg and "$" not in arg: 20 quoted = '"%s"' % arg 21 else: 22 raise NotImplementedError("Unable to quote %r" % arg) 23 file.write(quoted) 24 25 # For debugging / validation. 26 import ShUtil 27 28 dequoted = list(ShUtil.ShLexer(quoted).lex()) 29 if dequoted != [arg]: 30 raise NotImplementedError("Unable to quote %r" % arg) 31 32 for r in self.redirects: 33 if len(r[0]) == 1: 34 file.write("%s '%s'" % (r[0][0], r[1])) 35 else: 36 file.write("%s%s '%s'" % (r[0][1], r[0][0], r[1])) 37 38 39class GlobItem: 40 def __init__(self, pattern): 41 self.pattern = pattern 42 43 def __repr__(self): 44 return self.pattern 45 46 def __eq__(self, other): 47 if not isinstance(other, Command): 48 return False 49 50 return self.pattern == other.pattern 51 52 def resolve(self, cwd): 53 import glob 54 import os 55 56 if os.path.isabs(self.pattern): 57 abspath = self.pattern 58 else: 59 abspath = os.path.join(cwd, self.pattern) 60 results = glob.glob(abspath) 61 return [self.pattern] if len(results) == 0 else results 62 63 64class Pipeline: 65 def __init__(self, commands, negate=False, pipe_err=False): 66 self.commands = commands 67 self.negate = negate 68 self.pipe_err = pipe_err 69 70 def __repr__(self): 71 return "Pipeline(%r, %r, %r)" % (self.commands, self.negate, self.pipe_err) 72 73 def __eq__(self, other): 74 if not isinstance(other, Pipeline): 75 return False 76 77 return (self.commands, self.negate, self.pipe_err) == ( 78 other.commands, 79 other.negate, 80 self.pipe_err, 81 ) 82 83 def toShell(self, file, pipefail=False): 84 if pipefail != self.pipe_err: 85 raise ValueError('Inconsistent "pipefail" attribute!') 86 if self.negate: 87 file.write("! ") 88 for cmd in self.commands: 89 cmd.toShell(file) 90 if cmd is not self.commands[-1]: 91 file.write("|\n ") 92 93 94class Seq: 95 def __init__(self, lhs, op, rhs): 96 assert op in (";", "&", "||", "&&") 97 self.op = op 98 self.lhs = lhs 99 self.rhs = rhs 100 101 def __repr__(self): 102 return "Seq(%r, %r, %r)" % (self.lhs, self.op, self.rhs) 103 104 def __eq__(self, other): 105 if not isinstance(other, Seq): 106 return False 107 108 return (self.lhs, self.op, self.rhs) == (other.lhs, other.op, other.rhs) 109 110 def toShell(self, file, pipefail=False): 111 self.lhs.toShell(file, pipefail) 112 file.write(" %s\n" % self.op) 113 self.rhs.toShell(file, pipefail) 114