aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Schadt <kingdread@gmx.de>2023-03-30 21:19:46 +0200
committerDaniel Schadt <kingdread@gmx.de>2023-03-30 21:41:47 +0200
commit60a1585a37bfee43e3d6c7cac002eeee85768c5f (patch)
treee9bb6b163e5d6858f18c5b69aa8833b51d470507
parenta2aaf098ca5ac897a5e0e1b2302acaf0562f8aad (diff)
downloadfietsboek-60a1585a37bfee43e3d6c7cac002eeee85768c5f.tar.gz
fietsboek-60a1585a37bfee43e3d6c7cac002eeee85768c5f.tar.bz2
fietsboek-60a1585a37bfee43e3d6c7cac002eeee85768c5f.zip
check if data version matches at startup
This might be helpful to see some errors early.
-rw-r--r--fietsboek/__init__.py30
-rw-r--r--fietsboek/updater/__init__.py46
2 files changed, 75 insertions, 1 deletions
diff --git a/fietsboek/__init__.py b/fietsboek/__init__.py
index 41e8a04..ee7d8b7 100644
--- a/fietsboek/__init__.py
+++ b/fietsboek/__init__.py
@@ -14,6 +14,7 @@ Content
-------
"""
import importlib.metadata
+import logging
from pathlib import Path
from typing import Callable, Optional
@@ -33,9 +34,12 @@ from . import transformers
from .data import DataManager
from .pages import Pages
from .security import SecurityPolicy
+from .updater import Updater, UpdateState
__VERSION__ = importlib.metadata.version("fietsboek")
+LOGGER = logging.getLogger(__name__)
+
def locale_negotiator(request: Request) -> Optional[str]:
"""Negotiates the right locale to use.
@@ -88,12 +92,36 @@ def maintenance_mode(
return tween
-def main(_global_config, **settings):
+def check_update_state(config_uri: str):
+ """Checks the update state of the data, and logs a warning if there is a
+ mismatch.
+
+ :param config_uri: Path to the configuration file.
+ """
+ updater = Updater(config_uri)
+ updater.load()
+ state = updater.state()
+
+ if state == UpdateState.OUTDATED:
+ LOGGER.warning(
+ "The data seems to be outdated - make sure to run the fietsupdate migrations!"
+ )
+ elif state == UpdateState.TOO_NEW:
+ LOGGER.warning("The data seems to be too new, make sure to update the code accordingly!")
+ elif state == UpdateState.UNKNOWN:
+ LOGGER.warning("Could not determine version state of the data - check `fietsupdate status`")
+
+
+def main(global_config, **settings):
"""This function returns a Pyramid WSGI application."""
# Avoid a circular import by not importing at the top level
# pylint: disable=import-outside-toplevel,cyclic-import
from .views.tileproxy import TileRequester
+ # In tests this isn't passed, so guard against it
+ if "__file__" in global_config:
+ check_update_state(global_config["__file__"])
+
parsed_config = mod_config.parse(settings)
settings["jinja2.newstyle"] = True
diff --git a/fietsboek/updater/__init__.py b/fietsboek/updater/__init__.py
index fa7f5c6..5faa805 100644
--- a/fietsboek/updater/__init__.py
+++ b/fietsboek/updater/__init__.py
@@ -1,5 +1,6 @@
"""Updating (data migration) logic for fietsboek."""
import datetime
+import enum
import importlib.resources
import importlib.util
import logging
@@ -50,6 +51,26 @@ class Down(UpdateScript):
"""
+class UpdateState(enum.Enum):
+ """State of the applied updates.
+
+ This represents a "summary" of the output that ``fietsupdate status``
+ produces.
+ """
+
+ OKAY = enum.auto()
+ """Everything is good, the data is up to date."""
+
+ OUTDATED = enum.auto()
+ """The data is outdated, the update process should be run."""
+
+ TOO_NEW = enum.auto()
+ """The data contains revisions that are not known to Fietsboek yet."""
+
+ UNKNOWN = enum.auto()
+ """The data version could not be determined."""
+
+
class Updater:
"""A class that implements the updating logic.
@@ -284,6 +305,31 @@ class Updater:
return revision_id in self._transitive_versions()
return revision_id in self._reverse_versions() | set(self.current_versions())
+ def state(self) -> UpdateState:
+ """Checks the update state of the instance.
+
+ This returns a condensed version of what ``fietsupdate status``
+ outputs.
+
+ :return: The update state of the data.
+ """
+ state = UpdateState.OKAY
+ current = self.current_versions()
+ heads = self.heads()
+ if current:
+ for i in current:
+ if not self.exists(i):
+ state = UpdateState.TOO_NEW
+ else:
+ return UpdateState.UNKNOWN
+ updates = set(heads) - set(current)
+ if updates:
+ if state != UpdateState.OKAY:
+ # We are both too new and too old, so something is pretty wrong
+ return UpdateState.UNKNOWN
+ return UpdateState.OUTDATED
+ return state
+
class UpdateScript:
"""Represents an update script."""