-# Copyright (C) 2005-2010 Aaron Bentley and Panometrics, Inc.
-# Chris Ball <cjb@laptop.org>
-# Gianluca Montecchi <gian@grys.it>
-# Oleg Romanyshyn <oromanyshyn@panoramicfeedback.com>
-# W. Trevor King <wking@drexel.edu>
+# Copyright (C) 2009-2012 Chris Ball <cjb@laptop.org>
+# W. Trevor King <wking@tremily.us>
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
+# This file is part of Bugs Everywhere.
#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
+# Bugs Everywhere is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 2 of the License, or (at your option) any
+# later version.
#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+# Bugs Everywhere is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Bugs Everywhere. If not, see <http://www.gnu.org/licenses/>.
"""
A command line interface to Bugs Everywhere.
import optparse
import os
import sys
+import locale
import libbe
import libbe.bugdir
import libbe.command
+import libbe.command.help
import libbe.command.util
+import libbe.storage
import libbe.version
import libbe.ui.util.pager
+import libbe.util.encoding
+import libbe.util.http
+
if libbe.TESTING == True:
import doctest
if '_' in name: # reconstruct original option name
options[name.replace('_', '-')] = options.pop(name)
for name,value in options.items():
+ argument = None
+ option = self._option_by_name[name]
+ if option.arg != None:
+ argument = option.arg
if value == '--complete':
- argument = None
- option = self._option_by_name[name]
- if option.arg != None:
- argument = option.arg
fragment = None
indices = [i for i,arg in enumerate(args)
if arg == '--complete']
if i+1 < len(args):
fragment = args[i+1]
self.complete(argument, fragment)
+ elif argument is not None:
+ value = self.process_raw_argument(argument=argument, value=value)
+ options[name] = value
for i,arg in enumerate(parsed_args):
+ if i > 0 and self.command.name == 'be':
+ break # let this pass through for the command parser to handle
+ elif i < len(self.command.args):
+ argument = self.command.args[i]
+ elif len(self.command.args) == 0:
+ break # command doesn't take arguments
+ else:
+ argument = self.command.args[-1]
+ if argument.repeatable == False:
+ raise libbe.command.UserError('Too many arguments')
if arg == '--complete':
- if i > 0 and self.command.name == 'be':
- break # let this pass through for the command parser to handle
- elif i < len(self.command.args):
- argument = self.command.args[i]
- elif len(self.command.args) == 0:
- break # command doesn't take arguments
- else:
- argument = self.command.args[-1]
- if argument.repeatable == False:
- raise libbe.command.UserError('Too many arguments')
fragment = None
if i < len(parsed_args) - 1:
fragment = parsed_args[i+1]
self.complete(argument, fragment)
- if len(parsed_args) > len(self.command.args) \
- and self.command.args[-1].repeatable == False:
+ else:
+ value = self.process_raw_argument(argument=argument, value=arg)
+ parsed_args[i] = value
+ if (len(parsed_args) > len(self.command.args) and
+ (len(self.command.args) == 0 or
+ self.command.args[-1].repeatable == False)):
raise libbe.command.UserError('Too many arguments')
for arg in self.command.args[len(parsed_args):]:
if arg.optional == False:
- raise libbe.command.UserError(
- 'Missing required argument %s' % arg.metavar)
+ raise libbe.command.UsageError(
+ command=self.command,
+ message='Missing required argument %s' % arg.metavar)
return (options, parsed_args)
def callback(self, option, opt, value, parser):
print >> self.command.stdout, '\n'.join(comps)
raise CallbackExit
+ def process_raw_argument(self, argument, value):
+ if value == argument.default:
+ return value
+ if argument.type == 'string':
+ if not hasattr(self, 'argv_encoding'):
+ self.argv_encoding = libbe.util.encoding.get_argv_encoding()
+ return unicode(value, self.argv_encoding)
+ return value
+
+
class BE (libbe.command.Command):
"""Class for parsing the command line arguments for `be`.
This class does not contain a useful _run() method. Call this
... except CallbackExit:
... print ' got callback'
--help
- --complete
--version
...
subscribe
arg=libbe.command.Argument(
name='repo', metavar='REPO', default='.',
completion_callback=libbe.command.util.complete_path)),
+ libbe.command.Option(name='server', short_name='s',
+ help='Select BE command server (see `be help '
+ 'server`) rather than executing commands '
+ 'locally',
+ arg=libbe.command.Argument(
+ name='server', metavar='URL')),
libbe.command.Option(name='paginate',
help='Pipe all output into less (or if set, $PAGER).'),
libbe.command.Option(name='no-pager',
Class = libbe.command.get_command_class(command_name=name)
assert hasattr(Class, '__doc__') and Class.__doc__ != None, \
'Command class %s missing docstring' % Class
- cmdlist.append((name, Class.__doc__.splitlines()[0]))
+ cmdlist.append((Class.name, Class.__doc__.splitlines()[0]))
cmdlist.sort()
longest_cmd_len = max([len(name) for name,desc in cmdlist])
ret = ['Bugs Everywhere - Distributed bug tracking',
- '', 'Supported commands']
+ '', 'Commands:']
for name, desc in cmdlist:
numExtraSpaces = longest_cmd_len-len(name)
- ret.append('be %s%*s %s' % (name, numExtraSpaces, '', desc))
- ret.extend(['', 'Run', ' be help [command]', 'for more information.'])
+ ret.append('be {}{} {}'.format(name, ' '*numExtraSpaces, desc))
+
+ ret.extend(['', 'Topics:'])
+ topic_list = [
+ (name,desc.splitlines()[0])
+ for name,desc in sorted(libbe.command.help.TOPICS.items())]
+ longest_topic_len = max([len(name) for name,desc in topic_list])
+ for name,desc in topic_list:
+ extra_spaces = longest_topic_len - len(name)
+ ret.append('{}{} {}'.format(name, ' '*extra_spaces, desc))
+
+ ret.extend(['', 'Run', ' be help [command|topic]',
+ 'for more information.'])
return '\n'.join(ret)
def version(self, *args):
'See http://docs.python.org/library/locale.html for details',
])
return 1
+ except libbe.command.UsageError, e:
+ print >> ui.io.stdout, 'Usage Error:\n', e
+ if e.command:
+ print >> ui.io.stdout, e.command.usage()
+ print >> ui.io.stdout, 'For usage information, try'
+ print >> ui.io.stdout, ' be help %s' % e.command_name
+ return 1
except libbe.command.UserError, e:
print >> ui.io.stdout, 'ERROR:\n', e
return 1
+ except OSError, e:
+ print >> ui.io.stdout, 'OSError:\n', e
+ return 1
except libbe.storage.ConnectionError, e:
print >> ui.io.stdout, 'Connection Error:\n', e
return 1
+ except libbe.util.http.HTTPError, e:
+ print >> ui.io.stdout, 'HTTP Error:\n', e
+ return 1
except (libbe.util.id.MultipleIDMatches, libbe.util.id.NoIDMatches,
libbe.util.id.InvalidIDStructure), e:
print >> ui.io.stdout, 'Invalid id:\n', e
return ret
def main():
+ locale.setlocale(locale.LC_ALL, '')
io = libbe.command.StdInputOutput()
ui = CommandLine(io)
be = BE(ui=ui)
options,args = parser.parse_args()
except CallbackExit:
return 0
- except libbe.command.UserError, e:
- if str(e).endswith('COMMAND'):
+ except libbe.command.UsageError, e:
+ if isinstance(e.command, BE):
# no command given, print usage string
- print >> ui.io.stdout, 'ERROR:'
- print >> ui.io.stdout, be.usage(), '\n', e
+ print >> ui.io.stdout, 'Usage Error:\n', e
+ print >> ui.io.stdout, be.usage()
print >> ui.io.stdout, 'For example, try'
print >> ui.io.stdout, ' be help'
else:
- print >> ui.io.stdout, 'ERROR:\n', e
+ print >> ui.io.stdout, 'Usage Error:\n', e
+ if e.command:
+ print >> ui.io.stdout, e.command.usage()
+ print >> ui.io.stdout, 'For usage information, try'
+ print >> ui.io.stdout, ' be help %s' % e.command_name
return 1
command_name = args.pop(0)
return 1
ui.storage_callbacks = libbe.command.StorageCallbacks(options['repo'])
- command = Class(ui=ui)
+ command = Class(ui=ui, server=options['server'])
ui.setup_command(command)
- if command.name in ['comment', 'commit', 'import-xml', 'serve']:
+ if command.name in [
+ 'new', 'comment', 'commit', 'html', 'import-xml', 'serve-storage',
+ 'serve-commands']:
paginate = 'never'
else:
paginate = 'auto'
libbe.ui.util.pager.run_pager(paginate)
ret = dispatch(ui, command, args)
- ui.cleanup()
+ try:
+ ui.cleanup()
+ except IOError, e:
+ print >> ui.io.stdout, 'IOError:\n', e
+ return 1
+
return ret
if __name__ == '__main__':