From d781ac1101f8fec40533614d680ad467593af552 Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Sat, 3 May 2014 20:53:06 +0200 Subject: [PATCH] Kill it with fire. --- tests/storage/test_http.py | 10 +++--- vdirsyncer/storage/http.py | 66 ++++++++++++++++++++++++++++---------- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/tests/storage/test_http.py b/tests/storage/test_http.py index b560957..0ca581a 100644 --- a/tests/storage/test_http.py +++ b/tests/storage/test_http.py @@ -49,14 +49,15 @@ def test_split_collection_timezones(): u'END:VTIMEZONE' ) - full = u'\n'.join( + full = list( (u'BEGIN:VCALENDAR',) + timezone + tuple(line for item in items for line in item) + (u'END:VCALENDAR',) ) - given = [tuple(x.raw.splitlines()) for x in split_collection(full)] - expected = [item[:-1] + timezone + (item[-1],) for item in items] + given = [tuple(x) for x in split_collection(full)] + expected = [(u'BEGIN:VCALENDAR',) + timezone + item + (u'END:VCALENDAR',) + for item in items] print(given) print(expected) assert given == expected @@ -110,7 +111,8 @@ def test_list(monkeypatch): assert etag2 == etag found_items[item.raw.strip()] = href - assert set(found_items) == set(items) + assert set(found_items) == set(u'BEGIN:VCALENDAR\n' + x + '\nEND:VCALENDAR' + for x in items) for href, etag in s.list(): item, etag2 = s.get(href) diff --git a/vdirsyncer/storage/http.py b/vdirsyncer/storage/http.py index c8e65b2..cc2bdb6 100644 --- a/vdirsyncer/storage/http.py +++ b/vdirsyncer/storage/http.py @@ -15,19 +15,11 @@ from ..utils import expand_path, get_password, request, text_type, urlparse USERAGENT = 'vdirsyncer' -def split_collection(text): - ''' - This is a horrible "parser", but Python tooling isn't much better. The only - library which supports both calendars and addressbooks (VObject) is Python - 2 only and doesn't seem maintained anymore, the other one (icalendar) only - handles calendars... which wouldn't eliminate this function anyway. Let's - just hope this handles all cases. - ''' +def split_simple_collection(lines): item = [] collection_type = None item_type = None - timezone = None - for line in text.splitlines(): + for line in lines: if u':' not in line: item.append(line) continue @@ -38,19 +30,14 @@ def split_collection(text): elif item_type is None: item_type = value item.append(line) - if item_type == u'VTIMEZONE': - timezone = item else: item.append(line) elif key == u'END': if value == collection_type: break elif value == item_type: - if timezone is not None and item_type != u'VTIMEZONE': - item.extend(timezone) item.append(line) - if item_type != u'VTIMEZONE': - yield Item(u'\n'.join(item), needs_uid=False) + yield item item = [] item_type = None else: @@ -60,6 +47,50 @@ def split_collection(text): item.append(line) +def wrap_items(items, collection_type, exclude=(u'VTIMEZONE',)): + for item in items: + key, value = (x.strip() for x in item[0].split(u':')) + if value in exclude: + yield item + else: + yield ([u'BEGIN:' + collection_type] + item + + [u'END:' + collection_type]) + + +def inline_timezones(items): + timezone = None + for item in items: + if u':' not in item[0]: + import pdb + pdb.set_trace() + + key, value = (x.strip() for x in item[0].split(u':')) + if value == u'VTIMEZONE': + if timezone is not None: + raise ValueError('Multiple timezones.') + timezone = item + else: + if timezone is not None: + item = [item[0]] + timezone + item[1:] + yield item + + +def split_collection(lines): + collection_type = None + for line in lines: + key, value = (x.strip() for x in line.split(u':')) + if key == u'BEGIN': + collection_type = value + break + + is_calendar = collection_type == u'VCALENDAR' + rv = split_simple_collection(lines) + + if is_calendar: + rv = inline_timezones(wrap_items(rv, collection_type)) + + return rv + def prepare_auth(auth, username, password): if (username and password) or auth == 'basic': return (username, password) @@ -119,7 +150,8 @@ class HttpStorage(Storage): r = request('GET', self.url, **self._settings) r.raise_for_status() self._items.clear() - for i, item in enumerate(split_collection(r.text)): + for i, item in enumerate(split_collection(r.text.splitlines())): + item = Item(u'\n'.join(item), needs_uid=False) uid = item.uid if item.uid is not None else i self._items[uid] = item