1894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanclass Command:
2894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def __init__(self, args, redirects):
3894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.args = list(args)
4894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.redirects = list(redirects)
5894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
6894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def __repr__(self):
7894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return 'Command(%r, %r)' % (self.args, self.redirects)
8894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
9894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def __cmp__(self, other):
10894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if not isinstance(other, Command):
11894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return -1
12894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
13894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return cmp((self.args, self.redirects),
14894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                   (other.args, other.redirects))
15894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
16894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def toShell(self, file):
17894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        for arg in self.args:
18894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            if "'" not in arg:
19894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                quoted = "'%s'" % arg
20894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            elif '"' not in arg and '$' not in arg:
21894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                quoted = '"%s"' % arg
22894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            else:
23894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                raise NotImplementedError,'Unable to quote %r' % arg
24894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            print >>file, quoted,
25894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
26894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            # For debugging / validation.
27894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            import ShUtil
28894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            dequoted = list(ShUtil.ShLexer(quoted).lex())
29894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            if dequoted != [arg]:
30894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                raise NotImplementedError,'Unable to quote %r' % arg
31894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
32894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        for r in self.redirects:
33894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            if len(r[0]) == 1:
34894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                print >>file, "%s '%s'" % (r[0][0], r[1]),
35894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            else:
36894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                print >>file, "%s%s '%s'" % (r[0][1], r[0][0], r[1]),
37894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
38894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanclass Pipeline:
39894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def __init__(self, commands, negate=False, pipe_err=False):
40894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.commands = commands
41894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.negate = negate
42894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.pipe_err = pipe_err
43894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
44894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def __repr__(self):
45894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return 'Pipeline(%r, %r, %r)' % (self.commands, self.negate,
46894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                                         self.pipe_err)
47894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
48894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def __cmp__(self, other):
49894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if not isinstance(other, Pipeline):
50894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return -1
51894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
52894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return cmp((self.commands, self.negate, self.pipe_err),
53894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                   (other.commands, other.negate, self.pipe_err))
54894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
55894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def toShell(self, file, pipefail=False):
56894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if pipefail != self.pipe_err:
57894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            raise ValueError,'Inconsistent "pipefail" attribute!'
58894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if self.negate:
59894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            print >>file, '!',
60894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        for cmd in self.commands:
61894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            cmd.toShell(file)
62894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            if cmd is not self.commands[-1]:
63894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                print >>file, '|\n ',
64894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
65894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanclass Seq:
66894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def __init__(self, lhs, op, rhs):
67894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        assert op in (';', '&', '||', '&&')
68894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.op = op
69894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.lhs = lhs
70894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.rhs = rhs
71894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
72894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def __repr__(self):
73894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return 'Seq(%r, %r, %r)' % (self.lhs, self.op, self.rhs)
74894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
75894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def __cmp__(self, other):
76894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if not isinstance(other, Seq):
77894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return -1
78894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
79894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return cmp((self.lhs, self.op, self.rhs),
80894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                   (other.lhs, other.op, other.rhs))
81894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
82894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    def toShell(self, file, pipefail=False):
83894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.lhs.toShell(file, pipefail)
84894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        print >>file, ' %s\n' % self.op
85894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        self.rhs.toShell(file, pipefail)
86