mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-27 14:57:41 +00:00
(backport) Make docs build independent of app
This commit is contained in:
parent
0094acddd0
commit
68f2cf3195
11 changed files with 306 additions and 277 deletions
|
|
@ -9,15 +9,18 @@ Package maintainers and users who have to manually update their installation
|
||||||
may want to subscribe to `GitHub's tag feed
|
may want to subscribe to `GitHub's tag feed
|
||||||
<https://github.com/pimutils/vdirsyncer/tags.atom>`_.
|
<https://github.com/pimutils/vdirsyncer/tags.atom>`_.
|
||||||
|
|
||||||
|
Version 0.16.6
|
||||||
|
==============
|
||||||
|
|
||||||
|
- **Packagers:** Documentation building no longer needs a working installation
|
||||||
|
of vdirsyncer.
|
||||||
|
|
||||||
Version 0.16.5
|
Version 0.16.5
|
||||||
==============
|
==============
|
||||||
|
|
||||||
*released on 13 June 2018*
|
|
||||||
|
|
||||||
- **Packagers:** click-log 0.3 is required.
|
- **Packagers:** click-log 0.3 is required.
|
||||||
- All output will now happen on stderr (because of the upgrade of ``click-log``).
|
- All output will now happen on stderr (because of the upgrade of ``click-log``).
|
||||||
|
|
||||||
|
|
||||||
Version 0.16.4
|
Version 0.16.4
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
sphinx != 1.4.7
|
sphinx != 1.4.7
|
||||||
sphinx_rtd_theme
|
sphinx_rtd_theme
|
||||||
|
setuptools_scm
|
||||||
|
|
|
||||||
64
docs/conf.py
64
docs/conf.py
|
|
@ -6,7 +6,7 @@ import os
|
||||||
|
|
||||||
from sphinx.ext import autodoc
|
from sphinx.ext import autodoc
|
||||||
|
|
||||||
import vdirsyncer
|
import setuptools_scm
|
||||||
|
|
||||||
extensions = ['sphinx.ext.autodoc']
|
extensions = ['sphinx.ext.autodoc']
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@ project = u'vdirsyncer'
|
||||||
copyright = (u'2014-{}, Markus Unterwaditzer & contributors'
|
copyright = (u'2014-{}, Markus Unterwaditzer & contributors'
|
||||||
.format(datetime.date.today().strftime('%Y')))
|
.format(datetime.date.today().strftime('%Y')))
|
||||||
|
|
||||||
release = vdirsyncer.__version__
|
release = setuptools_scm.get_version(root='..', relative_to=__file__)
|
||||||
version = '.'.join(release.split('.')[:2]) # The short X.Y version.
|
version = '.'.join(release.split('.')[:2]) # The short X.Y version.
|
||||||
|
|
||||||
rst_epilog = '.. |vdirsyncer_version| replace:: %s' % release
|
rst_epilog = '.. |vdirsyncer_version| replace:: %s' % release
|
||||||
|
|
@ -75,9 +75,10 @@ def github_issue_role(name, rawtext, text, lineno, inliner,
|
||||||
prb = inliner.problematic(rawtext, rawtext, msg)
|
prb = inliner.problematic(rawtext, rawtext, msg)
|
||||||
return [prb], [msg]
|
return [prb], [msg]
|
||||||
|
|
||||||
import vdirsyncer
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
link = '{}/{}/{}'.format(vdirsyncer.PROJECT_HOME,
|
|
||||||
|
PROJECT_HOME = 'https://github.com/pimutils/vdirsyncer'
|
||||||
|
link = '{}/{}/{}'.format(PROJECT_HOME,
|
||||||
'issues' if name == 'gh' else 'pull',
|
'issues' if name == 'gh' else 'pull',
|
||||||
issue_num)
|
issue_num)
|
||||||
linktext = ('issue #{}' if name == 'gh'
|
linktext = ('issue #{}' if name == 'gh'
|
||||||
|
|
@ -87,64 +88,9 @@ def github_issue_role(name, rawtext, text, lineno, inliner,
|
||||||
return [node], []
|
return [node], []
|
||||||
|
|
||||||
|
|
||||||
def format_storage_config(cls, header=True):
|
|
||||||
if header is True:
|
|
||||||
yield '[storage example_for_{}]'.format(cls.storage_name)
|
|
||||||
yield 'type = "{}"'.format(cls.storage_name)
|
|
||||||
|
|
||||||
from vdirsyncer.storage.base import Storage
|
|
||||||
from vdirsyncer.utils import get_storage_init_specs
|
|
||||||
handled = set()
|
|
||||||
for spec in get_storage_init_specs(cls, stop_at=Storage):
|
|
||||||
defaults = spec.defaults or ()
|
|
||||||
defaults = dict(zip(spec.args[-len(defaults):], defaults))
|
|
||||||
for key in spec.args[1:]:
|
|
||||||
if key in handled:
|
|
||||||
continue
|
|
||||||
handled.add(key)
|
|
||||||
|
|
||||||
comment = '' if key not in defaults else '#'
|
|
||||||
value = defaults.get(key, '...')
|
|
||||||
yield '{}{} = {}'.format(comment, key, json.dumps(value))
|
|
||||||
|
|
||||||
|
|
||||||
class StorageDocumenter(autodoc.ClassDocumenter):
|
|
||||||
'''Custom formatter for auto-documenting storage classes. It assumes that
|
|
||||||
the first line of the class' docstring is its own paragraph.
|
|
||||||
|
|
||||||
After that first paragraph, an example configuration will be inserted and
|
|
||||||
Sphinx' __init__ signature removed.'''
|
|
||||||
|
|
||||||
objtype = 'storage'
|
|
||||||
domain = None
|
|
||||||
directivetype = 'storage'
|
|
||||||
option_spec = {}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def can_document_member(cls, member, membername, isattr, parent):
|
|
||||||
from vdirsyncer.storage.base import Storage
|
|
||||||
return isinstance(member, Storage)
|
|
||||||
|
|
||||||
def format_signature(self):
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def add_directive_header(self, sig):
|
|
||||||
directive = getattr(self, 'directivetype', self.objtype)
|
|
||||||
name = self.object.storage_name
|
|
||||||
self.add_line(u'.. %s:: %s%s' % (directive, name, sig),
|
|
||||||
'<autodoc>')
|
|
||||||
|
|
||||||
def get_doc(self, encoding=None, ignore=1):
|
|
||||||
rv = autodoc.ClassDocumenter.get_doc(self, encoding, ignore)
|
|
||||||
config = [u' ' + x for x in format_storage_config(self.object)]
|
|
||||||
rv[0] = rv[0][:1] + [u'::', u''] + config + [u''] + rv[0][1:]
|
|
||||||
return rv
|
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app):
|
||||||
from sphinx.domains.python import PyObject
|
from sphinx.domains.python import PyObject
|
||||||
app.add_object_type('storage', 'storage', 'pair: %s; storage',
|
app.add_object_type('storage', 'storage', 'pair: %s; storage',
|
||||||
doc_field_types=PyObject.doc_field_types)
|
doc_field_types=PyObject.doc_field_types)
|
||||||
app.add_role('gh', github_issue_role)
|
app.add_role('gh', github_issue_role)
|
||||||
app.add_role('ghpr', github_issue_role)
|
app.add_role('ghpr', github_issue_role)
|
||||||
app.add_autodocumenter(StorageDocumenter)
|
|
||||||
|
|
|
||||||
301
docs/config.rst
301
docs/config.rst
|
|
@ -150,9 +150,107 @@ Supported Storages
|
||||||
CalDAV and CardDAV
|
CalDAV and CardDAV
|
||||||
++++++++++++++++++
|
++++++++++++++++++
|
||||||
|
|
||||||
.. autostorage:: vdirsyncer.storage.dav.CalDAVStorage
|
.. note::
|
||||||
|
|
||||||
.. autostorage:: vdirsyncer.storage.dav.CardDAVStorage
|
Please also see :ref:`supported-servers`, as some servers may not work
|
||||||
|
well.
|
||||||
|
|
||||||
|
.. storage:: caldav
|
||||||
|
|
||||||
|
CalDAV.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[storage example_for_caldav]
|
||||||
|
type = "caldav"
|
||||||
|
#start_date = null
|
||||||
|
#end_date = null
|
||||||
|
#item_types = []
|
||||||
|
url = "..."
|
||||||
|
#username = ""
|
||||||
|
#password = ""
|
||||||
|
#verify = true
|
||||||
|
#auth = null
|
||||||
|
#useragent = "vdirsyncer/0.16.4"
|
||||||
|
#verify_fingerprint = null
|
||||||
|
#auth_cert = null
|
||||||
|
|
||||||
|
You can set a timerange to synchronize with the parameters ``start_date``
|
||||||
|
and ``end_date``. Inside those parameters, you can use any Python
|
||||||
|
expression to return a valid :py:class:`datetime.datetime` object. For
|
||||||
|
example, the following would synchronize the timerange from one year in the
|
||||||
|
past to one year in the future::
|
||||||
|
|
||||||
|
start_date = "datetime.now() - timedelta(days=365)"
|
||||||
|
end_date = "datetime.now() + timedelta(days=365)"
|
||||||
|
|
||||||
|
Either both or none have to be specified. The default is to synchronize
|
||||||
|
everything.
|
||||||
|
|
||||||
|
You can set ``item_types`` to restrict the *kind of items* you want to
|
||||||
|
synchronize. For example, if you want to only synchronize events (but don't
|
||||||
|
download any tasks from the server), set ``item_types = ["VEVENT"]``. If
|
||||||
|
you want to synchronize events and tasks, but have some ``VJOURNAL`` items
|
||||||
|
on the server you don't want to synchronize, use ``item_types = ["VEVENT",
|
||||||
|
"VTODO"]``.
|
||||||
|
|
||||||
|
:param start_date: Start date of timerange to show, default -inf.
|
||||||
|
:param end_date: End date of timerange to show, default +inf.
|
||||||
|
:param item_types: Kind of items to show. The default, the empty list, is
|
||||||
|
to show all. This depends on particular features on the server, the
|
||||||
|
results are not validated.
|
||||||
|
:param url: Base URL or an URL to a calendar.
|
||||||
|
:param username: Username for authentication.
|
||||||
|
:param password: Password for authentication.
|
||||||
|
:param verify: Verify SSL certificate, default True. This can also be a
|
||||||
|
local path to a self-signed SSL certificate. See :ref:`ssl-tutorial`
|
||||||
|
for more information.
|
||||||
|
:param verify_fingerprint: Optional. SHA1 or MD5 fingerprint of the
|
||||||
|
expected server certificate. See :ref:`ssl-tutorial` for more
|
||||||
|
information.
|
||||||
|
:param auth: Optional. Either ``basic``, ``digest`` or ``guess``. The
|
||||||
|
default is preemptive Basic auth, sending credentials even if server
|
||||||
|
didn't request them. This saves from an additional roundtrip per
|
||||||
|
request. Consider setting ``guess`` if this causes issues with your
|
||||||
|
server.
|
||||||
|
:param auth_cert: Optional. Either a path to a certificate with a client
|
||||||
|
certificate and the key or a list of paths to the files with them.
|
||||||
|
:param useragent: Default ``vdirsyncer``.
|
||||||
|
|
||||||
|
|
||||||
|
.. storage:: carddav
|
||||||
|
|
||||||
|
CardDAV.
|
||||||
|
|
||||||
|
::
|
||||||
|
[storage example_for_carddav]
|
||||||
|
type = "carddav"
|
||||||
|
url = "..."
|
||||||
|
#username = ""
|
||||||
|
#password = ""
|
||||||
|
#verify = true
|
||||||
|
#auth = null
|
||||||
|
#useragent = "vdirsyncer/0.16.4"
|
||||||
|
#verify_fingerprint = null
|
||||||
|
#auth_cert = null
|
||||||
|
|
||||||
|
:param url: Base URL or an URL to an addressbook.
|
||||||
|
:param username: Username for authentication.
|
||||||
|
:param password: Password for authentication.
|
||||||
|
:param verify: Verify SSL certificate, default True. This can also be a
|
||||||
|
local path to a self-signed SSL certificate. See :ref:`ssl-tutorial`
|
||||||
|
for more information.
|
||||||
|
:param verify_fingerprint: Optional. SHA1 or MD5 fingerprint of the
|
||||||
|
expected server certificate. See :ref:`ssl-tutorial` for more
|
||||||
|
information.
|
||||||
|
:param auth: Optional. Either ``basic``, ``digest`` or ``guess``. The
|
||||||
|
default is preemptive Basic auth, sending credentials even if server
|
||||||
|
didn't request them. This saves from an additional roundtrip per
|
||||||
|
request. Consider setting ``guess`` if this causes issues with your
|
||||||
|
server.
|
||||||
|
:param auth_cert: Optional. Either a path to a certificate with a client
|
||||||
|
certificate and the key or a list of paths to the files with them.
|
||||||
|
:param useragent: Default ``vdirsyncer``.
|
||||||
|
|
||||||
Google
|
Google
|
||||||
++++++
|
++++++
|
||||||
|
|
@ -206,9 +304,42 @@ or write anything to it.
|
||||||
a rather hidden `settings page
|
a rather hidden `settings page
|
||||||
<https://calendar.google.com/calendar/syncselect>`_.
|
<https://calendar.google.com/calendar/syncselect>`_.
|
||||||
|
|
||||||
.. autostorage:: vdirsyncer.storage.google.GoogleCalendarStorage
|
.. storage:: google_calendar
|
||||||
|
|
||||||
.. autostorage:: vdirsyncer.storage.google.GoogleContactsStorage
|
Google calendar.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[storage example_for_google_calendar]
|
||||||
|
type = "google_calendar"
|
||||||
|
token_file = "..."
|
||||||
|
client_id = "..."
|
||||||
|
client_secret = "..."
|
||||||
|
#start_date = null
|
||||||
|
#end_date = null
|
||||||
|
#item_types = []
|
||||||
|
|
||||||
|
Please refer to :storage:`caldav` regarding the ``item_types`` and timerange parameters.
|
||||||
|
|
||||||
|
:param token_file: A filepath where access tokens are stored.
|
||||||
|
:param client_id/client_secret: OAuth credentials, obtained from the Google
|
||||||
|
API Manager.
|
||||||
|
|
||||||
|
.. storage:: google_contacts
|
||||||
|
|
||||||
|
Google contacts.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[storage example_for_google_contacts]
|
||||||
|
type = "google_contacts"
|
||||||
|
token_file = "..."
|
||||||
|
client_id = "..."
|
||||||
|
client_secret = "..."
|
||||||
|
|
||||||
|
:param token_file: A filepath where access tokens are stored.
|
||||||
|
:param client_id/client_secret: OAuth credentials, obtained from the Google
|
||||||
|
API Manager.
|
||||||
|
|
||||||
EteSync
|
EteSync
|
||||||
+++++++
|
+++++++
|
||||||
|
|
@ -224,17 +355,123 @@ To use it, you need to install some optional dependencies::
|
||||||
On first usage you will be prompted for the service password and the encryption
|
On first usage you will be prompted for the service password and the encryption
|
||||||
password. Neither are stored.
|
password. Neither are stored.
|
||||||
|
|
||||||
.. autostorage:: vdirsyncer.storage.etesync.EtesyncContacts
|
.. storage:: etesync_contacts
|
||||||
|
|
||||||
.. autostorage:: vdirsyncer.storage.etesync.EtesyncCalendars
|
Contacts for etesync.
|
||||||
|
|
||||||
|
::
|
||||||
|
[storage example_for_etesync_contacts]
|
||||||
|
email = ...
|
||||||
|
secrets_dir = ...
|
||||||
|
#server_path = ...
|
||||||
|
#db_path = ...
|
||||||
|
|
||||||
|
:param email: The email address of your account.
|
||||||
|
:param secrets_dir: A directory where vdirsyncer can store the encryption
|
||||||
|
key and authentication token.
|
||||||
|
:param server_url: Optional. URL to the root of your custom server.
|
||||||
|
:param db_path: Optional. Use a different path for the database.
|
||||||
|
|
||||||
|
.. storage:: etesync_calendars
|
||||||
|
|
||||||
|
Calendars for etesync.
|
||||||
|
|
||||||
|
::
|
||||||
|
[storage example_for_etesync_calendars]
|
||||||
|
email = ...
|
||||||
|
secrets_dir = ...
|
||||||
|
#server_path = ...
|
||||||
|
#db_path = ...
|
||||||
|
|
||||||
|
:param email: The email address of your account.
|
||||||
|
:param secrets_dir: A directory where vdirsyncer can store the encryption
|
||||||
|
key and authentication token.
|
||||||
|
:param server_url: Optional. URL to the root of your custom server.
|
||||||
|
:param db_path: Optional. Use a different path for the database.
|
||||||
|
|
||||||
Local
|
Local
|
||||||
+++++
|
+++++
|
||||||
|
|
||||||
.. autostorage:: vdirsyncer.storage.filesystem.FilesystemStorage
|
.. storage:: filesystem
|
||||||
|
|
||||||
.. autostorage:: vdirsyncer.storage.singlefile.SingleFileStorage
|
Saves each item in its own file, given a directory.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[storage example_for_filesystem]
|
||||||
|
type = "filesystem"
|
||||||
|
path = "..."
|
||||||
|
fileext = "..."
|
||||||
|
#encoding = "utf-8"
|
||||||
|
#post_hook = null
|
||||||
|
|
||||||
|
Can be used with `khal <http://lostpackets.de/khal/>`_. See :doc:`vdir` for
|
||||||
|
a more formal description of the format.
|
||||||
|
|
||||||
|
Directories with a leading dot are ignored to make usage of e.g. version
|
||||||
|
control easier.
|
||||||
|
|
||||||
|
:param path: Absolute path to a vdir/collection. If this is used in
|
||||||
|
combination with the ``collections`` parameter in a pair-section, this
|
||||||
|
should point to a directory of vdirs instead.
|
||||||
|
:param fileext: The file extension to use (e.g. ``.txt``). Contained in the
|
||||||
|
href, so if you change the file extension after a sync, this will
|
||||||
|
trigger a re-download of everything (but *should* not cause data-loss
|
||||||
|
of any kind).
|
||||||
|
:param encoding: File encoding for items, both content and filename.
|
||||||
|
:param post_hook: A command to call for each item creation and
|
||||||
|
modification. The command will be called with the path of the
|
||||||
|
new/updated file.
|
||||||
|
|
||||||
|
.. storage:: singlefile
|
||||||
|
|
||||||
|
Save data in single local ``.vcf`` or ``.ics`` file.
|
||||||
|
|
||||||
|
The storage basically guesses how items should be joined in the file.
|
||||||
|
|
||||||
|
.. versionadded:: 0.1.6
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
This storage is very slow, and that is unlikely to change. You should
|
||||||
|
consider using :storage:`filesystem` if it fits your usecase.
|
||||||
|
|
||||||
|
:param path: The filepath to the file to be written to. If collections are
|
||||||
|
used, this should contain ``%s`` as a placeholder for the collection
|
||||||
|
name.
|
||||||
|
:param encoding: Which encoding the file should use. Defaults to UTF-8.
|
||||||
|
|
||||||
|
Example for syncing with :storage:`caldav`::
|
||||||
|
|
||||||
|
[pair my_calendar]
|
||||||
|
a = my_calendar_local
|
||||||
|
b = my_calendar_remote
|
||||||
|
collections = ["from a", "from b"]
|
||||||
|
|
||||||
|
[storage my_calendar_local]
|
||||||
|
type = "singlefile"
|
||||||
|
path = ~/.calendars/%s.ics
|
||||||
|
|
||||||
|
[storage my_calendar_remote]
|
||||||
|
type = "caldav"
|
||||||
|
url = https://caldav.example.org/
|
||||||
|
#username =
|
||||||
|
#password =
|
||||||
|
|
||||||
|
Example for syncing with :storage:`caldav` using a ``null`` collection::
|
||||||
|
|
||||||
|
[pair my_calendar]
|
||||||
|
a = my_calendar_local
|
||||||
|
b = my_calendar_remote
|
||||||
|
|
||||||
|
[storage my_calendar_local]
|
||||||
|
type = "singlefile"
|
||||||
|
path = ~/my_calendar.ics
|
||||||
|
|
||||||
|
[storage my_calendar_remote]
|
||||||
|
type = "caldav"
|
||||||
|
url = https://caldav.example.org/username/my_calendar/
|
||||||
|
#username =
|
||||||
|
#password =
|
||||||
|
|
||||||
Read-only storages
|
Read-only storages
|
||||||
++++++++++++++++++
|
++++++++++++++++++
|
||||||
|
|
@ -243,4 +480,50 @@ These storages don't support writing of their items, consequently ``read_only``
|
||||||
is set to ``true`` by default. Changing ``read_only`` to ``false`` on them
|
is set to ``true`` by default. Changing ``read_only`` to ``false`` on them
|
||||||
leads to an error.
|
leads to an error.
|
||||||
|
|
||||||
.. autostorage:: vdirsyncer.storage.http.HttpStorage
|
.. storage:: http
|
||||||
|
|
||||||
|
Use a simple ``.ics`` file (or similar) from the web.
|
||||||
|
``webcal://``-calendars are supposed to be used with this, but you have to
|
||||||
|
replace ``webcal://`` with ``http://``, or better, ``https://``.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[pair holidays]
|
||||||
|
a = holidays_local
|
||||||
|
b = holidays_remote
|
||||||
|
collections = null
|
||||||
|
|
||||||
|
[storage holidays_local]
|
||||||
|
type = "filesystem"
|
||||||
|
path = ~/.config/vdir/calendars/holidays/
|
||||||
|
fileext = .ics
|
||||||
|
|
||||||
|
[storage holidays_remote]
|
||||||
|
type = "http"
|
||||||
|
url = https://example.com/holidays_from_hicksville.ics
|
||||||
|
|
||||||
|
Too many WebCAL providers generate UIDs of all ``VEVENT``-components
|
||||||
|
on-the-fly, i.e. all UIDs change every time the calendar is downloaded.
|
||||||
|
This leads many synchronization programs to believe that all events have
|
||||||
|
been deleted and new ones created, and accordingly causes a lot of
|
||||||
|
unnecessary uploads and deletions on the other side. Vdirsyncer completely
|
||||||
|
ignores UIDs coming from :storage:`http` and will replace them with a hash
|
||||||
|
of the normalized item content.
|
||||||
|
|
||||||
|
:param url: URL to the ``.ics`` file.
|
||||||
|
:param username: Username for authentication.
|
||||||
|
:param password: Password for authentication.
|
||||||
|
:param verify: Verify SSL certificate, default True. This can also be a
|
||||||
|
local path to a self-signed SSL certificate. See :ref:`ssl-tutorial`
|
||||||
|
for more information.
|
||||||
|
:param verify_fingerprint: Optional. SHA1 or MD5 fingerprint of the
|
||||||
|
expected server certificate. See :ref:`ssl-tutorial` for more
|
||||||
|
information.
|
||||||
|
:param auth: Optional. Either ``basic``, ``digest`` or ``guess``. The
|
||||||
|
default is preemptive Basic auth, sending credentials even if server
|
||||||
|
didn't request them. This saves from an additional roundtrip per
|
||||||
|
request. Consider setting ``guess`` if this causes issues with your
|
||||||
|
server.
|
||||||
|
:param auth_cert: Optional. Either a path to a certificate with a client
|
||||||
|
certificate and the key or a list of paths to the files with them.
|
||||||
|
:param useragent: Default ``vdirsyncer``.
|
||||||
|
|
|
||||||
|
|
@ -93,26 +93,6 @@ def prepare_client_cert(cert):
|
||||||
return cert
|
return cert
|
||||||
|
|
||||||
|
|
||||||
HTTP_STORAGE_PARAMETERS = '''
|
|
||||||
:param username: Username for authentication.
|
|
||||||
:param password: Password for authentication.
|
|
||||||
:param verify: Verify SSL certificate, default True. This can also be a
|
|
||||||
local path to a self-signed SSL certificate. See :ref:`ssl-tutorial`
|
|
||||||
for more information.
|
|
||||||
:param verify_fingerprint: Optional. SHA1 or MD5 fingerprint of the
|
|
||||||
expected server certificate. See :ref:`ssl-tutorial` for more
|
|
||||||
information.
|
|
||||||
:param auth: Optional. Either ``basic``, ``digest`` or ``guess``. The
|
|
||||||
default is preemptive Basic auth, sending credentials even if server
|
|
||||||
didn't request them. This saves from an additional roundtrip per
|
|
||||||
request. Consider setting ``guess`` if this causes issues with your
|
|
||||||
server.
|
|
||||||
:param auth_cert: Optional. Either a path to a certificate with a client
|
|
||||||
certificate and the key or a list of paths to the files with them.
|
|
||||||
:param useragent: Default ``vdirsyncer``.
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
def _install_fingerprint_adapter(session, fingerprint):
|
def _install_fingerprint_adapter(session, fingerprint):
|
||||||
prefix = 'https://'
|
prefix = 'https://'
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ from requests.exceptions import HTTPError
|
||||||
|
|
||||||
from .base import Storage, normalize_meta_value
|
from .base import Storage, normalize_meta_value
|
||||||
from .. import exceptions, http, utils
|
from .. import exceptions, http, utils
|
||||||
from ..http import HTTP_STORAGE_PARAMETERS, USERAGENT, prepare_auth, \
|
from ..http import USERAGENT, prepare_auth, \
|
||||||
prepare_client_cert, prepare_verify
|
prepare_client_cert, prepare_verify
|
||||||
from ..vobject import Item
|
from ..vobject import Item
|
||||||
|
|
||||||
|
|
@ -397,17 +397,6 @@ class DAVSession(object):
|
||||||
|
|
||||||
|
|
||||||
class DAVStorage(Storage):
|
class DAVStorage(Storage):
|
||||||
|
|
||||||
__doc__ = '''
|
|
||||||
:param url: Base URL or an URL to a collection.
|
|
||||||
''' + HTTP_STORAGE_PARAMETERS + '''
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Please also see :ref:`supported-servers`, as some servers may not work
|
|
||||||
well.
|
|
||||||
'''
|
|
||||||
|
|
||||||
# the file extension of items. Useful for testing against radicale.
|
# the file extension of items. Useful for testing against radicale.
|
||||||
fileext = None
|
fileext = None
|
||||||
# mimetype of items
|
# mimetype of items
|
||||||
|
|
@ -714,36 +703,6 @@ class DAVStorage(Storage):
|
||||||
|
|
||||||
|
|
||||||
class CalDAVStorage(DAVStorage):
|
class CalDAVStorage(DAVStorage):
|
||||||
|
|
||||||
__doc__ = '''
|
|
||||||
CalDAV.
|
|
||||||
|
|
||||||
You can set a timerange to synchronize with the parameters ``start_date``
|
|
||||||
and ``end_date``. Inside those parameters, you can use any Python
|
|
||||||
expression to return a valid :py:class:`datetime.datetime` object. For
|
|
||||||
example, the following would synchronize the timerange from one year in the
|
|
||||||
past to one year in the future::
|
|
||||||
|
|
||||||
start_date = datetime.now() - timedelta(days=365)
|
|
||||||
end_date = datetime.now() + timedelta(days=365)
|
|
||||||
|
|
||||||
Either both or none have to be specified. The default is to synchronize
|
|
||||||
everything.
|
|
||||||
|
|
||||||
You can set ``item_types`` to restrict the *kind of items* you want to
|
|
||||||
synchronize. For example, if you want to only synchronize events (but don't
|
|
||||||
download any tasks from the server), set ``item_types = ["VEVENT"]``. If
|
|
||||||
you want to synchronize events and tasks, but have some ``VJOURNAL`` items
|
|
||||||
on the server you don't want to synchronize, use ``item_types = ["VEVENT",
|
|
||||||
"VTODO"]``.
|
|
||||||
|
|
||||||
:param start_date: Start date of timerange to show, default -inf.
|
|
||||||
:param end_date: End date of timerange to show, default +inf.
|
|
||||||
:param item_types: Kind of items to show. The default, the empty list, is
|
|
||||||
to show all. This depends on particular features on the server, the
|
|
||||||
results are not validated.
|
|
||||||
''' + DAVStorage.__doc__
|
|
||||||
|
|
||||||
storage_name = 'caldav'
|
storage_name = 'caldav'
|
||||||
fileext = '.ics'
|
fileext = '.ics'
|
||||||
item_mimetype = 'text/calendar'
|
item_mimetype = 'text/calendar'
|
||||||
|
|
@ -868,11 +827,6 @@ class CalDAVStorage(DAVStorage):
|
||||||
|
|
||||||
|
|
||||||
class CardDAVStorage(DAVStorage):
|
class CardDAVStorage(DAVStorage):
|
||||||
|
|
||||||
__doc__ = '''
|
|
||||||
CardDAV.
|
|
||||||
''' + DAVStorage.__doc__
|
|
||||||
|
|
||||||
storage_name = 'carddav'
|
storage_name = 'carddav'
|
||||||
fileext = '.vcf'
|
fileext = '.vcf'
|
||||||
item_mimetype = 'text/vcard'
|
item_mimetype = 'text/vcard'
|
||||||
|
|
|
||||||
|
|
@ -100,14 +100,6 @@ class _Session:
|
||||||
|
|
||||||
|
|
||||||
class EtesyncStorage(Storage):
|
class EtesyncStorage(Storage):
|
||||||
'''
|
|
||||||
:param email: The email address of your account.
|
|
||||||
:param secrets_dir: A directory where vdirsyncer can store the encryption
|
|
||||||
key and authentication token.
|
|
||||||
:param server_url: Optional. URL to the root of your custom server.
|
|
||||||
:param db_path: Optional. Use a different path for the database.
|
|
||||||
'''
|
|
||||||
|
|
||||||
_collection_type = None
|
_collection_type = None
|
||||||
_item_type = None
|
_item_type = None
|
||||||
_at_once = False
|
_at_once = False
|
||||||
|
|
@ -225,20 +217,12 @@ class EtesyncStorage(Storage):
|
||||||
|
|
||||||
|
|
||||||
class EtesyncContacts(EtesyncStorage):
|
class EtesyncContacts(EtesyncStorage):
|
||||||
__doc__ = '''
|
|
||||||
Contacts for EteSync.
|
|
||||||
''' + EtesyncStorage.__doc__
|
|
||||||
|
|
||||||
_collection_type = AddressBook
|
_collection_type = AddressBook
|
||||||
_item_type = Contact
|
_item_type = Contact
|
||||||
storage_name = 'etesync_contacts'
|
storage_name = 'etesync_contacts'
|
||||||
|
|
||||||
|
|
||||||
class EtesyncCalendars(EtesyncStorage):
|
class EtesyncCalendars(EtesyncStorage):
|
||||||
__doc__ = '''
|
|
||||||
Calendars for EteSync.
|
|
||||||
''' + EtesyncStorage.__doc__
|
|
||||||
|
|
||||||
_collection_type = Calendar
|
_collection_type = Calendar
|
||||||
_item_type = Event
|
_item_type = Event
|
||||||
storage_name = 'etesync_calendars'
|
storage_name = 'etesync_calendars'
|
||||||
|
|
|
||||||
|
|
@ -17,28 +17,6 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class FilesystemStorage(Storage):
|
class FilesystemStorage(Storage):
|
||||||
|
|
||||||
'''
|
|
||||||
Saves each item in its own file, given a directory.
|
|
||||||
|
|
||||||
Can be used with `khal <http://lostpackets.de/khal/>`_. See :doc:`vdir` for
|
|
||||||
a more formal description of the format.
|
|
||||||
|
|
||||||
Directories with a leading dot are ignored to make usage of e.g. version
|
|
||||||
control easier.
|
|
||||||
|
|
||||||
:param path: Absolute path to a vdir/collection. If this is used in
|
|
||||||
combination with the ``collections`` parameter in a pair-section, this
|
|
||||||
should point to a directory of vdirs instead.
|
|
||||||
:param fileext: The file extension to use (e.g. ``.txt``). Contained in the
|
|
||||||
href, so if you change the file extension after a sync, this will
|
|
||||||
trigger a re-download of everything (but *should* not cause data-loss
|
|
||||||
of any kind).
|
|
||||||
:param encoding: File encoding for items, both content and filename.
|
|
||||||
:param post_hook: A command to call for each item creation and
|
|
||||||
modification. The command will be called with the path of the
|
|
||||||
new/updated file.
|
|
||||||
'''
|
|
||||||
|
|
||||||
storage_name = 'filesystem'
|
storage_name = 'filesystem'
|
||||||
_repr_attributes = ('path',)
|
_repr_attributes = ('path',)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,20 +101,7 @@ class GoogleSession(dav.DAVSession):
|
||||||
_save_token(token)
|
_save_token(token)
|
||||||
|
|
||||||
|
|
||||||
GOOGLE_PARAMS_DOCS = '''
|
|
||||||
:param token_file: A filepath where access tokens are stored.
|
|
||||||
:param client_id/client_secret: OAuth credentials, obtained from the Google
|
|
||||||
API Manager.
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
class GoogleCalendarStorage(dav.CalDAVStorage):
|
class GoogleCalendarStorage(dav.CalDAVStorage):
|
||||||
__doc__ = '''Google calendar.
|
|
||||||
|
|
||||||
Please refer to :storage:`caldav` regarding
|
|
||||||
the ``item_types`` and timerange parameters.
|
|
||||||
''' + GOOGLE_PARAMS_DOCS
|
|
||||||
|
|
||||||
class session_class(GoogleSession):
|
class session_class(GoogleSession):
|
||||||
url = 'https://apidata.googleusercontent.com/caldav/v2/'
|
url = 'https://apidata.googleusercontent.com/caldav/v2/'
|
||||||
scope = ['https://www.googleapis.com/auth/calendar']
|
scope = ['https://www.googleapis.com/auth/calendar']
|
||||||
|
|
@ -150,10 +137,6 @@ class GoogleCalendarStorage(dav.CalDAVStorage):
|
||||||
|
|
||||||
|
|
||||||
class GoogleContactsStorage(dav.CardDAVStorage):
|
class GoogleContactsStorage(dav.CardDAVStorage):
|
||||||
__doc__ = '''Google contacts.
|
|
||||||
|
|
||||||
''' + GOOGLE_PARAMS_DOCS
|
|
||||||
|
|
||||||
class session_class(GoogleSession):
|
class session_class(GoogleSession):
|
||||||
# Google CardDAV is completely bonkers. Collection discovery doesn't
|
# Google CardDAV is completely bonkers. Collection discovery doesn't
|
||||||
# work properly, well-known URI takes us directly to single collection
|
# work properly, well-known URI takes us directly to single collection
|
||||||
|
|
|
||||||
|
|
@ -4,45 +4,12 @@ import urllib.parse as urlparse
|
||||||
|
|
||||||
from .base import Storage
|
from .base import Storage
|
||||||
from .. import exceptions
|
from .. import exceptions
|
||||||
from ..http import HTTP_STORAGE_PARAMETERS, USERAGENT, prepare_auth, \
|
from ..http import USERAGENT, prepare_auth, \
|
||||||
prepare_client_cert, prepare_verify, request
|
prepare_client_cert, prepare_verify, request
|
||||||
from ..vobject import Item, split_collection
|
from ..vobject import Item, split_collection
|
||||||
|
|
||||||
|
|
||||||
class HttpStorage(Storage):
|
class HttpStorage(Storage):
|
||||||
__doc__ = '''
|
|
||||||
Use a simple ``.ics`` file (or similar) from the web.
|
|
||||||
``webcal://``-calendars are supposed to be used with this, but you have to
|
|
||||||
replace ``webcal://`` with ``http://``, or better, ``https://``.
|
|
||||||
|
|
||||||
Too many WebCAL providers generate UIDs of all ``VEVENT``-components
|
|
||||||
on-the-fly, i.e. all UIDs change every time the calendar is downloaded.
|
|
||||||
This leads many synchronization programs to believe that all events have
|
|
||||||
been deleted and new ones created, and accordingly causes a lot of
|
|
||||||
unnecessary uploads and deletions on the other side. Vdirsyncer completely
|
|
||||||
ignores UIDs coming from :storage:`http` and will replace them with a hash
|
|
||||||
of the normalized item content.
|
|
||||||
|
|
||||||
:param url: URL to the ``.ics`` file.
|
|
||||||
''' + HTTP_STORAGE_PARAMETERS + '''
|
|
||||||
|
|
||||||
A simple example::
|
|
||||||
|
|
||||||
[pair holidays]
|
|
||||||
a = holidays_local
|
|
||||||
b = holidays_remote
|
|
||||||
collections = null
|
|
||||||
|
|
||||||
[storage holidays_local]
|
|
||||||
type = "filesystem"
|
|
||||||
path = ~/.config/vdir/calendars/holidays/
|
|
||||||
fileext = .ics
|
|
||||||
|
|
||||||
[storage holidays_remote]
|
|
||||||
type = "http"
|
|
||||||
url = https://example.com/holidays_from_hicksville.ics
|
|
||||||
'''
|
|
||||||
|
|
||||||
storage_name = 'http'
|
storage_name = 'http'
|
||||||
read_only = True
|
read_only = True
|
||||||
_repr_attributes = ('username', 'url')
|
_repr_attributes = ('username', 'url')
|
||||||
|
|
|
||||||
|
|
@ -30,56 +30,6 @@ def _writing_op(f):
|
||||||
|
|
||||||
|
|
||||||
class SingleFileStorage(Storage):
|
class SingleFileStorage(Storage):
|
||||||
'''Save data in single local ``.vcf`` or ``.ics`` file.
|
|
||||||
|
|
||||||
The storage basically guesses how items should be joined in the file.
|
|
||||||
|
|
||||||
.. versionadded:: 0.1.6
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
This storage is very slow, and that is unlikely to change. You should
|
|
||||||
consider using :storage:`filesystem` if it fits your usecase.
|
|
||||||
|
|
||||||
:param path: The filepath to the file to be written to. If collections are
|
|
||||||
used, this should contain ``%s`` as a placeholder for the collection
|
|
||||||
name.
|
|
||||||
:param encoding: Which encoding the file should use. Defaults to UTF-8.
|
|
||||||
|
|
||||||
Example for syncing with :storage:`caldav`::
|
|
||||||
|
|
||||||
[pair my_calendar]
|
|
||||||
a = my_calendar_local
|
|
||||||
b = my_calendar_remote
|
|
||||||
collections = ["from a", "from b"]
|
|
||||||
|
|
||||||
[storage my_calendar_local]
|
|
||||||
type = "singlefile"
|
|
||||||
path = ~/.calendars/%s.ics
|
|
||||||
|
|
||||||
[storage my_calendar_remote]
|
|
||||||
type = "caldav"
|
|
||||||
url = https://caldav.example.org/
|
|
||||||
#username =
|
|
||||||
#password =
|
|
||||||
|
|
||||||
Example for syncing with :storage:`caldav` using a ``null`` collection::
|
|
||||||
|
|
||||||
[pair my_calendar]
|
|
||||||
a = my_calendar_local
|
|
||||||
b = my_calendar_remote
|
|
||||||
|
|
||||||
[storage my_calendar_local]
|
|
||||||
type = "singlefile"
|
|
||||||
path = ~/my_calendar.ics
|
|
||||||
|
|
||||||
[storage my_calendar_remote]
|
|
||||||
type = "caldav"
|
|
||||||
url = https://caldav.example.org/username/my_calendar/
|
|
||||||
#username =
|
|
||||||
#password =
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
storage_name = 'singlefile'
|
storage_name = 'singlefile'
|
||||||
_repr_attributes = ('path',)
|
_repr_attributes = ('path',)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue