Extract config commands. Close #1

This commit is contained in:
Gabriel Augendre 2019-12-28 10:42:02 +01:00
parent 5734e36d7b
commit 4d254fc72e
No known key found for this signature in database
GPG key ID: 1E693F4CE4AEE7B4
4 changed files with 148 additions and 94 deletions

120
cleantoots/config.py Normal file
View file

@ -0,0 +1,120 @@
import configparser
import os
import sys
import click
from mastodon import Mastodon
@click.group()
@click.pass_obj
def config(config):
"""Manage cleantoot's config."""
pass
@config.command()
@click.pass_obj
def setup(config):
"""Initial setup for configuration directories and files."""
os.makedirs(config.dir, exist_ok=True)
if os.path.isfile(config.main_file):
click.secho(
"{} found. Not touching anything.".format(config.main_file), fg="yellow"
)
command = click.style("cleantoots config edit", bold=True)
click.echo("You may want to edit the file. Use: {}.".format(command))
return
default_config = configparser.ConfigParser()
default_config["DEFAULT"] = {
"boost_limit": 5,
"favorite_limit": 5,
"days_count": 30,
"timezone": "Europe/Paris",
}
default_config["Mastodon.social"] = {
"api_base_url": "https://mastodon.social",
"app_secret_file": "mastodon_social_app.secret",
"user_secret_file": "mastodon_social_user.secret",
"protected_toots": "1234\n5678",
}
with open(config.main_file, "w") as _file:
default_config.write(_file)
click.secho("{} written.".format(config.main_file), fg="green")
click.echo()
click.secho("Next steps", bold=True)
click.echo(
"You'll need to edit the config file in order to set some settings such as:"
)
click.echo("* The base URL of your Mastodon instance")
click.echo("* The toots you want to protect")
if sys.stdout.isatty() and sys.stdin.isatty():
click.echo()
click.secho("We're going to open the file for you now.")
click.pause()
click.edit(filename=config.main_file)
@config.command(name="list")
@click.pass_obj
def list_(config):
"""Display parsed config."""
if not config.sections():
click.secho("The config file doesn't seem to have any section.", fg="yellow")
command = click.style("cleantoots config setup", bold=True)
click.secho("You should set it up first. Use: {}".format(command))
return
for section_name in config.sections():
click.secho(section_name, bold=True)
section = config[section_name]
for key, value in section.items():
click.secho("{} = {}".format(key, value))
click.echo()
@config.command()
@click.pass_obj
def edit(config):
"""Edit config file."""
if not config.sections():
click.secho("The config file doesn't seem to have any section.", fg="yellow")
command = click.style("cleantoots config setup", bold=True)
click.secho("You should set it up first. Use: {}".format(command))
return
if sys.stdout.isatty() and sys.stdin.isatty():
click.edit(filename=config.main_file)
else:
click.secho("Not running in a terminal, can't open file.", fg="red")
@config.command()
@click.pass_obj
def login(config):
"""Fetch credentials for each app described in config file."""
for section in config.sections():
section = config[section]
Mastodon.create_app(
"cleantoots",
api_base_url=section.get("api_base_url"),
to_file=config.file(section.get("app_secret_file")),
)
mastodon = Mastodon(client_id=config.file(section.get("app_secret_file")))
if sys.stdout.isatty() and sys.stdin.isatty():
click.echo(
"We will now open a browser for each account set in the config file."
)
click.echo(
"You'll need to authenticate and then copy the code provided in the web "
"page back into this terminal, upon prompt."
)
click.pause()
click.launch(mastodon.auth_request_url())
else:
click.echo(
"Go to {}, authenticate and enter the code below.".format(
mastodon.auth_request_url()
)
)
code = click.prompt("Enter code for {}".format(section.get("api_base_url")))
mastodon.log_in(code=code, to_file=config.file(section.get("user_secret_file")))

View file

