vdirsyncer/vdirsyncer/repair.py
Hugo Osvaldo Barrera 1a1f6f0788 Initial async support
Add asyncio to the storage backends and most of the codebase. A lot of
it merely uses asyncio APIs, but still doesn't actually run several
things concurrently internally. Further improvements will be added on
top of these changes

Thanks to  Thomas Grainger (@graingert) for a few useful pointers
related to asyncio.
2021-06-26 13:40:35 +02:00

67 lines
2 KiB
Python

import logging
from os.path import basename
import aiostream
from .utils import generate_href
from .utils import href_safe
logger = logging.getLogger(__name__)
class IrreparableItem(Exception):
pass
async def repair_storage(storage, repair_unsafe_uid):
seen_uids = set()
all_hrefs = await aiostream.stream.list(storage.list())
for i, (href, _) in enumerate(all_hrefs):
item, etag = await storage.get(href)
logger.info("[{}/{}] Processing {}".format(i, len(all_hrefs), href))
try:
new_item = repair_item(href, item, seen_uids, repair_unsafe_uid)
except IrreparableItem:
logger.error(
"Item {!r} is malformed beyond repair. "
"The PRODID property may indicate which software "
"created this item.".format(href)
)
logger.error(f"Item content: {item.raw!r}")
continue
seen_uids.add(new_item.uid)
if new_item.raw != item.raw:
if new_item.uid != item.uid:
await storage.upload(new_item)
await storage.delete(href, etag)
else:
await storage.update(href, new_item, etag)
def repair_item(href, item, seen_uids, repair_unsafe_uid):
if item.parsed is None:
raise IrreparableItem()
new_item = item
if not item.uid:
logger.warning("No UID, assigning random UID.")
new_item = item.with_uid(generate_href())
elif item.uid in seen_uids:
logger.warning("Duplicate UID, assigning random UID.")
new_item = item.with_uid(generate_href())
elif not href_safe(item.uid) or not href_safe(basename(href)):
if not repair_unsafe_uid:
logger.warning(
"UID may cause problems, add " "--repair-unsafe-uid to repair."
)
else:
logger.warning("UID or href is unsafe, assigning random UID.")
new_item = item.with_uid(generate_href())
if not new_item.uid:
raise IrreparableItem()
return new_item