Skip to content
This repository was archived by the owner on Dec 29, 2017. It is now read-only.

Commit 4caa958

Browse files
authored
Move cli to submodule and added sirbot init (#27)
`sirbot init` will prompt the user for and auto generate a configuration file and an empty plugin
1 parent b9f3592 commit 4caa958

16 files changed

+332
-182
lines changed

docs/configuration.rst

+18-10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
Configuration
33
=============
44

5+
.. note::
6+
7+
A configuration file and an empty plugin can be auto-generated using:
8+
9+
.. code-block:: console
10+
11+
$ sirbot init
12+
513
Start
614
-----
715

@@ -16,19 +24,10 @@ To start Sir Bot-a-lot you can use one of:
1624
$ python run.py
1725
1826
19-
Environment variables
20-
---------------------
21-
22-
The environment variable take precedence over the command line arguments.
23-
24-
* :code:`SIRBOT_PORT`: Port where to run Sir Bot-a-lot
25-
* :code:`SIRBOT_CONFIG`: Path to Sir Bot-a-lot Yaml config file
26-
27-
2827
Command line arguments
2928
----------------------
3029

31-
The command line arguments take precedence over the configuration file.
30+
The command line arguments take precedence over the environment variables.
3231

3332
* :code:`-h --help`: Help message
3433
* :code:`-P --port`: Port where to run Sir Bot-a-lot
@@ -37,6 +36,15 @@ The command line arguments take precedence over the configuration file.
3736
* :code:`-p --plugins`: Plugins to start
3837

3938

39+
Environment variables
40+
---------------------
41+
42+
The environment variable take precedence over the configuration file.
43+
44+
* :code:`SIRBOT_PORT`: Port where to run Sir Bot-a-lot
45+
* :code:`SIRBOT_CONFIG`: Path to Sir Bot-a-lot Yaml config file
46+
47+
4048
Configuration file
4149
------------------
4250

docs/quickstart.rst

+6-1
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,13 @@ The default configuration file look like this:
4040
port: 8080
4141
plugins: []
4242
43-
Plugins can also be added with the :code:`--plugins` argument
43+
Plugins can also be added with the :code:`--plugins` argument.
4444

45+
You can auto-generate a configuration file and a basic plugin with:
46+
47+
.. code-block:: console
48+
49+
$ sirbot init
4550
4651
Start
4752
-----

requirements/requirements.in

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ multidict
55
pluggy
66
pyyaml
77
yarl
8+
mako

requirements/requirements.txt

+6-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
#
55
# pip-compile --output-file requirements/requirements.txt requirements/requirements.in
66
#
7-
aiohttp==2.0.7
7+
aiohttp==2.2.3
88
async-timeout==1.2.1
9-
chardet==3.0.2
10-
multidict==2.1.4
9+
chardet==3.0.4
10+
mako==1.0.6
11+
markupsafe==1.0 # via mako
12+
multidict==3.1.0
1113
pluggy==0.4.0
1214
pyyaml==3.12
13-
yarl==0.10.1
15+
yarl==0.11.0

requirements/requirements_dev.txt

+15-11
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,47 @@
44
#
55
# pip-compile --output-file requirements/requirements_dev.txt requirements/requirements_dev.in
66
#
7-
aiohttp==2.0.7 # via pytest-aiohttp
7+
aiohttp==2.2.3 # via pytest-aiohttp
88
alabaster==0.7.10 # via sphinx
99
async-timeout==1.2.1 # via aiohttp
1010
babel==2.4.0 # via sphinx
11-
chardet==3.0.2 # via aiohttp
11+
certifi==2017.4.17 # via requests
12+
chardet==3.0.4 # via aiohttp, requests
1213
click==6.7 # via pip-tools
1314
commonmark==0.5.4 # via recommonmark
14-
coverage==4.3.4
15+
coverage==4.4.1
1516
docutils==0.13.1 # via recommonmark, sphinx
1617
first==2.0.1 # via pip-tools
1718
flake8==3.3.0
19+
idna==2.5 # via requests
1820
imagesize==0.7.1 # via sphinx
1921
jinja2==2.9.6 # via sphinx
2022
markupsafe==1.0 # via jinja2
2123
mccabe==0.6.1 # via flake8
22-
multidict==2.1.4 # via aiohttp, yarl
24+
multidict==3.1.0 # via aiohttp, yarl
2325
pip-tools==1.9.0
2426
pluggy==0.4.0 # via tox
2527
pockets==0.5.1 # via sphinxcontrib-napoleon
26-
py==1.4.33 # via pytest, tox
28+
py==1.4.34 # via pytest, tox
2729
pycodestyle==2.3.1 # via flake8
2830
pyflakes==1.5.0 # via flake8
2931
pygments==2.2.0 # via sphinx
3032
pytest-aiohttp==0.1.3
31-
pytest-asyncio==0.5.0
32-
pytest-cov==2.4.0
33+
pytest-asyncio==0.6.0
34+
pytest-cov==2.5.1
3335
pytest-runner==2.11.1
34-
pytest==3.0.7 # via pytest-aiohttp, pytest-asyncio, pytest-cov
36+
pytest==3.1.3 # via pytest-aiohttp, pytest-asyncio, pytest-cov
3537
pytz==2017.2 # via babel
3638
recommonmark==0.4.0
37-
requests==2.13.0 # via sphinx
39+
requests==2.18.1 # via sphinx
3840
six==1.10.0 # via pip-tools, pockets, sphinx, sphinxcontrib-napoleon
3941
snowballstemmer==1.2.1 # via sphinx
4042
sphinx-pypi-upload==0.2.1
41-
sphinx==1.5.5
43+
sphinx==1.6.3
4244
sphinxcontrib-asyncio==0.2.0
4345
sphinxcontrib-napoleon==0.6.1
46+
sphinxcontrib-websupport==1.0.1 # via sphinx
4447
tox==2.7.0
48+
urllib3==1.21.1 # via requests
4549
virtualenv==15.1.0 # via tox
46-
yarl==0.10.1 # via aiohttp
50+
yarl==0.11.0 # via aiohttp

run.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python
22

3-
from sirbot.core.cli import main
3+
from sirbot.cli import main
44

55
if __name__ == '__main__':
66
main()

setup.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,17 @@ def parse_readme():
6464
'sirbot',
6565
'sirbot.core',
6666
'sirbot.utils',
67+
'sirbot.cli',
6768
],
6869
package_dir={
6970
'sirbot': 'sirbot',
7071
'sirbot.core': 'sirbot/core',
7172
'sirbot.utils': 'sirbot/utils',
73+
'sirbot.cli': 'sirbot/cli',
7274
},
7375
package_data={
7476
'sirbot.core': ['config.yml'],
77+
'sirbot.cli': ['sirbot.yml.mako', 'plugin.py.mako']
7578
},
7679
# To provide executable scripts, use entry points in preference to the
7780
# "scripts" keyword. Entry points provide cross-platform support and
@@ -86,7 +89,7 @@ def parse_readme():
8689
# installed, specify them here.
8790
entry_points={
8891
'console_scripts': [
89-
'sirbot=sirbot.core.cli:main'
92+
'sirbot=sirbot.cli:main'
9093
]
9194
},
9295
include_package_data=True,

