Reputation: 1277
I want to wrap multiple CLIs and make one parent CLI that will basically call the other CLIs under the hood.
To give an example, let's say I want to make my_cli that will wrap the git and cmake clis. For instance, when I call my_cli add
, it would call git add
under the hood and similarly when I can my_cli build
, it would call cmake build
.
I actually managed to implement an example using the python click library, but for this I need to (re)create the same CLI args and options of git in my_cli. Basically, it was too much copy and paste. I would just check which CLI args and options does git add
have and just go and create these using the click library for the add command.
I'm asking if this is the only way to achieve this. It would be great if I can somehow dynamically parse the cli args and give them forward to the click command without having to specify any cli args and options for my click command.
Here is an example from the click docs:
import click
@click.command()
@click.option('--name', prompt='Your name', help='The person to greet.') # is there a way to not know which args and option would my command expect?
def hello(name):
click.echo(f"Hello {name}!")
In click, the command needs to know which args and options to expect at declaration time. Is there a way to make this dynamic and forward the args and options to the command?
Here is a simple expected result:
import click
@click.command()
def add(*args, **kwargs): # args would be cli args and kwargs would be cli options passed by the user.
click.echo(f"git add {args} {kwargs}!")
Ideally, the help text for the add command need to be the same as the help text for git add
because if I achieve to pass the args and options dynamically, then I must also update the help text, otherwise my_cli add --help
would return nothing useful.
Upvotes: 0
Views: 721
Reputation: 2781
I've achieved this by defining a group/command like this:
import subprocess
import click
@click.group()
def cli():
pass
@cli.command(context_settings=dict(
ignore_unknown_options=True,
allow_extra_args=True,
))
@click.argument('command')
@click.pass_context
def run(ctx, command):
subprocess.run([command, *ctx.args])
if __name__ == '__main__':
cli()
and invoking it from my shell like:
python main.py run git -- --help
python main.py run git -- add --help
python main.py run git -- branch --help
python main.py run ls -- -al
Essentially, I told my click command to passthrough all arguments it receives to the command I have specified.
Hope this answers your question.
Upvotes: 2