mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-11 05:27:21 +00:00
feat: add migration to move old files to xdg directory
+ add db column for migration version + handle pre-init migrations + handle post-init migration
This commit is contained in:
parent
97e29c3254
commit
b77b1747f1
64
app/db/sqlite/migrations.py
Normal file
64
app/db/sqlite/migrations.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
"""
|
||||||
|
Reads and saves the latest database migrations version.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from app.db.sqlite.utils import SQLiteManager
|
||||||
|
|
||||||
|
|
||||||
|
class MigrationManager:
|
||||||
|
all_get_sql = "SELECT * FROM migrations"
|
||||||
|
pre_init_set_sql = "UPDATE migrations SET pre_init_version = ? WHERE id = 1"
|
||||||
|
post_init_set_sql = "UPDATE migrations SET post_init_version = ? WHERE id = 1"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_preinit_version(cls) -> int:
|
||||||
|
"""
|
||||||
|
Returns the latest userdata pre-init database version.
|
||||||
|
"""
|
||||||
|
with SQLiteManager() as cur:
|
||||||
|
cur.execute(cls.all_get_sql)
|
||||||
|
return int(cur.fetchone()[1])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_maindb_postinit_version(cls) -> int:
|
||||||
|
"""
|
||||||
|
Returns the latest maindb post-init database version.
|
||||||
|
"""
|
||||||
|
with SQLiteManager() as cur:
|
||||||
|
cur.execute(cls.all_get_sql)
|
||||||
|
return int(cur.fetchone()[2])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_userdatadb_postinit_version(cls) -> int:
|
||||||
|
"""
|
||||||
|
Returns the latest userdata post-init database version.
|
||||||
|
"""
|
||||||
|
with SQLiteManager(userdata_db=True) as cur:
|
||||||
|
cur.execute(cls.all_get_sql)
|
||||||
|
return cur.fetchone()[2]
|
||||||
|
|
||||||
|
# 👇 Setters 👇
|
||||||
|
@classmethod
|
||||||
|
def set_preinit_version(cls, version: int):
|
||||||
|
"""
|
||||||
|
Sets the userdata pre-init database version.
|
||||||
|
"""
|
||||||
|
with SQLiteManager() as cur:
|
||||||
|
cur.execute(cls.pre_init_set_sql, (version,))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_maindb_postinit_version(cls, version: int):
|
||||||
|
"""
|
||||||
|
Sets the maindb post-init database version.
|
||||||
|
"""
|
||||||
|
with SQLiteManager() as cur:
|
||||||
|
cur.execute(cls.post_init_set_sql, (version,))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_userdatadb_postinit_version(cls, version: int):
|
||||||
|
"""
|
||||||
|
Sets the userdata post-init database version.
|
||||||
|
"""
|
||||||
|
with SQLiteManager(userdata_db=True) as cur:
|
||||||
|
cur.execute(cls.post_init_set_sql, (version,))
|
@ -69,3 +69,13 @@ CREATE TABLE IF NOT EXISTS folders (
|
|||||||
trackcount integer NOT NULL
|
trackcount integer NOT NULL
|
||||||
);
|
);
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CREATE_MIGRATIONS_TABLE = """
|
||||||
|
CREATE TABLE IF NOT EXISTS migrations (
|
||||||
|
id integer PRIMARY KEY,
|
||||||
|
pre_init_version integer NOT NULL DEFAULT 0,
|
||||||
|
post_init_version integer NOT NULL DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO migrations (pre_init_version, post_init_version) VALUES (0, 0);
|
||||||
|
"""
|
||||||
|
@ -2,19 +2,43 @@
|
|||||||
Migrations module.
|
Migrations module.
|
||||||
|
|
||||||
Reads and applies the latest database migrations.
|
Reads and applies the latest database migrations.
|
||||||
|
|
||||||
|
PLEASE NOTE: OLDER MIGRATIONS CAN NEVER BE DELETED.
|
||||||
|
ONLY MODIFY OLD MIGRATIONS FOR BUG FIXES OR ENHANCEMENTS ONLY
|
||||||
|
[TRY NOT TO MODIFY BEHAVIOR, UNLESS YOU KNOW WHAT YOU'RE DOING].
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from app.db.sqlite.migrations import MigrationManager
|
||||||
|
from app.logger import log
|
||||||
|
|
||||||
from .main import main_db_migrations
|
from .main import main_db_migrations
|
||||||
from .userdata import userdata_db_migrations
|
from .userdata import userdata_db_migrations
|
||||||
|
|
||||||
|
|
||||||
def apply_migrations():
|
def apply_migrations():
|
||||||
userdb_version = 0
|
"""
|
||||||
maindb_version = 0
|
Applies the latest database migrations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
userdb_version = MigrationManager.get_userdatadb_postinit_version()
|
||||||
|
maindb_version = MigrationManager.get_maindb_postinit_version()
|
||||||
|
|
||||||
for migration in main_db_migrations:
|
for migration in main_db_migrations:
|
||||||
if migration.version > maindb_version:
|
if migration.version > maindb_version:
|
||||||
|
log.info("Running new MAIN-DB post-init migration: %s", migration.name)
|
||||||
migration.migrate()
|
migration.migrate()
|
||||||
|
|
||||||
for migration in userdata_db_migrations:
|
for migration in userdata_db_migrations:
|
||||||
if migration.version > userdb_version:
|
if migration.version > userdb_version:
|
||||||
|
log.info("Running new USERDATA-DB post-init migration: %s", migration.name)
|
||||||
migration.migrate()
|
migration.migrate()
|
||||||
|
|
||||||
|
|
||||||
|
def set_postinit_migration_versions():
|
||||||
|
"""
|
||||||
|
Sets the post-init migration versions.
|
||||||
|
"""
|
||||||
|
# TODO: Don't forget to remove the zeros below when you add a valid migration 👇.
|
||||||
|
MigrationManager.set_maindb_postinit_version(0)
|
||||||
|
MigrationManager.set_userdatadb_postinit_version(0)
|
||||||
|
38
app/migrations/_preinit/__init__.py
Normal file
38
app/migrations/_preinit/__init__.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
"""
|
||||||
|
Pre-init migrations are executed before the database is created.
|
||||||
|
Useful when you need to move files or folders before the database is created.
|
||||||
|
|
||||||
|
PLEASE NOTE: OLDER MIGRATIONS CAN NEVER BE DELETED.
|
||||||
|
ONLY MODIFY OLD MIGRATIONS FOR BUG FIXES OR ENHANCEMENTS ONLY.
|
||||||
|
[TRY NOT TO MODIFY BEHAVIOR, UNLESS YOU KNOW WHAT YOU'RE DOING].
|
||||||
|
"""
|
||||||
|
from sqlite3 import OperationalError
|
||||||
|
|
||||||
|
from app.db.sqlite.migrations import MigrationManager
|
||||||
|
from app.logger import log
|
||||||
|
|
||||||
|
from .move_to_xdg_folder import MoveToXdgFolder
|
||||||
|
|
||||||
|
all_preinits = [MoveToXdgFolder]
|
||||||
|
|
||||||
|
|
||||||
|
def run_preinit_migrations():
|
||||||
|
"""
|
||||||
|
Runs all pre-init migrations.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
userdb_version = MigrationManager.get_preinit_version()
|
||||||
|
except (OperationalError):
|
||||||
|
userdb_version = 0
|
||||||
|
|
||||||
|
for migration in all_preinits:
|
||||||
|
if migration.version > userdb_version:
|
||||||
|
log.warn("Running new pre-init migration: %s", migration.name)
|
||||||
|
migration.migrate()
|
||||||
|
|
||||||
|
|
||||||
|
def set_preinit_migration_versions():
|
||||||
|
"""
|
||||||
|
Sets the migration versions.
|
||||||
|
"""
|
||||||
|
MigrationManager.set_preinit_version(all_preinits[-1].version)
|
49
app/migrations/_preinit/move_to_xdg_folder.py
Normal file
49
app/migrations/_preinit/move_to_xdg_folder.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
"""
|
||||||
|
This migration handles moving the config folder to the XDG standard location.
|
||||||
|
It also handles moving the userdata and the downloaded artist images to the new location.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from app.settings import APP_DIR, USER_HOME_DIR
|
||||||
|
from app.logger import log
|
||||||
|
|
||||||
|
|
||||||
|
class MoveToXdgFolder:
|
||||||
|
version = 1
|
||||||
|
name = "MoveToXdgFolder"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def migrate():
|
||||||
|
old_config_dir = os.path.join(USER_HOME_DIR, ".swing")
|
||||||
|
new_config_dir = APP_DIR
|
||||||
|
|
||||||
|
if not os.path.exists(old_config_dir):
|
||||||
|
log.info("No old config folder found. Skipping migration.")
|
||||||
|
return
|
||||||
|
|
||||||
|
log.info("Found old config folder: %s", old_config_dir)
|
||||||
|
old_imgs_dir = os.path.join(old_config_dir, "images")
|
||||||
|
|
||||||
|
# move images to new location
|
||||||
|
if os.path.exists(old_imgs_dir):
|
||||||
|
shutil.copytree(
|
||||||
|
old_imgs_dir,
|
||||||
|
os.path.join(new_config_dir, "images"),
|
||||||
|
copy_function=shutil.copy2,
|
||||||
|
dirs_exist_ok=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
log.warn("Moved artist images to: %s", new_config_dir)
|
||||||
|
|
||||||
|
# move userdata.db to new location
|
||||||
|
userdata_db = os.path.join(old_config_dir, "userdata.db")
|
||||||
|
if os.path.exists(userdata_db):
|
||||||
|
shutil.copy2(userdata_db, new_config_dir)
|
||||||
|
|
||||||
|
log.warn("Moved userdata.db to: %s", new_config_dir)
|
||||||
|
log.warn("Migration complete. ✅")
|
||||||
|
|
||||||
|
# swing.db is not moved because the new code fixes bugs which require
|
||||||
|
# the whole database to be recreated anyway. (ie. the bug which caused duplicate album and artist color entries)
|
@ -1,4 +1,10 @@
|
|||||||
from .sample import SampleMigrationModel
|
"""
|
||||||
|
Migrations for the main database.
|
||||||
|
|
||||||
main_db_migrations = [SampleMigrationModel]
|
PLEASE NOTE: OLDER MIGRATIONS CAN NEVER BE DELETED.
|
||||||
|
ONLY MODIFY OLD MIGRATIONS FOR BUG FIXES OR ENHANCEMENTS ONLY
|
||||||
|
[TRY NOT TO MODIFY BEHAVIOR, UNLESS YOU KNOW WHAT YOU'RE DOING].
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
main_db_migrations = []
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
class SampleMigrationModel:
|
|
||||||
version = 1
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def migrate():
|
|
||||||
print("executing sample main db migration")
|
|
@ -1,4 +1,10 @@
|
|||||||
from .sample import SampleMigrationModel
|
"""
|
||||||
|
Migrations for the userdata database.
|
||||||
|
|
||||||
userdata_db_migrations = [SampleMigrationModel]
|
PLEASE NOTE: OLDER MIGRATIONS CAN NEVER BE DELETED.
|
||||||
|
ONLY MODIFY OLD MIGRATIONS FOR BUG FIXES OR ENHANCEMENTS ONLY
|
||||||
|
[TRY NOT TO MODIFY BEHAVIOR, UNLESS YOU KNOW WHAT YOU'RE DOING].
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
userdata_db_migrations = []
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
class SampleMigrationModel:
|
|
||||||
version = 1
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def migrate():
|
|
||||||
print("executing sample userdata db migration")
|
|
@ -3,14 +3,19 @@ Contains the functions to prepare the server for use.
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import time
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
|
|
||||||
from app import settings
|
from app import settings
|
||||||
from app.db.sqlite import create_connection, create_tables, queries
|
from app.db.sqlite import create_connection, create_tables, queries
|
||||||
from app.db.store import Store
|
from app.db.store import Store
|
||||||
|
from app.migrations import apply_migrations, set_postinit_migration_versions
|
||||||
|
from app.migrations._preinit import (
|
||||||
|
run_preinit_migrations,
|
||||||
|
set_preinit_migration_versions,
|
||||||
|
)
|
||||||
from app.settings import APP_DB_PATH, USERDATA_DB_PATH
|
from app.settings import APP_DB_PATH, USERDATA_DB_PATH
|
||||||
from app.utils import get_home_res_path
|
from app.utils import get_home_res_path
|
||||||
from app.migrations import apply_migrations
|
|
||||||
|
|
||||||
config = ConfigParser()
|
config = ConfigParser()
|
||||||
|
|
||||||
@ -102,6 +107,7 @@ def setup_sqlite():
|
|||||||
"""
|
"""
|
||||||
# if os.path.exists(DB_PATH):
|
# if os.path.exists(DB_PATH):
|
||||||
# os.remove(DB_PATH)
|
# os.remove(DB_PATH)
|
||||||
|
run_preinit_migrations()
|
||||||
|
|
||||||
app_db_conn = create_connection(APP_DB_PATH)
|
app_db_conn = create_connection(APP_DB_PATH)
|
||||||
playlist_db_conn = create_connection(USERDATA_DB_PATH)
|
playlist_db_conn = create_connection(USERDATA_DB_PATH)
|
||||||
@ -109,10 +115,15 @@ def setup_sqlite():
|
|||||||
create_tables(app_db_conn, queries.CREATE_APPDB_TABLES)
|
create_tables(app_db_conn, queries.CREATE_APPDB_TABLES)
|
||||||
create_tables(playlist_db_conn, queries.CREATE_USERDATA_TABLES)
|
create_tables(playlist_db_conn, queries.CREATE_USERDATA_TABLES)
|
||||||
|
|
||||||
|
create_tables(app_db_conn, queries.CREATE_MIGRATIONS_TABLE)
|
||||||
|
create_tables(playlist_db_conn, queries.CREATE_MIGRATIONS_TABLE)
|
||||||
|
|
||||||
app_db_conn.close()
|
app_db_conn.close()
|
||||||
playlist_db_conn.close()
|
playlist_db_conn.close()
|
||||||
|
|
||||||
apply_migrations()
|
apply_migrations()
|
||||||
|
set_preinit_migration_versions()
|
||||||
|
set_postinit_migration_versions()
|
||||||
|
|
||||||
Store.load_all_tracks()
|
Store.load_all_tracks()
|
||||||
Store.process_folders()
|
Store.process_folders()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user