"Add nested subcommand feature"

Bug #1290018 reported by Rahul Ranjan
10
This bug affects 2 people
Affects Status Importance Assigned to Milestone
cliff
Won't Fix
Undecided
Unassigned

Bug Description

current version of cliff support subcommands but the framework doesn't provide standard way of doing it.
like if we want to add subcommand having structure as below

[GLOBAL OPTIONS] [{SUB1 [options]}, {SUB2 [options]}, ...... ]

then we have to tweak the command manager class which is painful for every app. So there should be a generic framework for doing it.

Revision history for this message
Doug Hellmann (doug-hellmann) wrote :

I'm not sure I understand the goal. Do you mean that one command is the parent of another, and provides some options that the other uses? That can be done with a base class for the commands. You don't end up with the syntax you describe, but I'm not sure that syntax is necessary to achieve what you want.

Can you give a more concrete example of what those sub1 and sub2 commands might look like?

Revision history for this message
Terry Howe (thowe-g) wrote :

I could be totally missing something, but this sounds like something that should be done by the application with class inheritance. I can't think of a construct better than inheritance to provide base and more specialized behaviors.

Revision history for this message
Rahul Ranjan (rahul-rrixe) wrote :

@Terry yeah I am working for a application i.e. Apache-libcloud. We are trying to have interactive construct like this

 <main> <app> <command> <sub command>

[user@localhost] libcloud
(libcloud) <service> <resource> <action> [options]

service will have several resources and then each resources will have some actions accompaniesd with global options.

for e.g. if i want to know about registry list of node and the result should be in json format, the command structure would be like this

(libcloud) register node list -f json

@Doug I couldn't find documenation on subcommands, ofcource cliff provide this facility with inheritance but there should be some generic way to do this.
Also if you can guide me i will make upstream for that.

Revision history for this message
Doug Hellmann (doug-hellmann) wrote :

Rahul,

cliff does support subcommands, but not quite the way you seem to want to use them.

The command line structure I think you want is:

  libcloud --app-option app-val service1 --service1-option resource1 --shared-option val1 action1 --action1-option
  libcloud --app-option app-val service1 --service1-option resource1 --shared-option val1 action2 --action2-option

Having the parts of the command and the options mixed feels a little harder for users to understand, but obviously that's subjective.

First, in case it's not clear from the docs and example, a "command" can include more than one word. In the openstack client we have commands like "subnet list" and "subnet show". Those are listed as individual commands, but tab-completion makes them appear to the user as though they are subcommands (we went with "noun verb" to facilitate discovery through tab completion).

Cliff also supports having commands share options, because each command implementation is a class, and you can inherit the option definitions from a parent class.

So if you have a command "service1 resource1 action1" and another command "service1 resource1 action2" those could inherit from a Service1Resource1Base which defines the method to configure the common options. The Service1Resource1Action1 and Servide1Resource1Action2 classes could then add their own custom options. If there are application options for things like login credentials or configuration files, those can be defined by the application base class and consumed by the application, before any command class is loaded.

Using that structure, some libcloud command might look like:

  libcloud --app-option app-val service1 resource1 action1 --service1-option --shared-option val1 --action1-option
  libcloud --app-option app-val service1 resource1 action2 --service1-option --shared-option val1 --action2-option

with "service1 resource1 action1" mapping to a single class in your entry point metadata. The show and list command base classes are examples of this, since each introduces the appropriate formatter options but relies on the subclass to provide output data.

The openstack client uses application options (http://git.openstack.org/cgit/openstack/python-openstackclient/tree/openstackclient/shell.py#n135) but I don't see an example of us building an equivalent to Service1Resource1Base anywhere.

Revision history for this message
Rahul Ranjan (rahul-rrixe) wrote :

Hi Doug,

Libcloud has various IAAS clients like EC2, DigitalOcean etc. So We want command structure like this

libcloud <api> <resource> <action>

and by default cliff only supports

libcloud <api> <action> structure.

So that a user when want to use EC2 API, he can switch to that and the subcommands would follow the resource related
to EC2 only ;

libcloud EC2 compute list node -f json

Also we can have command consisting more than a word like "Create Node, Delete Node"
but they would be individual command as you have pointed in above comments,

Can you have look on this application https://github.com/racker/python-raxcli used by rackspace

We want similar implementation but their command manager is hacky.

Revision history for this message
Doug Hellmann (doug-hellmann) wrote :

Cliff does not impose a number of limits on the words in a command -- it takes the name registered and splits it into words and then requires that all of those words be provided on the command line. The custom command manager from rackspace is scanning the filesystem directly (instead of using entry points), and so to prevent recursing too far it looks like they do impose a 3 level structure. They load those commands into a command manager that has a nested structure, but if you're using the entry point based manager native to cliff you don't need that because cliff will do the lookup for you.

Do you have some sample code that shows what you are trying to do and that is not working? Maybe that would help me understand better.

Revision history for this message
Rahul Ranjan (rahul-rrixe) wrote :

@Doug,

I have just started working on the code, not much have been done. Will update you in coming two days with that.
your key points has helped me a lot to learn the new capabilities of cliff. let me implment that first and then i will
get back to you.

Thanks :)

Revision history for this message
Doug Hellmann (doug-hellmann) wrote :

I think we've resolved this, but if I'm wrong please reopen the ticket.

Changed in python-cliff:
status: New → Won't Fix
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.