From cb29c2567f0e390bc4464301a1453665c263691c Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Wed, 14 May 2014 14:48:50 +0200 Subject: [PATCH] Allow uploading of items without UID --- tests/storage/__init__.py | 11 ++++++++++- tests/storage/test_http.py | 4 ++-- vdirsyncer/storage/base.py | 7 +++++-- vdirsyncer/storage/dav.py | 10 ++++++---- vdirsyncer/storage/filesystem.py | 7 ++----- vdirsyncer/storage/http.py | 5 +---- vdirsyncer/storage/memory.py | 6 +++--- 7 files changed, 29 insertions(+), 21 deletions(-) diff --git a/tests/storage/__init__.py b/tests/storage/__init__.py index ba0e5fb..3b0e681 100644 --- a/tests/storage/__init__.py +++ b/tests/storage/__init__.py @@ -80,7 +80,7 @@ class StorageTests(object): s = self._get_storage() item = self._create_bogus_item(1) with pytest.raises(exceptions.PreconditionFailed): - s.update(s._get_href('1'), item, '"123"') + s.update(s._get_href(item), item, '"123"') with pytest.raises(exceptions.PreconditionFailed): s.update('huehue', item, '"123"') @@ -164,3 +164,12 @@ class StorageTests(object): href, etag = s.upload(self._create_bogus_item(1)) assert s.has(href) assert not s.has('asd') + + def test_upload_without_uid(self): + lines = [x for x in self._create_bogus_item('1').raw.splitlines() + if u'UID' not in x] + item = Item(u'\n'.join(lines)) + + s = self._get_storage() + href, etag = s.upload(item) + assert s.has(href) diff --git a/tests/storage/test_http.py b/tests/storage/test_http.py index da926dc..2ae1b0a 100644 --- a/tests/storage/test_http.py +++ b/tests/storage/test_http.py @@ -106,7 +106,7 @@ def test_list(monkeypatch): for href, etag in s.list(): item, etag2 = s.get(href) - assert item.uid is not None + assert item.uid is None assert etag2 == etag found_items[item.raw.strip()] = href @@ -115,6 +115,6 @@ def test_list(monkeypatch): for href, etag in s.list(): item, etag2 = s.get(href) - assert item.uid is not None + assert item.uid is None assert etag2 == etag assert found_items[item.raw.strip()] == href diff --git a/vdirsyncer/storage/base.py b/vdirsyncer/storage/base.py index e380d90..42cfd58 100644 --- a/vdirsyncer/storage/base.py +++ b/vdirsyncer/storage/base.py @@ -7,6 +7,8 @@ :license: MIT, see LICENSE for more details. ''' +import hashlib + from .. import exceptions from .. import utils @@ -27,6 +29,7 @@ class Item(object): self.uid = uid self.raw = u'\n'.join(raw) + self.hash = hashlib.sha256(self.raw.encode('utf-8')).hexdigest() class Storage(object): @@ -67,8 +70,8 @@ class Storage(object): ''' raise NotImplementedError() - def _get_href(self, uid): - return uid + self.fileext + def _get_href(self, item): + return (item.uid or item.hash) + self.fileext def __repr__(self): return '<{}(**{})>'.format( diff --git a/vdirsyncer/storage/dav.py b/vdirsyncer/storage/dav.py index bf2e5ed..cebfc2a 100644 --- a/vdirsyncer/storage/dav.py +++ b/vdirsyncer/storage/dav.py @@ -115,13 +115,15 @@ class DavStorage(Storage): def _normalize_href(self, href): '''Normalize the href to be a path only relative to hostname and schema.''' + if not href: + raise ValueError(href) x = utils.urlparse.urljoin(self.url, href) assert x.startswith(self.url) return utils.urlunquote_plus(utils.urlparse.urlsplit(x).path) - def _get_href(self, uid): - uid = utils.urlunquote_plus(uid) - return self._normalize_href(super(DavStorage, self)._get_href(uid)) + def _get_href(self, item): + href = utils.urlunquote_plus(item.uid or item.hash) + self.fileext + return self._normalize_href(href) def _request(self, method, path, data=None, headers=None): path = path or self.parsed_url.path @@ -218,7 +220,7 @@ class DavStorage(Storage): return self._put(href, item, etag) def upload(self, item): - href = self._get_href(item.uid) + href = self._get_href(item) return self._put(href, item, None) def delete(self, href, etag): diff --git a/vdirsyncer/storage/filesystem.py b/vdirsyncer/storage/filesystem.py index 7f24736..be8b470 100644 --- a/vdirsyncer/storage/filesystem.py +++ b/vdirsyncer/storage/filesystem.py @@ -100,9 +100,6 @@ class FilesystemStorage(Storage): def _get_filepath(self, href): return os.path.join(self.path, href) - def _get_href(self, uid): - return uid + self.fileext - def list(self): for fname in os.listdir(self.path): fpath = os.path.join(self.path, fname) @@ -123,7 +120,7 @@ class FilesystemStorage(Storage): raise def upload(self, item): - href = self._get_href(item.uid) + href = self._get_href(item) fpath = self._get_filepath(href) if os.path.exists(fpath): raise exceptions.AlreadyExistingError(item.uid) @@ -137,7 +134,7 @@ class FilesystemStorage(Storage): def update(self, href, item, etag): fpath = self._get_filepath(href) - if href != self._get_href(item.uid): + if href != self._get_href(item): logger.warning('href != uid + fileext: href={}; uid={}' .format(href, item.uid)) if not os.path.exists(fpath): diff --git a/vdirsyncer/storage/http.py b/vdirsyncer/storage/http.py index 4f77a82..a473028 100644 --- a/vdirsyncer/storage/http.py +++ b/vdirsyncer/storage/http.py @@ -156,10 +156,7 @@ class HttpStorage(Storage): self._items.clear() for i, item in enumerate(split_collection(r.text.splitlines())): item = Item(u'\n'.join(item)) - etag = hashlib.sha256(item.raw.encode('utf-8')).hexdigest() - if item.uid is None: - item.uid = etag - self._items[item.uid] = item, etag + self._items[self._get_href(item)] = item, item.hash for href, (item, etag) in self._items.items(): yield href, etag diff --git a/vdirsyncer/storage/memory.py b/vdirsyncer/storage/memory.py index eb53398..9d82f53 100644 --- a/vdirsyncer/storage/memory.py +++ b/vdirsyncer/storage/memory.py @@ -39,15 +39,15 @@ class MemoryStorage(Storage): return href in self.items def upload(self, item): - href = self._get_href(item.uid) + href = self._get_href(item) if href in self.items: - raise exceptions.AlreadyExistingError(item.uid) + raise exceptions.AlreadyExistingError(item) etag = _get_etag() self.items[href] = (etag, item) return href, etag def update(self, href, item, etag): - if href != self._get_href(item.uid) or href not in self.items: + if href != self._get_href(item) or href not in self.items: raise exceptions.NotFoundError(href) actual_etag, _ = self.items[href] if etag != actual_etag: