diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index 382e1e03..3923e54a 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -865,6 +865,12 @@ Delete sync-token that are older than the specified time. (seconds) Default: `2592000` +#### skip_broken_item + +Skip broken item instead of triggering an exception + +Default: False + ##### hook Command that is run after changes to storage. Take a look at the diff --git a/config b/config index 4a2e2f29..ff4f5c53 100644 --- a/config +++ b/config @@ -99,6 +99,9 @@ # Delete sync token that are older (seconds) #max_sync_token_age = 2592000 +# Skip broken item instead of triggering an exception +#skip_broken_item = False + # Command that is run after changes to storage # Example: ([ -d .git ] || git init) && git add -A && (git diff --cached --quiet || git commit -m "Changes by \"%(user)s\"") #hook = @@ -139,4 +142,4 @@ #type = none #rabbitmq_endpoint = #rabbitmq_topic = -#rabbitmq_queue_type = classic \ No newline at end of file +#rabbitmq_queue_type = classic diff --git a/radicale/config.py b/radicale/config.py index 27352bdc..567847c0 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -211,6 +211,10 @@ DEFAULT_CONFIG_SCHEMA: types.CONFIG_SCHEMA = OrderedDict([ "value": "2592000", # 30 days "help": "delete sync token that are older", "type": positive_int}), + ("skip_broken_item", { + "value": "False", + "help": "skip broken item instead of triggering exception", + "type": bool}), ("hook", { "value": "", "help": "command that is run after changes to storage", diff --git a/radicale/storage/multifilesystem/base.py b/radicale/storage/multifilesystem/base.py index bbb02198..a7cc0bee 100644 --- a/radicale/storage/multifilesystem/base.py +++ b/radicale/storage/multifilesystem/base.py @@ -1,7 +1,8 @@ # This file is part of Radicale - CalDAV and CardDAV server # Copyright © 2014 Jean-Marc Martins # Copyright © 2012-2017 Guillaume Ayoub -# Copyright © 2017-2019 Unrud +# Copyright © 2017-2022 Unrud +# Copyright © 2024-2024 Peter Bieringer # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -40,6 +41,7 @@ class CollectionBase(storage.BaseCollection): # Path should already be sanitized self._path = pathutils.strip_path(path) self._encoding = storage_.configuration.get("encoding", "stock") + self._skip_broken_item = storage_.configuration.get("storage", "skip_broken_item") if filesystem_path is None: filesystem_path = pathutils.path_to_filesystem(folder, self.path) self._filesystem_path = filesystem_path diff --git a/radicale/storage/multifilesystem/get.py b/radicale/storage/multifilesystem/get.py index 0a1fd73f..c52c1f7e 100644 --- a/radicale/storage/multifilesystem/get.py +++ b/radicale/storage/multifilesystem/get.py @@ -1,7 +1,8 @@ # This file is part of Radicale - CalDAV and CardDAV server # Copyright © 2014 Jean-Marc Martins # Copyright © 2012-2017 Guillaume Ayoub -# Copyright © 2017-2018 Unrud +# Copyright © 2017-2022 Unrud +# Copyright © 2024-2024 Peter Bieringer # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -101,8 +102,12 @@ class CollectionPartGet(CollectionPartCache, CollectionPartLock, cache_content = self._store_item_cache( href, temp_item, cache_hash) except Exception as e: - raise RuntimeError("Failed to load item %r in %r: %s" % - (href, self.path, e)) from e + if self._skip_broken_item: + logger.warning("Skip broken item %r in %r: %s", href, self.path, e) + return None + else: + raise RuntimeError("Failed to load item %r in %r: %s" % + (href, self.path, e)) from e # Clean cache entries once after the data in the file # system was edited externally. if not self._item_cache_cleaned: