1 # Copyright (C) 2005-2012 Aaron Bentley <abentley@panoramicfeedback.com>
2 # Chris Ball <cjb@laptop.org>
3 # Gianluca Montecchi <gian@grys.it>
4 # Thomas Gerigk <tgerigk@gmx.de>
5 # Thomas Habets <thomas@habets.pp.se>
6 # W. Trevor King <wking@tremily.us>
8 # This file is part of Bugs Everywhere.
10 # Bugs Everywhere is free software: you can redistribute it and/or modify it
11 # under the terms of the GNU General Public License as published by the Free
12 # Software Foundation, either version 2 of the License, or (at your option) any
15 # Bugs Everywhere is distributed in the hope that it will be useful, but
16 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 # You should have received a copy of the GNU General Public License along with
21 # Bugs Everywhere. If not, see <http://www.gnu.org/licenses/>.
27 import libbe.command.util
32 class Show (libbe.command.Command):
33 """Show a particular bug, comment, or combination of both.
36 >>> import libbe.bugdir
37 >>> bd = libbe.bugdir.SimpleBugDir(memory=False)
38 >>> io = libbe.command.StringInputOutput()
39 >>> io.stdout = sys.stdout
40 >>> io.stdout.encoding = 'ascii'
41 >>> ui = libbe.command.UserInterface(io=io)
42 >>> ui.storage_callbacks.set_storage(bd.storage)
45 >>> ret = ui.run(cmd, args=['/a',]) # doctest: +ELLIPSIS
52 Creator : John Doe <jdoe@example.com>
57 >>> ret = ui.run(cmd, {'xml':True}, ['/a']) # doctest: +ELLIPSIS
58 <?xml version="1.0" encoding="..." ?>
62 <committer>...</committer>
64 <revision>...</revision>
68 <short-name>abc/a</short-name>
69 <severity>minor</severity>
71 <creator>John Doe <jdoe@example.com></creator>
72 <created>Thu, 01 Jan 1970 00:00:00 +0000</created>
73 <summary>Bug A</summary>
81 def __init__(self, *args, **kwargs):
82 libbe.command.Command.__init__(self, *args, **kwargs)
84 libbe.command.Option(name='xml', short_name='x',
86 libbe.command.Option(name='only-raw-body',
87 help="When printing only a single comment, just print it's"
88 " body. This allows extraction of non-text content types."),
89 libbe.command.Option(name='no-comments', short_name='c',
90 help="Disable comment output. This is useful if you just "
91 "want more details on a bug's current status."),
94 libbe.command.Argument(
95 name='id', metavar='ID', default=None,
96 optional=True, repeatable=True,
97 completion_callback=libbe.command.util.complete_bug_comment_id),
100 def _run(self, **params):
101 bugdirs = self._get_bugdirs()
102 if params['only-raw-body'] == True:
103 if len(params['id']) != 1:
104 raise libbe.command.UserError(
105 'only one ID accepted with --only-raw-body')
106 bugdir,bug,comment = (
107 libbe.command.util.bugdir_bug_comment_from_user_id(
108 bugdirs, params['id'][0]))
109 if comment == bug.comment_root:
110 raise libbe.command.UserError(
111 "--only-raw-body requires a comment ID, not '%s'"
113 sys.__stdout__.write(comment.body)
115 print >> self.stdout, \
116 output(bugdirs, params['id'], encoding=self.stdout.encoding,
117 as_xml=params['xml'],
118 with_comments=not params['no-comments'])
121 def _long_help(self):
123 Show all information about the bugs or comments whose IDs are given.
124 If no IDs are given, show the entire repository.
126 Without the --xml flag set, it's probably not a good idea to mix bug
127 and comment IDs in a single call, but you're free to do so if you
128 like. With the --xml flag set, there will never be any root comments,
129 so mix and match away (the bug listings for directly requested
130 comments will be restricted to the bug uuid and the requested
133 Directly requested comments will be grouped by their parent bug and
134 placed at the end of the output, so the ordering may not match the
135 order of the listed IDs.
138 def _sort_ids(bugdirs, ids, with_comments=True):
142 p = libbe.util.id.parse_user(bugdirs, id)
143 if p['type'] == 'bug':
144 bugs.append(p['bug'])
145 elif with_comments == True:
146 if p['bug'] not in root_comments:
147 root_comments[p['bug']] = [p['comment']]
149 root_comments[p['bug']].append(p['comment'])
150 for bugname in root_comments.keys():
151 assert bugname not in bugs, \
152 'specifically requested both #/%s/%s# and #/%s#' \
153 % (bugname, root_comments[bugname][0], bugname)
154 return (bugs, root_comments)
156 def _xml_header(encoding):
157 lines = ['<?xml version="1.0" encoding="%s" ?>' % encoding,
160 ' <tag>%s</tag>' % libbe.version.version()]
161 for tag,value in sorted(libbe.version.version_info.items()):
162 lines.append(' <%s>%s</%s>' % (tag, value, tag))
163 lines.append(' </version>')
169 def output(bugdirs, ids, encoding, as_xml=True, with_comments=True):
170 if ids == None or len(ids) == 0:
172 for bugdir in bugdirs.values():
173 bugdir.load_all_bugs()
174 ids.extend([bug.id.user() for bug in bugdir])
175 uuids,root_comments = _sort_ids(bugdirs, ids, with_comments)
178 lines.extend(_xml_header(encoding))
180 spaces_left = len(ids) - 1
181 for bugname in uuids:
182 bug = libbe.command.util.bug_from_uuid(bugdirs, bugname)
184 lines.append(bug.xml(indent=2, show_comments=with_comments))
186 lines.append(bug.string(show_comments=with_comments))
189 lines.append('') # add a blank line between bugs/comments
190 for bugname,comments in root_comments.items():
191 bug = libbe.command.util.bug_from_uuid(bugdirs, bugname)
193 lines.extend([' <bug>', ' <uuid>%s</uuid>' % bug.uuid])
194 for commname in comments:
196 comment = bug.comment_root.comment_from_uuid(commname)
198 raise libbe.command.UserError(e.message)
200 lines.append(comment.xml(indent=4))
202 lines.append(comment.string())
205 lines.append('') # add a blank line between bugs/comments
207 lines.append('</bug>')
209 lines.extend(_xml_footer())
210 return '\n'.join(lines)