From 57ad5fee820c133ea64ed68c42a89cc4ae6c4336 Mon Sep 17 00:00:00 2001 From: Xibo Ning Date: Apr 28 2016 13:33:30 +0000 Subject: structural help, categorize commands into groups --- diff --git a/cli/koji b/cli/koji index 3744db4..958c6ad 100755 --- a/cli/koji +++ b/cli/koji @@ -121,14 +121,45 @@ def arg_filter(arg): #handle lists/dicts? return arg +categories = { + 'admin' : 'admin commands', + 'build' : 'build commands', + 'search' : 'search commands', + 'download' : 'download commands', + 'monitor' : 'monitor commands', + 'info' : 'info commands', + 'bind' : 'bind commands', + 'misc' : 'miscellaneous commands', +} + +def get_epilog_str(progname=None): + if progname is None: + progname = os.path.basename(sys.argv[0]) or 'koji' + categories_ordered=', '.join(sorted(['all'] + categories.keys())) + epilog_str = ''' +Try "%(progname)s --help" for help about global options +Try "%(progname)s help" to get all available commands +Try "%(progname)s --help" for help about the options of a particular command +Try "%(progname)s help " to get commands under a particular category +Available categories are: %(categories)s +''' % ({'progname': progname, 'categories': categories_ordered}) + return _(epilog_str) def get_options(): """process options from command line and config file""" - usage = _("%prog [global-options] command [command-options-and-arguments]") + common_commands = ['build', 'help', 'download-build', + 'latest-pkg', 'search', 'list-targets'] + usage = _("%%prog [global-options] command [command-options-and-arguments]" + "\n\nCommon commands: %s" % ', '.join(sorted(common_commands))) parser = OptionParser(usage=usage) parser.disable_interspersed_args() progname = os.path.basename(sys.argv[0]) or 'koji' + parser.__dict__['origin_format_help'] = parser.format_help + parser.__dict__['format_help'] = lambda formatter=None: ( + "%(origin_format_help)s%(epilog)s" % ({ + 'origin_format_help': parser.origin_format_help(formatter), + 'epilog': get_epilog_str()})) parser.add_option("-c", "--config", dest="configFile", help=_("use alternate configuration file"), metavar="FILE") parser.add_option("-p", "--profile", default=progname, @@ -835,7 +866,7 @@ def _running_in_bg(): return False def handle_build(options, session, args): - "Build a package from source" + "[build] Build a package from source" usage = _("usage: %prog build [options] target ") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -912,7 +943,7 @@ def handle_build(options, session, args): def handle_chain_build(options, session, args): # XXX - replace handle_build with this, once chain-building has gotten testing - "Build one or more packages from source" + "[build] Build one or more packages from source" usage = _("usage: %prog chain-build [options] target URL [URL2 [:] URL3 [:] URL4 ...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -986,7 +1017,7 @@ def handle_chain_build(options, session, args): return watch_tasks(session,[task_id],quiet=options.quiet) def handle_maven_build(options, session, args): - "Build a Maven package from source" + "[build] Build a Maven package from source" usage = _("usage: %prog maven-build [options] target URL") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -1082,7 +1113,7 @@ def handle_maven_build(options, session, args): return watch_tasks(session,[task_id],quiet=options.quiet) def handle_wrapper_rpm(options, session, args): - """Build wrapper rpms for any archives associated with a build.""" + """[build] Build wrapper rpms for any archives associated with a build.""" usage = _("usage: %prog wrapper-rpm [options] target build-id|n-v-r URL") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -1148,7 +1179,7 @@ def handle_wrapper_rpm(options, session, args): return watch_tasks(session,[task_id],quiet=options.quiet) def handle_maven_chain(options, session, args): - "Run a set of Maven builds in dependency order" + "[build] Run a set of Maven builds in dependency order" usage = _("usage: %prog maven-chain [options] target config...") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -1200,7 +1231,7 @@ def handle_maven_chain(options, session, args): return watch_tasks(session, [task_id], quiet=options.quiet) def handle_resubmit(options, session, args): - """Retry a canceled or failed task, using the same parameter as the original task.""" + """[build] Retry a canceled or failed task, using the same parameter as the original task.""" usage = _("usage: %prog resubmit [options] taskID") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -1227,7 +1258,7 @@ def handle_resubmit(options, session, args): return watch_tasks(session, [newID], quiet=options.quiet) def handle_call(options, session, args): - "[admin] Execute an arbitrary XML-RPC call" + "Execute an arbitrary XML-RPC call" usage = _("usage: %prog call [options] name [arg...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -1259,7 +1290,7 @@ def handle_call(options, session, args): pprint.pprint(getattr(session, name).__call__(*non_kw, **kw)) def anon_handle_mock_config(options, session, args): - "Create a mock config" + "[info] Create a mock config" usage = _("usage: %prog mock-config [options]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -2183,7 +2214,7 @@ def handle_add_volume(options, session, args): print "Added volume %(name)s with id %(id)i" % volinfo def handle_list_volumes(options, session, args): - "List storage volumes" + "[info] List storage volumes" usage = _("usage: %prog list-volumes") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -2555,7 +2586,7 @@ def handle_revoke_cg_access(options, session, args): def anon_handle_latest_build(options, session, args): - "Print the latest builds for a tag" + "[info] Print the latest builds for a tag" usage = _("usage: %prog latest-build [options] tag package [package...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -2629,7 +2660,7 @@ def anon_handle_latest_build(options, session, args): def anon_handle_list_api(options, session, args): - "Print the list of XML-RPC APIs" + "[info] Print the list of XML-RPC APIs" usage = _("usage: %prog list-api [options]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -2660,7 +2691,7 @@ def anon_handle_list_api(options, session, args): print " description: %s" % x['doc'] def anon_handle_list_tagged(options, session, args): - "List the builds or rpms in a tag" + "[info] List the builds or rpms in a tag" usage = _("usage: %prog list-tagged [options] tag [package]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -2761,7 +2792,7 @@ def anon_handle_list_tagged(options, session, args): print line def anon_handle_list_buildroot(options, session, args): - "List the rpms used in or built in a buildroot" + "[info] List the rpms used in or built in a buildroot" usage = _("usage: %prog list-buildroot [options] buildroot-id") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -2791,7 +2822,7 @@ def anon_handle_list_buildroot(options, session, args): print nvra def anon_handle_list_untagged(options, session, args): - "List untagged builds" + "[info] List untagged builds" usage = _("usage: %prog list-untagged [options] [package]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -2847,7 +2878,7 @@ def print_group_list_req_package(pkg): print " %(package)s: %(basearchonly)s, %(type)s [%(tag_name)s]" % pkg def anon_handle_list_groups(options, session, args): - "Print the group listings" + "[info] Print the group listings" usage = _("usage: %prog list-groups [options] [group]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -2975,7 +3006,7 @@ def handle_unblock_group_req(options, session, args): session.groupReqListUnblock(tag, group, req) def anon_handle_list_hosts(options, session, args): - "Print the host listing" + "[info] Print the host listing" usage = _("usage: %prog list-hosts [options]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -3030,7 +3061,7 @@ def anon_handle_list_hosts(options, session, args): print "%(name)-28s %(enabled)-3s %(ready)-3s %(task_load)4.1f/%(capacity)-3.1f %(arches)-16s %(update)s" % host def anon_handle_list_pkgs(options, session, args): - "Print the package listing for tag or for owner" + "[info] Print the package listing for tag or for owner" usage = _("usage: %prog list-pkgs [options]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -3107,7 +3138,7 @@ def anon_handle_list_pkgs(options, session, args): print fmt % pkg def anon_handle_rpminfo(options, session, args): - "Print basic information about an RPM" + "[info] Print basic information about an RPM" usage = _("usage: %prog rpminfo [options] [ ...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -3173,7 +3204,7 @@ def anon_handle_rpminfo(options, session, args): def anon_handle_buildinfo(options, session, args): - "Print basic information about a build" + "[info] Print basic information about a build" usage = _("usage: %prog buildinfo [options] [ ...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -3639,7 +3670,7 @@ def handle_remove_tag(options, session, args): session.deleteTag(tag_info['id']) def anon_handle_list_targets(options, session, args): - "List the build targets" + "[info] List the build targets" usage = _("usage: %prog list-targets [options]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -3703,7 +3734,7 @@ def _printInheritance(tags, sibdepths=None, reverse=False): _printInheritance(tags, sibdepths, reverse) def anon_handle_list_tag_inheritance(options, session, args): - "Print the inheritance information for a tag" + "[info] Print the inheritance information for a tag" usage = _("usage: %prog list-tag-inheritance [options] ") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -3758,7 +3789,7 @@ def anon_handle_list_tag_inheritance(options, session, args): _printInheritance(data, None, opts['reverse']) def anon_handle_list_tags(options, session, args): - "Print the list of tags" + "[info] Print the list of tags" usage = _("usage: %prog list-tags [options] [pattern]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -3814,7 +3845,7 @@ def anon_handle_list_tags(options, session, args): print '' def anon_handle_list_tag_history(options, session, args): - "Print a history of tag operations" + "[info] Print a history of tag operations" usage = _("usage: %prog list-tag-history [options]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -4085,7 +4116,7 @@ _table_keys = { } def anon_handle_list_history(options, session, args): - "Display historical data" + "[info] Display historical data" usage = _("usage: %prog list-history [options]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -4420,7 +4451,7 @@ def _printTaskInfo(session, task_id, level=0, recurse=True, verbose=True): _printTaskInfo(session, child['id'], level, verbose=verbose) def anon_handle_taskinfo(options, session, args): - """Show information about a task""" + """[info] Show information about a task""" usage = _("usage: %prog taskinfo [options] taskID [taskID...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -4438,7 +4469,7 @@ def anon_handle_taskinfo(options, session, args): _printTaskInfo(session, task_id, 0, options.recurse, options.verbose) def anon_handle_taginfo(options, session, args): - "Print basic information about a tag" + "[info] Print basic information about a tag" usage = _("usage: %prog taginfo [options] [ ...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -4921,7 +4952,7 @@ def handle_remove_tag_inheritance(options, session, args): session.setInheritanceData(tag['id'], inheritanceData) def anon_handle_show_groups(options, session, args): - "Show groups data for a tag" + "[info] Show groups data for a tag" usage = _("usage: %prog show-groups [options] ") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -4944,7 +4975,7 @@ def anon_handle_show_groups(options, session, args): pprint.pprint(groups) def anon_handle_list_external_repos(options, session, args): - "List external repos" + "[info] List external repos" usage = _("usage: %prog list-external-repos [options]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -5142,7 +5173,7 @@ def handle_remove_external_repo(options, session, args): # This handler is for spinning livecd images # def handle_spin_livecd(options, session, args): - """[admin] Create a live CD image given a kickstart file""" + """[build] Create a live CD image given a kickstart file""" # Usage & option parsing. usage = _("usage: %prog spin-livecd [options] " + @@ -5186,7 +5217,7 @@ def handle_spin_livecd(options, session, args): # This handler is for spinning appliance images # def handle_spin_appliance(options, session, args): - """[admin] Create an appliance given a kickstart file""" + """[build] Create an appliance given a kickstart file""" # Usage & option parsing usage = _("usage: %prog spin-appliance [options] " + @@ -5239,7 +5270,7 @@ def handle_spin_appliance(options, session, args): _build_image(options, task_options, session, args, 'appliance') def handle_image_build_indirection(options, session, args): - """Create a disk image using other disk images via the Indirection plugin""" + """[build] Create a disk image using other disk images via the Indirection plugin""" usage = _("usage: %prog image-build-indirection [base_image] " + "[utility_image] [indirection_build_template]") usage += _("\n %prog image-build --config FILE") @@ -5383,7 +5414,7 @@ def _build_image_indirection(options, task_opts, session, args): def handle_image_build(options, session, args): - """Create a disk image given an install tree""" + """[build] Create a disk image given an install tree""" formats = ('vmdk', 'qcow', 'qcow2', 'vdi', 'vpc', 'rhevm-ova', 'vsphere-ova', 'vagrant-virtualbox', 'vagrant-libvirt', 'vagrant-vmware-fusion', 'docker', 'raw-xz', @@ -5634,7 +5665,7 @@ def _build_image_oz(options, task_opts, session, args): return def handle_win_build(options, session, args): - """Build a Windows package from source""" + """[build] Build a Windows package from source""" # Usage & option parsing usage = _("usage: %prog win-build [options] target URL VM") usage += _("\n(Specify the --help global option for a list of other " + @@ -5728,7 +5759,7 @@ def handle_free_task(options, session, args): session.freeTask(task_id) def handle_cancel(options, session, args): - "Cancel tasks and/or builds" + "[build] Cancel tasks and/or builds" usage = _("usage: %prog cancel [options] [ ...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -5846,7 +5877,7 @@ def _list_tasks(options, session): def handle_list_tasks(options, session, args): - "Print the list of tasks" + "[info] Print the list of tasks" usage = _("usage: %prog list-tasks [options]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -5969,7 +6000,7 @@ def handle_set_pkg_owner_global(options, session, args): session.packageListSetOwner(entry['tag_id'], entry['package_name'], user['id']) def anon_handle_watch_task(options, session, args): - "Track progress of particular tasks" + "[monitor] Track progress of particular tasks" usage = _("usage: %prog watch-task [options] [...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -6010,7 +6041,7 @@ def anon_handle_watch_task(options, session, args): return watch_tasks(session, tasks, quiet=options.quiet) def anon_handle_watch_logs(options, session, args): - "Watch logs in realtime" + "[monitor] Watch logs in realtime" usage = _("usage: %prog watch-logs [options] [...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -6057,7 +6088,7 @@ def handle_make_task(opts, session, args): return watch_tasks(session, [task_id], quiet=opts.quiet) def handle_tag_build(opts, session, args): - "Apply a tag to one or more builds" + "[bind] Apply a tag to one or more builds" usage = _("usage: %prog tag-build [options] [...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -6081,7 +6112,7 @@ def handle_tag_build(opts, session, args): return watch_tasks(session,tasks,quiet=opts.quiet) def handle_move_build(opts, session, args): - "'Move' one or more builds between tags" + "[bind] 'Move' one or more builds between tags" usage = _("usage: %prog move-build [options] [...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -6127,7 +6158,7 @@ def handle_move_build(opts, session, args): return watch_tasks(session, tasks, quiet=opts.quiet) def handle_untag_build(options, session, args): - "Remove a tag from one or more builds" + "[bind] Remove a tag from one or more builds" usage = _("usage: %prog untag-build [options] [...]") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -6212,7 +6243,7 @@ def handle_unblock_pkg(options, session, args): session.packageListUnblock(tag,package) def anon_handle_download_build(options, session, args): - "Download a built package" + "[download] Download a built package" usage = _("usage: %prog download-build [options] ") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -6348,7 +6379,7 @@ def anon_handle_download_build(options, session, args): def anon_handle_download_logs(options, session, args): - "Download a logs for package" + "[download] Download a logs for package" FAIL_LOG = "task_failed.log" usage = _("usage: %prog download-logs [options] [ ...]") @@ -6465,7 +6496,7 @@ def anon_handle_download_logs(options, session, args): def anon_handle_download_task(options, session, args): - "Download the output of a build task " + "[download] Download the output of a build task " usage = _("usage: %prog download-task ") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -6541,7 +6572,7 @@ def anon_handle_download_task(options, session, args): output_file.close() def anon_handle_wait_repo(options, session, args): - "Wait for a repo to be regenerated" + "[monitor] Wait for a repo to be regenerated" usage = _("usage: %prog wait-repo [options] ") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) @@ -6679,7 +6710,7 @@ def handle_regen_repo(options, session, args): return watch_tasks(session, [task_id], quiet=options.quiet) def anon_handle_search(options, session, args): - "Search the system" + "[search] Search the system" usage = _("usage: %prog search [options] search_type pattern") usage += _('\nAvailable search types: %s') % ', '.join(_search_types) usage += _("\n(Specify the --help global option for a list of other help options)") @@ -6704,7 +6735,7 @@ def anon_handle_search(options, session, args): print row['name'] def handle_moshimoshi(options, session, args): - "Introduce yourself" + "[misc] Introduce yourself" usage = _("usage: %prog moshimoshi [options]") parser = OptionParser(usage=usage) (opts, args) = parser.parse_args(args) @@ -6798,16 +6829,36 @@ def handle_runroot(options, session, args): def handle_help(options, session, args): - "List available commands" - usage = _("usage: %prog help [options]") + "[info] List available commands" + usage = _("usage: %prog help ...") usage += _("\n(Specify the --help global option for a list of other help options)") parser = OptionParser(usage=usage) - parser.add_option("--admin", action="store_true", help=_("show admin commands")) + # the --admin opt is for backwards compatibility. It is equivalent to: koji help admin + parser.add_option("--admin", action="store_true", help=optparse.SUPPRESS_HELP) + (options, args) = parser.parse_args(args) - list_commands(show_admin=options.admin) + + chosen = set(args) + if options.admin: + chosen.add('admin') + avail = set(categories.keys() + ['all']) + unavail = chosen - avail + for arg in unavail: + print "No such help category: %s" % arg + + if not chosen: + list_commands() + else: + list_commands(chosen) -def list_commands(show_admin=False): +def list_commands(categories_chosen=None): + if categories_chosen is None or "all" in categories_chosen: + categories_chosen = categories.keys() + else: + # copy list since we're about to modify it + categories_chosen = list(categories_chosen) + categories_chosen.sort() handlers = [] for name,value in globals().items(): if name.startswith('handle_'): @@ -6820,17 +6871,17 @@ def list_commands(show_admin=False): handlers.append((alias,value)) handlers.sort() print _("Available commands:") - for alias,handler in handlers: - desc = handler.__doc__ - if desc.startswith('[admin] '): - if not show_admin: + for category in categories_chosen: + print _("\n%s:" % categories[category]) + for alias,handler in handlers: + desc = handler.__doc__ + if desc.startswith('[%s] ' % category): + desc = desc[len('[%s] ' % category):] + elif category != 'misc' or desc.startswith('['): continue - desc = desc[8:] - print " %-25s %s" % (alias, desc) - progname = os.path.basename(sys.argv[0]) or 'koji' - print _('(Type "%s --help" for help about global options') % progname - print _(' or "%s --help" for help about a particular command\'s options') % progname - print _(' or "%s help --admin" for help about privileged administrative commands.)') % progname + print " %-25s %s" % (alias, desc) + + print("%s" % get_epilog_str().rstrip("\n")) def error(msg=None, code=1): if msg: