Wrap things in a little less silly fashion
[trac-attack.git] / trac-attack.py
1 #!/usr/bin/python
2 import ConfigParser
3 from optparse import OptionParser
4 import os, os.path, sys
5 import xmlrpclib
6 import textwrap
7
8 config = ConfigParser.RawConfigParser()
9 config.read(os.path.join(os.environ['HOME'], '.trac-attack.rc'))
10 default_trac = config.get('main', 'default')
11
12 options = OptionParser()
13 options.add_option('-t', '--trac', dest = "trac",
14                    help = "Which trac to connect to")
15
16 def open_rpc(trac):
17     url = config.get(trac, 'url')
18     return xmlrpclib.ServerProxy(url)
19
20 def list_tickets(tickets):
21     listing_wrapper = textwrap.TextWrapper(
22             width = 63, replace_whitespace = True, drop_whitespace = True,
23             subsequent_indent = ' ' * 17)
24
25     print "%-7s %-8s %s" % ('ID', 'priority', 'summary')
26     print '-' * 70
27     for t in tickets:
28         print "#%-6d %-8s" % (t[0], t[3]['priority']), listing_wrapper.fill(t[3]['summary'])
29
30 def show_ticket(ticket):
31     description_wrap = textwrap.TextWrapper(width = 80)
32
33     (id, time_created, time_changed, attributes) = ticket
34
35     print "Ticket #%d (%s %s)" % (id, attributes['status'], attributes['type'])
36     print attributes['summary']
37     print
38
39     fields = [
40             [('Reported by', 'reporter'), ('Owned by', 'owner')],
41             [('Priority', 'priority'), ('Milestone', 'milestone')],
42             [('Component', 'component'), ('Version', 'version')],
43             [('Keywords', 'keywords'), ('Cc', 'cc')],
44     ]
45     for row in fields:
46         print "%-39s %-39s" % tuple(map(lambda x: "%s: %s" % (x[0], attributes[x[1]]), row))
47
48     print
49     for line in attributes['description'].split("\n"):
50         print description_wrap.fill(line)
51     print
52
53 def editor():
54     raise NotImplementedError
55
56 def comment_on_ticket(id, comment):
57     raise NotImplementedError
58
59 def main():
60     (flags, args) = options.parse_args()
61     trac = flags.trac or default_trac
62     server = open_rpc(trac)
63     user = config.get(trac, 'user')
64     
65     if args[0] == 'ls' or args[0] == 'list':
66         if len(args) > 1:
67             try:
68                 query = config.get('queries', args[1])
69             except ConfigParser.NoOptionError:
70                 print "I couldn't find the query %s" % args[1]
71                 sys.exit(1)
72         else:
73             try:
74                 query = config.get('queries', 'default')
75             except ConfigParser.NoOptionError:
76                 query = "status!=closed&owner=$USER"
77         tickets = server.ticket.query(query)
78         multicall = xmlrpclib.MultiCall(server)
79         for t in tickets:
80             multicall.ticket.get(t)
81         list_tickets(multicall())
82     elif args[0] == 'info' or args[0] == 'show':
83         id = int(args[1])
84         ticket = server.ticket.get(id)
85         show_ticket(ticket)
86     elif args[0] == 'comment':
87         id = int(args[1])
88         comment = editor()
89         comment_on_ticket(id, comment)
90     else:
91         print "Command %s not understood" % args[0]
92
93 if __name__ == "__main__":
94     main()