mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-13 12:05:54 +00:00
Copyright headers, more docstrings
This commit is contained in:
parent
220f921ab6
commit
ca92d9a428
14 changed files with 183 additions and 41 deletions
19
LICENSE
Normal file
19
LICENSE
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2013 Markus Unterwaditzer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
2
setup.cfg
Normal file
2
setup.cfg
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
[wheel]
|
||||
universal = 1
|
||||
29
setup.py
Normal file
29
setup.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer
|
||||
~~~~~~~~~~
|
||||
|
||||
vdirsyncer is a syncronization tool for vdir. See the README for more
|
||||
details.
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name='vdirsyncer',
|
||||
version='0.1.0',
|
||||
author='Markus Unterwaditzer',
|
||||
author_email='markus@unterwaditzer.net',
|
||||
url='https://github.com/untitaker/vdirsyncer',
|
||||
description='A syncronization tool for vdir',
|
||||
long_description=open('README.md').read(),
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
entry_points={
|
||||
'console_scripts': ['vdirsyncer = vdirsyncer.cli:main']
|
||||
},
|
||||
install_requires=['argvard']
|
||||
)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer
|
||||
~~~~~~~~~~
|
||||
|
||||
vdirsyncer is a syncronization tool for vdir. See the README for more
|
||||
details.
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
__version__ = '0.1.0'
|
||||
|
|
@ -1,10 +1,23 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.cli
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
import os
|
||||
import ConfigParser
|
||||
from vdirsyncer.cli_utils import path
|
||||
from vdirsyncer.sync import sync_classes
|
||||
|
||||
def _path(p):
|
||||
p = os.path.expanduser(p)
|
||||
p = os.path.abspath(p)
|
||||
return p
|
||||
|
||||
def get_config_parser(env):
|
||||
fname = env.get('VDIRSYNCER_CONFIG', path('~/.vdirsyncer/config'))
|
||||
fname = env.get('VDIRSYNCER_CONFIG', _path('~/.vdirsyncer/config'))
|
||||
c = ConfigParser.SafeConfigParser()
|
||||
c.read(fname)
|
||||
return dict((c, c.items(c)) for c in c.sections())
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
watdo.cli_utils
|
||||
~~~~~~~~~
|
||||
|
||||
This module contains helper functions that should be useful for arbitrary
|
||||
CLI interfaces.
|
||||
|
||||
:copyright: (c) 2013 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def bail_out(msg):
|
||||
print(msg)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def check_directory(path):
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
|
||||
|
||||
def path(p):
|
||||
p = os.path.expanduser(p)
|
||||
p = os.path.abspath(p)
|
||||
return p
|
||||
|
||||
|
||||
def confirm(message='Are you sure? (Y/n)'):
|
||||
inp = raw_input(message).lower().strip()
|
||||
if not inp or inp == 'y':
|
||||
return True
|
||||
return False
|
||||
|
|
@ -1,11 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.exceptions
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
class Error(Exception):
|
||||
'''Baseclass for all errors.'''
|
||||
pass
|
||||
|
||||
class NotFoundError(Error):
|
||||
'''The item does not exist (anymore).'''
|
||||
pass
|
||||
|
||||
class AlreadyExistingError(Error):
|
||||
'''The item exists although it shouldn't, possible race condition.'''
|
||||
pass
|
||||
|
||||
class WrongEtagError(Error):
|
||||
'''The given etag doesn't match the etag from the storage, possible race
|
||||
condition.'''
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.storage
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There are storage classes which control the access to one vdir-collection
|
||||
and offer basic CRUD-ish methods for modifying those collections. The exact
|
||||
interface is described in `vdirsyncer.storage.base`, the `Storage` class
|
||||
should be a superclass of all storage classes.
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
|
@ -1,3 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.storage.base
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
class Item(object):
|
||||
'''should-be-immutable wrapper class for VCALENDAR and VCARD'''
|
||||
def __init__(self, raw):
|
||||
|
|
@ -14,6 +23,8 @@ class Item(object):
|
|||
|
||||
|
||||
class Storage(object):
|
||||
'''Superclass of all storages, mainly useful to summarize the interface to
|
||||
implement.'''
|
||||
def __init__(self, fileext='', item_class=Item):
|
||||
self.fileext = fileext
|
||||
self.item_class = item_class
|
||||
|
|
|
|||
|
|
@ -1,9 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.storage.filesystem
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
import os
|
||||
from vdirsyncer.storage.base import Storage, Item
|
||||
import vdirsyncer.exceptions as exceptions
|
||||
|
||||
class FilesystemStorage(Storage):
|
||||
'''Saves data in vdir collection, mtime is etag.'''
|
||||
def __init__(self, path, **kwargs):
|
||||
'''
|
||||
:param path: Absolute path to a *collection* inside a vdir.
|
||||
'''
|
||||
self.path = path
|
||||
super(FilesystemStorage, self).__init__(**kwargs)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.storage.memory
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
import datetime
|
||||
from vdirsyncer.storage.base import Item, Storage
|
||||
import vdirsyncer.exceptions as exceptions
|
||||
|
||||
class MemoryStorage(Storage):
|
||||
'''
|
||||
Saves data in RAM, only useful for testing.
|
||||
'''
|
||||
def __init__(self, **kwargs):
|
||||
self.items = {} # uid => (etag, object)
|
||||
super(MemoryStorage, self).__init__(**kwargs)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,31 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.sync
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
The function in `vdirsyncer.sync` can be called on two instances of
|
||||
`Storage` to syncronize them. Due to the abstract API storage classes are
|
||||
implementing, the two given instances don't have to be of the same exact
|
||||
type. This allows us not only to syncronize a local vdir with a CalDAV
|
||||
server, but also syncronize two CalDAV servers or two local vdirs.
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
|
||||
def sync(storage_a, storage_b, status):
|
||||
'''Syncronizes two storages.
|
||||
|
||||
:param storage_a: The first storage
|
||||
:type storage_a: :class:`vdirsyncer.storage.base.Storage`
|
||||
:param storage_b: The second storage
|
||||
:param status: {uid: (etag_a, etag_b)}
|
||||
:type storage_b: :class:`vdirsyncer.storage.base.Storage`
|
||||
:param status:
|
||||
{uid: (etag_a, etag_b)}, metadata about the two storages for detection
|
||||
of changes. Will be modified by the function and should be passed to it
|
||||
at the next sync. If this is the first sync, an empty dictionary should
|
||||
be provided.
|
||||
'''
|
||||
list_a = dict(storage_a.list_items())
|
||||
list_b = dict(storage_b.list_items())
|
||||
|
|
@ -15,7 +37,7 @@ def sync(storage_a, storage_b, status):
|
|||
for uid in set(list_a).union(set(list_b)):
|
||||
if uid not in status:
|
||||
if uid in list_a and uid in list_b: # missing status
|
||||
status[uid] = (list_a[uid], list_b[uid]) # TODO: might need etag diffing too?
|
||||
status[uid] = (list_a[uid], list_b[uid]) # TODO: might need some kind of diffing too?
|
||||
elif uid in list_a and uid not in list_b: # new item in a
|
||||
prefetch_items_from_a.append(uid)
|
||||
actions.append(('upload', uid, 'a', 'b'))
|
||||
|
|
|
|||
|
|
@ -1,3 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.tests.test_storage
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
__version__ = '0.1.0'
|
||||
|
||||
from unittest import TestCase
|
||||
import os
|
||||
import tempfile
|
||||
|
|
|
|||
|
|
@ -1,3 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
vdirsyncer.tests.test_sync
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: (c) 2014 Markus Unterwaditzer
|
||||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
from unittest import TestCase
|
||||
from vdirsyncer.storage.base import Item
|
||||
from vdirsyncer.storage.memory import MemoryStorage
|
||||
|
|
|
|||
Loading…
Reference in a new issue