Revert db checks in launcher that caused instability with imports. Resolve #3790

This commit is contained in:
Griatch 2025-05-22 23:10:53 +02:00
parent 4bc6abfdb9
commit baf9a4068b
2 changed files with 62 additions and 84 deletions

View file

@ -50,6 +50,7 @@ This upgrade requires running `evennia migrate` on your existing database
- [Fix][pull3768]: Make sure the `CmdCopy` command copies object categories, - [Fix][pull3768]: Make sure the `CmdCopy` command copies object categories,
since otherwise plurals were lost (jaborsh) since otherwise plurals were lost (jaborsh)
- [Fix][issue3788]: `GLOBAL_SCRIPTS.all()` raised error (Griatch) - [Fix][issue3788]: `GLOBAL_SCRIPTS.all()` raised error (Griatch)
- [Fix][issue3790]: Fix migration issue due to new db init-check code in launcher (Griatch)
- Fix: `options` setting `NOPROMPTGOAHEAD` was not possible to set (Griatch) - Fix: `options` setting `NOPROMPTGOAHEAD` was not possible to set (Griatch)
- Fix: Make `\\` properly preserve one backlash in funcparser (Griatch) - Fix: Make `\\` properly preserve one backlash in funcparser (Griatch)
- Fix: The testing 'echo' inputfunc didn't work correctly; now returns both args/kwargs (Griatch) - Fix: The testing 'echo' inputfunc didn't work correctly; now returns both args/kwargs (Griatch)
@ -90,6 +91,7 @@ This upgrade requires running `evennia migrate` on your existing database
[issue3688]: https://github.com/evennia/evennia/issues/3688 [issue3688]: https://github.com/evennia/evennia/issues/3688
[issue3687]: https://github.com/evennia/evennia/issues/3687 [issue3687]: https://github.com/evennia/evennia/issues/3687
[issue3788]: https://github.com/evennia/evennia/issues/3788 [issue3788]: https://github.com/evennia/evennia/issues/3788
[issue3790]: https://github.com/evennia/evennia/issues/3790

View file

