Python3 Migrate
This commit is contained in:
231
venv/lib/python3.7/site-packages/mopidy/__main__.py
Normal file
231
venv/lib/python3.7/site-packages/mopidy/__main__.py
Normal file
@@ -0,0 +1,231 @@
|
||||
import logging
|
||||
import signal
|
||||
import sys
|
||||
|
||||
import pykka.debug
|
||||
|
||||
from mopidy import commands
|
||||
from mopidy import config as config_lib
|
||||
from mopidy import ext
|
||||
from mopidy.internal import log, path, process, versioning
|
||||
from mopidy.internal.gi import Gst # noqa: F401
|
||||
|
||||
try:
|
||||
# Make GLib's mainloop the event loop for python-dbus
|
||||
import dbus.mainloop.glib
|
||||
|
||||
dbus.mainloop.glib.threads_init()
|
||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def main():
|
||||
log.bootstrap_delayed_logging()
|
||||
logger.info(f"Starting Mopidy {versioning.get_version()}")
|
||||
|
||||
signal.signal(signal.SIGTERM, process.sigterm_handler)
|
||||
# Windows does not have signal.SIGUSR1
|
||||
if hasattr(signal, "SIGUSR1"):
|
||||
signal.signal(signal.SIGUSR1, pykka.debug.log_thread_tracebacks)
|
||||
|
||||
try:
|
||||
registry = ext.Registry()
|
||||
|
||||
root_cmd = commands.RootCommand()
|
||||
config_cmd = commands.ConfigCommand()
|
||||
deps_cmd = commands.DepsCommand()
|
||||
|
||||
root_cmd.set(extension=None, registry=registry)
|
||||
root_cmd.add_child("config", config_cmd)
|
||||
root_cmd.add_child("deps", deps_cmd)
|
||||
|
||||
extensions_data = ext.load_extensions()
|
||||
|
||||
for data in extensions_data:
|
||||
if data.command: # TODO: check isinstance?
|
||||
data.command.set(extension=data.extension)
|
||||
root_cmd.add_child(data.extension.ext_name, data.command)
|
||||
|
||||
args = root_cmd.parse(sys.argv[1:])
|
||||
|
||||
config, config_errors = config_lib.load(
|
||||
args.config_files,
|
||||
[d.config_schema for d in extensions_data],
|
||||
[d.config_defaults for d in extensions_data],
|
||||
args.config_overrides,
|
||||
)
|
||||
|
||||
create_core_dirs(config)
|
||||
create_initial_config_file(args, extensions_data)
|
||||
|
||||
log.setup_logging(
|
||||
config, args.base_verbosity_level, args.verbosity_level
|
||||
)
|
||||
|
||||
extensions = {
|
||||
"validate": [],
|
||||
"config": [],
|
||||
"disabled": [],
|
||||
"enabled": [],
|
||||
}
|
||||
for data in extensions_data:
|
||||
extension = data.extension
|
||||
|
||||
# TODO: factor out all of this to a helper that can be tested
|
||||
if not ext.validate_extension_data(data):
|
||||
config[extension.ext_name] = {"enabled": False}
|
||||
config_errors[extension.ext_name] = {
|
||||
"enabled": "extension disabled by self check."
|
||||
}
|
||||
extensions["validate"].append(extension)
|
||||
elif not config[extension.ext_name]["enabled"]:
|
||||
config[extension.ext_name] = {"enabled": False}
|
||||
config_errors[extension.ext_name] = {
|
||||
"enabled": "extension disabled by user config."
|
||||
}
|
||||
extensions["disabled"].append(extension)
|
||||
elif config_errors.get(extension.ext_name):
|
||||
config[extension.ext_name]["enabled"] = False
|
||||
config_errors[extension.ext_name][
|
||||
"enabled"
|
||||
] = "extension disabled due to config errors."
|
||||
extensions["config"].append(extension)
|
||||
else:
|
||||
extensions["enabled"].append(extension)
|
||||
|
||||
log_extension_info(
|
||||
[d.extension for d in extensions_data], extensions["enabled"]
|
||||
)
|
||||
|
||||
# Config and deps commands are simply special cased for now.
|
||||
if args.command == config_cmd:
|
||||
schemas = [d.config_schema for d in extensions_data]
|
||||
return args.command.run(config, config_errors, schemas)
|
||||
elif args.command == deps_cmd:
|
||||
return args.command.run()
|
||||
|
||||
check_config_errors(config, config_errors, extensions)
|
||||
|
||||
if not extensions["enabled"]:
|
||||
logger.error("No extension enabled, exiting...")
|
||||
sys.exit(1)
|
||||
|
||||
# Read-only config from here on, please.
|
||||
proxied_config = config_lib.Proxy(config)
|
||||
|
||||
if args.extension and args.extension not in extensions["enabled"]:
|
||||
logger.error(
|
||||
"Unable to run command provided by disabled extension %s",
|
||||
args.extension.ext_name,
|
||||
)
|
||||
return 1
|
||||
|
||||
for extension in extensions["enabled"]:
|
||||
try:
|
||||
extension.setup(registry)
|
||||
except Exception:
|
||||
# TODO: would be nice a transactional registry. But sadly this
|
||||
# is a bit tricky since our current API is giving out a mutable
|
||||
# list. We might however be able to replace this with a
|
||||
# collections.Sequence to provide a RO view.
|
||||
logger.exception(
|
||||
f"Extension {extension.ext_name} failed during setup. "
|
||||
f"This might have left the registry in a bad state."
|
||||
)
|
||||
|
||||
# Anything that wants to exit after this point must use
|
||||
# mopidy.internal.process.exit_process as actors can have been started.
|
||||
try:
|
||||
return args.command.run(args, proxied_config)
|
||||
except NotImplementedError:
|
||||
print(root_cmd.format_help())
|
||||
return 1
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except Exception as ex:
|
||||
logger.exception(ex)
|
||||
raise
|
||||
|
||||
|
||||
def create_core_dirs(config):
|
||||
path.get_or_create_dir(config["core"]["cache_dir"])
|
||||
path.get_or_create_dir(config["core"]["config_dir"])
|
||||
path.get_or_create_dir(config["core"]["data_dir"])
|
||||
|
||||
|
||||
def create_initial_config_file(args, extensions_data):
|
||||
"""Initialize whatever the last config file is with defaults"""
|
||||
|
||||
config_file = path.expand_path(args.config_files[-1])
|
||||
|
||||
if config_file.exists():
|
||||
return
|
||||
|
||||
try:
|
||||
default = config_lib.format_initial(extensions_data)
|
||||
path.get_or_create_file(
|
||||
config_file,
|
||||
mkdir=False,
|
||||
content=default.encode(errors="surrogateescape"),
|
||||
)
|
||||
logger.info(f"Initialized {config_file.as_uri()} with default config")
|
||||
except OSError as exc:
|
||||
logger.warning(
|
||||
f"Unable to initialize {config_file.as_uri()} with default config: {exc}"
|
||||
)
|
||||
|
||||
|
||||
def log_extension_info(all_extensions, enabled_extensions):
|
||||
# TODO: distinguish disabled vs blocked by env?
|
||||
enabled_names = {e.ext_name for e in enabled_extensions}
|
||||
disabled_names = {e.ext_name for e in all_extensions} - enabled_names
|
||||
logger.info("Enabled extensions: %s", ", ".join(enabled_names) or "none")
|
||||
logger.info("Disabled extensions: %s", ", ".join(disabled_names) or "none")
|
||||
|
||||
|
||||
def check_config_errors(config, errors, extensions):
|
||||
fatal_errors = []
|
||||
extension_names = {}
|
||||
all_extension_names = set()
|
||||
|
||||
for state in extensions:
|
||||
extension_names[state] = {e.ext_name for e in extensions[state]}
|
||||
all_extension_names.update(extension_names[state])
|
||||
|
||||
for section in sorted(errors):
|
||||
if not errors[section]:
|
||||
continue
|
||||
|
||||
if section not in all_extension_names:
|
||||
logger.warning(f"Found fatal {section} configuration errors:")
|
||||
fatal_errors.append(section)
|
||||
elif section in extension_names["config"]:
|
||||
del errors[section]["enabled"]
|
||||
logger.warning(
|
||||
f"Found {section} configuration errors. "
|
||||
f"The extension has been automatically disabled:"
|
||||
)
|
||||
else:
|
||||
continue
|
||||
|
||||
for field, msg in errors[section].items():
|
||||
logger.warning(f" {section}/{field} {msg}")
|
||||
|
||||
if extensions["config"]:
|
||||
logger.warning(
|
||||
"Please fix the extension configuration errors or "
|
||||
"disable the extensions to silence these messages."
|
||||
)
|
||||
|
||||
if fatal_errors:
|
||||
logger.error("Please fix fatal configuration errors, exiting...")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user