From fc7b50d69f1454c4f25e16633d0cac7cd4295f9a Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Sun, 9 Jun 2024 13:57:32 +0200 Subject: [PATCH 1/6] add option to skip broken item instead of triggering exception --- DOCUMENTATION.md | 6 ++++++ config | 3 +++ radicale/config.py | 4 ++++ radicale/storage/multifilesystem/base.py | 1 + radicale/storage/multifilesystem/get.py | 6 +++++- 5 files changed, 19 insertions(+), 1 deletion(-) 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..9cc77ecb 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 = diff --git a/radicale/config.py b/radicale/config.py index 27352bdc..31765634 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..db82e9ee 100644 --- a/radicale/storage/multifilesystem/base.py +++ b/radicale/storage/multifilesystem/base.py @@ -40,6 +40,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..ab3bd90e 100644 --- a/radicale/storage/multifilesystem/get.py +++ b/radicale/storage/multifilesystem/get.py @@ -101,7 +101,11 @@ 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" % + if self._skip_broken_item: + logger.warning("Skip broken item %r in %r: %s", href, self.path, e) + return + 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. From a70c69ee2842598001e89b1df838157508ee2bde Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Sun, 9 Jun 2024 13:57:52 +0200 Subject: [PATCH 2/6] update copyright --- radicale/storage/multifilesystem/base.py | 3 ++- radicale/storage/multifilesystem/get.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/radicale/storage/multifilesystem/base.py b/radicale/storage/multifilesystem/base.py index db82e9ee..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 diff --git a/radicale/storage/multifilesystem/get.py b/radicale/storage/multifilesystem/get.py index ab3bd90e..a2ee9e83 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 From e02a31af89429f858a0c7880c15a93020b75c80d Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Sun, 9 Jun 2024 14:35:14 +0200 Subject: [PATCH 3/6] fix flake8 error report --- radicale/storage/multifilesystem/get.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radicale/storage/multifilesystem/get.py b/radicale/storage/multifilesystem/get.py index a2ee9e83..afbfd3cc 100644 --- a/radicale/storage/multifilesystem/get.py +++ b/radicale/storage/multifilesystem/get.py @@ -107,7 +107,7 @@ class CollectionPartGet(CollectionPartCache, CollectionPartLock, return else: raise RuntimeError("Failed to load item %r in %r: %s" % - (href, self.path, e)) from e + (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: From 59bd8e8330aa46fb4166a92af2da7e995c7b0188 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Sun, 9 Jun 2024 14:44:21 +0200 Subject: [PATCH 4/6] fix missing return value --- radicale/storage/multifilesystem/get.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radicale/storage/multifilesystem/get.py b/radicale/storage/multifilesystem/get.py index afbfd3cc..c52c1f7e 100644 --- a/radicale/storage/multifilesystem/get.py +++ b/radicale/storage/multifilesystem/get.py @@ -104,7 +104,7 @@ class CollectionPartGet(CollectionPartCache, CollectionPartLock, except Exception as e: if self._skip_broken_item: logger.warning("Skip broken item %r in %r: %s", href, self.path, e) - return + return None else: raise RuntimeError("Failed to load item %r in %r: %s" % (href, self.path, e)) from e From 5b5273abbf91d1db51ba063d8215085427ab8ec2 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Sun, 9 Jun 2024 14:45:32 +0200 Subject: [PATCH 5/6] fix missing newline --- config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config b/config index 9cc77ecb..ff4f5c53 100644 --- a/config +++ b/config @@ -142,4 +142,4 @@ #type = none #rabbitmq_endpoint = #rabbitmq_topic = -#rabbitmq_queue_type = classic \ No newline at end of file +#rabbitmq_queue_type = classic From 0cf8ede6c78dd05581cd8f324cab8823fa2404b0 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Sun, 9 Jun 2024 15:20:28 +0200 Subject: [PATCH 6/6] bugfix --- radicale/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radicale/config.py b/radicale/config.py index 31765634..567847c0 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -212,7 +212,7 @@ DEFAULT_CONFIG_SCHEMA: types.CONFIG_SCHEMA = OrderedDict([ "help": "delete sync token that are older", "type": positive_int}), ("skip_broken_item", { - "value": False, + "value": "False", "help": "skip broken item instead of triggering exception", "type": bool}), ("hook", {