@ -248,7 +248,7 @@ RECREATED_MISSING = """
ERROR_DATABASE = """ ERROR_DATABASE = """
ERROR: Your database does not exist or is not set up correctly. ERROR: Your database does not exist or is not set up correctly.
Missing tables: {missing_tables} (error was '{traceback}')
If you think your database should work, make sure you are running your If you think your database should work, make sure you are running your
commands from inside your game directory. If this error persists, run commands from inside your game directory. If this error persists, run
@ -820,7 +820,7 @@ def start_evennia(pprofiler=False, sprofiler=False):
if response: if response:
_, _, _, _, pinfo, sinfo = response _, _, _, _, pinfo, sinfo = response
_print_info(pinfo, sinfo) _print_info(pinfo, sinfo)
_reactor_stop() _reactor_stop()
def _portal_started(*args): def _portal_started(*args):
print( print(
@ -1460,15 +1460,9 @@ def create_game_directory(dirname):
def create_superuser(): def create_superuser():
""" """
Auto-create the superuser account. Returns `True` if superuser was created. Create the superuser account
""" """
from evennia.accounts.models import AccountDB
if AccountDB.objects.filter(is_superuser=True).exists():
# if superuser already exists, do nothing here
return False
print( print(
"\nCreate a superuser below. The superuser is Account #1, the 'owner' " "\nCreate a superuser below. The superuser is Account #1, the 'owner' "
"account of the server. Email is optional and can be empty.\n" "account of the server. Email is optional and can be empty.\n"
@ -1480,95 +1474,79 @@ def create_superuser():
password = environ.get("EVENNIA_SUPERUSER_PASSWORD") password = environ.get("EVENNIA_SUPERUSER_PASSWORD")
if (username is not None) and (password is not None) and len(password) > 0: if (username is not None) and (password is not None) and len(password) > 0:
from evennia.accounts.models import AccountDB
superuser = AccountDB.objects.create_superuser(username, email, password) superuser = AccountDB.objects.create_superuser(username, email, password)
superuser.save() superuser.save()
else: else:
django.core.management.call_command("createsuperuser", interactive=True) django.core.management.call_command("createsuperuser", interactive=True)
return True
def check_database(always_return=False): def check_database(always_return=False):
""" """
Check if the database exists and has basic tables. This is only run by the launcher. Check so the database exists.
Args: Args:
always_return (bool, optional): If True, will not raise exceptions on errors. always_return (bool, optional): If set, will always return True/False
also on critical errors. No output will be printed.
Returns: Returns:
exists (bool): `True` if database exists and seems set up, `False` otherwise. exists (bool): `True` if the database exists, otherwise `False`.
If `always_return` is `False`, this will raise exceptions instead of
returning `False`.
""" """
# Check if database exists # Check so a database exists and is accessible
from django.conf import settings
from django.db import connection from django.db import connection
tables_to_check = [ tables = connection.introspection.get_table_list(connection.cursor())
"accounts_accountdb", # base account table if not tables or not isinstance(tables[0], str): # django 1.8+
"objects_objectdb", # base object table tables = [tableinfo.name for tableinfo in tables]
"scripts_scriptdb", # base script table if tables and "accounts_accountdb" in tables:
"typeclasses_tag", # base tag table # database exists and seems set up. Initialize evennia.
] evennia._init()
# Try to get Account#1
from evennia.accounts.models import AccountDB
try: try:
with connection.cursor() as cursor: AccountDB.objects.get(id=1)
# Get all table names in the database except (django.db.utils.OperationalError, ProgrammingError) as e:
if connection.vendor == "postgresql": if always_return:
cursor.execute( return False
""" print(ERROR_DATABASE.format(traceback=e))
SELECT tablename FROM pg_tables sys.exit()
WHERE schemaname = 'public' except AccountDB.DoesNotExist:
""" # no superuser yet. We need to create it.
)
elif connection.vendor == "mysql":
cursor.execute(
"""
SELECT table_name FROM information_schema.tables
WHERE table_schema = %s
""",
[settings.DATABASES["default"]["NAME"]],
)
elif connection.vendor == "sqlite":
cursor.execute(
"""
SELECT name FROM sqlite_master
WHERE type='table' AND name NOT LIKE 'sqlite_%'
"""
)
else:
if not always_return:
raise Exception(
f"Unsupported database: {connection.vendor}"
"Evennia supports PostgreSQL, MySQL, and SQLite only."
)
return False
existing_tables = {row[0].lower() for row in cursor.fetchall()} other_superuser = AccountDB.objects.filter(is_superuser=True)
if other_superuser:
# Another superuser was found, but not with id=1. This may
# happen if using flush (the auto-id starts at a higher
# value). Wwe copy this superuser into id=1. To do
# this we must deepcopy it, delete it then save the copy
# with the new id. This allows us to avoid the UNIQUE
# constraint on usernames.
other = other_superuser[0]
other_id = other.id
other_key = other.username
print(WARNING_MOVING_SUPERUSER.format(other_key=other_key, other_id=other_id))
res = ""
while res.upper() != "Y":
# ask for permission
res = eval(input("Continue [Y]/N: "))
if res.upper() == "N":
sys.exit()
elif not res:
break
# continue with the
from copy import deepcopy
# Check if essential tables exist new = deepcopy(other)
missing_tables = [table for table in tables_to_check if table not in existing_tables] other.delete()
new.id = 1
if missing_tables: new.save()
if always_return: else:
return False create_superuser()
raise Exception( check_database(always_return=always_return)
f"Database tables missing: {', '.join(missing_tables)}. " return True
"\nDid you remember to run migrations?"
)
else:
create_superuser()
return True
except Exception as exc:
if not always_return:
raise
import traceback
traceback.print_exc()
return False
def getenv(): def getenv():
@ -1810,12 +1788,11 @@ def init_game_directory(path, check_db=True, need_gamedir=True):
else: else:
os.environ["DJANGO_SETTINGS_MODULE"] = SETTINGS_DOTPATH os.environ["DJANGO_SETTINGS_MODULE"] = SETTINGS_DOTPATH
# required since django1.7
django.setup()
# test existence of the settings module # test existence of the settings module
try: try:
# required since django1.7
django.setup()
from django.conf import settings from django.conf import settings
except Exception as ex: except Exception as ex:
if not str(ex).startswith("No module named"): if not str(ex).startswith("No module named"):
@ -1828,7 +1805,6 @@ def init_game_directory(path, check_db=True, need_gamedir=True):
# this will both check the database and initialize the evennia dir. # this will both check the database and initialize the evennia dir.
if check_db: if check_db:
check_database() check_database()
evennia._init()
# if we don't have to check the game directory, return right away # if we don't have to check the game directory, return right away
if not need_gamedir: if not need_gamedir: