[libvirt] [PATCH] [V1] virsh: Categorize commands into groups for virsh help output

Change the virsh help out. The new output of "virsh help" and "virsh --help" will be like: Secret: secret-define define or modify a secret from an XML file secret-dumpxml secret attributes in XML secret-set-value set a secret value secret-get-value Output a secret value secret-undefine undefine a secret secret-list list secrets Snapshot: snapshot-create Create a snapshot snapshot-current Get the current snapshot snapshot-delete Delete a domain snapshot snapshot-dumpxml Dump XML for a domain snapshot snapshot-list List snapshots for a domain snapshot-revert Revert a domain to a snapshot Also support output help information of specified command group, e.g. % ./tools/virsh help "Network Filter" Network Filter: nwfilter-define define or update a network filter from an XML file nwfilter-undefine undefine a network filter nwfilter-dumpxml network filter information in XML nwfilter-list list network filters nwfilter-edit edit XML configuration for a network filter * tools/virsh.c: - introduce new struct "vshCmdGrp" and macros to define the groups. - split previous array "commands" into small arrays which are orgnized by group - changed some functions, such as "vshCmdDefSearch" - the modifications doesn't affect tests * TODO: - the output format is still not nice, need improved. - the category of groups probly not reasonable and need improved. - need to update virsh.pod. - PO files. - do enough testing to ensure it doesn't break anything, because virsh is so important for end-users. :-) - not sure if it's fine of group name contains space, Because it need user to quote the whole group name when input. Probly we need some abstract group names for user. --- tools/virsh.c | 370 ++++++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 260 insertions(+), 110 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index b485eff..ee7fef6 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -127,6 +127,22 @@ typedef enum { } vshCmdOptType; /* + * Command group types + */ +#define VSH_CMD_GRP_DOM_MANAGEMENT "Domain Management" +#define VSH_CMD_GRP_DOM_MONITORING "Domain Monitoring" +#define VSH_CMD_GRP_STORAGE_POOL "Storage Pool" +#define VSH_CMD_GRP_STORAGE_VOL "Storage Volume" +#define VSH_CMD_GRP_NETWORK "Networking" +#define VSH_CMD_GRP_NODEDEV "Node Device" +#define VSH_CMD_GRP_IFACE "Interface" +#define VSH_CMD_GRP_NWFILTER "Network Filter" +#define VSH_CMD_GRP_SECRET "Secret" +#define VSH_CMD_GRP_SNAPSHOT "Snapshot" +#define VSH_CMD_GRP_HOST_AND_HV "Host and Hypervisor" +#define VSH_CMD_GRP_VIRSH "Virsh Itself" + +/* * Command Option Flags */ #define VSH_OFLAG_NONE 0 /* without flags */ @@ -203,8 +219,12 @@ typedef struct __vshControl { char *historyfile; /* readline history file name */ } __vshControl; +typedef struct vshCmdGrp { + const char *name; + const vshCmdDef *commands; +} vshCmdGrp; -static const vshCmdDef commands[]; +static const vshCmdGrp cmdGroups[]; static void vshError(vshControl *ctl, const char *format, ...) ATTRIBUTE_FMT_PRINTF(2, 3); @@ -219,7 +239,9 @@ static int vshParseArgv(vshControl *ctl, int argc, char **argv); static const char *vshCmddefGetInfo(const vshCmdDef *cmd, const char *info); static const vshCmdDef *vshCmddefSearch(const char *cmdname); +static const vshCmdGrp *vshCmdGrpSearch(const char *grpname); static int vshCmddefHelp(vshControl *ctl, const char *name); +static int vshCmdGrpHelp(vshControl *ctl, const char *name); static vshCmdOpt *vshCommandOpt(const vshCmd *cmd, const char *name); static int vshCommandOptInt(const vshCmd *cmd, const char *name, int *found); @@ -548,18 +570,37 @@ static const vshCmdOptDef opts_help[] = { static int cmdHelp(vshControl *ctl, const vshCmd *cmd) { - const char *cmdname = vshCommandOptString(cmd, "command", NULL); + const vshCmdDef *c; + const vshCmdGrp *g; + const char *name = vshCommandOptString(cmd, "command", NULL); - if (!cmdname) { + if (!name) { + const vshCmdGrp *grp; const vshCmdDef *def; - vshPrint(ctl, "%s", _("Commands:\n\n")); - for (def = commands; def->name; def++) - vshPrint(ctl, " %-15s %s\n", def->name, - _(vshCmddefGetInfo(def, "help"))); + vshPrint(ctl, "%s", _("Grouped commands:\n\n")); + + for (grp = cmdGroups; grp->name; grp++) { + vshPrint(ctl, " %s:\n", grp->name); + + for (def = grp->commands; def->name; def++) + vshPrint(ctl, " %-30s %s\n", def->name, + _(vshCmddefGetInfo(def, "help"))); + + vshPrint(ctl, "\n"); + } + return TRUE; } - return vshCmddefHelp(ctl, cmdname); + + if ((c = vshCmddefSearch(name))) { + return vshCmddefHelp(ctl, name); + } else if ((g = vshCmdGrpSearch(name))) { + return vshCmdGrpHelp(ctl, name); + } else { + vshError(ctl, _("command or command group '%s' doesn't exist"), name); + return FALSE; + } } /* @@ -9807,27 +9848,17 @@ cleanup: return ret; } -/* - * Commands - */ -static const vshCmdDef commands[] = { - {"help", cmdHelp, opts_help, info_help}, +static const vshCmdDef domManagementCmds[] = { {"attach-device", cmdAttachDevice, opts_attach_device, info_attach_device}, {"attach-disk", cmdAttachDisk, opts_attach_disk, info_attach_disk}, {"attach-interface", cmdAttachInterface, opts_attach_interface, info_attach_interface}, {"autostart", cmdAutostart, opts_autostart, info_autostart}, - {"capabilities", cmdCapabilities, NULL, info_capabilities}, -#ifndef WIN32 - {"cd", cmdCd, opts_cd, info_cd}, -#endif - {"connect", cmdConnect, opts_connect, info_connect}, #ifndef WIN32 {"console", cmdConsole, opts_console, info_console}, #endif {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline}, {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare}, {"create", cmdCreate, opts_create, info_create}, - {"start", cmdStart, opts_start, info_start}, {"destroy", cmdDestroy, opts_destroy, info_destroy}, {"detach-device", cmdDetachDevice, opts_detach_device, info_detach_device}, {"detach-disk", cmdDetachDisk, opts_detach_disk, info_detach_disk}, @@ -9835,15 +9866,9 @@ static const vshCmdDef commands[] = { {"define", cmdDefine, opts_define, info_define}, {"domid", cmdDomid, opts_domid, info_domid}, {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid}, - {"dominfo", cmdDominfo, opts_dominfo, info_dominfo}, {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo}, {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort}, {"domname", cmdDomname, opts_domname, info_domname}, - {"domstate", cmdDomstate, opts_domstate, info_domstate}, - {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat}, - {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat}, - {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat}, - {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo}, {"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, info_domxmlfromnative}, {"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, info_domxmltonative}, {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml}, @@ -9855,11 +9880,85 @@ static const vshCmdDef commands[] = { opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as}, {"freecell", cmdFreecell, opts_freecell, info_freecell}, {"hostname", cmdHostname, NULL, info_hostname}, - {"list", cmdList, opts_list, info_list}, {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus}, {"migrate", cmdMigrate, opts_migrate, info_migrate}, {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime}, + {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave}, + {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, info_managedsaveremove}, + {"reboot", cmdReboot, opts_reboot, info_reboot}, + {"restore", cmdRestore, opts_restore, info_restore}, + {"resume", cmdResume, opts_resume, info_resume}, + {"save", cmdSave, opts_save, info_save}, + {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo}, + {"start", cmdStart, opts_start, info_start}, + {"dump", cmdDump, opts_dump, info_dump}, + {"shutdown", cmdShutdown, opts_shutdown, info_shutdown}, + {"setmem", cmdSetmem, opts_setmem, info_setmem}, + {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem}, + {"memtune", cmdMemtune, opts_memtune, info_memtune}, + {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus}, + {"suspend", cmdSuspend, opts_suspend, info_suspend}, + {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole}, + {"undefine", cmdUndefine, opts_undefine, info_undefine}, + {"update-device", cmdUpdateDevice, opts_update_device, info_update_device}, + {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount}, + {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo}, + {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin}, + {"version", cmdVersion, NULL, info_version}, + {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay}, + {NULL, NULL, NULL, NULL} +}; + +static const vshCmdDef domMonitoringCmds[] = { + {"dominfo", cmdDominfo, opts_dominfo, info_dominfo}, + {"domstate", cmdDomstate, opts_domstate, info_domstate}, + {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat}, + {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat}, + {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat}, + {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo}, + {"list", cmdList, opts_list, info_list}, + {NULL, NULL, NULL, NULL} +}; + +static const vshCmdDef storagePoolCmds[] = { + {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart}, + {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build}, + {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create}, + {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as}, + {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define}, + {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as}, + {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy}, + {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete}, + {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml}, + {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit}, + {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info}, + {"pool-list", cmdPoolList, opts_pool_list, info_pool_list}, + {"pool-name", cmdPoolName, opts_pool_name, info_pool_name}, + {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh}, + {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start}, + {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, info_pool_undefine}, + {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid}, + {NULL, NULL, NULL, NULL} +}; + +static const vshCmdDef storageVolCmds[] = { + {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create}, + {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, info_vol_create_from}, + {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as}, + {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone}, + {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete}, + {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe}, + {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml}, + {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info}, + {"vol-list", cmdVolList, opts_vol_list, info_vol_list}, + {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool}, + {"vol-path", cmdVolPath, opts_vol_path, info_vol_path}, + {"vol-name", cmdVolName, opts_vol_name, info_vol_name}, + {"vol-key", cmdVolKey, opts_vol_key, info_vol_key}, + {NULL, NULL, NULL, NULL} +}; +static const vshCmdDef networkCmds[] = { {"net-autostart", cmdNetworkAutostart, opts_network_autostart, info_network_autostart}, {"net-create", cmdNetworkCreate, opts_network_create, info_network_create}, {"net-define", cmdNetworkDefine, opts_network_define, info_network_define}, @@ -9871,7 +9970,22 @@ static const vshCmdDef commands[] = { {"net-start", cmdNetworkStart, opts_network_start, info_network_start}, {"net-undefine", cmdNetworkUndefine, opts_network_undefine, info_network_undefine}, {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid}, + {NULL, NULL, NULL, NULL} +}; +static const vshCmdDef nodedevCmds[] = { + {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo}, + {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, info_node_list_devices}, + {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, info_node_device_dumpxml}, + {"nodedev-dettach", cmdNodeDeviceDettach, opts_node_device_dettach, info_node_device_dettach}, + {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, info_node_device_reattach}, + {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, info_node_device_reset}, + {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, info_node_device_create}, + {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, info_node_device_destroy}, + {NULL, NULL, NULL, NULL} +}; + +static const vshCmdDef ifaceCmds[] = { {"iface-list", cmdInterfaceList, opts_interface_list, info_interface_list}, {"iface-name", cmdInterfaceName, opts_interface_name, info_interface_name}, {"iface-mac", cmdInterfaceMAC, opts_interface_mac, info_interface_mac}, @@ -9881,104 +9995,78 @@ static const vshCmdDef commands[] = { {"iface-edit", cmdInterfaceEdit, opts_interface_edit, info_interface_edit}, {"iface-start", cmdInterfaceStart, opts_interface_start, info_interface_start}, {"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, info_interface_destroy}, + {NULL, NULL, NULL, NULL} +}; - {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave}, - {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, info_managedsaveremove}, - - {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo}, - - {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, info_node_list_devices}, - {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, info_node_device_dumpxml}, - {"nodedev-dettach", cmdNodeDeviceDettach, opts_node_device_dettach, info_node_device_dettach}, - {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, info_node_device_reattach}, - {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, info_node_device_reset}, - {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, info_node_device_create}, - {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, info_node_device_destroy}, - +static const vshCmdDef nwfilterCmds[] = { {"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, info_nwfilter_define}, {"nwfilter-undefine", cmdNWFilterUndefine, opts_nwfilter_undefine, info_nwfilter_undefine}, {"nwfilter-dumpxml", cmdNWFilterDumpXML, opts_nwfilter_dumpxml, info_nwfilter_dumpxml}, {"nwfilter-list", cmdNWFilterList, opts_nwfilter_list, info_nwfilter_list}, {"nwfilter-edit", cmdNWFilterEdit, opts_nwfilter_edit, info_nwfilter_edit}, + {NULL, NULL, NULL, NULL} +}; - {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart}, - {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build}, - {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create}, - {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as}, - {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define}, - {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as}, - {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy}, - {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete}, - {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml}, - {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit}, - {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info}, - {"pool-list", cmdPoolList, opts_pool_list, info_pool_list}, - {"pool-name", cmdPoolName, opts_pool_name, info_pool_name}, - {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh}, - {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start}, - {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, info_pool_undefine}, - {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid}, - +static const vshCmdDef secretCmds[] = { {"secret-define", cmdSecretDefine, opts_secret_define, info_secret_define}, {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, info_secret_dumpxml}, {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, info_secret_set_value}, {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, info_secret_get_value}, {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, info_secret_undefine}, {"secret-list", cmdSecretList, NULL, info_secret_list}, + {NULL, NULL, NULL, NULL} +}; - +static const vshCmdDef virshCmds[] = { #ifndef WIN32 {"pwd", cmdPwd, NULL, info_pwd}, #endif {"quit", cmdQuit, NULL, info_quit}, {"exit", cmdQuit, NULL, info_quit}, - {"reboot", cmdReboot, opts_reboot, info_reboot}, - {"restore", cmdRestore, opts_restore, info_restore}, - {"resume", cmdResume, opts_resume, info_resume}, - {"save", cmdSave, opts_save, info_save}, - {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo}, - {"dump", cmdDump, opts_dump, info_dump}, - {"shutdown", cmdShutdown, opts_shutdown, info_shutdown}, - {"setmem", cmdSetmem, opts_setmem, info_setmem}, - {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem}, - {"memtune", cmdMemtune, opts_memtune, info_memtune}, - {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus}, - {"suspend", cmdSuspend, opts_suspend, info_suspend}, - {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole}, - {"undefine", cmdUndefine, opts_undefine, info_undefine}, - {"update-device", cmdUpdateDevice, opts_update_device, info_update_device}, - {"uri", cmdURI, NULL, info_uri}, - - {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create}, - {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, info_vol_create_from}, - {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as}, - {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone}, - {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete}, - {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe}, - {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml}, - {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info}, - {"vol-list", cmdVolList, opts_vol_list, info_vol_list}, - {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool}, - {"vol-path", cmdVolPath, opts_vol_path, info_vol_path}, - {"vol-name", cmdVolName, opts_vol_name, info_vol_name}, - {"vol-key", cmdVolKey, opts_vol_key, info_vol_key}, - - {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount}, - {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo}, - {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin}, - {"version", cmdVersion, NULL, info_version}, - {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay}, + {"help", cmdHelp, opts_help, info_help}, +#ifndef WIN32 + {"cd", cmdCd, opts_cd, info_cd}, +#endif + {"echo", cmdEcho, opts_echo, info_echo}, + {NULL, NULL, NULL, NULL} +}; +static const vshCmdDef snapshotCmds[] = { {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, info_snapshot_create}, {"snapshot-current", cmdSnapshotCurrent, opts_snapshot_current, info_snapshot_current}, {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, info_snapshot_delete}, {"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml, info_snapshot_dumpxml}, {"snapshot-list", cmdSnapshotList, opts_snapshot_list, info_snapshot_list}, {"snapshot-revert", cmdDomainSnapshotRevert, opts_snapshot_revert, info_snapshot_revert}, + {NULL, NULL, NULL, NULL} +}; +static const vshCmdDef hostAndHypervisorCmds[] = { + {"capabilities", cmdCapabilities, NULL, info_capabilities}, + {"connect", cmdConnect, opts_connect, info_connect}, + {"uri", cmdURI, NULL, info_uri}, + {"freecell", cmdFreecell, opts_freecell, info_freecell}, + {"hostname", cmdHostname, NULL, info_hostname}, {NULL, NULL, NULL, NULL} }; +static const vshCmdGrp cmdGroups[] = { + {VSH_CMD_GRP_DOM_MANAGEMENT, domManagementCmds}, + {VSH_CMD_GRP_DOM_MONITORING, domMonitoringCmds}, + {VSH_CMD_GRP_STORAGE_POOL, storagePoolCmds}, + {VSH_CMD_GRP_STORAGE_VOL, storageVolCmds}, + {VSH_CMD_GRP_NETWORK, networkCmds}, + {VSH_CMD_GRP_NODEDEV, nodedevCmds}, + {VSH_CMD_GRP_IFACE, ifaceCmds}, + {VSH_CMD_GRP_NWFILTER, nwfilterCmds}, + {VSH_CMD_GRP_SECRET, secretCmds}, + {VSH_CMD_GRP_SNAPSHOT, snapshotCmds}, + {VSH_CMD_GRP_HOST_AND_HV, hostAndHypervisorCmds}, + {VSH_CMD_GRP_VIRSH, virshCmds}, + {NULL, NULL} +}; + + /* --------------- * Utils for work with command definition * --------------- @@ -10060,15 +10148,54 @@ vshCommandCheckOpts(vshControl *ctl, const vshCmd *cmd) static const vshCmdDef * vshCmddefSearch(const char *cmdname) { + const vshCmdGrp *g; const vshCmdDef *c; - for (c = commands; c->name; c++) - if (STREQ(c->name, cmdname)) - return c; + for (g = cmdGroups; g->name; g++) { + for (c = g->commands; c->name; c++) { + if(STREQ(c->name, cmdname)) + return c; + } + } + + return NULL; +} + +static const vshCmdGrp * +vshCmdGrpSearch(const char *grpname) +{ + const vshCmdGrp *g; + + for (g = cmdGroups; g->name; g++) { + if(STREQ(g->name, grpname)) + return g; + } + return NULL; } static int +vshCmdGrpHelp(vshControl *ctl, const char *grpname) +{ + const vshCmdGrp *grp = vshCmdGrpSearch(grpname); + const vshCmdDef *cmd = NULL; + + if (!grp) { + vshError(ctl, _("command group '%s' doesn't exist"), grpname); + return FALSE; + } else { + vshPrint(ctl, " %s:\n", grp->name); + + for (cmd = grp->commands; cmd->name; cmd++) { + vshPrint(ctl, " %-30s %s\n", cmd->name, + _(vshCmddefGetInfo(cmd, "help"))); + } + } + + return TRUE; +} + +static int vshCmddefHelp(vshControl *ctl, const char *cmdname) { const vshCmdDef *def = vshCmddefSearch(cmdname); @@ -11242,25 +11369,40 @@ vshCloseLogFile(vshControl *ctl) static char * vshReadlineCommandGenerator(const char *text, int state) { - static int list_index, len; + static int grp_list_index, cmd_list_index, len; const char *name; + const vshCmdGrp *grp; + const vshCmdDef *cmds; + + grp = cmdGroups; /* If this is a new word to complete, initialize now. This * includes saving the length of TEXT for efficiency, and * initializing the index variable to 0. */ if (!state) { - list_index = 0; + grp_list_index = 0; + cmd_list_index = 0; len = strlen(text); } /* Return the next name which partially matches from the * command list. */ - while ((name = commands[list_index].name)) { - list_index++; - if (STREQLEN(name, text, len)) - return vshStrdup(NULL, name); + while (grp[grp_list_index].name) { + cmds = grp[grp_list_index].commands; + + if (cmds[cmd_list_index].name) { + while ((name = cmds[cmd_list_index].name)) { + cmd_list_index++; + + if (STREQLEN(name, text, len)) + return vshStrdup(NULL, name); + } + } else { + cmd_list_index = 0; + grp_list_index++; + } } /* If no names matched, then return NULL. */ @@ -11452,13 +11594,13 @@ vshDeinit(vshControl *ctl) return TRUE; } -/* - * Print usage - */ + static void vshUsage(void) { + const vshCmdGrp *grp; const vshCmdDef *cmd; + fprintf(stdout, _("\n%s [options]... [<command_string>]" "\n%s [options]... <command> [args...]\n\n" " options:\n" @@ -11470,12 +11612,20 @@ vshUsage(void) " -t | --timing print timing information\n" " -l | --log <file> output logging to file\n" " -v | --version program version\n\n" - " commands (non interactive mode):\n"), progname, progname); + " commands (non interactive mode):\n\n"), progname, progname); + + for (grp = cmdGroups; grp->name; grp++) { + fprintf(stdout, " %s:\n", grp->name); - for (cmd = commands; cmd->name; cmd++) - fprintf(stdout, - " %-15s %s\n", cmd->name, _(vshCmddefGetInfo(cmd, "help"))); + for (cmd = grp->commands; cmd->name; cmd++) + fprintf(stdout, + " %-30s %s\n", cmd->name, _(vshCmddefGetInfo(cmd, "help"))); + fprintf(stdout, "\n"); + } + + fprintf(stdout, "%s", + _("\n (specify help <group> for details about commands in that group)\n\n")); fprintf(stdout, "%s", _("\n (specify help <command> for details about the command)\n\n")); return; -- 1.7.2.3

