aboutsummaryrefslogtreecommitdiffstats
path: root/libbe/ui
diff options
context:
space:
mode:
authorW. Trevor King <wking@drexel.edu>2009-12-12 20:57:59 -0500
committerW. Trevor King <wking@drexel.edu>2009-12-12 20:57:59 -0500
commitdff6bd9bf89ca80e2265696a478e540476718c9c (patch)
tree230f35262808052839ae2401d99cdf23cc304f20 /libbe/ui
parent86f886399813d37f3cfcf74a824d352e01eb0d8c (diff)
downloadbugseverywhere-dff6bd9bf89ca80e2265696a478e540476718c9c.tar.gz
Moved be to libbe.ui.command_line and transitioned to Command format.
Diffstat (limited to 'libbe/ui')
-rw-r--r--libbe/ui/base.py1
-rwxr-xr-xlibbe/ui/command_line.py270
-rw-r--r--libbe/ui/util/cmdutil.py108
3 files changed, 271 insertions, 108 deletions
diff --git a/libbe/ui/base.py b/libbe/ui/base.py
index e69de29..b98f164 100644
--- a/libbe/ui/base.py
+++ b/libbe/ui/base.py
@@ -0,0 +1 @@
+# Copyright
diff --git a/libbe/ui/command_line.py b/libbe/ui/command_line.py
new file mode 100755
index 0000000..e84d32a
--- /dev/null
+++ b/libbe/ui/command_line.py
@@ -0,0 +1,270 @@
+# Copyright (C) 2005-2009 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>
+#
+# 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 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.
+#
+# 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.
+
+"""
+A command line interface to Bugs Everywhere.
+"""
+
+import optparse
+import os
+import sys
+
+import libbe
+import libbe.command
+import libbe.command.util
+import libbe.version
+import libbe.ui.util.pager
+
+if libbe.TESTING == True:
+ import doctest
+
+class CallbackExit (Exception):
+ pass
+
+class CmdOptionParser(optparse.OptionParser):
+ def __init__(self, command):
+ self.command = command
+ optparse.OptionParser.__init__(self)
+ self.disable_interspersed_args()
+ self.remove_option('-h')
+ self._option_by_name = {}
+ for option in self.command.options:
+ self._add_option(option)
+
+ def _add_option(self, option):
+ option.validate()
+ self._option_by_name[option.name] = option
+ opt_strings = ['--'+option.name]
+ if option.short_name != None:
+ opt_strings.append('-'+option.short_name)
+ if option.arg == None: # a callback option
+ opt = optparse.Option(
+ *opt_strings, action='callback',
+ callback=self.callback, help=option.help)
+ else:
+ kwargs = {}
+ if option.arg.type == 'bool':
+ action = 'store_true'
+ else:
+ kwargs['type'] = option.arg.type
+ action = 'store'
+ opt = optparse.Option(
+ *opt_strings, metavar=option.arg.metavar,
+ default=option.arg.default, action=action,
+ help=option.help, **kwargs)
+ opt._option = option
+ self.add_option(opt)
+
+ def parse_args(self, args=None, values=None):
+ args = self._get_args(args)
+ options,parsed_args = optparse.OptionParser.parse_args(
+ self, args=args, values=values)
+ for name,value in options.__dict__.items():
+ 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']
+ for i in indices:
+ assert i > 0 # this --complete is an option value
+ if args[i-1] in ['--%s' % o.name
+ for o in self.command.options]:
+ name = args[i-1][2:]
+ if name == option.name:
+ break
+ elif option.short_name != None \
+ and args[i-1].startswith('-') \
+ and args[i-1].endswith(option.short_name):
+ break
+ if i+1 < len(args):
+ fragment = args[i+1]
+ self.complete(argument, fragment)
+ for i,arg in enumerate(parsed_args):
+ if arg == '--complete':
+ if i < len(self.command.args):
+ argument = self.command.args[i]
+ else:
+ argument = self.command.args[-1]
+ if argument.repeatable == False:
+ raise libbe.command.UserError('Too many arguments')
+ fragment = None
+ if i < len(args) - 1:
+ fragment = args[i+1]
+ self.complete(argument, fragment)
+ if len(parsed_args) > len(self.command.args) \
+ and self.command.args[-1] == 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)
+ return (options, parsed_args)
+
+ def callback(self, option, opt, value, parser):
+ command_option = option._option
+ if command_option.name == 'complete':
+ argument = None
+ fragment = None
+ if len(parser.rargs) > 0:
+ fragment = parser.rargs[0]
+ self.complete(argument, fragment)
+ else:
+ print command_option.callback(
+ self.command, command_option, value)
+ raise CallbackExit
+
+ def complete(self, argument=None, fragment=None):
+ print argument, fragment
+ comps = self.command.complete(argument, fragment)
+ if fragment != None:
+ comps = [c for c in comps if c.startswith(fragment)]
+ print '\n'.join(comps)
+ raise CallbackExit
+
+
+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
+ module's main() function instead.
+
+ >>> be = BE()
+ >>> p = CmdOptionParser(be)
+ >>> p.exit_after_callback = False
+ >>> try:
+ ... options,args = p.parse_args(['--help']) # doctest: +ELLIPSIS
+ ... except CallbackExit:
+ ... pass
+ usage: be [options] [COMMAND [command-options] [COMMAND-ARGS ...]]
+ <BLANKLINE>
+ Options:
+ -h HELP, --help=HELP Print a help message.
+ <BLANKLINE>
+ --complete=STRING Print a list of possible completions.
+ <BLANKLINE>
+ --version=VERSION Print version string.
+ ...
+ >>> options,args = p.parse_args(['--complete']) # doctest: +ELLIPSIS
+ """
+ name = 'be'
+
+ def __init__(self, *args, **kwargs):
+ libbe.command.Command.__init__(self, *args, **kwargs)
+ self.options.extend([
+ libbe.command.Option(name='version',
+ help='Print version string.',
+ callback=self.version),
+ libbe.command.Option(name='full-version',
+ help='Print full version information.',
+ callback=self.full_version),
+ libbe.command.Option(name='repo', short_name='r',
+ help='Select BE repository (see `be help repo`) rather '
+ 'than the current directory.',
+ arg=libbe.command.Argument(
+ name='repo', metavar='REPO', default='.',
+ completion_callback=libbe.command.util.complete_path)),
+ libbe.command.Option(name='paginate',
+ help='Pipe all output into less (or if set, $PAGER).'),
+ libbe.command.Option(name='no-pager',
+ help='Do not pipe git output into a pager.'),
+ ])
+ self.args.extend([
+ libbe.command.Argument(
+ name='command', optional=False,
+ completion_callback=libbe.command.util.complete_command),
+ libbe.command.Argument(
+ name='args', optional=True, repeatable=True)
+ ])
+
+ def _usage(self):
+ return 'usage: be [options] [COMMAND [command-options] [COMMAND-ARGS ...]]'
+
+ def _long_help(self):
+ cmdlist = []
+ for name in libbe.command.commands():
+ module = libbe.command.get_command(name)
+ Class = getattr(module, name.capitalize())
+ cmdlist.append((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']
+ 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.'])
+ return '\n'.join(ret)
+
+ def version(self, *args):
+ return libbe.version.version(verbose=False)
+
+ def full_version(self, *args):
+ return libbe.version.version(verbose=True)
+
+def main():
+ parser = CmdOptionParser(BE())
+ try:
+ options,args = parser.parse_args()
+ except CallbackExit:
+ return 0
+ except libbe.command.UserError, e:
+ print 'ERROR:\n', e
+ return 1
+
+ paginate = 'auto'
+ if options.paginate == True:
+ paginate = 'always'
+ if options.no_pager== True:
+ paginate = 'never'
+ libbe.ui.util.pager.run_pager(paginate)
+
+ command_name = args[0]
+ try:
+ module = libbe.command.get_command(command_name)
+ except libbe.command.UnknownCommand, e:
+ print e
+ return 1
+ Class = getattr(module, command_name.capitalize())
+ command = Class()
+ parser = CmdOptionParser(command)
+ if command.requires_bugdir == True:
+ storage = libbe.storage.get_storage(options['repo'])
+ storage.connect()
+ bugdir = BugDir(storage)
+ else:
+ storage = None
+ bugdir = None
+ try:
+ options,args = parser.parse_args(args[1:])
+ command.run(bugdir, options, args)
+ except CallbackExit:
+ if storage != None: storage.disconnect()
+ return 0
+ except libbe.command.UserError, e:
+ if storage != None: storage.disconnect()
+ print 'ERROR:\n', e
+ return 1
+ if storage != None: storage.disconnect()
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/libbe/ui/util/cmdutil.py b/libbe/ui/util/cmdutil.py
index b2d8a99..86ff9fc 100644
--- a/libbe/ui/util/cmdutil.py
+++ b/libbe/ui/util/cmdutil.py
@@ -55,115 +55,7 @@ def execute(cmd, args,
ret = 0
return ret
-class GetHelp(Exception):
- pass
-
-
-class GetCompletions(Exception):
- def __init__(self, completions=[]):
- msg = "Get allowed completions"
- Exception.__init__(self, msg)
- self.completions = completions
-
-def raise_get_help(option, opt, value, parser):
- raise GetHelp
-
-def raise_get_completions(option, opt, value, parser):
- if hasattr(parser, "command") and parser.command == "be":
- comps = []
- for command, module in iter_commands():
- comps.append(command)
- for opt in parser.option_list:
- comps.append(opt.get_opt_string())
- raise GetCompletions(comps)
- raise GetCompletions(completions(sys.argv[1]))
-
-def completions(cmd):
- parser = get_command(cmd).get_parser()
- longopts = []
- for opt in parser.option_list:
- longopts.append(opt.get_opt_string())
- return longopts
-
-
-class CmdOptionParser(optparse.OptionParser):
- def __init__(self, usage):
- optparse.OptionParser.__init__(self, usage)
- self.disable_interspersed_args()
- self.remove_option("-h")
- self.add_option("-h", "--help", action="callback",
- callback=raise_get_help, help="Print a help message")
- self.add_option("--complete", action="callback",
- callback=raise_get_completions,
- help="Print a list of available completions")
-
- def error(self, message):
- raise UsageError(message)
-
- def iter_options(self):
- return iter_combine([self._short_opt.iterkeys(),
- self._long_opt.iterkeys()])
-
- def help_str(self):
- f = StringIO()
- self.print_help(f)
- return f.getvalue()
-
-def option_value_pairs(options, parser):
- """
- Iterate through OptionParser (option, value) pairs.
- """
- for option in [o.dest for o in parser.option_list if o.dest != None]:
- value = getattr(options, option)
- yield (option, value)
-def default_complete(options, args, parser, bugid_args={}):
- """
- A dud complete implementation for becommands so that the
- --complete argument doesn't cause any problems. Use this
- until you've set up a command-specific complete function.
-
- bugid_args is an optional dict where the keys are positional
- arguments taking bug shortnames and the values are functions for
- filtering, since that's a common enough operation.
- e.g. for "be open [options] BUGID"
- bugid_args = {0: lambda bug : bug.active == False}
- A positional argument of -1 specifies all remaining arguments
- (e.g in the case of "be show BUGID BUGID ...").
- """
- for option,value in option_value_pairs(options, parser):
- if value == "--complete":
- raise GetCompletions()
- if len(bugid_args.keys()) > 0:
- max_pos_arg = max(bugid_args.keys())
- else:
- max_pos_arg = -1
- for pos,value in enumerate(args):
- if value == "--complete":
- filter = None
- if pos in bugid_args:
- filter = bugid_args[pos]
- if pos > max_pos_arg and -1 in bugid_args:
- filter = bugid_args[-1]
- if filter != None:
- bugshortnames = []
- try:
- bd = bugdir.BugDir(from_disk=True,
- manipulate_encodings=False)
- bd.load_all_bugs()
- bugs = [bug for bug in bd if filter(bug) == True]
- bugshortnames = [bd.bug_shortname(bug) for bug in bugs]
- except bugdir.NoBugDir:
- pass
- raise GetCompletions(bugshortnames)
- raise GetCompletions()
-
-def complete_path(path):
- """List possible path completions for path."""
- comps = glob.glob(path+"*") + glob.glob(path+"/*")
- if len(comps) == 1 and os.path.isdir(comps[0]):
- comps.extend(glob.glob(comps[0]+"/*"))
- return comps
def restrict_file_access(bugdir, path):