@ -1,13 +1,13 @@
import configparser import configparser
import os import os
import pathlib import pathlib
import sys
import click import click
import pendulum import pendulum
from click import Abort
from mastodon import Mastodon from mastodon import Mastodon
from cleantoots import config as config_commands
HOME = pathlib.Path.home() HOME = pathlib.Path.home()
DEFAULT_CONFIG_DIR = click.get_app_dir("cleantoots") DEFAULT_CONFIG_DIR = click.get_app_dir("cleantoots")
DEFAULT_CONFIG_FILENAME = "config.ini" DEFAULT_CONFIG_FILENAME = "config.ini"
@ -43,6 +43,7 @@ class CleanTootsConfig(configparser.ConfigParser):
default=DEFAULT_CONFIG_FILENAME, default=DEFAULT_CONFIG_FILENAME,
show_default=True, show_default=True,
) )
@click.version_option()
@click.pass_context @click.pass_context
def cli(ctx, config_dir, config_file): def cli(ctx, config_dir, config_file):
""" """
@ -57,89 +58,7 @@ def cli(ctx, config_dir, config_file):
ctx.obj = CleanTootsConfig(config_dir, config_file) ctx.obj = CleanTootsConfig(config_dir, config_file)
@cli.command() cli.add_command(config_commands.config)
@click.pass_obj
def setup_config(config):
"""Initial setup for configuration directories and files."""
os.makedirs(config.dir, exist_ok=True)
if os.path.isfile(config.main_file):
click.secho(
"{} found. Not touching anything.".format(config.main_file), fg="red"
)
raise Abort()
default_config = configparser.ConfigParser()
default_config["DEFAULT"] = {
"boost_limit": 5,
"favorite_limit": 5,
"days_count": 30,
"timezone": "Europe/Paris",
}
default_config["Mastodon.social"] = {
"api_base_url": "https://mastodon.social",
"app_secret_file": "mastodon_social_app.secret",
"user_secret_file": "mastodon_social_user.secret",
"protected_toots": "1234\n5678",
}
with open(config.main_file, "w") as _file:
default_config.write(_file)
click.secho("{} written.".format(config.main_file), fg="green")
click.echo()
click.secho("Next steps", bold=True)
click.echo(
"You'll need to edit the config file in order to set some settings such as:"
)
click.echo("* The base URL of your Mastodon instance")
click.echo("* The toots you want to protect")
if sys.stdout.isatty() and sys.stdin.isatty():
click.echo()
click.secho("We're going to open the file for you now.")
click.pause()
click.edit(filename=config.main_file)
@cli.command()
@click.pass_obj
def config(config):
"""Display parsed config."""
for section_name in config.sections():
click.secho(section_name, bold=True)
section = config[section_name]
for key, value in section.items():
click.secho("{} = {}".format(key, value))
click.echo()
@cli.command()
@click.pass_obj
def login(config):
"""Fetch credentials for each app described in config file."""
for section in config.sections():
section = config[section]
Mastodon.create_app(
"cleantoots",
api_base_url=section.get("api_base_url"),
to_file=config.file(section.get("app_secret_file")),
)
mastodon = Mastodon(client_id=config.file(section.get("app_secret_file")))
if sys.stdout.isatty() and sys.stdin.isatty():
click.echo(
"We will now open a browser for each account set in the config file."
)
click.echo(
"You'll need to authenticate and then copy the code provided in the web "
"page back into this terminal, upon prompt."
)
click.pause()
click.launch(mastodon.auth_request_url())
else:
click.echo(
"Go to {}, authenticate and enter the code below.".format(
mastodon.auth_request_url()
)
)
code = click.prompt("Enter code for {}".format(section.get("api_base_url")))
mastodon.log_in(code=code, to_file=config.file(section.get("user_secret_file")))
@cli.command() @cli.command()

View file

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "cleantoots" name = "cleantoots"
version = "0.2.3" version = "0.3.0"
description = "Cleanup your toot history." description = "Cleanup your toot history."
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
authors = ["Gabriel Augendre <gabriel@augendre.info>"] authors = ["Gabriel Augendre <gabriel@augendre.info>"]

View file

@ -12,23 +12,24 @@ class SetupConfigTestCase(unittest.TestCase):
def test_setup_config(self): def test_setup_config(self):
with self.runner.isolated_filesystem(): with self.runner.isolated_filesystem():
result = self.runner.invoke(cli, ["-d", ".", "setup-config"]) result = self.runner.invoke(cli, ["-d", ".", "config", "setup"])
self.assertEqual(result.exit_code, 0) self.assertEqual(result.exit_code, 0)
self.assertIn("config.ini written", result.output) self.assertIn("config.ini written", result.output)
self.assertTrue(os.path.isfile(os.path.join(".", "config.ini"))) self.assertTrue(os.path.isfile(os.path.join(".", "config.ini")))
def test_setup_config_twice_fails(self): def test_setup_config_twice_fails(self):
with self.runner.isolated_filesystem(): with self.runner.isolated_filesystem():
self.runner.invoke(cli, ["-d", ".", "setup-config"]) self.runner.invoke(cli, ["-d", ".", "config", "setup"])
self.assertTrue(os.path.isfile(os.path.join(".", "config.ini"))) self.assertTrue(os.path.isfile(os.path.join(".", "config.ini")))
result = self.runner.invoke(cli, ["-d", ".", "setup-config"]) result = self.runner.invoke(cli, ["-d", ".", "config", "setup"])
self.assertEqual(result.exit_code, 1) self.assertEqual(result.exit_code, 0)
self.assertIn("Not touching anything", result.output) self.assertIn("Not touching anything", result.output)
self.assertIn("cleantoots config edit", result.output)
def test_config_output(self): def test_config_output(self):
with self.runner.isolated_filesystem(): with self.runner.isolated_filesystem():
self.runner.invoke(cli, ["-d", ".", "setup-config"]) self.runner.invoke(cli, ["-d", ".", "config", "setup"])
result = self.runner.invoke(cli, ["-d", ".", "config"]) result = self.runner.invoke(cli, ["-d", ".", "config", "list"])
expected = [ expected = [
"Mastodon.social", "Mastodon.social",
"api_base_url", "api_base_url",
@ -43,10 +44,24 @@ class SetupConfigTestCase(unittest.TestCase):
for exp in expected: for exp in expected:
self.assertIn(exp, result.output) self.assertIn(exp, result.output)
def test_config_list_no_file(self):
with self.runner.isolated_filesystem():
result = self.runner.invoke(cli, ["-d", ".", "config", "list"])
self.assertIn("cleantoots config setup", result.output)
self.assertEqual(0, result.exit_code)
def test_config_edit_no_file(self):
with self.runner.isolated_filesystem():
result = self.runner.invoke(cli, ["-d", ".", "config", "edit"])
self.assertIn("cleantoots config setup", result.output)
self.assertEqual(0, result.exit_code)
def test_login_output(self): def test_login_output(self):
with self.runner.isolated_filesystem(): with self.runner.isolated_filesystem():
self.runner.invoke(cli, ["-d", ".", "setup-config"]) self.runner.invoke(cli, ["-d", ".", "config", "setup"])
result = self.runner.invoke(cli, ["-d", ".", "login"], input="\nFAKECODE") result = self.runner.invoke(
cli, ["-d", ".", "config", "login"], input="\nFAKECODE"
)
self.assertIn("Enter code for", result.output) self.assertIn("Enter code for", result.output)