Skip to content

Commit

Permalink
add commands collector and info on readme
Browse files Browse the repository at this point in the history
  • Loading branch information
rochacbruno committed Jun 11, 2016
1 parent ac25b36 commit e17d24e
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 9 deletions.
56 changes: 56 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,62 @@ also it comes with an interactive shell with iPython support.
With that you now have a file **manage.yml** file describing how **manage** command should discovery your app modules and custom commands

The Shell
---------

By default the command :code:`manage shell` is included, it is a simple Python REPL console with some
configurable options.

You can change the banner message to say anything you want, e.g: "Welcome to my shell!" and you can also
specify some objects to be automatically imported in to the shell context so when you enter in to the shell you
already have your project's common objects available.

Also you can specify a custom function to run or a string based code block to run, useful to init and configure the objects.

If **IPython** is installed it will use it, otherwise will use the default Python console including support for tab autocomplete.

Lets see an example:

Edit the file :code:`manage.yml` with the following content::

---
shell:
readline_enabled: true
banner:
enabled: true
envvars: true
message: "{USER}, welcome to my Shell!"
auto_import:
display: true
objects:
myapp.module.Class:
myapp.module.object:
as: obj
init:
configure:
args:
- a
- b
kwargs:
foo: bar
init:
myapp.initialization.start:
args:
- a
- b
kwargs:
foo: bar
init_script: -
from foo import bar
bar.configure()


Then the above configurations will give you the :code:`manage shell` as in the picture below


Custom Commands
---------------


Credits
---------
Expand Down
61 changes: 52 additions & 9 deletions manage/cli.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,57 @@
# coding: utf-8

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import click
import code
import readline
import rlcompleter
# import importlib


@click.group()
def core_cmd():
""" Core commands wrapper """
pass


# class RobotteloLoader(object):
# def __getattr__(self, item):
# return importlib.import_module('robottelo.{0}'.format(item))


@core_cmd.command()
@click.option('--ipython/--no-ipython', default=True)
def shell(ipython):
"""Runs a Python shell with Robottelo context"""
_vars = globals()
_vars.update(locals())
auto_imported = {
}
_vars.update(auto_imported)
banner_msg = (
'Welcome to PROGRAM interactive shell\n'
'\tAuto imported: {0}\n'
).format(auto_imported.keys())
readline.set_completer(rlcompleter.Completer(_vars).complete)
readline.parse_and_bind('tab: complete')
try:
if ipython is True:
from IPython import start_ipython
from traitlets.config import Config
c = Config()
c.TerminalInteractiveShell.banner2 = banner_msg
start_ipython(argv=[], user_ns=_vars, config=c)
else:
raise ImportError
except ImportError:
shell = code.InteractiveConsole(_vars)
shell.interact(banner=banner_msg)

@click.command()
def main(args=None):
"""Console script for manage"""
click.echo("Replace this message by putting your code into "
"manage.cli.main")
click.echo("See click documentation at http://http://click.pocoo.org/")

help_text = """
PROGRAM Interactive shell!
"""
main = click.CommandCollection(help=help_text)
main.add_source(core_cmd)

if __name__ == "__main__":
if __name__ == '__main__':
main()
49 changes: 49 additions & 0 deletions manage/commands_collector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import sys
import os
import click
import importlib


class CommandsCollector(click.MultiCommand):
"""A MultiCommand to collect all click commands from a given
modules path and base name for the module.
The commands functions needs to be in a module inside commands
folder and the name of the file will be used as the command name.
"""

def __init__(self, modules_path, base_module_name, **attrs):
click.MultiCommand.__init__(self, **attrs)
self.base_module_name = base_module_name
self.modules_path = modules_path

def list_commands(self, *args, **kwargs):
commands = []
for _path, _dir, _ in os.walk(self.modules_path):
if 'commands' not in _dir:
continue
for filename in os.listdir(os.path.join(_path, 'commands')):
if filename.endswith('.py') and filename != '__init__.py':
cmd = filename[:-3]
_, module_name = os.path.split(_path)
commands.append('{0}_{1}'.format(module_name, cmd))
commands.sort()
return commands

def get_command(self, ctx, name):
try:
if sys.version_info[0] == 2:
name = name.encode('ascii', 'replace')
splitted = name.split('_')
if len(splitted) <= 1:
return
module_name, command_name = splitted
if not all([module_name, command_name]):
return
module = '{0}.{1}.commands.{2}'.format(
self.base_module_name,
module_name,
command_name)
mod = importlib.import_module(module)
except ImportError:
return
return getattr(mod, 'cli', None)

0 comments on commit e17d24e

Please sign in to comment.