improved env loading

This commit is contained in:
evilchili 2022-12-21 21:16:06 -08:00
parent 7c82226ff9
commit 41a21671ca
6 changed files with 105 additions and 28 deletions

View File

@ -1,21 +1,36 @@
import logging import logging
import os import os
import sys
import typer import typer
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
from textwrap import dedent
from dotenv import load_dotenv from dotenv import load_dotenv
from rich import print
from rich.logging import RichHandler from rich.logging import RichHandler
import groove.path
from groove.shell import interactive_shell from groove.shell import interactive_shell
from groove.db.manager import database_manager from groove.db.manager import database_manager
from groove.webserver import webserver from groove.webserver import webserver
from groove.exceptions import ConfigurationError
from groove.console import Console
app = typer.Typer() app = typer.Typer()
def initialize(): @app.callback()
load_dotenv() def main(
context: typer.Context,
env: Optional[Path] = typer.Option(
Path('~/.groove'),
help="Path to the Groove on Demand environment",
)
):
load_dotenv(env.expanduser())
debug = os.getenv('DEBUG', None) debug = os.getenv('DEBUG', None)
logging.basicConfig( logging.basicConfig(
format='%(message)s', format='%(message)s',
@ -26,13 +41,76 @@ def initialize():
) )
logging.getLogger('asyncio').setLevel(logging.ERROR) logging.getLogger('asyncio').setLevel(logging.ERROR)
try:
groove.path.media_root()
groove.path.static_root()
groove.path.themes_root()
groove.path.database()
except ConfigurationError as e:
sys.stderr.write(f'{e}\n')
sys.exit(1)
@app.command() @app.command()
def list(): def setup(context: typer.Context):
""" """
List all Playlists (Re)Initialize Groove on Demand.
"""
print(dedent(
"""
Interactive setup is not yet available. Sorry!
In the mean time, please make sure you set MEDIA_ROOT and SECRET_KEY
in your environment. By default, Groove on Demand will attempt to load
these variables from ~/.groove, which may contain the following
variables as well. See also the --env paramter.
# Set this one. The path containing your media files
MEDIA_ROOT=
# the kinds of files to import
# MEDIA_GLOB=*.mp3,*.flac,*.m4a
# where to store the groove_on_demand.db sqlite database.
# DATABASE_PATH=~
# Try 'groove themes' to see a list of available themes.
# DEFAULT_THEME=blue_train
# Web interface configuration
# HOST=127.0.0.1
# PORT=2323
# Set this to a suitably random string.
SECRET_KEY=much secret very private
# Console configuration
# EDITOR=
# CONSOLE_WIDTH=auto
"""
))
@app.command()
def themes(context: typer.Context):
"""
List the available themes.
"""
print("Available themes:")
themes = [theme for theme in groove.path.themes_root().iterdir()]
tags = ('artist', 'title', 'bold', 'dim', 'link', 'prompt', 'bright', 'text', 'help')
for theme in themes:
text = ''
for tag in tags:
text += f'[{tag}]◼◼◼◼◼◼'
Console(theme=theme.name).print(f' ▪ [title]{theme.name}[/title] {text}')
@app.command()
def playlists(context: typer.Context):
"""
List all playlists
""" """
initialize()
with database_manager() as manager: with database_manager() as manager:
shell = interactive_shell.InteractiveShell(manager) shell = interactive_shell.InteractiveShell(manager)
shell.list(None) shell.list(None)
@ -40,6 +118,7 @@ def list():
@app.command() @app.command()
def scan( def scan(
context: typer.Context,
path: Optional[Path] = typer.Option( path: Optional[Path] = typer.Option(
'', '',
help="A path to scan, relative to your MEDIA_ROOT. " help="A path to scan, relative to your MEDIA_ROOT. "
@ -49,7 +128,6 @@ def scan(
""" """
Scan the filesystem and create track entries in the database. Scan the filesystem and create track entries in the database.
""" """
initialize()
with database_manager() as manager: with database_manager() as manager:
shell = interactive_shell.InteractiveShell(manager) shell = interactive_shell.InteractiveShell(manager)
shell.console.print("Starting the Groove on Demand scanner...") shell.console.print("Starting the Groove on Demand scanner...")
@ -57,13 +135,17 @@ def scan(
@app.command() @app.command()
def shell(): def shell(context: typer.Context):
initialize() """
interactive_shell.start() Start the Groove on Demand interactive shell.
"""
with database_manager() as manager:
interactive_shell.InteractiveShell(manager).start()
@app.command() @app.command()
def server( def server(
context: typer.Context,
host: str = typer.Argument( host: str = typer.Argument(
'0.0.0.0', '0.0.0.0',
help="bind address", help="bind address",
@ -80,7 +162,6 @@ def server(
""" """
Start the Groove on Demand playlsit server. Start the Groove on Demand playlsit server.
""" """
initialize()
with database_manager() as manager: with database_manager() as manager:
manager.import_from_filesystem() manager.import_from_filesystem()
webserver.start(host=host, port=port, debug=debug) webserver.start(host=host, port=port, debug=debug)

View File

@ -26,7 +26,7 @@ BASE_STYLE = {
} }
def console_theme(theme_name: Union[str, None] = None) -> dict: def console_theme(theme_name: Union[str, None] = 'blue_train') -> dict:
""" """
Return a console theme as a dictionary. Return a console theme as a dictionary.
@ -36,8 +36,8 @@ def console_theme(theme_name: Union[str, None] = None) -> dict:
cfg = ConfigParser() cfg = ConfigParser()
cfg.read_dict({'styles': BASE_STYLE}) cfg.read_dict({'styles': BASE_STYLE})
cfg.read(theme( cfg.read(theme(
theme_name or os.environ['DEFAULT_THEME']) / Path('console.cfg') Path(theme_name or os.environ['DEFAULT_THEME']) / Path('console.cfg')
) ))
return cfg['styles'] return cfg['styles']

View File

@ -69,7 +69,7 @@ class MediaScanner:
console: Union[Console, None] = None, console: Union[Console, None] = None,
) -> None: ) -> None:
self._db = db self._db = db
self._glob = tuple((glob or os.environ.get('MEDIA_GLOB')).split(',')) self._glob = tuple((glob or os.environ.get('MEDIA_GLOB', '*.mp3,*.flac,*.m4a')).split(','))
self._root = groove.path.media_root() self._root = groove.path.media_root()
self._console = console or Console() self._console = console or Console()
self._scanned = 0 self._scanned = 0

View File

@ -4,14 +4,14 @@ import os
from pathlib import Path from pathlib import Path
from groove.exceptions import ConfigurationError, ThemeMissingException, ThemeConfigurationError from groove.exceptions import ConfigurationError, ThemeMissingException, ThemeConfigurationError
_setup_hint = "You may be able to solve this error by running 'groove setup'." _setup_hint = "You may be able to solve this error by running 'groove setup' or specifying the --env parameter."
_reinstall_hint = "You might need to reinstall Groove On Demand to fix this error." _reinstall_hint = "You might need to reinstall Groove On Demand to fix this error."
def root(): def root():
path = os.environ.get('GROOVE_ON_DEMAND_ROOT', None) path = os.environ.get('GROOVE_ON_DEMAND_ROOT', None)
if not path: if not path:
raise ConfigurationError(f"GROOVE_ON_DEMAND_ROOT is not defined in your environment.\n\n{_setup_hint}") raise ConfigurationError(f"GROOVE_ON_DEMAND_ROOT is not defined in your environment.\n{_setup_hint}")
path = Path(path).expanduser() path = Path(path).expanduser()
if not path.exists() or not path.is_dir(): if not path.exists() or not path.is_dir():
raise ConfigurationError( raise ConfigurationError(
@ -83,7 +83,7 @@ def themes_root():
def theme(name): def theme(name):
path = themes_root() / Path(name) path = themes_root() / Path(name)
if not path.exists() or not path.is_dir(): if not path.exists():
available = ','.join(available_themes()) available = ','.join(available_themes())
raise ThemeMissingException( raise ThemeMissingException(
f"A theme directory named {name} does not exist or isn't a directory. " f"A theme directory named {name} does not exist or isn't a directory. "
@ -102,13 +102,9 @@ def available_themes():
def database(): def database():
path = os.environ.get('DATABASE_PATH', None) path = Path(os.environ.get('DATABASE_PATH', '~')).expanduser()
if not path: if not path.exists() or not path.is_dir():
path = root() raise ConfigurationError(
else: # pragma: no cover "DATABASE_PATH doesn't exist or isn't a directory.\n\n{_setup_hint}"
path = Path(path).expanduser() )
if not path.exists() or not path.is_dir():
raise ConfigurationError(
"DATABASE_PATH doesn't exist or isn't a directory.\n\n{_setup_hint}"
)
return path / Path('groove_on_demand.db') return path / Path('groove_on_demand.db')

View File

@ -16,7 +16,7 @@ from groove.webserver import requests, themes
server = bottle.Bottle() server = bottle.Bottle()
def start(host: str, port: int, debug: bool) -> None: # pragma: no cover def start(host: str = '127.0.0.1', port: int = 2323, debug: bool = False) -> None: # pragma: no cover
""" """
Start the Bottle app. Start the Bottle app.
""" """

View File

@ -35,7 +35,7 @@ def test_theme_no_path():
def test_database_default(env): def test_database_default(env):
assert path.database().relative_to(path.root()) assert path.database()
def test_database(env): def test_database(env):