1 # Copyright (C) 2005-2012 Aaron Bentley <abentley@panoramicfeedback.com>
2 # Chris Ball <cjb@laptop.org>
3 # Gianluca Montecchi <gian@grys.it>
4 # Marien Zwart <marien.zwart@gmail.com>
5 # Thomas Gerigk <tgerigk@gmx.de>
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/>.
25 import libbe.command.util
26 import libbe.command.depend
30 class Target (libbe.command.Command):
31 """Assorted bug target manipulations and queries
33 >>> import os, StringIO, sys
34 >>> import libbe.bugdir
35 >>> bd = libbe.bugdir.SimpleBugDir(memory=False)
36 >>> io = libbe.command.StringInputOutput()
37 >>> io.stdout = sys.stdout
38 >>> ui = libbe.command.UserInterface(io=io)
39 >>> ui.storage_callbacks.set_storage(bd.storage)
40 >>> cmd = Target(ui=ui)
42 >>> ret = ui.run(cmd, args=['/a'])
44 >>> ret = ui.run(cmd, args=['/a', 'tomorrow'])
45 >>> ret = ui.run(cmd, args=['/a'])
48 >>> ui.io.stdout = StringIO.StringIO()
49 >>> ret = ui.run(cmd, {'resolve':True}, ['tomorrow'])
50 >>> output = ui.io.get_stdout().strip()
52 >>> target = bd.bug_from_uuid(output)
53 >>> print target.summary
55 >>> print target.severity
58 >>> ui.io.stdout = sys.stdout
59 >>> ret = ui.run(cmd, args=['/a', 'none'])
60 >>> ret = ui.run(cmd, args=['/a'])
67 def __init__(self, *args, **kwargs):
68 libbe.command.Command.__init__(self, *args, **kwargs)
70 libbe.command.Option(name='resolve', short_name='r',
71 help="Print the UUID for the target bug whose summary "
72 "matches TARGET. If TARGET is not given, print the UUID "
73 "of the current bugdir target."),
74 libbe.command.Option(name='bugdir', short_name='b',
75 help='Short bugdir UUID for the target resolution. You '
76 'only need to set this if you have multiple bugdirs in '
78 arg=libbe.command.Argument(
79 name='bugdir', metavar='ID', default=None,
80 completion_callback=libbe.command.util.complete_bugdir_id)),
83 libbe.command.Argument(
84 name='id', metavar='BUG-ID', optional=True,
85 completion_callback=libbe.command.util.complete_bug_id),
86 libbe.command.Argument(
87 name='target', metavar='TARGET', optional=True,
88 completion_callback=complete_target),
91 def _run(self, **params):
92 if params['resolve'] == False:
93 if params['id'] == None:
94 raise libbe.command.UserError('Please specify a bug id.')
96 if params['target'] != None:
97 raise libbe.command.UserError('Too many arguments')
98 params['target'] = params.pop('id')
99 bugdirs = self._get_bugdirs()
100 if params['resolve'] == True:
102 bugdir = bugdirs[bugdir]
103 elif len(bugdirs) == 1:
104 bugdir = bugdirs.values()[0]
106 raise libbe.command.UserError(
107 'Ambiguous bugdir {}'.format(sorted(bugdirs.values())))
108 bug = bug_from_target_summary(bugdirs, bugdir, params['target'])
110 print >> self.stdout, 'No target assigned.'
112 print >> self.stdout, bug.uuid
114 bugdir,bug,comment = (
115 libbe.command.util.bugdir_bug_comment_from_user_id(
116 bugdirs, params['id']))
117 if params['target'] == None:
118 target = bug_target(bugdirs, bug)
120 print >> self.stdout, 'No target assigned.'
122 print >> self.stdout, target.summary
124 if params['target'] == 'none':
125 target = remove_target(bugdirs, bug)
127 target = add_target(bugdirs, bugdir, bug, params['target'])
131 return 'usage: be %(name)s BUG-ID [TARGET]\nor: be %(name)s --resolve [TARGET]' \
132 % vars(self.__class__)
134 def _long_help(self):
136 Assorted bug target manipulations and queries.
138 If no target is specified, the bug's current target is printed. If
139 TARGET is specified, it will be assigned to the bug, creating a new
140 target bug if necessary.
142 Targets are free-form; any text may be specified. They will generally
143 be milestone names or release numbers. The value "none" can be used
146 In the alternative `be target --resolve TARGET` form, print the UUID
147 of the target-bug with summary TARGET. If target is not given, return
148 use the bugdir's current target (see `be set`).
150 If you want to list all bugs blocking the current target, try
151 $ be depend --status -closed,fixed,wontfix --severity -target \
152 $(be target --resolve)
154 If you want to set the current bugdir target by summary (rather than
156 $ be set target $(be target --resolve SUMMARY)
159 def bug_from_target_summary(bugdirs, bugdir, summary=None):
161 if bugdir.target == None:
164 return bugdir.bug_from_uuid(bugdir.target)
166 for uuid in bugdir.uuids():
167 bug = bugdir.bug_from_uuid(uuid)
168 if bug.severity == 'target' and bug.summary == summary:
170 if len(matched) == 0:
173 raise Exception('Several targets with same summary: %s'
174 % '\n '.join([bug.uuid for bug in matched]))
177 def bug_target(bugdirs, bug):
178 if bug.severity == 'target':
181 for blocked in libbe.command.depend.get_blocks(bugdirs, bug):
182 if blocked.severity == 'target':
183 matched.append(blocked)
184 if len(matched) == 0:
187 raise Exception('This bug (%s) blocks several targets: %s'
189 '\n '.join([b.uuid for b in matched])))
192 def remove_target(bugdirs, bug):
193 target = bug_target(bugdirs, bug)
194 libbe.command.depend.remove_block(target, bug)
197 def add_target(bugdirs, bugdir, bug, summary):
198 target = bug_from_target_summary(bugdirs, bugdir, summary)
200 target = bugdir.new_bug(summary=summary)
201 target.severity = 'target'
202 libbe.command.depend.add_block(target, bug)
205 def targets(bugdirs):
206 """Generate all possible target bug summaries."""
207 for bugdir in bugdirs.values():
208 bugdir.load_all_bugs()
210 if bug.severity == 'target':
213 def target_dict(bugdirs):
215 Return a dict with bug UUID keys and bug summary values for all
219 for bug in targets(bugdirs):
223 def complete_target(command, argument, fragment=None):
224 """List possible command completions for fragment."""
225 return targets(command._get_bugdirs())