sirbot/cli/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .cli import main # noQa

sirbot/cli/cli.py

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import argparse
2+
import asyncio
3+
import logging
4+
import sys
5+
6+
from . import config, initialize
7+
from ..core import SirBot
8+
9+
10+
def parse_args(arguments):
11+
parser = argparse.ArgumentParser(description='The good Sir Bot-a-lot')
12+
parser.add_argument('-P', '--port', dest='port', action='store',
13+
type=int,
14+
help='port')
15+
parser.add_argument('-c', '--config', action='store',
16+
help='config file path')
17+
parser.add_argument('-u', '--update', help='Update plugins',
18+
action='store_true', dest='update')
19+
parser.add_argument('-p', '--plugins', help='Plugins to load',
20+
dest='plugins', nargs='+')
21+
22+
subparsers = parser.add_subparsers(help='Additional commands',
23+
dest='subcommands')
24+
25+
init_parser = subparsers.add_parser('init',
26+
help='Initialize your Sir Bot-a-lot'
27+
' configuration')
28+
init_parser.set_defaults(func=initialize.initialize_plugin)
29+
init_parser.add_argument('-n', '--name', action='store',
30+
help='configuration plugin name')
31+
init_parser.add_argument('-p', '--plugins', help='Plugins to load',
32+
dest='plugins', nargs='+')
33+
init_parser.add_argument('-P', '--port', dest='port', action='store',
34+
type=int, help='port')
35+
init_parser.add_argument('-l', '--log', dest='log_level', action='store',
36+
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
37+
help='Logging level', default='INFO')
38+
39+
return parser.parse_args(arguments)
40+
41+
42+
def main(): # pragma: no cover
43+
args = parse_args(sys.argv[1:])
44+
logging.basicConfig()
45+
46+
if args.subcommands:
47+
args.func(args)
48+
else:
49+
configuration = config.load_config(args)
50+
if args.update:
51+
update(configuration)
52+
else:
53+
start(configuration)
54+
55+
56+
def start(configuration, loop=None): # pragma: no cover
57+
if not loop:
58+
loop = asyncio.get_event_loop()
59+
60+
bot = SirBot(config=configuration, loop=loop)
61+
bot.run(port=int(configuration['sirbot']['port']))
62+
return bot
63+
64+
65+
def update(configuration, loop=None):
66+
if not loop:
67+
loop = asyncio.get_event_loop()
68+
69+
bot = SirBot(config=configuration, loop=loop)
70+
loop.run_until_complete(bot.update())
71+
return bot
72+
73+
74+
if __name__ == '__main__':
75+
main() # pragma: no cover