On Nov 5, 2010, at 7:16 PM, Osier Yang wrote: <snip>
Also support output help information of specified command group, e.g.
% ./tools/virsh help "Network Filter" <snip>
- not sure if it's fine of group name contains space, Because it need user to quote the whole group name when input. Probly we need some abstract group names for user.
In general, this all looks like a good start. :) The quoted group names bit though... yeah, it's not good for usability. :/ Thinking here, that we should aim for something where a person can type in one simple key word (preferably tab completion works on it too). ie: virsh # help filter (outputs Network Filter help info) Actually, the tab completion isn't all that required. If it's an easy thing to add, then "might as well", but if it's a bunch of coding then it's probably not worth it. :) With the group key words, they could be listed in the help text itself, something like: virsh # help ... Network Filter (help keyword 'filter') nwfilter-define define or update a network filter from an XML file nwfilter-undefine undefine a network filter nwfilter-dumpxml network filter information in XML nwfilter-list list network filters nwfilter-edit edit XML configuration for a network filter ... It might make the help output look a bit messy, but its nice and clear and puts info in front of people at the point they need it. As a starting point, if the above seems reasonable to you, how's this for keywords? "Domain Management" -> domain "Domain Monitoring" -> monitor "Storage Pool" -> pool "Storage Volume" -> volume "Networking" -> network "Node Device" -> device "Interface" -> interface "Network Filter" -> filter "Secret" -> secret "Snapshot" -> snapshot "Host and Hypervisor" -> host "Virsh Itself" -> virsh I've thrown the keywords above onto the wiki page, in case it helps: http://wiki.libvirt.org/page/VirshHelpV2 :) + Justin

