diff options
| author | Armin Ronacher <armin.ronacher@active-4.com> | 2014-05-25 14:49:06 +0200 |
|---|---|---|
| committer | Armin Ronacher <armin.ronacher@active-4.com> | 2014-05-25 14:49:06 +0200 |
| commit | fdb0a8ce6d12a334b378076ec97a484105fa8618 (patch) | |
| tree | 2cd77f19ec7d451c8fd49c278f854d33e5164125 /examples/aliases | |
| parent | 9f778e82f4d03f5daa8b7fedfff8b2827b7432ae (diff) | |
| download | click-fdb0a8ce6d12a334b378076ec97a484105fa8618.tar.gz | |
Added a complex aliases example
Diffstat (limited to 'examples/aliases')
| -rw-r--r-- | examples/aliases/README | 16 | ||||
| -rw-r--r-- | examples/aliases/aliases.ini | 2 | ||||
| -rw-r--r-- | examples/aliases/aliases.py | 111 | ||||
| -rw-r--r-- | examples/aliases/setup.py | 15 |
4 files changed, 144 insertions, 0 deletions
diff --git a/examples/aliases/README b/examples/aliases/README new file mode 100644 index 0000000..3249847 --- /dev/null +++ b/examples/aliases/README @@ -0,0 +1,16 @@ +$ complex_ + + complex is an example of building very complex cli + applications that load subcommands dynamically from + a plugin folder and other things. + + All the commands are implemented as plugins in the + `complex.commands` package. If a python module is + placed named "cmd_foo" it will show up as "foo" + command and the `cli` object within it will be + loaded as nested click command. + +Usage: + + $ pip install --editable . + $ complex --help diff --git a/examples/aliases/aliases.ini b/examples/aliases/aliases.ini new file mode 100644 index 0000000..4f1d54c --- /dev/null +++ b/examples/aliases/aliases.ini @@ -0,0 +1,2 @@ +[aliases] +ci=commit diff --git a/examples/aliases/aliases.py b/examples/aliases/aliases.py new file mode 100644 index 0000000..4c7e30d --- /dev/null +++ b/examples/aliases/aliases.py @@ -0,0 +1,111 @@ +import os +import click + +try: + import ConfigParser as configparser +except ImportError: + import configparser + + +class Config(object): + """The config in this example only holds aliases.""" + + def __init__(self): + self.path = os.getcwd() + self.aliases = {} + + def read_config(self, filename): + parser = configparser.RawConfigParser() + parser.read([filename]) + try: + self.aliases.update(parser.items('aliases')) + except configparser.NoSectionError: + pass + + +pass_config = click.make_pass_decorator(Config, ensure=True) + + +class AliasedGroup(click.Group): + """This subclass of a group supports looking up aliases in a config + file and with a bit of magic. + """ + + def get_command(self, ctx, cmd_name): + # Step one: bulitin commands as normal + rv = click.Group.get_command(self, ctx, cmd_name) + if rv is not None: + return rv + + # Step two: find the config object and ensure it's there. This + # will create the config object is missing. + cfg = ctx.ensure_object(Config) + + # Step three: lookup an explicit command aliase in the config + if cmd_name in cfg.aliases: + actual_cmd = cfg.aliases[cmd_name] + return click.Group.get_command(self, ctx, actual_cmd) + + # Alternative option: if we did not find an explicit alias we + # allow automatic abbreviation of the command. "status" for + # instance will match "st". We only allow that however if + # there is only one command. + matches = [x for x in self.list_commands(ctx) + if x.lower().startswith(cmd_name.lower())] + if not matches: + return None + elif len(matches) == 1: + return click.Group.get_command(self, ctx, matches[0]) + ctx.fail('Too many matches: %s' % ', '.join(sorted(matches))) + + +def read_config(ctx, value): + """Callback that is used whenever --config is passed. We use this to + always load the correct config. This means that the config is loaded + even if the group itself never executes so our aliases stay always + available. + """ + cfg = ctx.ensure_object(Config) + if value is None: + value = os.path.join(os.path.dirname(__file__), 'aliases.ini') + cfg.read_config(value) + return value + + +@click.command(cls=AliasedGroup) +@click.option('--config', type=click.Path(exists=True, dir_okay=False), + callback=read_config, expose_value=False, + help='The config file to use instead of the default.') +def cli(): + """An example application that supports aliases.""" + + +@cli.command() +def push(): + """Pushes changes.""" + click.echo('Push') + + +@cli.command() +def pull(): + """Pulls changes.""" + click.echo('Pull') + + +@cli.command() +def clone(): + """Clones a repository.""" + click.echo('Clone') + + +@cli.command() +def commit(): + """Commits pending changes.""" + click.echo('Commit') + + +@cli.command() +@pass_config +def status(config): + """Shows the status.""" + click.echo('Status for %s' % config.path) diff --git a/examples/aliases/setup.py b/examples/aliases/setup.py new file mode 100644 index 0000000..c725501 --- /dev/null +++ b/examples/aliases/setup.py @@ -0,0 +1,15 @@ +from setuptools import setup + +setup( + name='click-example-aliases', + version='1.0', + py_modules=['aliases'], + include_package_data=True, + install_requires=[ + 'Click', + ], + entry_points=''' + [console_scripts] + aliases=aliases:cli + ''', +) |