sirbot/cli/config.py

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import os
2+
import yaml
3+
4+
5+
def load_config(args):
6+
7+
path = args.config or os.getenv('SIRBOT_CONFIG')
8+
port = args.port or os.getenv('SIRBOT_PORT')
9+
config = load_file(path)
10+
11+
if 'sirbot' not in config:
12+
config['sirbot'] = dict()
13+
14+
if args.plugins:
15+
if 'plugins' not in config['sirbot']:
16+
config['sirbot']['plugins'] = list()
17+
config['sirbot']['plugins'].extend(args.plugins)
18+
19+
if port:
20+
config['sirbot']['port'] = port
21+
elif 'port' not in config['sirbot']:
22+
config['sirbot']['port'] = 8080
23+
24+
return config
25+
26+
27+
def load_file(path=None):
28+
29+
if not path:
30+
return dict()
31+
if not os.path.isabs(path):
32+
path = os.path.join(os.getcwd(), path)
33+
34+
with open(path) as file:
35+
return yaml.load(file)

sirbot/cli/initialize.py

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import os
2+
3+
from mako.template import Template
4+
5+
6+
def initialize_plugin(args):
7+
try:
8+
config = make_config(args)
9+
generate_yaml(config)
10+
generate_python(config)
11+
except KeyboardInterrupt:
12+
pass
13+
14+
15+
def make_config(args):
16+
config = {
17+
'name': args.name,
18+
'plugins': args.plugins,
19+
'port': args.port,
20+
'log_level': args.log_level
21+
}
22+
23+
if not config['name']:
24+
while True:
25+
name = input('Configuration plugin name: ')
26+
if len(name) > 0:
27+
break
28+
config['name'] = name.lower().replace(' ', '_').strip()
29+
30+
if not config['plugins']:
31+
plugins = input('Plugins to load (comma separated list): ')
32+
33+
if plugins:
34+
config['plugins'] = set(
35+
plugin.strip() for plugin in plugins.split(',')
36+
)
37+
else:
38+
print('No plugins will be configured')
39+
else:
40+
config['plugins'] = set(config['plugins'])
41+
config['plugins'].add(config['name'])
42+
43+
if not config['port']:
44+
while True:
45+
try:
46+
port = int(input('Sir Bot-a-lot port: '))
47+
except ValueError:
48+
print('Please enter an integer')
49+
else:
50+
config['port'] = port
51+
break
52+
53+
return config
54+
55+
56+
def generate_yaml(config):
57+
path = os.path.join(
58+
os.path.dirname(os.path.abspath(__file__)), 'sirbot.yml.mako'
59+
)
60+
61+
config_template = Template(filename=path)
62+
config_render = config_template.render(**config)
63+
64+
with open('sirbot.yml', 'w') as file:
65+
file.write(config_render)
66+
67+
68+
def generate_python(config):
69+
path = os.path.join(
70+
os.path.dirname(os.path.abspath(__file__)), 'plugin.py.mako'
71+
)
72+
73+
plugin_template = Template(filename=path)
74+
plugin_render = plugin_template.render(**config)
75+
76+
with open('{}.py'.format(config['name']), 'w') as file:
77+
file.write(plugin_render)

0 commit comments

Comments
 (0)