diff options
Diffstat (limited to 'ihatemoney')
| -rwxr-xr-x | ihatemoney/manage.py | 135 | ||||
| -rw-r--r-- | ihatemoney/tests/main_test.py | 28 |
2 files changed, 74 insertions, 89 deletions
diff --git a/ihatemoney/manage.py b/ihatemoney/manage.py index eb1e24c..805a07f 100755 --- a/ihatemoney/manage.py +++ b/ihatemoney/manage.py @@ -5,8 +5,8 @@ import os import random import sys -from flask_migrate import Migrate, MigrateCommand -from flask_script import Command, Manager, Option +import click +from flask.cli import FlaskGroup from werkzeug.security import generate_password_hash from ihatemoney.models import Project, db @@ -14,31 +14,48 @@ from ihatemoney.run import create_app from ihatemoney.utils import create_jinja_env -class GeneratePasswordHash(Command): +@click.group(cls=FlaskGroup, create_app=create_app) +def cli(): + """IHateMoney Management script""" - """Get password from user and hash it without printing it in clear text.""" - def run(self): - password = getpass.getpass(prompt="Password: ") - print(generate_password_hash(password)) - - -class GenerateConfig(Command): - def get_options(self): - return [ - Option( - "config_file", - choices=[ - "ihatemoney.cfg", - "apache-vhost.conf", - "gunicorn.conf.py", - "supervisord.conf", - "nginx.conf", - ], - ) +@cli.command( + context_settings={"ignore_unknown_options": True, "allow_extra_args": True} +) +@click.pass_context +def runserver(ctx): + """Deprecated, use the "run" command instead""" + click.secho( + '"runserver" is deprecated, please use the standard "run" flask command', + fg="red", + ) + run = cli.get_command(ctx, "run") + ctx.forward(run) + + +@click.command(name="generate_password_hash") +def password_hash(): + """Get password from user and hash it without printing it in clear text.""" + password = getpass.getpass(prompt="Password: ") + print(generate_password_hash(password)) + + +@click.command() +@click.argument( + "config_file", + type=click.Choice( + [ + "ihatemoney.cfg", + "apache-vhost.conf", + "gunicorn.conf.py", + "supervisord.conf", + "nginx.conf", ] + ), +) +def generate_config(config_file): + """Generate front-end server configuration""" - @staticmethod def gen_secret_key(): return "".join( [ @@ -49,59 +66,33 @@ class GenerateConfig(Command): ] ) - def run(self, config_file): - env = create_jinja_env("conf-templates", strict_rendering=True) - template = env.get_template(f"{config_file}.j2") + env = create_jinja_env("conf-templates", strict_rendering=True) + template = env.get_template(f"{config_file}.j2") - bin_path = os.path.dirname(sys.executable) - pkg_path = os.path.abspath(os.path.dirname(__file__)) + bin_path = os.path.dirname(sys.executable) + pkg_path = os.path.abspath(os.path.dirname(__file__)) - print( - template.render( - pkg_path=pkg_path, - bin_path=bin_path, - sys_prefix=sys.prefix, - secret_key=self.gen_secret_key(), - ) + print( + template.render( + pkg_path=pkg_path, + bin_path=bin_path, + sys_prefix=sys.prefix, + secret_key=gen_secret_key(), ) - - -class DeleteProject(Command): - def run(self, project_name): - demo_project = Project.query.get(project_name) - db.session.delete(demo_project) + ) + + +@cli.command() +@click.argument("project_name") +def delete_project(project_name): + """Delete a project""" + project = Project.query.get(project_name) + if project is None: + click.secho(f'Project "{project_name}" not found', fg="red") + else: + db.session.delete(project) db.session.commit() -def main(): - QUIET_COMMANDS = ("generate_password_hash", "generate-config") - - exception = None - backup_stderr = sys.stderr - # Hack to divert stderr for commands generating content to stdout - # to avoid confusing the user - if len(sys.argv) > 1 and sys.argv[1] in QUIET_COMMANDS: - sys.stderr = open(os.devnull, "w") - - try: - app = create_app() - Migrate(app, db) - except Exception as e: - exception = e - - # Restore stderr - sys.stderr = backup_stderr - - if exception: - raise exception - - manager = Manager(app) - manager.add_command("db", MigrateCommand) - manager.add_command("generate_password_hash", GeneratePasswordHash) - manager.add_command("generate-config", GenerateConfig) - manager.add_command("delete-project", DeleteProject) - manager.run() - - if __name__ == "__main__": - main() + cli() diff --git a/ihatemoney/tests/main_test.py b/ihatemoney/tests/main_test.py index 06dbfac..f052ee0 100644 --- a/ihatemoney/tests/main_test.py +++ b/ihatemoney/tests/main_test.py @@ -1,4 +1,3 @@ -import io import os import smtplib import socket @@ -9,7 +8,7 @@ from sqlalchemy import orm from ihatemoney import models from ihatemoney.currency_convertor import CurrencyConverter -from ihatemoney.manage import DeleteProject, GenerateConfig, GeneratePasswordHash +from ihatemoney.manage import delete_project, generate_config, password_hash from ihatemoney.run import load_configuration from ihatemoney.tests.common.ihatemoney_testcase import BaseTestCase, IhatemoneyTestCase @@ -82,28 +81,23 @@ class CommandTestCase(BaseTestCase): - raise no exception - produce something non-empty """ - cmd = GenerateConfig() - for config_file in cmd.get_options()[0].kwargs["choices"]: - with patch("sys.stdout", new=io.StringIO()) as stdout: - cmd.run(config_file) - print(stdout.getvalue()) - self.assertNotEqual(len(stdout.getvalue().strip()), 0) + runner = self.app.test_cli_runner() + for config_file in generate_config.params[0].type.choices: + result = runner.invoke(generate_config, config_file) + self.assertNotEqual(len(result.output.strip()), 0) def test_generate_password_hash(self): - cmd = GeneratePasswordHash() - with patch("sys.stdout", new=io.StringIO()) as stdout, patch( - "getpass.getpass", new=lambda prompt: "secret" - ): # NOQA - cmd.run() - print(stdout.getvalue()) - self.assertEqual(len(stdout.getvalue().strip()), 189) + runner = self.app.test_cli_runner() + with patch("getpass.getpass", new=lambda prompt: "secret"): + result = runner.invoke(password_hash) + self.assertEqual(len(result.output.strip()), 94) def test_demo_project_deletion(self): self.create_project("demo") self.assertEquals(models.Project.query.get("demo").name, "demo") - cmd = DeleteProject() - cmd.run("demo") + runner = self.app.test_cli_runner() + runner.invoke(delete_project, "demo") self.assertEqual(len(models.Project.query.all()), 0) |
