diff --git a/conftest.py b/conftest.py index 3787228..78f2640 100644 --- a/conftest.py +++ b/conftest.py @@ -42,10 +42,21 @@ def config(isolated_dir: Path) -> Config: with sqlite3.connect(cache_database_path) as conn: with CACHE_SCHEMA_PATH.open("r") as fp: conn.executescript(fp.read()) - conn.execute("CREATE TABLE _schema_hash (value TEXT PRIMARY KEY)") + conn.execute( + """ + CREATE TABLE _schema_hash ( + schema_hash TEXT + , config_hash TEXT + , PRIMARY KEY (schema_hash, config_hash) + ) + """ + ) with CACHE_SCHEMA_PATH.open("rb") as fp: - latest_schema_hash = hashlib.sha256(fp.read()).hexdigest() - conn.execute("INSERT INTO _schema_hash (value) VALUES (?)", (latest_schema_hash,)) + schema_hash = hashlib.sha256(fp.read()).hexdigest() + conn.execute( + "INSERT INTO _schema_hash (schema_hash, config_hash) VALUES (?, ?)", + (schema_hash, "00ff"), + ) music_source_dir = isolated_dir / "source" music_source_dir.mkdir() @@ -64,6 +75,7 @@ def config(isolated_dir: Path) -> Config: fuse_hide_artists=[], fuse_hide_genres=[], fuse_hide_labels=[], + hash="00ff", ) diff --git a/rose/cache.py b/rose/cache.py index fa87055..8db4127 100644 --- a/rose/cache.py +++ b/rose/cache.py @@ -56,7 +56,7 @@ def migrate_database(c: Config) -> None: its own data. """ with CACHE_SCHEMA_PATH.open("rb") as fp: - latest_schema_hash = hashlib.sha256(fp.read()).hexdigest() + schema_hash = hashlib.sha256(fp.read()).hexdigest() with connect(c) as conn: cursor = conn.execute( @@ -68,8 +68,9 @@ def migrate_database(c: Config) -> None: """ ) if cursor.fetchone()[0]: - cursor = conn.execute("SELECT value FROM _schema_hash") - if (row := cursor.fetchone()) and row[0] == latest_schema_hash: + cursor = conn.execute("SELECT schema_hash, config_hash FROM _schema_hash") + row = cursor.fetchone() + if row and row["schema_hash"] == schema_hash and row["config_hash"] == c.hash: # Everything matches! Exit! return @@ -77,8 +78,19 @@ def migrate_database(c: Config) -> None: with connect(c) as conn: with CACHE_SCHEMA_PATH.open("r") as fp: conn.executescript(fp.read()) - conn.execute("CREATE TABLE _schema_hash (value TEXT PRIMARY KEY)") - conn.execute("INSERT INTO _schema_hash (value) VALUES (?)", (latest_schema_hash,)) + conn.execute( + """ + CREATE TABLE _schema_hash ( + schema_hash TEXT + , config_hash TEXT + , PRIMARY KEY (schema_hash, config_hash) + ) + """ + ) + conn.execute( + "INSERT INTO _schema_hash (schema_hash, config_hash) VALUES (?, ?)", + (schema_hash, c.hash), + ) @dataclass diff --git a/rose/cache_test.py b/rose/cache_test.py index 852d534..4097641 100644 --- a/rose/cache_test.py +++ b/rose/cache_test.py @@ -40,26 +40,40 @@ def test_schema(config: Config) -> None: # Test that the schema successfully bootstraps. with CACHE_SCHEMA_PATH.open("rb") as fp: - latest_schema_hash = hashlib.sha256(fp.read()).hexdigest() + schema_hash = hashlib.sha256(fp.read()).hexdigest() migrate_database(config) with connect(config) as conn: - cursor = conn.execute("SELECT value FROM _schema_hash") - assert cursor.fetchone()[0] == latest_schema_hash + cursor = conn.execute("SELECT schema_hash, config_hash FROM _schema_hash") + row = cursor.fetchone() + assert row["schema_hash"] == schema_hash + assert row["config_hash"] == config.hash def test_migration(config: Config) -> None: # Test that "migrating" the database correctly migrates it. config.cache_database_path.unlink() with connect(config) as conn: - conn.execute("CREATE TABLE _schema_hash (value TEXT PRIMARY KEY)") - conn.execute("INSERT INTO _schema_hash (value) VALUES ('haha')") + conn.execute( + """ + CREATE TABLE _schema_hash ( + schema_hash TEXT + , config_hash TEXT + , PRIMARY KEY (schema_hash, config_hash) + ) + """ + ) + conn.execute( + "INSERT INTO _schema_hash (schema_hash, config_hash) VALUES ('haha', 'lala')", + ) with CACHE_SCHEMA_PATH.open("rb") as fp: latest_schema_hash = hashlib.sha256(fp.read()).hexdigest() migrate_database(config) with connect(config) as conn: - cursor = conn.execute("SELECT value FROM _schema_hash") - assert cursor.fetchone()[0] == latest_schema_hash + cursor = conn.execute("SELECT schema_hash, config_hash FROM _schema_hash") + row = cursor.fetchone() + assert row["schema_hash"] == latest_schema_hash + assert row["config_hash"] == config.hash cursor = conn.execute("SELECT COUNT(*) FROM _schema_hash") assert cursor.fetchone()[0] == 1 diff --git a/rose/config.py b/rose/config.py index c4a446d..5276d4c 100644 --- a/rose/config.py +++ b/rose/config.py @@ -4,6 +4,7 @@ import os from collections import defaultdict from dataclasses import dataclass +from hashlib import sha256 from pathlib import Path import tomllib @@ -46,12 +47,16 @@ class Config: fuse_hide_genres: list[str] fuse_hide_labels: list[str] + hash: str + @classmethod def read(cls, config_path_override: Path | None = None) -> Config: cfgpath = config_path_override or CONFIG_PATH + cfgtext = "" try: - with cfgpath.open("rb") as fp: - data = tomllib.load(fp) + with cfgpath.open("r") as fp: + cfgtext = fp.read() + data = tomllib.loads(cfgtext) except FileNotFoundError as e: raise ConfigNotFoundError(f"Configuration file not found ({cfgpath})") from e @@ -180,4 +185,5 @@ def read(cls, config_path_override: Path | None = None) -> Config: fuse_hide_artists=fuse_hide_artists, fuse_hide_genres=fuse_hide_genres, fuse_hide_labels=fuse_hide_labels, + hash=sha256(cfgtext.encode()).hexdigest(), ) diff --git a/rose/config_test.py b/rose/config_test.py index a70be07..8a6071d 100644 --- a/rose/config_test.py +++ b/rose/config_test.py @@ -43,7 +43,8 @@ def test_config_full() -> None: """ # noqa: E501 ) - assert Config.read(config_path_override=path) == Config( + c = Config.read(config_path_override=path) + assert c == Config( music_source_dir=Path.home() / ".music-src", fuse_mount_dir=Path.home() / "music", cache_dir=cache_dir, @@ -70,6 +71,7 @@ def test_config_full() -> None: fuse_hide_artists=["xxx"], fuse_hide_genres=["yyy"], fuse_hide_labels=["zzz"], + hash=c.hash, )