于 2010年11月05日 17:27, Justin Clift 写道:
On Nov 5, 2010, at 7:16 PM, Osier Yang wrote: <snip>
Also support output help information of specified command group, e.g.
% ./tools/virsh help "Network Filter" <snip>
- not sure if it's fine of group name contains space, Because it need user to quote the whole group name when input. Probly we need some abstract group names for user.
In general, this all looks like a good start. :)
The quoted group names bit though... yeah, it's not good for usability. :/
Thinking here, that we should aim for something where a person can type in one simple key word (preferably tab completion works on it too).
ie:
virsh # help filter (outputs Network Filter help info)
Actually, the tab completion isn't all that required. If it's an easy thing to add, then "might as well", but if it's a bunch of coding then it's probably not worth it. :)
Currently virsh just tab completes the first command and options of that command.. e.g. "virsh # migrate --" "virsh # help some_command" doesn't support tab completion for "some_command". think it's no need to add it, it's only helpful for "help" command, and yes, a bunch of coding, and also it will make "help" confused if we use the short key word for groups, e.g. suppose we use "domain" as the key word for "domain management" group. then what should "virsh # help dom" behave? :-)
With the group key words, they could be listed in the help text itself, something like:
virsh # help ... Network Filter (help keyword 'filter') nwfilter-define define or update a network filter from an XML file nwfilter-undefine undefine a network filter nwfilter-dumpxml network filter information in XML nwfilter-list list network filters nwfilter-edit edit XML configuration for a network filter ...
It might make the help output look a bit messy, but its nice and clear and puts info in front of people at the point they need it.
As a starting point, if the above seems reasonable to you, how's this for keywords?
"Domain Management" -> domain "Domain Monitoring" -> monitor "Storage Pool" -> pool "Storage Volume" -> volume "Networking" -> network "Node Device" -> device
nodedev instead?
"Interface" -> interface "Network Filter" -> filter "Secret" -> secret "Snapshot" -> snapshot "Host and Hypervisor" -> host "Virsh Itself" -> virsh
I've thrown the keywords above onto the wiki page, in case it helps:
it's the guide, thanks :-) - Osier
:)
+ Justin
participants (2)
-
Justin Clift
-
Osier Yang